Skip to content

Seed the world with live ADS-B traffic from adsb.retina.fm - #14

Merged
jehanazad merged 1 commit into
mainfrom
feat/live-adsb-seed
Sep 10, 2026
Merged

jehanazad merged 1 commit into
mainfrom
feat/live-adsb-seed

Conversation

@jehanazad

Copy link
Copy Markdown
Contributor

Summary

  • New retina_simulation/live_adsb.py: LiveAdsbClient polls an adsb.lol-shaped feed (/v2/point/{lat}/{lon}/{radius_nm} — what adsb.retina.fm serves) and normalises tar1090 rows (ground/positionless rows dropped, seen_pos resolved to an absolute capture time, last-good cache across a failed fetch).
  • SimulationWorld.ingest_live_aircraft turns feed rows into live-<hex> world aircraft flying their real position/altitude/ground speed/track/vertical rate, extrapolated from the fix's capture time and dead-reckoned between polls. They are echoed by the synthetic nodes like any other aircraft, but the feed owns them: no waypoints, no separation slowing, no lifetime — they expire only when the feed stops reporting them (live_stale_s, 60 s).
  • frac_live_dark casts a share of the live aircraft as dark: mirrored without their transponder (has_adsb off, adsb_hex None → no tag in node frames, omitted from the ADS-B push, ground truth keyed by object id — the shape of a synthetic dark spawn with a real trajectory underneath). The cast is a stable per-hex hash, so moving the knob re-partitions the aircraft already in the air (raising it only ever adds dark aircraft) and set_frac_live_dark applies it at the next config poll.
  • Independence: spawning now counts synthetic aircraft only, so min/max_aircraft + frac_dark keep governing the synthetic traffic layered on top, whatever the feed reports.
  • Orchestrator: --live-adsb-url / --live-adsb-interval start _seed_live_adsb over the --metro/--metros areas; frac_live_dark and live_adsb_enabled ride the existing /api/simulation/config poll (disabling clears the live aircraft). Ground-truth payloads carry source: live|sim; the ADS-B push carries the callsign. --real-adsb is ignored while seeding runs (both would push the same hexes into one server cache under two world tags).

Server side (fleet entrypoint env, Physics Settings slider, config keys, counts): offworldlabs/retina-server PR to follow, pinning this branch.

Test plan

  • pytest — 200 passed (26 new in tests/test_live_adsb.py: parsing, client URL + last-good fallback, ingest/extrapolation/update/expiry, synthetic independence, dark cast stability/monotonicity, frame/push/GT shapes for both roles)
  • pre-commit run --all-files green (ruff, ruff-format, vulture, ruff-config)
  • Live on the test droplet via the server PR

🤖 Generated with Claude Code

Real aircraft over the fleet's metro now join the simulated world and are
echoed by the synthetic nodes: a new LiveAdsbClient polls an adsb.lol-shaped
feed (/v2/point/{lat}/{lon}/{radius_nm}; adsb.retina.fm serves it), and
SimulationWorld.ingest_live_aircraft turns each row into a `live-<hex>`
aircraft flying its real position, altitude, ground speed, track and
vertical rate, extrapolated from the fix's capture time and dead-reckoned
between polls. The feed owns these aircraft: no waypoints, no separation
slowing, no lifetime — they leave when the feed stops reporting them.

Two independent knobs:

- frac_live_dark casts a share of the LIVE aircraft as dark — mirrored
  without their transponder (has_adsb off, adsb_hex None), so the node
  frames carry no tag for them, the ADS-B push omits them, and the ground
  truth keys them by object id, exactly like a synthetic dark spawn. The
  cast is a stable per-hex hash, so moving the knob re-partitions the
  aircraft already in the air (raising it only adds dark aircraft) instead
  of re-rolling them, and set_frac_live_dark applies it at the next config
  poll rather than the next fleet turnover.
- min/max_aircraft and frac_dark keep governing the SYNTHETIC spawns
  layered on top: spawning counts synthetic aircraft only, so the feed's
  population never starves synthetic spawns or vice versa.

Orchestrator: --live-adsb-url / --live-adsb-interval start _seed_live_adsb
over the --metro/--metros areas; the backend's frac_live_dark and
live_adsb_enabled ride the existing /api/simulation/config poll (pausing
clears the live aircraft). Ground-truth payloads carry source=live|sim;
the ADS-B push now carries the callsign. --real-adsb is ignored while
seeding runs — both would push the same hexes into one cache under two
world tags.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jehanazad
jehanazad merged commit 6ffb678 into main Sep 10, 2026
2 checks passed
@jehanazad
jehanazad deleted the feat/live-adsb-seed branch September 10, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant