Low-Pass Filter Design and Comparison: Moving Average, Butterworth, and Chebyshev

Design and compare three types of low-pass filters (moving average, Butterworth, Chebyshev) in Python, analyzing frequency response, group delay, and step response.

Introduction

The low-pass filter (LPF) is one of the most fundamental building blocks in signal processing. It passes frequency components below a cutoff frequency while attenuating higher-frequency noise.

This article examines three representative low-pass filters:

  1. Moving average filter (FIR): The simplest structure with linear phase
  2. Butterworth filter (IIR): Maximally flat magnitude response in the passband
  3. Chebyshev Type I filter (IIR): Sharper transition band at the cost of passband ripple

We derive the theoretical basis for each, then design and compare them in Python.

Moving Average Filter

The moving average filter is an FIR filter that outputs the arithmetic mean of the most recent \(N\) samples.

Transfer Function

Given an input signal \(x[n]\), the output is defined as:

\[y[n] = \frac{1}{N}\sum_{k=0}^{N-1} x[n-k] \tag{1}\]

Applying the Z-transform yields the transfer function:

\[H(z) = \frac{1}{N}\sum_{k=0}^{N-1} z^{-k} = \frac{1}{N} \cdot \frac{1 - z^{-N}}{1 - z^{-1}} \tag{2}\]

Frequency Response

Substituting \(z = e^{j\omega}\) gives the frequency response:

\[H(e^{j\omega}) = \frac{1}{N} \cdot \frac{1 - e^{-jN\omega}}{1 - e^{-j\omega}} = \frac{1}{N} \cdot \frac{\sin(N\omega/2)}{\sin(\omega/2)} \cdot e^{-j(N-1)\omega/2} \tag{3}\]

The magnitude response is \(\frac{1}{N}\left|\frac{\sin(N\omega/2)}{\sin(\omega/2)}\right|\), which has a sinc-like shape. This means the moving average filter provides only modest stopband attenuation and poor frequency selectivity. However, the phase response is \(-(N-1)\omega/2\), giving it perfectly linear phase — a significant advantage when waveform fidelity matters.

Butterworth Filter

The Butterworth filter is an IIR filter with the maximally flat magnitude response in the passband.

Magnitude Response

The squared magnitude of an \(N\)-th order Butterworth filter is defined as:

\[|H(j\omega)|^2 = \frac{1}{1 + \left(\frac{\omega}{\omega_c}\right)^{2N}} \tag{4}\]

where \(\omega_c\) is the cutoff frequency and \(N\) is the filter order.

From this expression we can observe:

  • At \(\omega = 0\): \(|H| = 1\) (unity DC gain)
  • At \(\omega = \omega_c\): \(|H| = 1/\sqrt{2}\) (\(-3\) dB point)
  • Higher order \(N\) yields a steeper transition band

The Butterworth filter has no ripple in either the passband or stopband, which makes it a versatile general-purpose filter.

Design

In Python, scipy.signal.butter provides a convenient design function:

from scipy.signal import butter
b, a = butter(N=4, Wn=0.3)  # 4th order, normalized cutoff 0.3

Chebyshev Type I Filter

The Chebyshev Type I filter is an IIR filter with equiripple behavior in the passband, based on Chebyshev polynomials.

Magnitude Response

The squared magnitude of an \(N\)-th order Chebyshev Type I filter is:

\[|H(j\omega)|^2 = \frac{1}{1 + \varepsilon^2 T_N^2\left(\frac{\omega}{\omega_c}\right)} \tag{5}\]

where \(\varepsilon\) controls the ripple amplitude and \(T_N\) is the \(N\)-th order Chebyshev polynomial, defined by the recurrence:

\[T_0(x) = 1, \quad T_1(x) = x, \quad T_{n+1}(x) = 2xT_n(x) - T_{n-1}(x) \tag{6}\]

In the passband (\(\omega \le \omega_c\)), \(T_N\) oscillates between \(-1\) and \(1\), introducing ripple in the magnitude response. The trade-off is a steeper transition band compared to a Butterworth filter of the same order.

Design

In Python, scipy.signal.cheby1 is used. The rp parameter specifies the maximum passband ripple in dB:

from scipy.signal import cheby1
b, a = cheby1(N=4, rp=1, Wn=0.3)  # 4th order, 1 dB ripple, normalized cutoff 0.3

Python Comparison

The following code designs all three filters under the same conditions and compares their frequency response, group delay, and step response.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import (
    butter, cheby1, freqz, group_delay, dstep, dlti
)

# --- Filter design ---
N_ORDER = 4        # Filter order
WN = 0.3           # Normalized cutoff frequency (relative to Nyquist)
N_MA = 13          # Moving average tap count (odd recommended)
RP = 1.0           # Chebyshev Type I passband ripple [dB]

# Moving average filter
b_ma = np.ones(N_MA) / N_MA
a_ma = [1.0]

# Butterworth filter
b_bw, a_bw = butter(N_ORDER, WN)

# Chebyshev Type I filter
b_cb, a_cb = cheby1(N_ORDER, RP, WN)

filters = [
    ("Moving Average (N=13)", b_ma, a_ma),
    ("Butterworth (N=4)", b_bw, a_bw),
    ("Chebyshev I (N=4, rp=1dB)", b_cb, a_cb),
]

# --- 1. Frequency response ---
fig, ax = plt.subplots(figsize=(8, 5))
for label, b, a in filters:
    w, h = freqz(b, a, worN=2048)
    freq = w / np.pi  # Normalized frequency
    mag_db = 20 * np.log10(np.abs(h) + 1e-12)
    ax.plot(freq, mag_db, label=label)

ax.set_xlabel("Normalized Frequency (×π rad/sample)")
ax.set_ylabel("Magnitude (dB)")
ax.set_title("Frequency Response Comparison")
ax.set_xlim(0, 1)
ax.set_ylim(-60, 5)
ax.axvline(WN, color="gray", linestyle="--", alpha=0.5, label=f"Cutoff = {WN}")
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.show()

# --- 2. Group delay ---
fig, ax = plt.subplots(figsize=(8, 5))
for label, b, a in filters:
    w, gd = group_delay((b, a), w=2048)
    freq = w / np.pi
    ax.plot(freq, gd, label=label)

ax.set_xlabel("Normalized Frequency (×π rad/sample)")
ax.set_ylabel("Group Delay (samples)")
ax.set_title("Group Delay Comparison")
ax.set_xlim(0, 1)
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.show()

# --- 3. Step response ---
fig, ax = plt.subplots(figsize=(8, 5))
n_steps = 60
for label, b, a in filters:
    system = dlti(b, a, dt=1)
    t, y = dstep(system, n=n_steps)
    ax.step(t[0].flatten(), y[0].flatten(), label=label, where="post")

ax.set_xlabel("Sample")
ax.set_ylabel("Amplitude")
ax.set_title("Step Response Comparison")
ax.axhline(1.0, color="gray", linestyle="--", alpha=0.5)
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.show()

Frequency response comparison

Group delay comparison

Step response comparison

Reading the Frequency Response

  • The moving average filter shows shallow stopband attenuation; high frequencies leak through except at null (zero) positions.
  • The Butterworth filter has a flat passband with a smooth, moderate roll-off.
  • The Chebyshev Type I filter has passband ripple but achieves the sharpest transition band.

Reading the Group Delay

  • The moving average filter has constant group delay across all frequencies (\((N-1)/2\) samples) due to its linear phase.
  • Both the Butterworth and Chebyshev Type I filters exhibit increasing group delay near the cutoff frequency, indicating nonlinear phase.

Reading the Step Response

  • The moving average filter reaches steady state with no overshoot.
  • The Butterworth filter shows slight overshoot before settling.
  • The Chebyshev Type I filter exhibits the largest overshoot due to passband ripple.

Filter Selection Guide

PropertyMoving AverageButterworthChebyshev Type I
PassbandFlatMaximally flatEquiripple
Transition bandGradualModerateSharp
Stopband attenuationShallowModerateDeep
PhaseLinearNonlinearNonlinear
Group delayConstantFrequency-dependentFrequency-dependent
Computational costLowModerateModerate
Primary use caseNoise smoothingGeneral-purpose filteringSharp cutoff required

Guidelines for choosing a filter:

  • When phase distortion must be avoided (waveform shape matters) — Moving average filter
  • When passband flatness is critical (faithful reproduction of measurement signals) — Butterworth filter
  • When the transition band must be as narrow as possible (separating adjacent frequency components) — Chebyshev Type I filter

Conclusion

This article presented the theoretical background and design methods for three low-pass filters — moving average, Butterworth, and Chebyshev Type I — and compared their frequency response, group delay, and step response using Python.

Each filter has its own strengths and weaknesses; choosing the right one depends on the requirements of the application. For related material on the EMA filter (a first-order IIR filter), see also Frequency Characteristics of the Exponential Moving Average Filter. For a systematic overview of state-space model-based filtering methods (Kalman filter, EKF, UKF, particle filter), see Fundamentals of Filtering Methods in Signal Processing.

References