Publish a synthetic node's declared cone as its detection area - #32
Merged
jehanazad merged 1 commit intoSep 15, 2026
Merged
Conversation
get_node_summary publishes to_polygon(evidence_only=True) for every node. That is right for real hardware — a real node's beam_azimuth_deg and beam_width_deg are unsurveyed configuration, so drawing them would claim coverage nobody measured — but it is wrong for a simulator node. The simulator emits a detection only for an aircraft inside the node's declared cone (retina_simulation/world.py::_aircraft_in_detection_cone), so for those nodes the cone IS the detection area by definition, and the evidence is the unreliable half: the calibration points come from ADS-B hexes bound to tracks and roughly a third of those binds are to the wrong aircraft. Measured on test 2026-09-13, synth-GVL-SCAT-0032 (42 deg beam) held 3,037 calibration points of which 47% lay outside its wedge (34% ignoring the two edge bins), 55 out-of-wedge bins had opened, and the published polygon covered 71 of 72 bearings. Every synthetic node on the test map draws as a disc. So: EmpiricalCoverageState.declared_wedge_polygon() draws the prior azimuth and width at _reach_at on each bearing — already the bistatic ellipse when a differential limit and the TX are known, else the circle, which is exactly the simulator's own range rule — with no clamp, no bins and no min-points gate. An omni prior gets a full ring; a directional one an apex-closed wedge with both edges exact. NodeAnalyticsManager.register_node grows a keyword-only declared_geometry_is_truth flag (default False, asserted per registration, so a re-registration without it drops the node again), and get_node_summary publishes the declared wedge for a flagged node and the evidence-only shape for everyone else. The FOV diagnostics block is skipped for a flagged node — it describes the learned wedge, which such a node does not publish — while n_points/n_filled_bins stay in the payload: the evidence is still accumulated and still worth reporting, it just is not drawn. Every summary now names its "polygon_source" (declared / evidence / learned) so the map can say which it is showing rather than guess. A flag change invalidates the 60 s summaries cache the same way a rebuilt detection area does; retire_node, _reset_for_tests and the "cannot place this node" path all clear it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
jehanazad
added a commit
that referenced
this pull request
Sep 15, 2026
Publish a synthetic node's declared cone as its detection area (#32 onto main)
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.
Summary
Adds
EmpiricalCoverageState.declared_wedge_polygon()and a per-nodedeclared_geometry_is_truthflag onNodeAnalyticsManager.register_node, so a node whose declared cone is its detection area (a simulator node) is published as that cone instead of as its accumulated evidence. Real nodes are unchanged: evidence-only polygon, now taggedpolygon_source: "evidence"("learned"under FOV shadow/active).Stacked on #28 (base branch is its head); merge #28 first and GitHub retargets this one to
main.Why
The simulator only emits a detection for an aircraft inside a node's declared cone (
retina_simulation/world.py::_aircraft_in_detection_cone), so for a synthetic node the wedge is ground truth. The calibration points that feed the evidence polygon come from ADS-B hexes bound to tracks, and a steady share of those binds are the wrong aircraft. Measured on the test deployment 2026-09-13 from the persisted bins: one 42° node held 3,037 points of which 47 % lay outside its wedge (34 % ignoring the two edge bins); 55 out-of-wedge bins had reachedFOV_OPEN_MIN_POINTS, and the published polygon covered 71 of 72 bearings. Across an eight-node sample 5–41 % of points were fully outside the wedge, yet even a 5 % node opened 15+ stray bearings, because three points open a bin.Changes
declared_wedge_polygon(step_deg=2.5): apex, both wedge edges exactly plus everystep_degbetween, apex — radius per bearing is_reach_at(the bistatic ellipse when TX + differential limit are declared, else the monostatic circle: the simulator's own range rule), no clamp multiplier, no bins read. Omni prior → closed ring, no apex.register_node(..., *, declared_geometry_is_truth=False): membership in_declared_truthasserted per registration, dropped on retire / reset / loss of geometry; a membership change invalidates the summaries cache.get_node_summary: declared nodes publish the wedge withpolygon_source: "declared"regardless ofn_points, and skip the evidence-derived FOV diagnostics; everyone else gainspolygon_source.Test coverage
tests/test_declared_wedge.py: 26 new tests — vertex bearings within half-width and ranges at_reach_at(±1 %), both edges present, closure, omni ring, elliptical vs circular reach, manager publication for flagged / unflagged nodes, zero-point publication, flag drop on re-register and retire, cache invalidation.pre-commit run --all-files: ruff, ruff-format, vulture, ruff-config all pass.SimulationWorld._aircraft_in_detection_coneon 25,919 / 25,921 grid points; both disagreements sit on the boundary.Review notes
offset_latlonstep every polygon in the file uses, so reading a vertex back spherically shows a ~0.2° convergence term at 50 km; the tests measure spherically on purpose and carry a documented 0.25° slack.🤖 Generated with Claude Code