FIR vs IIR Filters: Characteristics, Design, and Python Implementation

Comparison of FIR and IIR digital filters covering theory, frequency response, stability, phase characteristics, with Python design examples using SciPy.

Introduction

Digital filters are fundamental to extracting or removing specific frequency components from discrete-time signals. They are broadly classified into two types: FIR (Finite Impulse Response) filters and IIR (Infinite Impulse Response) filters.

This article explains the mathematical definitions, characteristic differences, and design methods of both types, and compares their frequency and phase responses using Python with SciPy.

FIR Filters

Definition

The output of an FIR filter is a weighted sum of present and past input values:

\[y[n] = \sum_{k=0}^{M} b_k \, x[n-k] \tag{1}\]

where \(b_k\) are the filter coefficients and \(M\) is the filter order. The impulse response is finite, completing in \(M+1\) samples.

Transfer Function

Through the Z-transform, the transfer function is:

\[H(z) = \sum_{k=0}^{M} b_k \, z^{-k} \tag{2}\]

Since the denominator is 1 (all-zero model), FIR filters are always stable.

Linear Phase Property

The greatest advantage of FIR filters is that linear phase is guaranteed when the coefficients are symmetric (\(b_k = b_{M-k}\)) or antisymmetric. Linear phase means all frequency components are delayed by the same amount of time, preserving the signal waveform shape.

IIR Filters

Definition

IIR filters have a recursive structure, feeding back past output values:

\[y[n] = \sum_{k=0}^{M} b_k \, x[n-k] - \sum_{k=1}^{N} a_k \, y[n-k] \tag{3}\]

Transfer Function

\[H(z) = \frac{\sum_{k=0}^{M} b_k \, z^{-k}}{1 + \sum_{k=1}^{N} a_k \, z^{-k}} = \frac{B(z)}{A(z)} \tag{4}\]

The presence of the denominator polynomial \(A(z)\) makes the impulse response theoretically infinite. Stability requires all poles to lie within the unit circle.

FIR vs IIR Comparison

PropertyFIRIIR
StabilityAlways stableDesign-dependent (pole placement required)
Linear phaseGuaranteed with symmetric coefficientsGenerally nonlinear phase
Filter orderHigh order needed for sharp cutoffSharp characteristics with low order
Computational costIncreases with orderAchievable with fewer coefficients
Design methodsWindow, least squares, Parks-McClellanButterworth, Chebyshev, Elliptic
Analog correspondenceNoneConverted from analog prototypes

Python Implementation: Lowpass Filter Design and Comparison

The following code designs a lowpass filter with 100 Hz cutoff frequency using both FIR and IIR approaches, and compares their frequency responses.

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

# --- Parameters ---
fs = 1000       # Sampling frequency [Hz]
fc = 100        # Cutoff frequency [Hz]
nyq = fs / 2    # Nyquist frequency

# --- FIR filter design (window method) ---
fir_order = 50
fir_coeff = signal.firwin(fir_order + 1, fc / nyq)

# --- IIR filter design (4th-order Butterworth) ---
iir_order = 4
iir_sos = signal.butter(iir_order, fc / nyq, output='sos')

# --- Frequency response ---
w_fir, h_fir = signal.freqz(fir_coeff, worN=2048, fs=fs)
w_iir, h_iir = signal.sosfreqz(iir_sos, worN=2048, fs=fs)

# --- Plot ---
fig, axes = plt.subplots(2, 1, figsize=(10, 8))

# Magnitude response
axes[0].plot(w_fir, 20 * np.log10(np.abs(h_fir) + 1e-12), label=f'FIR (order={fir_order})')
axes[0].plot(w_iir, 20 * np.log10(np.abs(h_iir) + 1e-12), label=f'IIR Butterworth (order={iir_order})')
axes[0].set_xlabel('Frequency [Hz]')
axes[0].set_ylabel('Magnitude [dB]')
axes[0].set_title('Magnitude Response')
axes[0].set_xlim(0, 500)
axes[0].set_ylim(-80, 5)
axes[0].axvline(fc, color='gray', linestyle='--', alpha=0.5, label=f'Cutoff ({fc} Hz)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# Phase response
angles_fir = np.unwrap(np.angle(h_fir))
angles_iir = np.unwrap(np.angle(h_iir))
axes[1].plot(w_fir, np.degrees(angles_fir), label=f'FIR (order={fir_order})')
axes[1].plot(w_iir, np.degrees(angles_iir), label=f'IIR Butterworth (order={iir_order})')
axes[1].set_xlabel('Frequency [Hz]')
axes[1].set_ylabel('Phase [degrees]')
axes[1].set_title('Phase Response')
axes[1].set_xlim(0, 500)
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Phase Characteristics Discussion

The key differences visible in the plots above:

  • FIR filter: Phase varies linearly with frequency in the passband (linear phase). This means constant group delay, preserving the temporal shape of pulse waveforms.
  • IIR filter: Phase varies nonlinearly. Phase change becomes steep near cutoff, with group delay varying by frequency. However, zero-phase filtering is achievable using filtfilt.

Practical Selection Guidelines

  • Faithful waveform reproduction needed (ECG, audio, seismic) → FIR (linear phase)
  • Real-time processing with low computational costIIR (low order)
  • Absolute stability guarantee requiredFIR
  • Reproduce analog filter characteristicsIIR (bilinear transform)

References

  • Oppenheim, A. V., & Schafer, R. W. (2009). Discrete-Time Signal Processing (3rd ed.). Prentice Hall.
  • Parks, T. W., & Burrus, C. S. (1987). Digital Filter Design. Wiley.
  • SciPy Signal Processing documentation