Skip to content

Add transponder outages (frac_adsb_outage) - #13

Merged
jehanazad merged 1 commit into
mainfrom
feat/adsb-outage
Sep 8, 2026
Merged

jehanazad merged 1 commit into
mainfrom
feat/adsb-outage

Conversation

@jehanazad

Copy link
Copy Markdown
Contributor

Summary

The simulator never stopped ADS-B. Every has_adsb aircraft was tagged in every node frame and pushed to the server every second for its whole life, so the backend's "known-track hold" (a node track claimed to an ADS-B hex staying claimed after the broadcast stops) had no way to be exercised against simulated traffic.

This adds a transponder-outage model: an ADS-B aircraft goes silent mid-flight and comes back. has_adsb and adsb_hex are deliberately untouched — the aircraft still HAS a transponder, it is simply not broadcasting, which is what separates this from a dark target.

Default is 0.0 (off): nothing changes for anyone who does not set the knob.

Changes

  • SimulatedAircraft: adsb_outage_start_s / adsb_outage_end_s (world-clock seconds), sim_now_s (clock refreshed each step()), and an adsb_silent property.
  • SimulationWorld.frac_adsb_outage (default 0.0) — the fraction OF the ADS-B population that gets an outage. Rolled at spawn: start 20–120 s after spawn, duration 60–240 s. Those bounds are module constants: long enough to age past the backend's 45 s fix cap and 60 s map expiry, short enough to recur several times in a 20-minute capture.
  • schedule_adsb_outages() rolls live ADS-B aircraft that have no window yet (start 5–60 s out), so raising the knob at runtime does not have to wait for a fleet turnover. Aircraft that already carry a window are skipped, so a 5 s config poll cannot re-roll the same aircraft forever.
  • generate_detections_for_node: while silent, the ADS-B list gets a None slot — exactly what a dark aircraft gets. Delay/Doppler/SNR and the miss model are unchanged, so the echo is still there.
  • get_aircraft_summary reports adsb_silent; build_ground_truth_payload passes it through; build_adsb_push_payload skips silent aircraft (that push IS the broadcast).
  • _poll_simulation_config applies cfg["frac_adsb_outage"] (default 0.0) alongside frac_dark, and re-rolls in-flight aircraft when it is on.

Test coverage

New tests/test_adsb_outage.py: knob at 1.0 vs 0.0, dark aircraft never scheduled, half-open silence window, runtime re-roll (including the idempotence of repeated polls), tag present before/after and None during, radar detections unaffected while silent, summary flag, ground-truth passthrough with a legacy-payload default, and push-payload skipping. tests/test_dual_fraction.py's stub world gained the new attribute/method.

Full lib suite: 128 passed, 5 skipped.

Review notes

  • The outage is intentionally orthogonal to frac_dark: it is a fraction of the ADS-B aircraft, not a spawn-type roll, so it does not participate in the frac_* sum.
  • adsb_silent reads sim_now_s rather than a back-reference to the world; step() refreshes it for every aircraft, and _spawn_aircraft seeds it.

🤖 Generated with Claude Code

The simulator never stopped ADS-B: every has_adsb aircraft was tagged in
every node frame and pushed every second, so the backend's known-track hold
(a node track claimed to a hex staying claimed after ADS-B stops) could not
be exercised live.

SimulatedAircraft now carries an outage window (adsb_outage_start_s /
adsb_outage_end_s, world-clock seconds) plus an adsb_silent property.
has_adsb and adsb_hex are untouched — the aircraft still HAS a transponder,
it is silent. While silent the node frame gets a None ADS-B slot (exactly
what a dark aircraft gets), the ADS-B push skips the aircraft entirely, and
the summary / ground-truth payload carry adsb_silent so the server can tell
a silent transponder apart from a genuinely dark target.

SimulationWorld.frac_adsb_outage defaults to 0.0 (off), rolls at spawn, and
is applied by the config poll alongside frac_dark. Raising the knob at
runtime also rolls aircraft already in the air (schedule_adsb_outages), so
verification does not have to wait for a fleet turnover.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jehanazad
jehanazad merged commit f06d534 into main Sep 8, 2026
2 checks passed
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