CMP-272 · Lesson 12 of 12 · 24 min

The z-transform and digital filters

The Laplace transform is the natural language of circuits; the z-transform is its counterpart for sampled data and digital filters. It turns difference equations into algebra, explains why a unit delay is drawn as a box labelled z⁻¹, and lets an engineer judge the stability and frequency response of a digital filter by looking at its poles and zeros on a plane. This last lesson uses it to design the filter that finally removes the 60 Hz hum from Amara's microphone channel, to convert an analog filter into a digital one, and to pull together the whole signal chain of the accessible pedestrian signal.

Definition and region of convergence

The z-transform of a discrete-time signal x[n] is

\[X(z) = \sum_{n=-\infty}^{\infty} x[n]\,z^{-n}\]

where z is a complex variable. Writing z = re^(jΩ) shows the connection to the DTFT: on the unit circle, r = 1, the z-transform becomes X(e^(jΩ)), the frequency response or spectrum. Off the circle, the factor r^(−n) damps or amplifies the signal, just as e^(−σt) does in the Laplace transform, so the z-transform exists for signals, such as growing sequences, whose DTFT does not. The sum converges only for some z, the region of convergence. For a causal signal the ROC is the region outside a circle that passes through the outermost pole.

The most important pair is the geometric sequence. For x[n] = aⁿu[n],

\[X(z) = \sum_{n=0}^{\infty} \big(az^{-1}\big)^n = \frac{1}{1 - az^{-1}} = \frac{z}{z - a}, \qquad |z| > |a|\]

Setting a = 1 gives the unit step, u[n] ↔ z/(z − 1), and the unit impulse transforms to 1. Damped and oscillating sequences follow by letting a be complex, just as damped sinusoids followed from complex exponentials in continuous time.

The delay property and transfer functions

Delaying a sequence by one sample multiplies its z-transform by z⁻¹: x[n − 1] ↔ z⁻¹X(z), for a signal at rest beforehand. That is why a unit delay in a block diagram is labelled z⁻¹, as in lesson 5. Applying the property term by term to a linear constant-coefficient difference equation turns it into an algebraic equation, and the ratio of output to input transforms is the transfer function:

\[H(z) = \frac{Y(z)}{X(z)} = \frac{b_0 + b_1 z^{-1} + \cdots + b_M z^{-M}}{1 + a_1 z^{-1} + \cdots + a_N z^{-N}}\]

The numerator coefficients b_k multiply delayed inputs and the denominator coefficients a_k multiply delayed outputs, so the transfer function can be read straight from the code and the code straight from the transfer function. The exponential moving average of lesson 5, y[n] = (1 − α)y[n − 1] + αx[n], has H(z) = α/(1 − (1 − α)z⁻¹) = αz/(z − (1 − α)): a zero at z = 0 and a pole at z = 1 − α.

Poles, zeros and stability in the z-plane

Factoring H(z) gives its zeros and poles, plotted on the z-plane with the unit circle drawn for reference. Each pole p contributes a term pⁿ to the impulse response. If |p| < 1 the term decays, if |p| = 1 it persists, and if |p| > 1 it grows. A causal digital filter is therefore stable if and only if all its poles lie strictly inside the unit circle. FIR filters have all their poles at z = 0 and are always stable; IIR filters must be checked. The exponential moving average has its pole at 1 − α, inside the circle for any α between 0 and 2, and the accumulator has its pole at z = 1, on the circle, which is why it is not BIBO stable.

The link to the s-plane comes from sampling. A continuous-time term e^(pt) sampled every T seconds becomes (e^(pT))ⁿ, so a pole at s = p maps to a pole at z = e^(pT). The left half of the s-plane maps to the inside of the unit circle, the imaginary axis maps to the circle itself, and the right half-plane maps outside. Stable analog filters become stable digital filters, and the further left an s-plane pole is, the closer to the origin its z-plane pole lands.

Reading the frequency response from the plane

Because the frequency response is H(z) on the unit circle, poles and zeros shape it geometrically. Imagine walking around the circle from Ω = 0 (z = 1, DC) to Ω = π (z = −1, the Nyquist frequency). The magnitude of H at each point is proportional to the product of the distances to the zeros divided by the product of the distances to the poles. A zero placed exactly on the circle at angle Ω₀ makes the response zero at that frequency. A pole placed just inside the circle at angle Ω₀ makes the response large near that frequency. The moving average's nulls from lesson 10 are zeros on the unit circle, and a resonator that emphasizes one frequency is a pole pair just inside it.

Designing a notch filter

Amara's analog high-pass filter reduced the 60 Hz hum by only about 11 dB. A digital notch filter can remove it almost completely while leaving the rest of the band untouched. The recipe uses the geometry directly: place a pair of zeros on the unit circle at ±Ω₀, the hum frequency, to null it, and a pair of poles at the same angles but radius r slightly less than 1, so that away from Ω₀ each pole nearly cancels the effect of its neighbouring zero:

\[H(z) = \frac{1 - 2\cos\Omega_0\,z^{-1} + z^{-2}}{1 - 2r\cos\Omega_0\,z^{-1} + r^2 z^{-2}}\]

The closer r is to 1, the narrower the notch: its width is roughly (1 − r)f_s/π hertz. With r too close to 1, though, the filter takes a long time to settle, because its poles' terms rⁿ decay slowly, and rounding of the coefficients in fixed-point arithmetic can push the poles onto or outside the circle.

Left, a z-plane with the unit circle, two zeros marked as circles on the unit circle at small positive and negative angles, and two poles marked as crosses just inside them. Right, the magnitude response in decibels from 0 to 4 kilohertz, flat at 0 decibels except for a deep, narrow notch at 60 hertz.
Pole-zero map and magnitude response of a 60 Hz notch filter at an 8 kHz sampling rate. Zeros on the circle null the hum; poles just inside keep the notch narrow.

Worked problem

Coefficients of the hum notch

Design a notch for 60 Hz at f_s = 8 kHz with r = 0.99, write its difference equation and estimate the notch width.

Show solution
  1. Convert the frequency to radians per sample.
  2. \[\Omega_0 = 2\pi\,\frac{60}{8000} = 0.04712, \qquad \cos\Omega_0 = 0.998890\]
  3. Substitute into the transfer function: 2cos Ω₀ = 1.997780, 2r cos Ω₀ = 1.977802 and r² = 0.9801.
  4. \[y[n] = x[n] - 1.997780\,x[n-1] + x[n-2] + 1.977802\,y[n-1] - 0.9801\,y[n-2]\]
  5. \[\text{width} \approx \frac{(1 - r)f_s}{\pi} = \frac{0.01 \times 8000}{\pi} \approx 25\ \text{Hz}\]

Answer: The filter needs five multiplications and four stored values per sample. Its notch is about 25 Hz wide, centred on 60 Hz, so the 880 Hz locator tone and the traffic noise band pass essentially unchanged. The coefficients need about six significant digits; with 16-bit fixed-point arithmetic Daniel stores them in a format with 14 fractional bits and checks the pole radius after rounding.

From analog to digital: the bilinear transform

Engineers often start from a proven analog design, such as a Butterworth filter, and convert it. Lesson 5's backward difference works only when the sampling interval is much shorter than the filter's time constants. The bilinear transform is better: it substitutes

\[s = \frac{2}{T}\,\frac{1 - z^{-1}}{1 + z^{-1}}\]

into H(s). It maps the whole imaginary axis onto the unit circle exactly once, so a stable analog filter always gives a stable digital filter and there is no aliasing of the frequency response. The price is that the frequency axis is warped: analog frequency ω_a and digital frequency Ω are related by ω_a = (2/T)tan(Ω/2). To make a corner land at the right digital frequency, the designer prewarps it, choosing the analog corner from that formula before converting. Near DC the warping is negligible; near the Nyquist frequency it is severe.

Worked problem

Converting the RC filter

Convert H(s) = 1/(1 + s/ω_c) with f_c = 995 Hz to a digital filter at f_s = 8 kHz with the bilinear transform, prewarping the corner.

Show solution
  1. Prewarp: the digital corner is Ω_c = 2π(995/8000) = 0.7815 rad per sample.
  2. \[\omega_a = \frac{2}{T}\tan\frac{\Omega_c}{2} = 16000\tan(0.3907) \approx 6{,}591\ \text{rad/s}\]
  3. Substitute s = (2/T)(1 − z⁻¹)/(1 + z⁻¹) with K = (2/T)/ω_a = 16000/6591 ≈ 2.428.
  4. \[H(z) = \frac{1 + z^{-1}}{(1 + K) + (1 - K)z^{-1}} = \frac{0.2917\,(1 + z^{-1})}{1 - 0.4165\,z^{-1}}\]

Answer: y[n] = 0.4165y[n − 1] + 0.2917(x[n] + x[n − 1]). The pole is at z = 0.4165, inside the circle, and the zero at z = −1 makes the response exactly zero at the Nyquist frequency, a bonus that the analog prototype cannot offer.

The whole signal chain

Amara's final design for the accessible pedestrian signal uses nearly every idea in this course. The microphone feeds an analog high-pass filter that takes the edge off the 60 Hz hum and a fourth-order Butterworth anti-aliasing filter with a 2 kHz corner (lessons 8 and 9). The ADC samples at 8 kHz. In firmware, the hum notch removes what remains of the 60 Hz interference (this lesson). Every 50 ms, a 400-sample block is windowed and transformed with an FFT; bins from 300 Hz to 3 kHz, excluding a band around the 880 Hz tick, give the street noise level, and bin 44 gives the tick level (lesson 10). The noise level is smoothed by an exponential moving average (lesson 5) and fed to the volume loop, whose gain is limited for good damping (lesson 11). On the tachometer, a four-point moving average whose nulls cancel the pump's 5 Hz wobble cleans the speed reading (lessons 3 and 10). None of these steps is complicated on its own. What the course provides is the ability to predict, before writing a line of firmware, what each one will do.

The 60 Hz notch filter: its magnitude response at several frequencies, a stability check and its effect on hum plus a quiet locator tone.
import cmath, math

fs, f0, r = 8000.0, 60.0, 0.99
W0 = 2 * math.pi * f0 / fs
b = [1.0, -2 * math.cos(W0), 1.0]
a = [1.0, -2 * r * math.cos(W0), r * r]

def H(f):
    z = cmath.exp(1j * 2 * math.pi * f / fs)
    return (b[0] + b[1] / z + b[2] / z**2) / (a[0] + a[1] / z + a[2] / z**2)

for f in (0, 40, 50, 60, 70, 80, 880, 4000):
    g = abs(H(f))
    print(f"{f:5d} Hz: {20*math.log10(g) if g > 1e-12 else float('-inf'):8.1f} dB")

poles = [r * cmath.exp(1j * W0), r * cmath.exp(-1j * W0)]
print("pole radius", round(abs(poles[0]), 4), "-> stable" if all(abs(p) < 1 for p in poles) else "-> unstable")

# Filter one second of hum plus a quiet 880 Hz tone
x = [0.5 * math.cos(2 * math.pi * 60 * n / fs) + 0.05 * math.cos(2 * math.pi * 880 * n / fs)
     for n in range(8000)]
y = [0.0] * len(x)
for n in range(len(x)):
    y[n] = (b[0] * x[n] + (b[1] * x[n - 1] if n >= 1 else 0) + (b[2] * x[n - 2] if n >= 2 else 0)
            - (a[1] * y[n - 1] if n >= 1 else 0) - (a[2] * y[n - 2] if n >= 2 else 0))
def rms(v):
    return math.sqrt(sum(t * t for t in v) / len(v))
print(f"input RMS {rms(x[4000:]):.4f}, output RMS {rms(y[4000:]):.4f} (tone alone: {0.05/math.sqrt(2):.4f})")
Output
    0 Hz:     -0.3 dB
   40 Hz:     -1.5 dB
   50 Hz:     -4.2 dB
   60 Hz:     -inf dB
   70 Hz:     -4.2 dB
   80 Hz:     -1.4 dB
  880 Hz:      0.1 dB
 4000 Hz:      0.1 dB
pole radius 0.99 -> stable
input RMS 0.3553, output RMS 0.0357 (tone alone: 0.0354)

The notch is infinitely deep at exactly 60 Hz, about 4 dB down 10 Hz either side and only about 1.5 dB down 20 Hz either side, which matches the estimated width of 25 Hz between the −3 dB points. At DC the loss is a third of a decibel, and at 880 Hz and 4 kHz the gain is within 0.1 dB of unity. The poles sit at radius 0.99, safely inside the circle. On the test signal, the hum dominates the input, but after the filter has settled the output RMS matches the quiet tone alone, so the hum has been removed and the tone kept. A deep notch built from five multiplications per sample is a small piece of code with a large effect, which is a fair summary of digital signal processing.

Common mistakes

  • MistakePlacing the poles of a notch on the unit circle.

    InsteadPoles must be strictly inside the circle for stability; only the zeros go on the circle.

  • MistakeForgetting to prewarp when using the bilinear transform.

    InsteadWithout prewarping, the digital corner lands below the intended frequency, badly so near the Nyquist frequency.

  • MistakeAssuming coefficient rounding is harmless in IIR filters.

    InsteadPoles close to the circle are sensitive; check the pole radius after quantizing coefficients.

  • MistakeReading H(z) off the code with the wrong sign for feedback terms.

    InsteadIn H(z) = B(z)/(1 + a₁z⁻¹ + …), y[n] = … − a₁y[n − 1] − …; signs flip between the two forms.

  • MistakeJudging stability from |H(e^(jΩ))|.

    InsteadA filter can have a reasonable-looking response on the circle and still be unstable; check that every pole has magnitude less than 1.

Summary and key terms

  • The z-transform X(z) = Σx[n]z^(−n) generalizes the DTFT; on the unit circle it gives the frequency response.
  • A one-sample delay multiplies by z⁻¹, so difference equations become rational transfer functions H(z).
  • A causal digital filter is stable if and only if all its poles lie inside the unit circle; z = e^(sT) maps the left half s-plane inside the circle.
  • Zeros on the unit circle null frequencies; poles just inside the circle emphasize them, and together they make notch filters.
  • The bilinear transform converts analog designs to stable digital ones, with prewarping to place critical frequencies correctly.
  • Real systems chain analog filters, sampling, digital filters, FFT analysis and feedback, each predictable with the tools of this course.
z-transform
X(z) = Σx[n]z^(−n), the transform of a discrete-time signal as a function of a complex variable z.
Unit circle
The circle |z| = 1 in the z-plane, on which the z-transform equals the DTFT.
Notch filter
A filter that removes a narrow band around one frequency and passes the rest.
Bilinear transform
The substitution s = (2/T)(1 − z⁻¹)/(1 + z⁻¹) used to convert analog filters to digital ones.
Prewarping
Adjusting an analog design frequency so that the bilinear transform places it at the intended digital frequency.
Coefficient quantization
Rounding filter coefficients to a finite word length, which can move poles and zeros.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. Find the z-transform of x[n] = 0.5ⁿu[n] − δ[n − 2].

    Show answer

    z/(z − 0.5) − z⁻², with |z| > 0.5.

  2. Write H(z) for y[n] = 0.9y[n − 1] + x[n] − x[n − 1]. Where are its pole and zero?

    Show answer

    H(z) = (1 − z⁻¹)/(1 − 0.9z⁻¹); zero at z = 1, pole at z = 0.9. It is a high-pass filter that blocks DC.

  3. Is a filter with poles at 0.5 ± j0.9 stable?

    Show answer

    No; |0.5 + j0.9| ≈ 1.03 > 1.

  4. An analog pole at s = −1,000 rad/s is sampled at T = 0.1 ms. Where does it land in the z-plane?

    Show answer

    z = e^(−0.1) ≈ 0.905.

  5. Design notch zeros for 50 Hz hum at f_s = 1 kHz.

    Show answer

    Zeros at e^(±j2π(0.05)) = e^(±j0.314) on the unit circle.

  6. Why does a notch with r = 0.999 take longer to settle than one with r = 0.99?

    Show answer

    Its pole terms decay as 0.999ⁿ, which takes about 1,000 samples per time constant instead of about 100.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz