What you are building
Aircraft transponders send Mode S replies and ADS-B messages near 1090 MHz. This project receives those broadcasts only. It does not transmit or ask an aircraft to reply. Use a software-defined radio (SDR) that covers the band, a suitable antenna and a computer that can stream samples.
Radio rules and permitted uses differ by country. Confirm local requirements before receiving, storing or sharing data. Do not use a hobby receiver as a source for navigation, separation or any other safety decision.
Start with samples whose answer is known
Write and test the decoder before connecting an antenna. Begin with a small offline I/Q file containing a known preamble, known message bits and a correct parity field. A GNU Radio File Source can replay raw samples, including a saved capture or samples made by a test program.
- Decode the clean fixture and compare every recovered bit with the source message.
- Use a GNU Radio Channel Model or the project test runner to add reproducible noise, frequency offset, sample-clock error and multipath. Sweep one change at a time and keep the seeds.
- Corrupt, truncate and clip copies of the fixture. Check that the decoder rejects them for the right reason before trying a recorded over-the-air sample.
This stage is completely offline. It creates complex numbers in a file and does not generate a radio transmission. Move to a live receiver only after the clean and impaired fixtures pass. The Simulating Physical Systems course covers deterministic signal replay and the move from generated samples to real sensors.
Project milestones
- Capture a short, versioned block of complex samples.
Record centre frequency, sample rate, gain, SDR model, timestamp and sample format. Keep this file as a regression fixture so every decoder change sees identical input.
- Separate wanted signal, noise and overload.
Inspect time and spectrum, set gain below clipping and estimate the local noise floor. A stronger antenna or filter can help; maximum gain can make reception worse.
- Convert I/Q samples into magnitude or power.
For each complex sample compute a consistent amplitude measure. Preserve enough numeric range, and write a unit test for zero, a known phasor and a clipped sample.
- Find the Mode S preamble by its pulse timing.
Compare the samples with the expected high and low pulse positions. Check them against the measured noise floor. Reject a candidate if its quiet positions are also high. Compute every offset from the configured sample rate.
- Recover pulse-position bits after each preamble.
Compare the first and second half of each one-microsecond symbol. Record a confidence margin as well as the chosen bit and stop cleanly when the sample block ends.
- Parse the downlink format and expected frame length.
Use the first five bits to identify the Mode S downlink format. It tells the parser whether the message is 56 or 112 bits. Reject unknown or cut-off frames without reading past the buffer.
- Check the 24-bit parity field.
Implement the Mode S CRC polynomial as bit arithmetic. Test it against published messages and vectors made by a second program. Keep a parity failure separate from weak-signal confidence.
- Decode the aircraft address, type code and one simple field.
Start with the 24-bit address and aircraft identification where present. Preserve raw bits beside decoded values and mark fields unavailable rather than inventing a default.
- Add altitude, velocity or position with explicit units.
Each extended-squitter type has its own layout and validity rules. Global position decoding uses a pair of compact-position reports and a reference location. Add it only after the simpler fields, then test it against known vectors.
- Run live with bounded queues and useful counters.
Separate sample capture from decoding, cap queue length and count samples, preambles, valid frames, parity failures and dropped buffers. Display rate and receiver health as well as decoded messages.
- Replay the fixture and compare with an independent decoder.
The saved sample block must produce identical frame boundaries and bits. Compare valid messages with a separate established decoder, investigate every disagreement and retain the cases as regression tests.
Review the receiver in four passes
Make it work
Find one strong preamble and print one parity-valid frame from a saved capture.
Make it correct
Use known bit vectors, truncated frames, corrupted bits and independent-decoder comparison.
Make it fast
Profile magnitude, correlation and CRC under the required sample rate before changing code.
Make it survive
Test clipping, noise bursts, sample loss, queue overflow, device disconnect and a changed sample rate.
Optional extension: learned signal detection
A small learned detector can rank noisy preamble candidates. Keep the timing detector, bit recovery and parity check as a reference. Train and test on separate capture sessions and receiver setups. Measure false candidates per hour, and keep the CRC as the final integrity check. A language model may explain a decoded record or query saved data. It should not decide whether raw safety-related bits are valid.
Relevant lessons: Training and Evaluation and event-level metrics.
Completion record
Keep the capture settings and samples. Also keep antenna and gain notes, thresholds, CRC vectors, decoder comparisons, timing results and failure counters. State which message types and fields are supported.