Write the aircraft down, and draw where they went
ADS-B was a live table and nothing else: an aircraft was overhead for four minutes and then gone, with nothing kept. Now everything heard goes into adsb_<time>.jsonl as it arrives -- one object per frame, the raw hex beside what was read out of it, flushed per line because a listening session ends with control-C -- with a readable report beside it. flights.py asks who the aircraft are: adsbdb for the airframe and the route, hexdb behind it, cached for a month. What needs no website is answered without one, because the ICAO address block says which country registered the aircraft and the first three letters of an airline callsign are its designator. Nothing but the address and the callsign heard on the air is ever sent. bandsaunter flights [LOG...] --out sky.gif reads a log back and draws the evening as a map with the clock running. Every frame is a moment: each aircraft is where it actually was then, interpolated between the position reports either side of it and dead-reckoned from its last speed and heading between them, and dropped rather than guessed at once it has not been heard for --stale seconds. The GIF is written here -- palette, LZW, frame differencing against a transparent index -- so nothing but numpy is needed; ffmpeg writes an MP4 where it happens to be installed, and .png draws the whole evening at once. The decoder needed 6.3 s to read a second of sky, so a live capture was losing six frames in seven. Reading the bits off a running total instead of summing each window takes that to 0.6 s, with identical output. --simulate flies six aircraft that are not there past a receiver that is not there, through the real encoder, the real checksum and the real decoder, so all of this can be tried without an aerial. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
This commit is contained in:
parent
a8a8548369
commit
eae60cb04d
15 changed files with 3857 additions and 177 deletions
84
README.md
84
README.md
|
|
@ -942,7 +942,8 @@ turns it off.
|
|||
```bash
|
||||
bandsaunter adsb # listen on 1090 MHz until interrupted
|
||||
bandsaunter adsb --frames # print every frame as it arrives
|
||||
bandsaunter adsb --kml planes.kml # and write what was heard as a map
|
||||
bandsaunter adsb --simulate # invent a sky, for a receiver with no aerial
|
||||
bandsaunter flights # read the log back: report, map, animation
|
||||
```
|
||||
|
||||
Every airliner overhead broadcasts its address, callsign, altitude, position
|
||||
|
|
@ -973,7 +974,86 @@ than resolved against two different grids.
|
|||
|
||||
An aerial cut for 1090 MHz is the difference between hearing the airport and
|
||||
hearing the county; the whip supplied with a dongle is a quarter of the length
|
||||
it wants.
|
||||
it wants. `--simulate` flies six imaginary aircraft past an imaginary receiver
|
||||
— real frames, real checksums, the same decoder — so the whole of the rest of
|
||||
this section can be tried before any of that is wired up.
|
||||
|
||||
### What is written down
|
||||
|
||||
An aircraft is overhead for four minutes and then gone, so everything heard
|
||||
goes into a log as it arrives: `adsb_<time>.jsonl` in the output directory, one
|
||||
JSON object per frame, flushed as it is written because a listening session
|
||||
ends with control-C.
|
||||
|
||||
```json
|
||||
{"t":1788496791.486,"icao":"4008F6","df":17,"tc":19,
|
||||
"hex":"8D4008F69905A11E202C00D3450D","gs_kt":480.3,"track":300.0,"vs_fpm":640}
|
||||
```
|
||||
|
||||
**The raw frame goes down next to what was read out of it**, because the frame
|
||||
is the evidence and everything else on the line is an opinion about it: a
|
||||
better decoder can be run over the same evening later. Beside it goes a
|
||||
readable report, one block per aircraft. A frame costs about 160 bytes on
|
||||
disk, so a busy sky is a few tens of megabytes an hour; `--no-log` listens
|
||||
without writing anything down.
|
||||
|
||||
### Who the aircraft is
|
||||
|
||||
The frames say `4008F6`, not "a Boeing 747 registered in the United Kingdom
|
||||
flying Heathrow to Seattle". That comes from a register, and two are asked —
|
||||
[adsbdb](https://api.adsbdb.com) for the airframe and the route, then
|
||||
[hexdb](https://hexdb.io) — with the answers cached for a month. Nothing is
|
||||
sent to either but the address or the callsign that was heard on the air.
|
||||
|
||||
What can be answered without asking anybody is: the **address block** says
|
||||
which country registered the aircraft (fixed by treaty, so `4008F6` is British
|
||||
and `A835AF` is American with no network at all), and the first three letters
|
||||
of an airline callsign are its ICAO designator, so `RYR1234` is Ryanair.
|
||||
`--no-lookup` stops at that.
|
||||
|
||||
```
|
||||
4008F6 BAW49
|
||||
registration: G-VROS
|
||||
aircraft: Boeing Company 747-443
|
||||
operator: CELESTIAL AVIATION TRADING 14 LTD
|
||||
registered in: United Kingdom
|
||||
route: London Heathrow Airport → Seattle Tacoma International Airport
|
||||
heard: 2026-09-03 21:44:47 to 2026-09-03 21:48:46 (3 min 59 s, 132 frames)
|
||||
from: 48.2742, -121.7963
|
||||
to: 48.5334, -122.4725
|
||||
flew: 31.2 nm over 81 positions
|
||||
altitude: 33,000 to 35,475 ft
|
||||
speed: up to 480 kt
|
||||
```
|
||||
|
||||
### The moving map
|
||||
|
||||
```bash
|
||||
bandsaunter flights # the newest log: report and a GIF
|
||||
bandsaunter flights evening.jsonl --out sky.mp4 --speed 60
|
||||
bandsaunter flights --out sky.png # the whole evening in one picture
|
||||
bandsaunter flights --kml --no-map # for Google Earth instead
|
||||
```
|
||||
|
||||
A log is a list of times and places; drawn on a map with the clock running it
|
||||
is an evening's air traffic. **Every frame is a moment**: each aircraft is
|
||||
drawn where it actually was then — interpolated between the position reports
|
||||
either side of it, and dead-reckoned from its last known speed and heading
|
||||
where none arrived — so an aircraft crossing the picture in ten seconds took
|
||||
the twenty minutes the data says it took. Nothing moves at a constant speed
|
||||
for the look of the thing, and an aircraft not heard from for five minutes
|
||||
stops being drawn rather than being flown on by guesswork.
|
||||
|
||||
Time runs at `--speed` seconds of flying per second of animation, or give
|
||||
`--seconds` and let it work the speed out. Altitude is the colour, low warm to
|
||||
high cold, with the key along the bottom; the trail behind each aircraft is the
|
||||
path it actually flew, in the colours of the heights it flew them at.
|
||||
|
||||
The GIF is written here from first principles — a palette, an LZW stream, frame
|
||||
differencing with a transparent index — in the same spirit as the PNGs
|
||||
elsewhere, so nothing but numpy is needed to draw one. Where ffmpeg happens to
|
||||
be installed, `--out something.mp4` is smaller and smoother; where it is not,
|
||||
nothing breaks and a GIF is written instead.
|
||||
|
||||
## Meters and weather sensors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue