Signals / SDR / Field Reference

Satellite Signal Decode: From IQ to Frames

raw iq → telemetry ccsds / dsn lineage The path from a recorded baseband file to decoded spacecraft telemetry is a fixed pipeline: demodulate the carrier, recover symbols, undo the channel coding, find the frames. Each stage has a small set of knobs, and a failure at one stage has a recognizable signature in the next. This is the working reference for that pipeline, with the Dwingeloo Tianwen-2 X-band capture as the running example.

7
pipeline stages
r=1/2
typical inner code
255,223
classic RS outer
0x1ACFFC1D
ccsds asm

The pipeline, end to end

Every coherent digital downlink decodes along the same spine. Read it top to bottom; each stage consumes the output of the one above. The failure mode that matters most is the silent one: a stage that locks while the next refuses to sync, which always means the break is downstream of where it looks.

IQ fileci16/cf32 carrierPLL / costas symbolsTED / clock viterbiinner FEC ASM sync+ derand RS decodeouter FEC framesCADU / packets DEMOD FEC + FRAMING if a stage locks but the next will not sync, the fault is downstream of the locked stage
fig 1. the decode spine. demod recovers bits; FEC and framing turn bits into trusted frames.

Stage 1 · Know your IQ file

Before any DSP, read the container. A baseband recording is just interleaved samples, and getting the sample format wrong produces noise that looks plausibly like a weak signal. SigMF files carry the answer in a sidecar JSON; trust it over the filename. The three numbers you must have before touching anything: sample rate, datatype, and center frequency.

# ci16_le: interleaved int16 I,Q little-endian, 4 bytes/sample raw = np.fromfile(path, dtype="<i2") iq = (raw[0::2] + 1j*raw[1::2]).astype(np.complex64) / 32768.0 # cf32: already complex float, just view it iq = np.fromfile(path, dtype=np.complex64)
  • Nyquist check: the recorded bandwidth is the sample rate. A 2 Msps file holds plus or minus 1 MHz around the center. If your signal is wider, it is clipped and no decode will be clean.
  • Sanity FFT first: plot the power spectrum before anything else. You are looking for the carrier, the symmetric data sidebands, and where they sit relative to DC.

Stage 2 · Identify the modulation

The spectrum tells you most of it. A sharp spike with symmetric humps either side is residual-carrier PM, the deep-space default: most power parked in the carrier for tracking, data riding a subcarrier on the shoulders. No central spike, just a hump, means suppressed-carrier PSK where all power is in the data. The constellation after coarse lock confirms the order: two blobs is BPSK, four is QPSK.

spectrum signaturelikely modulationrecover with
sharp central spike + symmetric sidebandsresidual-carrier PCM/PSK/PMPLL on carrier, then subcarrier costas
single smooth hump, no spikesuppressed-carrier BPSK/QPSKcostas loop
two humps, constant envelopeFSK / GFSKquadrature demod
flat-topped wideband blockOQPSK / high-rate, or oversampledpoly-phase clock sync

Stage 3 · Recover carrier and symbols

Two loops, in order. First lock the carrier: an FFT-peak estimate de-rotates the bulk of the offset, a PLL or Costas loop tracks the rest. For residual-carrier signals you then mix down to the subcarrier and Costas-lock that. Second, recover symbol timing with a timing error detector (Gardner is the workhorse) so you sample at the eye center. BPSK Costas recovery costs you absolute phase, which is why a 180 degree ambiguity follows you into the decoder.

Stage 4 · Undo the inner code

Most coherent downlinks wrap the data in a convolutional code, decoded by a Viterbi decoder. The CCSDS baseline is rate 1/2, constraint length 7, polynomials 0o171 and 0o133. Viterbi will report a lock state and a bit error rate. A synced Viterbi at low BER means your demod is good. This is the most important diagnostic in the whole chain: if Viterbi locks but frames never appear, stop touching the demod. The fault is in framing or the outer code.

Stage 5 · Find the frames

Decoded bits are a continuous stream. Framing finds structure in it. A correlator slides along looking for the attached sync marker, the known 32-bit pattern 0x1ACFFC1D for CCSDS. Once locked, the stream is sliced into fixed-length frames, the pseudo-randomizer is reversed, and the Reed-Solomon outer code corrects residual errors. This is where Chinese-lineage probes bite you: they often use RS in the conventional basis, not the CCSDS-default dual basis, and they interleave several codewords per frame. A generic CCSDS deframer with the wrong basis or depth correlates the ASM fine and then fails every RS codeword, which presents as permanent deframer NOSYNC.

Stage 6 · Parse the telemetry

Corrected frames are transfer frames carrying space packets on virtual channels. Split by APID, watch lengths, and start charting channels over time. Oscillating values are often attitude or spin. A slow exponential decay is usually a thermal control loop. Float32 fields that are not unit-norm are probably not quaternions. Without a secondary header there is no per-packet timestamp, so the frame counter is your clock.

The NOSYNC decision tree

The single most common failure once you have signal. Work it in this order; each step is cheap to test and the order is by probability.

  1. Viterbi not syncing? The problem is upstream, in demod. Check subcarrier frequency, symbol rate, and that you are actually locked to the carrier. demod fault
  2. Viterbi synced, deframer NOSYNC? The demod is fine. Everything below is framing or outer FEC. framing fault
  3. Sweep RS interleave depth. Wrong depth means the deinterleaver scrambles every codeword. Try the documented depth, then 1, 4, 5. most likely
  4. Toggle RS basis. Conventional vs dual. Chinese probes use conventional; generic decoders default to dual. very likely
  5. Confirm frame length and ASM. A wrong frame size desyncs immediately after the first marker. check
  6. Try both symbol polarities. The 180 degree BPSK ambiguity. Run normal and bit-inverted deframers in parallel. cheap
  7. Toggle the derandomizer. If it is off when it should be on, RS sees garbage. cheap

Worked example · Tianwen-2 X-band

The Dwingeloo 25 m dish recorded Tianwen-2 on its 8428.190 MHz downlink. Live SatDump showed Viterbi SYNCED at BER 0.0049 but the deframer stuck at NOSYNC. By the decision tree above, the demod was fine and the fault was framing. The fix was the RS configuration, confirmed against a published decode of the same recordings.

parametervaluenote
center / rate8428.190 MHz / 2 Mspsci16_le SigMF
modulationresidual-carrier PM, BPSK on subcarrier65536 Hz subcarrier
symbol rate16384 baud
inner codeconv r=1/2, K=7 (0o171/0o133)Viterbi
outer codeRS(255,223) conventional, interleave 4NOT dual basis
frame892 bytes, 1.000 s, AOS, VC1, SCID 0xED4 x 223
scramblerCCSDS pseudo-randomizer ON

The two knobs that resolved NOSYNC were interleave depth 4 and conventional basis, exactly steps 3 and 4 of the tree.

Tooling map

SatDump
gui / offline
prebuilt pipelines for most spacecraft. fastest path when a matching pipeline exists. the residual-carrier PM + CCSDS concatenated chain is built in.
gr-satellites
gnu radio
Estevez. deframers with the basis and interleave knobs exposed. has handled Tianwen lineage before. the right tool when SatDump will not lock.
GNU Radio
flowgraph
build the chain block by block when nothing prebuilt fits. full control over every loop.
inspectrum
visual
eyeball the subcarrier, measure symbol rate off the waterfall, find bursts before committing to a decode config.
numpy / python
scratch
load IQ, FFT, prototype carrier removal. good for the front-end learning exercise. do not hand-roll Viterbi or RS, reuse a library.
SigMF tools
metadata
parse the sidecar so sample rate, datatype, and frequency come from the recording, not a guess.

References

ccsds 131TM Synchronization and Channel CodingRS, convolutional, ASM, randomizer specs
decodeDecoding Tianwen-2Estevez, the worked-example parameters
timestampTianwen-2 telemetry updateinsert-zone epoch
toolgr-satellitesdeframer with basis / interleave knobs
toolSatDumpprebuilt decode pipelines
dataCAMRAS raw archivethe Dwingeloo IQ recordings, CC-BY 4.0
specSigMFsignal metadata format