Wiki / Concepts

Nyquist and Aliasing

Sampling turns a wave into numbers, and it has one hard rule: anything above half the sample rate folds back and lies to you. The same folding, used on purpose, is how a receiver digitises a band far above its converter rate.

Where a tone at f lands when you sample at Fs
Sample rate Fs, unique band 0 to Fs/2
Zone 1: f below Fs/2
seen at f, correct
Zone 2: Fs/2 to Fs
seen at Fs - f, mirrored
Zone 3: Fs to 3Fs/2
seen at f - Fs, upright
Folding is exact, not mysterious: a tone appears at its distance to the nearest multiple of Fs, and every odd zone arrives upright while every even zone arrives mirrored. Three different input frequencies can therefore produce byte-identical samples, which is why an anti-alias filter, not the software, is what decides which one you actually captured.

Sampling replaces a continuous wave by a list of numbers taken at a fixed rate, and the Nyquist criterion is the one rule that governs it: a sample rate Fs can only represent frequencies below Fs/2 unambiguously. Everything above that limit is not lost, it is folded back into the band you can see, arriving as a perfectly convincing signal at the wrong frequency. That is aliasing.

What it is

Sample a 7 kHz tone at 10 kSa/s and the samples you get are indistinguishable from those of a 3 kHz tone. The rule is arithmetic, not luck: a tone lands at its distance to the nearest multiple of Fs.

def alias(f, fs):
    """Where a tone at f appears when sampled at fs."""
    r = f % fs
    return min(r, fs - r)

fs = 10_000
for f in (3_000, 7_000, 13_000, 17_000):
    print(f, "->", alias(f, fs))     # 3000, 3000, 3000, 3000

Four different inputs, one identical output. The receiver cannot tell them apart afterwards, which is why an anti-alias filter in front of the converter is part of the sampling, not an optional extra.

Why it matters

Every capture you take is sampled, so every capture can contain ghosts. A peak in your waterfall where nothing transmits is usually not a discovery, it is an out-of-band signal that folded in because the filter was too wide or the rate too low. The same rule sets the practical ceiling of a capture: with a complex IQ stream, Fs samples per second carry Fs hertz of spectrum, so a 2.4 MSa/s dongle sees about 2.4 MHz at once and a signal wider than that gets its edges clipped no matter what the software does.

Undersampling on purpose

Turned around, the same folding is a tool. Bandpass sampling deliberately samples a narrow band that sits far above Fs/2: if the band is narrow and a filter guarantees nothing else is present, the fold is unambiguous and it lands the band cleanly in the first Nyquist zone. That is how a receiver can digitise a slice at 100 MHz with a 20 MSa/s converter and lose nothing. The condition is the filter: without it, undersampling folds every out-of-band signal on top of the wanted one.

Decimation

Radios rarely sample at the rate you asked for. They sample fast and then decimate, keeping one sample in N. Decimation has exactly one rule: filter first, then throw samples away. Dropping samples is itself a sampling operation at the lower rate, so anything above the new Fs/2 folds in. Skip the low-pass and you manufacture a peak at a frequency where nothing was ever transmitted.

Pitfalls

  • A clean-looking peak can be a ghost. Before believing a signal, change the sample rate or the centre frequency: a real signal stays where it is in absolute frequency, an alias moves.
  • Half the rate, not the rate. Fs must be more than twice the highest frequency present, not more than the frequency itself. The classic error is sizing the rate to the signal rather than to its bandwidth plus its offset.
  • Complex and real streams are not the same width. A real-valued stream at Fs carries Fs/2 of spectrum, a complex IQ stream at Fs carries the full Fs, from -Fs/2 to +Fs/2 around the tuned frequency.
  • Decimating without filtering. The most common self-inflicted alias in a homemade flowgraph, and it produces artefacts that look exactly like real signals.

Further reading