Overhaul ADS-B pipeline: dead reckoning, signal-gap handling, stale-track rendering#117
Merged
Merged
Conversation
…endering Server side (poller): - Dead-reckon stale BEAST positions forward along the last known velocity (bounded by ADSB_DEAD_RECKON_MAX_SECONDS, default 60s) so tracks keep moving through CPR gaps instead of freezing; altitude projects with the vertical rate. DR positions are flagged position_dr, never enter trails, DB observations, or geofence checks. - Seed the decoder's Tier-2 CPR reference from OpenSky/ultrafeeder positions so a single odd/even frame resolves position on (re-)entry into SDR range instead of waiting up to ~60s for a fresh even+odd pair. - Refresh decoder entities on every snapshot tick so DR advances during a total feed outage; bound the CPR heading-consistency guard to <30s gaps so it can't reject the first good fix after a long gap. - Fold in the raw-byte DF/length fast path from PR #115 (credit: Jules). - normalize_tar1090: handle alt_baro=="ground" (no more "ground" string in altitude, correct on_ground status), honor seen_pos for stale/ancient positions, null non-numeric track/gs/baro_rate. - Redis-hydrated aircraft now report position_stale until a real fix arrives. Frontend: - PVB keeps projecting dead-reckoned tracks between reports (previously stale tracks froze then snapped); positionDr joins the report key. - Stale/DR local aircraft render dimmed like OpenSky supplements. - Entity/Track types carry position_stale/position_dr/position_age_s. Tests: 13 new decoder tests (fast path, DR bounds, seed arbitration), 9 new tar1090 tests. Full poller suite passes (155), tsc clean. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01G6ZwvPTHAZ76MxF6swwryH
d3mocide
marked this pull request as ready for review
July 6, 2026 00:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
End-to-end overhaul of the ADS-B pipeline (local SDR BEAST feed + OpenSky supplement) targeting the three reported pain points: dead reckoning, odd signal gaps, and frontend rendering of stale tracks.
Server-side dead reckoning (
poller/normalizers/beast_decoder.py)project_position()(which existed inbeast_math.pybut was never called). DF17 TC19 velocity messages usually keep decoding through CPR position gaps, so the projected track stays close to truth.ADSB_DEAD_RECKON_MAX_SECONDS(default 60 s); the stale threshold is now configurable viaADSB_POSITION_STALE_SECONDS(default 10 s). Altitude projects with the vertical rate.position_dr(plusposition_age_s) and are estimates only: they never enter the trail ring buffer, DB observation history, or geofence entry/exit checks (guarded both at the publish call and insidedb.write_entity_observation).Signal-gap fixes
seed_reference()), so a single odd/even frame resolves a position the moment an aircraft (re-)enters SDR range — previously a cold lock waited up to ~60 s for a fresh even+odd pair. Local fixes stay authoritative; seeds apply only when the decoder's own fix is missing or stale.normalize_tar1090fixes:alt_baro: "ground"no longer leaks the string intoaltitudeand now correctly setson_groundstatus (readsb has noon_groundkey);seen_posis honored (drop > 60 s, flag stale > 10 s); non-numerictrack/gs/baro_rateare nulled.position_staleuntil a real fix arrives, matching the hydration docstring's intent.Frontend rendering
projectedSpeed = 0), then snapped to the next fix.positionDrjoins the report key so DR↔fix transitions re-blend smoothly.Entity/Tracktypes now carryposition_stale/position_dr/position_age_s.Relationship to PR #115
The raw-byte DF/length fast path from #115 (Jules) is folded into this branch verbatim (with credit) since this overhaul rewrites the surrounding
ingest()lines — merging this PR supersedes thebeast_decoder.pyhalf of #115. The.jules/bolt.mdlog addition in #115 is untouched here, so #115 can still be merged for that file (expect a trivial conflict inbeast_decoder.pyif it merges second).Testing
seen_posstaleness, non-numeric fields).tsc --noEmit: clean.docker compose config: valid.🤖 Generated with Claude Code
https://claude.ai/code/session_01G6ZwvPTHAZ76MxF6swwryH
Generated by Claude Code