Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ofdm-phy-simulation

GNU Radio Python Analysis License: MIT

A fully simulated OFDM transceiver in GNU Radio: baseband generation, RF-like up/down-conversion, an AWGN channel, and demodulation — every stage visualized, and the link's noise tolerance measured end-to-end rather than assumed.

Skills demonstrated: GNU Radio flowgraph design · OFDM PHY design (802.11-style numerology) · IQ modulation/demodulation · AWGN channel modeling · FIR filter design · DSP signal analysis · Python / Jupyter data analysis

Highlights

  • Parameters match real IEEE 802.11a/g PHY numerology: 64-pt FFT, 16-sample (25%) cyclic prefix, pilots at ±7/±21
  • Full TX → channel → RX chain visualized and cross-checked at 8 stages, time and frequency domain, including image-frequency/LO-leakage artifacts and why they force a decimating LPF
  • Measured a complete packet-delivery-rate waterfall curve across 30 noise levels (0.5–6.5): 99.96% → 0%, 50%-point at noise ≈3.95
  • Diagnosed GNU Radio's CRC32-gated all-or-nothing packet delivery from first principles, then confirmed it empirically — every delivered packet is byte-exact even at 2 of 9990 packets received
  • Derived the link's raw PHY rate (~7.68 kbps, ~1.2 bits/s/Hz) directly from the FFT/CP/modulation parameters and combined it with measured PDR into actual goodput numbers, not just a delivery percentage
  • Results validated with an automated TX/RX comparison in a companion notebook (analysis/visualize_results.ipynb), not just visual inspection of scopes

Table of Contents

Project Goal

Build a hands-on, end-to-end understanding of an OFDM transceiver — signal generation, RF up/down-conversion, channel impairments, demodulation — by implementing, visualizing, and measuring every stage in GNU Radio.

System Architecture

A complete OFDM link: transmitter (IFFT + cyclic prefix), a noisy channel, and a receiver that reverses the process via quadrature demodulation, LPF filtering, and FFT-based OFDM demodulation. Every block below is verified in isolation (Signal Visualization) and end-to-end (Results).

OFDM transceiver block diagram

Simulation Parameters

Parameter Value
FFT length 64
Subcarrier spacing 100 Hz (= 6.4 kHz / 64)
Cyclic prefix length 16 samples (25% of the useful symbol)
Useful / total OFDM symbol duration 10 ms / 12.5 ms
Pilot subcarriers -21, -7, 7, 21
Data subcarriers 48 (confirmed via oc_carriers)
Occupied subcarriers (total) 52 of 64 (48 data + 4 pilot; DC + 11 nulled)
Header modulation BPSK
Payload modulation QPSK
Baseband sample rate 6.4 kSa/s
Simulated "RF" sample rate 140.8 kSa/s (×22 interpolation)
Simulated carrier frequency 16 kHz
Channel model AWGN, amplitude swept 0.5–6.5 (see Results)

Design note: these aren't arbitrary numbers — 64-pt FFT, a 16-sample (25%) cyclic prefix, and pilots at exactly ±7/±21 is the same numerology IEEE 802.11a/g uses, just re-scaled to a low, easily-visualized sample rate.

Derived PHY throughput: with the confirmed 48 data-subcarrier layout (oc_carriers), QPSK payload gives 48 × 2 = 96 bits per OFDM symbol; at a 12.5 ms symbol period that's a raw payload PHY rate of 96 / 0.0125 s ≈ 7.68 kbps, or ≈1.2 bits/s/Hz across the 6.4 kHz channel — the standard way 802.11-style rate tables are computed (data subcarriers × bits/symbol / symbol duration), independent of packet framing overhead. Combined with the measured PDR curve below, this converts directly to goodput: ~7.68 kbps near-ideal (noise=0.5), ~3.84 kbps at the 50%-PDR point (noise≈3.95), and <0.2 kbps by noise=5.0.

Design Decisions & Trade-offs

  • 25% CP overhead — matches the 802.11a/g guard-interval ratio; protects against delay spread up to 2.5 ms here at the cost of 25% throughput.
  • BPSK header / QPSK payload — the header carries critical framing and stays on the most robust constellation; the payload trades robustness for 2× throughput. Standard practice: PHY headers are sent robust regardless of the negotiated payload rate.
  • Pilots at ±7/±21 — the same 802.11a/g layout for tracking residual frequency/phase offset across the band.
  • AWGN, not multipath — isolates and quantifies SNR degradation cleanly (see Results) before adding fading complexity (Possible Improvements).
  • Reduced sample rate (6.4 / 140.8 kSa/s) — keeps every ratio that matters (interpolation factor, filter cutoff-to-Fs, carrier-to-Fs) representative of a real IQ front-end, fully visualizable without SDR hardware.

On the packaged OFDM Tx/Rx blocks: OFDM Transmitter/OFDM Receiver are GNU Radio hier_block2 wrappers — internally they run sync, channel estimation, equalization, decoding, and a CRC32 integrity check, but only expose baseband-in / bytes-out. Two consequences: (1) any payload failing its CRC is dropped whole, not passed through corrupted — see Results for the empirical proof; (2) the pre-decision equalized symbol stream (needed for a constellation plot) isn't exposed — getting it means rebuilding the RX chain from primitive Sync/Channel-Estimator/Equalizer/Serializer blocks instead.

Signal Visualization

Each stage below is grounded in the actual captured plot, following the signal from bitstream to recovered data.

1. Carrier waveform — 16 kHz local oscillator for later I/Q conversion; confirmed directly from the trace (~10 cycles / 0.6 ms). Sine carrier

2. Baseband OFDM (after modulation) — straight out of the OFDM Transmitter (64-pt IFFT + 16-sample CP). The noise-like envelope is OFDM's characteristic high PAPR; packet_len: 560 markers show GNU Radio's Tagged Stream framing in action. After OFDM modulation After OFDM modulation - spectrum

3. Up-converted to carrier — after the Rational Resampler + I/Q mixing. Individual OFDM symbol envelopes are visible riding the 16 kHz carrier: the same PAPR, now visible at "RF". OFDM on carrier

4. Channel effect (A/B) — same tap point, AWGN off vs. on: noise floor rises from ~-60…-70 dB to ~-45…-50 dB, a measured ~15–20 dB SNR hit. OFDM on carrier - clean spectrum OFDM on carrier with noise - spectrum

5. After down-conversion, before filtering — wanted band near 0 Hz, plus a residual image band (~±30–35 kHz) and LO-leakage spurs (~±16 kHz). This is exactly why a decimating LPF must follow a real quadrature mixer. After lowering frequency - spectrum

6. After the decimating LPF — Hamming window, 3.3 kHz cutoff, ÷22. Image and leakage removed; amplitude back to ~±15. After FIR filter

7. Ready for demodulation — recombined I/Q, exactly as fed into the OFDM Receiver; tracks Stage 2 closely, with AWGN as the main visible difference. Ready to demodulation Ready to demodulation - spectrum

8. After demodulation — recovered byte stream. Amplitude range (~20–120) matches printable ASCII; the spectrum is a sharp, evenly-spaced harmonic comb — the expected Fourier signature of a looped, period-locked, essentially bit-exact recovery. After OFDM demodulation After OFDM demodulation - spectrum

Results: Packet Delivery Rate vs. Channel Noise

Noise Source amplitude was swept across 30 settings (0.5–6.5). Every sent message is one OFDM packet of 560 mapped symbols (~7 OFDM symbols, per the packet_len tag); sent packets were logged via a dedicated File Sink (data/TX_OFDM_Data_every_single_message.txt) and compared against data/RX_OFDM_Data.txt. Full analysis: analysis/visualize_results.ipynb.

Packet Delivery Ratio vs Noise

Noise Sent Received PDR Noise Sent Received PDR
0.5 4682 4680 99.96% 4.2 6556 2183 33.30%
2.7 4995 4989 99.88% 4.3 7180 1926 26.82%
3.0 4682 4627 98.83% 4.4 10303 2133 20.70%
3.1 5307 5177 97.55% 4.5 6243 943 15.11%
3.2 5307 5059 95.33% 4.6 6243 670 10.73%
3.3 6868 6301 91.74% 4.7 6243 473 7.58%
3.4 4995 4376 87.61% 4.8 5931 287 4.84%
3.5 5307 4271 80.48% 4.9 5620 187 3.33%
3.6 5931 4403 74.25% 5.0 5619 126 2.24%
3.7 5307 3574 67.33% 5.1 5932 82 1.38%
3.8 6556 3842 58.60% 5.2 5619 46 0.82%
3.9 5629 3057 54.31% 5.3 7493 35 0.47%
4.0 6556 2997 45.71% 5.4 6243 22 0.35%
4.1 8429 3417 40.55% 5.5 5619 12 0.21%
6.0 9990 2 0.02%
6.5 25600 0 0.00%

Reading the curve:

  • Classic waterfall shape: flat near 100% up to noise≈3.0, a sharp transition through 3.5–4.5, 50%-crossing at noise≈3.95, then a long tail to 0% by noise=6.5.
  • The knee is sharp rather than gradual because CRC32 turns individual symbol errors into a hard pass/fail per packet, not a gradually-degrading one.
  • Even in the extreme tail (2 of 9990 delivered at noise=6.0), every delivered packet is still byte-exact. This isn't a modulation effect — QPSK vs. BPSK affects whether a packet survives, not how corrupted a surviving one is. It's the CRC32 check itself: a packet either matches its checksum and is forwarded whole, or fails and is dropped whole — there's no partial-corruption state, so "delivered" and "byte-exact" are the same event at any noise level.
  • Delivery isn't literally 100% even at the lowest tested noise (amplitude 0.5 → 99.96%, 2/4682 lost) — a reminder that not all loss here is SNR-driven. A small residual floor from synchronization/framing edge effects (e.g. correlator misses at packet boundaries) persists even at negligible noise, separate from the AWGN-driven mechanism that dominates the rest of the curve.
  • Each point aggregates thousands of packets (n = 4682–25600); the binomial standard error stays under ~1% even near the 50% point (n≈5629 → SE≈0.7%), so the curve's shape reflects the underlying physics, not per-run measurement noise.
  • This is exactly the behavior real systems are built around: link adaptation / AMC (802.11 rate control, LTE/5G CQI-driven MCS selection) exists to step down to a more robust modulation before a link falls off this cliff, not after.
  • The x-axis is the linear Amplitude parameter of the Gaussian Noise Source, not a calibrated SNR in dB — see Possible Improvements.

Getting Started

# 1. Install GNU Radio: https://wiki.gnuradio.org/index.php/InstallingGR

# 2. Open the flowgraph
gnuradio-companion flowgraphs/ofdm_baseband_passband_transceiver.grc

# 3. ...or run it directly
python3 flowgraphs/ofdm_baseband_passband_transceiver.py

# 4. Post-process results
jupyter notebook analysis/visualize_results.ipynb

data/TestData.txt is read (looped) as the payload source. data/TX_OFDM_Data_every_single_message.txt logs every packet sent; data/RX_OFDM_Data.txt logs what's recovered.

Repository Structure

ofdm-phy-simulation/
├── analysis/
│   └── visualize_results.ipynb
├── data/
│   ├── TestData.txt
│   ├── TX_OFDM_Data_every_single_message.txt
│   └── RX_OFDM_Data.txt
├── flowgraphs/
│   ├── ofdm_baseband_passband_transceiver.grc
│   └── ofdm_baseband_passband_transceiver.py
├── images/
│   ├── Block_Diagram_of_the_Simulated_OFDM_Transceiver_System.jpg
│   ├── sine_carr.jpg
│   ├── after_OFDM_modulation.jpg
│   ├── after_OFDM_modulation_spec.jpg
│   ├── OFDM_modulation_on_carrier.jpg
│   ├── OFDM_modulation_on_carrier_spec.jpg
│   ├── OFDM_modulation_on_carrier_with_noise_spec.jpg
│   ├── OFDM_modulation_after_lowering_freq_spec.jpg
│   ├── OFDM_modulation_after_FIR_filter.jpg
│   ├── OFDM_redy_to_demodulation.jpg
│   ├── OFDM_redy_to_demodulation_spec.jpg
│   ├── after_OFDM_demodulation.jpg
│   ├── after_OFDM_demodulation_spec.jpg
│   └── packet_delivery_ratio.png
├── LICENSE
└── README.md

Possible Improvements

  • Add forward error correction (convolutional/LDPC) on top of the existing CRC32 detect-and-drop scheme, and compare coded vs. uncoded waterfall curves — this project deliberately stops at error detection, not correction
  • Calibrate the noise-amplitude x-axis into a proper Es/N0 (dB) scale — measure signal and noise power separately with a Probe Avg Mag^2 Value block rather than comparing linear amplitudes
  • Rebuild the RX chain from primitive blocks (Sync, Channel Estimator, Equalizer, Serializer) to expose a constellation/EVM plot
  • Channel estimation / equalization using the pilot subcarriers; timing and carrier frequency synchronization
  • Multipath / fading channel model (Rayleigh, Rician) in addition to AWGN
  • Run the same flowgraph over a real SDR (HackRF / RTL-SDR)

License

MIT — see LICENSE.

About

Simulated OFDM transceiver in GNU Radio with measured packet-delivery-rate vs. noise analysis

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages