fix!: consistent nav-data field naming + CNAV-2 EOP ΔUT_GPS scale fix#62
Merged
Conversation
Resolves #60 and extends it with two further inconsistencies found while auditing all nav-data structs against IS-GPS-200/705/800 and the Galileo OS SIS ICD v2.2. Klobuchar ionospheric coefficients (#60): - GPSL5IData, GPSL1C_DData: α0…α3/β0…β3 -> α_0…α_3/β_0…β_3 Almanac SV-clock coefficients (#60): - GPSL1CAAlmanac: af0/af1 -> a_f0/a_f1 SV health (D): - GPSL1CAData: svhealth -> sv_health, matching the sibling sv_health_sf4_25/ sv_health_sf5_25 fields; IS-GPS-200 labels all of them identically "SV Health". Rate of inclination (E): - GPSL5IData, GPSL1C_DData: i_0_dot -> i_dot. IS-GPS-200/705/800 name this IDOT (an absolute rate, not a delta), matching LNAV/Galileo i_dot; also aligns with PositionVelocityTime.jl's generic data.i_dot access. BREAKING CHANGE: renamed public struct fields on GPSL1CAData, GPSL1CAAlmanac, GPSL5IData and GPSL1C_DData. Downstream code reading the old names must update. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The L1C-D subframe-3 page-2 EOP field was decoded as ΔUT1 = UT1−UTC with scale 2⁻²⁴, reflecting a pre-Rev-G interpretation of the ICD. IS-GPS-800J Table 3.5-5 defines the 31-bit field as ΔUT_GPS = UT1−GPS (UT1−GPST) with scale 2⁻²³ (the rate keeps scale 2⁻²⁵). This brings L1C-D in line with the latest ICD and with the L5 CNAV MT32 decoder, which already uses ΔUT_GPS. - Rename struct/parser field ΔUT1/ΔUT1_dot → ΔUT_GPS/ΔUT_GPS_dot. - Fix scale factor 2⁻²⁴ → 2⁻²³ for the value; rate unchanged. - Update docstring/comments and the SF3 page-2 test expectation. Fixes #61. BREAKING CHANGE: the GPSL1C_DData fields ΔUT1/ΔUT1_dot are renamed to ΔUT_GPS/ΔUT_GPS_dot, and the decoded ΔUT_GPS value is now twice the previous (incorrect) value due to the 2⁻²⁴ → 2⁻²³ scale-factor fix. Downstream code reading data.ΔUT1 must be updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SF3 page-2 EOP assertions previously checked `raw * <the decoder's own LSB>`, which is tautological for scale factors — it cannot detect a wrong scale (this is how the earlier 2⁻²⁴ ΔUT_GPS bug went unnoticed). Re-anchor the EOP fields to Spirent's L1C reference capture: feed the raw integers Spirent actually transmitted and assert the physical values its own reference decoder reported. The expected values now come from an independent decoder, so a scale regression fails the test. Verified: reverting the decoder to 2⁻²⁴ makes the new ΔUT_GPS assertion fail. ΔUT_GPS is asserted as 2× Spirent's printed Delta_UT1, since Spirent uses the pre-Rev-G UT1−UTC scale 2⁻²⁴ while IS-GPS-800J Table 3.5-5 defines ΔUT_GPS = UT1−GPS at 2⁻²³ (matching the L5 MT32 golden test). GGTO stays synthetic — the capture carries no GGTO data — to retain its scale-factor coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #62 +/- ##
=======================================
Coverage 97.67% 97.67%
=======================================
Files 10 10
Lines 1336 1336
=======================================
Hits 1305 1305
Misses 31 31 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
zsoerenm
approved these changes
Jun 24, 2026
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
Resolves the field-naming inconsistencies in #60, extends them with two more found
while auditing every nav-data struct against IS-GPS-200/705/800 and the Galileo
OS SIS ICD v2.2, and fixes a CNAV-2 EOP scale-factor bug (#61) that the audit
surfaced. All names/scales are verified against the current ICDs and cross-checked
with GNSS-SDR and RTKLIB/PocketSDR.
Three self-contained commits:
refactor!— unify nav-data field names across signalsfix(l1c_d)!— correct CNAV-2 EOP ΔUT_GPS per IS-GPS-800J (Fixes Wrong LSB scale factor for CNAV-2 (L1C) EOP UT1-GPS difference: 2^-24 should be 2^-23 #61)test(gpsl1c)— anchor the SF3 page-2 EOP test to a Spirent L1C reference capture1. Field-naming unification (breaking)
GPSL5IData,GPSL1C_DDataα0…α3,β0…β3α_0…α_3,β_0…β_3M_0,i_0); aligns withGPSL1CAData(#60)GPSL1CAAlmanacaf0,af1a_f0,a_f1GPSL1CADatasvhealthsv_healthsv_health_sf4_25/_sf5_25; de-gluedGPSL5IData,GPSL1C_DDatai_0_doti_dotIDOT(absolute, not a delta); matches LNAV/Galileoi_dot, GNSS-SDR/RTKLIBidot, andPositionVelocityTime.jl's genericdata.i_dotaccess2. CNAV-2 EOP ΔUT_GPS fix (breaking — value change)
The L1C-D subframe-3 page-2 EOP field was decoded as
ΔUT1(UT1−UTC) with scale2⁻²⁴, a pre-Rev-G reading of the ICD. IS-GPS-800J Table 3.5-5 (and IS-GPS-705JTable 20-VII) define it as
ΔUT_GPS(UT1−GPS) with scale2⁻²³— the rate keeps2⁻²⁵. This brings L1C-D in line with the current ICD and with the already-correctL5 CNAV MT32 decoder.
GPSL1C_DData.ΔUT1/ΔUT1_dot→ΔUT_GPS/ΔUT_GPS_dotΔUT_GPSis now 2× the previous (incorrect) value3. Test hardening
The SF3 page-2 EOP assertions previously checked
raw * <the decoder's own LSB>—tautological for scale factors, which is exactly why the
2⁻²⁴bug went unnoticed.They're now anchored to a Spirent GSS L1C reference capture: the raw integers
Spirent transmitted are fed in, and the assertions are Spirent's own
reference-decoder values (an independent oracle). Confirmed it now catches the bug —
reverting the decoder to
2⁻²⁴makes the test fail.Breaking changes / migration
SemVer-major (public field renames + one value change). Downstream field reads:
Downstream impact checked:
PositionVelocityTime.jlandGNSSReceiver.jlreadnone of the renamed fields — except that PVT's
sat_position.jlalready expectsdata.i_dot, so thei_0_dot → i_dotrename actually aligns the CNAV structswith PVT (no PVT change needed). No consumer reads the EOP fields.
Verification
JuliaFormatter2.8.5: cleanOS SIS ICD v2.2; cross-referenced with GNSS-SDR and RTKLIB/PocketSDR
Release note
This is breaking —
Project.tomlstill reads2.1.0and needs a 3.0.0 bumpbefore tagging (not done in this PR yet).
Closes #60
Fixes #61