fix(gpscnav): don't require T_GD for positioning readiness#68
Merged
Conversation
`is_clock_correction_decoded` gated `is_decoding_completed_for_positioning` on T_GD, but CNAV broadcasts T_GD only in message type 30. On streams that carry the SV clock via MT31-37 without MT30, every message decodes and the ephemeris + clock polynomial complete, yet positioning never validates (and, downstream, raw_data is never promoted to data / the streaming counter never re-armed). Per IS-GPS-200 Table 30-XII (L2C) and IS-GPS-705J Table 20-XII (L5), T_GD (MT30 only) has a maximum broadcast interval of 288 s (L2C) / 144 s (L5), versus 48 s / 24 s for the clock (any of MT30-37) and the ephemeris (MT10/11) — ~6x less often. Gating a fix on T_GD can therefore stall positioning for minutes on a fully spec-compliant SV. Require only the SV clock polynomial (t_0c, a_f0/a_f1/a_f2); T_GD is a ~metre-level inter-signal correction applied downstream when present. Affects both GPS L2C and L5I (shared CNAV core). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #68 +/- ##
=======================================
Coverage 98.15% 98.15%
=======================================
Files 14 14
Lines 1515 1515
=======================================
Hits 1487 1487
Misses 28 28 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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
is_clock_correction_decoded(::GPSCNAVData)gated positioning readiness onT_GD. SinceT_GDis broadcast only in CNAV message type 30 — separatelyfrom, and far less often than, the SV clock — a receiver could fully decode a
satellite's ephemeris and clock yet never report it usable for positioning. This
drops the
T_GDrequirement (the SV clock polynomial is sufficient for a fix);T_GDis still applied downstream when present. Affects GPS L2C and L5I(shared CNAV core).
Root cause
is_decoding_completed_for_positioning→is_clock_correction_decodedrequiredt_0c, a_f0, a_f1, a_f2andT_GD. The clock polynomial rides in the sharedclock block of any of MT30–37 (
parse_clock_block), butT_GDis set only byparse_mt30. Positioning readiness was therefore silently coupled to MT30 beingin the broadcast schedule.
On a CNAV stream that carries the clock via MT31–37 without MT30, every message
decodes and the ephemeris + clock complete, but positioning never validates — and
because
validate_datais gated on the same check,raw_datais never promotedto
data(and the streaming counter never re-armed), so nothing downstream workseither.
Why T_GD must not gate a fix (ICD)
T_GDis a ~metre-level inter-signal (group-delay) correction, not required for aposition solution, and it is structurally infrequent. Maximum broadcast intervals:
So
T_GDis guaranteed only ~6× less often than the clock/ephemeris — requiringit can stall a fix for up to 288 s (L2C) / 144 s (L5) on a fully spec-compliant
satellite.
For reference within the codebase: GPS L1C-D (CNAV-2) already does not gate
positioning on
T_GD/ISC (only TOI + subframe-2 CED), and LNAV is unaffected(
T_GDrides in subframe 1 alongside the clock). This change brings CNAV in line.The fix
Remove
!isnothing(data.T_GD)fromis_clock_correction_decoded; require onlythe SV clock polynomial (
t_0c, a_f0, a_f1, a_f2). One function, plus a commentdocumenting the ICD rationale, and a note on the
GPSCNAVDatadocstring that theMT30-only fields (
T_GD, ISCs, Klobucharα/β) may benothingeven oncepositioning is ready.
Validation (real + simulated captures)
satellites whose MT30 lags; after — L2C produces a continuous PVT that agrees
with the independent L1 C/A solution to < 1 m (and the L2C-decoded orbit
matches the L1 broadcast to 0.82 m).
before — all 10 L2C and all 10 L5I satellites decode a full ephemeris but 0
position (T_GD never arrives); after — they validate and position, all three
bands (L1 / L2C / L5I) landing on the Fraunhofer IIS site to ~0.2 m.
Testing
Pkg.test()— 2446/2446 pass, includingAqua.test_all.decode_oncefixtures carry MT30,and the
!is_decoding_completed_for_positioningassertion in the L5I tests isgated by the ephemeris check (MT11 absent), not the clock check.
Related (not in this PR)
On MT30-less streams
PositionVelocityTimestill needs the MT30-only correctionsT_GD,ISC_L2C/ISC_L5I5, and the Klobucharα/β, and throws+(::Float64, ::Nothing)when they're absent. A companion PVT change to treatthese as absent-→-zero (and skip iono when
α/βare missing) would let L2C/L5position end-to-end without a workaround.
🤖 Generated with Claude Code