Thread the altitude layer set through the associator - #31
Merged
Merged
Conversation
An n=2 solve is exactly determined in (x, y) once the altitude is pinned, so its position error IS its altitude error. On a 20-minute test capture against ground truth, n=2 solves had a median altitude error of 1.46 km (p90 5.25) and a position error of 1.61 km when the altitude landed within 1 km of truth against 2.71 km when it did not (n=3, for contrast: 0.36 vs 2.54 km). That altitude comes from here — compute_overlap_zone precomputes each node pair's overlap on a horizontal lattice at a handful of altitude layers, and detection_association picks the best grid point and a delay-residual-weighted mean altitude across them. The horizontal step is not the limiter (the LM solve converges happily from a 3 km start); the altitude ladder is, and it was frozen at six layers whose widest gap (1.5 -> 3.0 -> 5.0) is 2 km. So make the ladder a parameter rather than a hardcode: altitudes_km on InterNodeAssociator, threaded into compute_overlap_zone on both zone-build paths (register_node and the rebuild), exactly the way grid_step_km already is. The library default is unchanged — DEFAULT_ALTITUDES_KM is the historic (1.5, 3.0, 5.0, 7.0, 9.0, 11.0), so every existing caller, unit test and offline bench sees the identical grid it saw before. The deployment is what overrides it. Cost is linear and nothing else moves: the columns are altitude-independent (that is the property the both-beams restructure rests on), so a twelve-layer ladder emits exactly twice the grid points of a six-layer one over the same geometry and pays twice the precompute. A test pins that ratio, and another pins that the associator's configured ladder actually reaches the zones register_node builds — a layer set that only takes effect on one of the two build paths would be worse than none. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Why
An n=2 solve is exactly determined in (x, y) once altitude is pinned, so its position error is its altitude error. On a 20-minute capture against ground truth (dark lane), n=2 solves had a median altitude error of 1.46 km (p90 5.25) and a position error of 1.61 km when the altitude was within 1 km of truth vs 2.71 km when it was not (n=3, for contrast: 0.36 vs 2.54 km).
That altitude comes from this library:
compute_overlap_zoneprecomputes each node pair's overlap on a horizontal lattice at a fixed set of altitude layers, anddetection_associationpicks the best grid point plus a delay-residual-weighted mean altitude across them. The horizontal step is not the limiter — the LM solve converges from a 3 km start. The altitude ladder is, and it was hardcoded at six layers whose widest gap (1.5 → 3.0 → 5.0 km) is 2 km.What
altitudes_kmis now a parameter ofInterNodeAssociator, threaded intocompute_overlap_zoneon both zone-build paths (register_nodeand the rebuild), exactly the waygrid_step_kmalready is.DEFAULT_ALTITUDES_KMkeeps the historic(1.5, 3.0, 5.0, 7.0, 9.0, 11.0)as the library default, so every existing caller, unit test and the offline bench see the identical grid they saw before. The deployment overrides it.5, 7, 9, 11, "six altitudes") now describe the configurable ladder instead of a frozen one.Cost
Linear, and nothing else moves: the columns are altitude-independent (the property the both-beams restructure rests on), so a twelve-layer ladder emits exactly 2× the grid points of a six-layer one over the same geometry and pays 2× the precompute. Measured on the test fixture pair: at
grid_step_km=5.0, 66 → 132 grid points (4.2 → 4.7 ms); at the productiongrid_step_km=3.0, 180 → 360 grid points (9.3 → 13.3 ms). The per-zone build is dominated by the once-per-column both-beams test, so the wall cost grows well under 2×.Tests
108 passedacrosstest_association.py,test_detection_association.py,test_coverage_prior.py,test_bistatic_footprint.py. Two new ones pin the 2× ratio and that the associator's configured ladder actually reaches the zonesregister_nodebuilds — a layer set that took effect on only one of the two build paths would be worse than none.ruff check/ruff format --checkclean.Consumed by the retina-server PR "Finer altitude layers and altitude continuity for n=2 solves".
🤖 Generated with Claude Code