GPS L1 C/A LNAV navigation message synthesis and decoding (subframes 1-3).
The legacy navigation (LNAV) message is the data stream modulated onto the GPS L1 C/A signal at 50 bits per second. Its structure is defined in IS-GPS-200 (Section 20.3): the message is organized into 1500-bit frames, each frame being five 300-bit subframes, and each subframe being ten 30-bit words. Every word carries 24 source data bits (most significant first) followed by 6 parity bits.
This module covers the clock and ephemeris subframes:
- Subframe 1 - SV clock correction and health (IS-GPS-200 Table 20-I).
- Subframe 2 - first half of the ephemeris (IS-GPS-200 Table 20-II).
- Subframe 3 - second half of the ephemeris (IS-GPS-200 Table 20-III).
The first word of every subframe is the telemetry (TLM) word; the second is the hand-over word (HOW). Both are described in IS-GPS-200 Section 20.3.3.
Words and bits
A subframe is represented as a flat list of 300 bits (0/1), most
significant bit first, with the ten words concatenated in transmission
order. word_length/0 is 30 and subframe_length/0 is 300.
Parameters and units
encode/2 and decode/1 exchange an Orbis.GNSS.Navigation.LNAV.Ephemeris struct
whose fields hold the natural engineering-unit values (the products of the
transmitted integers and their IS-GPS-200 scale factors). See that struct's
documentation for the per-field units. Angular ephemeris quantities use
semicircles (and semicircles/second), the harmonic correction terms use
radians, distances use meters, and clock/time quantities use seconds, exactly
as tabulated in IS-GPS-200.
Parity
The 6 parity bits of each word are produced by the (32, 26) Hamming code of
IS-GPS-200 Section 20.3.5.2 and Table 20-XIV, including the rule that the two
trailing parity bits of the previous word (D29*, D30*) feed the current
word and that D30* complements the 24 transmitted data bits. The last two
data bits of the HOW and of word 10 are solved so that those words'
D29/D30 parity bits are zero, per IS-GPS-200 Section 20.3.3.2. At the
start of each subframe the previous parity bits are seeded to zero, producing
self-consistent stand-alone subframes.
Examples
iex> Orbis.GNSS.Navigation.LNAV.word_length()
30
iex> Orbis.GNSS.Navigation.LNAV.subframe_length()
300
iex> Orbis.GNSS.Navigation.LNAV.preamble()
139
Summary
Functions
Decodes LNAV subframes 1-3 back into the engineering-unit parameter struct.
Encodes clock and ephemeris parameters into LNAV subframes 1-3.
Computes the 6 parity bits of a word (IS-GPS-200 Table 20-XIV).
Verifies the parity of a single 30-bit word.
The 8-bit TLM preamble 1000 1011 as an integer (IS-GPS-200 Section 20.3.3.1).
Extracts the 3-bit subframe ID from a hand-over word.
Bit length of a single LNAV subframe (IS-GPS-200 Section 20.3.2).
Extracts the 17-bit time-of-week count from a hand-over word.
Bit length of a single LNAV word (IS-GPS-200 Section 20.3.2).
Functions
@spec decode(%{ required(1) => [0 | 1], required(2) => [0 | 1], required(3) => [0 | 1] }) :: {:ok, Orbis.GNSS.Navigation.LNAV.Ephemeris.t()} | {:error, term()}
Decodes LNAV subframes 1-3 back into the engineering-unit parameter struct.
Accepts %{1 => bits, 2 => bits, 3 => bits} of 300-bit subframes. Parity is
verified on all 30 words first; a failure returns
{:error, {:parity_failed, subframe, word}} (word is 1-based). On success
returns {:ok, %Orbis.GNSS.Navigation.LNAV.Ephemeris{}}.
@spec encode( Orbis.GNSS.Navigation.LNAV.Ephemeris.t(), keyword() ) :: {:ok, %{required(1) => [0 | 1], required(2) => [0 | 1], required(3) => [0 | 1]}} | {:error, term()}
Encodes clock and ephemeris parameters into LNAV subframes 1-3.
Returns {:ok, %{1 => bits, 2 => bits, 3 => bits}} where each value is a flat
list of 300 bits (most significant first). Out-of-range parameters yield
{:error, {:out_of_range, field, value}}; this function never raises on bad
input.
Options
:tow- the 17-bit time-of-week count placed in each HOW (0..131071, default 0).:alert- HOW alert flag (0/1, default 0).:anti_spoof- HOW anti-spoof flag (0/1, default 0).:integrity- TLM integrity status flag (0/1, default 0).:tlm_message- 14-bit TLM message field (default 0).
@spec parity([0 | 1], 0 | 1, 0 | 1) :: [0 | 1]
Computes the 6 parity bits of a word (IS-GPS-200 Table 20-XIV).
data24 is the list of 24 source data bits (most significant first, before
the D30* complementation). d29_prev and d30_prev are the two trailing
parity bits of the previous word. Returns [D25, D26, D27, D28, D29, D30].
@spec parity_valid?([0 | 1], 0 | 1, 0 | 1) :: boolean()
Verifies the parity of a single 30-bit word.
word30 is the 30-bit word as transmitted (data bits possibly complemented
by D30*, followed by 6 received parity bits). d29_prev/d30_prev are the
previous word's trailing parity bits. Returns true when the recomputed
parity matches the received parity.
@spec preamble() :: 139
The 8-bit TLM preamble 1000 1011 as an integer (IS-GPS-200 Section 20.3.3.1).
Examples
iex> Orbis.GNSS.Navigation.LNAV.preamble()
139
@spec subframe_id([0 | 1]) :: 1..5
Extracts the 3-bit subframe ID from a hand-over word.
Accepts a 30-bit HOW word or a full 300-bit subframe. Returns the subframe identifier carried in HOW bits 20-22 (IS-GPS-200 Section 20.3.3.2).
Examples
iex> {:ok, sfs} = Orbis.GNSS.Navigation.LNAV.encode(Orbis.GNSS.Navigation.LNAV.Ephemeris.example(), tow: 0)
iex> Orbis.GNSS.Navigation.LNAV.subframe_id(sfs[2])
2
@spec subframe_length() :: 300
Bit length of a single LNAV subframe (IS-GPS-200 Section 20.3.2).
Examples
iex> Orbis.GNSS.Navigation.LNAV.subframe_length()
300
@spec tow([0 | 1]) :: non_neg_integer()
Extracts the 17-bit time-of-week count from a hand-over word.
Accepts either a 30-bit HOW word or a full 300-bit subframe (whose word 2 is the HOW). The returned value is the truncated Z-count carried in the HOW (units of 6 seconds), per IS-GPS-200 Section 20.3.3.2.
Examples
iex> {:ok, sfs} = Orbis.GNSS.Navigation.LNAV.encode(Orbis.GNSS.Navigation.LNAV.Ephemeris.example(), tow: 12345)
iex> Orbis.GNSS.Navigation.LNAV.tow(sfs[1])
12345
@spec word_length() :: 30
Bit length of a single LNAV word (IS-GPS-200 Section 20.3.2).
Examples
iex> Orbis.GNSS.Navigation.LNAV.word_length()
30