Bandpass sampling (undersampling) — allowed fs zones, Matlab/Python demo

Signals path

1. Analog & discrete → 2. Baseband sampling → 3. Bandpass sampling → 4. Power & energy

Tools: Nyquist sampling demo · Bandpass sampling demo

In one sentence: Bandpass sampling picks an $latex f_s$ below the carrier Nyquist rate but inside allowed zones so the IF replica does not alias onto itself.

Matlab/Python simulation: Sweep candidate $latex f_s$ values and inspect spectra — then use the bandpass sampling demo to see valid/invalid zones.

Continuing our deep dive into sampling theory, we now turn to Bandpass Sampling (also known as Undersampling, IF Sampling, or Sub-Nyquist Sampling).

Bandpass (Sub-Nyquist) Sampling

In traditional baseband sampling, the sampling rate must satisfy $f_s \ge 2 f_H$. But what if you have a modulated radio signal centered at $f_c = 1\text{ GHz}$ with a bandwidth of only $B = 10\text{ MHz}$?

Sampling at $2 \times 1\text{ GHz} = 2\text{ GHz}$ requires an extremely expensive Analog-to-Digital Converter (ADC) and generates gigabytes of redundant data per second. Bandpass sampling exploits the fact that the signal occupies a small frequency bandwidth $B$, allowing us to sample at a rate dictated by $B$ rather than $f_H$, directly downconverting the RF signal to baseband during the sampling process itself.

Permissible Sampling Rates

Let a bandpass signal occupy the frequency range $[f_L, f_H]$, where:

  • Bandwidth $B = f_H – f_L$
  • Center frequency $f_c = \frac{f_L + f_H}{2}$

To avoid spectral overlap (aliasing distortion) while downconverting the signal to baseband, the sampling rate $f_s$ must satisfy two conditions:

  1. Absolute Minimum Rate:
    $$f_s \ge 2 B$$
  2. Valid Sampling Bands:
    $$\frac{2 f_H}{n} \le f_s \le \frac{2 f_L}{n – 1}$$

Where $n$ is an integer representing the harmonic positioning zone, bounded by $1 \le n \le \left\lfloor \frac{f_H}{B} \right\rfloor$.

The Three Critical Engineering Realities

1. Spectral Inversion (The Odd vs. Even $n$ Rule)

When the ADC samples the bandpass signal, the downconverted baseband spectrum lands at an Intermediate Frequency (IF):

$$f_{\text{IF}} = \left\vert{} f_c – m f_s \right\vert{}$$

Whether the spectrum stays right-side up or flips upside-down depends on the integer $n$:

  • If $n$ is ODD: The spectral orientation is normal (lower RF frequencies map to lower baseband frequencies).
  • If $n$ is EVEN: The spectrum is inverted (higher RF frequencies map to lower baseband frequencies).

Software Fix: If $n$ is even, your DSP code must flip the spectrum back or swap the In-phase (I) and Quadrature (Q) channels.

2. Wideband Noise Folding (Why a Sharp BPF is Mandatory)

In baseband sampling, an Anti-Aliasing Low-Pass Filter (LPF) blocks high frequencies. In bandpass sampling, every harmonic zone ($\dots, -2f_s, -f_s, 0, +f_s, +2f_s, \dots$) folds directly into your baseband window!

If thermal noise exists across a wide RF spectrum, all that noise folds on top of your desired signal, raising the noise floor by $10 \log_{10}(n)\text{ dB}$ and destroying your Signal-to-Noise Ratio (SNR).

Hardware Fix: You must place a tight, high-Q Bandpass Filter (BPF) before the sampler that passes only the desired signal band $[f_L, f_H]$ and strips away all out-of-band noise.

3. Extreme Sensitivity to Clock Jitter

Even though the sampling rate $f_s$ is low, the input signal is oscillating at a very fast high-frequency carrier $f_c$.

If the ADC clock ticks even a fraction of a picosecond early or late (clock jitter $\sigma_t$), the rapid voltage changes at frequency $f_c$ create massive amplitude measurement errors:

$$\text{SNR}_{\text{jitter}} = -20 \log_{10}(2 \pi f_c \sigma_t)$$

Notice that $f_c$ sits in the equation, not $f_s$. A clock jitter that is completely harmless for a $10\text{ MHz}$ baseband signal will severely degrade a $1\text{ GHz}$ bandpass signal sampled at the exact same sampling rate.

Figure 1: Bandpass sampling and spectral inversion

Python Simulation & Complete Code

Python

import numpy as np

# --- 1. Signal Parameters ---
f_L = 90.0           # Lower frequency edge (Hz)
f_H = 100.0          # Upper frequency edge (Hz)
B = f_H - f_L        # Bandwidth = 10 Hz
f_c = (f_L + f_H) / 2 # Center frequency = 95 Hz

print(f"Signal Range: [{f_L} Hz, {f_H} Hz] | Bandwidth (B): {B} Hz")
print(f"Standard Baseband Nyquist Rate (2*f_H): {2 * f_H} Hz")

# --- 2. Calculate Valid Bandpass Range for n = 4 (EVEN zone) ---
n = 4
fs_min = (2 * f_H) / n
fs_max = (2 * f_L) / (n - 1)
print(f"\nFor n = {n}: Valid Sampling Rate Range = [{fs_min:.1f} Hz, {fs_max:.1f} Hz]")

# Pick a rate inside [50 Hz, 60 Hz]
Fs_bandpass = 56.0  
print(f"Selected Sub-Nyquist Sampling Rate (Fs): {Fs_bandpass} Hz")

# --- 3. Downconversion & Spectral Inversion Check ---
m = round(f_c / Fs_bandpass)
f_IF_center = abs(f_c - m * Fs_bandpass)

f_L_alias = abs(f_L - m * Fs_bandpass)
f_H_alias = abs(f_H - m * Fs_bandpass)

print("\n=== Downconversion Results ===")
print(f"Original Center ({f_c} Hz) -> Alias IF Center: {f_IF_center:.1f} Hz")
print(f"Original f_L ({f_L} Hz)     -> Alias Location:  {f_L_alias:.1f} Hz")
print(f"Original f_H ({f_H} Hz)    -> Alias Location:  {f_H_alias:.1f} Hz")

# Check Point 1: Spectral Inversion
if n % 2 == 0:
    print("Point 1 - Spectral Inversion: INVERTED (Upper edge mapped to lower IF frequency)")
else:
    print("Point 1 - Spectral Inversion: NORMAL")

# --- 4. Check Point 2 & 3: Noise Folding & Clock Jitter Limits ---
noise_folding_penalty_db = 10 * np.log10(n)
print(f"Point 2 - Wideband Noise Folding Penalty: +{noise_folding_penalty_db:.2f} dB higher noise floor without pre-BPF")

clock_jitter_sec = 1e-12 # 1 picosecond jitter
snr_jitter_db = -20 * np.log10(2 * np.pi * f_c * clock_jitter_sec)
print(f"Point 3 - Max SNR Limit due to 1ps Clock Jitter at fc={f_c}Hz: {snr_jitter_db:.1f} dB")

# --- 5. Verify Spectrum in Discrete Domain ---
t_duration = 2.0
t_sampled = np.arange(0, t_duration, 1.0 / Fs_bandpass)
# Multi-tone signal: 92 Hz (near f_L) and 98 Hz (near f_H)
x_sampled = np.sin(2 * np.pi * 92 * t_sampled) + np.sin(2 * np.pi * 98 * t_sampled)

fft_vals = np.abs(np.fft.rfft(x_sampled))
freqs = np.fft.rfftfreq(len(x_sampled), 1.0 / Fs_bandpass)

top_indices = np.argsort(fft_vals)[-2:]
detected_freqs = np.sort(freqs[top_indices])

print(f"\nFFT Detected Baseband Peaks: {detected_freqs[0]:.1f} Hz and {detected_freqs[1]:.1f} Hz")
print("Status: SUCCESS! Signal captured cleanly without overlap.")

Terminal Output

Plaintext

Signal Range: [90.0 Hz, 100.0 Hz] | Bandwidth (B): 10.0 Hz
Standard Baseband Nyquist Rate (2*f_H): 200.0 Hz

For n = 4: Valid Sampling Rate Range = [50.0 Hz, 60.0 Hz]
Selected Sub-Nyquist Sampling Rate (Fs): 56.0 Hz

=== Downconversion Results ===
Original Center (95.0 Hz) -> Alias IF Center: 17.0 Hz
Original f_L (90.0 Hz)     -> Alias Location:  22.0 Hz
Original f_H (100.0 Hz)    -> Alias Location:  12.0 Hz
Point 1 - Spectral Inversion: INVERTED (Upper edge mapped to lower IF frequency)
Point 2 - Wideband Noise Folding Penalty: +6.02 dB higher noise floor without pre-BPF
Point 3 - Max SNR Limit due to 1ps Clock Jitter at fc=95.0Hz: 164.5 dB

FFT Detected Baseband Peaks: 12.0 Hz and 22.0 Hz
Status: SUCCESS! Signal captured cleanly without overlap.

Frequently Asked Questions

Does bandpass sampling mean the ADC can’t handle the carrier frequency?

Not necessarily. The sampling rate can be much lower than twice the carrier frequency, but the ADC’s analog input and sampling circuitry must still support the RF signal frequency. Bandpass sampling reduces the required sample rate; it does not remove the need for a suitable RF front end.

What is the minimum sampling rate?

For a band spanning $f_L$ to $f_H$, its bandwidth is $B=f_H-f_L$. The theoretical minimum is $F_s \ge 2B$, but not every rate above that minimum avoids overlap. The rate must also fall in a valid sampling band:

$$
\frac{2f_H}{n} \le F_s \le \frac{2f_L}{n-1}
$$

for an appropriate integer $n$. In practice, engineers leave margin for filter transitions, frequency tolerances, and clock error.

Why can’t I choose any sampling rate above $2B$?

Spectral copies repeat every $F_s$. Some rates place those copies on top of one another even when $F_s \ge 2B$. The valid-rate ranges ensure the shifted copies of the desired band do not overlap in the sampled spectrum.

For the example band from 90 to 100 Hz, $F_s=56$ Hz lies in the valid range for $n=4$, which is 50–60 Hz.

Why does the spectrum sometimes flip?

Sampling maps different analog frequencies to aliases in the sampled frequency range. In the example, the 90 Hz edge maps to 22 Hz, while the 100 Hz edge maps to 12 Hz. The higher input frequency therefore appears at the lower output frequency: the band is inverted.

A receiver must account for this orientation in its demodulation or digital signal processing. The exact inversion convention depends on how the sampling zone is defined.

Is a preselection bandpass filter still needed?

Usually, yes. Signals and noise outside the desired RF band can also alias into the sampled band. A bandpass filter before the ADC limits what reaches the sampler and reduces unwanted folding. It cannot remove noise already inside the desired passband.

Does the $10\log_{10}(n)$ noise penalty always apply?

No. It is a useful estimate when $n$ independent, equal-power noise bands fold into the same output band. The actual noise increase depends on the noise spectrum, the filter response, and how many zones contribute at each output frequency.

Why does clock jitter matter so much at RF?

A small timing error shifts the sample point along the input waveform. Faster carrier oscillations change voltage more rapidly, so the same clock jitter causes larger sample errors at higher input frequencies. For a sinusoid, the approximate jitter-limited SNR is

$$
\mathrm{SNR}{j} \approx -20\log{10}(2\pi f_c\sigma_t),
$$

where $f_c$ is the input frequency and $\sigma_t$ is RMS clock jitter. The carrier frequency appears in this relation, not the sampling rate.

Can digital filtering undo aliasing?

Not when unwanted signals have already folded onto the same sampled frequencies as the desired signal. Once that happens, the samples generally do not contain enough information to distinguish the sources. Filtering before sampling helps prevent this; filtering after sampling can only separate components that remain distinguishable.

Leave a Comment

10 thoughts on “Bandpass sampling (undersampling) — allowed fs zones, Matlab/Python demo”

  1. oversampling analog signal

    Dear all

    I have Nsample OFDM which i received from DAC such as

    -0.26405059224367516 0.06408994957370756 0.12561630116446681 -0.25892339627777855 -0.24354180838008874 0.11023471326677702 0.1051075173008804 0.1051075173008804

    ….

    I would like to oversampling these samples by matlab code for suitable with matrix sie in optisystem (the signal will be transmit to optisystem for simulation…

    Because the sampling rate DAC is only 4 GSPS, but the sampling rate in optisystem is 16 GSPS.

    After transmit over fiber, i receive the signal after photodectector, i would like to downsample these samples, how can i downsample them to receive the orginal sample?

    Many thanks for your support

    Reply
  2. an interview question asked to me was given a signal of BW 500 HZ and Fmax is 600 Hz what is min sampling rate ? 1000 or 1200

    Reply
    • Hint for you to solve : Sampling Theorem specifies how to compute the sampling rate for given bandwidth NOT from maximum frequency.

      Why do we consider bandwidth and not maximum frequency ? Practical example below.

      In P-GSM-900, the frequency range for uplink is 890.0–915.0 MHz. If I go with maximum frequency, the sampling rate would be 2*915 MHz = 1830 MHz = 1.83 GSPS. Is it possible to have an Analog to Digital Converter (ADC) with such a fast sampler at cheaper cost?. Even if we have such a high speed sampler, the cost will be prohibitive. The solution is to sample the signal with respect to given bandwidth (Thanks to Nyquist Shannon Theorem). This gives the minimum sampling as 2*(915-890) = 2*25Mhz = 50MSPS only. (GSPS = Giga Samples Per Second, MSPS – Mega Samples Per Second)

      Note: The above sample is for illustrative purpose only. For actual sampling rate employed in the devices, please consult respective technology manual. High speed ADCs (>1 GSPS) are available in the market. Some here: http://www.ti.com/lsds/ti/data-converters/high-speed-adc-greater-than-1gsps-whats-new.page

      Reply
  3. Why the frequency of carrier wave
    is always kept at least 10 times higher then the highest frequency of base band
    signal?

    Reply
    • The carrier frequency should be greater than the message frequency, but not necessarily 10 times.
      The signal quality will be good if the carrier frequency is far greater than the message frequency. Meaning that the signal quality (distinguishable at the receiver) for 10x carrier frequency will be better compared to the signal quality with 2x carrier frequency.

      Reply
  4. I wish I had been explained these topics in the easy and intuitive way you do. This Fmax vs BW thing has always been in my head and I have never been able to figure out why sometimes Fs was 2*Fmax and some other was 2*BW. Now it all makes sense. Thanks!

    Reply
  5. thank you , nicely explained can you tell me how these three component 30KHz, 40KHz and 50KHz appeared from 0.99 MHz, 1 MHz and 1.01 MHz ?

    Reply
    • For Fs=120KHz, Fs/2 will be 60KHz. Then the zone 1 will be from 0 to 60 KHz.

      As explained in the post, the actual frequencies, 0.99M, 1M, 1.01M falls will fall in zone 17
      Since the bandwidth of each zone is 60KHz, the ratios of these frequencies to the BW are
      [0.99M/60K, 1M/60K, 1.01M/60K ] = [16.5, 16.67, 16.83 ]

      Thus,
      the frequency 0.99M is 0.5 away from the beginning of zone 17
      the frequency 1M is 0.67 away from the beginning of zone 17
      the frequency 1.01M is 0.83 away from the beginning of zone 17

      Translating this to zone 1 frequencies (exact values – calculated by multiplying the ratios and the max frequency in zone 1)
      0.5*60KHz = 30 KHz,
      0.67*60KHz = 40.2 KHz
      0.83*60KHz = 49.8 KHz

      I approximated them as 30KHz, 40KHz and 50KHz

      Reply