v0.1.0 · synthetic-IQ verified · Oct 2026 → Present
Spectrum
A $40 radio.
Every plane, ship and satellite overhead.
Plug a $40 USB radio into a laptop and see the invisible world: planes and ships on a live map from my own ADS-B and AIS decoders, the next weather satellites overhead, and plain-English answers about mystery signals.

Highlights
The problem.
The air around any laptop is full of broadcasts anyone may receive — aircraft position reports at 1090 MHz, ship transponders at 162 MHz, weather satellites at 137 MHz. A $40 RTL-SDR dongle can hear all of it.
Turning that into something a curious person can use takes a pile of single-purpose tools, each with its own driver setup and jargon. And a waterfall full of unexplained blips is the moment most people give up.
What I built.
One streaming DSP core — decimator, mixer, FM and AM demodulators, squelch, waterfall — feeds small stateful receivers that take any chunk size, so a radio, a file and a simulation are interchangeable. The ADS-B receiver is my own Mode S codec and PPM demodulator with CRC-24 one-bit repair and global-then-local CPR positions, so aircraft need no station location. The AIS receiver demodulates both channels from one capture with per-burst carrier-offset removal, HDLC framing and NMEA output.
Satellite passes come from SGP4 on Celestrak elements. Spectrum decides when to record, records SigMF cleanly, and hands LRPT decoding to SatDump, detecting whether it is talking to the 1.2 or the 2.0 command line. The identifier measures bandwidth, burst timing, keying and symbol rate, checks the band plan, and scores 11 classes of weighted rules, showing the reasons that fired. Claude can give a second opinion on the spectrogram; if it fails, the rule result stands.
I had no radio, so the tests decode signals rather than bits. A generator models the physical layer — pulse timing with sub-sample offsets, Gaussian-filtered GMSK, carrier offsets, noise — and a simulated sky with ground truth drives both the demo and every end-to-end test.
Screens.


What I considered.
Rejected
Build on an existing ADS-B decoding library
The obvious one, pyModeS, is GPL-3 and this repo is MIT. The codec is my own, and its tests use published reference frames with known decoded values.
Rejected
Decode the weather-satellite images in-house
Viterbi, Reed-Solomon and JPEG for LRPT is SatDump's job, and it does it well. The NOAA APT satellites retired in 2025, so the targets are Meteor-M2 3 and 4.
Chosen
Test decoders on physically modelled signals, not on bit streams
A decoder that passes only on clean bits tells you nothing about a weak frame landing between samples. The cost is that every number is still synthetic until someone plugs in a real dongle.
Results.
- On the demo's synthetic sky, 203 of 204 transmitted ADS-B frames decode with a valid CRC (3 repaired by one-bit correction), all 8 aircraft are located with a median position error of 58 m, and all 6 ships decode from 60 AIS packets.
- AIS decodes with up to ±7 kHz of tuning error; ADS-B positions tested at four locations on four continents, with the codec checked against published Mode S reference frames.
- The identifier names a 433.92 MHz on-off-keyed sensor with high confidence and explains it in plain English; its 11 classes are validated on synthetic signals only.
- 101 tests and a clean fresh-clone install; CI green on Python 3.10–3.13 and macOS on the first run.
Architecture
How it fits together.
- 01
RTL-SDRor SigMF file
Simulated skyground truth
- 02
DSP coredecimate · mix · demodulate
- 03
ADS-BPPM · CRC · CPR
AISGMSK · HDLC · NMEA
- 04
SatellitesSGP4 → SatDump
Identifier11 rule classes
- 05
Web UImap · waterfall · passes · scanner
In hindsight
Nothing here has been run against a real radio. The RTL-SDR and SoapySDR paths are thin wrappers that have never seen a V4, the SatDump hand-off is tested against stand-ins that mimic its two command lines, and the identifier's real-world accuracy is unmeasured. The bundled satellite elements are real but age, so the demo pins its clock near their epoch and says so. The decision I'd make again is testing on modelled signals: it is what caught the classic 2 MS/s weakness for frames whose pulses land between samples, which a bit-level test never would have.
Tech specs.
- Type
- Project
- Where
- Personal
- When
- Oct 2026 → Present
- Duration
- 1 mo
- Status
- v0.1.0 · synthetic-IQ verified
- Stack
- PythonNumPySciPySkyfieldFastAPIWebSocketsLeafletClaudeGitHub Actions
- Caveats
- All decoding is verified on physically modelled synthetic IQ and published reference frames. Not yet run on a real RTL-SDR or a real SatDump install.