PCM Frame Structure
The PCM (Pulse Code Modulation) telemetry system converts analog sensor readings and digital status words from the spacecraft into a serial bit stream. This stream is organized into fixed-length frames, each beginning with a sync word that lets the ground station find the frame boundaries in the raw data. Understanding the frame structure is essential for interpreting anything the spacecraft sends.
Frame formats, sync word structure, and A/D converter specifications are from the NAA Telecommunication Systems Study Guide (Course A-624). AGC channel assignments are from the Virtual AGC project.
Frame layout
Section titled “Frame layout”Each high-rate frame contains exactly 128 eight-bit words, for a total of 1024 bits. The first four words (32 bits) are the sync word. The remaining 124 words carry telemetry data.
block-beta
columns 8
block:sync:4
s1["Word 1"] s2["Word 2"] s3["Word 3"] s4["Word 4"]
end
block:data:4
d1["Word 5"] d2["..."] d3["..."] d4["Word 128"]
end
style sync fill:#5c3a1a,stroke:#bd7a3a
style data fill:#1a3a5c,stroke:#3a7abd
At the high bit rate of 51,200 bps, each 1024-bit frame takes exactly 20 milliseconds to transmit. Fifty of these frames make up one subframe, which spans exactly one second.
The sync word
Section titled “The sync word”The 32-bit sync word is not a simple fixed pattern. It encodes four distinct fields:
block-beta
columns 32
block:a:5
a1["A field<br/>5 bits"]
end
block:core:15
c1["Fixed Core<br/>15 bits"]
end
block:b:6
b1["B field<br/>6 bits"]
end
block:fid:6
f1["Frame ID<br/>6 bits"]
end
style a fill:#2d5016,stroke:#4a8c2a
style core fill:#5c3a1a,stroke:#bd7a3a
style b fill:#2d5016,stroke:#4a8c2a
style fid fill:#1a3a5c,stroke:#3a7abd
| Field | Bits | Default Value | Purpose |
|---|---|---|---|
| A | 5 | 10101 | Patchboard-selectable identifier |
| Core | 15 | 111001101011100 | Fixed correlator pattern (complemented on odd frames) |
| B | 6 | 110100 | Patchboard-selectable identifier |
| Frame ID | 6 | 1-50 | Frame number within subframe |
The A and B fields were configurable via patchboard on the actual spacecraft hardware — they served as a mission identifier, letting the ground station distinguish between multiple spacecraft transmitting on similar frequencies. gr-apollo uses the default values from the study guide.
The Frame ID counts from 1 to 50 within each subframe. This is how the ground station knows which frame it is looking at within the one-second subframe cycle.
Complement-on-odd
Section titled “Complement-on-odd”The 15-bit fixed core is bitwise complemented on odd-numbered frames. On even frames (2, 4, 6, …, 50), the core bits are 111001101011100. On odd frames (1, 3, 5, …, 49), they become 000110010100011.
This alternation serves two purposes:
-
DC balance. If the core never changed, the sync word would have a persistent DC bias that could cause baseline wander in the NRZ bit stream. Alternating between the pattern and its complement ensures the long-term average is near zero.
-
Frame counting verification. The ground station can confirm it has not gained or lost a frame by checking whether the core matches the expected polarity for the current frame ID. If the polarity disagrees with the frame count, something has slipped.
Frame sync state machine
Section titled “Frame sync state machine”Finding frame boundaries in a continuous bit stream is a three-phase process. The FrameSyncEngine implements a state machine:
stateDiagram-v2
[*] --> SEARCH
SEARCH --> VERIFY : Sync match found<br/>(Hamming distance <= 3)
VERIFY --> LOCKED : N consecutive hits<br/>at frame boundaries
VERIFY --> SEARCH : Miss at expected boundary
LOCKED --> LOCKED : Hit at frame boundary
LOCKED --> SEARCH : M consecutive misses
note right of SEARCH
Sliding 32-bit window
checks every bit position
end note
note right of VERIFY
Candidate found,
waiting to confirm
at next frame boundary
end note
note right of LOCKED
Stable lock,
emitting frames
end note
SEARCH — The engine slides a 32-bit window across the incoming bits one bit at a time. At each position, it correlates the window contents against both the even and odd reference patterns (the 26 static bits — A + core + B). When the Hamming distance falls within the threshold, the engine has a candidate.
VERIFY — One match is not enough. Noise could produce a false trigger. The engine waits for the next frame boundary (1024 bits later at high rate) and checks whether another valid sync word appears there. After the configured number of consecutive hits at expected boundaries (default: 2), it transitions to LOCKED.
LOCKED — The engine is confident it has found the correct frame alignment. It emits complete frames as PDUs. If noise corrupts a sync word, the engine tolerates it and keeps going. Only after multiple consecutive misses at frame boundaries (default: 3) does it give up and return to SEARCH.
Why a 3-bit Hamming distance threshold?
Section titled “Why a 3-bit Hamming distance threshold?”The sync word has 26 static bits (the A, core, and B fields). The frame ID changes every frame, so the correlator ignores it. A random 26-bit sequence has an expected Hamming distance of 13 from any reference pattern. Allowing up to 3 bit errors gives a comfortable margin:
-
Probability of false trigger (random data matching within distance 3 of a 26-bit pattern): approximately 1 in 4,000. At 51,200 bits per second, this means a false trigger roughly every 80 milliseconds — which is why the VERIFY state exists. Two false triggers landing exactly 1024 bits apart is astronomically unlikely.
-
Probability of missed detection (a real sync word with more than 3 errors): at typical operating SNR, the bit error rate is well below 10^-3, making 4 or more errors in the 26 static bits extremely rare.
Data words
Section titled “Data words”The 124 data words (positions 5-128) carry three types of measurements:
Most data words are high-level analog measurements. The spacecraft’s A/D converter (the “coder”) samples 0-5V sensor outputs with 8-bit resolution.
The mapping is not quite what you would expect from a standard ADC:
| Code | Voltage | Meaning |
|---|---|---|
| 0 | — | Below range (error) |
| 1 | 0.00 V | Zero reference |
| 2 | 0.0197 V | First real step |
| 127 | 2.48 V | Midscale |
| 254 | 4.98 V | Full scale |
| 255 | > 5.0 V | Overflow |
The step size is 19.7 mV per LSB, calculated as 4.98V / 253 steps. Code 0 and code 255 are reserved as boundary indicators, leaving 253 actual measurement levels from code 1 to code 254.
Some spacecraft sensors produce signals in the 0-40 mV range (thermocouples, strain gauges). These are amplified by a factor of 125 before reaching the A/D converter, so a 40 mV input produces a full-scale 5V signal at the coder input.
The telemetry system does not mark which words are low-level — that is determined by the patchboard configuration and known a priori from the telemetry assignment list. When processing low-level channels, divide the recovered voltage by 125 to get the actual sensor voltage.
Several word positions carry digital status bits rather than analog measurements. These come from two sources:
- Parallel digital inputs — 8-bit status registers read directly into frame positions
- Serial digital inputs — shift-register data clocked in by the PCM system
The most important digital words for gr-apollo are at positions 34, 35, and 57, which carry AGC downlink telemetry data. These three positions are the pipeline through which the Apollo Guidance Computer’s internal state reaches the ground.
AGC telemetry channels
Section titled “AGC telemetry channels”Three word positions within each frame have special significance for computer telemetry:
| Word Position | AGC Channel | Octal | Role |
|---|---|---|---|
| 34 | DNTM1 | 034 | Telemetry word high byte (bits 14-8) |
| 35 | DNTM2 | 035 | Telemetry word low byte (bits 7-0) |
| 57 | OUTLINK | 057 | Additional digital downlink data |
The Apollo Guidance Computer uses 15-bit words internally. Since the PCM system works in 8-bit bytes, each AGC word is split across two consecutive frame positions. Word 34 carries the upper 7 bits (bits 14 through 8) in its lower 7 bits. Word 35 carries the lower 8 bits (bits 7 through 0) directly.
Reassembly is straightforward:
agc_word = ((dntm1_byte & 0x7F) << 8) | dntm2_byteAt 50 frames per second, this means 50 AGC words per second arrive through the telemetry channel. The AGC buffers 400 words into each downlink list snapshot (taking about 8 seconds at high rate), then transmits the buffer contents as a coherent block of navigation state, autopilot settings, or other mission-phase-specific data.
High rate vs. low rate
Section titled “High rate vs. low rate”The PCM system supports two bit rates, selectable by ground command. The choice affects frame size, frame rate, and the amount of data per second:
| Parameter | High Rate | Low Rate |
|---|---|---|
| Bit rate | 51,200 bps | 1,600 bps |
| Clock divider | 512 kHz / 10 | 512 kHz / 320 |
| Words per frame | 128 | 200 |
| Frames per second | 50 | 1 |
| Words per second | 6,400 | 200 |
| Subframe period | 1 second (50 frames) | N/A |
| Bits per frame | 1,024 | 1,600 |
| Frame period | 20 ms | 1 second |
Low rate was used during translunar coast and other quiet phases where the Deep Space Network antenna time was shared between missions. High rate was used during critical mission phases — launch, lunar orbit insertion, powered descent, EVA — where dense telemetry coverage was essential.
Subframe structure
Section titled “Subframe structure”At high rate, 50 consecutive frames form one subframe spanning exactly one second. The subframe concept matters because some telemetry measurements are commutated — they appear in different word positions across different frames within the subframe.
For example, a temperature sensor might be assigned to word position 72 in frame 3 of each subframe, while a pressure sensor occupies word 72 in frame 4. The same word position carries different physical measurements depending on which frame within the subframe you are looking at.
The frame ID field in the sync word (values 1 through 50) tells you which frame you are in, enabling the ground station software to route each word to the correct telemetry parameter.
graph LR
subgraph Subframe ["Subframe (1 second)"]
F1["Frame 1<br/>ID=1, odd"] --> F2["Frame 2<br/>ID=2, even"]
F2 --> F3["Frame 3<br/>ID=3, odd"]
F3 --> F4["..."]
F4 --> F50["Frame 50<br/>ID=50, even"]
end
style Subframe fill:#1a1a2e,stroke:#3a7abd
style F1 fill:#5c3a1a,stroke:#bd7a3a
style F2 fill:#1a3a5c,stroke:#3a7abd
style F3 fill:#5c3a1a,stroke:#bd7a3a
style F50 fill:#1a3a5c,stroke:#3a7abd
The alternating colors reflect the complement-on-odd behavior of the sync core: odd frames (1, 3, 5, …) use the complemented pattern, even frames (2, 4, 6, …) use the normal pattern.