— Wyglinski et al., SDR for Engineers, Ch 6">
Classroom Glossary Public page

RF-201 Week 2 — QAM + Hardware Modulation Observation

1,260 words

"IQ representation is not a mathematical convenience. It is the hardware reality of the mixer." — Wyglinski et al., SDR for Engineers, Ch 6


Lecture (90 min)

2.1 QAM: Combining Phase and Amplitude

Quadrature Amplitude Modulation combines phase encoding and amplitude encoding. Each symbol carries log₂(M) bits where M is the constellation size.

16-QAM: 16 points arranged in a 4×4 rectangular grid. The real axis (I component) takes four values; the imaginary axis (Q component) takes four values. 4 bits per symbol.

64-QAM: 8×8 grid. 6 bits per symbol. 802.11n's maximum basic MCS.

256-QAM: 16×16 grid. 8 bits per symbol. 802.11ac and later.

1024-QAM: 32×32 grid. 10 bits per symbol. 802.11ax (Wi-Fi 6/6E). Requires SNR > 35 dB — essentially requires you to be close to the AP.

The SNR escalator: As QAM order increases, the minimum Euclidean distance between adjacent constellation points decreases for a fixed total signal power. Halving the distance requires 6 dB more SNR to maintain the same bit error rate. This is not negotiable; it is Shannon's theorem in practice. The 802.11ax standard can reach 1024-QAM only because it was designed for short-range indoor use.

Gray coding: Adjacent QAM symbols differ by exactly one bit. This minimises bit errors when a symbol is mistaken for an adjacent symbol — the most common noise-induced error. Gray coding is standard in every production QAM implementation.

2.2 OFDM: Many Subcarriers Solve the Multipath Problem

Modern Wi-Fi, LTE, 5G NR, and OFDM-based LoRa all use Orthogonal Frequency Division Multiplexing. WIR-101 mentioned OFDM; this week opens the mechanism.

The multipath problem: A wideband signal transmitted over a multipath channel (indoor reflections) arrives at the receiver as many delayed copies. The copies interfere destructively at some frequencies and constructively at others — frequency-selective fading. A single wideband signal sees the full fading pattern as ISI (intersymbol interference).

OFDM's solution: Divide the channel bandwidth into N narrow subcarriers. Each subcarrier is so narrow that the channel looks flat across its bandwidth (no ISI within a subcarrier). Each subcarrier is independently QAM-modulated at a slow symbol rate. The narrow subcarriers are orthogonal (their cross-correlations are zero), so they don't interfere with each other despite sitting adjacent.

The cyclic prefix: OFDM adds a guard interval (the cyclic prefix, CP) before each OFDM symbol by copying the end of the symbol to its front. The CP absorbs multipath delays. As long as the multipath delay spread is shorter than the CP duration, ISI disappears.

802.11n's OFDM parameters: 64 subcarriers, 52 data + 4 pilot, 8-subcarrier CP. Center frequency can be 20 or 40 MHz channel width.

2.3 OFDM in GNU Radio

PySDR Chapter 4 (OFDM) is the required reading for this week's lab.

Key GNU Radio blocks:

Block Purpose
OFDM Carrier Allocator Map data symbols to subcarrier indices; insert pilots
IFFT Convert frequency-domain OFDM frame to time domain
OFDM Cyclic Prefixer Prepend cyclic prefix
OFDM Frame Equalizer Channel estimation and correction at receiver
OFDM Serializer Strip pilot tones; output data symbols

2.4 Hardware Observation: Seeing All Seven Modulations with the ANTSDR E200

Week 2 lab moves from software simulation to hardware observation. You will configure the ANTSDR E200 to receive known test signals and observe the constellation and spectrum for each modulation.

Exercise setup:

  1. Configure a signal generator (GNU Radio + PlutoSDR Sink on the E200 TX) to emit each modulation in sequence
  2. Configure a receiver flowgraph (GNU Radio + PlutoSDR Source) to capture the output
  3. Observe QT GUI Constellation Sink for each modulation

What you expect to see:

Modulation Constellation Spectrum shape
OOK Two points: origin (0+0j) and (1+0j) Sinc sidebands around carrier
BPSK Two points on real axis: (-A, 0) and (+A, 0) Narrowband around carrier
QPSK Four points at 45°: (±A, ±A)/√2 Similar bandwidth to BPSK (same symbol rate, 2x bits)
16-QAM 4×4 grid of 16 points Same bandwidth as QPSK (same symbol rate, 4x bits)
GFSK Arc/track (phase trajectory); not static clusters Wider than BPSK at same data rate; smooth spectral shape
WBFM Circular / ring (constant amplitude, varying phase) Wide spectral spread
AM-DSB Amplitude-varying clusters Two sidebands symmetric around carrier

The constellation is the fingerprint of the modulation. You will use this intuition in every protocol-RE workflow from this week forward.

2.5 The Architecture Comparison Sidebar: Seven Modulations at a Glance

The full Architecture Comparison Sidebar publishes in handouts/cross-chapter-rf-201-architecture-sidebars.md. The relevant section restated:

Every modulation is a tradeoff. A deployment that chooses OOK (garage door opener, tire pressure sensor) is optimising for receiver simplicity and cost over bandwidth efficiency and noise robustness. A deployment that chooses 1024-QAM (Wi-Fi 6E at 6 GHz) is optimising for throughput at the cost of maximum operating range. A security engineer reading a captured signal reads not just the protocol but the engineering philosophy of the system designer.

IoT devices that use OOK/ASK in the sub-GHz bands are disproportionately vulnerable to replay attacks precisely because OOK demodulation is trivial with an RTL-SDR and rtl_433. That is not an accident. It is the consequence of a cost optimisation that made the receiver simple and left the security layer to the protocol above the RF — a layer that in many sub-GHz remote-control devices does not exist.

2.6 Sampling Rate, Bandwidth, and the Nyquist Theorem (Preview)

We will deepen the IQ-sampling mathematics in Weeks 8-9. This week establishes the working vocabulary:

Nyquist theorem for IQ (complex) sampling: Observable bandwidth = sample_rate (not sample_rate/2).

For real-valued sampling, the Nyquist condition is: sample_rate ≥ 2 × f_max. For complex IQ sampling, the observable bandwidth is exactly equal to the sample_rate because negative frequencies are distinguishable from positive frequencies in the complex representation. The ANTSDR E200 at 20 MSPS captures 20 MHz of bandwidth centred at whatever f_c you tune to.

At 2 MSPS, you capture 2 MHz around the centre frequency. At 20 MSPS, you capture 20 MHz. The sub-GHz garage-door signal from WIR-101 Lab 9 was ~10 kHz wide; the RTL-SDR's 2.4 MHz capture at 433.92 MHz contained the entire signal with room to spare.


Lab 1 (Week 2 extension): Hardware Constellation Capture

Deliverable additions this week:

  • Constellation screenshots for BPSK, QPSK, 16-QAM from ANTSDR loopback or software simulation
  • Write a 1-paragraph comparison: how does the constellation change as you increase QAM order?
  • Spectrum screenshot comparing GFSK vs. BPSK at the same symbol rate (observe the bandwidth difference)

Virtual path: All constellation plots can be generated in GNU Radio or PySDR without hardware using the Signal Source → GFSK Mod / PSK Mod / QAM Mod chains from Week 1 homework. No hardware needed.


Homework

Reading (1.5 hr):

  • Wyglinski Ch 2, §2.1-2.3 (ADC/DAC chain; quantisation noise; sampling)
  • PySDR Ch 2 (Frequency Domain) — review from WIR-101 context but read at full depth
  • PySDR Ch 3 (Modulation) — the build-it-yourself companion to this week's lecture

Hands-on (2 hr): Implement the QPSK demodulator in PySDR (in-browser workbench or local Python):

import numpy as np
import matplotlib.pyplot as plt

# Generate QPSK signal
samples_per_symbol = 8
bits = np.random.randint(0, 2, 100)
# Map bits to QPSK symbols
symbols = []
for i in range(0, len(bits), 2):
    if   bits[i]==0 and bits[i+1]==0: symbols.append( 1+1j)
    elif bits[i]==0 and bits[i+1]==1: symbols.append(-1+1j)
    elif bits[i]==1 and bits[i+1]==0: symbols.append( 1-1j)
    else:                             symbols.append(-1-1j)
symbols = np.array(symbols) / np.sqrt(2)

# Upsample (repeat each symbol)
signal = np.repeat(symbols, samples_per_symbol)

# Add AWGN noise at SNR=10dB
snr_db = 10
noise_power = 1 / (10**(snr_db/10))
noise = np.sqrt(noise_power/2) * (np.random.randn(len(signal)) + 1j*np.random.randn(len(signal)))
rx = signal + noise

# Downsample: take one sample per symbol
rx_symbols = rx[samples_per_symbol//2::samples_per_symbol]

# Plot constellation
plt.figure(figsize=(5,5))
plt.scatter(rx_symbols.real, rx_symbols.imag, alpha=0.3, s=10)
plt.axhline(0, c='k', linewidth=0.5); plt.axvline(0, c='k', linewidth=0.5)
plt.title('QPSK Constellation (SNR=10dB)'); plt.xlabel('I'); plt.ylabel('Q')
plt.grid(True, alpha=0.3); plt.axis('equal'); plt.show()

Run this at SNR = 20dB, 10dB, and 3dB. Describe what happens to the constellation as SNR decreases. At what SNR do the four clusters start to overlap?


Key Terms

  • QAM order (M): number of constellation points; log₂(M) bits per symbol; higher M requires higher SNR
  • OFDM: Orthogonal Frequency Division Multiplexing; N parallel narrow subcarriers; solves multipath ISI
  • Cyclic prefix (CP): guard interval prepended to each OFDM symbol; absorbs multipath delay spread
  • Euclidean distance: straight-line distance between constellation points; noise moves symbols; smaller distance = more errors
  • Gray coding: adjacent constellation points differ by 1 bit; minimises bit errors from symbol slip
  • Subcarrier: individual narrow-band tone within OFDM; independently QAM-modulated
  • Pilot tone: fixed-value subcarriers used by the receiver for channel estimation