Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Use scipy.signal.freqz to calculate a digital filter’s complex frequency response, then plot its magnitude with np.abs(h). For a magnitude-in-decibels plot, convert that magnitude with 20 * np.log10(...). Set fs to the filter’s sampling frequency to put the x-axis in hertz.

Calculate and plot magnitude

freqz returns two arrays: w, the frequencies at which the response was evaluated, and h, the complex-valued response. Because h is complex, plot its absolute value for magnitude rather than plotting h directly.

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# b and a are the filter numerator and denominator coefficients.
fs = 48_000  # Example sampling frequency in Hz
w, h = signal.freqz(b, a, fs=fs)

fig, ax = plt.subplots()
ax.plot(w, 20 * np.log10(np.maximum(np.abs(h), 1e-12)))
ax.set(
    xlabel="Frequency (Hz)",
    ylabel="Magnitude (dB)",
    title="Digital filter frequency response",
)
ax.grid(True)
plt.show()

The 1e-12 floor prevents taking the logarithm of zero. It is a display choice, not a measurement of the filter; values below the floor appear at the floor on this plot. For a linear magnitude plot instead, use ax.plot(w, np.abs(h)) and label the vertical axis “Magnitude” or “Gain.” The SciPy tutorial also shows plotting np.abs(H) against frequencies returned by freqz. SciPy signal-processing tutorial.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose frequency units and range

The current documented signature is freqz(b, a=1, worN=512, whole=False, plot=None, fs=2*pi, include_nyquist=False). By default, worN=512 requests 512 frequency samples. With the default fs, frequencies are in radians per sample, and the default one-sided range runs from zero toward π, the Nyquist frequency.

#1 Best Overall
Sale
Fundamentals of Statistical Signal Processing, Volume I: Estimation Theory
  • describes the field of parameter estimation based on time series data.
  • provides a summary of principal approaches as well as a “roadmap” to use in the selection of an estimator.
  • extends many of the results for real data/real parameters to complex data/complex parameters.
  • summarizes as examples many of the important estimators used in practice.
  • illustrates how a digital computer can be used to assess performance of an estimator.
  • Use hertz: pass the actual sample rate, such as fs=48_000. The returned w values and x-axis are then in hertz, and the default range runs from zero toward half that sample rate.
  • Use the full digital frequency range: set whole=True to evaluate from zero to fs, rather than only through the Nyquist region.
  • Include the Nyquist endpoint: set include_nyquist=True. It includes the final Nyquist sample only when whole=False and worN is an integer; in other cases the option is ignored.
  • Evaluate selected frequencies: pass an explicit frequency array as worN. Its values must use the same units as fs.

For dense response curves, increase the integer worN to request more samples. SciPy documents cases where a fast FFT length can improve performance, but grid density and endpoint choices are usually the key plotting decisions. Keep the sampling-frequency setting consistent with the one used to specify filter design edges, since design functions can have different sampling-frequency defaults. SciPy freqz reference and signal-processing tutorial.

Add a phase plot

Phase comes from the angle of the complex response. Use np.unwrap to remove jumps by multiples of 2π, and plot phase separately so its scale does not compete with magnitude.

phase = np.unwrap(np.angle(h))

fig, (ax_mag, ax_phase) = plt.subplots(2, 1, sharex=True)
ax_mag.plot(w, np.abs(h))
ax_mag.set_ylabel("Magnitude")
ax_mag.grid(True)

ax_phase.plot(w, phase)
ax_phase.set(xlabel="Frequency (Hz)", ylabel="Phase (radians)")
ax_phase.grid(True)
plt.show()

Here fs was supplied in the earlier freqz call, so the shared frequency axis is in hertz. If you use decibels for magnitude, replace the first subplot’s np.abs(h) with the decibel expression from the previous example.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Avoid plotting the real part by mistake

Do not pass matplotlib.pyplot.plot as freqz’s plot callback when you intend to show amplitude. SciPy warns that this plots the real part of the complex response, not its magnitude. Calculate w, h and plot np.abs(h) explicitly, or provide a callback that plots the absolute value. SciPy freqz reference.

Use the SOS function for second-order sections

If your filter is represented as second-order sections (SOS), use scipy.signal.freqz_sos rather than converting the sections to a single numerator and denominator polynomial just to calculate the response. SciPy documents a high-order example in which numerical error affects the response computed from a single transfer-function coefficient representation, and compares it with the SOS-based calculation. This is a representation and numerical-stability consideration, not evidence that every freqz result is inaccurate. SciPy freqz_sos reference. The SciPy signal function index distinguishes freqz for coefficient form from freqz_sos for SOS form.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Check plots before comparing them

Two response curves are meaningfully comparable only when their setup and presentation choices are clear. Check that the sampling rate and frequency-axis units match, that grid density and Nyquist endpoint handling are appropriate, and that both magnitude curves use the same scale (linear or decibels). For phase, check whether it is unwrapped and displayed on a legible separate axis. Also account for whether the filters use polynomial coefficients or SOS, particularly for high-order filters.

Quick Recap

SaleBestseller No. 1
Fundamentals of Statistical Signal Processing, Volume I: Estimation Theory
Fundamentals of Statistical Signal Processing, Volume I: Estimation Theory
describes the field of parameter estimation based on time series data.; summarizes as examples many of the important estimators used in practice.
$113.89

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.