Skip to content
Radar Systems

Waveforms and pulse compression: matched filter proved, chirp, Barker codes and ambiguity function

The matched filter proved with Cauchy-Schwarz, the linear chirp and the compression ratio, sidelobes and the Hamming window, Barker codes, Woodward's ambiguity function, with a simple analogy and the simulation in Python.

The radar equation asks for energy to see far; range resolution asks for bandwidth, that is short pulses. With a simple pulse of duration \tau the two requirements conflict: a short pulse carries little energy, unless the peak power is huge. Pulse compression resolves the conflict: a long pulse is transmitted, but with an internal modulation that makes it “wide in bandwidth”, and in reception it is compressed by a matched filter. This lesson proves that the matched filter is the optimum receiver, analyses the linear chirp and the Barker codes, and introduces the ambiguity function, which describes at once the range and velocity resolution of any waveform.

The idea in simple words

Imagine having to recognise a friend’s whistle in a noisy room. If the whistle is a very short sharp blast, it gets lost in the noise. If instead it is a long tune you know well, you recognise it even when it is faint: your brain compares what it hears with the tune it expects, note by note, and adds up all the small similarities. This is exactly what the matched filter does: it compares the received signal with a copy of the transmitted one, instant by instant, and gives a peak when the two match.

The chirp is the most used “tune”: a whistle whose pitch rises steadily, like a bird’s song (hence the name). The radar transmits a long chirp, hence with plenty of energy; when the receiver compares it with the copy, all that energy is concentrated in a very narrow peak, as if the radar had transmitted a very short and very powerful pulse. Range (energy) and precision (narrow peak) are obtained together.

The matched filter

The receiver gets r(t) = s(t) + n(t), with s(t) the expected echo and n(t) white noise of spectral density N_0/2. We look for the linear filter h(t) that maximises the output signal-to-noise ratio at an instant t_0.

Theorem (matched filter). The optimum filter is h(t) = s^*(t_0 - t), the time-reversed and conjugated replica of the signal, and the maximum signal-to-noise ratio is \frac{2E}{N_0}, with E the signal energy.

Proof. At the output, in the frequency domain, the signal is y_s(t_0) = \int H(f)S(f)e^{j2\pi ft_0}df and the noise power is \frac{N_0}{2}\int|H(f)|^2df. By the Cauchy-Schwarz inequality \big|\int H(f)\,S(f)e^{j2\pi ft_0}df\big|^2 \le \int|H(f)|^2df\cdot\int|S(f)|^2df, hence

    \[ SNR = \frac{|y_s(t_0)|^2}{\frac{N_0}{2}\int|H|^2df} \le \frac{2}{N_0}\int|S(f)|^2df = \frac{2E}{N_0} \]

Equality holds if H(f) = S^*(f)e^{-j2\pi ft_0}, which in time is h(t) = s^*(t_0 - t). ∎

The result is remarkable: the optimum signal-to-noise ratio depends only on the energy of the signal, not on its shape. The shape can therefore be chosen to obtain the desired resolution, without losing sensitivity. Filtering with s^*(t_0 - t) is the same as computing the correlation between the received and the transmitted signal: the output peaks at the echo delay.

The linear chirp

The chirp (linear frequency modulation, LFM) is a pulse of duration T whose frequency rises linearly by B: s(t) = e^{j\pi(B/T)t^2} for |t| \lt  T/2. After the matched filter the compressed pulse has the shape of a sinc about 1/B wide (at −3 dB, 0.886/B): the resolution is that of a pulse of duration 1/B, with the energy of a pulse of duration T. The compression ratio is BT, the duration × bandwidth product.

Example. T = 20 μs and B = 10 MHz: BT = 200. The compressed signal has a −3 dB width of 85 ns (against 0.886/B = 89 ns from theory: the small difference is due to sampling) and a resolution of 12.7 m, while the transmitted pulse is 3 km long. With the same peak power, a simple 85 ns pulse would carry 235 times less energy.

Sidelobes. The sinc has sidelobes at −13.2 dB: a strong echo can hide a weak target nearby. A window (Hamming, Taylor) is applied to the receive filter: with the Hamming window the sidelobes drop to −42 dB, at the cost of a wider peak (135 ns instead of 85, about 60 % more) and a small loss of gain. It is the same trade-off as windows in spectral analysis.

The chirp after the matched filter
In blue the matched filter output, in decibels, around the peak: a sinc with sidelobes at minus 13 dB. In orange the same output with the Hamming window: a slightly wider peak but sidelobes below minus 40 dB.

The chirp has two valuable practical properties: it is easy to generate (with voltage-controlled oscillators or direct digital synthesis) and it is Doppler tolerant: an echo from a moving target is still well compressed, only slightly shifted in range (the range-Doppler coupling). It is the waveform of the FMCW car radars (lesson on FMCW radars).

Phase codes

Alternatively the pulse is split into N sub-pulses (“chips”) with phase 0 or π according to a code. Barker codes have the ideal autocorrelation for binary sequences: peak N and sidelobes of magnitude at most 1. The longest known has length 13:

    \[ +1\ +1\ +1\ +1\ +1\ -1\ -1\ +1\ +1\ -1\ +1\ -1\ +1 \]

with autocorrelation 1, 0, 1, 0, \dots, 13, \dots, 0, 1 and therefore a peak-to-sidelobe ratio of 20\log_{10}13 = 22.3 dB. For larger compression ratios, polyphase codes (Frank, P4) or long pseudo-random sequences are used, and in modern digital radars waveforms designed by computer.

The ambiguity function

The matched filter is matched to an echo with a given delay and a given Doppler. If the echo has a different Doppler \nu, the output changes. Woodward’s ambiguity function describes the output as a function of both:

    \[ \chi(\tau, \nu) = \int s(t)\,s^*(t - \tau)\,e^{j2\pi\nu t}\,dt \]

|\chi(\tau, 0)| is the range response (the compression), |\chi(0, \nu)| the velocity response. A theorem by Woodward states that the volume \iint|\chi|^2d\tau\,d\nu is the same for all waveforms with the same energy: the ambiguity cannot be squeezed into a single point, only moved elsewhere. The chirp has a “tilted ridge” function (the range-Doppler coupling); a pulse train has a “bed of nails” function, with the range and velocity ambiguities of the lessons on the radar equation and on Doppler. Choosing the waveform is therefore choosing which ambiguities are acceptable for the application.

Summary

  • The matched filter is the best possible receiver for a known signal in noise: it compares what is received with the copy of what was transmitted (correlation).
  • The signal-to-noise ratio it achieves depends only on the signal energy, not on its shape.
  • A long modulated pulse (chirp or phase code) carries plenty of energy and, after compression, gives the resolution of a short pulse: \Delta R \approx c/2B.
  • The sidelobes of the compressed peak are lowered with a window, at the cost of a slightly wider peak.
  • The ambiguity function shows how each waveform responds to range and velocity errors together; total ambiguity cannot be removed, only moved.

The code

import numpy as np

fs, T, B = 200e6, 20e-6, 10e6                       # sampling rate, chirp duration and bandwidth
t = np.arange(0, T, 1 / fs)
chirp = np.exp(1j * np.pi * B / T * (t - T / 2) ** 2)
received = np.r_[np.zeros(4000), chirp, np.zeros(4000)]          # isolated echo, no noise

def compress(window):
    y = np.abs(np.correlate(received, chirp * window, mode="same"))   # matched filter = correlation
    return y / y.max()

for name, w in (("rectangular", np.ones(len(chirp))), ("Hamming", np.hamming(len(chirp)))):
    p = compress(w)
    k = np.argmax(p)
    above = np.where(p >= 1 / np.sqrt(2))[0]                       # samples above -3 dB
    width = (above[-1] - above[0] + 1) / fs
    guard = int((1.5 if name == "rectangular" else 2.5) * fs / B)
    lobes = np.r_[p[:k - guard], p[k + guard:]]
    print(f"{name:12s}: -3 dB width {width * 1e9:.0f} ns, first sidelobe {20 * np.log10(lobes.max()):.1f} dB")
print(f"compression ratio BT = {B * T:.0f}, resolution c/(2B) = {3e8 / (2 * B):.0f} m")

barker = np.array([1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1])
print("Barker 13:", np.correlate(barker, barker, "full"), f"peak/sidelobe = {20 * np.log10(13):.1f} dB")

Running it prints 85 ns and −13.5 dB (rectangular), 135 ns and −42.2 dB (Hamming), BT = 200 and 15 m, and the autocorrelation of the Barker code with peak 13 and sidelobes 0 and 1.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x