Skip to content

Latest commit

 

History

History
230 lines (165 loc) · 7.3 KB

File metadata and controls

230 lines (165 loc) · 7.3 KB

TM Synchronization and Channel Coding (TMSC)

The tmsc package implements the CCSDS 131.0-B-4 TM Synchronization and Channel Coding sublayer — the layer between the TM Data Link Protocol and the physical link that handles frame synchronization, pseudo-randomization, and forward error correction.

Quick Start

import "github.com/ravisuhag/astro/pkg/tmsc"

// Wrap a Transfer Frame into a CADU for transmission
cadu := tmsc.WrapCADU(encodedFrame, nil, true) // nil=default ASM, true=randomize

// Unwrap a received CADU back into a Transfer Frame
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)

// Reed-Solomon error correction
rs := tmsc.NewRS255_223()
codeword, _ := rs.Encode(data)
corrected, nerrs, _ := rs.Decode(codeword)

Architecture

The TMSC sublayer sits between the TM Data Link Protocol (tmdl) and the physical layer:

+-----------------------------------------+
|  TM Space Data Link Protocol (tmdl)     |
|  Packs data into Transfer Frames        |
+-----------------------------------------+
|  TM Sync & Channel Coding (tmsc)        |  <-- This package
|  ASM, pseudo-randomization, FEC         |
+-----------------------------------------+
|  Physical Layer (RF/Optical link)       |
+-----------------------------------------+

Attached Sync Marker (ASM)

The ASM is a known 4-byte bit pattern prepended to each Transfer Frame. The receiver uses it to find frame boundaries in the continuous bitstream.

// Get the standard CCSDS ASM (0x1ACFFC1D)
asm := tmsc.DefaultASM() // Returns []byte{0x1A, 0xCF, 0xFC, 0x1D}

The ASM was carefully chosen for its autocorrelation properties — it can be detected reliably even in the presence of noise. A fresh copy is returned each call to prevent accidental mutation.

CADU Wrapping and Unwrapping

A Channel Access Data Unit (CADU) is the combination of ASM + Transfer Frame data. This is the unit that is actually transmitted over the physical link.

+--------+------------------------+
|  ASM   |    Transfer Frame      |
| (4B)   |                        |
+--------+------------------------+
|<------------ CADU ------------->|

Wrapping (Send Path)

// Wrap with default ASM and pseudo-randomization
cadu := tmsc.WrapCADU(encodedFrame, nil, true)

// Wrap with default ASM, no randomization
cadu := tmsc.WrapCADU(encodedFrame, nil, false)

// Wrap with custom ASM
customASM := []byte{0xDE, 0xAD, 0xBE, 0xEF}
cadu := tmsc.WrapCADU(encodedFrame, customASM, true)

Unwrapping (Receive Path)

// Unwrap with default ASM and de-randomization
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)
if errors.Is(err, tmsc.ErrSyncMarkerMismatch) {
    // ASM not found at expected position
}

// Unwrap without de-randomization
frameData, err := tmsc.UnwrapCADU(cadu, nil, false)

Pseudo-Randomization

CCSDS pseudo-randomization ensures good signal properties by preventing long runs of identical bits that can confuse clock recovery. The Transfer Frame bytes are XORed with a pseudo-random noise (PN) sequence.

// Randomize data (XOR with PN sequence)
randomized := tmsc.Randomize(data)

// De-randomize (same operation — XOR is self-inverse)
original := tmsc.Randomize(randomized)

The PN sequence is generated by an 8-bit LFSR with polynomial h(x) = x^8 + x^7 + x^5 + x^3 + 1, initialized to all 1s (0xFF).

// Generate PN sequence of arbitrary length
pnSeq := tmsc.GeneratePNSequence(1024)

Important: The ASM is never randomized. Only the Transfer Frame content is XORed.

Reed-Solomon Error Correction

The package provides CCSDS Reed-Solomon codes over GF(2^8) with primitive polynomial 0x187 and first consecutive root (FCR) 112.

Available Codes

Code Parity Symbols Error Correction Use Case
RS(255,223) 32 Up to 16 errors Standard CCSDS coding
RS(255,239) 16 Up to 8 errors Lower overhead alternative

Basic Encoding and Decoding

// Create a codec
rs := tmsc.NewRS255_223() // or tmsc.NewRS255_239()

// Encode: data (223 bytes) -> codeword (255 bytes)
data := make([]byte, rs.DataLen()) // 223 bytes for RS(255,223)
codeword, err := rs.Encode(data)

// Decode: corrects errors in-place, returns corrected data
corrected, numErrors, err := rs.Decode(codeword)
if errors.Is(err, tmsc.ErrUncorrectable) {
    // Too many errors to correct
}
fmt.Printf("Corrected %d symbol errors\n", numErrors)

Interleaved Encoding and Decoding

CCSDS supports symbol interleaving to spread burst errors across multiple codewords, improving resilience against clustered bit errors.

Valid interleave depths: 1, 2, 3, 4, 5, 8.

rs := tmsc.NewRS255_223()
depth := 4

// Input must be exactly depth * DataLen() bytes
data := make([]byte, depth*rs.DataLen()) // 4 * 223 = 892 bytes
interleaved, err := rs.EncodeInterleaved(data, depth)
// Output: depth * 255 = 1020 bytes

// Decode interleaved data
corrected, totalErrors, err := rs.DecodeInterleaved(interleaved, depth)

How interleaving works:

  1. Input data is de-interleaved into depth separate blocks.
  2. Each block is independently RS-encoded to a 255-byte codeword.
  3. The codewords are interleaved byte-by-byte into the output.

On decode, the reverse is performed. This means a burst error affecting consecutive bytes in the interleaved stream is distributed across multiple codewords, where each codeword sees only a few symbol errors.

Codec Properties

rs := tmsc.NewRS255_223()
rs.NRoots()  // 32 — number of parity symbols
rs.DataLen() // 223 — data bytes per codeword

Full Pipeline Example

Send Path (Spacecraft to Ground)

import (
    "github.com/ravisuhag/astro/pkg/tmdl"
    "github.com/ravisuhag/astro/pkg/tmsc"
)

// 1. Get a Transfer Frame from the TM Data Link layer
frame, _ := pc.GetNextFrame()
encoded, _ := frame.Encode()

// 2. (Optional) Apply Reed-Solomon encoding
rs := tmsc.NewRS255_223()
// Pad encoded frame to RS data length if needed, or use interleaving

// 3. Wrap as CADU — randomize and prepend ASM
cadu := tmsc.WrapCADU(encoded, nil, true)

// 4. Transmit CADU over the physical link
transmit(cadu)

Receive Path (Ground Station)

// 1. Receive CADU from physical link
cadu := receive()

// 2. Unwrap CADU — strip ASM and de-randomize
frameData, err := tmsc.UnwrapCADU(cadu, nil, true)
if err != nil { /* handle sync errors */ }

// 3. (Optional) Apply Reed-Solomon decoding/correction

// 4. Decode the Transfer Frame
frame, err := tmdl.DecodeTMTransferFrame(frameData)
if err != nil { /* handle CRC errors */ }

Errors

All errors are exported package-level variables, suitable for use with errors.Is:

Error Meaning
ErrDataTooShort CADU too short to contain the ASM
ErrSyncMarkerMismatch CADU does not start with the expected ASM
ErrInvalidDataLength Data length does not match RS code parameters
ErrInvalidInterleaveDepth Unsupported interleaving depth (must be 1, 2, 3, 4, 5, or 8)
ErrUncorrectable Errors exceed RS correction capability

Reference