Matched Filter and Correlator Receiver
Why the Matched Filter Is Fundamental
The matched filter is the optimal linear receiver for detecting a known signal in AWGN. It maximizes the output SNR and is the basis of every receiver from BPSK detectors to radar pulse compressors. Understanding the matched filter connects modulation theory to practical implementation.
Definition: Matched Filter
Matched Filter
The matched filter for a known signal of duration has impulse response:
The output at time is:
which is the correlation of the received signal with the template. In discrete time:
def matched_filter(received, template):
"""Correlator receiver: inner product with template."""
return np.sum(received * np.conj(template))
Definition: Bank of Correlators
Bank of Correlators
For -ary detection, the receiver computes correlations and picks the largest:
This is equivalent to ML detection when all symbols have equal energy.
def correlator_bank(received_block, templates):
"""Correlator bank: returns detected symbol index."""
correlations = np.array([
np.real(np.sum(received_block * np.conj(t)))
for t in templates
])
return np.argmax(correlations)
Definition: Output SNR of the Matched Filter
Output SNR of the Matched Filter
The matched filter output SNR is:
where is the signal energy. This depends only on the signal energy, not its shape.
Theorem: Matched Filter Maximizes Output SNR
Among all linear filters , the matched filter maximizes the output signal-to-noise ratio. By the Cauchy-Schwarz inequality:
with equality when for any .
The matched filter "collects" all the signal energy while weighting the noise optimally. It is the time-domain analog of the water-filling solution.
Cauchy-Schwarz
with equality iff . For the signal component, , so the optimal .
SNR expression
. Maximized when .
Theorem: Matched Filter and Correlator Equivalence
The matched filter output sampled at equals the correlator output:
Both implementations produce identical decisions. The matched filter is an LTI system (filter then sample); the correlator multiplies then integrates (no filtering).
Convolution with a time-reversed conjugate is the same as correlation. The matched filter is better for continuous-time hardware; the correlator is natural in DSP where you have the samples in memory.
Theorem: Sufficient Statistic for AWGN Detection
The matched filter outputs form a sufficient statistic for detection: no other processing of can improve the error probability. The noise in the matched filter output orthogonal to the signal subspace carries no information about which symbol was sent.
The matched filter projects onto the signal subspace, discarding the noise component orthogonal to all signals.
Example: BPSK Matched Filter Implementation
Implement a matched filter receiver for BPSK with raised-cosine pulse shaping. Show that the matched filter output SNR matches .
Pulse shape and matched filter
import numpy as np
from scipy.signal import fftconvolve
# Raised-cosine pulse
sps = 8 # samples per symbol
beta = 0.35 # roll-off factor
span = 6 # pulse spans 6 symbols
t = np.arange(-span*sps, span*sps+1) / sps
rc_pulse = np.sinc(t) * np.cos(np.pi*beta*t) / (1 - (2*beta*t)**2 + 1e-10)
rc_pulse /= np.sqrt(np.sum(rc_pulse**2)) # unit energy
# Matched filter = time-reversed conjugate
mf = rc_pulse[::-1] # real pulse, so just reverse
Transmit, receive, detect
N_bits = 10000
bits = np.random.randint(0, 2, N_bits)
symbols = 2 * bits - 1 # BPSK: +1/-1
# Upsample and pulse-shape
tx = np.zeros(N_bits * sps)
tx[::sps] = symbols
tx_shaped = fftconvolve(tx, rc_pulse, mode='same')
# Add noise
EbN0_dB = 10
EbN0 = 10**(EbN0_dB/10)
sigma = np.sqrt(1 / (2*EbN0))
noise = sigma * np.random.randn(len(tx_shaped))
rx = tx_shaped + noise
# Matched filter
mf_out = fftconvolve(rx, mf, mode='same')
decisions = mf_out[::sps] > 0
ber = np.mean(bits != decisions.astype(int))
print(f"BER = {ber:.5f}")
Example: Eye Diagram from Matched Filter Output
Generate an eye diagram from the matched filter output to visualize inter-symbol interference and noise margin.
Implementation
import matplotlib.pyplot as plt
# Overlay segments of length 2T
fig, ax = plt.subplots(figsize=(8, 4))
segment_len = 2 * sps
for i in range(100):
start = i * sps + sps // 2
if start + segment_len > len(mf_out):
break
segment = mf_out[start:start+segment_len]
t_axis = np.arange(segment_len) / sps
ax.plot(t_axis, segment, color='blue', alpha=0.1, linewidth=0.5)
ax.set_xlabel('Time (symbol periods)')
ax.set_ylabel('Amplitude')
ax.set_title('Eye Diagram')
Interpretation
The eye opening at the sampling instant shows the noise margin. A wide-open eye indicates good ISI suppression and high SNR.
Matched Filter Output Visualization
Visualize the matched filter operation: input signal, filter, and output with sampling instants marked.
Parameters
Common Mistake: Not Normalizing the Matched Filter
Mistake:
Using np.correlate(rx, pulse) without normalizing the pulse
energy, leading to incorrect SNR measurements.
Correction:
Normalize the pulse to unit energy: pulse /= np.sqrt(np.sum(pulse**2)).
The matched filter output then directly gives the sufficient statistic.
Why This Matters: Matched Filtering in RAKE Receivers
In CDMA systems, the RAKE receiver applies matched filtering independently to each multipath component, then combines the outputs. Each RAKE finger is a correlator matched to the spreading code, time-aligned to a different path delay. This extracts the multipath diversity that a single correlator would miss.
See full treatment in Chapter 21
Matched Filter
A linear filter whose impulse response is the time-reversed conjugate of the target signal, . Maximizes output SNR in AWGN.
Correlator Receiver
A receiver that multiplies the received signal by each possible template and integrates, selecting the template with largest output.
Eye Diagram
A visualization of overlaid symbol-period segments of a signal, showing the noise margin, timing jitter, and ISI at a glance.