Patrick Lidstone
Self-hosted

Inmarsat-C STD-C / EGC — native decoder

The L-band maritime store-and-forward messaging and SafetyNET/MSI broadcast downlink: BPSK at 1200 sym/s through a CCSDS r=1/2 K=7 Viterbi decoder, a 15-bit LFSR descrambler, a 64-column block de-interleaver and a 24-bit unique-word frame sync, with an EGC (Enhanced Group Call) message layer on top.

Rafe project · app/radio/inmarsat.py, test_inmarsat.py · RX (+ reference encoder for self-test) · reuses the CCSDS Viterbi and BPSK receiver from app/radio/sat/ · frame/scrambler/interleaver/UW constants validated self-consistently; exact on-air interop is the next step


Abstract

Inmarsat-C is the low-rate geostationary satellite service that carries, among other traffic, EGC SafetyNET — the satellite counterpart of NAVTEX: navigational warnings, weather, and distress relays broadcast to ships beyond MF/VHF range. The downlink TDM carrier is BPSK at 1200 symbols/s in the 1.5 GHz band, protected by the same convolutional code the space agencies use (rate 1/2, constraint length 7), block interleaving against burst fades, and an additive scrambler for spectral conditioning.

Rafe's decoder is deliberately layered on the satellite DSP already in the repo: the BPSK carrier/timing recovery and the K=7 Viterbi come from app/radio/sat/ (shared with LRPT/CCSDS), and this module adds the four STD-C-specific stages — descrambler, de-interleaver, unique-word frame sync, and the EGC message layer. This document pins every constant of those stages, the exact encode/decode order, and the honest interop status: the chain round-trips through noise, carrier offset and raw IQ in the test suite, but the frame constants (notably the unique word) still need validation against a live off-air STD-C capture.


1. Background

1.1 The system

An Inmarsat-C terminal is a telex-grade store-and-forward messager: ~600 bit/s usable, no voice. Traffic flows ship↔︎shore through Land Earth Stations (LES); the shore-to-ship direction rides continuous TDM carriers from each satellite. EGC is the broadcast service multiplexed into those carriers — SafetyNET (maritime safety, structured by NAV/MET area) and FleetNET (commercial group messaging). A receive-only EGC watch is exactly what this decoder targets: lock the TDM downlink, recover frames, and parse the safety messages.

1.2 The coding chain

The downlink protection stack, outermost first:

info bits → scramble (LFSR x^15+x^14+1) → conv encode r=1/2 K=7
          → block interleave (64 columns) → [UW ‖ payload] → BPSK

Note the order: scrambling is applied to the info bits before encoding (and therefore descrambling happens after Viterbi decoding). The interleaver sits between the encoder and the channel so a fade is dispersed into isolated soft-bit hits, which the Viterbi absorbs — the standard concatenation logic (maths guide §12.1).


2. The exact constants

2.1 Physical layer

Parameter Value Code
Modulation BPSK sat.qpsk_rx.demod_bpsk
Symbol rate 1200 sym/s SYM_RATE = 1200
Pulse shaping RRC, α = 0.5 demod_bpsk(..., alpha=0.5)
Receiver chain AGC → RRC matched filter → Gardner timing → BPSK Costas sat/qpsk_rx.py
Bit mapping symbol real part: +1 → bit 0, −1 → bit 1 soft = (1 − real)/2

2.2 FEC — CCSDS convolutional code (shared with sat/)

Parameter Value
Rate, constraint length 1/2, K = 7 (64 states)
Generators G1 = 0o171, G2 = 0o133, G2 output inverted (CCSDS convention)
Decoder soft-input Viterbi (sat/viterbi.py), inputs 0.0–1.0
Flush 6 zero bits; coded length = 2·(n_info + 6)

2.3 Scrambler

15-bit additive LFSR, polynomial \(x^{15}+x^{14}+1\), seed 0x7FFF:

output bit  = reg & 1
feedback    = (reg >> 14) ^ (reg >> 13)   (bits 14 ⊕ 13)
reg         = ((reg << 1) | feedback) & 0x7FFF

The PN sequence is XORed onto the bits; the operation is involutive (descramble = scramble). This is the same polynomial family as DVB-S's energy-dispersal scrambler (see the Commonalities table).

2.4 Interleaver

Block interleaver, 64 columns: write the coded bits row by row (zero-pad the last row), transmit column by column. De-interleaving reshapes column-major and reads back row-major, preserving soft values so the Viterbi loses nothing.

2.5 Frame sync — the unique word

24-bit UW prepended to each interleaved block:

1 0 1 1 0 0 0 1  1 1 0 0 1 0 1 1  0 1 0 0 1 1 1 0     = 0xB1CB4E

The receiver hard-slices the soft stream at 0.5 and slides a correlator, accepting the first position with ≤ 3 bit errors against the UW. The UW also resolves BPSK's 180° phase ambiguity: decode_iq simply tries both polarities and keeps whichever one both finds a UW and Viterbi-decodes (cf. LRPT's four-rotation ASM hunt, same idea).

Interop caveat (deliberate): this UW value is flagged in the source for confirmation against the STD-C TDM spec. The decode chain is self-consistent — the encoder and decoder agree — but a live capture must confirm the word (and the interleaver geometry) before off-air claims.

2.6 Frame assembly

stdc_encode(info):  TX = UW ‖ interleave( conv_encode( scramble(info) ) )
stdc_decode(soft):  find UW (≤3 err) → deinterleave 2·(n_info+6) soft bits
                    → Viterbi → descramble → info

The decoder needs n_info (the expected payload size) to size the de-interleave — frame-length signalling from the real TDM structure is not yet implemented (§6).


3. The EGC message layer

build_egc / parse_egc serialise a SafetyNET-style message into the frame payload. Layout (all single bytes unless noted):

Offset Field Value
0 magic 0x7C
1 priority 0 routine · 1 safety · 2 urgency · 3 distress (2 LSBs)
2 service code default 0x31
3 LES id originating Land Earth Station
4–5 sequence number 16-bit big-endian
6 area code NAV/MET area or address group
7 text length n ≤ 255
8 … 8+n−1 text ASCII
last checksum two's complement of the byte sum: sum(body + checksum) ≡ 0 (mod 256)

parse_egc rejects a payload that is short, lacks the magic, or fails the checksum, and otherwise returns priority (named), service, LES, sequence, area, and the text.

Scope note: this is Rafe's compact serialisation of the EGC semantics (the fields a SafetyNET watchkeeper needs), not a byte-exact transcription of the on-air EGC packet header, which carries additional repetition/presentation codes inside the TDM packet structure. Off-air decoding will extend this layer once the TDM framing (§6) is in.


4. Decoding raw IQ, end to end

decode_iq(iq, fs, n_info):

  1. demod_bpsk — AGC, RRC (α = 0.5) matched filter, Gardner symbol timing, BPSK Costas loop → complex symbols.
  2. Normalise amplitude by the mean |real part|.
  3. For each polarity ±1: map to soft bits clip((1 − real·scale·pol)/2, 0, 1), run stdc_decode; return the first success.

The IQ round-trip test drives this with 5 Hz carrier offset, fractional-sample timing offset, 0.8 rad phase, and additive noise — decoded to the exact EGC text.


5. Validation

Test Asserts
test_scramble_involutive descramble(scramble(x)) = x
test_interleave_roundtrip 64-column interleave/de-interleave is exact (incl. padding)
test_egc_build_parse priority/LES/seq/text recovered
test_egc_checksum_rejects one flipped byte → {"error": "checksum"}
test_stdc_chain_clean encode → decode identity on the full frame
test_stdc_chain_noisy_offset 19-bit stream offset + 4 % random bit flips → exact text
test_stdc_bpsk_iq raw BPSK IQ with frequency/timing/phase offsets + noise → exact text (both BPSK polarities handled)

6. Limitations and interop caveats

  • TDM frame structure not yet implemented. A real STD-C carrier is a continuous sequence of fixed-length TDM frames (8.64 s, with frame counters and packet descriptors delimiting the multiplexed packets). This module decodes one UW-framed block of known payload size; carrier-following and packet demultiplexing are the next layer.
  • UW / interleaver constants need on-air confirmation (§2.5). The scrambler polynomial and the convolutional code are standard and shared with the validated CCSDS chain.
  • EGC layer is semantic, not byte-exact (§3).
  • Uplink (ship-to-shore) signalling is out of scope — this is a shore-to-ship watch receiver.

Related: LRPT (the same Viterbi core and BPSK/QPSK receiver lineage), NAVTEX (the MF sibling service EGC SafetyNET extends to satellite coverage), and the maths guide on convolutional codes and LFSR scrambling.