Understanding Frequency Response Analysis of IIR Filters

Frequency response analysis is a cornerstone of digital filter design and evaluation. For Infinite Impulse Response (IIR) filters, which rely on feedback to achieve sharp roll-offs and efficient implementations, understanding how the filter reacts to different frequencies is essential. The frequency response reveals the magnitude and phase characteristics, enabling engineers to verify that the filter meets specifications such as passband ripple, stopband attenuation, and transition width. This article provides a comprehensive guide to performing frequency response analysis of IIR filters using two powerful environments: MATLAB and Python. Both platforms offer built-in functions that simplify the process, but they differ in syntax, flexibility, and ecosystem integration.

Theoretical Background of IIR Filter Frequency Response

The frequency response H(e) of a digital filter is derived from its system function:

H(z) = (b0 + b1z-1 + ... + bMz-M) / (1 + a1z-1 + ... + aNz-N)

Evaluating on the unit circle (z = e) gives the frequency response. The magnitude response |H(e)| in decibels (dB) indicates how much a frequency component is amplified or attenuated, while the phase response ∠H(e) shows the phase shift introduced. For IIR filters, the feedback (denominator polynomial) can lead to resonant peaks or sharp transitions, making accurate analysis critical.

Key Parameters in Frequency Response Plots

  • Cutoff frequency: Frequency where the magnitude drops by 3 dB (for low-pass/high-pass) or defines the band edges (for band-pass).
  • Passband ripple: Variation in magnitude within the passband, often critical in Chebyshev and elliptic filters.
  • Stopband attenuation: Minimum attenuation in the stopband, measured in dB.
  • Transition width: The frequency region between passband and stopband edges.

MATLAB’s official documentation on IIR filter frequency response provides additional context on these parameters.

Performing Frequency Response Analysis in MATLAB

MATLAB offers the freqz function as the primary tool for computing and plotting the frequency response of a digital filter. It returns the complex frequency response vector h and the corresponding frequency vector w. The function can plot the magnitude and phase automatically if called without output arguments.

Basic Usage with IIR Filter Coefficients

Consider a low-pass IIR filter designed using the Butterworth method (order 2, normalized cutoff 0.5). The numerator and denominator coefficients are:

b = [0.0675, 0.1349, 0.0675];  % numerator coefficients
a = [1.0000, -1.1430, 0.4128]; % denominator coefficients

To plot the frequency response, simply call:

freqz(b, a)

This generates two subplots: the magnitude response (in dB) and the phase response (in degrees or radians, depending on settings). The default frequency range is 0 to π rad/sample (or 0 to half the sampling rate if a sample rate is provided).

Customizing the Plot and Computing Numerical Values

You can obtain the numerical data for further processing:

[h, w] = freqz(b, a, 1024);  % 1024 points
magnitude_dB = 20*log10(abs(h));
phase_deg = unwrap(angle(h)) * 180/pi;

This is useful when you need to extract specific values, such as the attenuation at a given frequency, or when you want to overlay multiple filters. MATLAB also supports specifying a sampling frequency (fs) to map frequencies to real-world values:

freqz(b, a, 512, 1000);  % 1000 Hz sampling rate

The freqz documentation on MathWorks details all available options, including plotting on a logarithmic frequency axis using freqz(b,a,'whole',1024) or manually with semilogx.

Analyzing Phase Response and Group Delay

While freqz shows the unwrapped phase, the group delay (derivative of phase with respect to frequency) is often more insightful for understanding filter latency. MATLAB provides the grpdelay function:

grpdelay(b, a, 1024)

For IIR filters, group delay can vary significantly across frequencies, especially near the cutoff. This is a key tradeoff compared to Finite Impulse Response (FIR) filters, which can have linear phase.

Performing Frequency Response Analysis in Python

Python, with the scipy.signal library, offers an equivalent freqz function that closely mirrors MATLAB’s interface. However, Python gives users more control over the plotting process through libraries like Matplotlib. The syntax is similar but uses NumPy arrays.

Basic Example with the Same Coefficients

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

b = [0.0675, 0.1349, 0.0675]
a = [1.0, -1.1430, 0.4128]

w, h = freqz(b, a, worN=8000)

plt.figure(figsize=(10, 6))
plt.subplot(2, 1, 1)
plt.plot(w / np.pi, 20 * np.log10(np.abs(h)))
plt.title('Magnitude Response')
plt.ylabel('Magnitude (dB)')
plt.grid(True)
plt.ylim(-80, 5)

plt.subplot(2, 1, 2)
plt.plot(w / np.pi, np.angle(h))  # unwrapped by default if set
plt.title('Phase Response')
plt.xlabel('Normalized Frequency (×π rad/sample)')
plt.ylabel('Phase (radians)')
plt.grid(True)

plt.tight_layout()
plt.show()

The worN parameter specifies the number of points. The frequency vector w is in radians/sample; dividing by π gives normalized frequency (0 to 1). To convert to real frequencies, you can multiply by fs/2.

Designing and Analyzing a Butterworth IIR Filter in Python

Python also excels at filter design via scipy.signal.butter, cheby1, ellip, etc. For example:

from scipy.signal import butter, freqz

b, a = butter(4, 0.2, 'low')  # 4th order, normalized cutoff 0.2
w, h = freqz(b, a)

This workflow is common in real-world signal processing pipelines. The SciPy freqz documentation explains how to use it with different filter representations, including second-order sections (SOS) which are numerically more stable for high-order IIR filters.

Handling High-Order Filters with Second-Order Sections

For IIR filters with order above 8–10, direct-form implementation can introduce numerical errors. Python’s sosfreqz function handles SOS filters:

sos = butter(8, 0.3, 'low', output='sos')
w, h = sosfreqz(sos)

This ensures accurate frequency response computation even for high-order elliptic filters that have steep transitions.

Comparing MATLAB and Python Workflows

Both platforms provide robust frequency response analysis, but there are practical differences:

AspectMATLABPython
Ease of initial plotSingle command freqz(b,a)Requires a few lines of Matplotlib code
FlexibilityLimited customization without additional commandsFull control over plot elements
Numerical stabilityAutomatic handling of high-order via sosfreqz (option)Explicit SOS support via sosfreqz
IntegrationGood with Simulink and DSP System ToolboxIntegrates with NumPy, Pandas, and deep learning frameworks
CostProprietary (expensive)Free and open-source

For students and researchers, Python’s free availability and extensive library ecosystem often make it the preferred choice, while MATLAB remains dominant in industry environments where toolboxes like DSP System Toolbox or Filter Design HDL Coder are required.

Advanced Topics in IIR Frequency Response Analysis

Pole-Zero Plots and Stability Analysis

Frequency response is closely tied to the pole-zero locations. Poles near the unit circle cause sharp peaks in the magnitude response, while zeros can create deep notches. MATLAB’s zplane(b,a) and Python’s scipy.signal.tf2zpk (or a custom function) can plot the pole-zero diagram. For example, in Python:

z, p, k = tf2zpk(b, a)
plt.scatter(np.real(z), np.imag(z), marker='o', color='b')
plt.scatter(np.real(p), np.imag(p), marker='x', color='r')
circle = plt.Circle((0,0), 1, fill=False, color='k')
plt.gca().add_patch(circle)
plt.axis('equal')
plt.title('Pole-Zero Plot')
plt.show()

This visualization complements the frequency response by showing stability criteria (all poles inside the unit circle) and potential resonance.

Group Delay and Phase Linearity

IIR filters inherently have nonlinear phase, which can distort waveforms. The group delay τg(ω) = -d∠H/dω quantifies time delay at each frequency. Both MATLAB (grpdelay) and Python (scipy.signal.group_delay) compute this. Plotting group delay alongside magnitude response is recommended when the filter is used in applications sensitive to phase distortion, such as audio equalizers.

# Python group delay example
from scipy.signal import group_delay
w, gd = group_delay((b, a), w=512)
plt.plot(w/np.pi, gd)
plt.title('Group Delay')
plt.xlabel('Normalized Frequency (×π rad/sample)')
plt.ylabel('Group Delay (samples)')
plt.grid(True)

Frequency Response for Multirate Systems

When IIR filters are used in decimation or interpolation, the frequency response must be considered after rate changes. MATLAB’s freqz can be combined with upfirdn or polyphase decomposition, while Python’s scipy.signal.resample_poly and freqz can be adapted. This is a more advanced topic, but essential for modern communication systems and software-defined radio.

Interpreting Common IIR Filter Responses

Below are typical magnitude responses for common IIR filter types:

  • Butterworth: Maximally flat passband, monotonic roll-off, no ripple. Phase response is relatively smooth.
  • Chebyshev Type I: Ripple in the passband, steeper roll-off than Butterworth for the same order. Phase nonlinearity is more pronounced.
  • Chebyshev Type II: Ripple in the stopband, flat passband. Less common due to stopband artifacts.
  • Elliptic (Cauer): Ripple in both passband and stopband, steepest possible roll-off for given order. Significant phase distortion.
  • Bessel: Maximally flat group delay (linear phase approximation), but poor magnitude selectivity. Useful in analog-filter emulation.

When performing frequency response analysis, always check the passband ripple and stopband attenuation against your design specs. For instance, an elliptic low-pass filter with 0.1 dB passband ripple and 60 dB stopband attenuation may exhibit a group delay that varies by hundreds of samples near the transition, which could be unacceptable in time-domain applications.

Practical Tips for Accurate Frequency Response Analysis

  1. Use sufficient frequency resolution: The worN parameter (or freqz’s default) should be at least 512 points. For filters with narrow features, 2048 points or more may be needed.
  2. Avoid numerical overflow: For high-order IIR filters, decompose into second-order sections (SOS). Both MATLAB (tf2sos) and Python (scipy.signal.tf2sos) support this. Then use sosfreqz.
  3. Check the sampling frequency: When plotting against real frequencies, ensure you pass fs correctly. Normalized frequency (0 to 1) corresponds to 0 to fs/2.
  4. Unwrap the phase: The default phase from freqz may be wrapped. Use unwrap(angle(h)) in both environments to see a continuous phase curve.
  5. Combine plots for comparison: When designing filters, overlay the target specification masks (e.g., passband edges with rectangles) to visually verify compliance. This can be done in MATLAB with patch or in Python with ax.fill_between.

Conclusion

Frequency response analysis is an indispensable tool for anyone working with IIR filters, from students learning digital signal processing to engineers designing audio equalizers, communication systems, or biomedical signal filters. Both MATLAB and Python provide powerful, accessible functions like freqz and scipy.signal.freqz that allow you to compute and visualize the magnitude and phase responses with minimal code. By extending the analysis to pole-zero plots, group delay, and using second-order sections for stability, you can gain a deep understanding of filter behavior. Whether you choose MATLAB for its integrated toolboxes or Python for its openness and flexibility, mastering these techniques will significantly enhance your ability to design, validate, and optimize IIR filters in practical projects.

For further reading, consult MathWorks’ IIR filter overview and SciPy’s signal processing tutorial.