Z-Transform and Digital Filters: FIR vs IIR with Worked Examples
The z-transform does for discrete-time signals what the Laplace transform does for continuous ones: it turns difference equations into algebra and reveals stability and frequency response through poles and zeros. It is the language of digital filters running on microcontrollers, DSP chips and FPGAs. This tutorial covers the definition, the region of convergence, the key pairs and properties, an inverse transform by partial fractions, and then designs and compares a simple FIR filter and a simple IIR filter, ending with C code that implements both.
Definition, Pairs and Region of Convergence
X(z) = Σ x[n] z^(-n) (sum over all n), z is a complex variable Key property (delay): x[n - k] -> z^(-k) X(z)
The delay property is why z^-1 is drawn as a unit delay block in filter diagrams. The sum converges only for some values of z, called the region of convergence (ROC). The same algebraic X(z) can correspond to different signals with different ROCs, so the ROC is part of the answer.
| x[n] | X(z) | ROC |
|---|---|---|
| δ[n] | 1 | All z |
| u[n] | z/(z - 1) | |z| > 1 |
| a^n u[n] | z/(z - a) | |z| > |a| |
| -a^n u[-n - 1] | z/(z - a) | |z| < |a| |
| n a^n u[n] | az/(z - a)^2 | |z| > |a| |
| δ[n - k] | z^(-k) | All z except 0 (k > 0) |
For a causal signal the ROC is outside the outermost pole. An LTI system is stable if its ROC includes the unit circle |z| = 1. Combining the two, a causal system is stable when all poles lie strictly inside the unit circle, the discrete counterpart of the left half-plane rule for Laplace.
Worked Example: Inverse Z-Transform
X(z) = z / ((z - 1)(z - 0.5)), ROC |z| > 1 (causal) Expand X(z)/z, not X(z): X(z)/z = 1/((z - 1)(z - 0.5)) = 2/(z - 1) - 2/(z - 0.5) X(z) = 2z/(z - 1) - 2z/(z - 0.5) x[n] = 2u[n] - 2(0.5)^n u[n] Check by long division: x[0] = 0, x[1] = 1, x[2] = 1.5 Formula: x[0] = 2 - 2 = 0, x[1] = 2 - 1 = 1, x[2] = 2 - 0.5 = 1.5
Dividing by z first is the standard trick: it makes every partial fraction term become az/(z - p) after multiplying back, which matches the table directly.
Link to the Laplace transform and real frequencies
If a continuous signal is sampled every T seconds, the z-transform is the Laplace transform of the sampled signal with z = e^(sT). This mapping sends the jω axis of the s-plane onto the unit circle and the stable left half-plane into the inside of the circle, which is why the two stability rules match. Points on the unit circle are written z = e^(jω), where the digital frequency ω in radians per sample relates to real frequency f by ω = 2πf/fs. For example, with fs = 1 kHz, ω = π/2 corresponds to 250 Hz and ω = π to the Nyquist frequency of 500 Hz. Keep this conversion handy: filter specifications are given in hertz, but H(z) works in radians per sample.
From Difference Equation to Frequency Response
A digital filter is described by a difference equation that combines current and past inputs, and possibly past outputs. Taking the z-transform of both sides and using the delay property gives the transfer function H(z) = Y(z)/X(z). Setting z = e^(jω), where ω runs from 0 to π (π corresponds to half the sampling rate), gives the frequency response.
FIR example: two-point average
y[n] = 0.5 x[n] + 0.5 x[n - 1] H(z) = 0.5 (1 + z^(-1)) zero at z = -1, no poles except z = 0 |H| at ω = 0 : 0.5 |1 + 1| = 1 (DC passes) |H| at ω = π/2 : 0.5 |1 + e^(-jπ/2)| = 0.707 (-3 dB at fs/4) |H| at ω = π : 0.5 |1 - 1| = 0 (Nyquist blocked)
IIR example: first-order low-pass (exponential smoother)
y[n] = a y[n - 1] + (1 - a) x[n], choose a = 0.9 H(z) = (1 - a) / (1 - a z^(-1)) = 0.1 / (1 - 0.9 z^(-1)) pole at z = 0.9 |H| at ω = 0 : 0.1 / (1 - 0.9) = 1 |H| at ω = π : 0.1 / (1 + 0.9) = 0.053 Impulse response h[n] = 0.1 (0.9)^n u[n] -> never exactly zero
The pole at 0.9 is inside the unit circle, so the filter is stable. Move a closer to 1 and the pole approaches the circle: the filter smooths more heavily but responds more slowly. With a = 1 or greater it becomes unstable. This single line of code is one of the most common filters in embedded firmware, used to smooth ADC readings.
FIR versus IIR
| Feature | FIR | IIR |
|---|---|---|
| Impulse response | Finite length | Infinite, decays over time |
| Uses past outputs (feedback) | No | Yes |
| Poles | Only at z = 0, always stable | Anywhere; must be inside unit circle |
| Phase | Exactly linear if coefficients are symmetric | Non-linear in general |
| Order for a sharp cutoff | High, many multiplies per sample | Low, few multiplies per sample |
| Sensitivity to coefficient rounding | Low | Higher, especially for high order |
| Typical design methods | Windowing, Parks-McClellan | Bilinear transform of Butterworth or Chebyshev prototypes |
Choose FIR when phase linearity matters, as in audio crossovers, data communication pulse shaping and ECG processing, or when guaranteed stability is important. Choose IIR when computing power is limited and a sharp magnitude response is enough, as in simple sensor smoothing or tone detection. High-order IIR filters are usually implemented as cascaded second-order sections to limit coefficient sensitivity.
Both Filters in C
#include <stdio.h>
/* FIR: y[n] = 0.5 x[n] + 0.5 x[n-1] */
typedef struct { float x1; } fir2_t;
float fir2_step(fir2_t *f, float x)
{
float y = 0.5f * x + 0.5f * f->x1;
f->x1 = x; /* store x[n] for the next call */
return y;
}
/* IIR: y[n] = a y[n-1] + (1 - a) x[n] */
typedef struct { float a; float y1; } iir1_t;
float iir1_step(iir1_t *f, float x)
{
float y = f->a * f->y1 + (1.0f - f->a) * x;
f->y1 = y; /* feedback: store y[n] */
return y;
}
int main(void)
{
fir2_t fir = { 0.0f };
iir1_t iir = { 0.9f, 0.0f };
printf("n FIR IIR\n");
for (int n = 0; n < 6; n++) {
float x = (n == 0) ? 1.0f : 0.0f; /* unit impulse */
printf("%d %.5f %.5f\n", n, fir2_step(&fir, x), iir1_step(&iir, x));
}
return 0;
}
n FIR IIR 0 0.50000 0.10000 1 0.50000 0.09000 2 0.00000 0.08100 3 0.00000 0.07290 4 0.00000 0.06561 5 0.00000 0.05905
The output shows the defining difference: the FIR response ends after two samples, while the IIR response decays geometrically by 0.9 each step and never reaches exactly zero.
Summary
- The z-transform turns delays into powers of z^-1, so difference equations become rational functions H(z).
- Always state the ROC; a causal system is stable when every pole is inside the unit circle.
- Evaluate H(z) on the unit circle, z = e^(jω), to get the frequency response.
- FIR filters are always stable and can have linear phase; IIR filters achieve sharp responses with far fewer coefficients but need care with stability and phase.