All docsStellar LinkRF bench · by Stellar Systems v0.1.0

Radio Concepts

Modulation & Coding

The modulations the modem implements, the CCSDS framing and coding chain, frame lengths, the scrambler, preamble and fill, and CCSDS transfer frames.

This page describes what happens to your bytes between the moment they enter the modem and the moment they come out of the receiver, and which profile fields control each step. The register level detail is in Transmitter Chain and Receiver Chain.

Modulations#

phy.modulationStatusNotes
BPSKImplementedOne bit per symbol
QPSKImplementedTwo bits per symbol; the reference configuration of the bench
GMSKImplemented, approximatedphy.bt is required and must be 0.5. See the note below
OQPSKRefusedNo half-symbol offset path exists in the fabric; it would transmit plain QPSK
MSKRefusedWould transmit GMSK (BT 0.5) instead
π/4-DQPSKRefusedNeither the differential encoding nor the π/4 rotation exists
FSK, GFSKRefusedNo FSK path; phy.freq_deviation_hz reaches no register

A refused modulation fails the profile apply with a message saying why. All modulations run at 4 samples per symbol. BPSK and QPSK use root-raised-cosine shaping (α = 0.35) and Gray mapping; the receiver is coherent (Costas carrier loop, Gardner timing recovery).

The transmit and receive chains#

text
TX:  bytes -> framer -> fec_tx -> scrambler -> asm_insert -> tx_fill -> modulator -> DUC
RX:  DDC -> AGC -> matched filter -> timing -> carrier -> slicer -> demod
         -> deframer (find ASM, un-rotate, descramble) -> fec_rx -> bytes

The two chains are not mirror images, and the placement follows CCSDS 131.0-B:

  • the attached sync marker is added after coding, so the receiver can find frames before it decodes them;
  • the scrambler works on the coded stream, just before the marker, and the marker itself is never scrambled;
  • on receive, the deframer sits before the FEC decoder: it delimits frames and descrambles on the coded stream.

Frames and frame lengths#

The framer cuts the transmit byte stream into frames of FRAME_LEN bytes, taken from framing.mtu_bytes (default 256 when absent). Because every code expands the frame and the deframer counts coded bytes, the two ends are programmed with different lengths:

framing.fec.typeFramer FRAME_LENDeframer FRAME_LENConstraint
nonemtu_bytesmtu_bytes—
conv (K=7, r=1/2)mtu_bytes2 × mtu_bytes—
rs (RS(255,223))223255mtu_bytes must be 223
rs+conv223510mtu_bytes must be 223

The profile manager computes both values; you only set mtu_bytes.

Packet boundaries do not survive by default. The framer pads a short frame only when the DMA signals the end of a block, which happens once per 4096-byte block, not per packet. Otherwise it closes frames on the byte count alone, so what comes back is your byte stream re-cut at FRAME_LEN. To keep one packet per frame, send packets in fixed slots of FRAME_LEN bytes (see Datapath and Transmission). Slots only stay aligned when FRAME_LEN divides 4096: 1024, 512, 256, 128, 64 or 16 work, 223 does not, so slot framing is not available with Reed-Solomon.

Attached sync marker (ASM)#

framing.sync_word.value_hex sets the 32-bit marker (the CCSDS value is 1ACFFC1D). The same value is written to the transmitter and the receiver.

  • No sync_word, no marker. A profile without sync_word transmits raw frames with no marker, and the receiver cannot lock onto anything: such a profile is transmit-only (the raw_tx profile is one, used to put a known signal on a spectrum analyser).
  • Phase ambiguity is resolved in the receiver. A QPSK carrier loop can lock on any of four phases (BPSK and GMSK: two). The deframer searches the marker under every rotation the modulation allows, latches the one that matched, and un-rotates the payload. The matched rotation is readable in rx_demod.deframer.status bits [4:3] (0, 90, 180 or 270 degrees).
  • One wrong bit is tolerated. A marker with exactly one wrong bit out of 32 is accepted and the frame delivered; these soft matches are counted separately (ERR_CNT) and give a pre-FEC bit error estimate (ber_asm). A marker with two wrong bits is not matched and the frame is lost.

Scrambler#

The CCSDS pseudo-randomiser, polynomial x^8+x^7+x^5+x^3+1, byte-wise, applied to the coded stream before the marker.

YAML
framing:
  scrambler:
    enabled: true
    seed: 0xFF        # optional, 8 bits, default 0xFF (all ones, the CCSDS preset)

The same register value (enable in bit 0, seed in bits [15:8]) is written to both ends, so the transmitter and receiver cannot disagree. scrambler.polynomial is descriptive: the polynomial is fixed in the fabric.

Forward error correction#

YAML
framing:
  fec:
    type: "rs+conv"     # none | conv | rs | rs+conv
    rate: "223/255"     # required when type is not none; informative
typeEncoder (TX)Decoder (RX)
nonebypassedbypassed
convconvolutional K=7, r=1/2, G1=171₈, G2=133₈ (bit-exact CCSDS)Viterbi
rsReed-Solomon (255,223), GF(2⁸) polynomial 0x187Berlekamp-Massey, Chien/Forney
rs+convRS outer, convolutional inner (the CCSDS 131.0-B concatenation)Viterbi, then RS
ldpc, turbo, polarnot implemented — the chain is configured as uncoded—

Points to know:

  • The Reed-Solomon implementation uses the conventional basis, not the CCSDS dual basis. Its correcting power is the same, but interoperability with a third-party CCSDS RS decoder or encoder is not guaranteed.
  • fec.rate must be present when coding is enabled, but it does not select anything: the code type does.
  • framing.interleaver is descriptive; there is no interleaver in the datapath.
  • The receiver counts corrected bytes and uncorrectable codewords (fec_rx.CORR_CNT, FAIL_CNT). An uncorrectable codeword is still delivered, errors included.

Preamble and inter-frame fill#

After a silence, the receiver's AGC, timing loop and carrier loop start cold; between frames, a modulator with nothing to send would simply stop and let the loops drift. The tx_fill block solves both:

  • a preamble of pre_symbols symbols is sent before a frame that follows a silence;
  • up to post_symbols symbols of fill are sent between frames.

Fill is inserted only at frame boundaries, after the marker insertion, so it is never scrambled or coded and never appears inside a frame.

YAML
framing:
  preamble:
    type: "fill"          # "fill" (built-in pattern) or "pattern" (your own value_hex)
    # value_hex: "727252D02A1FEDD8"   # optional for fill, required for pattern
    pre_symbols: 512      # default 512
    post_symbols: 2048    # default 2048; 0 is refused
FieldMeaning
typefill uses the built-in 64-bit pattern 0x727252D02A1FEDD8 unless value_hex is given; pattern requires value_hex
value_hex64-bit pattern, 16 hex digits read MSB first; 8 digits are repeated to fill 64 bits
pre_symbolsPreamble length before a frame that follows silence. The measured threshold on the PL loopback is 161 to 192 symbols; 512 gives margin (about 26 ms at 19 531 baud)
post_symbolsMaximum fill between two frames. It must be bounded: the profile sequencer commits only after 64 clocks with no TX sample, so an endless fill would block every later profile apply and channel change

Every pattern is checked before it is written: it must stay at least 8 bits away from every image of the sync word the deframer searches (the deframer accepts 1 wrong bit), and its mean must stay below a quarter of full scale (a biased pattern is a carrier). A profile without framing.preamble disables the fill.

CCSDS transfer frames#

framing.transfer_frame adds a CCSDS Space Data Link layer on the PS side. It has no register behind it: satlinkd's link service wraps each message in a transfer frame before handing the octets to the modem, and locates frames again in the received stream.

YAML
framing:
  mtu_bytes: 1024          # the transfer frame IS the PL frame
  transfer_frame:
    type: "tm"             # tm (132.0-B), aos (732.0-B) or uslp (732.1-B)
    scid: 0x0AB            # 10 bits for TM, 8 for AOS, 16 for USLP
    vcid: 1                # 3 bits for TM, 6 for AOS and USLP
    fecf: true             # CRC-16 Frame Error Control Field, default true

Rules checked at apply:

  • mtu_bytes is required and must divide 4096 (1024, 512, 256, 128, 64 work; the common mission length 1115 does not);
  • the SCID and VCID must fit the field widths of the chosen frame type;
  • transfer frames cannot be combined with rs or rs+conv (223 does not divide 4096). Use none or conv and let the FECF carry the error detection.

Received frames are published on the link service with framing: "transfer_frame" and a quality verdict: good (FECF checks), erred (FECF fails; the payload is still delivered) or undetermined (no FECF, or no verdict possible). A message larger than one frame is refused, not segmented. The CCSDS layers left out (SDLS, COP-1, LDPC and turbo codes, AOS header error control) are listed in Known Limitations.

Encoding and other descriptive fields#

phy.encoding (nrz, nrzi, …) is descriptive: line coding is not implemented, and the receiver resolves phase ambiguity by searching marker rotations instead of by differential coding. See RF Profiles for the complete list of fields and which of them reach the hardware.

Stellar Link · v0.1.0

↑↓ to moveEnter to open