Skip to content

feat: Galileo E5a F/NAV decoder#63

Merged
siebc merged 1 commit into
masterfrom
sc/galileo-e5a
Jun 30, 2026
Merged

feat: Galileo E5a F/NAV decoder#63
siebc merged 1 commit into
masterfrom
sc/galileo-e5a

Conversation

@giove-a

@giove-a giove-a commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Adds a decoder for the Galileo Open Service F/NAV message broadcast on the
E5a-I data component (50 sps). It recovers ephemeris, clock correction,
ionospheric correction, BGD, signal health / data validity, GST-UTC and GST-GPS
conversion, and the word-type-5/6 split-almanac chain — per OS SIS ICD v2.2 §5.1
(word types 1–6).

Usage mirrors the existing decoders:

state = GalileoE5aDecoderState(prn)            # or GNSSDecoderState(GalileoE5aI(), prn)
state = decode(state, soft_symbols, n)
is_sat_healthy(state) && # state.data ready for positioning

What's in here

  • src/galileo/e5a.jl — F/NAV decoder: page sync, FEC, CRC, and word-type
    1–6 field parsing, plus the SVID-2 split-almanac stitching across WT5/WT6.
  • src/galileo/galileo.jl (new) — definitions shared by every Galileo
    signal, factored out of e1b.jl: the SignalHealth / DataValidityStatus
    enums, GalileoAlmanac, and the common galileo_viterbi FEC primitive.
  • src/gnss.jl — hoists the package-wide physical constants (GNSS_PI,
    SPEED_OF_LIGHT, EARTH_ROTATION_RATE) to a single source of truth; GPS
    decoders now reference them (values unchanged).

The FEC chain reuses the shared Galileo K=7 NSC Viterbi (G1=0o171, G2=0o133 with
G2 inverted): 12-symbol sync detection → 61×8 block deinterleave → G2 sign-flip
on the soft LLRs → AFF3CT Viterbi (K=238, N=488) → CRC-24Q over the 238-bit page.
Consumes soft symbols end-to-end like L1 C/A and E1B, so the public decode API
is unchanged.

Testing

test/galileo_e5a.jl drives the full decode path against a Spirent PRN 21
capture (152 F/NAV pages). Field values are checked against the independent
Spirent ground-truth dump, so a layout mistake can't be masked by a shared
encode/decode bug. Covered: FEC round-trip, CRC validity, the full
ephemeris/clock frame, the WT5/WT6 split-almanac stitching, the 180° polarity
ambiguity, and reset semantics. Full suite: 2043 / 2043 pass.

Dependency / CI note

Requires GNSSSignals ≥ 2.3 (compat bumped from 2.2), which adds the
GalileoE5aI / GalileoE5aQ signal types (JuliaGNSS/GNSSSignals.jl#83).

⚠️ At time of opening, GNSSSignals 2.3.0 is merged to master but not yet
registered
in General (registry max is 2.2.2). CI will stay red until
2.3.0 is registered
— the "2.3" compat can't resolve before then, so the
failing jobs can simply be re-run once it lands. No further changes are needed
here.

Compatibility

Non-breaking — purely additive (new GalileoE5aDecoderState export). The
e1b.jl / gnss.jl refactor relocates code without changing any public symbol,
signature, or constant value. Suggest a minor version bump (3.0.0 → 3.1.0).

🤖 Generated with Claude Code

@siebc
siebc requested a review from zsoerenm June 29, 2026 12:03
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.13%. Comparing base (6c0fa32) to head (d12a05b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #63      +/-   ##
==========================================
+ Coverage   97.67%   98.13%   +0.45%     
==========================================
  Files          10       12       +2     
  Lines        1336     1499     +163     
==========================================
+ Hits         1305     1471     +166     
+ Misses         31       28       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Decode the Galileo Open Service F/NAV message on the E5a-I data component
(50 sps). Recovers ephemeris, clock correction, ionospheric correction,
BGD, signal health / data validity, GST-UTC and GST-GPS conversion, and
the word-type-5/6 split-almanac chain, per OS SIS ICD v2.2 §5.1 (word
types 1-6).

The FEC chain reuses the shared Galileo K=7 NSC Viterbi (G1=0o171,
G2=0o133, G2 inverted): 12-symbol sync detection, 61x8 block deinterleave,
G2 sign-flip on the soft LLRs, AFF3CT Viterbi (K=238, N=488), then CRC-24Q
over the 238-bit page. Consumes soft symbols end-to-end like L1 C/A and
E1B, so the public decode API is unchanged.

To support this, factor the definitions common to every Galileo signal
(SignalHealth / DataValidityStatus enums, GalileoAlmanac, the
galileo_viterbi FEC primitive) out of e1b.jl into a new
galileo/galileo.jl, and hoist the package-wide physical constants
(GNSS_PI, SPEED_OF_LIGHT, EARTH_ROTATION_RATE) into gnss.jl as a single
source of truth.

Requires GNSSSignals 2.3 (compat bumped from 2.2), which adds the
GalileoE5aI / GalileoE5aQ signal types (GNSSSignals.jl PR #83). The
GNSSDecoderState(::GalileoE5aI, prn) dispatch resolves that type directly,
mirroring the E1B constructor; F/NAV rides only on the E5a-I data
component, so E5a-Q (pilot) does not map to this decoder.

Non-breaking: purely additive (new GalileoE5aDecoderState export). The
e1b.jl/gnss.jl refactor relocates code without changing any public symbol,
signature, or constant value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@siebc
siebc merged commit 86e6c2b into master Jun 30, 2026
9 checks passed
@siebc
siebc deleted the sc/galileo-e5a branch June 30, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants