>
section 4 of 117 min read

4. IIR Filter Design

4.1 Why IIR

You want a sharp low-pass with cutoff at fc=2f_c = 2 kHz and stopband attenuation 60 dB at fs=2.5f_s = 2.5 kHz, sample rate 8 kHz. You can do it with an FIR (Section 5) of about 100 taps, or an IIR (Section 4) of order 8 (about 8 multiplies per output for a cascade of biquads). The IIR is roughly 10×10\times less computation.

That is the IIR's selling point: same magnitude response, much lower order. The price: nonlinear phase, potential stability concerns, and higher coefficient sensitivity. For applications where shape, not phase, matters (RF preselection, analog-style audio EQ, control-loop compensators), IIR wins. For applications where phase matters (audio crossovers, image processing, communications equalization), FIR is preferred.

4.2 The standard recipe: design analog, transform to digital

The classical IIR design path:

  1. Translate digital specs into equivalent analog specs (handling frequency warp, depending on transformation).
  2. Design an analog prototype filter of the desired type (Butterworth, Chebyshev, elliptic, Bessel) of the right order.
  3. Apply an analog-to-digital transformation (impulse invariance or bilinear) to map the analog H(s)H(s) into a digital H(z)H(z).
  4. Verify that the digital H(z)H(z) meets the original specs; iterate if not.
  5. Choose a structure (cascade of biquads is almost always the right choice).

The analog-prototype shortcut works because the analog filter design problem has been beautifully solved for decades: closed-form formulas exist for the pole-zero locations of Butterworth, Chebyshev, and elliptic filters, all sitting in canonical forms. Don't reinvent that work; transform to digital.

4.3 Analog filter types: Butterworth, Chebyshev, elliptic, Bessel

Each analog prototype trades off ripple, transition steepness, and phase response.

Butterworth. Maximally flat magnitude response in the passband (every derivative of H|H| at ω=0\omega = 0 is zero), monotone falloff in the stopband.

H(jω)2=11+(ω/ωc)2N|H(j\omega)|^2 = \frac{1}{1 + (\omega/\omega_c)^{2N}}

For order NN, the falloff is 20N-20N dB/decade above the cutoff. Pole locations: equally spaced on a circle of radius ωc\omega_c in the left half-plane. Smooth, well-behaved, the default for general-purpose use. Audio EQ, control compensators, and sensor anti-aliasing typically use Butterworths.

Chebyshev type I. Allows ripple of magnitude ϵ\epsilon in the passband to get a sharper transition than Butterworth of the same order. Stopband is monotone. Sharper rolloff for given order, at the cost of in-band ripple. Used where stopband attenuation matters more than passband flatness.

Chebyshev type II (inverse Chebyshev). Ripple in the stopband, smooth passband. Sharper transition than Butterworth. Used where you want a flat passband but sharp transition.

Elliptic (Cauer) filter. Ripple in both passband and stopband. Achieves the sharpest possible transition for a given filter order. The formula involves Jacobi elliptic functions; not closed-form, but tabulated and built into every design tool. Used where you must squeeze every dB of transition steepness from minimum order, e.g., in CD-audio anti-imaging filters of yesteryear.

Bessel. Designed for maximally flat group delay (linear phase) in the passband. Magnitude rolloff is gentle (worst of the four), but the pulse response is the cleanest, with no overshoot and minimal ringing. Used in pulse-shaping for digital communications, oscilloscope analog front ends (you want the scope's filter to not distort pulse edges), and audio crossovers where transient response matters.

A summary picture of the trade-offs:

FilterPassbandStopbandPhaseWhen to use
Butterworthflatmonotonebowedgeneral-purpose
Cheby Iripplemonotonebowedsharp rolloff, ripple OK
Cheby IIflatripplebowedflat passband, sharp transition
Ellipticrippleripplebowedsharpest possible transition
Besselflatgentlelinearpreserve pulse shape

4.4 The bilinear transform, derived

The bilinear transform is the standard analog-to-digital mapping. Given an analog Ha(s)H_a(s), the digital filter is

Hd(z)=Ha ⁣(2Tz1z+1)H_d(z) = H_a\!\left(\frac{2}{T}\,\frac{z - 1}{z + 1}\right)

i.e., substitute s(2/T)(z1)/(z+1)s \to (2/T)(z-1)/(z+1) everywhere ss appears.

Where does this come from? Trapezoidal integration of 1/s1/s. Recall that an integrator in the analog world has H(s)=1/sH(s) = 1/s. In discrete time, the trapezoidal rule for integration of a sequence x[n]x[n] is

y[n]=y[n1]+T2(x[n]+x[n1])y[n] = y[n-1] + \frac{T}{2}\,(x[n] + x[n-1])

Take the Z-transform:

Y(z)=z1Y(z)+T2(1+z1)X(z)Y(z) = z^{-1} Y(z) + \frac{T}{2}(1 + z^{-1}) X(z) Y(z)X(z)=T21+z11z1=T2z+1z1\frac{Y(z)}{X(z)} = \frac{T}{2}\,\frac{1 + z^{-1}}{1 - z^{-1}} = \frac{T}{2}\,\frac{z + 1}{z - 1}

Compare to the analog integrator 1/s1/s. So the trapezoidal-rule digital integrator approximates 1/s1/s by (T/2)(z+1)/(z1)(T/2)\,(z+1)/(z-1), i.e., ss is approximated by (2/T)(z1)/(z+1)(2/T)\,(z-1)/(z+1). That is the bilinear transform, derived from the trapezoidal rule.

Properties of the bilinear transform:

  • Maps the entire jωj\omega-axis (the analog frequency axis) to the unit circle (the digital frequency axis), one-to-one. So no aliasing: every analog frequency is uniquely represented in the digital filter, no overlap.
  • Maps the left half-plane (stable analog) to the inside of the unit circle (stable digital). So a stable analog prototype always becomes a stable digital filter.
  • Distorts the frequency axis: this is frequency warping. The relation between analog frequency Ω\Omega and digital frequency ω\omega is

Ω=2Ttan(ω/2)\Omega = \frac{2}{T}\tan(\omega/2)

For small ω\omega (low frequencies), Ωω/T\Omega \approx \omega/T (linear). At ω=π\omega = \pi (Nyquist), Ω\Omega \to \infty. The whole infinite analog axis squished into the finite digital range.

Rubber-band analogy. Imagine the infinite analog frequency axis as an infinitely long rubber band. The bilinear transform stretches and squishes it nonlinearly to fit on the finite unit circle: low frequencies are barely warped, high frequencies are bent more and more aggressively as they approach the digital Nyquist. Filter shape (e.g., the relative slope of the transition) is preserved if you account for the warping by prewarping your specs.

Prewarping means: if you want digital cutoff ωc\omega_c, design analog prototype with cutoff Ωc=(2/T)tan(ωc/2)\Omega_c = (2/T)\tan(\omega_c/2) before the bilinear transform. Then the bilinear transform places the digital cutoff exactly where you wanted it.

4.5 Impulse invariance, the alternative

Rather than the bilinear transform, you can use impulse invariance: sample the analog impulse response.

hd[n]=Tha(nT)h_d[n] = T\,h_a(nT)

This causes the digital filter's impulse response to be a sampled version of the analog's. It maps poles via z=esTz = e^{sT} (each analog pole at sks_k becomes a digital pole at eskTe^{s_k T}).

Drawback: aliasing. If the analog filter's frequency response extends above π/T\pi/T, those high-frequency tails fold back into the digital passband. Most useful for low-pass filters where the analog response decays well before π/T\pi/T. Used historically and in some specific applications (Bessel filter approximation, where bilinear-transform's frequency warping would distort the all-important phase response).

Bilinear transform is the default for almost everything. Impulse invariance is an option to remember exists.

4.6 Frequency transformations: lowpass to highpass / bandpass / bandstop

You designed a digital lowpass. To get other types:

  • LP → HP. Substitute z1z1z^{-1} \to -z^{-1} in HLP(z)H_{LP}(z). Equivalently, in the analog prototype before bilinear transform, substitute sωc/ss \to \omega_c/s.
  • LP → BP. Substitute s(s2+ω02)/(sΔω)s \to (s^2 + \omega_0^2)/(s\,\Delta\omega) where ω0\omega_0 is band center and Δω\Delta\omega is bandwidth. This doubles the order.
  • LP → BS (band-stop). Substitute ssΔω/(s2+ω02)s \to s\,\Delta\omega/(s^2 + \omega_0^2). Also doubles order.

All available as one-line calls in scipy.signal.

4.7 IIR design in code

The fastest way to design an IIR is in scipy.signal:

python
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
 
fs = 8000          # sample rate, Hz
fc = 1500          # passband edge
fstop = 2000       # stopband edge
gpass = 1.0        # passband ripple, dB
gstop = 40.0       # stopband attenuation, dB
 
# Compute order and natural frequency for Chebyshev-I
N, Wn = signal.cheb1ord(fc/(fs/2), fstop/(fs/2), gpass, gstop)
print(f"Cheby-I order: {N}")
 
# Design as second-order sections (cascade of biquads)
sos = signal.cheby1(N, gpass, Wn, btype='low', output='sos')
 
# Plot magnitude response
w, h = signal.sosfreqz(sos, worN=2048, fs=fs)
plt.semilogx(w, 20*np.log10(np.abs(h)))
plt.xlabel('Frequency (Hz)'); plt.ylabel('Magnitude (dB)')
plt.grid(True, which='both'); plt.show()
 
# Filter a real signal
x = np.random.randn(10000)
y = signal.sosfilt(sos, x)

sos is a N×6N \times 6 array, one row per biquad (numerator coefficients, then denominator). sosfilt runs them in cascade with proper internal scaling. This is what production audio engines look like under the hood.

For Butterworth, replace cheb1ord and cheby1 with buttord and butter. For elliptic: ellipord, ellip. For Bessel (which doesn't have a fixed-order specification; you choose order to balance flatness against rolloff): bessel.