Field Guide · algorithm

Also known as: P25 RS codes, RS(24,12,13), RS(36,20,17), GF(64) Reed-Solomon

The P25 Reed-Solomon codes are three shortened Reed-Solomon codes over the finite field GF(2⁶) that TIA-102.BAAA-A §5.9 uses as the outer FEC on P25’s most valuable fields.1 They protect the Link Control word, the Encryption Sync, and the Header Data Unit — sitting on top of an inner Hamming/Golay layer to correct the residual symbol errors that survive it. GopherTrunk decodes all three with the classic pipeline: Berlekamp-Massey for the error-locator polynomial, a Chien search for the error positions, and Forney’s algorithm for the magnitudes.2

K info symbols (systematic) R = N−K parity symbols each symbol = one 6-bit GF(2⁶) element · corrects up to t = R/2 symbol errors syndromes Berlekamp-Massey Chien Forney
All three P25 RS codes are systematic and shortened: K information symbols followed by R parity symbols over GF(2⁶), corrected by the syndrome → Berlekamp-Massey → Chien → Forney chain.

The three codes

Each code is shortened from the natural RS(63, K, D) form by deleting leading information symbols, and all three share one field: GF(2⁶) generated by the primitive polynomial α⁶ + α + 1. Elements are 6-bit values where bit i is the α^i coefficient, α is 0b000010, and since α⁶³ = 1 a log/exp table makes multiplication and inversion single lookups. The three codes differ only in dimensions and role:

Code K N D t Role in P25
RS(24,12,13) 12 24 13 6 Link Control word (LCW); Phase 2 SACCH outer FEC
RS(24,16,9) 16 24 9 4 Encryption Sync (MI + ALGID + KID); Phase 2 FACCH
RS(36,20,17) 20 36 17 8 Header Data Unit (HDU)

Encoding is systematic: the K information symbols pass through verbatim, and the R parity symbols are the information vector times the right-hand parity columns of the spec’s generator matrix. GopherTrunk stores those matrices directly from §5.9 in the octal form the spec prints:

// TIA-102.BAAA-A §5.9 "GLC matrix", from internal/radio/framing/rs_gf64.go
// Right-hand 12×12 parity sub-matrix for RS(24,12,13); octal = 6-bit GF(2⁶) elems.
var rsParity24_12 = [12][12]byte{
    {0o62, 0o44, 0o03, 0o25, 0o14, 0o16, 0o27, 0o03, 0o53, 0o04, 0o36, 0o47},
    // … 11 more rows (GES and PHDR matrices likewise) …
}

How the decode works

The decoder treats the received codeword as a polynomial and evaluates it at the generator’s roots α¹…α^R to get R syndromes — all zero means the word is already valid. Berlekamp-Massey synthesises the shortest LFSR (the error-locator polynomial Λ) that generates the syndrome sequence; if its degree exceeds t = R/2 the word is uncorrectable and returned as such. A Chien search evaluates Λ across the field to find the error positions, and Forney’s formula computes each error magnitude from the error-evaluator and the formal derivative of Λ. GopherTrunk then re-computes the syndromes on the corrected word as a defensive check, so a genuine >t error pattern that happens to yield a low-degree locator is rejected rather than returned as a plausible-but-wrong codeword.

Relevance to SDR

internal/radio/framing/rs_gf64.go builds the GF(2⁶) field once at init and exposes EncodeRS…, VerifyRS…, and DecodeRS… for all three codes. These are what turn a marginally decoded voice frame into a trustworthy one: after the inner Hamming(10,6,3) layer fixes single-bit errors, the RS layer corrects whole symbols the Hamming pass missed — without it, residual bit errors corrupt the talkgroup and source in a Link Control word under low SNR, ending calls early. The same GF(2⁶) codes are reused by P25 Phase 2 as the outer FEC over its SACCH/FACCH channels.

Sources

  1. Reed-Solomon error correction — Wikipedia, on the symbol-oriented block codes P25 uses over GF(2⁶). 

  2. Berlekamp-Massey algorithm — Wikipedia, on the error-locator synthesis at the heart of the decoder. 

See also