Safeguard
Supply Chain Security•

Nyquist-Shannon Sampling Theorem: From Digital Audio to SDR

Sample faster than twice the highest frequency and a band limited signal can be rebuilt. Worked examples from CD audio, G.711 phones, aliasing and SDR.

Safeguard Security Team
43 min read

The Nyquist-Shannon sampling theorem says that a signal containing no frequencies above B hertz is completely determined by samples taken more often than 2B times per second, so it can be rebuilt exactly from those samples. Sample any slower and frequencies above half the sample rate fold back as false tones called aliases, which is why an anti-aliasing filter sits in front of every analog to digital converter. CD audio at 44.1 kHz, telephone audio at 8 kHz and the IQ streams of a software defined radio are all the same rule applied with different numbers.

This post goes one level deeper than our explainer on the Fourier transform, which shows how a signal splits into frequencies. Here we take that frequency view and ask the practical question every audio, telecom and radio engineer asks first: how fast do I have to sample, and what goes wrong if I get it wrong? If you want the physical picture of where radio frequencies sit, our tour of the electromagnetic spectrum covers it.

A note before we start. Safeguard builds single purpose security models for software. They do not do signal processing, mathematics or physics, and nothing in this post was calculated by them. The worked examples were computed with a short Python script using NumPy and SciPy, shown later, so you can check every number yourself.

Key takeaways

  • The rule in one line. If a signal has no energy above B Hz, samples taken at a rate fs greater than 2B are enough to reconstruct it exactly. Shannon stated it in 1949 as samples "spaced 1/2W seconds" apart for a signal with no frequencies above W.
  • Two names that people mix up. The Nyquist rate is 2B, a property of the signal. The Nyquist frequency is fs/2, a property of the sampler. CD audio has a Nyquist frequency of 22,050 Hz.
  • Many inventors. E. T. Whittaker published the interpolation series in 1915, Harry Nyquist analysed telegraph signalling in 1928, Vladimir Kotelnikov stated the theorem for communications in 1933 and Claude Shannon put it at the centre of communication theory in 1949. Shannon himself credited earlier mathematicians.
  • Aliasing is folding. A tone above fs/2 shows up at a mirrored frequency inside the band. A 7 kHz tone sampled at 10 kHz produces exactly the same samples as a 3 kHz tone.
  • Filters are the real cost. The theorem assumes a perfectly band limited signal. Real filters need room to roll off, which is why CD audio leaves a 2,050 Hz gap between 20 kHz and 22,050 Hz, and why modern converters oversample.
  • Telephony is the classic case. ITU-T G.711 recommends 8,000 samples per second, and G.712 specifies the 300 Hz to 3,400 Hz voice channel, giving a 64 kbit/s stream at 8 bits per sample.
  • Bandpass and IQ sampling bend the rule, not break it. What has to exceed twice something is the bandwidth, not the carrier frequency, provided the band sits wholly inside one Nyquist zone. Complex IQ sampling at fs captures fs hertz of spectrum.
  • The software matters too. Resamplers, filter libraries and SDR toolkits are open source dependencies with their own release and patch cycles, which is where supply chain hygiene meets this topic.

What does the Nyquist-Shannon sampling theorem say?

Take a continuous signal x(t), such as the voltage from a microphone. Sampling means measuring it at regular instants t = nT, where T is the sampling interval and fs = 1/T is the sampling rate in samples per second (hertz). The result is a list of numbers x[n].

The theorem answers one question: when does that list contain everything that was in the original signal? Shannon's 1949 paper in the Proceedings of the IRE gives the answer as Theorem 1: if a function contains no frequencies higher than W cycles per second, it is completely determined by its values at points spaced 1/(2W) seconds apart. Written in today's notation:

If X(f) = 0 for all |f| >= B   (the signal is band limited to B Hz)
and fs > 2B                    (sample faster than twice B)
then x(t) is fully recoverable from x[n] = x(n / fs)

Reconstruction (Whittaker-Shannon interpolation):
x(t) = sum over n of  x[n] * sinc( fs * t - n )
where sinc(u) = sin(pi * u) / (pi * u)

Each sample contributes one sinc pulse centred on its own instant. Every sinc pulse is zero at every other sample instant, so the sum passes exactly through all the samples, and between samples the pulses add up to the unique band limited curve that fits them.

Why twice the highest frequency?

Sampling multiplies the signal by a train of impulses spaced T apart. In the frequency domain that creates copies of the original spectrum centred on 0, fs, 2fs, 3fs and so on. If the original spectrum runs from minus B to plus B, each copy occupies a band 2B wide. The copies do not overlap as long as fs is greater than 2B. When they do not overlap, a low pass filter can cut out the copy at zero and discard the rest, which is exactly what reconstruction does.

If fs is less than 2B, neighbouring copies overlap. The overlapping parts add together and no filter can separate them afterwards. That overlap is aliasing.

What about sampling exactly at twice the frequency?

The boundary case is fragile. Sample a sine wave at exactly twice its frequency and you might land on every peak and trough, or you might land on every zero crossing and record nothing at all. That is why the condition is written with a strict "greater than" in most modern texts, and why practical systems leave a margin.

What Shannon also showed: 2TW numbers

In the same paper Shannon pointed out a consequence that matters to anyone sizing storage or bandwidth. A signal limited to bandwidth W and lasting T seconds can be described by 2TW numbers. His own example was a 5 MHz television signal lasting an hour, which he said would be represented by a point in a space of about 3.6 × 10^10 dimensions. The same counting tells you that one second of a 20 kHz audio signal needs at least 40,000 numbers per channel.

Who discovered the sampling theorem, and when?

The theorem has several names because several people reached it, sometimes independently, over about 35 years. The table lists the milestones we could confirm against a primary record.

YearWhoPublicationWhat it contributed
1915E. T. Whittaker"On the Functions which are represented by the Expansions of the Interpolation-Theory", Proceedings of the Royal Society of Edinburgh, vol. 35, pp. 181 to 194The cardinal series: a function built from equally spaced values using sinc shaped terms
1928Harry Nyquist"Certain Topics in Telegraph Transmission Theory", Transactions of the AIEE, vol. 47, no. 2, pp. 617 to 644 (April 1928)Showed that about 2W independent pulse values per second can be sent through a channel of bandwidth W
1933Vladimir Kotelnikov"On the transmission capacity of 'ether' and wire in electric communications", materials for the 1st All-Union Congress on the Technical Reconstruction of Communication Facilities; English translation in Physics-Uspekhi 49, 736 to 744 (2006)A precise statement of the sampling theorem for communication engineering
1935J. M. WhittakerInterpolatory Function Theory, Cambridge Tracts in Mathematics and Mathematical Physics, no. 33The mathematical treatment Shannon cites in 1949
1941W. R. Bennett"Time division multiplex systems", Bell System Technical Journal, vol. 20A related result on a steady state basis, cited by Shannon
1949Claude Shannon"Communication in the Presence of Noise", Proceedings of the IRE, vol. 37, no. 1, pp. 10 to 21 (January 1949)Theorem 1 in its modern form, plus the 2TW dimension count

Shannon was candid about priority. His paper says Theorem 1 "has been given previously in other forms by mathematicians" but had not appeared explicitly in communication theory, and it credits Nyquist and Gabor with pointing out that roughly 2TW numbers are enough. That is why you will see the theorem called Nyquist-Shannon, Whittaker-Kotelnikov-Shannon, WKS, or the Kotelnikov theorem in Russian language literature. The Russian Academy of Sciences held a session on 22 February 2006 to commemorate Kotelnikov, and Physics-Uspekhi republished his 1933 paper with the proceedings. IEEE Communications Magazine ran a short history titled "The origins of the sampling theorem" by H. D. Lüke in April 1999 for readers who want more of the backstory.

Note that Nyquist's 1928 paper was about how fast you can signal through a telegraph line, not about sampling a waveform; the name stuck to sampling because the arithmetic is the same.

What is aliasing?

Aliasing happens when a frequency above the Nyquist frequency (fs/2) is sampled. The samples it produces are identical to those of a lower frequency, so after sampling there is no way to tell which one was really there. The higher frequency has taken on an alias.

For a real valued sine wave of frequency f sampled at fs, the apparent frequency is found by folding:

f_alias = | f - k * fs |   choosing the integer k that puts the result in [0, fs/2]

Shortcut for fs/2 < f < fs:   f_alias = fs - f

Picture the frequency axis as a strip of paper folded like a fan, with creases at fs/2, fs, 3fs/2 and so on. Every frequency lands somewhere on the first panel from 0 to fs/2. Frequencies on odd panels land the right way round; frequencies on even panels land mirrored. Those panels are called Nyquist zones: the first zone runs from 0 to fs/2, the second from fs/2 to fs, the third from fs to 3fs/2, and so on.

Why can't software fix aliasing after the fact?

Because the information is gone. A 3 kHz tone and a 7 kHz tone sampled at 10 kHz produce the same numbers to within floating point rounding (we check this below), so no algorithm can tell them apart. Aliasing can only be prevented before the sampler.

Why do anti-aliasing filters sit before every analog to digital converter?

An anti-aliasing filter is an analog low pass filter placed between the sensor and the converter. Its job is to remove energy above fs/2 so that nothing can fold back into the band you care about. Without it, ultrasonic noise from a switching power supply, radio interference picked up on a cable or a harmonic of the signal itself can appear in the digital record as an audible tone or a false measurement.

The telephone network writes this requirement into its standard. ITU-T G.712, which specifies the transmission performance of PCM channels, says that with any sine wave between 4,600 Hz and 72 kHz applied to the input, the level of any image frequency produced at the output should be at least 25 dB below the test signal. That is a direct, testable limit on aliasing.

On the playback side there is a matching reconstruction filter, sometimes called an anti-imaging filter, after the digital to analog converter. It removes the spectral copies at fs, 2fs and so on that the sampling process created, leaving the smooth band limited signal.

Nyquist rate versus Nyquist frequency

These two terms describe different things and are easy to swap by mistake.

TermDefinitionBelongs toCD audio exampleTelephone example
Nyquist rate2B, twice the highest frequency in the signalThe signal2 × 20,000 Hz = 40,000 samples/s2 × 3,400 Hz = 6,800 samples/s
Nyquist frequencyfs/2, half the sample rate actually usedThe sampler44,100 / 2 = 22,050 Hz8,000 / 2 = 4,000 Hz
Guard bandNyquist frequency minus BThe design margin22,050 minus 20,000 = 2,050 Hz4,000 minus 3,400 = 600 Hz
Oversampling ratiofs divided by the Nyquist rateThe design44,100 / 40,000 = 1.10258,000 / 6,800 = 1.18

The guard band row is where the engineering lives. A wider guard band means a cheaper, gentler filter; a narrower one means more samples saved but a steeper, harder filter.

Worked example 1: why CD audio uses 44.1 kHz

The Compact Disc digital audio system is standardised internationally as IEC 60908, "Audio recording, Compact disc digital audio system". It stores two channels of 16 bit linear PCM at 44,100 samples per second; the libsamplerate documentation uses converting "from the CD sample rate of 44.1kHz to the 48kHz sample rate used by DAT players" as its standard example.

Step 1: the target bandwidth. The conventional range of human hearing is about 20 Hz to 20 kHz, so B = 20,000 Hz.

Step 2: the Nyquist rate. 2B = 40,000 samples per second. Anything above that can, in principle, carry the full audible band.

Step 3: the chosen rate and its margin.

fs                 = 44,100 samples/s
Nyquist frequency  = fs / 2 = 22,050 Hz
Guard band         = 22,050 - 20,000 = 2,050 Hz
Guard band as a ratio of the passband edge = 2,050 / 20,000 = 10.25 %
In octaves         = log2(22,050 / 20,000) = 0.141 octave

Step 4: what the filter has to do. A 16 bit system has a theoretical dynamic range of about 6.02 × 16 + 1.76 = 98.1 dB. To stop a full scale tone just above 22,050 Hz from aliasing into the audible band at a level above the noise floor, the anti-aliasing filter must pass 20 kHz almost untouched and reach roughly 98 dB of attenuation by 22,050 Hz.

Required slope ≈ 98.1 dB / 0.141 octave ≈ 697 dB per octave
Each analog filter pole gives about 6.02 dB per octave
Equivalent order ≈ 697 / 6.02 ≈ 116 poles

No practical analog filter has 116 poles. A converter that samples directly at 44.1 kHz has to accept a compromise near the band edge: some passband ripple, phase distortion or less stopband rejection. That is the transition band price of choosing 44.1 kHz rather than a much higher rate.

Step 5: how oversampling moves the problem into software. Modern converters sample far faster than 44.1 kHz and then filter and decimate digitally. Suppose the converter runs at 64 × 44,100 = 2,822,400 samples per second. Now the only frequencies that can alias into the 0 to 20 kHz band are those within 20 kHz of 2,822,400 Hz.

Analog filter must pass:     0 to 20,000 Hz
Analog filter must reject:   above 2,822,400 - 20,000 = 2,802,400 Hz
Transition width in octaves: log2(2,802,400 / 20,000) = 7.13 octaves
Required slope:              98.1 / 7.13 ≈ 13.8 dB per octave
Equivalent order:            about 2 to 3 poles

A gentle second or third order analog filter is enough. The sharp cut at 20 to 22.05 kHz is then done by a digital FIR filter, which can be made very steep with linear phase and exact repeatability.

Step 6: how long that digital filter is. The Kaiser window design formula estimates the number of taps N for a stopband attenuation A in dB and a transition width Δf at sample rate fs:

N ≈ (A - 7.95) / (2.285 * 2 * pi * Δf / fs)

Final decimation stage at 88,200 Hz in, 44,100 Hz out:
N ≈ (98.1 - 7.95) / (2.285 * 2 * pi * 2,050 / 88,200) ≈ 270 taps

A few hundred multiply and add operations per sample is trivial for modern hardware. Oversampling trades an impossible analog filter for an easy digital one.

Step 7: the data rate.

44,100 samples/s × 16 bits × 2 channels = 1,411,200 bits/s ≈ 1.41 Mbit/s

This 1.41 Mbit/s figure is the raw PCM rate of CD audio before any error correction coding on the disc.

Worked example 2: telephone audio at 8 kHz (ITU-T G.711)

ITU-T G.711, "Pulse code modulation (PCM) of voice frequencies", is the codec behind the classic digital telephone network and still a baseline codec in voice over IP. Its in force edition is G.711 (11/88), with Amendment 1 (08/09) adding an annex.

Step 1: the sample rate. G.711 says the nominal sampling rate is 8,000 samples per second, with a tolerance of plus or minus 50 parts per million.

Step 2: the band that survives. The Nyquist frequency is 8,000 / 2 = 4,000 Hz. The companion standard G.712 specifies channel performance over the range 300 Hz to 3,400 Hz, so the usable voice band is 3,100 Hz wide and the guard band above it is 4,000 minus 3,400 = 600 Hz.

fs                 = 8,000 samples/s
Nyquist frequency  = 4,000 Hz
Voice band         = 300 Hz to 3,400 Hz (G.712)
Guard band         = 600 Hz, or 0.24 octave
Bit rate           = 8,000 samples/s × 8 bits = 64,000 bit/s = 64 kbit/s

Step 3: the out of band requirement. As mentioned above, G.712 requires that any input tone from 4,600 Hz to 72 kHz produce images at least 25 dB below the test level. The filter therefore has from 3,400 Hz to 4,600 Hz, about 0.44 octave, to get to that point. That is a much gentler task than the 98 dB demanded by CD audio, because a phone channel has far less dynamic range to protect.

Step 4: the clock tolerance in numbers. Plus or minus 50 ppm sounds tiny, but it adds up.

Frequency error = 8,000 × 50e-6 = ±0.4 samples per second
Over one hour   = 0.4 × 3,600 = ±1,440 samples
At 8,000 samples/s that is ±0.18 seconds of drift per hour

This is why digital telephone networks lock their sample clocks to a common reference rather than letting each device run free. The same issue appears in any system that streams samples between two independently clocked devices, such as a USB microphone feeding a computer's sound card, and it is the reason asynchronous sample rate converters exist. National metrology laboratories such as the NIST Time and Frequency Division, which maintains the standard for frequency and time interval for the United States, sit at the top of the chain of references that oscillators are ultimately calibrated against.

Step 5: what 8 kHz removes. Everything above about 3.4 kHz and below about 300 Hz is gone. Low frequencies carry much of the warmth of a voice, and many consonants, especially fricatives such as "s", "f" and "th", carry a lot of their energy above 4 kHz. That is why "f" and "s" are easy to confuse on a narrowband call and why people spell words out with phonetic alphabets. Wideband telephony relaxes the limit: ITU-T G.722 is titled "7 kHz audio-coding within 64 kbit/s", and by the theorem a 7 kHz band needs a sample rate above 14,000 samples per second.

Step 6: what 8 bits buys. G.711 uses logarithmic companding (the A-law and µ-law variants) rather than 8 bit linear samples, so quiet sounds get finer steps than loud ones. That is a quantisation choice, separate from the sample rate.

Worked example 3: a 7 kHz tone sampled at 10 kHz

This is the textbook demonstration of aliasing, and it is worth working through sample by sample.

Step 1: set up. fs = 10,000 Hz, so the Nyquist frequency is 5,000 Hz. The tone is f = 7,000 Hz, which is above 5,000 Hz and therefore in the second Nyquist zone.

Step 2: fold it.

f_alias = fs - f = 10,000 - 7,000 = 3,000 Hz

Step 3: prove it with the samples. The n-th sample of a cosine at 7 kHz is cos(2π × 7,000 × n / 10,000) = cos(2π × 0.7 × n). Because cosine repeats every whole turn, 0.7 turns per sample is indistinguishable from 0.7 minus 1 = minus 0.3 turns per sample, and cosine is even, so it equals cos(2π × 0.3 × n), which is a 3 kHz cosine.

nTime (µs)7 kHz cosine sample3 kHz cosine sample
001.0001.000
1100-0.309-0.309
2200-0.809-0.809
33000.8090.809
44000.3090.309
5500-1.000-1.000

The two columns match. In our NumPy check the largest difference over ten samples was about 5 × 10^-15, which is floating point rounding.

Step 4: the phase detail. For a sine rather than a cosine, sin(2π × 0.7 × n) equals minus sin(2π × 0.3 × n). The alias has the same frequency but inverted phase. That is the "mirror" of the even Nyquist zone: frequency runs backwards there, so phase flips.

Step 5: what a listener would hear. If this were an audio system with no anti-aliasing filter, a 7 kHz whistle would be played back as a 3 kHz whistle. Worse, if the input tone rose from 6 kHz to 9 kHz, the output would fall from 4 kHz to 1 kHz. That backwards motion is the signature of aliasing.

The wagon wheel effect in video

Film and video are sampling in time. A camera that records 24 frames per second has a temporal Nyquist frequency of 12 Hz. A spoked wheel is a periodic pattern, so what matters is how often a spoke passes a given angle.

Take a wheel with 12 identical spokes, filmed at 24 frames per second:

Spoke passing frequency = 12 spokes × wheel rotation rate r (rev/s)

r = 2.0 rev/s  ->  24.0 Hz  ->  folds to 0 Hz       (wheel looks frozen)
r = 1.9 rev/s  ->  22.8 Hz  ->  22.8 - 24 = -1.2 Hz (spokes drift backwards)
r = 2.1 rev/s  ->  25.2 Hz  ->  25.2 - 24 = +1.2 Hz (spokes creep forwards slowly)

At minus 1.2 spoke steps per second, with 12 spokes per turn, the wheel appears to turn backwards at 0.1 revolutions per second while really spinning forwards at 1.9. For a car tyre of about 0.65 m diameter (2.04 m circumference), 2.0 revolutions per second is about 4.1 m/s or 14.7 km/h, so the illusion shows up at parking speeds, which matches what you see in films.

Purves, Paydarfar and Andrews described this in the Proceedings of the National Academy of Sciences in 1996, noting that wheels in movies "often appear to be rotating backward" under stroboscopic presentation. Their more surprising finding was that a similar illusion can appear under continuous light, which they used to argue that vision itself processes motion as a series of episodes. For engineers, the takeaway is simpler: the wagon wheel effect is aliasing in time, and the same fold that turns 7 kHz into 3 kHz turns a forward wheel into a backward one.

Worked example 4: bandpass sampling and IQ sampling in software defined radio

Radio signals sit at high carrier frequencies but usually occupy a narrow bandwidth. An FM broadcast station near 100 MHz uses roughly 200 kHz. Sampling at more than twice 100 MHz would waste almost all of the samples on empty spectrum. Two techniques avoid that.

Bandpass sampling (undersampling)

The general form of the theorem says the rate must exceed twice the bandwidth, not twice the highest frequency, provided the band sits entirely within one Nyquist zone. A Texas Instruments application note, "Why Oversample when Undersampling can do the Job?" (SLAA594A, 2013), works a clean example that we can extend.

Step 1: the signal. An intermediate frequency (IF) signal centred at 70 MHz with 20 MHz bandwidth, so it occupies 60 MHz to 80 MHz. Lowpass thinking says fs must exceed 2 × 80 = 160 MS/s. Bandwidth thinking says fs must exceed 2 × 20 = 40 MS/s.

Step 2: the valid ranges. For a band from fL to fH, the alias free sample rates fall in windows indexed by an integer n (the Nyquist zone that holds the band):

2 * fH / n  <=  fs  <=  2 * fL / (n - 1)       n = 1, 2, ... up to floor(fH / (fH - fL))

fL = 60 MHz, fH = 80 MHz, so n can be 1 to 4
n = 1:  fs >= 160 MS/s
n = 2:  80   <= fs <= 120   MS/s
n = 3:  53.3 <= fs <= 60    MS/s
n = 4:  40   <= fs <= 40    MS/s  (a single point, no margin at all)

Step 3: pick a rate. The application note uses 56 MS/s, which is inside the n = 3 window. The third Nyquist zone runs from 56 to 84 MHz, the band folds down by 56 MHz and appears centred at 70 minus 56 = 14 MHz, spanning 4 MHz to 24 MHz. Because 3 is odd, the spectrum is not inverted.

Step 4: compare with 100 MS/s. The same note also shows a 100 MS/s case. That puts the band in the second Nyquist zone (50 to 100 MHz), so it folds to 100 minus 70 = 30 MHz, spanning 20 to 40 MHz, and because 2 is even, the spectrum is mirrored. The note points out that spectral inversion happens in even zones and that the whole band must stay within a single zone.

Step 5: count the cost. Sampling at 56 MS/s instead of 160 MS/s or more cuts the output data rate by a factor of about three, with matching savings in power and in the data path to the FPGA or processor. The price is that the converter's analog input bandwidth and sampling clock must still be good at 80 MHz, because the sample and hold sees the real high frequency signal. Clock jitter matters more, since a timing error of Δt produces a larger voltage error on a faster changing waveform. And the band pass filter in front of the converter becomes the anti-aliasing filter: it must remove everything outside 60 to 80 MHz, including noise in the other Nyquist zones that would otherwise fold on top of the wanted signal.

IQ (complex) sampling

Most software defined radios take a different route. They mix the radio signal down with two copies of a local oscillator 90 degrees apart, producing an in phase (I) and a quadrature (Q) baseband signal. Sampling both gives a stream of complex numbers I + jQ. As the PySDR textbook puts it, IQ sampling "is the form of sampling that an SDR performs".

The key difference from real sampling:

Real sampling at fs:     captures 0 to fs/2           -> fs/2 Hz of usable bandwidth
Complex IQ sampling at fs: captures -fs/2 to +fs/2   -> fs Hz of usable bandwidth

A complex sample carries two numbers, so you get the same information per number, but the spectrum is no longer forced to be symmetric. Positive and negative frequencies around the tuned centre are different signals and the radio can tell them apart.

Step 1: tune and sample. The widely used RTL-SDR family of USB receivers is driven by the open source librtlsdr library. Its source code rejects sample rates at or below 225 kHz, between 300 kHz and 900 kHz, and above 3.2 MHz; the command line tool rtl_sdr defaults to 2,048,000 samples per second. Choose 2.4 MS/s centred at 100.1 MHz:

fs (complex)        = 2,400,000 samples/s
Captured spectrum   = 100.1 MHz ± 1.2 MHz  ->  98.9 MHz to 101.3 MHz
Equivalent real fs  = 4.8 MS/s would be needed for the same 2.4 MHz span
Raw data rate       = 2.4e6 samples × 2 values × 8 bits = 38.4 Mbit/s

Step 2: pick out one station. A broadcast FM channel needs about 200 kHz. Shift the wanted station to 0 Hz in software, low pass filter to about 100 kHz either side and decimate by 10:

2,400,000 / 10 = 240,000 complex samples/s
New span = ±120 kHz, enough for a ±100 kHz FM channel with a small guard band

Step 3: demodulate and decimate again. FM demodulation turns the phase changes into a real audio signal. Mono FM audio runs to about 15 kHz, so decimating by 5 gives 48,000 samples per second with a 24 kHz Nyquist frequency, a comfortable margin.

240,000 / 5 = 48,000 samples/s  ->  Nyquist frequency 24 kHz for 15 kHz audio

Every decimation step has the same rule built in: filter to below the new Nyquist frequency first, then throw samples away. Skip the filter and out of channel stations fold into your audio.

Step 4: the DC spike. Direct conversion receivers often show a spike at exactly 0 Hz from local oscillator leakage and DC offset. The common fix, which PySDR calls offset tuning, is to tune the hardware a little off the wanted station and shift it digitally, so the spike lands outside the band you keep.

Table: application, signal bandwidth and typical sample rate

ApplicationSignal bandwidthTypical sample rateNyquist frequencySource or basis
Narrowband telephone (PCM)300 Hz to 3,400 Hz8,000 samples/s4,000 HzITU-T G.711, G.712
Wideband telephoneup to 7 kHzabove 14,000 samples/s by the theoremabove 7,000 HzITU-T G.722 title
CD audio20 Hz to 20 kHz44,100 samples/s22,050 HzIEC 60908; libsamplerate docs
Professional and video audio20 Hz to 20 kHz48,000 samples/s24,000 Hzlibsamplerate docs (DAT)
FM channel after SDR decimation (example)about ±100 kHz240,000 complex samples/s±120 kHz spanWorked example above
Low cost USB SDR (RTL-SDR family)up to about 3.2 MHz captured0.225 to 0.3 or 0.9 to 3.2 MS/s complex±fs/2 around centrelibrtlsdr source
70 MHz IF with 20 MHz bandwidth60 MHz to 80 MHz56 MS/s (undersampled)28 MHzTI SLAA594A
Same IF, lowpass approach0 to 80 MHzabove 160 MS/sabove 80 MHzTI SLAA594A

Do not confuse any of these with packet sampling in network monitoring. When sFlow samples one packet in N, it is making a statistical estimate of traffic, not capturing a band limited waveform, and the Nyquist-Shannon theorem does not apply.

Decision table: which sampling approach fits?

SituationApproachWhyWatch out for
Audio, sensors, anything starting near 0 HzLowpass (baseband) sampling with oversamplingGentle analog filter, sharp digital filterDecimation filter quality, clock jitter
Narrow RF band, wideband converter availableBandpass samplingLower data rate, ADC acts as a mixerBand must sit inside one Nyquist zone; even zones invert
Tuneable receiver, general purpose SDRQuadrature (IQ) downconversion then complex samplingFull fs of bandwidth, positive and negative offsets distinctDC spike, IQ imbalance images
Changing between standard audio ratesPolyphase rational resamplingExact ratios such as 160/147 for 44.1 to 48 kHzFilter length versus latency
Two independently clocked devicesAsynchronous sample rate conversionAbsorbs ppm driftRatio tracking, buffer under or overrun

Step by step: see aliasing and resampling in Python

The script below reproduces every number in this post. It uses NumPy and SciPy, both open source. Pin and hash your dependencies before you run it; the lockfile step is part of the walkthrough because the same libraries end up in production DSP code.

1. Create an isolated environment with pinned dependencies.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install numpy scipy
python -m pip freeze > requirements.txt
# Later installs on CI or another machine:
python -m pip install -r requirements.txt

For stricter installs, generate a requirements file that includes hashes and install it with pip install --require-hashes -r requirements.txt, so a changed artifact fails the install instead of slipping in.

2. Prove the 7 kHz to 3 kHz alias.

import numpy as np

fs = 10_000          # samples per second
n = np.arange(10)    # ten sample indices
t = n / fs           # sample times in seconds

x7 = np.cos(2 * np.pi * 7_000 * t)
x3 = np.cos(2 * np.pi * 3_000 * t)
print("max |x7 - x3| =", np.max(np.abs(x7 - x3)))   # about 5e-15

s7 = np.sin(2 * np.pi * 7_000 * t)
s3 = np.sin(2 * np.pi * 3_000 * t)
print("sine alias is inverted:", np.allclose(s7, -s3))  # True

3. Find the alias of any frequency.

def alias(f, fs):
    """Apparent frequency of a real tone f sampled at fs (both in Hz)."""
    f_mod = f % fs
    return f_mod if f_mod <= fs / 2 else fs - f_mod

for f in (3_000, 7_000, 12_000, 23_000):
    print(f, "Hz ->", alias(f, 10_000), "Hz")
# 3000 -> 3000, 7000 -> 3000, 12000 -> 2000, 23000 -> 3000

4. See it in a spectrum.

fs = 10_000
t = np.arange(fs) / fs                     # one second
x = np.cos(2 * np.pi * 7_000 * t)
spectrum = np.abs(np.fft.rfft(x))
freqs = np.fft.rfftfreq(len(x), 1 / fs)
print("peak at", freqs[np.argmax(spectrum)], "Hz")   # 3000.0 Hz

5. Check the filter arithmetic for CD audio.

import math

A = 6.02 * 16 + 1.76                       # dB, 16 bit dynamic range
octaves = math.log2(22_050 / 20_000)
print(f"slope {A / octaves:.0f} dB/oct, order {A / octaves / 6.02:.0f}")

fs_os = 64 * 44_100
oct_os = math.log2((fs_os - 20_000) / 20_000)
print(f"64x: slope {A / oct_os:.1f} dB/oct, order {A / oct_os / 6.02:.1f}")

def kaiser_taps(A, df, fs):
    return (A - 7.95) / (2.285 * 2 * math.pi * df / fs)

print(f"taps at 88.2 kHz: {kaiser_taps(A, 2_050, 88_200):.0f}")

6. Resample 44.1 kHz audio to 48 kHz correctly. The ratio 48,000 / 44,100 reduces to 160 / 147. SciPy's resample_poly upsamples by up, applies a zero phase low pass FIR filter and downsamples by down, so the filter that prevents aliasing is built in.

from scipy import signal

fs_in = 44_100
t = np.arange(fs_in) / fs_in
x = np.sin(2 * np.pi * 1_000 * t)          # one second of 1 kHz

y = signal.resample_poly(x, up=160, down=147)
print(len(x), "->", len(y))                # 44100 -> 48000

7. Decimate an SDR capture safely. scipy.signal.decimate applies an anti-aliasing filter before downsampling. Use the FIR option for linear phase:

iq = np.load("capture_iq.npy")             # complex64, 2.4 MS/s, already shifted to 0 Hz
iq_240k = signal.decimate(iq, 10, ftype="fir")

8. Capture real IQ samples with an RTL-SDR (optional). The rtl_sdr tool writes raw 8 bit unsigned interleaved I and Q bytes. Its usage text lists -f for the centre frequency, -s for the sample rate and -n for the number of samples.

# 10 seconds at 2.4 MS/s centred on 100.1 MHz
rtl_sdr -f 100100000 -s 2400000 -n 24000000 fm_100p1.bin
raw = np.fromfile("fm_100p1.bin", dtype=np.uint8).astype(np.float32)
iq = (raw[0::2] - 127.5) / 127.5 + 1j * (raw[1::2] - 127.5) / 127.5
np.save("capture_iq.npy", iq.astype(np.complex64))

Check that you only listen to signals you are permitted to receive where you live; receiving broadcast FM is fine in most places, other bands may not be.

The software bridge: DSP libraries and SDR toolchains are dependencies too

Here is the honest link to what Safeguard does. Safeguard does not analyse signals, design filters or test converters, and its models do not do mathematics. What it does is look after the software supply chain, and almost every system in this post runs on open source signal processing code: NumPy and SciPy in analysis scripts, libsamplerate in audio pipelines (its home page notes that release binaries and source packages are signed by the current release manager, and publishes the key), librtlsdr for USB receivers, and GNU Radio, which describes itself as "a free & open-source software development toolkit that provides signal processing blocks to implement software radios". Those libraries are compiled into firmware images, desktop audio tools, ground station software and lab instruments, and they get new releases and occasional security fixes like any other dependency. Knowing which version of each one your products contain, and moving to fixed versions quickly, is ordinary dependency hygiene. That is the part we can help with; the sampling theory is yours.

Common mistakes

  • Swapping Nyquist rate and Nyquist frequency. The Nyquist rate is twice the signal's highest frequency; the Nyquist frequency is half the sample rate. Saying "the Nyquist rate of CD audio is 22.05 kHz" mixes them up.
  • Sampling at exactly 2B. The boundary case can capture nothing at all for a sine at the boundary. Always leave a margin.
  • Ignoring filter roll off. No real filter goes from pass to stop instantly. If the guard band is too narrow for your filter, either aliases leak in or the top of your band is attenuated. Budget the transition band explicitly, as in the CD example.
  • Treating aliasing as a software bug to fix later. Once aliases are in the samples, no algorithm can remove them. Filter before the converter and before every decimation.
  • Decimating by dropping samples. Taking every tenth sample without a low pass filter first is aliasing by design. Use a decimator that filters, such as scipy.signal.decimate or a polyphase filter.
  • Assuming higher sample rates always sound better. Beyond a comfortable margin above twice the audible band, higher rates add room for gentler filters and processing, not audible detail. They cost storage (96 kHz, 24 bit stereo is 4.6 Mbit/s, over three times the CD rate) and can introduce intermodulation in playback chains that are not linear above 20 kHz.
  • Forgetting that bits and rate are different. Sample rate sets bandwidth; bit depth sets the noise floor. A 192 kHz, 8 bit recording is still noisy.
  • Placing a bandpass signal across a zone boundary. In undersampling, the whole band must sit inside one Nyquist zone. Straddling a boundary folds part of the band on top of the rest.
  • Ignoring spectral inversion in even zones. A band in the second or fourth Nyquist zone arrives mirrored, which matters for single sideband and for any modulation where up and down in frequency mean different things.
  • Trusting the clock blindly. A 50 ppm clock error at 8 kHz is 1,440 samples an hour. Two free running devices will drift apart.

FAQ

What is the Nyquist-Shannon sampling theorem in simple terms?

If a signal contains no frequencies above B hertz, measuring it more than 2B times per second captures all of its information, and the original can be rebuilt exactly from those measurements. Sample too slowly and high frequencies disguise themselves as low ones.

What is the difference between the Nyquist rate and the Nyquist frequency?

The Nyquist rate is twice the highest frequency in the signal, so it describes the signal. The Nyquist frequency is half of the sample rate you actually use, so it describes the system. For CD audio, the Nyquist rate of a 20 kHz signal is 40,000 samples per second and the Nyquist frequency of the 44.1 kHz system is 22,050 Hz.

Why is CD audio sampled at 44.1 kHz and not 40 kHz?

Because real anti-aliasing filters need room to roll off. 44.1 kHz gives a Nyquist frequency of 22,050 Hz, leaving a 2,050 Hz guard band above the 20 kHz audible limit for the filter to move from pass to stop.

Why does telephone audio sound muffled?

ITU-T G.711 samples at 8,000 times per second, so nothing above 4 kHz can be carried, and G.712 specifies the channel from 300 Hz to 3,400 Hz. Much of the energy of consonants like "s" and "f" lies above that, and the low end below 300 Hz is cut as well.

What is aliasing in simple terms?

Aliasing is when a frequency above half the sample rate produces the same samples as a lower frequency, so it shows up in the digital record as a false tone. A 7 kHz tone sampled at 10 kHz looks exactly like a 3 kHz tone.

Why do wheels look like they spin backwards in videos?

Video samples motion at a fixed frame rate. When the spokes move almost one spoke spacing between frames, the brain matches each spoke with the one just behind it, so the wheel appears to creep backwards. It is aliasing in time; at 24 frames per second a 12 spoke wheel turning at 1.9 revolutions per second appears to turn backwards at 0.1.

Can you sample a signal below its Nyquist rate?

You can sample below twice the highest frequency if the signal occupies a narrow band and that band sits wholly inside one Nyquist zone. This is bandpass sampling or undersampling. The rate still has to exceed twice the bandwidth, and the analog front end must handle the real high frequency.

Why do software defined radios use IQ sampling?

Complex IQ sampling at fs captures fs hertz of spectrum around the tuned frequency and keeps positive and negative offsets distinct, so a radio can tune, filter and demodulate any signal in that window in software. Real sampling at the same rate captures only half as much bandwidth.

Does a higher sample rate improve audio quality?

Only up to a point. Beyond a comfortable margin above twice the audible bandwidth, extra rate adds filter and processing headroom, not audible detail.

Who really discovered the sampling theorem?

Several people. Whittaker published the interpolation series in 1915, Nyquist analysed signalling rates in 1928, Kotelnikov stated the theorem for communications in 1933 and Shannon made it central to information theory in 1949, crediting earlier mathematicians in his paper.

Signal processing systems still ship software, and that software has dependencies. A rebuilt SDR ground station or an audio product's next firmware image pulls in DSP libraries, codecs and drivers again, and any of them can carry a known vulnerability that has a fix waiting upstream. The section below explains how Safeguard helps teams close that gap for the open source components they build and ship; it does not apply to the analog front end or to converter hardware.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

None of these demos involve signal processing or radio hardware; they show the software side described in the bridge above.

The first demo is a real Safeguard CLI session: it installs the CLI, opens the interactive terminal and asks it to fix a lodash CVE in a repository. It reads the finding and advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing. The same flow applies to a web dashboard for an SDR receiver or an audio processing service your team maintains: scan the repository, then let the assistant propose the dependency upgrade under your approval.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with its device code and then scans from the terminal. That suits radio and audio engineering teams who keep DSP code, firmware build trees and Python analysis environments on their own hardware and want the scan to run where the code lives.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. For an engineer who already works with Claude while writing a resampling pipeline or an SDR flowgraph, it brings dependency findings into the same conversation, limited to the tools you allow.

Click through it at your own pace, or open it full screen.

To try it on your own repositories, download Safeguard and follow the CLI documentation.

Quick check

A 13 kHz tone is sampled at 20 kHz with no anti-aliasing filter. At what frequency does it appear?

The Nyquist frequency is 10 kHz, so 13 kHz is in the second Nyquist zone. It folds to 20 minus 13 = 7 kHz, with inverted phase for a sine.

A signal occupies 60 MHz to 80 MHz. Is 56 MS/s a valid sample rate, and where does the band land?

Yes. The band fits inside the third Nyquist zone (56 to 84 MHz), which satisfies 2 × 80 / 3 = 53.3 MS/s up to 2 × 60 / 2 = 60 MS/s. It folds down to 4 MHz to 24 MHz, centred at 14 MHz, and is not inverted because the zone number is odd.

Sources

Last reviewed: 25 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.