API Reference

Decoder State

GNSSDecoder.GNSSDecoderState — Type
struct GNSSDecoderState{D<:GNSSDecoder.AbstractGNSSData, C<:GNSSDecoder.AbstractGNSSConstants, CA<:GNSSDecoder.AbstractGNSSCache}

Generic decoder state for GNSS signal decoding. This parametric struct holds all state required for decoding navigation messages from GNSS satellites.

The struct itself is immutable; per-field reconstruction works via the keyword constructor. Every buffer a decoder needs is allocated once, by the per-signal constructor, and owned by the state: the soft-symbol CircularDeque{Float32} (capacity syncro_sequence_length + preamble_length), the FEC scratch and voting tallies in the cache, and the containers (almanac stores, health tables, ...) that raw_data and data reference, preallocated in the cache's DataStorage.

Those buffers are overwritten by decode!, which is what makes it allocation-free: the state it returns shares them with the state passed in, so treat the returned value as the live state and do not use the earlier one; take a copy if a snapshot is needed. The transient packed-bit buffer used for preamble matching is not stored here; it is computed as a local value at sync time and threaded through the sync path (see pack_buffer / try_sync).

Type Parameters

  • D<:AbstractGNSSData: The data type holding decoded navigation message fields
  • C<:AbstractGNSSConstants: Constants specific to the GNSS system (e.g., preamble, timing)
  • CA<:AbstractGNSSCache: Cache for intermediate decoding state (carries the soft-symbol buffer)

Fields

  • prn::Int64: Pseudo-Random Noise code identifier for the satellite
  • raw_data::GNSSDecoder.AbstractGNSSData: Partially decoded navigation data (not yet validated)
  • data::GNSSDecoder.AbstractGNSSData: Validated navigation data ready for use
  • constants::GNSSDecoder.AbstractGNSSConstants: System-specific constants (preamble, timing parameters)
  • cache::GNSSDecoder.AbstractGNSSCache: Cache for intermediate decoding state (holds the soft-symbol CircularDeque{Float32})
  • num_bits_after_valid_syncro_sequence::Union{Nothing, Int64}: Number of symbols received after the last valid synchronization sequence, or nothing if not yet synchronized
  • is_shifted_by_180_degrees::Bool: Whether the signal phase is inverted by 180 degrees

See Also

source

Constructors

GNSSDecoder.GPSL1CADecoderState — Function
GPSL1CADecoderState(
    prn
) -> GNSSDecoderState{GPSL1CAData, GNSSDecoder.GPSL1CAConstants, GNSSDecoder.GPSL1CACache}

Create a decoder state for GPS L1 C/A navigation messages.

Initializes a GNSSDecoderState configured for decoding GPS L1 C/A (Coarse/Acquisition) civil navigation messages. The decoder extracts ephemeris, clock correction, and health data from the 50 bps LNAV data stream.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-32 for GPS satellites)

Returns

  • GNSSDecoderState{GPSL1CAData}: Initialized decoder state for GPS L1

Example

state = GPSL1CADecoderState(1)  # Create decoder for PRN 1
state = decode!(state, bits, num_bits)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GalileoE1BDecoderState — Function
GalileoE1BDecoderState(
    prn
) -> GNSSDecoderState{GalileoINAVData, GNSSDecoder.GalileoINAVConstants{:GalileoE1B}, GNSSDecoder.GalileoINAVCache}

Create a decoder state for Galileo E1-B I/NAV navigation messages.

Initializes a GNSSDecoderState configured for decoding Galileo E1-B (Open Service) navigation messages. The decoder extracts ephemeris, clock correction, ionospheric parameters, and health data from the 250 sps I/NAV symbol stream using Viterbi decoding, and publishes them in a GalileoINAVData (the shared I/NAV container, also used by the E5b decoder).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-36 for Galileo satellites)

Returns

  • GNSSDecoderState{GalileoINAVData}: Initialized decoder state for Galileo E1-B

Example

state = GalileoE1BDecoderState(1)  # Create decoder for PRN 1
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GalileoE5bDecoderState — Function
GalileoE5bDecoderState(
    prn
) -> GNSSDecoderState{GalileoINAVData, GNSSDecoder.GalileoINAVConstants{:GalileoE5bI}, GNSSDecoder.GalileoINAVCache}

Create a decoder state for Galileo E5b I/NAV navigation messages.

Initializes a GNSSDecoderState configured for decoding the Galileo I/NAV message from the FEC-encoded 250 sps soft symbols of the E5b-I component. The I/NAV message is identical to E1-B's, so decoding reuses the shared I/NAV core: the 10-bit page-sync pattern is matched at both ends of the 260-symbol window, the 240 encoded symbols are 30×8 deinterleaved and Viterbi-decoded to a 114-bit page part, consecutive even + odd parts are stitched into a 128-bit nominal word, and the pair is gated on CRC-24Q before its word type is parsed. Decoded fields land in a GalileoINAVData (the shared I/NAV container).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-36 for Galileo satellites)

Returns

  • GNSSDecoderState{GalileoINAVData}: Initialized decoder state for Galileo E5b

Example

state = GalileoE5bDecoderState(1)  # Create decoder for PRN 1
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GalileoE5aDecoderState — Function
GalileoE5aDecoderState(
    prn
) -> GNSSDecoderState{GalileoE5aData, GNSSDecoder.GalileoE5aConstants, GNSSDecoder.GalileoE5aCache}

Create a decoder state for Galileo E5a F/NAV navigation messages.

Initializes a GNSSDecoderState configured for decoding Galileo E5a (Open Service) F/NAV navigation messages. The decoder extracts ephemeris, clock correction, ionospheric parameters, almanac, and health data from the 50 sps F/NAV data stream broadcast on the E5a-I component using Viterbi decoding.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-36 for Galileo satellites)

Returns

  • GNSSDecoderState{GalileoE5aData}: Initialized decoder state for Galileo E5a

Example

state = GalileoE5aDecoderState(21)  # Create decoder for PRN 21
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GalileoE6BDecoderState — Function
GalileoE6BDecoderState(
    prn
) -> GNSSDecoderState{GalileoE6BData, GNSSDecoder.GalileoE6BConstants, GNSSDecoder.GalileoE6BCache}

Create a decoder state for Galileo E6-B C/NAV (High Accuracy Service) messages.

Initializes a GNSSDecoderState configured for decoding the Galileo HAS message from the FEC-encoded 1000 sps soft symbols of the E6-B component. Each sync attempt matches the 16-symbol sync pattern 1011011101110000 at both ends of the 1016-symbol window, 123×8 deinterleaves and Viterbi-decodes the 984 encoded symbols to a 486-bit page, and gates it on CRC-24Q. Valid, non-dummy pages are accumulated per Message ID until MS distinct HAS Page IDs are held, at which point the Reed-Solomon erasure decoder recovers the HAS message and its Message Type 1 content blocks are parsed into a GalileoE6BData.

One satellite is slow; several are fast

A HAS message needs MS (up to 32) distinct encoded pages. One satellite broadcasts one page per second, so a single-satellite decoder needs up to 32 seconds per message. HAS is designed for pages to be pooled across satellites — a receiver tracking several E6-B satellites completes messages far sooner. Each decoder state here accumulates only its own satellite's pages; combining them across satellites is a receiver-level concern.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-50 for Galileo E6)

Returns

  • GNSSDecoderState{GalileoE6BData}: Initialized decoder state for Galileo E6-B

Example

state = GalileoE6BDecoderState(1)  # Create decoder for PRN 1
state = decode!(state, soft_symbols, num_symbols)
if !isnothing(state.data.orbit_corrections)
    # Apply HAS corrections to the I/NAV ephemeris of the masked satellites
end

See Also

source
GNSSDecoder.GPSL1C_DDecoderState — Function
GPSL1C_DDecoderState(
    prn
) -> GNSSDecoderState{GPSL1C_DData, GNSSDecoder.GPSL1C_DConstants, GNSSDecoder.GPSL1C_DCache}

Create a decoder state for GPS L1C-D (CNAV-2) navigation messages.

Wires up a GNSSDecoderState with a 1852-symbol soft-symbol buffer, the 400-entry BCH(51,8) TOI codeword table (src/coding/bch_toi.jl), and two Aff3ct LDPC belief-propagation decoders loaded lazily from the committed .alist parity matrices in data/.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for L1C).

Returns

  • GNSSDecoderState{GPSL1C_DData}: Initialized decoder state for GPS L1C-D.

Example

state = GPSL1C_DDecoderState(1)            # PRN 1
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GPSL5IDecoderState — Function
GPSL5IDecoderState(
    prn
) -> GNSSDecoderState{GPSCNAVData, GNSSDecoder.GPSCNAVConstants{:GPSL5I}, GNSSDecoder.GPSCNAVCache}

Create a decoder state for GPS L5I CNAV navigation messages.

Initializes a GNSSDecoderState configured for decoding GPS L5I civil navigation (CNAV) messages from FEC-encoded 100 sps soft symbols. Each sync attempt Viterbi-decodes the buffered 616-symbol window, locates the 8-bit preamble (0b10001011) at both ends of the decoded bit window, validates the 300-bit message with CRC-24Q, and dispatches it to per-type parsers (message types 10-15, 30-37, and 40, IS-GPS-705J §20.3.3).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for GPS satellites)

Returns

  • GNSSDecoderState{GPSCNAVData}: Initialized decoder state for GPS L5I

Example

state = GPSL5IDecoderState(1)            # PRN 1
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.GPSL2CMDecoderState — Function
GPSL2CMDecoderState(
    prn
) -> GNSSDecoderState{GPSCNAVData, GNSSDecoder.GPSCNAVConstants{:GPSL2CM}, GNSSDecoder.GPSCNAVCache}

Create a decoder state for GPS L2C CNAV navigation messages.

Initializes a GNSSDecoderState configured for decoding GPS L2C civil navigation (CNAV) messages from the FEC-encoded 50 sps soft symbols of the L2 CM component. The CNAV message is identical to GPS L5I's, so decoding reuses the shared GPS CNAV core: each sync attempt Viterbi-decodes the buffered 616-symbol window, locates the 8-bit preamble (0b10001011) at both ends of the decoded bit window, validates the 300-bit message with CRC-24Q, and dispatches it to per-type parsers (message types 10-15, 30-37, and 40, IS-GPS-200N §30.3.3). Decoded fields land in a GPSCNAVData (the shared CNAV container).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for GPS satellites)

Returns

  • GNSSDecoderState{GPSCNAVData}: Initialized decoder state for GPS L2C

Example

state = GPSL2CMDecoderState(1)           # PRN 1
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.BeiDouB1IDecoderState — Function
BeiDouB1IDecoderState(
    prn
) -> GNSSDecoderState{BeiDouDNAVData, GNSSDecoder.BeiDouDNAVConstants{:BeiDouB1I}, GNSSDecoder.BeiDouDNAVCache}

Create a decoder state for BeiDou B1I legacy navigation messages (D1/D2 NAV).

Initializes a GNSSDecoderState configured for decoding the BeiDou legacy navigation message from B1I soft symbols. For MEO/IGSO satellites (PRN 6-58) that is the D1 message: 50 bps data bits after wipe-off of the NH20 secondary code. For GEO satellites (PRN 1-5 and 59-63) it is the D2 message at 500 bps (no secondary code); the decoder selects the format from the PRN. Each 300-bit subframe is synchronized via the 11-bit preamble 11100010010, BCH(15,11,1)-decoded per word, and parsed into a BeiDouDNAVData (the container shared with B3I).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for BeiDou satellites)

Returns

  • GNSSDecoderState{BeiDouDNAVData}: Initialized decoder state for BeiDou B1I

Example

state = BeiDouB1IDecoderState(20)         # PRN 20 (MEO/IGSO ⇒ D1)
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.BeiDouB3IDecoderState — Function
BeiDouB3IDecoderState(
    prn
) -> GNSSDecoderState{BeiDouDNAVData, GNSSDecoder.BeiDouDNAVConstants{:BeiDouB3I}, GNSSDecoder.BeiDouDNAVCache}

Create a decoder state for BeiDou B3I legacy navigation messages (D1/D2 NAV).

Initializes a GNSSDecoderState configured for decoding the BeiDou legacy navigation message from B3I soft symbols. The message is identical to B1I's (see BeiDouB1IDecoderState), so decoding reuses the shared legacy NAV core: D1 (50 bps, after NH20 wipe-off) for MEO/IGSO PRNs, D2 (500 bps) for GEO PRNs, 11-bit preamble sync, per-word BCH(15,11,1) correction, and parsing into the shared BeiDouDNAVData container.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for BeiDou satellites)

Returns

  • GNSSDecoderState{BeiDouDNAVData}: Initialized decoder state for BeiDou B3I

Example

state = BeiDouB3IDecoderState(30)         # PRN 30 (MEO/IGSO ⇒ D1)
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.BeiDouB1CDecoderState — Function
BeiDouB1CDecoderState(
    prn
) -> GNSSDecoderState{BeiDouB1CData, GNSSDecoder.BeiDouB1CConstants, GNSSDecoder.BeiDouB1CCache}

Create a decoder state for BeiDou B1C (B-CNAV1) navigation messages.

Wires up a GNSSDecoderState with a 1872-symbol soft-symbol buffer, the BCH(21,6) PRN / BCH(51,8) SOH subframe-1 codeword tables, and two Aff3ct LDPC belief-propagation decoders loaded from the committed binary-image .alist parity matrices in data/ (see scripts/generate_beidou_alist.jl).

Like GPS L1C-D, the LDPC decode is flooding sum-product and therefore scale-sensitive: feed soft symbols whose magnitudes are confidence-weighted on a roughly LLR-like scale (≈ 2·r/σ²) for best performance at marginal SNR (see the soft-symbol convention note on decode!).

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for BeiDou).

Returns

  • GNSSDecoderState{BeiDouB1CData}: Initialized decoder state for BeiDou B1C.

Example

state = BeiDouB1CDecoderState(30)          # PRN 30
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.BeiDouB2aDecoderState — Function
BeiDouB2aDecoderState(
    prn
) -> GNSSDecoderState{BeiDouB2aData, GNSSDecoder.BeiDouB2aConstants, GNSSDecoder.BeiDouB2aCache}

Create a decoder state for BeiDou B2a (B-CNAV2) navigation messages.

Initializes a GNSSDecoderState configured for decoding the B-CNAV2 message from the 200 sps soft symbols of the B2a data component (BDS-SIS-ICD-B2a-1.0). Each sync attempt matches the 24-symbol preamble 0xE24DE8 at both ends of the buffered 600-symbol frame window (in either polarity); a matched frame is LDPC-decoded through the binary image of the ICD's 64-ary LDPC(96,48) code, gated on CRC-24Q and on the broadcast PRN matching this decoder's PRN, and dispatched to per-message-type parsers (message types 10, 11, 30-34, and 40). Decoded fields land in a BeiDouB2aData.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (1-63 for BeiDou satellites)

Returns

  • GNSSDecoderState{BeiDouB2aData}: Initialized decoder state for BeiDou B2a

Example

state = BeiDouB2aDecoderState(19)         # PRN 19
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source
GNSSDecoder.BeiDouB2bDecoderState — Function
BeiDouB2bDecoderState(
    prn
) -> GNSSDecoderState{BeiDouB2bData, GNSSDecoder.BeiDouB2bConstants, GNSSDecoder.BeiDouB2bCache}

Create a decoder state for BeiDou B2b (B-CNAV3) navigation messages.

Initializes a GNSSDecoderState configured for decoding B-CNAV3 messages from the 1000 sps soft symbols of the B2b_I component (BDS-SIS-ICD-B2b-1.0). Each sync attempt matches the 16-symbol preamble 0xEB90 at both ends of the 1016-symbol window, checks the 6 unencoded PRN symbols against prn, LDPC-decodes the 972 encoded symbols through the binary image of the ICD's 64-ary LDPC(162, 81) code, and validates the 486-bit message with CRC-24Q before dispatching it to the per-type parsers (message types 10, 30, and 40). Decoded fields land in a BeiDouB2bData.

Arguments

  • prn::Int: Pseudo-Random Noise code identifier (6-58 — the B2bI ranging codes of Table 5-1. The wider 1-63 range is the almanac's `PRNa` key, not a trackable B2b channel.)

Returns

  • GNSSDecoderState{BeiDouB2bData}: Initialized decoder state for BeiDou B2b

Example

state = BeiDouB2bDecoderState(26)        # PRN 26
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Use state.data for positioning
end

See Also

source

Decoding

decode! overwrites the buffers the decoder state was constructed with and allocates nothing. Continue with the state it returns; take a copy first if you need a snapshot of the earlier one.

GNSSDecoder.decode! — Function
decode!(
    state::GNSSDecoderState,
    soft_symbols::AbstractVector{<:Real},
    num_symbols::Int64;
    decode_once
) -> GNSSDecoderState

Decode GNSS navigation message soft symbols, overwriting the storage state holds, and return the updated state. Allocates nothing.

decode! writes straight into the buffers that state was constructed with — the soft-symbol buffer, the FEC scratch, the voting tallies in state.cache, and every container referenced from state.raw_data and state.data (almanac stores, health tables, HAS masks, ...). Those are all sized once, when the decoder state is constructed, so a streaming receiver pays no allocation per symbol:

state = GPSL1CADecoderState(25)
for chunk in soft_symbol_chunks
    state = decode!(state, chunk, length(chunk))
end
Earlier states are overwritten

The returned state shares its storage with state, and later calls keep overwriting it. Treat the return value as the live decoder and do not use state (or anything read out of its containers, such as state.data.almanacs) after the call. Take a copy first if a snapshot is needed.

Processes incoming soft symbols from a GNSS signal, detecting preambles and decoding synchronization sequences to extract navigation data. The function handles both normal and 180-degree phase-shifted signals automatically.

Soft-symbol convention

soft_symbols is an AbstractVector{<:Real}; Float32 is canonical. The sign carries the bit decision and the magnitude carries confidence (standard LLR convention):

  • positive ⇒ bit 0, negative ⇒ bit 1 — but treat this as a convention, not a hard input requirement. The absolute polarity of a Costas-tracked signal is inherently 180°-ambiguous, so the decoder does not depend on it: it matches the preamble in either polarity and flips internally (recording the result in is_shifted_by_180_degrees). Feeding the opposite sign decodes the same data; only the reported polarity flag differs. (Note: Tracking.jl's get_soft_bits happens to use the opposite sign — positive ⇒ bit 1 — which is harmless for exactly this reason.)
  • magnitude ⇒ confidence. No normalization is required; values need not lie in [-1, 1]. GPS L1 C/A (hard-slice + parity) and Galileo E1B (Viterbi, whose ML path is invariant to a global scale) use the sign and are indifferent to the magnitude scale. The LDPC decodes (GPS L1C-D and the BeiDou B-CNAV family: B1C, B2a, B2b) are flooding sum-product, which is scale-sensitive, so there the magnitudes should be confidence-weighted on a roughly LLR-like scale (≈ 2·r/σ²) for best performance at marginal SNR — but still need not be normalized to a fixed range.

Glue from Tracking.jl: feed get_soft_bits (polarity-corrected, amplitude-weighted soft bits) for every signal. See CONTEXT.md for the full glossary.

Arguments

  • state::GNSSDecoderState: Current decoder state
  • soft_symbols::AbstractVector{<:Real}: Soft symbols to consume, oldest first
  • num_symbols::Int: Number of leading entries of soft_symbols to process

Keywords

  • decode_once::Bool=false: If true, stops once all required positioning data has been validated (subframes 1-3 for GPS L1 C/A; word types 1-5 for Galileo E1B)

Returns

  • GNSSDecoderState: Updated decoder state with newly decoded data, sharing (and having overwritten) state's storage

See Also

source
Base.copy — Method
copy(state::GNSSDecoderState) -> GNSSDecoderState

Independent copy of a decoder state: its soft-symbol buffer, cache and every container referenced from raw_data and data are copied (see duplicate), so decode! on the copy overwrites nothing state can see, and vice versa. The copy keeps every buffer's capacity, so it decodes without allocating as well.

source

Preallocated Storage

The keyed stores in the decoded data are sized once, when the decoder state is constructed, so that decode! can overwrite them instead of allocating. The broadcast text messages are inline CStaticStrings from StaticStrings.jl for the same reason.

GNSSDecoder.SlotDictionary — Type
mutable struct SlotDictionary{V, N} <: Dictionaries.AbstractDictionary{Int64, V}

A dictionary from Int keys in 0:N-1 to values of type V, with one slot per possible key allocated up front — every N-sized buffer exists from construction on, so inserting, overwriting or deleting an entry never allocates. This is what makes decode! allocation-free for the keyed stores of the decoded data (almanacs keyed by satellite, HAS masks keyed by Mask ID, ...): the key range of each is small and fixed by its ICD.

It is an AbstractDictionary from Dictionaries.jl, so it reads like the Dictionary it replaces (d[key], haskey, keys, pairs, length, ...), with one difference: it iterates in ascending key order rather than in insertion order. Any AbstractDictionary converts to it, which is what lets a decoded data container be constructed from a Dictionary.

Inserting a key outside 0:N-1 throws.

source

State Management

GNSSDecoder.reset_decoder_state! — Function
reset_decoder_state!(state::GNSSDecoderState) -> GNSSDecoderState

Reset a decoder after a signal loss or reacquisition, overwriting the buffers state holds (the soft-symbol buffer is emptied), and return the reset state. Allocates nothing. What is reset (the time of week, the validated data) and what is kept for a fast recovery is per signal, and documented on each signal's method. As with decode!, treat the return value as the live decoder and do not use state afterwards.

source

Health Status

GNSSDecoder.is_sat_healthy — Function
is_sat_healthy(state::GNSSDecoderState{<:GPSL1CAData})

Check if the GPS satellite is healthy and usable for positioning.

Examines the 6-bit satellite health field (sv_health) from subframe 1. A satellite is considered healthy only if all health bits are zero ("000000").

Warning

This function requires that subframe 1 has been successfully decoded. Check that state.data.sv_health is not nothing before relying on this result.

Arguments

  • state::GNSSDecoderState{<:GPSL1CAData}: GPS L1 decoder state with decoded data

Returns

  • Bool: true if satellite health status indicates normal operation

Example

state = GPSL1CADecoderState(1)
state = decode!(state, bits, num_bits)
if is_sat_healthy(state)
    # Safe to use for positioning
end

See Also

source
is_sat_healthy(state::GNSSDecoderState{<:GPSL1C_DData})

Check if the GPS L1C-D satellite is healthy and usable for positioning.

Examines the 1-bit L1C signal health flag from subframe 2 (IS-GPS-800J §3.5.3.4): a satellite is healthy iff the health bit is 0 (Signal OK).

Warning

Requires subframe 2 to have been decoded; returns false until then.

Arguments

  • state::GNSSDecoderState{<:GPSL1C_DData}: GPS L1C-D decoder state.

Returns

  • Bool: true iff the L1C signal-health bit indicates OK.
source
is_sat_healthy(
    state::GNSSDecoderState{<:GPSCNAVData, <:GNSSDecoder.GPSCNAVConstants{:GPSL5I}}
) -> Bool

Check if the GPS L5 satellite is healthy and usable for positioning.

Examines the L5 signal health bit decoded from the most recent message type 10 (IS-GPS-705J §20.3.3.1.1.2): a satellite is healthy iff the health bit is 0 (all navigation data on the L5 signal are OK).

Warning

Requires message type 10 to have been decoded and the positioning set to have been validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:GPSCNAVData,<:GPSL5IConstants}: GPS L5I decoder state.

Returns

  • Bool: true iff the L5 signal-health bit indicates OK.
source
is_sat_healthy(
    state::GNSSDecoderState{<:GPSCNAVData, <:GNSSDecoder.GPSCNAVConstants{:GPSL2CM}}
) -> Bool

Check if the GPS L2C satellite is healthy and usable for positioning.

Examines the L2 signal health bit decoded from the most recent message type 10 (IS-GPS-200N §30.3.3.1.1.2): a satellite is healthy iff the L2 health bit is 0 (some or all codes and data on the L2 carrier are OK). This is the only decode-level difference from GPS L5I, which reports the L5 health bit.

Warning

Requires message type 10 to have been decoded and the positioning set to have been validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:GPSCNAVData,<:GPSL2CMConstants}: GPS L2C decoder state.

Returns

  • Bool: true iff the L2 signal-health bit indicates OK.
source
is_sat_healthy(
    state::GNSSDecoderState{<:GalileoINAVData, <:GNSSDecoder.GalileoINAVConstants{:GalileoE1B}}
) -> Bool

Check if the Galileo satellite is healthy and usable for positioning on E1-B.

Examines both the signal health status (E1B_SHS) and data validity status (E1B_DVS) from I/NAV word type 5. A satellite is considered healthy only if both conditions are met:

  • Signal health is signal_ok
  • Data validity is navigation_data_valid

This is the only decode-level difference from the Galileo E5b decoder, which reports the E5b facet of the same word type 5.

Warning

This function requires that word type 5 has been successfully decoded. Check that state.data.E1B_SHS is not nothing before relying on this result.

Arguments

  • state::GNSSDecoderState{<:GalileoINAVData,<:GalileoE1BConstants}: Galileo E1-B decoder state with decoded data

Returns

  • Bool: true if satellite health and data validity indicate normal operation

Example

state = GalileoE1BDecoderState(1)
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Safe to use for positioning
end

See Also

source
is_sat_healthy(
    state::GNSSDecoderState{<:GalileoINAVData, <:GNSSDecoder.GalileoINAVConstants{:GalileoE5bI}}
) -> Bool

Check if the Galileo satellite is healthy and usable for positioning on E5b.

Examines both the E5b signal health status (E5b_SHS) and E5b data validity status (E5b_DVS) from I/NAV word type 5 (OS SIS ICD Tables 81 and 84). A satellite is considered healthy only if both conditions are met:

  • Signal health is signal_ok
  • Data validity is navigation_data_valid

This is the only decode-level difference from the Galileo E1-B decoder, which reports the E1-B/C facet of the same word type 5. Word type 5 carries both facets, so a decoder on either component always has both available.

Warning

This function requires that word type 5 has been successfully decoded. Check that state.data.E5b_SHS is not nothing before relying on this result.

Arguments

  • state::GNSSDecoderState{<:GalileoINAVData,<:GalileoE5bConstants}: Galileo E5b decoder state with decoded data

Returns

  • Bool: true if satellite health and data validity indicate normal operation

Example

state = GalileoE5bDecoderState(1)
state = decode!(state, soft_symbols, num_symbols)
if is_sat_healthy(state)
    # Safe to use for positioning
end

See Also

source
is_sat_healthy(state::GNSSDecoderState{<:GalileoE5aData})

Check if the Galileo satellite is healthy and usable for positioning on E5a.

Examines both the E5a signal-health status (E5a_SHS) and the E5a data-validity status (E5a_DVS) from page type 1. A satellite is considered healthy only if the signal health is signal_ok and the data validity is navigation_data_valid.

Warning

This requires that page type 1 has been successfully decoded. Check that state.data.E5a_SHS is not nothing before relying on the result.

source
is_sat_healthy(state::GNSSDecoderState{<:GalileoE6BData})

Report whether this satellite's High Accuracy Service data is usable.

E6-B C/NAV broadcasts no health flag for the transmitting satellite — it carries corrections, not that satellite's own navigation data — so what this reports is the service status from the HAS Page Header (ICD Table 9): true only while HAS is in operational mode, when nominal performance is expected.

Test mode (has_test_mode) returns false: the data decodes normally and is published in state.data, but the ICD warns that "nominal performance may not be met", so it should not be trusted silently. has_do_not_use also returns false, and additionally causes every previously received message to be discarded (see decode_syncro_sequence).

Arguments

  • state::GNSSDecoderState{<:GalileoE6BData}: Galileo E6-B decoder state

Returns

  • Bool: true iff the last valid page reported operational HAS status

See Also

source
is_sat_healthy(state::GNSSDecoderState{<:BeiDouDNAVData})

Check if the BeiDou satellite is healthy and usable for positioning, from the legacy D1/D2 navigation message.

Examines the autonomous satellite health flag (SatH1) broadcast in D1 subframe 1 / D2 subframe 1 page 1: 0 means the broadcasting satellite is good, 1 means not (BDS-SIS-ICD-B1I-3.0 / -B3I-1.0 §5.2.4.6).

One method covers both B1I and B3I: the two signals carry the same SatH1 bit of the same message, so unlike GPS L5I and L2CM — which select different health bits out of a shared CNAV container — there is nothing per-signal to dispatch on.

Warning

Requires the fundamental navigation data to have been decoded and validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:BeiDouDNAVData}: BeiDou B1I or B3I decoder state

Returns

  • Bool: true iff SatH1 indicates a healthy satellite
source
is_sat_healthy(state::GNSSDecoderState{<:BeiDouB1CData})

Check if the BeiDou B1C satellite is healthy and usable for positioning.

Examines the 2-bit satellite health status (HS) broadcast in every subframe-3 page (BDS-SIS-ICD-B1C-1.0 §7.14, Table 7-22): a satellite is healthy iff HS == 0 (the satellite provides services). The B1C integrity status flags (DIF/SIF/AIF, §7.15) are reported separately on BeiDouB1CData and are deliberately not folded in here — they flag message/signal integrity for precision users, not the satellite's service state.

Warning

Requires a subframe-3 page to have been decoded and the positioning set validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:BeiDouB1CData}: BeiDou B1C decoder state.

Returns

  • Bool: true iff the health status word indicates a healthy satellite.
source
is_sat_healthy(state::GNSSDecoderState{<:BeiDouB2aData})

Check if the BeiDou B2a satellite is healthy and usable for positioning.

Examines the 2-bit satellite health status HS decoded from the most recent message of types 11 or 30-34 or 40 (BDS-SIS-ICD-B2a-1.0 §7.14, Table 7-22): the satellite is healthy iff HS == 0 ("the satellite is healthy / provides services"). HS = 1 means unhealthy or in test; 2-3 are reserved and treated as unhealthy.

Warning

Requires a health-carrying message to have been decoded and the positioning set to have been validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:BeiDouB2aData}: BeiDou B2a decoder state.

Returns

  • Bool: true iff the broadcast health status indicates a usable satellite.
source
is_sat_healthy(state::GNSSDecoderState{<:BeiDouB2bData})

Check if the BeiDou B2b satellite is healthy and usable for positioning.

Examines the 2-bit satellite health status (HS) decoded from the most recent message type 30 (BDS-SIS-ICD-B2b-1.0 §7.13, Table 7-20): a satellite is healthy iff HS = 0 ("the satellite is healthy / provides services"); 1 means unhealthy or in test, 2-3 are reserved.

Warning

Requires message type 30 to have been decoded and the positioning set to have been validated; returns false until then.

Arguments

  • state::GNSSDecoderState{<:BeiDouB2bData}: BeiDou B2b decoder state.

Returns

  • Bool: true iff the health status word indicates a healthy satellite.
source

Positioning Readiness

Pair is_decoding_completed_for_positioning with is_sat_healthy to gate use of a satellite in a fix: the first confirms the required navigation data set has been decoded and validated, the second that the satellite is broadcasting healthy. See the docstring for what it deliberately does not gate on (ephemeris freshness, second-order corrections, the alert flag).

GNSSDecoder.is_decoding_completed_for_positioning — Function
is_decoding_completed_for_positioning(
    state::GNSSDecoderState
) -> Any

Report whether a decoder has recovered the minimum navigation data a positioning engine needs from this satellite: a time of week, a full ephemeris (orbit) set, and the SV clock-correction polynomial (plus, on the signals that carry it in the same required set, the broadcast week number and single-band group delay). Dispatches on the validated data field, so it only becomes true once the required message set has passed CRC/parity and the cross-subframe issue-of-data consistency check that promotes raw_data to data.

This is the readiness gate a receiver (e.g. PositionVelocityTime.jl) should pair with is_sat_healthy: whenever this returns true, the health field is_sat_healthy inspects is guaranteed to have been decoded, so the two can be checked together without a separate nothing guard.

What this deliberately does *not* gate on

A true here means the data set is complete and self-consistent — it is a necessary condition for using the SV in a fix, not a blanket guarantee that no further judgement is required:

  • Ephemeris freshness. Only presence is checked, not age. The decoder has no notion of "now", so the consumer must still reject ephemerides outside their fit interval (fit_interval / t_0e age).

  • Second-order corrections. Klobuchar / BDGIM ionosphere and UTC parameters are intentionally excluded: they are broadcast far less often, so apply them when present and treat nothing as zero rather than waiting for them. Group delay and inter-signal corrections (T_GD, ISC_*) split on one question — does this signal's own correction ride in the block the gate already waits for?

    Where it does, it is required, because it is a metre-scale bias rather than a refinement and costs nothing to wait for. BeiDou B1C's T_GD_B1Cp and ISC_B1Cd are in the same CRC-protected subframe 2 as the ephemeris and clock, B2b's T_GD_B2bI is in the same MT30 as the clock, and B1I/B3I's T_GD1 is in the same D1 subframe 1 / D2 page 1 as the clock, so all are gated on here.

    Where it does not, it is excluded, because requiring it would mean waiting for a message the ICD declines to schedule: BeiDou B2a's T_GD_B2ap / ISC_B2ad are in MT30 alone while the clock is in MT30-34, and the GPS CNAV T_GD and ISC_* likewise arrive on their own cadence.

    Corrections for a band this decoder is not on — B1C's T_GD_B2ap, B1I/B3I's T_GD2 (there is no B2I signal here to range on, and none planned), the GPS ISC_L5Q5 on an L1 fix — are never required either way. Such a field is still decoded and published; it is only this readiness gate that ignores it.

  • Alert flag. is_sat_healthy reflects the broadcast health bits only; a receiver that wants to honour the L1 C/A alert flag (or equivalent) must check it separately.

source
is_decoding_completed_for_positioning(
    data::GalileoE6BData
) -> Bool

Always false for Galileo E6-B.

C/NAV carries no ephemeris, clock polynomial or week number of its own: the HAS message is a set of corrections to the broadcast navigation data of another signal (Galileo I/NAV or GPS LNAV, selected per constellation by the mask's Navigation Message Index). A positioning engine therefore pairs an E6-B decoder with an I/NAV or LNAV decoder rather than using it alone, so this readiness gate — which asks whether this satellite's own positioning set is complete — can never be satisfied here.

Use state.data.orbit_corrections, .clock_corrections, .code_biases and .phase_biases (each with its own validity interval and IOD_set_id) together with the corresponding ephemeris decoder instead.

source

Signal Metadata

A decoder state knows which signal it demodulates, so GNSSSignals' signal accessors are extended for GNSSDecoderState and answer directly from the state — no need to carry the signal alongside the decoder just to ask what it is. Each forwards to the corresponding signal in GNSSSignals through get_signal_type, so every value stays single-sourced, and each folds to a compile-time constant.

AccessorAnswersExample (GPSL2CMDecoderState(1))
get_signal_id / get_signal_namewhich signal:GPSL2CM / "GPS L2CM"
get_constellation_id / get_constellation_namewhich constellation:GPS / "GPS"
get_band / get_band_id / get_band_namewhich RF bandL2() / :L2 / "L2"
get_data_frequencynavigation-message symbol rate50 Hz
get_time_system / get_time_system_id / get_time_system_nametime scale the decoded week numbers and times of week are counted inGPST() / :GPST / "GPS Time"
get_system_start_time / get_tai_system_start_time / get_tai_offsetthat scale's epoch (as a UTC label, and on the continuous TAI scale) and offset from TAI — what turns a decoded WN/TOW pair into an absolute instant1980-01-06T00:00:00 / 1980-01-06T00:00:19 / 19 s

Dispatch is on the constants type, which keeps decoders that share a data container distinct: GPS L5-I and L2C-M both decode into a GPSCNAVData, and Galileo E1-B and E5b-I both into a GalileoINAVData, but each reports its own band, ids and symbol rates.

using GNSSDecoder, GNSSSignals
get_data_frequency(GPSL5IDecoderState(1))     # 100 Hz
get_data_frequency(GPSL2CMDecoderState(1))    #  50 Hz
get_signal_name(GalileoE5aDecoderState(1))    # "Galileo E5a-I"
get_signal_name(GalileoE5bDecoderState(1))    # "Galileo E5b-I"
get_band_id(GalileoE6BDecoderState(1))        # :E6
get_band_id(GalileoE1BDecoderState(1))        # :L1 — bands are identified by RF
                                              #       frequency, not ICD label
get_system_start_time(GalileoE1BDecoderState(1))  # 1999-08-21T23:59:47

Accessors describing the spreading code (get_code_length, get_code_frequency, get_carrier_phase_offset, …) are not forwarded — they belong to acquisition and tracking rather than to a symbol-domain decoder — but remain one step away via get_signal_type:

get_code_length(get_signal_type(GPSL1CADecoderState(1)))  # 1023
GNSSDecoder.get_signal_type — Function
get_signal_type(state::GNSSDecoderState) -> Type{<:AbstractGNSSSignal}
get_signal_type(constants::AbstractGNSSConstants) -> Type{<:AbstractGNSSSignal}

Get the GNSSSignals signal type whose navigation message a decoder demodulates, e.g. GPSL1CA for a GPSL1CADecoderState. This is the single mapping from this package's decoders back into GNSSSignals; every signal accessor listed under "Signal metadata" in the docs is forwarded through it, and it is the entry point for anything not forwarded (get_signal_type(state) accepts every GNSSSignals accessor that takes a signal type).

Returns the type, not an instance: constructing a signal builds its spreading code matrix and SIMD lookup table, which a decoder — working purely in the symbol domain — never needs. Being a type, it also folds to a compile-time constant, so the forwarded accessors cost nothing at run time.

Stated per signal file, dispatched on the constants type rather than the data type, because the constants are what tell apart decoders that share a data container: GPS L5-I and L2C-M both decode into a GPSCNAVData but are distinct signals (GPSCNAVConstants{:GPSL5I} vs GPSCNAVConstants{:GPSL2CM}).

The mapping names the data-bearing component of a signal pair, since that is what carries the navigation message: GPSL2CM (not the GPSL2CL pilot) and GalileoE5aI (not the GalileoE5aQ pilot). A decoder built from an approximation of a signal reports the signal it approximates — the E1B BOC(1,1) decoder state is a GalileoE1B, since the approximation is a tracking/acquisition concern and the I/NAV stream it decodes is identical.

Examples

using GNSSDecoder, GNSSSignals
get_signal_type(GPSL1CADecoderState(1))            # GPSL1CA
get_signal_type(GPSL2CMDecoderState(1))            # GPSL2CM
get_code_length(get_signal_type(GPSL1CADecoderState(1)))  # 1023

See Also

source

Satellite and Time Metadata

Three questions a positioning engine asks of every decoder, whatever signal it is on. Each is answered from broadcast data by some signals and from constellation structure by others, and each is reconstruction work the ICD defines — so it is done here, once per signal, rather than in every consumer.

AccessorAnswersnothing when
get_orbit_classGEO / IGSO / MEO, as an OrbitClassthe signal cannot say — see the warning in its docstring
get_time_of_weekseconds of week at the epoch the message stampsno time has been decoded and validated yet
get_time_offsetoffset to another constellation's time scale, as a GNSSTimeOffsetthis satellite is not broadcasting one for that target

get_time_of_week folds away the four spellings the ICDs use — a plain TOW or SOW on most signals, ITOW·7200 + toi·18 on GPS L1C-D, and HOW·3600 + soh·18 on BeiDou B1C — and pairs with the state's symbol counter to give the current time on every signal with one expression:

using GNSSDecoder, GNSSSignals
tow = get_time_of_week(state)
now = tow + state.num_bits_after_valid_syncro_sequence / get_data_frequency(state)

get_time_offset folds away the five shapes the same quantity is broadcast in — Galileo's two-term GPS-only GGTO, the GPS CNAV and CNAV-2 GGTOs tagged by a GNSS_ID/GGTO_ID code, BeiDou B2a/B2b's single tagged BGTO set, B1C's set keyed per system, and D1/D2's three epochless pairs named per system — including each ICD's "not available" sentinel:

offset = get_time_offset(state, GPST())     # `GPST()`, `GST()` or `BDT()`
# Δτ is the time since the offset's reference epoch: `t - t_0 + 604800(WN - WN_0)`,
# or simply `t` on BeiDou D1/D2, which broadcasts no epoch (`t_0 === nothing`).
t_gpst = t_bdt - (offset.A_0 + offset.A_1 * Δτ + offset.A_2 * Δτ^2)

It also folds in the part that is not broadcast. Two time scales differ by a defined whole-second offset plus a steering residual, and only the residual is on the air — the bias coefficient is 16 bits at 2⁻³⁵ s, a range of ±0.95 µs, which cannot express a whole second. A_0 carries both, so the subtraction above is true as written. The defined part is zero between GPST and GST (both TAI − 19 s) and −14 s from BDT to either, so a consumer that tested only Galileo would never see it.

GNSSDecoder.OrbitClass — Type
OrbitClass

Orbit class of a navigation satellite: get_orbit_class reports it.

The three classes the ICDs of the constellations decoded here distinguish. The values are deliberately not exported, like the health enums' values: medium_earth_orbit is exactly the name a receiver or orbit-propagation package alongside this one may define, and consumers compare against them rarely enough that GNSSDecoder.geostationary_orbit costs nothing.

Values

  • geostationary_orbit: GEO
  • inclined_geosynchronous_orbit: IGSO
  • medium_earth_orbit: MEO

The integer values are this package's own; nothing here relies on them matching any ICD's encoding, and BeiDou's 2-bit sat_type (1 GEO / 2 IGSO / 3 MEO) is mapped across explicitly.

source
GNSSDecoder.get_orbit_class — Function
get_orbit_class(state::GNSSDecoderState) -> Union{Nothing,OrbitClass}

Orbit class of the satellite this decoder is tracking, or nothing when the signal does not make it knowable.

Answered from whichever source the signal actually has:

  • GPS and Galileo — medium_earth_orbit for every satellite. Both constellations are MEO-only by design, so this needs no decoded data and is available before the first subframe.
  • BeiDou B1C, B2a, B2b — from the broadcast sat_type field of the satellite's own Ephemeris I block (1 GEO / 2 IGSO / 3 MEO, reserved 0; Table 7-6 of each ICD). nothing until that block has been decoded and promoted, and nothing for the reserved code — the same screen is_known_sat_type applies to positioning.
  • BeiDou B1I and B3I — geostationary_orbit for the GEO PRNs, nothing otherwise. D1/D2 NAV broadcasts no orbit-type field, and the PRN partition the ICD fixes (BDS-SIS-ICD-B1I-3.0 Table 4-1) separates GEO from non-GEO only, so IGSO and MEO cannot be told apart on these signals.
`nothing` is not `medium_earth_orbit`

Because of that last case, a nothing means "this signal cannot say", not "not GEO" and not "MEO". Testing === GNSSDecoder.geostationary_orbit is exact on every signal — a satellite that is GEO always reports so. Testing === GNSSDecoder.medium_earth_orbit is not: a B1I MEO satellite reports nothing. Treat nothing as unknown and branch on the GEO case.

Example

# Which reference does this BeiDou satellite's ephemeris use?
if get_orbit_class(state) === GNSSDecoder.geostationary_orbit
    # GEO/IGSO semi-major-axis reference
end

See Also

source
GNSSDecoder.get_time_of_week — Function
get_time_of_week(state::GNSSDecoderState) -> Any

Seconds of week that the decoder's validated navigation data stamps, or nothing before a time has been decoded.

Every signal here broadcasts one, but four of them do not broadcast it as seconds: GPS L1C-D counts two-hour intervals plus 18-second TOI steps, BeiDou B1C counts hours plus 18-second SOH steps, and the rest carry a plain TOW or SOW. The reconstruction is the ICD's, so it is done here rather than in every consumer:

SignalBroadcast fieldsSeconds of week
GPS L1 C/A, GPS CNAV (L2C/L5)TOWTOW
GPS L1C-DITOW, toiITOW·7200 + toi·18, toi = 0 carrying into the next interval (IS-GPS-800 §3.5.2, §3.5.3.2)
Galileo I/NAV (E1-B, E5b-I), E5a F/NAVTOWTOW
BeiDou B1I, B3I (D1/D2)SOWSOW
BeiDou B1CHOW, sohHOW·3600 + soh·18 (BDS-SIS-ICD-B1C §7.3)
BeiDou B2a, B2bSOWSOW

Galileo E6-B answers nothing always: C/NAV carries HAS corrections stamped with a time of hour per correction block, not a time of week, and those stay on the blocks that own them (see GalileoHASCorrectionBlock).

The epoch it denotes, and reading the current time

Every signal's value is the time of the epoch that num_bits_after_valid_syncro_sequence is anchored to — which is why the anchor is set per signal at promotion time, to the frame the broadcast field actually stamps (the next subframe for GPS LNAV, CNAV and L1C-D; the current frame for the BeiDou signals). So the current time of week is the same expression on every signal:

tow = get_time_of_week(state)
now = tow + state.num_bits_after_valid_syncro_sequence / get_data_frequency(state)

Because it reads data rather than raw_data, this returns a time only once the message set has passed CRC/parity and the cross-subframe consistency check — the same gate is_decoding_completed_for_positioning reports. Call it on state.raw_data directly to see an unvalidated time.

See Also

source
get_time_of_week(
    data::GPSL1C_DData
) -> Union{Nothing, Int64}

Seconds of week of the epoch the TOI stamps: ITOW·7200 + toi·18, with toi = 0 counted into the next two-hour interval.

CNAV-2 splits the time of week across two message parts and two rates — the subframe-2 ITOW counts the two-hour intervals since the start of the week (IS-GPS-800 §3.5.3.2) and the subframe-1 toi counts the 18-second frames within the interval (§3.5.2) — so neither field is a time of week on its own. Both must be present; nothing until they are.

The toi = 0 special case is the ICD's, not ours. §3.5.2 defines the TOI count relative to "the two-hour period represented by ITOW count in the subframe 2 of the next 18-second frame", with a range of 0–399: the frame broadcasting toi = 0 is the last frame of the old two-hour interval, so its own subframe-2 ITOW is one interval behind the one its TOI counts against. Without the carry, that one frame in every 400 stamps a time two hours in the past. The week wrap (ITOW = 83, toi = 0 stamps second 0 of the following week, while the paired WN is still the old week) is folded by the mod; a consumer combining this with WN inherits that one-frame-per-week ambiguity, which is also the ICD's.

source
get_time_of_week(
    data::BeiDouB1CData
) -> Union{Nothing, Int64}

Seconds of week of the epoch the SOH stamps: HOW·3600 + soh·18.

B-CNAV1 splits the time of week across two subframes and two rates — the subframe-2 HOW counts whole hours of the week and the subframe-1 soh counts the 18-second frames within the hour (BDS-SIS-ICD-B1C-1.0 §7.3, Table 7-2) — so neither field is a time of week on its own. Both must be present; nothing until they are.

The epoch is the leading edge of the current frame's subframe 1, which is what num_bits_after_valid_syncro_sequence is anchored to for this signal (see validate_data below); GPS L1C-D's TOI stamps the next frame instead, so its otherwise identical-looking reconstruction is anchored differently.

source
GNSSDecoder.GNSSTimeOffset — Type
struct GNSSTimeOffset{T<:GNSSSignals.TimeSystem}

One broadcast time offset between two GNSS time scales, normalised across the five shapes the ICDs state it in. get_time_offset returns it.

The offset at a time t (seconds of week) in week WN of the broadcasting satellite's own time scale is

Δτ = t - t_0 + 604800 * (WN - WN_0)
Δt = A_0 + A_1 * Δτ + A_2 * Δτ^2

and Δt is the broadcasting system's time minus the target system's — t_own - t_target, the direction every ICD here defines the quantity in (Galileo OS SIS ICD §5.1.8; IS-GPS-800/200 GGTO; BDS-SIS-ICD-B1C §7.13.2 Eq. 7-30). To convert a seconds-of-week reading, subtract: t_target = t_own - Δt.

`A_0` is not the broadcast coefficient alone

Two systems differ by a defined whole-second offset plus a broadcast steering residual, and only the second of those is on the air. The bias coefficient every one of these messages carries is 16 bits at 2⁻³⁵ s — a range of ±0.95 µs — so it cannot express a whole-second offset even in principle, and does not try to: real BeiDou satellites broadcast tens of nanoseconds against a BDT-to-GPST offset of 14 seconds.

A_0 is the sum of both, so the subtraction above is true as written. The defined part is get_tai_offset(target) - get_tai_offset(get_time_system(state)), every one of these scales being a fixed offset from TAI with no leap seconds of its own; the broadcast part stays available raw on the decoded data (data.A_0BGTO, data.A_0G, data.A_0GGTO), which is where this package keeps broadcast values.

Nothing about this shows on a Galileo decoder, where GST and GPST are both TAI − 19 s and the defined part is exactly zero. It is −14 s on every BeiDou signal (19 − 33: a BDT reading is 14 s behind, so converting away from BDT subtracts a negative), which is why the two cases must not be told apart by testing one. IS-GPS-800J §3.5.4.2.1.1 states the split outright: the GGTO parameters provide the offset "modulo one second", and "users must also apply any integer seconds difference between the systems using definitions of each system time scale" — the integer part is what this field folds in.

`WN_0` is resolved, not as broadcast

The reference week is sent truncated, and not always to the width of the week it is subtracted from — Galileo's WN_0G is 6 bits against a 12-bit WN. WN_0 here has been lifted into the decoder's own week numbering, so WN - WN_0 in the expression above is a real week count on every signal. The raw field stays on the decoded data (data.WN_0G, data.WN_0BGTO, data.WN_GGTO).

Seconds of week, not week numbers

This converts a time of week; it says nothing about which week. The scales do not share a week origin — BDT week 0 is GPS week 1356, exactly 9492 days later — so a full (WN, TOW) conversion also needs the epoch difference from get_system_start_time, and must carry the rollover when adding Δt crosses a week boundary.

Signals that broadcast fewer terms are widened rather than given a separate type: Galileo's GGTO has no quadratic term and reports A_2 == 0, and BeiDou D1/D2's two-term offsets carry no reference epoch at all and report t_0 === nothing / WN_0 === nothing. Both are exact — a zero coefficient contributes nothing, and an absent epoch is reported as absent rather than guessed. An absent epoch has a defined meaning, not a missing one: the D1/D2 polynomial's argument is the time of week itself (BDS-SIS-ICD-B1I-3.0 §5.2.4.19, Δt_GPS = A_0GPS + A_1GPS · t_E), so t_0 === nothing evaluates as Δτ = t — equivalent to t_0 = 0 with WN_0 equal to the current week, which is also why such an offset needs no week number to be usable.

Fields

  • target::GNSSSignals.TimeSystem: Time scale the offset is to; the broadcasting satellite's own scale is get_time_system of the decoder state
  • A_0::Float64: Bias coefficient (s): the broadcast steering residual plus the defined whole-second offset between the two scales — see the note above
  • A_1::Float64: Drift coefficient (s/s)
  • A_2::Float64: Drift-rate coefficient (s/s²); zero on the signals that broadcast only two terms
  • t_0::Union{Nothing, Int64}: Reference time of week (s), or nothing on BeiDou D1/D2, which broadcasts none
  • WN_0::Union{Nothing, Int64}: Reference week number, lifted out of its truncated broadcast field into the decoder's own week numbering (see resolve_reference_week), so WN - WN_0 is a real week count; nothing on BeiDou D1/D2, which broadcasts none. Valid only in that difference: across a week-number rollover the resolved value can fall outside the broadcast field's range, including below zero, so it is not an absolute week to place an epoch with

See Also

source
GNSSDecoder.get_time_offset — Function
get_time_offset(state::GNSSDecoderState, target::TimeSystem) -> Union{Nothing,GNSSTimeOffset}

The broadcast offset from this satellite's own time scale to target, as a GNSSTimeOffset, or nothing when this decoder has no such offset.

target is a GNSSSignals.TimeSystem — GPST(), GST() or BDT(). The satellite's own scale is get_time_system(state); asking for that returns nothing, because the offset from a scale to itself is not a broadcast quantity.

nothing also covers, and does not distinguish between, the three ways a signal can fail to have one:

  • it broadcasts no inter-system offset at all (GPS L1 C/A, Galileo E6-B),
  • it does, but has not decoded one yet,
  • it has, but for a different system than target — the GPS, B2a and B2b messages carry a single offset set tagged with the system it refers to, so which one is on the air is the satellite's choice, while Galileo's is GPS-only by definition and BeiDou B1C keys a set per system.

The ICDs' "not available" sentinels are screened here, so a returned offset is always a real one: a GPS/BeiDou GNSS_ID/GGTO_ID of 0 means "no offset in this message" (IS-GPS-800 Table 6.2-7, BDS-SIS-ICD-B1C §7.13.1), and Galileo marks an absent GGTO by setting all four fields to all ones (§5.1.8, handled at decode by galileo_ggto).

GLONASS offsets are decoded and published as fields, but cannot be asked for here: GNSSSignals defines no GLONASS TimeSystem, this package decodes no GLONASS signal, and inventing a target type for a constellation neither package handles would be a name with nothing behind it. Read data.GNSS_ID and the coefficient fields directly for those.

Example

# Steer a BeiDou observable onto GPS time.
offset = get_time_offset(state, GPST())
if !isnothing(offset)
    # D1/D2 broadcasts no reference epoch (`t_0 === nothing`); its polynomial's
    # argument is the time of week itself (BDS-SIS-ICD-B1I-3.0 §5.2.4.19).
    Δτ = isnothing(offset.t_0) ? tow : tow - offset.t_0 + 604800 * (wn - offset.WN_0)
    t_gps = t_bdt - (offset.A_0 + offset.A_1 * Δτ + offset.A_2 * Δτ^2)
end

See Also

source

Shared Utilities

Signal-independent building blocks used across the decoders (CRC-24Q, the BCH(51,8) TOI codec, the block (de)interleaver, and the GF(2^8) Reed-Solomon codec behind Galileo HAS).

These are public but unexported, so they are reached through the module: write GNSSDecoder.crc24q(…), or import what you need with using GNSSDecoder: crc24q.

GNSSDecoder.crc24q — Function
crc24q(bytes::AbstractVector{UInt8}) -> UInt32

Compute the CRC-24Q checksum (polynomial 0x1864cfb, init 0, no input or output reflection, xor-out 0) over bytes. The result is right-aligned in the low 24 bits of the returned UInt32; bits 24..31 are always zero.

For a complete CRC-protected message — i.e. a message followed by its big-endian 24-bit checksum — crc24q(message_with_crc) returns 0 iff the checksum matches.

source
crc24q(bits::AbstractVector{Bool}) -> UInt32

Bit-stream variant. bits is interpreted MSB-first in the same direction as the wire (i.e. the first bit of bits enters the CRC register first). length(bits) need not be a multiple of 8 — any leftover bits at the tail are processed bit-by-bit. The CRC field, if appended, must therefore also appear MSB-first as 24 individual bits.

source
crc24q(word::Unsigned, num_bytes::Integer) -> UInt32

Packed-word variant: compute the CRC over the low num_bytes octets of word, most significant octet first. Equivalent to crc24q(bytes) for the same octets, without materialising them.

This is the form the Galileo decoders need. A CRC-protected page arrives packed into one wide BitIntegers word (UInt288 for an I/NAV page pair, UInt512 for an E6-B C/NAV page), and its bit length is not a whole number of octets — 106 and 486 respectively. Rounding num_bytes up is safe and is what both callers do: the register initialises to zero, so the few leading zero bits of the rounded-up representation feed in as no-ops and leave the checksum unchanged.

Prefer this over crc24q(reverse(digits(UInt8, word; base = 256))), which is correct but allocates two vectors and, more importantly, drives num_bytes software divisions on a wide integer — measured at 133 µs for a 61-octet UInt512 against 0.33 µs here, because BitIntegers division falls back to a generic implementation while shifts and masks compile down.

source
GNSSDecoder.BCHToiSync — Type
BCHToiSync(toi::Int, polarity_flipped::Bool)

Result of a successful multi-subframe BCH(51,8) sync. toi is the TOI value of the first of the two subframes that matched. polarity_flipped == true means the receiver is Costas-locked 180° off and every bit must be inverted before downstream processing.

source
GNSSDecoder.sync_bch_toi — Function
sync_bch_toi(first52, next52) -> Union{BCHToiSync, Nothing}

Run the multi-subframe BCH(51,8) match used by GPS L1C-D frame sync. first52 and next52 are 52-symbol windows that, if the receiver is synchronised, hold the BCH-encoded TOI of two consecutive subframes. Both inputs are accepted as either packed UInt64 hard codewords — which is what the receiver passes, via pack_bits_lsb_first (src/gnss.jl) — or an iterable of 52 Bool-castable hard decisions, which pack_hard_codeword packs. Soft symbols are not accepted: hard-slicing them is the deque reader's job, one step earlier.

Returns a BCHToiSync for the lowest toi ∈ 0..399 that makes either:

  • first52 == BCH_TOI_CODEWORDS[toi] and next52 == BCH_TOI_CODEWORDS[(toi+1) mod 400] — reported as polarity_flipped == false, or
  • the bitwise complement of first52 and next52 matching the same pair — reported as polarity_flipped == true (Costas-lock 180° off).

If neither holds for any TOI, returns nothing.

Note on inherent ambiguity: because the BCH(51,8) construction XORs the 51 LFSR bits with the MSB of the 9-bit TOI, the codeword for t + 256 is the bitwise complement of the codeword for t (whenever both are in range). The receiver therefore cannot tell apart "TOI=t, no flip" from "TOI=t + 256, with flip" for t ∈ 0..143, and this function always reports the low branch (following PocketSDR's sync_CNV2_frame match order). The caller must resolve the pair: decode_syncro_sequence in src/gps/l1c_d.jl does it by TOI continuity with the previous frame when one is held, and otherwise by trying subframe 2's LDPC+CRC under both branches — the CRC is the only in-band oracle. A consumer that takes the reported branch at face value is wrong for every frame whose true TOI is ≥ 256, i.e. 43 minutes of every 2-hour interval.

This mirrors PocketSDR's sync_CNV2_frame algorithm — see /home/schoenbrod/Code/PocketSDR/python/sdr_nav.py.

source
GNSSDecoder.pack_hard_codeword — Function
pack_hard_codeword(bits) -> UInt64

Pack 52 hard-decision symbols (any iterable of Bool-castable values, e.g. Vector{Bool}, Vector{UInt8}, BitVector) into a UInt64 codeword with the first symbol at bit 0. Errors if length(bits) != 52.

This is the encoder-side and test-side packer. The receiver never reaches it: try_sync hard-slices its two windows straight off the soft-symbol deque with pack_bits_lsb_first (src/gnss.jl), which produces the same bit order without materialising the 52 symbols first.

source
GNSSDecoder.deinterleave! — Function
deinterleave!(dst, src, rows, cols) -> dst

Reverse a rows × cols block interleaver. src is the received (column- major-written, row-major-read) stream; dst receives the original (row-major) stream. Both must satisfy length(dst) == length(src) == rows*cols. dst and src may not alias.

Element type T is preserved — works for Float32 soft symbols, Bool hard slices, Int8, anything.

source
GNSSDecoder.interleave! — Function
interleave!(dst, src, rows, cols) -> dst

Forward (transmit-side) block interleaver. Inverse of deinterleave!: write src row-major into a rows × cols matrix, read column-major into dst.

source
GNSSDecoder.GaloisField256 — Type
struct GaloisField256

Multiplication tables for GF(256), built from a primitive polynomial. Constructed once and shared; all field arithmetic below takes it as its first argument.

The extension degree is fixed at 8, not a parameter: the tables are sized for 255 nonzero elements and the reduction step tests the carry out of bit 8, so only a degree-8 primitive polynomial gives a valid field here. Only the polynomial itself varies (Galileo HAS and CCSDS pick different ones).

Fields

  • exponentials::Vector{UInt8}: exponentials[i+1] == α^i, tabulated for i = 0 … 2(order-1) so that products can be looked up from a sum of logarithms without a modulo.
  • logarithms::Vector{UInt8}: logarithms[x+1] == i such that α^i == x, for x = 1 … order-1 (logarithms[1] is unused — zero has no logarithm).
source
GNSSDecoder.GALILEO_HAS_GF256 — Constant
GALILEO_HAS_GF256

GF(256) as the Galileo HAS SIS ICD defines it: primitive polynomial p(α) = α^8 + α^4 + α^3 + α^2 + 1 (ICD Issue 1.0, Eq. 7 — wire form 0x11d, the same field AES and CCSDS conventionally use).

source
GNSSDecoder.rs_generator_polynomial — Function
rs_generator_polynomial(field, num_parity) -> Vector{UInt8}

Generator polynomial of the narrow-sense Reed-Solomon code with num_parity parity symbols, g(x) = ∏_{i=1}^{num_parity} (x - α^i), returned lowest-degree-coefficient first (result[j+1] == g_j). For the Galileo HAS code (num_parity = 223) this reproduces HAS SIS ICD Table 42.

source
GNSSDecoder.rs_systematic_generator_matrix — Function
rs_systematic_generator_matrix(field, n, k) -> Matrix{UInt8}

The n × k systematic generator matrix G = [I; P] of the narrow-sense Reed-Solomon code RS(n, k), in the row/column order the Galileo HAS SIS ICD fixes (Issue 1.0, Eq. 12-15 and Annex B): Γ = G ⋅ c where the information vector is c = [c_{k-1}, …, c_0] and the code vector is Γ = [c_{k-1}, …, c_0, γ_{n-k-1}, …, γ_0] — information part first, both parts in descending coefficient order.

Column i is therefore the codeword of the i-th unit information vector: rows 1:k are the identity, and rows k+1:n hold the parity submatrix P, with row k + t carrying γ_{n-k-t}. Reproduces the ICD's Annex B attachment exactly for (n, k) = (255, 32).

Erasure decoding (see rs_erasure_decode) needs only G, so this one function is the whole codec a receiver requires.

source
GNSSDecoder.rs_erasure_decode — Function
rs_erasure_decode(field, G, received_rows, received::AbstractMatrix{UInt8}, k)
    -> Union{Nothing,Matrix{UInt8}}

Recover the information symbols of a systematic RS code from any k received code symbols per column — the Galileo HAS HPVRS decode (HAS SIS ICD, Issue 1.0, §6.4).

  • G is the systematic generator matrix from rs_systematic_generator_matrix.
  • received_rows are the 1-based code-vector indices (HAS page IDs) of the k collected symbols, in the same order as the rows of received.
  • received is k × J: row r holds the J symbols of the code vector indexed received_rows[r] (for HAS, J = 53 octets per page).
  • k is the information length actually in use. HAS transmits messages of k = MS ≤ 32 pages and zero-pads the information vector to the code's dimension, so only the first k columns of G matter.

Returns a k × J matrix whose row i is information symbol block i (HAS non-encoded page M_i), or nothing if the chosen rows are linearly dependent (the k × k submatrix is singular). Allocates its result and working matrices; rs_erasure_decode! is the in-place form the decoder uses.

Rows k+1 … (code dimension) carry nothing

The code is MDS, so any k distinct code symbols determine the message — with one exception created by the zero padding. When k is less than the code dimension, systematic rows k+1 … dimension are zero in the first k columns, because the information symbols they carry are the padding. Such a row contributes no equation and makes the submatrix singular. HAS therefore never transmits those pages ("Pages Ck+1, …, CK contain only zeroes and are excluded from transmission", ICD §6.3) and a caller must not collect them. Passing one, or the same row twice, is reported as nothing rather than silently producing garbage.

source
GNSSDecoder.rs_erasure_decode! — Function
rs_erasure_decode!(out, scratch::RSErasureScratch, field, G, received_rows, received, k)
    -> Union{Nothing,typeof(out)}

In-place rs_erasure_decode: the same decode from the first k rows of received (which may have more rows — a preallocated page store), writing the k × J information symbols into out row by row — information block i, symbol j at out[(i - 1) * J + j] — which for HAS is exactly the reassembled message octets in page order. Only out[1:k*J] is overwritten, and the working matrices in scratch are overwritten too. Returns out, or nothing if the decoding matrix is singular. Allocates nothing.

source
GNSSDecoder.RSErasureScratch — Type
struct RSErasureScratch

Preallocated working matrices for rs_erasure_decode!: the decoding matrix and its inverse, sized once for the largest information length that will be decoded (the code dimension). Both are overwritten by every decode.

Fields

  • decoding::Matrix{UInt8}: D = G[received_rows, 1:k] in its leading k × k block, eliminated in place
  • inverse::Matrix{UInt8}: D⁻¹ in its leading k × k block
source

Data Types

Every concrete per-signal data type subtypes the abstract supertype of its constellation, which in turn subtypes AbstractGNSSData. The supertypes carry the facts every signal of a constellation shares, stated once via subtype dispatch. Three intermediate levels name families within a constellation: AbstractGalileoEphemerisData separates the ephemeris-bearing Galileo messages from E6-B's corrections-only data, and AbstractGPSCNAVData / AbstractBeiDouCNAVData name the modern civil message families (CNAV/CNAV-2 and B-CNAV1/2/3), whose shared quasi-Keplerian ephemeris a consumer's propagator dispatches on.

GNSSDecoder.AbstractGPSData — Type
AbstractGPSData <: AbstractGNSSData

Abstract supertype for the decoded navigation data of a signal transmitted by the GPS constellation, e.g. GPSL1CAData, GPSCNAVData.

Its purpose is to carry the constellation-level facts every GPS signal's data shares, so they can be stated once (on the supertype, via subtype dispatch) instead of once per signal. Constellation membership is encoded at the struct definition site — the <: AbstractGPSData line written anyway — so a new GPS signal inherits the shared behaviour with nothing to remember. Genuinely per-signal facts (the subframe/message-type completeness checks, the health-bit selection in is_sat_healthy) stay defined on the concrete data types.

source
GNSSDecoder.AbstractGPSCNAVData — Type
AbstractGPSCNAVData <: AbstractGPSData

Abstract supertype for the modern GPS civil navigation messages: CNAV (GPSCNAVData, on L2C and L5) and CNAV-2 (GPSL1C_DData, on L1C).

What the two messages share — and legacy LNAV (GPSL1CAData) does not — is a full-width 13-bit week number and the quasi-Keplerian ephemeris broadcast as deltas off the fixed reference values A_REF and Ω̇_REF (IS-GPS-200N §30.3.3.1.1, IS-GPS-800J §3.5.3), so a consumer's propagator and week handling dispatch on this type rather than enumerating the two messages. The GPS counterpart of AbstractBeiDouCNAVData.

source
GNSSDecoder.AbstractGalileoData — Type
AbstractGalileoData <: AbstractGNSSData

Abstract supertype for the decoded navigation data of a signal transmitted by the Galileo constellation, e.g. GalileoINAVData (E1-B, E5b-I), GalileoE5aData, GalileoE6BData.

The Galileo counterpart to AbstractGPSData: it carries the facts every Galileo signal's data shares, whatever that signal broadcasts. The health-status and positioning-readiness checks genuinely differ per signal and stay on the concrete data types.

Note that "every Galileo signal" is not "every Galileo signal carries an ephemeris" — GalileoE6BData holds HAS corrections to another signal's navigation data and has no orbital fields at all. The ephemeris and clock completeness checks therefore live one level down, on AbstractGalileoEphemerisData.

source
GNSSDecoder.AbstractGalileoEphemerisData — Type
AbstractGalileoEphemerisData <: AbstractGalileoData

Abstract supertype for the Galileo signals whose navigation message carries an ephemeris and clock of its own: GalileoINAVData (E1-B, E5b-I) and GalileoE5aData (E5a-I).

This exists so is_ephemeris_decoded and is_clock_correction_decoded — which check the same orbital and clock fields for I/NAV and F/NAV, and so are stated once (see src/galileo/galileo.jl) — are dispatched on a type that actually has those fields. Declaring them on AbstractGalileoData instead would put a method on the supertype that raises a FieldError for GalileoE6BData, whose C/NAV message broadcasts corrections rather than an ephemeris; a future corrections-only or almanac-only Galileo signal would inherit the same trap.

source
GNSSDecoder.AbstractBeiDouData — Type
AbstractBeiDouData <: AbstractGNSSData

Abstract supertype for the decoded navigation data of a signal transmitted by the BeiDou constellation, e.g. BeiDouDNAVData (B1I/B3I), BeiDouB1CData, BeiDouB2aData, BeiDouB2bData.

The BeiDou counterpart to AbstractGPSData and AbstractGalileoData: it carries the constellation-level facts every BeiDou signal's data shares, so they can be stated once via subtype dispatch. Genuinely per-signal facts (the message-set completeness checks, the health-flag selection in is_sat_healthy) stay defined on the concrete data types.

source
GNSSDecoder.AbstractBeiDouCNAVData — Type
AbstractBeiDouCNAVData <: AbstractBeiDouData

Abstract supertype for the BDS-3 B-CNAV navigation messages: B-CNAV1 (BeiDouB1CData, on B1C), B-CNAV2 (BeiDouB2aData, on B2a) and B-CNAV3 (BeiDouB2bData, on B2b).

What the three messages share — and the legacy D1/D2 message (BeiDouDNAVData, on B1I/B3I) does not — is the quasi-Keplerian ephemeris broadcast as ΔA off a sat_type-selected reference semi-major axis with an outright Ω̇, the broadcast sat_type orbit class itself (get_orbit_class dispatches on this type), and the BDGIM ionospheric coefficient set. The BeiDou counterpart of AbstractGPSCNAVData.

source

GPS L1 C/A

GNSSDecoder.GPSL1CAConstants — Type
GPSL1CAConstants

WGS 84 constants and LNAV message structure parameters for GPS L1 C/A signal decoding.

The physical constants are defined in IS-GPS-200 (Interface Specification) and are used for computing satellite positions and clock corrections from broadcast ephemeris data.

Fields

  • syncro_sequence_length::Int: Length of synchronization sequence in bits (300 bits = 10 words × 30 bits)
  • preamble::UInt8: TLM word preamble pattern (10001011 binary, 0x8B)
  • preamble_length::Int: Length of preamble in bits (8)
  • word_length::Int: Length of each LNAV word in bits (30)
  • PI::Float64: Mathematical constant π = 3.1415926535898 (IS-GPS-200 Table 20-IV)
  • Ω_dot_e::Float64: WGS 84 Earth rotation rate = 7.2921151467×10⁻⁵ rad/s
  • c::Float64: Speed of light = 2.99792458×10⁸ m/s
  • μ::Float64: WGS 84 Earth gravitational parameter = 3.986005×10¹⁴ m³/s²
  • F::Float64: Relativistic correction constant = -4.442807633×10⁻¹⁰ s/√m

Reference

IS-GPS-200N, Section 20.3.3 and Table 20-IV

source
GNSSDecoder.GPSL1CAData — Type
GPSL1CAData

Decoded GPS L1 C/A LNAV navigation message data.

Contains ephemeris, clock correction, and satellite health parameters decoded from subframes 1, 2, and 3 of the GPS LNAV message. All parameters conform to IS-GPS-200N.

Telemetry and Handover Word (TLM/HOW) Fields

  • last_subframe_id::Int: ID of the last decoded subframe (1-5)
  • integrity_status_flag::Bool: Level of integrity assurance the URA carries (IS-GPS-200N 20.3.3.1). false is the legacy level (4.42 x URA bounds the instantaneous URE with probability 1 - 1e-5 per hour); true is the enhanced level (5.73 x URA at 1 - 1e-8 per hour). A true therefore means stronger integrity, not a fault - the fault indicator is alert_flag.
  • TOW::Int64: Time of Week at the start of the next subframe (seconds, 0-604794 in steps of 6)
  • alert_flag::Bool: URA may be worse than indicated (0=OK, 1=alert)
  • anti_spoof_flag::Bool: Anti-spoofing mode (0=off, 1=on)
  • num_bits_after_valid_syncro_sequence_after_last_TOW::Int: Symbol-counter value when TOW was decoded

Subframe 1 - Clock Correction Parameters

  • WN::Int64: GPS week number (modulo 1024)
  • code_on_L2::Int64: Code on L2 channel (0=invalid, 1=P-code, 2=C/A-code, 3=invalid)
  • URA_index::Int64: User Range Accuracy index, the raw 4-bit broadcast value (IS-GPS-200N 20.3.3.3.1.3, Table 20-I). Not converted to metres: the index is what the SV transmits, the table maps it to a bound rather than a value, and index 15 means "no accuracy prediction available - use at own risk", which a metre value cannot express.
  • sv_health::Int64: Raw 6-bit satellite health word (0 = healthy; IS-GPS-200N 20.3.3.3.1.4, Table 20-VIII)
  • IODC::Int64: Issue of Data, Clock (10 bits, 0-1023). An integer because every operation the ICD defines on it is arithmetic: IODE == IODC & 0xff (20.3.4.4), inequality against the values of the preceding six hours, and the Table 20-XII range tests that select the curve-fit interval (IODC < 240, 240-247, 248-255, 496)
  • L2_P_data_flag::Bool: L2 P-code data flag (1=LNAV OFF on P-code)
  • T_GD::Float64: L1-L2 group delay correction (seconds)
  • t_0c::Int64: Clock reference time (seconds; the ICD writes toc)
  • a_f0::Float64: Clock bias correction coefficient (seconds)
  • a_f1::Float64: Clock drift correction coefficient (s/s)
  • a_f2::Float64: Clock drift rate correction coefficient (s/s²)

Subframe 2 - Ephemeris Parameters (Part 1)

  • IODE_Sub_2::Int64: Issue of Data, Ephemeris from subframe 2 (8 bits)
  • C_rs::Float64: Sine harmonic correction to orbit radius (meters)
  • Δn::Float64: Mean motion difference from computed value (rad/s)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • C_uc::Float64: Cosine harmonic correction to argument of latitude (rad)
  • e::Float64: Eccentricity (dimensionless, range 0-0.03)
  • C_us::Float64: Sine harmonic correction to argument of latitude (rad)
  • sqrt_A::Float64: Square root of semi-major axis (√m)
  • t_0e::Int64: Ephemeris reference time (seconds; the ICD writes toe)
  • fit_interval::Bool: Curve fit interval flag (0=4h, 1=>4h)
  • AODO::Int64: Age of Data Offset for the NMCT (seconds; 5-bit broadcast count with an LSB of 900 s, so 27900 s means "NMCT unavailable")

Subframe 3 - Ephemeris Parameters (Part 2)

  • C_ic::Float64: Cosine harmonic correction to inclination (rad)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad)
  • C_is::Float64: Sine harmonic correction to inclination (rad)
  • i_0::Float64: Inclination angle at reference time (rad)
  • C_rc::Float64: Cosine harmonic correction to orbit radius (meters)
  • ω::Float64: Argument of perigee (rad)
  • Ω_dot::Float64: Rate of right ascension (rad/s)
  • IODE_Sub_3::Int64: Issue of Data, Ephemeris from subframe 3 (8 bits)
  • i_dot::Float64: Rate of inclination angle (rad/s)

Subframe 4 Page 18 - Ionosphere and UTC

  • α_0..α_3::Float64: Klobuchar ionospheric delay coefficients (s, s/sc, s/sc², s/sc³)
  • β_0..β_3::Float64: Klobuchar ionospheric period coefficients (s, s/sc, s/sc², s/sc³)
  • A_0UTC::Float64: Constant term of the UTC polynomial (s; the ICD writes A0)
  • A_1UTC::Float64: 1st-order term of the UTC polynomial (s/s; the ICD writes A1)
  • Δt_LS::Int64: Leap-second count before the pending adjustment (s)
  • t_0t::Int64: UTC reference time of week (s; the ICD writes tot)
  • WN_0t::Int64: UTC reference week number (modulo 256; the ICD writes WNt)
  • WN_LSF::Int64: Week number of the leap-second adjustment (modulo 256)
  • DN::Int64: Day number at the end of which the leap second becomes effective (1-7)
  • Δt_LSF::Int64: Leap-second count after the pending adjustment (s)

Subframe 4 Page 25 / Subframe 5 Page 25 - Configuration and health

  • sv_config::Vector{Int64}: 4-bit A-S flag and SV configuration per SV 1-32
  • sv_health_sf4_25::Vector{Int64}: Raw 6-bit health words for SV 25-32
  • sv_health_sf5_25::Vector{Int64}: Raw 6-bit health words for SV 1-24

Subframe 5 Pages 1-24 - Almanac

  • almanacs::SlotDictionary{GPSL1CAAlmanac,33}: Per-SV almanacs, keyed by SV ID
  • t_0a::Int64: Almanac reference time of week (s; the ICD writes toa)
  • WN_a::Int64: Almanac reference week number (modulo 256)

Reference

IS-GPS-200N, Tables 20-I, 20-II, 20-III, Sections 20.3.3.3-20.3.3.4

source
GNSSDecoder.GPSL1CAAlmanac — Type
GPSL1CAAlmanac

Almanac data for one GPS satellite, decoded from a single LNAV almanac page (subframe 4 pages 2-5 / 7-10 for SV 25-32, subframe 5 pages 1-24 for SV 1-24).

The almanac provides reduced-precision orbital and clock parameters for satellite acquisition planning and bootstrapping position fixes. Inclination is broadcast as a delta from the nominal GPS constellation value (i_nominal = 0.3 semi-circles ≈ 54°), which the decoder stores in δi.

Fields

  • e::Float64: Eccentricity (dimensionless)
  • t_0a::Int: Almanac reference time of week (seconds)
  • δi::Float64: Inclination delta from nominal 0.3 semi-circles (rad)
  • Ω_dot::Float64: Rate of right ascension (rad/s)
  • sv_health::Int64: Raw 8-bit SV health word (0 = healthy; IS-GPS-200N 20.3.3.5.1.3, Table 20-VII — the MSB summarises the navigation data and the five LSBs are a coded signal-component status, so the word is kept raw)
  • sqrt_A::Float64: Square root of semi-major axis (√m)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad)
  • ω::Float64: Argument of perigee (rad)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • a_f0::Float64: SV clock bias correction coefficient (seconds)
  • a_f1::Float64: SV clock drift correction coefficient (s/s)

Reference

IS-GPS-200N, Section 20.3.3.5.1.2, Table 20-VI

source

Galileo I/NAV (shared by E1-B and E5b)

Galileo E1-B and E5b-I carry the identical I/NAV message — the OS SIS ICD states they use "the same page layout", differing only in page sequencing — so they share the decoded GalileoINAVData container and one constants struct, GalileoINAVConstants. The per-signal constants are type aliases that fix its signal tag; they differ only in which signal-health facet of word type 5 is_sat_healthy reports (E1-B/C or E5b), mirroring GPS CNAV.

GNSSDecoder.GalileoINAVConstants — Type
GalileoINAVConstants{S}

GTRF constants and I/NAV message structure parameters shared by the two Galileo signal components that broadcast I/NAV, E1-B and E5b-I. Aliased per signal as GalileoE1BConstants (S = :GalileoE1B) and GalileoE5bConstants (S = :GalileoE5bI); the field values are identical and the tag S only selects the signal reported by get_signal_type and the health facet checked by is_sat_healthy.

The physical constants are defined in the Galileo OS SIS ICD (Open Service Signal-In-Space Interface Control Document) and are used for computing satellite positions and clock corrections from broadcast ephemeris data.

Fields

  • syncro_sequence_length::Int: Length of synchronization sequence in bits (250 bits per page)
  • preamble::UInt16: Page synchronization pattern (0101100000 binary)
  • preamble_length::Int: Length of preamble in bits (10)
  • PI::Float64: Mathematical constant π = 3.1415926535898 (Galileo OS SIS ICD Table 68)
  • Ω_dot_e::Float64: Mean angular velocity of the Earth = 7.2921151467×10⁻⁵ rad/s
  • c::Float64: Speed of light = 2.99792458×10⁸ m/s
  • μ::Float64: Geocentric gravitational constant = 3.986004418×10¹⁴ m³/s²
  • F::Float64: Relativistic correction constant = -4.442807309×10⁻¹⁰ s/√m

Reference

Galileo OS SIS ICD, Issue 2.2, Table 68

source
GNSSDecoder.GalileoE1BConstants — Type
GalileoE1BConstants

Galileo E1-B specialization of GalileoINAVConstants (GalileoINAVConstants{:GalileoE1B}). Same field values as the E5b constants — the I/NAV message is identical on both components; the distinct tag only selects the reported signal and the E1-B/C health facet in is_sat_healthy. Reference: Galileo OS SIS ICD, Issue 2.2, Table 38 / Table 68.

source
GNSSDecoder.GalileoE5bConstants — Type
GalileoE5bConstants

Galileo E5b specialization of GalileoINAVConstants (GalileoINAVConstants{:GalileoE5bI}). Same field values as the E1-B constants — the I/NAV message is identical on both components; the distinct tag only selects the reported signal (GalileoE5bI, the data-bearing component; GalileoE5bQ is the dataless pilot) and the E5b health facet in is_sat_healthy. Reference: Galileo OS SIS ICD, Issue 2.2, Table 38 / Table 68.

source
GNSSDecoder.GalileoINAVData — Type
GalileoINAVData

Decoded Galileo I/NAV navigation message data — the shared container for the two signal components that broadcast I/NAV, E1-B and E5b-I.

Contains ephemeris, clock correction, signal health, group delay, ionospheric correction, GST-UTC and GST-GPS conversion, almanac, and Reduced CED parameters decoded from the Galileo I/NAV message. All parameters conform to the Galileo OS SIS ICD, Issue 2.2.

Galileo System Time (GST) Fields

  • WN::Int64: Week Number (0-4095)
  • TOW::Int64: Time of Week at message transmission (seconds, 0-604799)

Satellite Identification (Word Type 4)

  • SVID::Int: Satellite Identifier (1-36 nominal range)

Ephemeris Parameters (Word Types 1-3)

  • t_0e::Float64: Ephemeris reference time (seconds)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • e::Float64: Eccentricity (dimensionless)
  • sqrt_A::Float64: Square root of semi-major axis (√m)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad)
  • i_0::Float64: Inclination angle at reference time (rad)
  • ω::Float64: Argument of perigee (rad)
  • i_dot::Float64: Rate of change of inclination angle (rad/s)
  • Ω_dot::Float64: Rate of change of right ascension (rad/s)
  • Δn::Float64: Mean motion difference from computed value (rad/s)
  • C_uc::Float64: Cosine harmonic correction to argument of latitude (rad)
  • C_us::Float64: Sine harmonic correction to argument of latitude (rad)
  • C_rc::Float64: Cosine harmonic correction to orbit radius (meters)
  • C_rs::Float64: Sine harmonic correction to orbit radius (meters)
  • C_ic::Float64: Cosine harmonic correction to inclination (rad)
  • C_is::Float64: Sine harmonic correction to inclination (rad)

Signal-In-Space Accuracy (Word Type 3)

  • SISA_E1_E5b::Int: SISA index for dual frequency E1-E5b (Table 91/92; 255 = NAPA)

Clock Correction Parameters (Word Type 4)

  • t_0c::Float64: Clock correction reference time (seconds)
  • a_f0::Float64: SV clock bias correction coefficient (seconds)
  • a_f1::Float64: SV clock drift correction coefficient (s/s)
  • a_f2::Float64: SV clock drift rate correction coefficient (s/s²)

Issue of Data (Word Types 1-4)

  • IOD_nav1::UInt: Issue of Data from word type 1 (10-bit)
  • IOD_nav2::UInt: Issue of Data from word type 2 (10-bit)
  • IOD_nav3::UInt: Issue of Data from word type 3 (10-bit)
  • IOD_nav4::UInt: Issue of Data from word type 4 (10-bit)
  • num_pages_after_last_TOW::Int: Pages decoded since last TOW update
  • num_bits_after_valid_syncro_sequence_after_last_TOW::Int: Bits since last TOW sync

Signal Health and Data Validity (Word Type 5)

  • E1B_SHS::SignalHealth: E1-B/C signal health status (0=OK, 1=out of service, 2=Extended Operations Mode, 3=in test)
  • E5b_SHS::SignalHealth: E5b signal health status
  • E1B_DVS::DataValidityStatus: E1-B data validity (0=valid, 1=working without guarantee)
  • E5b_DVS::DataValidityStatus: E5b data validity

Broadcast Group Delay (Word Type 5)

  • BGD_E1_E5a::Float64: E1-E5a group delay correction (seconds)
  • BGD_E1_E5b::Float64: E1-E5b group delay correction (seconds)

Ionospheric Correction (Word Type 5)

  • a_i0::Float64: Effective Ionisation Level 1st-order coefficient (sfu)
  • a_i1::Float64: Effective Ionisation Level 2nd-order coefficient (sfu/degree)
  • a_i2::Float64: Effective Ionisation Level 3rd-order coefficient (sfu/degree²)
  • iono_storm_flag_region1..5::Bool: Ionospheric Disturbance (storm) flags for regions 1-5

GST-UTC Conversion (Word Type 6)

  • A_0UTC::Float64: Constant term of polynomial (s; the ICD writes A0)
  • A_1UTC::Float64: 1st-order term of polynomial (s/s; the ICD writes A1)
  • Δt_LS::Int: Leap Second count before leap second adjustment (s)
  • t_0t::Int: UTC data reference Time of Week (s)
  • WN_0t::Int: UTC data reference Week Number (8-bit, modulo 256)
  • WN_LSF::Int: Week Number of leap second adjustment (8-bit, modulo 256)
  • DN::Int: Day Number at end of which leap second becomes effective (1=Sunday … 7=Saturday)
  • Δt_LSF::Int: Leap Second count after leap second adjustment (s)

GST-GPS Conversion / GGTO (Word Type 10)

  • A_0G::Float64: Constant term of GST-GPS offset polynomial (s)

  • A_1G::Float64: Rate of change of GST-GPS offset (s/s)

  • t_0G::Int: GGTO reference time (s)

  • WN_0G::Int: GGTO reference Week Number (6-bit)

    All four stay nothing when the satellite broadcasts the ICD's "GGTO not valid" encoding — every one of the four fields all ones (5.1.8).

Almanac (Word Types 7-10)

  • almanacs::SlotDictionary{GalileoAlmanac,64}: Decoded almanacs keyed by SVID. Entries are inserted as Galileo broadcasts the almanac chain across word types 7→10. SVIDs not yet seen are absent from the dictionary. In-flight chain partials live in the decoder cache and are flushed here only once a full almanac for an SVID has been assembled with a consistent IODa. The store is preallocated with one slot per value of the 6-bit SVID field (0-63) and each flush overwrites that SVID's slot in place (see decode!).

Reduced Clock and Ephemeris Data (Word Type 16)

  • reduced_ced::GalileoReducedCED: Reduced CED for fast initial fix

Reference

Galileo OS SIS ICD, Issue 2.2, Tables 42-55, 67-87

source
GNSSDecoder.GalileoReducedCED — Type
GalileoReducedCED

Reduced Clock and Ephemeris Data, decoded from word type 16.

A compact ephemeris/clock set transmitted within a single I/NAV word. Provides reduced-accuracy parameters that allow a receiver to compute an initial position fix before the full ephemeris (words 1-4) has been collected. Reduced CED parameters must NOT be combined with full-precision parameters from words 1-4.

Fields

  • ΔA_red::Float64: Difference of semi-major axis from nominal (meters)
  • e_x_red::Float64: Eccentricity vector x-component, e·cos(ω) (dimensionless)
  • e_y_red::Float64: Eccentricity vector y-component, e·sin(ω) (dimensionless)
  • Δi_0_red::Float64: Inclination delta from nominal (rad)
  • Ω_0_red::Float64: Longitude of ascending node at weekly epoch (rad)
  • λ_0_red::Float64: Mean argument of latitude, M0+ω (rad)
  • a_f0_red::Float64: SV clock bias correction coefficient (seconds)
  • a_f1_red::Float64: SV clock drift correction coefficient (s/s)

Reference

Galileo OS SIS ICD, Issue 2.2, Table 87

source
GNSSDecoder.GalileoAlmanac — Type
GalileoAlmanac

Almanac data for one Galileo satellite.

The almanac provides reduced-precision orbital and clock parameters for predicting satellite positions and selecting satellites for tracking. Differences (Δsqrt_A, δi) are relative to nominal Galileo constellation values (A_nominal = 29 600 000 m, i_nominal = 56°; OS SIS ICD Issue 2.2 Table 1). The same record is produced by both the I/NAV decoder (word types 7-10) and the F/NAV decoder (page types 5-6); they differ only in which signal-health facet they populate (see below).

Fields

  • SVID::Int: Satellite identifier (1-36 nominal range; 0 = unused entry)
  • Δsqrt_A::Float64: Difference of √(semi-major axis) from nominal (√m)
  • e::Float64: Eccentricity (dimensionless)
  • ω::Float64: Argument of perigee (rad)
  • δi::Float64: Inclination delta from nominal (rad)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad)
  • Ω_dot::Float64: Rate of change of right ascension (rad/s)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • a_f0::Float64: Truncated SV clock bias (seconds)
  • a_f1::Float64: Truncated SV clock drift (s/s)
  • E5b_SHS::SignalHealth: Predicted E5b signal health status (Galileo I/NAV word types 7-10)
  • E1B_SHS::SignalHealth: Predicted E1-B/C signal health status (Galileo I/NAV word types 7-10)
  • E5a_SHS::SignalHealth: Predicted E5a signal health status (Galileo F/NAV page types 5-6; nothing for I/NAV-decoded almanacs)
  • IOD_a::Int: Almanac IOD
  • WN_a::Int: Almanac reference Week Number
  • t_0a::Int: Almanac reference time (seconds)

Reference

Galileo OS SIS ICD, Issue 2.2, Table 86 (the almanac parameters, shared by I/NAV and F/NAV); bit allocations in Tables 51-54 (I/NAV word types 7-10) and Tables 34-35 (F/NAV page types 5-6)

source
GNSSDecoder.SignalHealth — Type
SignalHealth

Galileo signal health status enumeration.

Indicates the operational status of a Galileo signal component (I/NAV word type 5, E5a F/NAV page type 1, and the per-satellite almanacs of both).

Values

  • signal_ok: Signal is operating normally (value 0)
  • signal_out_of_service: Signal is out of service (value 1)
  • signal_in_extended_operations_mode: Signal is in Extended Operations Mode (value 2)
  • signal_component_currently_in_test: Signal component is currently in test (value 3)

Reference

Galileo OS SIS ICD, Issue 2.2, Table 84

source
GNSSDecoder.DataValidityStatus — Type
DataValidityStatus

Galileo navigation data validity status enumeration.

Indicates whether the broadcast navigation data should be trusted for positioning.

Values

  • navigation_data_valid: Navigation data is valid (value 0)
  • working_without_guarantee: Navigation data is working without guarantee (value 1)

Reference

Galileo OS SIS ICD, Issue 2.2, Table 81

source

Galileo E5a

GNSSDecoder.GalileoE5aConstants — Type
GalileoE5aConstants

GTRF constants and F/NAV message structure parameters for Galileo E5a signal decoding.

The physical constants are defined in the Galileo OS SIS ICD (Open Service Signal-In-Space Interface Control Document) and are used for computing satellite positions and clock corrections from broadcast ephemeris data.

Fields

  • syncro_sequence_length::Int: Length of one F/NAV page in channel symbols (500 symbols = 10 s at 50 sps)
  • preamble::UInt16: F/NAV synchronisation pattern (101101110000 binary)
  • preamble_length::Int: Length of the sync pattern in symbols (12)
  • PI::Float64: Mathematical constant π = 3.1415926535898 (Galileo OS SIS ICD Table 68)
  • Ω_dot_e::Float64: Mean angular velocity of the Earth = 7.2921151467×10⁻⁵ rad/s
  • c::Float64: Speed of light = 2.99792458×10⁸ m/s
  • μ::Float64: Geocentric gravitational constant = 3.986004418×10¹⁴ m³/s²
  • F::Float64: Relativistic correction constant = -4.442807309×10⁻¹⁰ s/√m

Reference

Galileo OS SIS ICD, Issue 2.2, §4.2 and Table 68

source
GNSSDecoder.GalileoE5aData — Type
GalileoE5aData

Decoded Galileo E5a F/NAV navigation message data.

Contains ephemeris, clock correction, signal health, group delay, ionospheric correction, GST-UTC and GST-GPS conversion, and almanac parameters decoded from the Galileo F/NAV message (the data component broadcast on E5a-I). All parameters conform to the Galileo OS SIS ICD, Issue 2.2, §5.1.

Unlike I/NAV (E1B/E5b), F/NAV carries only the E5a signal-health (E5a_SHS) and data-validity (E5a_DVS) flags and a single broadcast group delay (BGD(E1, E5a)); there is no Reduced CED and no E5b/E1-B field. Angular quantities are stored in radians (the ICD broadcasts them in semi-circles; the decoder multiplies by π), matching the convention used by GalileoINAVData.

Galileo System Time (GST) Fields

  • WN::Int64: Week Number (0-4095)
  • TOW::Int64: Time of Week at the start of the page (seconds, 0-604799)

Satellite Identification (Page Type 1)

  • SVID::Int: Satellite Identifier (1-36 nominal range)

Ephemeris Parameters (Page Types 2-4)

  • t_0e::Float64: Ephemeris reference time (seconds)
  • M_0::Float64: Mean anomaly at reference time (radians)
  • e::Float64: Eccentricity (dimensionless)
  • sqrt_A::Float64: Square root of semi-major axis (√m)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (radians)
  • i_0::Float64: Inclination angle at reference time (radians)
  • ω::Float64: Argument of perigee (radians)
  • i_dot::Float64: Rate of change of inclination angle (radians/s)
  • Ω_dot::Float64: Rate of change of right ascension (radians/s)
  • Δn::Float64: Mean motion difference from computed value (radians/s)
  • C_uc::Float64: Cosine harmonic correction to argument of latitude (rad)
  • C_us::Float64: Sine harmonic correction to argument of latitude (rad)
  • C_rc::Float64: Cosine harmonic correction to orbit radius (meters)
  • C_rs::Float64: Sine harmonic correction to orbit radius (meters)
  • C_ic::Float64: Cosine harmonic correction to inclination (rad)
  • C_is::Float64: Sine harmonic correction to inclination (rad)

Signal-In-Space Accuracy (Page Type 1)

  • SISA_E1_E5a::Int: SISA index for dual frequency E1-E5a (Table 91/92; 255 = NAPA)

Clock Correction Parameters (Page Type 1)

  • t_0c::Float64: Clock correction reference time (seconds)
  • a_f0::Float64: SV clock bias correction coefficient (seconds)
  • a_f1::Float64: SV clock drift correction coefficient (s/s)
  • a_f2::Float64: SV clock drift rate correction coefficient (s/s²)

Issue of Data (Page Types 1-4)

  • IOD_nav1::UInt: Issue of Data from page type 1 (10-bit)
  • IOD_nav2::UInt: Issue of Data from page type 2 (10-bit)
  • IOD_nav3::UInt: Issue of Data from page type 3 (10-bit)
  • IOD_nav4::UInt: Issue of Data from page type 4 (10-bit)
  • num_pages_after_last_TOW::Int: Pages decoded since last TOW update
  • num_bits_after_valid_syncro_sequence_after_last_TOW::Int: Symbols since last TOW sync

Signal Health and Data Validity (Page Type 1)

  • E5a_SHS::SignalHealth: E5a signal health status (0=OK, 1=out of service, 2=Extended Operations Mode, 3=in test)
  • E5a_DVS::DataValidityStatus: E5a data validity (0=valid, 1=working without guarantee)

Broadcast Group Delay (Page Type 1)

  • BGD_E1_E5a::Float64: E1-E5a group delay correction (seconds)

Ionospheric Correction (Page Type 1)

  • a_i0::Float64: Effective Ionisation Level 1st-order coefficient (sfu)
  • a_i1::Float64: Effective Ionisation Level 2nd-order coefficient (sfu/degree)
  • a_i2::Float64: Effective Ionisation Level 3rd-order coefficient (sfu/degree²)
  • iono_storm_flag_region1..5::Bool: Ionospheric Disturbance (storm) flags for regions 1-5

GST-UTC Conversion (Page Type 4)

  • A_0UTC::Float64: Constant term of polynomial (s; the ICD writes A0)
  • A_1UTC::Float64: 1st-order term of polynomial (s/s; the ICD writes A1)
  • Δt_LS::Int: Leap Second count before leap second adjustment (s)
  • t_0t::Int: UTC data reference Time of Week (s)
  • WN_0t::Int: UTC data reference Week Number (8-bit, modulo 256)
  • WN_LSF::Int: Week Number of leap second adjustment (8-bit, modulo 256)
  • DN::Int: Day Number at end of which leap second becomes effective (1=Sunday … 7=Saturday)
  • Δt_LSF::Int: Leap Second count after leap second adjustment (s)

GST-GPS Conversion / GGTO (Page Type 4)

  • A_0G::Float64: Constant term of GST-GPS offset polynomial (s)

  • A_1G::Float64: Rate of change of GST-GPS offset (s/s)

  • t_0G::Int: GGTO reference time (s)

  • WN_0G::Int: GGTO reference Week Number (6-bit)

    All four stay nothing when the satellite broadcasts the ICD's "GGTO not valid" encoding — every one of the four fields all ones (5.1.8).

Almanac (Page Types 5-6)

  • almanacs::SlotDictionary{GalileoAlmanac,64}: Decoded almanacs keyed by SVID, preallocated with one slot per value of the 6-bit SVID field (0-63); every store and epoch back-patch below overwrites a slot in place (see decode!). Galileo broadcasts three almanacs across the word-type-5/6 pair: SVID-1 (full in WT5), SVID-2 (split across WT5 and WT6), and SVID-3 (full in WT6). The in-flight SVID-2 partial lives in the decoder cache and is flushed here only once WT6 completes it with a consistent IOD_a. SVID-3, though fully carried in WT6, inherits its reference epoch (WN_a/t_0a) from the paired WT5; when that partial is missing (mid-stream acquisition or an IOD cutover), the SVID-3 record is still stored with WN_a/t_0a left nothing — the decoder keeps whatever it can decode rather than discarding it. Because the epoch is shared by every almanac of a given IOD_a, a later WT5 back-fills it into any such partial record, so a one-shot WT6 orbit becomes usable even if that WT6 never reappears. An almanac may therefore be incomplete: any field can be nothing, and in particular a record's reference epoch (WN_a/t_0a) may be absent until a matching WT5 arrives — check the fields you need before using a record. F/NAV almanacs carry the E5a health (E5a_SHS); the E5b/E1-B almanac-health fields are left nothing.

Reference

Galileo OS SIS ICD, Issue 2.2, Tables 28-36 (F/NAV frame and page-type bit allocations) and §5.1, Tables 67-87 (the parameter definitions and scale factors)

source

Galileo E6-B (C/NAV — High Accuracy Service)

Galileo E6-B carries the C/NAV message, which is the Signal-in-Space channel of the Galileo High Accuracy Service: PPP-grade orbit, clock, code-bias and phase-bias corrections to another signal's broadcast ephemeris, rather than an ephemeris of its own. A HAS message is spread across up to 32 encoded pages distributed among satellites and reassembled with a Reed-Solomon erasure decode (see Shared Utilities), so GalileoE6BData exposes both the latest complete GalileoHASMessage and an accumulated view of the latest of each correction block.

GNSSDecoder.GalileoE6BConstants — Type
struct GalileoE6BConstants <: GNSSDecoder.AbstractGNSSConstants

Constants for the Galileo E6-B C/NAV (HAS) decoder — Galileo HAS SIS ICD, Issue 1.0.

Unlike every other decoder in this package these carry only the sync geometry the shared decode loop needs. C/NAV broadcasts corrections to another signal's ephemeris, never an ephemeris of its own, so there is no satellite position to compute here and no π, μ, F, speed of light or Earth rotation rate to compute it with. Carrying them anyway would imply orbit math this decoder does not do — uniformity of interface is already what AbstractGNSSConstants provides, and the type lattice states the same distinction one level up (GalileoE6BData is an AbstractGalileoData but not an AbstractGalileoEphemerisData).

Fields

  • syncro_sequence_length::Int64: Page length drained after each decoded page (1000 symbols)
  • preamble::UInt16: Synchronisation pattern 0xB770 = 1011011101110000 (ICD §2.3.1), MSB first
  • preamble_length::Int64: Trailing next-page sync segment retained for sync (16 symbols)
source
GNSSDecoder.GalileoE6BData — Type
GalileoE6BData <: AbstractGalileoData

Decoded Galileo E6-B C/NAV (High Accuracy Service) data.

Two views of the same stream are kept, because both are genuinely useful:

  • message is the most recently completed HAS message, exactly as the ICD defines it — one atomic unit, with whichever content blocks its header flagged.
  • masks and the five correction-block fields accumulate the latest of each kind across messages. This is what a correction consumer wants: HAS routinely splits a mask + orbit + bias message from a clock-only message (ICD §5.1), so no single message holds a usable set.

Every field here has passed the per-page CRC-24Q and the RS erasure decode, so raw_data and data track each other (there is no cross-message issue-of-data vote to run — see validate_data).

Storage

Every container here — the message record, the Mask ID store and the five correction blocks — is preallocated by the decoder state (to the ICD's maxima) and overwritten in place by decode!; data has its own set, which validate_data overwrites with a copy of raw_data's, so the two never share a container.

Service status

  • HAS_status::HASStatus: HAS status from the most recent valid page (Table 9)

Decoded content

  • message::GalileoHASMessage: the most recently completed message in full, including its header — message.TOH, .mask_id, .IOD_set_id and .message_id. Those are deliberately not mirrored as flat fields here: the blocks below can come from different messages, so each carries its own TOH / mask_id / IOD_set_id, and those are the ones to age a correction against. A flat data.TOH alongside data.orbit_corrections.TOH would look like the same fact and is not.
  • masks::SlotDictionary{GalileoHASMask,32}: every mask received so far, keyed by Mask ID (0-31)
  • orbit_corrections::GalileoHASCorrectionBlock{GalileoHASOrbitCorrection}: latest Orbit Corrections block
  • clock_corrections::GalileoHASCorrectionBlock{GalileoHASClockCorrection}: latest Clock Full-Set Corrections block
  • clock_subset_corrections::GalileoHASCorrectionBlock{GalileoHASClockCorrection}: latest Clock Subset Corrections block
  • code_biases::GalileoHASCorrectionBlock{GalileoHASCodeBias}: latest Code Biases block
  • phase_biases::GalileoHASCorrectionBlock{GalileoHASPhaseBias}: latest Phase Biases block

Reference

Galileo HAS SIS ICD, Issue 1.0

source
GNSSDecoder.GalileoHASMessage — Type
GalileoHASMessage

One completely received and decoded HAS message — the atomic unit the ICD defines, reassembled from MS HAS Encoded Pages by the RS erasure decoder.

Only Message Type 1 is specified (ICD Table 10), so in practice message_type == 1 and the six block fields are populated according to the flags of the MT1 header; a flag that was 0 leaves its field nothing.

Overwritten in place

A message is a preallocated, mutable record owned by the decoder state: decode! overwrites it with the next completed message. In state.data its block fields are the very blocks state.data publishes as the latest of each kind (data.message.clock_corrections === data.clock_corrections when the message carried one). Copy the state to keep a snapshot.

Fields

  • message_id::Int: Message ID (MID) the pages carried (0-31)
  • message_type::Int: Message Type (1 = satellite corrections)
  • message_size::Int: Message size in non-encoded pages (MS, 1-32)
  • TOH::Int: Time Of Hour (seconds into the GST hour, 0-3599)
  • mask_id::Int: Mask ID (0-31)
  • IOD_set_id::Int: IOD Set ID (0-31)
  • mask::Union{Nothing,GalileoHASMask}: Mask block, when the Mask Flag was set
  • orbit_corrections::Union{Nothing,GalileoHASCorrectionBlock{GalileoHASOrbitCorrection}}: Orbit Corrections block
  • clock_corrections::Union{Nothing,GalileoHASCorrectionBlock{GalileoHASClockCorrection}}: Clock Full-Set Corrections block
  • clock_subset_corrections::Union{Nothing,GalileoHASCorrectionBlock{GalileoHASClockCorrection}}: Clock Subset Corrections block
  • code_biases::Union{Nothing,GalileoHASCorrectionBlock{GalileoHASCodeBias}}: Code Biases block
  • phase_biases::Union{Nothing,GalileoHASCorrectionBlock{GalileoHASPhaseBias}}: Phase Biases block

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 11-14

source
GNSSDecoder.GalileoHASMask — Type
GalileoHASMask

One complete HAS Mask block: the per-constellation masks it defines, under the Mask ID that later messages reference. An immutable, pointer-free value, so storing it (in the Mask ID store, a message, the validated data) copies it.

Fields

  • mask_id::Int: Mask ID this mask defines (0-31)
  • satellite_masks::GalileoHASSatelliteMaskList: one entry per corrected constellation, in broadcast order (an AbstractVector{GalileoHASSatelliteMask})

Reference

Galileo HAS SIS ICD, Issue 1.0, Table 15

source
GNSSDecoder.GalileoHASSatelliteMask — Type
GalileoHASSatelliteMask

The HAS mask for one constellation: which satellites are corrected, which signals carry biases, and which broadcast navigation message the orbit and clock corrections refer to.

The raw ICD bit fields are kept alongside the expanded lists, since the raw masks are what later blocks' lengths are computed from. An immutable, pointer-free value: the expanded lists are views computed from the raw masks (see GalileoHASMaskIndices), and the Cell Mask is stored inline.

Fields

  • GNSS_ID::Int: GNSS index — 0 = GPS, 2 = Galileo (Table 18)
  • satellite_mask::UInt64: 40-bit Satellite Mask, MSB = satellite index 0 (Table 19)
  • signal_mask::UInt16: 16-bit Signal Mask, MSB = signal index 0 (Table 20)
  • cell_mask::Union{Nothing,GalileoHASCellMask}: Nsat × Nsig Cell Mask (an AbstractMatrix{Bool}), or nothing when the Cell Mask Availability Flag is 0 (biases then cover every masked satellite/signal pair)
  • nav_message_index::Int: Navigation Message Index — 0 = I/NAV (Galileo) / LNAV (GPS) (Table 21)
  • SVIDs::GalileoHASMaskIndices: Satellite IDs of the masked satellites (satellite index + 1, i.e. Galileo SVID / GPS PRN), an AbstractVector{Int} derived from satellite_mask
  • signal_indices::GalileoHASMaskIndices: Signal indices of the masked signals (0-based, per Table 20), an AbstractVector{Int} derived from signal_mask

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 16-21

source
GNSSDecoder.GalileoHASSatelliteMaskList — Type
struct GalileoHASSatelliteMaskList <: AbstractVector{GalileoHASSatelliteMask}

The per-constellation masks of one HAS Mask block, as an immutable, inline AbstractVector{GalileoHASSatelliteMask} of at most 15 entries (the ICD's 4-bit Nsys). Compares equal to a Vector of the same masks.

Fields

  • items::NTuple{15, GalileoHASSatelliteMask}: The masks in broadcast order; slots past length hold a placeholder
  • length::Int64: Number of masks (Nsys)
source
GNSSDecoder.GalileoHASMaskIndices — Type
struct GalileoHASMaskIndices <: AbstractVector{Int64}

The indices named by the set bits of a HAS bit mask (MSB = index 0), counting from first_index: an immutable AbstractVector{Int} computed from the mask itself, so it stores no list and never allocates.

It is what GalileoHASSatelliteMask's SVIDs (40-bit Satellite Mask, first_index = 1: Galileo SVID / GPS PRN) and signal_indices (16-bit Signal Mask, first_index = 0) are. It compares equal to a Vector of the same indices.

Fields

  • mask::UInt64: The raw mask, right-aligned in width bits
  • width::Int64: Width of the mask in bits (40 or 16)
  • first_index::Int64: Index named by the mask's most significant bit
source
GNSSDecoder.GalileoHASCellMask — Type
struct GalileoHASCellMask <: AbstractMatrix{Bool}

An Nsat × Nsig HAS Cell Mask (ICD §5.2.1.5) as an immutable, inline AbstractMatrix{Bool}: one row of up to 16 bits per satellite, stored in a fixed 40-row tuple so it never allocates. It compares equal to a Matrix{Bool} with the same cells, and any AbstractMatrix{Bool} of at most 40 × 16 converts to it.

Fields

  • rows::NTuple{40, UInt16}: Row r holds satellite r's cells as broadcast, num_signals bits right-aligned with signal 1 in the most significant of them; rows past num_satellites are zero
  • num_satellites::Int64: Number of rows (Nsat)
  • num_signals::Int64: Number of columns (Nsig)
source
GNSSDecoder.GalileoHASCorrectionBlock — Type
GalileoHASCorrectionBlock{T}

One HAS MT1 content block: a validity interval, the message header context it was broadcast under, and the per-satellite (or per-cell) corrections themselves.

Every block carries its own Validity Interval Index (ICD §5.2.2.1) starting at the message's Time Of Hour, so blocks of one message can — and routinely do — expire at different times. mask_id and IOD_set_id identify the satellite set and the broadcast-ephemeris issue the corrections apply to (ICD §7.6).

Overwritten in place

A block is a preallocated, mutable buffer owned by the decoder state: decode! overwrites its fields and the contents of its corrections vector when a later message carries a block of the same kind. Take a copy(state) to keep a snapshot.

Fields

  • TOH::Int: Time Of Hour of the message that carried this block (seconds into the GST hour, 0-3599)
  • mask_id::Int: Mask ID the corrections are keyed to
  • IOD_set_id::Int: IOD Set ID the corrections are keyed to
  • validity_interval::Union{Nothing,Int}: Validity interval in seconds from TOH (nothing for the reserved index 15)
  • corrections::Vector{T}: the block's entries, in broadcast order — a buffer preallocated to the most entries a message can carry, resized within that capacity

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 22, 27, 32, 35, 38

source
GNSSDecoder.GalileoHASOrbitCorrection — Type
GalileoHASOrbitCorrection

Orbit correction for one satellite, in the satellite-centred NTW frame (radial / in-track / cross-track, ICD §7.2).

A field is nothing where the ICD's "data not available" sentinel was broadcast (the most negative two's-complement value: -10.24 m radial, -16.384 m in- and cross-track). This is deliberately not folded to zero — a zero correction and an absent correction are different facts, and GNSS-SDR's choice to map both to 0 m downstream loses that.

Fields

  • GNSS_ID::Int: GNSS index the satellite belongs to (Table 18)
  • SVID::Int: Satellite ID (Galileo SVID / GPS PRN)
  • IOD_ref::Int: Reference IOD of the corrected broadcast navigation data — IODnav for Galileo, IODE/IODC for GPS (Table 26)
  • δ_radial::Union{Nothing,Float64}: Delta Radial correction (meters, LSB 0.0025)
  • δ_in_track::Union{Nothing,Float64}: Delta In-Track correction (meters, LSB 0.008)
  • δ_cross_track::Union{Nothing,Float64}: Delta Cross-Track correction (meters, LSB 0.008)

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 24-25

source
GNSSDecoder.GalileoHASClockCorrection — Type
GalileoHASClockCorrection

Clock correction for one satellite (ICD §7.3).

δ_clock already has the constellation's Delta Clock Multiplier applied, so it is the correction in meters ready to use; multiplier is reported alongside for traceability. δ_clock is nothing for the "data not available" sentinel (raw -4096); do_not_use marks the distinct "satellite shall not be used" sentinel (raw +4095), which carries no correction either but means something stronger.

Fields

  • GNSS_ID::Int: GNSS index the satellite belongs to (Table 18)
  • SVID::Int: Satellite ID (Galileo SVID / GPS PRN)
  • multiplier::Int: Delta Clock Multiplier applied, 1-4 (Table 29)
  • δ_clock::Union{Nothing,Float64}: Delta clock correction (meters, LSB 0.0025 × multiplier)
  • do_not_use::Bool: The satellite shall not be used (Table 31)

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 28-34

source
GNSSDecoder.GalileoHASCodeBias — Type
GalileoHASCodeBias

Code bias for one satellite/signal cell (ICD §7.4). bias is nothing for the "data not available" sentinel (raw -1024).

Fields

  • GNSS_ID::Int: GNSS index (Table 18)
  • SVID::Int: Satellite ID (Galileo SVID / GPS PRN)
  • signal_index::Int: Signal index within the constellation's Signal Mask (0-based, Table 20)
  • bias::Union{Nothing,Float64}: Code bias (meters, LSB 0.02)

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 36-37

source
GNSSDecoder.GalileoHASPhaseBias — Type
GalileoHASPhaseBias

Phase bias for one satellite/signal cell (ICD §7.5). bias is nothing for the "data not available" sentinel (raw -1024). phase_discontinuity_indicator increments whenever the fixed ambiguity for this satellite and signal must be re-initialised (ICD §5.2.6.1).

Fields

  • GNSS_ID::Int: GNSS index (Table 18)
  • SVID::Int: Satellite ID (Galileo SVID / GPS PRN)
  • signal_index::Int: Signal index within the constellation's Signal Mask (0-based, Table 20)
  • bias::Union{Nothing,Float64}: Phase bias (cycles, LSB 0.01)
  • phase_discontinuity_indicator::Int: Phase Discontinuity Indicator (0-3)

Reference

Galileo HAS SIS ICD, Issue 1.0, Tables 39-40

source
GNSSDecoder.HASStatus — Type
HASStatus

Galileo High Accuracy Service status, broadcast in every HAS Page Header.

Values

  • has_test_mode: HAS service testing activities ongoing; nominal performance may not be met (value 0)
  • has_operational_mode: HAS is expected to provide nominal performance (value 1)
  • has_status_reserved: Reserved (value 2)
  • has_do_not_use: Users shall stop using HAS from all satellites and discard previously received messages (value 3)

Reference

Galileo HAS SIS ICD, Issue 1.0, Table 9

source

GPS L1C-D

GNSSDecoder.GPSL1C_DConstants — Type
GPSL1C_DConstants

WGS 84 constants and CNAV-2 message structure parameters for GPS L1C-D decoding.

The frame is modelled through the generic streaming framework: preamble_length is the 52-symbol subframe-1 BCH segment of the next frame retained at the tail of the sync window, and syncro_sequence_length is the 1800-symbol frame that is drained once a subframe is decoded.

Fields

  • syncro_sequence_length::Int64: Frame length drained after each decoded subframe (1800 symbols)
  • preamble_length::Int64: Trailing next-frame subframe-1 BCH segment retained for sync (52 symbols)
  • PI::Float64: Mathematical constant π (IS-GPS-800J)
  • Ω_dot_e::Float64: WGS 84 Earth rotation rate (rad/s)
  • c::Float64: Speed of light (m/s)
  • μ::Float64: WGS 84 Earth gravitational parameter (m³/s²)
  • F::Float64: Relativistic correction constant (s/√m)

Reference

IS-GPS-800J, Sections 3.2 and 3.5, Table 3.5-1.

source
GNSSDecoder.GPSL1C_DData — Type
GPSL1C_DData

Decoded GPS L1C-D (CNAV-2) navigation message data.

Holds the subframe-2 clock, ephemeris, and accuracy parameters (IS-GPS-800J Figure 3.5-1 / Table 3.5-1). Subframe-3 page contents are not parsed in this slice (issue #39); only the count of CRC-valid subframe-3 pages received is tracked. Field-naming follows GPSL1CAData: semi-circle quantities are converted to radians on decode (multiplied by π), all Union{Nothing,…} until first decoded.

Sync / timing

  • toi::Int: Last validated Time-Of-Interval count (0..399), or nothing.
  • ITOW::Int64: Interval time of week — number of two-hour epochs since the start of the week (subframe 2 bits 14-21).
  • WN::Int64: Transmission week number, modulo-8192 (subframe 2 bits 1-13).
  • t_op::Int64: CEI data sequence propagation time of week (seconds). Not the same field as t_op_D, which is the DC Data Predict Time of Week.

Health / accuracy

  • l1c_health::Bool: L1C signal health bit (false = OK, true = bad/unavailable).
  • ura_ed_index::Int64: Ephemeris URA index (signed).
  • integrity_status_flag::Bool: Level of integrity assurance the URA carries (bit 566; 3.5.3.10.1). false is the legacy level, true the enhanced one — "URA is integrity assured to the enhanced level only when the integrity status flag is '1'" (3.5.3.10).
  • WN_op::Int64: CEI data sequence propagation week number (bits 567-574, modulo 256). Pairs with t_op in the integrity-assured URA_NED expression of 3.5.3.10, which needs both.
  • ura_ned0_index::Int64, ura_ned1_index::Int64, ura_ned2_index::Int64: Non-elevation-dependent accuracy indices — NED Accuracy, NED Accuracy Change, and NED Accuracy Change Rate. Not three interchangeable clock URAs: they are the terms of one time-dependent NED bound.

Ephemeris (Table 3.5-1)

  • t_0e::Int64: Ephemeris/clock data reference time of week (seconds; the ICD writes toe).
  • ΔA::Float64: Semi-major axis difference at reference time (meters).
  • A_dot::Float64: Change rate in semi-major axis (m/s).
  • Δn_0::Float64: Mean motion difference from computed value (rad/s).
  • Δn_0_dot::Float64: Rate of mean motion difference (rad/s²).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • e::Float64: Eccentricity (dimensionless).
  • ω::Float64: Argument of perigee (rad).
  • Ω_0::Float64: Reference right ascension angle (rad).
  • i_0::Float64: Inclination angle at reference time (rad).
  • ΔΩ_dot::Float64: Rate of right ascension difference (rad/s).
  • i_dot::Float64: Rate of inclination angle (rad/s).
  • C_is::Float64, C_ic::Float64: Sine/cosine inclination harmonic corrections (rad).
  • C_rs::Float64, C_rc::Float64: Sine/cosine orbit-radius harmonic corrections (m).
  • C_us::Float64, C_uc::Float64: Sine/cosine argument-of-latitude harmonic corrections (rad).

Clock (Table 3.5-1)

  • t_0c::Int64: Clock data reference time of week (seconds; the ICD writes toc). Equals t_0e in CNAV-2.
  • a_f0::Float64, a_f1::Float64, a_f2::Float64: Clock bias / drift / drift-rate.
  • T_GD::Float64: L1/L2 P(Y) inter-signal correction (seconds).
  • ISC_L1CP::Float64, ISC_L1CD::Float64: L1CP / L1CD inter-signal corrections (seconds).

Subframe 3 (IS-GPS-800J §3.5.4 — IRN-IS-800J layout)

Subframe-3 pages are parsed after their CRC passes, dispatching on the 6-bit page number (bits 9-14; bits 1-8 are the transmitting PRN). Layouts follow IS-GPS-800J as amended by IRN-IS-800J-003. num_sf3_pages_received counts every CRC-valid SF3 page regardless of whether its page format is parsed.

Page 1 — UTC + Klobuchar iono + ISC

  • A_0UTC,A_1UTC,A_2UTC::Float64: UTC polynomial (s, s/s, s/s²; the ICD names them A0-n/A1-n/A2-n, Table 3.5-3).
  • Δt_LS,Δt_LSF::Int64: current/past and future leap-second counts (s).
  • t_0t::Int64: UTC reference time of week (s; the ICD writes t_ot).
  • WN_0t,WN_LSF::Int64: UTC and leap-second reference week numbers (the ICD writes WN_ot for the first).
  • DN::Int64: leap-second reference day number (1-7).
  • α_0,α_1,α_2,α_3,β_0,β_1,β_2,β_3::Float64: Klobuchar ionospheric coefficients.
  • ISC_L1CA,ISC_L2C,ISC_L5I5,ISC_L5Q5::Float64: inter-signal corrections (s).

Page 2 — GGTO + EOP

  • A_0GGTO,A_1GGTO,A_2GGTO::Float64: GPS/GNSS time-offset polynomial (the ICD writes A0GGTO/A1GGTO/A2GGTO).
  • t_GGTO::Int64, WN_GGTO::Int64: GGTO reference time/week.
  • GGTO_ID::Int64: GNSS the time offset refers to — 0 none, 1 Galileo, 2 GLONASS, 3-7 reserved. (Named "GNSS ID" in IS-GPS-800 ≤ Rev J; renamed "GGTO ID" by IRN-IS-800J-003.)
  • t_EOP::Int64: EOP reference time of week (s).
  • PM_X,PM_X_dot,PM_Y,PM_Y_dot::Float64: polar-motion values/rates.
  • ΔUT_GPS,ΔUT_GPS_dot::Float64: UT1-GPS (UT1−GPST) difference and rate.

Pages 3/4/5 — keyed dictionaries (nothing until first decoded)

Keyed by the 8-bit PRN_a field, one preallocated slot per possible value (SlotDictionary, iterated in ascending PRN order). A decoded packet overwrites its PRN's slot in place (see decode!).

  • reduced_almanacs::SlotDictionary{GPSL1C_DReducedAlmanac,256} (page 3).
  • midi_almanacs::SlotDictionary{GPSL1C_DMidiAlmanac,256} (page 4).
  • differential_corrections::SlotDictionary{GPSL1C_DDifferentialCorrection,256} (page 5).

Page 6 — Text

  • text_message::CStaticString{29}: up to 29 ASCII characters (control chars stripped), stored inline; compares equal to the matching String.

Counters

  • num_sf3_pages_received::Int: Count of CRC-valid subframe-3 pages received.

Reference

IS-GPS-800J, Figures 3.5-1 through 3.5-9 and Tables 3.5-1, 3.5-3 … 3.5-8.

source
GNSSDecoder.GPSL1C_DReducedAlmanac — Type
GPSL1C_DReducedAlmanac

One satellite's reduced-almanac packet from subframe 3, page 3 (IS-GPS-800J Figure 3.5-9, Table 3.5-6).

The reduced almanac gives a very coarse ephemeris for satellite selection. Each page-3 carries six 33-bit packets; this struct holds one decoded packet plus the page-level almanac reference week/time. A reduced almanac is complete in a single page — there is no IOD-driven multi-page chaining like Galileo's word types 7-10 — so GPSL1C_DData.reduced_almanacs entries are inserted whole, keyed by PRN_a. Reduced and Midi almanacs use separate structs (their field sets barely overlap); they share the keyed SlotDictionary pattern.

Reference values to apply (Table 3.5-6 footnotes): e = 0, δi = +0.0056 semi-circles (so i₀ = 0.30 sc = 54° and i₀ + δi = 55°), Ω̇ = -2.6e-9 semi-circles/s, A = A_ref + δA with A_ref = 26 559 710 m, Φ₀ = M₀ + ω. Semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: Almanac satellite PRN (8-bit field; 0 marks an empty packet, IS-GPS-800J §3.5.4.3.5.1.1). The CNAV reduced almanac carries the same quantity in 6 bits — see GPSCNAVReducedAlmanac.
  • WN_a::Int: Almanac reference week number (mod 8192).
  • t_0a::Int: Almanac reference time of week (seconds).
  • δA::Float64: Semi-major-axis delta from A_ref (meters).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • Φ_0::Float64: Argument of latitude at reference time, M₀+ω (rad).
  • l1_health::Bool, l2_health::Bool, l5_health::Bool: per-band health (false = OK, true = some/all signals bad).

Reference

IS-GPS-800J, Figure 3.5-4 / Figure 3.5-9 / Table 3.5-6.

source
GNSSDecoder.GPSL1C_DMidiAlmanac — Type
GPSL1C_DMidiAlmanac

One satellite's Midi almanac from subframe 3, page 4 (IS-GPS-800J Figure 3.5-5, Table 3.5-7).

The Midi almanac is a medium-precision single-SV almanac. Each page-4 carries exactly one SV's almanac, complete in that single page (no multi-page chaining), so GPSL1C_DData.midi_almanacs entries are inserted whole, keyed by PRN_a. Inclination is δi relative to i₀ = 0.30 semi-circles (54°); semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: Almanac satellite PRN.
  • WN_a::Int: Almanac reference week number (mod 8192).
  • t_0a::Int: Almanac reference time of week (seconds).
  • e::Float64: Eccentricity (dimensionless).
  • δi::Float64: Inclination delta from i₀ = 0.30 sc (rad); add the reference.
  • Ω_dot::Float64: Rate of right ascension (rad/s).
  • sqrt_A::Float64: Square root of the semi-major axis (√m).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • ω::Float64: Argument of perigee (rad).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • a_f0::Float64, a_f1::Float64: Clock bias / drift (s, s/s).
  • l1_health::Bool, l2_health::Bool, l5_health::Bool: per-band health.

Reference

IS-GPS-800J, Figure 3.5-5 / Table 3.5-7.

source
GNSSDecoder.GPSL1C_DDifferentialCorrection — Type
GPSL1C_DDifferentialCorrection

One satellite's clock+ephemeris differential-correction packet from subframe 3, page 5 (IS-GPS-800J Figure 3.5-6 / Figure 3.5-10 / Table 3.5-8).

A page-5 carries the predict/reference times plus exactly one DC packet (a 34-bit CDC segment and a 92-bit EDC segment that form an indivisible pair) for another SV, keyed by PRN_a. An all-ones PRN ID (0xFF = 255) in any PRN ID field marks an empty packet — the remainder of the data block is then filler (IS-GPS-800J §3.5.4.4.4.1). dc_data_type selects the data the corrections apply to: false ⇒ CNAV-2 (D_L1C), true ⇒ legacy NAV (D). Semi-circle fields → radians.

Fields

  • PRN_a::Int: PRN the corrections apply to.
  • t_op_D::Int: DC data predict time of week (seconds).
  • t_OD::Int: Time of DC data (seconds).
  • dc_data_type::Bool: false ⇒ CNAV-2, true ⇒ legacy NAV.
  • δa_f0::Float64, δa_f1::Float64: Clock bias / drift corrections (s, s/s).
  • UDRA_index::Int, UDRA_dot_index::Int: (rate-of-)UDRA indices (signed).
  • Δα::Float64, Δβ::Float64: Ephemeris α/β corrections (dimensionless).
  • Δγ::Float64: Ephemeris γ correction (rad).
  • Δi::Float64, ΔΩ::Float64: Inclination / right-ascension corrections (rad).
  • ΔA::Float64: Semi-major-axis correction (meters).

Reference

IS-GPS-800J, Figure 3.5-6 / Figure 3.5-10 / Table 3.5-8.

source

GPS CNAV (shared by L5I and L2C)

GPS L5I and GPS L2C carry the identical CNAV message, so they share the decoded GPSCNAVData container (and its almanac/correction records) and one constants struct, GPSCNAVConstants. The per-signal constants are type aliases that fix its signal tag; they differ only in which signal-health bit is_sat_healthy reports.

GNSSDecoder.GPSCNAVConstants — Type
GPSCNAVConstants{S} <: AbstractGNSSConstants

WGS 84 constants and CNAV message structure parameters shared by the GPS CNAV signals. The CNAV message is identical on GPS L5I and GPS L2C, so the field values are identical too; the phantom signal tag S (:GPSL5I / :GPSL2CM) exists only so is_sat_healthy can dispatch on the signal (L5I reports the L5 health bit, L2C the L2 health bit). The per-signal aliases GPSL5IConstants and GPSL2CMConstants fix S.

The message is modelled through the generic streaming framework: syncro_sequence_length is the 600-symbol message that is drained once decoded, and preamble_length is the 16-symbol encoding of the next message's preamble retained at the tail of the sync window.

Fields

  • syncro_sequence_length::Int64: Message length drained after each decoded message (600 symbols)
  • preamble_length::Int64: Trailing next-message preamble segment retained for sync (16 symbols)
  • PI::Float64: Mathematical constant π (IS-GPS-705J Table 20-II / IS-GPS-200N §30.3.3)
  • Ω_dot_e::Float64: WGS 84 Earth rotation rate (rad/s)
  • c::Float64: Speed of light (m/s)
  • μ::Float64: WGS 84 Earth gravitational parameter (m³/s²)
  • F::Float64: Relativistic correction constant (s/√m)

Reference

IS-GPS-705J §20.3.3 (L5I CNAV data) ≡ IS-GPS-200N §30.3.2 (L2C CNAV data) — the same message on the two signals. The signal layers that differ are IS-GPS-705J §3.3.3.1 (L5 data modulation, 100 sps) and IS-GPS-200N §3.3.3.1 (L2 CM, 50 sps).

source
GNSSDecoder.GPSL2CMConstants — Type
GPSL2CMConstants

GPS L2C specialization of GPSCNAVConstants (GPSCNAVConstants{:GPSL2CM}). Same field values as the GPS L5I constants — the CNAV message is identical on both signals; the distinct tag only selects the L2 health bit in is_sat_healthy. The data-bearing L2C component is the L2 CM code (GPSL2CM); the L2 CL code is a dataless pilot. Reference: IS-GPS-200N §30.3.2 / §3.3.3.1.

source
GNSSDecoder.GPSCNAVData — Type
GPSCNAVData

Decoded GPS CNAV navigation message data, shared by GPS L5I and GPS L2C (the CNAV message is identical on both signals).

Holds the parameters decoded from CNAV message types 10, 11, 12, 13, 14, 15, 30-37, and 40 (IS-GPS-705J §20.3.3 ≡ IS-GPS-200N §30.3.3). The decoder fills fields incrementally as the corresponding message types are received. Field-naming follows GPSL1C_DData (CNAV-2 broadcasts nearly the same parameter set): semi-circle quantities are converted to radians on decode (multiplied by π), all Union{Nothing,…} until first decoded.

Header (every message)

  • last_message_type::Int: Most recently decoded message type (0 until then).
  • TOW::Int64: SV time in seconds at the start of the next message (message TOW count × 6; the next message is 6 s away on L5I, 12 s on L2C).
  • alert_flag::Bool: Raised when the signal URA may be worse than indicated.

Health / accuracy (message types 10, 30-37)

  • l1_health::Bool, l2_health::Bool, l5_health::Bool: per-band signal health (false = OK).
  • ura_ed_index::Int64: Ephemeris URA index (signed).
  • ura_ned0_index::Int64, ura_ned1_index::Int64, ura_ned2_index::Int64: Non-elevation-dependent accuracy indices — NED Accuracy, NED Accuracy Change, and NED Accuracy Change Rate. Not three interchangeable clock URAs: they are the terms of one time-dependent NED bound.

Ephemeris (message types 10 + 11, Table 20-I)

  • WN::Int64: Transmission week number, modulo-8192.
  • t_op::Int64: CEI data sequence propagation time of week (seconds). Not the same field as t_op_D, which is the DC Data Predict Time of Week.
  • t_0e::Int64: Ephemeris data reference time of week (seconds; the ICD writes toe).
  • ΔA::Float64: Semi-major axis difference at reference time (meters).
  • A_dot::Float64: Change rate in semi-major axis (m/s).
  • Δn_0::Float64: Mean motion difference from computed value (rad/s).
  • Δn_0_dot::Float64: Rate of mean motion difference (rad/s²).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • e::Float64: Eccentricity (dimensionless).
  • ω::Float64: Argument of perigee (rad).
  • Ω_0::Float64: Reference right ascension angle (rad).
  • i_0::Float64: Inclination angle at reference time (rad).
  • ΔΩ_dot::Float64: Rate of right ascension difference (rad/s).
  • i_dot::Float64: Rate of inclination angle (rad/s).
  • C_is::Float64, C_ic::Float64: Sine/cosine inclination harmonic corrections (rad).
  • C_rs::Float64, C_rc::Float64: Sine/cosine orbit-radius harmonic corrections (m).
  • C_us::Float64, C_uc::Float64: Sine/cosine argument-of-latitude harmonic corrections (rad).
  • integrity_status_flag::Bool, l2c_phasing::Bool: message type 10 flags.

Clock (message types 30-37, Table 20-III)

  • t_0c::Int64: Clock data reference time of week (seconds; the ICD writes toc).
  • a_f0::Float64, a_f1::Float64, a_f2::Float64: Clock bias / drift / drift-rate.

Group delay / ISC + ionosphere (message type 30, Tables 20-III / 20-IV)

These fields are carried only by message type 30, which is broadcast far less often than the clock/ephemeris (max interval 288 s on L2C / 144 s on L5, vs 48 s / 24 s — IS-GPS-200 Table 30-XII, IS-GPS-705J Table 20-XII). They may therefore still be nothing even once positioning is otherwise ready: is_decoding_completed_for_positioning deliberately does not wait for them, so code that applies these corrections must handle nothing (treat as 0).

  • T_GD::Float64: L1/L2 P(Y) inter-signal correction (seconds).
  • ISC_L1CA,ISC_L2C,ISC_L5I5,ISC_L5Q5::Float64: inter-signal corrections (s).
  • α_0,α_1,α_2,α_3,β_0,β_1,β_2,β_3::Float64: Klobuchar ionospheric coefficients.
  • WN_op::Int64: Data predict week number (mod 256).

EOP (message type 32, Table 20-VII)

  • t_EOP::Int64: EOP reference time of week (s).
  • PM_X,PM_X_dot,PM_Y,PM_Y_dot::Float64: polar-motion values/rates (arcsec, arcsec/day).
  • ΔUT_GPS,ΔUT_GPS_dot::Float64: UT1-GPS difference (s) and rate (s/day).

UTC (message type 33, Table 20-IX)

  • A_0UTC,A_1UTC,A_2UTC::Float64: UTC polynomial (s, s/s, s/s²; the ICD names them A0-n/A1-n/A2-n).
  • Δt_LS,Δt_LSF::Int64: current/past and future leap-second counts (s).
  • t_0t::Int64: UTC reference time of week (s; the ICD writes t_ot).
  • WN_0t,WN_LSF::Int64: UTC and leap-second reference week numbers (the ICD writes WN_ot for the first).
  • DN::Int64: leap-second reference day number (1-7).

GGTO (message type 35, Table 20-XI)

  • A_0GGTO,A_1GGTO,A_2GGTO::Float64: GPS/GNSS time-offset polynomial (the ICD writes A0GGTO/A1GGTO/A2GGTO).
  • t_GGTO::Int64, WN_GGTO::Int64: GGTO reference time/week.
  • GNSS_ID::Int64: GNSS Type ID — 0 no data available, 1 Galileo, 2 GLONASS, 3-7 reserved. The ICD directs that a reserved code be read as "the GGTO data to which it applies is presently unusable", so there is no BeiDou code to decode: IS-GPS-200N §30.3.3.8.1 and IS-GPS-705J §20.3.3.8.1 both stop at GLONASS.

Almanacs / corrections / text — keyed stores (nothing until first decoded)

The keyed stores are SlotDictionarys with one preallocated slot per key the ICD field can hold, iterated in ascending PRN_a order. The decoder overwrites them in place (see decode!): each packet overwrites its PRN's slot of the store in raw_data, and each promotion to data overwrites the separate validated stores with the raw ones.

  • reduced_almanacs::SlotDictionary{GPSCNAVReducedAlmanac,64} (message types 12, 31; 6-bit PRN_a, 1-63).
  • midi_almanacs::SlotDictionary{GPSCNAVMidiAlmanac,64} (message type 37; 6-bit PRN_a, 1-63).
  • clock_corrections::SlotDictionary{GPSCNAVClockDifferentialCorrection,256} (message types 13, 34; 8-bit PRN ID, 0-254 — all-ones marks an empty packet).
  • ephemeris_corrections::SlotDictionary{GPSCNAVEphemerisDifferentialCorrection,256} (message types 14, 34; 8-bit PRN ID).
  • text_mt15::CStaticString{29}, text_page_mt15::Int64: message type 15 text page (29 ASCII characters, control chars stripped).
  • text_mt36::CStaticString{18}, text_page_mt36::Int64: message type 36 text page (18 ASCII characters, control chars stripped).
  • ism::GPSCNAVIntegritySupportMessage: message type 40 Integrity Support Message.

Reference

IS-GPS-705J, Figures 20-1 through 20-17 and Tables 20-I through 20-XIa.

source
GNSSDecoder.GPSCNAVReducedAlmanac — Type
GPSCNAVReducedAlmanac

One satellite's reduced-almanac packet from CNAV message types 12 or 31 (IS-GPS-705J Figure 20-16, Table 20-VI).

The reduced almanac gives a very coarse ephemeris for satellite selection. Message type 12 carries seven 31-bit packets, message type 31 four; each packet is complete in itself, so GPSCNAVData.reduced_almanacs entries are inserted whole, keyed by PRN_a (mirrors GPSL1C_DReducedAlmanac).

Reference values to apply (Table 20-VI footnotes): e = 0, δi = +0.0056 semi-circles (so i = 55°), Ω̇ = -2.6e-9 semi-circles/s, A = A_ref + δA with A_ref = 26 559 710 m, Φ₀ = M₀ + ω. Semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: Almanac satellite PRN (1-63; 0 marks an empty packet).
  • WN_a::Int: Almanac reference week number (mod 8192).
  • t_0a::Int: Almanac reference time of week (seconds).
  • δA::Float64: Semi-major-axis delta from A_ref (meters).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • Φ_0::Float64: Argument of latitude at reference time, M₀+ω (rad).
  • l1_health::Bool, l2_health::Bool, l5_health::Bool: per-band health (false = OK, true = some/all signals bad).

Reference

IS-GPS-705J, Figures 20-4 / 20-11 / 20-16, Table 20-VI.

source
GNSSDecoder.GPSCNAVMidiAlmanac — Type
GPSCNAVMidiAlmanac

One satellite's Midi almanac from CNAV message type 37 (IS-GPS-705J Figure 20-10, Table 20-V).

The Midi almanac is a medium-precision single-SV almanac, complete in a single message, so GPSCNAVData.midi_almanacs entries are inserted whole, keyed by PRN_a (mirrors GPSL1C_DMidiAlmanac). Inclination is δi relative to i₀ = 0.30 semi-circles (54°); semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: Almanac satellite PRN.
  • WN_a::Int: Almanac reference week number (mod 8192).
  • t_0a::Int: Almanac reference time of week (seconds).
  • e::Float64: Eccentricity (dimensionless).
  • δi::Float64: Inclination delta from i₀ = 0.30 sc (rad); add the reference.
  • Ω_dot::Float64: Rate of right ascension (rad/s).
  • sqrt_A::Float64: Square root of the semi-major axis (√m).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • ω::Float64: Argument of perigee (rad).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • a_f0::Float64, a_f1::Float64: Clock bias / drift (s, s/s).
  • l1_health::Bool, l2_health::Bool, l5_health::Bool: per-band health.

Reference

IS-GPS-705J, Figure 20-10, Table 20-V.

source
GNSSDecoder.GPSCNAVClockDifferentialCorrection — Type
GPSCNAVClockDifferentialCorrection

One satellite's clock differential-correction (CDC) packet from CNAV message types 13 or 34, keyed by PRN_a (IS-GPS-705J Figure 20-17, Table 20-X).

dc_data_type selects the data the corrections apply to: false ⇒ CNAV (message types 30-37), true ⇒ legacy NAV. A PRN ID of all-ones marks an empty packet (not stored).

Fields

  • PRN_a::Int: PRN the corrections apply to.
  • t_op_D::Int: DC data predict time of week (seconds).
  • t_OD::Int: Time of DC data (seconds).
  • dc_data_type::Bool: false ⇒ CNAV, true ⇒ legacy NAV.
  • δa_f0::Float64, δa_f1::Float64: Clock bias / drift corrections (s, s/s).
  • UDRA_index::Int: UDRA index (signed).

Reference

IS-GPS-705J, Figures 20-7 / 20-12 / 20-17, Table 20-X.

source
GNSSDecoder.GPSCNAVEphemerisDifferentialCorrection — Type
GPSCNAVEphemerisDifferentialCorrection

One satellite's ephemeris differential-correction (EDC) packet from CNAV message types 14 or 34, keyed by PRN_a (IS-GPS-705J Figure 20-17, Table 20-X). Semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: PRN the corrections apply to.
  • t_op_D::Int: DC data predict time of week (seconds).
  • t_OD::Int: Time of DC data (seconds).
  • dc_data_type::Bool: false ⇒ CNAV, true ⇒ legacy NAV.
  • Δα::Float64, Δβ::Float64: Ephemeris α/β corrections (dimensionless).
  • Δγ::Float64: Ephemeris γ correction (rad).
  • Δi::Float64, ΔΩ::Float64: Inclination / right-ascension corrections (rad).
  • ΔA::Float64: Semi-major-axis correction (meters).
  • UDRA_dot_index::Int: Rate-of-UDRA index (signed).

Reference

IS-GPS-705J, Figures 20-7 / 20-13 / 20-17, Table 20-X.

source
GNSSDecoder.GPSCNAVIntegritySupportMessage — Type
GPSCNAVIntegritySupportMessage

Integrity Support Message from CNAV message type 40 (ARAIM), complete in a single message (IS-GPS-705J Figure 20-14a, Table 20-XIa).

Fields

  • GNSS_ID::Int: GNSS identifier the ISM applies to.
  • WN_ISM::Int, TOW_ISM::Int: ISM reference week / time-of-week counts.
  • t_correl::Int, b_nom::Int, γ_nom::Int, R_sat::Int, P_const::Int, MFD::Int, service_level::Int: encoded ARAIM parameter indices.
  • mask::UInt64: 63-bit SV mask (MSB = PRN 1).

Reference

IS-GPS-705J, Figure 20-14a, Table 20-XIa.

source

BeiDou D1/D2 NAV (shared by B1I and B3I)

BeiDou B1I and B3I carry the identical legacy navigation message — D1 NAV on MEO/IGSO satellites, D2 NAV on GEO satellites, selected by PRN — so they share the decoded BeiDouDNAVData container and one constants struct, BeiDouDNAVConstants. The per-signal constants are type aliases that fix its signal tag, mirroring GPS CNAV.

GNSSDecoder.BeiDouDNAVConstants — Type
BeiDouDNAVConstants{S}

BDCS constants and D1/D2 NAV message structure parameters for the BeiDou B1I/B3I legacy signals, parameterized on the signal tag S (:BeiDouB1I or :BeiDouB3I) like GPSCNAVConstants. The distinct tag selects the signal identity (get_signal_type) — the message structure and all constants are identical on both signals (BDS-SIS-ICD-B3I-1.0 §5 mirrors BDS-SIS-ICD-B1I-3.0 §5).

Fields

  • syncro_sequence_length::Int: Length of one subframe in bits (300)
  • preamble::UInt16: 11-bit preamble 11100010010 (modified Barker code, §5.2.4.1)
  • preamble_length::Int: Length of preamble in bits (11)
  • word_length::Int: Length of each word in bits (30)
  • PI::Float64: π = 3.1415926535898 (BDS-SIS-ICD-B1I-3.0 Table 5-11)
  • Ω_dot_e::Float64: BDCS Earth rotation rate = 7.2921150×10⁻⁵ rad/s (differs from WGS-84!)
  • c::Float64: Speed of light = 2.99792458×10⁸ m/s
  • μ::Float64: BDCS geocentric gravitational constant = 3.986004418×10¹⁴ m³/s²
  • F::Float64: Relativistic correction constant −2√μ/c² = -4.442807309×10⁻¹⁰ s/√m (§5.2.4.9)

Reference

BDS-SIS-ICD-B1I-3.0, §5.1-§5.3 and Tables 5-7, 5-10, 5-11

source
GNSSDecoder.BeiDouB1IConstants — Type
BeiDouB1IConstants

BeiDou B1I specialization of BeiDouDNAVConstants (BeiDouDNAVConstants{:BeiDouB1I}). Same field values as the B3I constants — the legacy D1/D2 message is identical on both signals; the distinct tag only selects the signal identity reported by get_signal_type. Reference: BDS-SIS-ICD-B1I-3.0 §5.

source
GNSSDecoder.BeiDouB3IConstants — Type
BeiDouB3IConstants

BeiDou B3I specialization of BeiDouDNAVConstants (BeiDouDNAVConstants{:BeiDouB3I}). Same field values as the B1I constants — the legacy D1/D2 message is identical on both signals; the distinct tag only selects the signal identity reported by get_signal_type. Reference: BDS-SIS-ICD-B3I-1.0 §5.

source
GNSSDecoder.BeiDouDNAVData — Type
BeiDouDNAVData

Decoded BeiDou D1/D2 legacy navigation message data, shared by the B1I and B3I decoders (the broadcast message is structurally identical on both signals; see src/beidou/b1i.jl for the group-delay semantics that differ).

All parameters conform to BDS-SIS-ICD-B1I-3.0 §5.2 (D1) / §5.3 (D2). Angles broadcast in semicircles are stored in radians (scaled by the ICD π); times are in seconds of BeiDou Time (BDT).

Frame Fields

  • last_subframe_id::Int: FraID of the last decoded subframe (1-5)
  • SOW::Int64: Seconds of week at the leading edge of the current subframe's preamble (D1) or of subframe 1 of the current frame (D2), §5.2.4.3/§5.3.3.1
  • num_bits_after_valid_syncro_sequence_after_last_SOW::Int: Symbol-counter value when SOW was decoded (drives the SOW plausibility screen)

Subframe 1 (D1) / Subframe 1 Pages 1-4 (D2) - Clock, Health, Iono

The D2 page split is not one-to-one with the D1 subframe: pages 1-2 carry the health, accuracy and Klobuchar coefficients, a_0 arrives on page 3 and a_1/a_2/AODE on pages 3-4 (Figures 5-14-3 and 5-14-4).

  • SatH1::Bool: Autonomous satellite health flag (0 = good, §5.2.4.6)
  • AODC::Int64: Age of data, clock (§5.2.4.8)
  • URAI::Int64: User range accuracy index, the raw 4-bit broadcast value (§5.2.4.5, Table 5-4). Not converted to metres — see GPSL1CAData.URA_index for why; index 15 is "no accuracy prediction".
  • WN::Int64: BDT week number (0-8191, weeks since 2006-01-01, §5.2.4.4)
  • t_0c::Int64: Clock correction reference time (s, scale 2³; the ICD writes toc)
  • a_f0::Float64: Clock bias (s, scale 2⁻³³; the ICD names it a_0)
  • a_f1::Float64: Clock rate (s/s, scale 2⁻⁵⁰; the ICD names it a_1)
  • a_f2::Float64: Clock drift rate (s/s², scale 2⁻⁶⁶; the ICD names it a_2)
  • T_GD1::Float64: B1I equipment group delay differential (s, broadcast in 0.1 ns)
  • T_GD2::Float64: B2I equipment group delay differential (s, broadcast in 0.1 ns)
  • α_0..α_3, β_0..β_3::Float64: Klobuchar ionospheric model parameters (§5.2.4.7)
  • AODE::Int64: Age of data, ephemeris (§5.2.4.11)

Subframes 2-3 (D1) / Subframe 1 Pages 4-10 (D2) - Ephemeris

D2 page 3 is the clock page; the ephemeris starts on page 4 with Δn and C_uc (Figure 5-14-4).

  • t_0e::Int64: Ephemeris reference time (s, scale 2³; the ICD writes toe; split across subframes 2 and 3 in D1 — assembled once both parts are present)
  • sqrt_A::Float64: Square root of semi-major axis (√m, scale 2⁻¹⁹)
  • e::Float64: Eccentricity (scale 2⁻³³)
  • ω::Float64: Argument of perigee (rad)
  • Δn::Float64: Mean motion difference (rad/s)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad)
  • Ω_dot::Float64: Rate of right ascension (rad/s)
  • i_0::Float64: Inclination at reference time (rad)
  • i_dot::Float64: Rate of inclination (IDOT, rad/s)
  • C_uc, C_us::Float64: Harmonic corrections to argument of latitude (rad, scale 2⁻³¹)
  • C_rc, C_rs::Float64: Harmonic corrections to orbit radius (m, scale 2⁻⁶)
  • C_ic, C_is::Float64: Harmonic corrections to inclination (rad, scale 2⁻³¹)

D1 Subframes 4-5 - Almanac, Health, Time Offsets

  • almanacs::SlotDictionary{BeiDouDNAVAlmanac,64}: Per-SVID almanacs (SV 1-30, plus SV 31-63 when the expanded almanac is broadcast). One preallocated slot per SV ID; a decoded page overwrites its SV's slot in place.

  • health::SlotDictionary{UInt16,64}: Per-SVID 9-bit satellite health information words (Table 5-16; 0 = fully healthy). One preallocated slot per SV ID; a decoded health page overwrites its SVs' slots in place.

  • AmEpID::Int64: Identification of expanded almanacs (§5.2.4.14)

  • WN_a::Int64: Almanac week number (modulo 256, §5.2.4.16)

  • t_0a::Int64: Almanac reference time from subframe 5 page 8 (s, scale 2¹²)

  • A_0GPS, A_1GPS::Float64: BDT-GPS time offset (s, s/s; §5.2.4.19)

  • A_0Gal, A_1Gal::Float64: BDT-Galileo time offset (s, s/s; §5.2.4.20)

  • A_0GLO, A_1GLO::Float64: BDT-GLONASS time offset (s, s/s; §5.2.4.21)

    All three sections are marked "(Not broadcast temporarily)" in BDS-SIS-ICD-B1I-3.0, so expect all six to stay nothing on the air.

  • A_0UTC, A_1UTC::Float64: BDT-UTC offset polynomial (s, s/s; §5.2.4.18)

  • Δt_LS, Δt_LSF::Int64: Leap seconds before/after the new leap second (s)

  • WN_LSF, DN::Int64: Week number and day number of the new leap second

Reference

BDS-SIS-ICD-B1I-3.0 §5.2.4, §5.3.3 (and identically BDS-SIS-ICD-B3I-1.0 §5)

source
GNSSDecoder.BeiDouDNAVAlmanac — Type
BeiDouDNAVAlmanac

Almanac data for one BeiDou satellite, decoded from a single D1 almanac page (subframe 4 pages 1-24 for SV 1-24, subframe 5 pages 1-6 for SV 25-30, and — when the expanded-almanac identification AmEpID is 11 — subframe 5 pages 11-23 for SV 31-63 by time sharing, BDS-SIS-ICD-B1I-3.0 §5.2.4.13-§5.2.4.15).

Angles are stored in radians (the broadcast semicircle values scaled by the ICD's π). The reference inclination the broadcast δi corrects is i₀ = 0.3 semicircles for MEO/IGSO satellites and i₀ = 0 for GEO (Table 5-15 note).

Fields

  • sqrt_A::Float64: Square root of semi-major axis (√m)
  • a_f0::Float64: Satellite clock bias (s; the ICD names it a_0)
  • a_f1::Float64: Satellite clock rate (s/s; the ICD names it a_1)
  • Ω_0::Float64: Longitude of ascending node at reference time (rad)
  • e::Float64: Eccentricity (dimensionless)
  • δi::Float64: Correction of orbit reference inclination at reference time (rad)
  • t_0a::Int: Almanac reference time (s, scale 2¹²), from this page
  • Ω_dot::Float64: Rate of right ascension (rad/s)
  • ω::Float64: Argument of perigee (rad)
  • M_0::Float64: Mean anomaly at reference time (rad)
  • WN_a::Int64: Almanac reference week in force when this page was decoded, or nothing if subframe 5 page 8 had not been seen yet
Use this record's own reference epoch

t_0a and WN_a here belong to this entry, and BeiDouDNAVData also carries a t_0a/WN_a pair — the global one most recently broadcast in subframe 5 page 8. The almanac cycle is 24 pages spread over 12 minutes, so the two can disagree across an almanac changeover; pairing an entry with the global epoch would then propagate the wrong reference time. Prefer the entry's own fields, as BeiDouReducedAlmanac forces by construction.

Reference

BDS-SIS-ICD-B1I-3.0, Tables 5-12 and 5-14

source

BeiDou B1C

GNSSDecoder.BeiDouB1CConstants — Type
BeiDouB1CConstants

BDCS constants and B-CNAV1 message structure parameters for BeiDou B1C decoding.

The frame is modelled through the generic streaming framework: preamble_length is the 72-symbol subframe-1 BCH segment of the next frame retained at the tail of the sync window, and syncro_sequence_length is the 1800-symbol frame that is drained once a frame is decoded.

Fields

  • syncro_sequence_length::Int64: Frame length drained after each decoded frame (1800 symbols)
  • preamble_length::Int64: Trailing next-frame subframe-1 BCH segment retained for sync (72 symbols)
  • PI::Float64: Mathematical constant π (BDS-SIS-ICD-B1C-1.0 Table 7-9)
  • Ω_dot_e::Float64: BDCS Earth rotation rate (rad/s) — differs from the WGS-84 value
  • c::Float64: Speed of light (m/s)
  • μ::Float64: BDCS Earth gravitational parameter (m³/s²)
  • F::Float64: Relativistic correction constant F = -2√μ/c² (s/√m, ICD §7.5.2)

Reference

BDS-SIS-ICD-B1C-1.0, Sections 6.2 and 7.5-7.7 (Tables 7-8, 7-9).

source
GNSSDecoder.BeiDouB1CData — Type
BeiDouB1CData

Decoded BeiDou B1C (B-CNAV1) navigation message data.

Holds the subframe-2 system time, ephemeris, clock, and group-delay parameters (BDS-SIS-ICD-B1C-1.0 Figure 6-6, Tables 7-5 .. 7-8) plus the paged subframe-3 contents (Figures 6-8 .. 6-11). Semi-circle quantities are converted to radians on decode (multiplied by π); all fields are Union{Nothing,…} until first decoded.

Sync / timing (ICD §7.3)

  • soh::Int: Last validated Seconds-Of-Hour count (0..199, in 18 s units); the epoch it denotes is the leading edge of the current frame's subframe 1. Seconds of week at that epoch = HOW·3600 + soh·18.
  • HOW::Int64: Hours of week (0..167, subframe 2).
  • WN::Int64: BDT week number (0..8191, subframe 2).

Issue of data (ICD §7.4)

  • IODC::Int64: Issue of data, clock (10 bits).
  • IODE::Int64: Issue of data, ephemeris (8 bits). Not necessarily equal to the 8 LSBs of IODC, even inside one CRC-protected subframe 2: §7.4.3 says the two "may be different … during the update of the ephemeris and clock correction data", and a user "shall use the preceding matched pair" until they agree. is_decoding_completed_for_positioning enforces that match.

Ephemeris (Figure 6-12/6-13, Table 7-8)

  • t_0e::Int64: Ephemeris reference time of week (seconds; the ICD writes toe).
  • sat_type::Int64: Satellite orbit type (raw 2 bits: 1 GEO, 2 IGSO, 3 MEO, 0 reserved). Selects the semi-major-axis reference A_ref = 27 906 100 m (MEO) or 42 162 200 m (IGSO/GEO).
  • ΔA::Float64: Semi-major axis difference at reference time (meters).
  • A_dot::Float64: Change rate in semi-major axis (m/s).
  • Δn_0::Float64: Mean motion difference at reference time (rad/s).
  • Δn_0_dot::Float64: Rate of mean motion difference (rad/s²).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • e::Float64: Eccentricity (dimensionless).
  • ω::Float64: Argument of perigee (rad).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • i_0::Float64: Inclination angle at reference time (rad).
  • Ω_dot::Float64: Rate of right ascension (rad/s).
  • i_dot::Float64: Rate of inclination angle (rad/s).
  • C_is::Float64, C_ic::Float64: Sine/cosine inclination harmonic corrections (rad).
  • C_rs::Float64, C_rc::Float64: Sine/cosine orbit-radius harmonic corrections (m).
  • C_us::Float64, C_uc::Float64: Sine/cosine argument-of-latitude harmonic corrections (rad).

Clock and group delay (Figure 6-14, Tables 7-5, 7-6)

  • t_0c::Int64: Clock reference time of week (seconds; the ICD writes toc).

  • a_f0::Float64, a_f1::Float64, a_f2::Float64: Clock bias / drift / drift-rate (s, s/s, s/s²; the ICD names them a_0/a_1/a_2). The broadcast clock is referenced to the B3I signal (ICD §7.6.1).

  • T_GD_B2ap::Float64: Group delay differential of the B2a pilot (s).

  • ISC_B1Cd::Float64: Group delay differential between the B1C data and pilot components (s).

  • T_GD_B1Cp::Float64: Group delay differential of the B1C pilot, relative to B3I (s).

    A B1C receiver needs both: a_f0 is referenced to B3I (§7.6.1), so reaching the B1C data component means adding T_GD_B1Cp (B1C pilot vs B3I) and then ISC_B1Cd (B1C data vs B1C pilot). They ride in the same CRC-protected subframe 2 as the clock, so is_decoding_completed_for_positioning requires both and a consumer never has to treat either as optional. T_GD_B2ap is the B2a pilot's delta and is not required here.

Subframe 3 page header (Figures 6-8 .. 6-11, §7.14-7.17)

Present on every defined page type, refreshed whenever any page decodes:

  • HS::Int64: Satellite health status (Table 7-22: 0 healthy, 1 unhealthy or in test, 2-3 reserved).
  • DIF::Bool, SIF::Bool, AIF::Bool: Data / signal / accuracy integrity flags for B1C (Table 7-23; true flags a problem).
  • SISMAI::Int64: Signal-in-space monitoring accuracy index (4 bits).
  • SISAI_oe::Int64: Orbit along-track/cross-track accuracy index (5 bits, pages 1 and 3).
  • t_op::Int64: Time of week for data prediction (s; 11-bit broadcast count with an LSB of 300 s — see beidou_sisai_oc_block for why the factor holds although B1C-1.0 §7.16 defers the block's parameter table), and SISAI_ocb::Int64, SISAI_oc1::Int64, SISAI_oc2::Int64: orbit radius / clock accuracy indices (pages 1, 2, and 4).

Subframe 3, page type 1 — ionosphere + BDT-UTC (Figures 6-16, 6-17)

  • α_bdgim_1 .. α_bdgim_9::Float64: BDGIM ionospheric coefficients (TECu; Table 7-10 — the broadcast α_bdgim_5 carries scale factor −2⁻³, applied on decode). The ICD names them α_1 … α_9; the bdgim qualifier is this package's, because the Klobuchar α_0 … α_3 on GPSL1CAData, GPSCNAVData, GPSL1C_DData and BeiDouDNAVData are a different model with different units, and one name for both would let generic code apply the wrong one without complaint.
  • A_0UTC,A_1UTC,A_2UTC::Float64: BDT-UTC polynomial (s, s/s, s/s²).
  • Δt_LS,Δt_LSF::Int64: current or past and future leap-second counts (s; Table 7-20 — the past case is what selects Eq. (7-29) over (7-25)).
  • t_0t::Int64: UTC reference time of week (s); WN_0t::Int64: reference week. (The ICD writes t_ot/WN_ot.) (The ICD writes t_ot/WN_ot.)
  • WN_LSF::Int64, DN::Int64: leap-second reference week/day (day 0..6).

Subframe 3, page type 3 — EOP + BGTO (Figures 6-19, 6-20)

  • t_EOP::Int64: EOP reference time of week (s).
  • PM_X,PM_X_dot,PM_Y,PM_Y_dot::Float64: polar motion (arc-seconds, arc-seconds/day).
  • ΔUT1::Float64, ΔUT1_dot::Float64: UT1-UTC difference (s) and rate (s/day).
  • bgtos::SlotDictionary{BeiDouB1CBGTO,8}: BDT-GNSS time offsets keyed by the 3-bit GNSS ID (1-7). Overwritten in place by decode!.

Subframe 3, page types 2/4 — keyed almanac dictionaries

  • reduced_almanacs::SlotDictionary{BeiDouReducedAlmanac,64} (page type 2).
  • midi_almanacs::SlotDictionary{BeiDouMidiAlmanac,64} (page type 4).

Both are keyed by PRN_a (1-63) and, like bgtos, preallocated in the decoder's cache and overwritten in place by decode!: one slot per key, so a newer almanac for a PRN overwrites the older one.

Counters

  • num_sf3_pages_received::Int: Count of CRC-valid subframe-3 pages received.

Reference

BDS-SIS-ICD-B1C-1.0, Figures 6-5 .. 6-21 and Tables 7-2 .. 7-23.

source
GNSSDecoder.BeiDouB1CBGTO — Type
BeiDouB1CBGTO

One BDT-GNSS time offset (BGTO) parameter set from B-CNAV1 subframe 3, page type 3 (BDS-SIS-ICD-B1C-1.0 Figure 6-20, Table 7-21).

Δt = t_BD - t_GNSS = A_0BGTO + A_1BGTO·Δτ + A_2BGTO·Δτ² with Δτ = t_BD - t_0BGTO + 604800(WN - WN_0BGTO) (ICD Eq. 7-30). Different frames may broadcast offsets for different systems, so sets are keyed by GNSS_ID in BeiDouB1CData.

Fields

  • GNSS_ID::Int: GNSS type the offset refers to (1 GPS, 2 Galileo, 3 GLONASS; 0 marks the parameters as unavailable and is never stored).
  • WN_0BGTO::Int: Reference week number.
  • t_0BGTO::Int: Reference time of week (seconds).
  • A_0BGTO::Float64, A_1BGTO::Float64, A_2BGTO::Float64: Bias / drift / drift-rate coefficients (s, s/s, s/s²).

Reference

BDS-SIS-ICD-B1C-1.0, Figure 6-20, Table 7-21, §7.13.2.

source

BeiDou B2a

GNSSDecoder.BeiDouB2aConstants — Type
struct BeiDouB2aConstants <: GNSSDecoder.AbstractGNSSConstants

Constants for the BeiDou B2a (B-CNAV2) decoder (BDS-SIS-ICD-B2a-1.0).

Fields

  • syncro_sequence_length::Int64: Frame length drained after each decoded frame (600 symbols)
  • preamble_length::Int64: Preamble length (24 symbols, 0xE24DE8, ICD §6.2.1)
  • preamble::UInt64: Preamble bit pattern (MSB-first packing of 111000100100110111101000)
  • PI::Float64: Mathematical constant π (ICD Table 7-9)
  • Ω_dot_e::Float64: BDCS Earth rotation rate (rad/s, ICD Table 7-9 — differs from WGS-84)
  • c::Float64: Speed of light (m/s, ICD §7.5.2)
  • μ::Float64: BDCS geocentric gravitational constant (m³/s², ICD Table 7-9)
  • F::Float64: Relativistic correction constant F = −2√μ/c² (s/√m, ICD §7.5.2; same value as Galileo's GTRF constant because μ agrees)
source
GNSSDecoder.BeiDouB2aData — Type
struct BeiDouB2aData <: GNSSDecoder.AbstractBeiDouCNAVData

Decoded BeiDou B2a B-CNAV2 navigation data (BDS-SIS-ICD-B2a-1.0 §6.2.3, §7).

Every field is nothing until its carrying message type has been decoded. Angles are stored in radians (ICD semicircle values scaled by π = GNSS_PI), times in seconds, week numbers in weeks of BDT (epoch 2006-01-01T00:00:00 UTC, §7.3).

Ephemeris pairing bookkeeping: ephemeris I lives in message type 10 (with the set's IODE) and ephemeris II in message type 11, which carries no IOD of its own — the ICD instead requires MT10 and MT11 to be broadcast continuously together (§6.2.3). SOW_mt10 / SOW_mt11 record the SOW of the frames that delivered each half so is_ephemeris_decoded can require them to be adjacent frames (|ΔSOW| = 3 s), which is what "broadcast continuously together" makes observable on the air interface.

Fields

  • last_message_type::Int64: Message type of the most recently decoded frame (0 = none yet)
  • SOW::Union{Nothing, Int64}: Seconds of week of the most recent frame (s; epoch = rising edge of that frame's first preamble chip, §7.3)
  • WN::Union{Nothing, Int64}: BDT week number (MT10, §7.3)
  • HS::Union{Nothing, Int64}: Satellite health status HS (2 bits: 0 healthy, 1 unhealthy or in test, 2-3 reserved; MT11/30-34/40, §7.14)
  • DIF_B2a::Union{Nothing, Bool}: B2a data integrity flag (0 = message error within predictive accuracy, §7.15)
  • SIF_B2a::Union{Nothing, Bool}: B2a signal integrity flag (0 = signal normal, §7.15)
  • AIF_B2a::Union{Nothing, Bool}: B2a accuracy integrity flag (0 = SISMAI value valid, §7.15)
  • SISMAI::Union{Nothing, Int64}: Signal in space monitoring accuracy index (4 bits; definition deferred to a future ICD update, §7.17)
  • DIF_B1C::Union{Nothing, Bool}: B1C data integrity flag (also broadcast on B-CNAV2, §7.15)
  • SIF_B1C::Union{Nothing, Bool}: B1C signal integrity flag (§7.15)
  • AIF_B1C::Union{Nothing, Bool}: B1C accuracy integrity flag (§7.15)
  • IODE::Union{Nothing, Int64}: Issue of data, ephemeris (8 bits, MT10, §7.4.1)
  • t_0e::Union{Nothing, Int64}: Ephemeris reference time (s, ×300; the ICD writes toe)
  • sat_type::Union{Nothing, Int64}: Satellite orbit type (2 bits: 1 = GEO, 2 = IGSO, 3 = MEO, 0 reserved; Table 7-8)
  • ΔA::Union{Nothing, Float64}: Semi-major axis difference at reference time (m; vs A_ref = 27906100 m MEO / 42162200 m IGSO-GEO)
  • A_dot::Union{Nothing, Float64}: Change rate of semi-major axis (m/s)
  • Δn_0::Union{Nothing, Float64}: Mean motion difference at reference time (rad/s)
  • Δn_0_dot::Union{Nothing, Float64}: Rate of mean motion difference (rad/s²)
  • M_0::Union{Nothing, Float64}: Mean anomaly at reference time (rad)
  • e::Union{Nothing, Float64}: Eccentricity (dimensionless)
  • ω::Union{Nothing, Float64}: Argument of perigee (rad)
  • SOW_mt10::Union{Nothing, Int64}: SOW of the frame that delivered ephemeris I (pairing bookkeeping, see type docstring)
  • Ω_0::Union{Nothing, Float64}: Longitude of ascending node at weekly epoch (rad, MT11)
  • i_0::Union{Nothing, Float64}: Inclination angle at reference time (rad)
  • Ω_dot::Union{Nothing, Float64}: Rate of right ascension (rad/s)
  • i_dot::Union{Nothing, Float64}: Rate of inclination angle (rad/s)
  • C_is::Union{Nothing, Float64}: Amplitude of sine harmonic correction to inclination (rad)
  • C_ic::Union{Nothing, Float64}: Amplitude of cosine harmonic correction to inclination (rad)
  • C_rs::Union{Nothing, Float64}: Amplitude of sine harmonic correction to orbit radius (m)
  • C_rc::Union{Nothing, Float64}: Amplitude of cosine harmonic correction to orbit radius (m)
  • C_us::Union{Nothing, Float64}: Amplitude of sine harmonic correction to argument of latitude (rad)
  • C_uc::Union{Nothing, Float64}: Amplitude of cosine harmonic correction to argument of latitude (rad)
  • SOW_mt11::Union{Nothing, Int64}: SOW of the frame that delivered ephemeris II (pairing bookkeeping, see type docstring)
  • IODC::Union{Nothing, Int64}: Issue of data, clock (10 bits; a matched pair has IODE == IODC & 0xFF, §7.4.3)
  • t_0c::Union{Nothing, Int64}: Clock correction reference time (s, ×300; the ICD writes toc)
  • a_f0::Union{Nothing, Float64}: SV clock bias (s; the ICD names it a_0)
  • a_f1::Union{Nothing, Float64}: SV clock drift (s/s; the ICD names it a_1)
  • a_f2::Union{Nothing, Float64}: SV clock drift rate (s/s²; the ICD names it a_2)
  • T_GD_B2ap::Union{Nothing, Float64}: Group delay differential of the B2a pilot component vs the B3I-referenced clock (s)
  • ISC_B2ad::Union{Nothing, Float64}: Group delay differential between the B2a data and pilot components (s)
  • T_GD_B1Cp::Union{Nothing, Float64}: Group delay differential of the B1C pilot component (s)
  • α_bdgim_1::Union{Nothing, Float64}: BDGIM parameter α₁ (TECu). The ICD names the nine α_1 … α_9; the bdgim qualifier is this package's, keeping them distinct from the Klobuchar α_0 … α_3 of the other containers (see b1c.jl).
  • α_bdgim_2::Union{Nothing, Float64}: BDGIM parameter α₂ (TECu)
  • α_bdgim_3::Union{Nothing, Float64}: BDGIM parameter α₃ (TECu)
  • α_bdgim_4::Union{Nothing, Float64}: BDGIM parameter α₄ (TECu)
  • α_bdgim_5::Union{Nothing, Float64}: BDGIM parameter α₅ (TECu; broadcast with scale −2⁻³, Table 7-10)
  • α_bdgim_6::Union{Nothing, Float64}: BDGIM parameter α₆ (TECu)
  • α_bdgim_7::Union{Nothing, Float64}: BDGIM parameter α₇ (TECu)
  • α_bdgim_8::Union{Nothing, Float64}: BDGIM parameter α₈ (TECu)
  • α_bdgim_9::Union{Nothing, Float64}: BDGIM parameter α₉ (TECu)
  • t_EOP::Union{Nothing, Int64}: EOP data reference time (s, ×2⁴)
  • PM_X::Union{Nothing, Float64}: X-axis polar motion at reference time (arc-seconds)
  • PM_X_dot::Union{Nothing, Float64}: X-axis polar motion drift (arc-seconds/day)
  • PM_Y::Union{Nothing, Float64}: Y-axis polar motion at reference time (arc-seconds)
  • PM_Y_dot::Union{Nothing, Float64}: Y-axis polar motion drift (arc-seconds/day)
  • ΔUT1::Union{Nothing, Float64}: UT1−UTC difference at reference time (s)
  • ΔUT1_dot::Union{Nothing, Float64}: Rate of UT1−UTC difference (s/day)
  • A_0UTC::Union{Nothing, Float64}: Bias coefficient of BDT relative to UTC (s)
  • A_1UTC::Union{Nothing, Float64}: Drift coefficient of BDT relative to UTC (s/s)
  • A_2UTC::Union{Nothing, Float64}: Drift rate coefficient of BDT relative to UTC (s/s²)
  • Δt_LS::Union{Nothing, Int64}: Current or past leap second count (s)
  • t_0t::Union{Nothing, Int64}: Reference time of week for the UTC parameters (s, ×2⁴; the ICD writes t_ot)
  • WN_0t::Union{Nothing, Int64}: Reference week number for the UTC parameters (the ICD writes WN_ot)
  • WN_LSF::Union{Nothing, Int64}: Leap second reference week number
  • DN::Union{Nothing, Int64}: Leap second reference day number (0-6)
  • Δt_LSF::Union{Nothing, Int64}: Current or future leap second count (s)
  • GNSS_ID::Union{Nothing, Int64}: GNSS type the BGTO parameters refer to (0 = unavailable, 1 = GPS, 2 = Galileo, 3 = GLONASS, 4-7 reserved; §7.13.1)
  • WN_0BGTO::Union{Nothing, Int64}: BGTO reference week number
  • t_0BGTO::Union{Nothing, Int64}: BGTO reference time of week (s, ×2⁴)
  • A_0BGTO::Union{Nothing, Float64}: Bias coefficient of BDT relative to the identified GNSS time (s)
  • A_1BGTO::Union{Nothing, Float64}: Drift coefficient of BDT relative to the identified GNSS time (s/s)
  • A_2BGTO::Union{Nothing, Float64}: Drift rate coefficient of BDT relative to the identified GNSS time (s/s²)
  • t_op::Union{Nothing, Int64}: Time of week for data prediction (s; 11-bit count, LSB 300 s — see beidou_sisai_oc_block)
  • SISAI_ocb::Union{Nothing, Int64}: Satellite orbit radius & fixed clock bias accuracy index (raw, §7.16)
  • SISAI_oc1::Union{Nothing, Int64}: Satellite clock bias accuracy index (raw, §7.16)
  • SISAI_oc2::Union{Nothing, Int64}: Satellite clock drift accuracy index (raw, §7.16)
  • SISAI_oe::Union{Nothing, Int64}: Satellite orbit along-track/cross-track accuracy index (raw, MT40, §7.16)
  • reduced_almanacs::Union{Nothing, SlotDictionary{BeiDouReducedAlmanac, 64}}: Reduced almanacs keyed by PRN 1-63 (MT31: three per message; MT33: one per message); preallocated, overwritten in place by decode!
  • midi_almanacs::Union{Nothing, SlotDictionary{BeiDouMidiAlmanac, 64}}: Midi almanacs keyed by PRN 1-63 (MT40: one per message); preallocated, overwritten in place by decode!
source

BeiDou B2b

GNSSDecoder.BeiDouB2bConstants — Type
struct BeiDouB2bConstants <: GNSSDecoder.AbstractGNSSConstants

Constants for the BeiDou B2b (B-CNAV3) decoder — BDS-SIS-ICD-B2b-1.0.

Fields

  • syncro_sequence_length::Int64: Frame length drained after each decoded frame (1000 symbols)
  • preamble::UInt16: Preamble 0xEB90 (ICD §6.2.1), MSB first
  • preamble_length::Int64: Trailing next-frame preamble segment retained for sync (16 symbols)
  • PI::Float64: Mathematical constant π (BDS-SIS-ICD-B2b-1.0 Table 7-13)
  • Ω_dot_e::Float64: BDCS Earth rotation rate (rad/s) — differs from the WGS-84 value
  • c::Float64: Speed of light (m/s)
  • μ::Float64: BDCS Earth gravitational parameter (m³/s²)
  • F::Float64: Relativistic correction constant F = -2√μ/c² (s/√m, ICD §7.4.2)
source
GNSSDecoder.BeiDouB2bData — Type
BeiDouB2bData <: AbstractBeiDouCNAVData

Decoded BeiDou B-CNAV3 navigation data (BDS-SIS-ICD-B2b-1.0 §6.2.3 / §7).

Every field is nothing until first decoded from a CRC-validated frame. Message type 10 carries a complete ephemeris in one frame, message type 30 a complete clock set; B-CNAV3 broadcasts no issue-of-data stamps, so no cross-message consistency vote is needed (or possible) before promotion — each CRC-gated message is atomic.

Header (every message type)

  • last_message_type::Int: MesType of the most recently decoded frame (Table 7-1; 0 until the first decode).
  • SOW::Int64: Seconds of week of the current frame's leading edge (s). Broadcast as a 20-bit count with LSB 1 s — the scale factor of the Chinese-language Table 7-2; the English edition misprints it as 3. See decode_syncro_sequence for why the English table is not followed.

Message type 10 — ephemeris (Figures 6-3, 6-6, 6-7) and integrity flags

  • sat_type::Int64: Satellite orbit type (binary 01 = GEO, 10 = IGSO, 11 = MEO; Table 7-6).
  • t_0e::Int64: Ephemeris reference time (s, LSB 300; the ICD writes toe).
  • ΔA::Float64: Semi-major axis difference at reference time (m) relative to A_ref = 27 906 100 m (MEO) / 42 162 200 m (IGSO/GEO).
  • A_dot::Float64: Change rate of semi-major axis (m/s).
  • Δn_0::Float64: Mean motion difference at reference time (rad/s).
  • Δn_0_dot::Float64: Rate of mean motion difference (rad/s²).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • e::Float64: Eccentricity.
  • ω::Float64: Argument of perigee (rad).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • i_0::Float64: Inclination at reference time (rad).
  • Ω_dot::Float64: Rate of right ascension (rad/s) — broadcast in full, not as a difference.
  • i_dot::Float64: Rate of inclination (rad/s).
  • C_is,C_ic::Float64: Sine/cosine harmonic correction to inclination (rad).
  • C_rs,C_rc::Float64: Sine/cosine harmonic correction to orbit radius (m).
  • C_us,C_uc::Float64: Sine/cosine harmonic correction to argument of latitude (rad).
  • DIF,SIF,AIF::Bool: Data / signal / accuracy integrity flags for the B2b_I signal (false = OK, Table 7-21).
  • SISMAI::Int64: Signal in space monitoring accuracy index (4 bits; semantics deferred to a future ICD update, §7.16). B2b-1.0 Figure 6-3 labels the broadcast field SISMA, reserving SISMAI for its index; B1C-1.0 and B2a-1.0 label the same field SISMAI, which is the spelling this package follows.

Message type 30 — clock, group delay, ionosphere, UTC, EOP, accuracy, health

  • WN::Int64: BDT week number at the current frame's epoch (Table 7-2).
  • t_0c::Int64: Clock correction reference time (s, LSB 300).
  • a_f0::Float64: Clock bias (s). a_f1::Float64: drift (s/s). a_f2::Float64: drift rate (s/s²). (Table 7-3; the ICD names them a0/a1/a2, and writes toc for t_0c.)
  • T_GD_B2bI::Float64: Group delay differential of the B2bI signal relative to B3I (s, Table 7-4). Required, not optional: `af0is referenced to B3I (§7.6), so a B2b_I receiver must add this to reach its own component. It arrives in the same MT30 as the clock, soisdecodingcompletedforpositioning` gates on it at no cost in time to first fix.
  • α_bdgim_1 … α_bdgim_9::Float64: BDGIM ionospheric model parameters (TECu, Table 7-8; αbdgim5 is broadcast unsigned and the decoder applies its negative scale factor, -2⁻³). The ICD names them α_1 … α_9; see b1c.jl for why the bdgim qualifier is added.
  • A_0UTC,A_1UTC,A_2UTC::Float64: BDT-UTC polynomial (s, s/s, s/s²; Table 7-18).
  • Δt_LS::Int64: Current or past leap-second count (s). Δt_LSF::Int64: current or future leap-second count (s).
  • t_0t::Int64: UTC reference time of week (s, LSB 2⁴). WN_0t::Int64: UTC reference week. (The ICD writes t_ot/WN_ot.)
  • WN_LSF::Int64: Leap-second reference week. DN::Int64: leap-second reference day (0-6).
  • t_EOP::Int64: EOP reference time (s, LSB 2⁴; Table 7-16).
  • PM_X,PM_Y::Float64: Polar motion (arc-seconds). PM_X_dot,PM_Y_dot::Float64: drift (arc-seconds/day).
  • ΔUT1::Float64: UT1-UTC difference (s). ΔUT1_dot::Float64: its rate (s/day).
  • t_op::Int64: Time of week for data prediction (s; 11-bit count, LSB 300 s — see beidou_sisai_oc_block).
  • SISAI_ocb,SISAI_oc1,SISAI_oc2,SISAI_oe::Int64: Signal-in-space accuracy index fields, raw broadcast values (5/3/3/5 bits; semantics deferred to a future ICD update, §7.15).
  • HS::Int64: Satellite health status (0 = healthy, 1 = unhealthy or in test, 2-3 reserved; Table 7-20).

Message type 40 — BGTO and almanacs (Figure 6-5)

  • GNSS_ID::Int64: BGTO GNSS identification (0 = not available, 1 = GPS, 2 = Galileo, 3 = GLONASS; §7.12).
  • WN_0BGTO::Int64, t_0BGTO::Int64: BGTO reference week / time of week (s, LSB 2⁴).
  • A_0BGTO,A_1BGTO,A_2BGTO::Float64: BDT-GNSS time offset polynomial (s, s/s, s/s²; Table 7-19).
  • midi_almanacs::SlotDictionary{BeiDouMidiAlmanac,64}: Midi almanacs keyed by PRN_a (1-63, §7.8).
  • reduced_almanacs::SlotDictionary{BeiDouReducedAlmanac,64}: Reduced almanacs keyed by PRN_a (1-63, §7.9). Both almanac stores are preallocated in the decoder's cache and overwritten in place by decode!.
  • WN_a::Int64, t_0a::Int64: Almanac reference week / time (s, LSB 2¹²) for the reduced almanacs (Table 7-15).

Reference

BDS-SIS-ICD-B2b-1.0, Figures 6-3 through 6-15 and Tables 7-1 through 7-21.

source

BeiDou shared almanac records

The BDS-3 midi and reduced almanac blocks are bit-identical across B-CNAV1 (B1C), B-CNAV2 (B2a), and B-CNAV3 (B2b), so all three decoders produce the same record types.

GNSSDecoder.BeiDouMidiAlmanac — Type
BeiDouMidiAlmanac

Midi almanac for one BeiDou satellite.

The BDS-3 midi almanac is one 156-bit block whose layout, scale factors, and reference values are identical across the three B-CNAV messages, so the same record is produced by the B1C decoder (B-CNAV1 subframe 3 page type 4, BDS-SIS-ICD-B1C-1.0 Figure 6-21 / Table 7-13), the B2a decoder (B-CNAV2 message type 40, BDS-SIS-ICD-B2a-1.0 Figure 6-20 / Table 7-13), and the B2b decoder (B-CNAV3 message type 40, BDS-SIS-ICD-B2b-1.0 Figure 6-15 / Table 7-11) — mirroring how GalileoAlmanac is shared by the I/NAV and F/NAV decoders. Each block is complete in itself and keyed by PRN_a in the per-signal data containers.

Reference value to apply (ICD notes to the midi-almanac tables): inclination is i = i_ref + δi with i_ref = 0.30π rad (54°) for MEO/IGSO satellites and i_ref = 0.0 for GEO satellites, selected by sat_type. Semi-circle fields are converted to radians on decode.

Fields

  • PRN_a::Int: Almanac satellite PRN (1-63; a zero PRN marks an empty block and is never stored).
  • sat_type::Int: Satellite orbit type (2 bits: 1 = GEO, 2 = IGSO, 3 = MEO, 0 reserved).
  • WN_a::Int: Almanac reference week number (BDT week).
  • t_0a::Int: Almanac reference time of week (seconds, LSB 2¹²).
  • e::Float64: Eccentricity (dimensionless).
  • δi::Float64: Inclination delta from the sat_type reference (rad).
  • sqrt_A::Float64: Square root of the semi-major axis (√m).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • Ω_dot::Float64: Rate of right ascension (rad/s).
  • ω::Float64: Argument of perigee (rad).
  • M_0::Float64: Mean anomaly at reference time (rad).
  • a_f0::Float64, a_f1::Float64: Satellite clock bias / drift (s, s/s). The midi-almanac terms are the one BeiDou clock pair the ICDs already spell af0/af1 (B2b-1.0 Table 7-11, B1C/B2a-1.0 Table 7-13) — unlike the clock-correction block, which they write a_0/a_1/a_2.
  • health::Int: Raw 8-bit satellite health word (BDS-SIS-ICD-B2b-1.0 Table 7-12, the fullest definition: bit 8 (MSB) = satellite clock, bit 7 = B1C signal, bit 6 = B2a signal, bit 5 = B2b_I signal, bits 4-1 reserved; 0 = healthy. The earlier B1C/B2a ICDs' Table 7-14 defines the same word without the B2b bit).
source
GNSSDecoder.BeiDouReducedAlmanac — Type
BeiDouReducedAlmanac

Reduced almanac for one BeiDou satellite.

The BDS-3 reduced almanac is one 38-bit block whose layout, scale factors, and reference values are identical across the three B-CNAV messages, so the same record is produced by the B1C decoder (B-CNAV1 subframe 3 page type 2, four blocks per page, BDS-SIS-ICD-B1C-1.0 Figure 6-18 / Table 7-16), the B2a decoder (B-CNAV2 message types 31 and 33, BDS-SIS-ICD-B2a-1.0 Figure 6-17 / Table 7-16), and the B2b decoder (B-CNAV3 message type 40, five blocks per message, BDS-SIS-ICD-B2b-1.0 Figure 6-12 / Table 7-14). The 38-bit block itself carries no epoch; the almanac reference week/time broadcast alongside it in the carrying page/message is copied into every record, so each record is complete in itself and keyed by PRN_a in the per-signal data containers.

Reference values to apply (ICD notes to the reduced-almanac tables): A = A_ref + δA with A_ref = 27 906 100 m (MEO) or 42 162 200 m (IGSO/GEO) selected by sat_type; Φ₀ = M₀ + ω relative to e = 0 and δi = 0 with i = 55° (MEO/IGSO) or i = 0° (GEO). The user algorithm is the midi almanac's with the missing parameters set to zero.

Fields

  • PRN_a::Int: Almanac satellite PRN (1-63; a zero PRN marks an empty block and is never stored).
  • sat_type::Int: Satellite orbit type (2 bits: 1 = GEO, 2 = IGSO, 3 = MEO, 0 reserved).
  • WN_a::Int: Almanac reference week number (from the carrying page/message).
  • t_0a::Int: Almanac reference time of week (seconds, from the carrying page/message).
  • δA::Float64: Semi-major-axis correction to the sat_type reference (m).
  • Ω_0::Float64: Longitude of ascending node at weekly epoch (rad).
  • Φ_0::Float64: Argument of latitude at reference time, M₀ + ω (rad).
  • health::Int: Raw 8-bit satellite health word (same layout as BeiDouMidiAlmanac's).
source