Skip to content

Latest commit

Β 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Operation Basaltwindow β€” Conquer the RF Spectrum

GNU Radio 3.10 SDRangel signals hardware MIT

Operation Basaltwindow

A hands-on course for conquering the RF spectrum β€” learn to demodulate IQ and QAM signals with GNU Radio and SDRangel, then prove it against realistic captures of LTE, digital video (DVB), and Wi-Fi. Part 2 of the RF Range series (follow-on to Coldferry).

Basaltwindow takes you from "I can see a signal on a waterfall" to "I can pull the bits out of it" β€” complex IQ, quadrature amplitude modulation, receiver synchronization, and real physical-layer decode (an LTE Physical Cell ID and a DVB transport-stream program map), all from raw samples.

πŸš€ New to this? Start with QAM in an Afternoon

A gentle 2–4 hour, no-hardware, no-math-up-front on-ramp that turns radio noise into bits and makes QAM click. The full 62-hour Program of Instruction is here when you want the deep version β€” but you don't need it to get started.


Contents


Start here: QAM in an afternoon

If 62 hours sounds like a lot, it should β€” that's the full program. Most people should start with the QAM Fast Track (Basaltwindow_QAM_Fast_Track.docx): a 2–4 hour, hardware-free, confidence-first course built on one idea β€” QAM is just dots on a plane, and a receiver's only job is to un-blur them.

Time You'll be able to…
2 h See, explain, and run a QAM demodulator in simulation
3 h …plus demodulate a captured signal yourself and read out bits
4 h …plus decode something real (a DVB service, or an LTE cell ID)

No math up front, no SDR required β€” it all runs in the loopback simulation.

Quickstart (no hardware needed)

# 1. Install GNU Radio 3.10 (Ubuntu 22.04/24.04)
sudo apt install gnuradio soapysdr-tools

# 2. See a QAM receiver work, start to finish, in pure simulation
gnuradio-companion flowgraphs/qam_loopback_sim.grc     # press the β–Ά button

# 3. Demodulate a "captured" signal from file
gnuradio-companion flowgraphs/qam_rx_demod.grc         # point File Source at an iq_samples/*.iq

# 4. Prove it numerically (EVM, LTE cell-ID decode, DVB transport-stream parse)
python3 verify_demod.py
python3 verify_signals.py

You will watch a noisy, rotating blur collapse into a clean QPSK constellation β€” the whole point of a receiver, in one picture:

Before/after synchronization

What you get

Piece What it is
Lab Guide (Basaltwindow_Lab_Guide.docx) 13-page student manual: IQ & QAM from fundamentals, per-radio setup, four exercises (sim β†’ bench β†’ range β†’ SDRangel), block reference, troubleshooting, safety.
Program of Instruction (docs/PROGRAM_OF_INSTRUCTION.md, Basaltwindow_POI.docx) Full ~62-hour curriculum: objectives, 12 blocks of instruction, labs, assessments, capstone, schedule.
GNU Radio flowgraphs (flowgraphs/) Loopback simulation, QAM transmitter, and QAM receiver (.grc + generated .py).
SDRangel config (sdrangel/) REST-API script + guide to drive SDRangel as a demod station.
Signal library (iq_samples/) 8 synthetic-but-standards-faithful IQ captures + ground-truth transport streams.
Tools parse_ts.py (MPEG-TS parser), verify_*.py (decode proofs), generators.
Reference card (signal_reference_card.png) PSD + spectrogram of every signal β€” a recognition sheet.

The signal library

Every capture is interleaved complex float32 (GNU Radio's native complex type); the sample rate is in each filename. They are synthetic but standards-faithful β€” correct bandwidths, framing, cyclic prefix, real LTE sync signals, real Wi-Fi preambles, and valid MPEG transport streams.

Signal reference card

Capture Standard Sample rate Decodes to
lte_fdd_5MHz_qpsk_7p68Msps LTE FDD 5 MHz DL 7.68 Msps Physical Cell ID 126
lte_fdd_10MHz_64qam_15p36Msps LTE FDD 10 MHz DL 15.36 Msps Physical Cell ID 166
lte_fdd_20MHz_16qam_30p72Msps LTE FDD 20 MHz DL 30.72 Msps Physical Cell ID 302
dvbs_video_qpsk_2Msym_4Msps DVB-S-style video 4.0 Msps MPEG-TS program map (H.264 + AAC)
dvbs_rickroll_qpsk_2Msym_4Msps DVB-S-style video 4.0 Msps service "Never Gonna Give You Up" + text 🎡
wifi_80211g_20MHz_20Msps 802.11g Wi-Fi 20.0 Msps preamble / bursts
qpsk_2Msps, qam16_2Msps Generic QPSK / 16-QAM 2.0 Msps training symbols

See iq_samples/SIGNAL_MANIFEST.md for full details.

Two real decode wins (and one easter egg)

Recovering a constellation is the hard, universal part of receiving any digital signal. Basaltwindow lets you go one step past it and read something a real network actually broadcasts:

  • LTE Physical Cell ID. The LTE captures carry real PSS (Zadoff-Chu) and SSS (m-sequences per 3GPP 36.211). A cell search recovers PCI = 3Β·N_ID_1 + N_ID_2 β€” 126, 166, 302 β€” exactly what a real handset computes at power-on.
  • DVB transport stream. The video captures carry a valid MPEG-TS (PAT, PMT, SDT, correct CRCs). Demodulate the QPSK, byte-sync on 0x47, and python3 parse_ts.py prints the program map (H.264 video, AAC audio).

Easter egg. The dvbs_rickroll capture's DVB service name is "Never Gonna Give You Up" and its data stream carries a message. Demodulate and parse it and your own receiver rickrolls you β€” while teaching DVB service information and payload extraction. (The payload is original text; no song is embedded.)

$ python3 parse_ts.py iq_samples/dvbs_rickroll_reference.ts
Service (SDT): "Never Gonna Give You Up"  provider "RickTV"
  elementary stream PID 0x0100  type 0x1B (H.264 video)
  elementary stream PID 0x0101  type 0x0F (AAC audio)
  elementary stream PID 0x00A0  type 0x06 (PES private data)
Embedded data-stream text:
  === OPERATION BASALTWINDOW / RF RANGE -- DECODE CONFIRMED === ...

The QAM receiver

The five jobs a receiver must do, in order β€” exactly the blocks you wire up:

SDR ─▢ AGC ─▢ FLL band-edge ─▢ polyphase clock sync ─▢ CMA equalizer ─▢ Costas loop ─▢ slicer ─▢ bits
       level   coarse carrier     symbol timing          channel         fine carrier   decision

verify_demod.py runs this chain on a noisy, frequency-offset QPSK signal and measures the result: ~13% EVM, 99.9% of symbols in tight clusters β€” locked.

Program of Instruction

Two ways in, depending on your time:

  • QAM Fast Track β€” the 2–4 hour on-ramp. Start here.
  • Full Program of Instruction β€” the complete ~62-hour, 8-day curriculum (also Basaltwindow_POI.docx): course goals, prerequisites, 12 blocks of instruction with enabling objectives, hands-on labs mapped to this repo, an assessment strategy, a capstone, an equipment list, and references.

Hardware fleet

Radio TX/RX Role
RTL-SDR RX only (≀ 2.4 Msps) The cheap demod station β€” one per student.
HackRF One TX & RX, half-duplex (1 MHz–6 GHz) Range transmitter / receiver.
AntSDR E200 TX & RX, full-duplex (Pluto/IIO) Bench-loopback star β€” TX and RX at once.
KrakenSDR RX only (5 coherent) Direction-finding extension (not core).

Reading captures from file works on any workstation. Over-the-air replay of the wideband captures (15.36 / 30.72 / 20 Msps) needs HackRF or AntSDR.

The honest decode boundary

You genuinely recover a real cell ID and a real program map from raw IQ β€” the same operations real receivers perform. What these captures deliberately omit is the FEC / scrambling / higher-layer stack that turns a program map into playable video or a PCI into a cell's full system information. On real signals those are extra, well-defined steps (srsRAN for LTE, a DVB decoder for video) β€” not a different skill. The demodulation you practice here is the physical layer all of it stands on.

Reproduce the verification

python3.12 make_signals.py      # regenerate the IQ captures + reference transport streams
python3.12 verify_signals.py    # LTE cell-ID decode, DVB TS parse, Wi-Fi detection, reference card
python3    verify_demod.py      # QAM receiver EVM (needs GNU Radio python bindings)
node       build_guide.js       # rebuild the lab guide docx
python3.12 make_banner.py       # rebuild this banner

Latest verification output is checked in at iq_samples/VERIFICATION_REPORT.txt.

GNU Radio's Python bindings on Ubuntu 24.04 are built for CPython 3.12 β€” run the signal scripts with python3.12.

Repository layout

operation-basaltwindow/
β”œβ”€β”€ README.md                     ← you are here
β”œβ”€β”€ assets/banner.png
β”œβ”€β”€ docs/PROGRAM_OF_INSTRUCTION.md
β”œβ”€β”€ Basaltwindow_Lab_Guide.docx   ← student lab guide
β”œβ”€β”€ Basaltwindow_POI.docx         ← program of instruction (Word)
β”œβ”€β”€ flowgraphs/                   ← GNU Radio .grc (+ generated .py)
β”‚   β”œβ”€β”€ qam_loopback_sim.grc
β”‚   β”œβ”€β”€ qam_tx_range.grc
β”‚   └── qam_rx_demod.grc
β”œβ”€β”€ sdrangel/                     ← SDRangel REST config + guide
β”œβ”€β”€ iq_samples/                   ← the signal library + manifest + reference TS
β”œβ”€β”€ parse_ts.py                   ← MPEG-TS / DVB SDT parser
β”œβ”€β”€ verify_demod.py               ← receiver EVM proof
β”œβ”€β”€ verify_signals.py             ← LTE/DVB/Wi-Fi decode proofs + reference card
β”œβ”€β”€ make_signals.py               ← signal generator
β”œβ”€β”€ gen_flowgraphs.py             ← flowgraph generator
β”œβ”€β”€ make_assets.py / make_banner.py / build_guide.js
β”œβ”€β”€ signal_reference_card.png
└── constellation_before_after.png

License & disclaimer

Code and documents are released under the MIT License (see LICENSE).

Disclaimer. All IQ captures in this repository are synthetic β€” generated by make_signals.py. They are standards-faithful for teaching but are not real intercepts and carry no real user data. The "rickroll" capture contains only original text and a DVB service name; no song or copyrighted media is embedded. Transmitting any signal over the air is subject to authorization β€” see the Lab Guide, Appendix B.

About

Turn radio noise into bits. A hands-on course in demodulating IQ & QAM with GNU Radio + SDRangel (LTE, DVB & Wi-Fi included).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages