gr-apollo/grc/apollo_usb_downlink_receiver.block.yml
Ryan Malloy 0ee7ff0ad7 Implement full Apollo USB downlink decoder chain
Complete signal processing pipeline from complex baseband to decoded
PCM telemetry, verified against the 1965 NAA Study Guide (A-624):

Core demod (Phase 1):
  - PM demodulator with carrier PLL recovery
  - 1.024 MHz subcarrier extractor (bandpass + downconvert)
  - BPSK demodulator with Costas loop + symbol sync
  - Convenience hier_block2 combining subcarrier + BPSK

PCM frame processing (Phase 2):
  - 32-bit frame sync with Hamming distance correlator
  - SEARCH/VERIFY/LOCKED state machine, complement-on-odd handling
  - Frame demultiplexer (128-word, A/D voltage scaling)
  - AGC downlink decoder (15-bit word reassembly from DNTM1/DNTM2)

Voice and analog (Phase 3):
  - 1.25 MHz FM voice subcarrier demod to 8 kHz audio
  - SCO demodulator for 9 analog sensor channels (14.5-165 kHz)

Virtual AGC integration (Phase 4):
  - TCP bridge client with auto-reconnect and channel filtering
  - DSKY uplink encoder (VERB/NOUN/DATA command sequences)

Top-level receiver (Phase 5):
  - usb_downlink_receiver hier_block2: one block, complex in, PDUs out
  - 14 GRC block YAML definitions for GNU Radio Companion
  - Example scripts for signal analysis and full-chain demo

Infrastructure:
  - constants.py with all timing/frequency/frame parameters
  - protocol.py for sync word + AGC packet encode/decode
  - Synthetic USB signal generator for testing
  - 222 tests passing, ruff lint clean
2026-02-20 13:18:42 -07:00

93 lines
2.4 KiB
YAML

id: apollo_usb_downlink_receiver
label: Apollo USB Downlink Receiver
category: '[Apollo USB]'
flags: [python]
parameters:
- id: sample_rate
label: Sample Rate
dtype: float
default: '5120000'
- id: bit_rate
label: PCM Bit Rate
dtype: int
default: '51200'
options: ['51200', '1600']
option_labels: ['51.2 kbps (high rate)', '1.6 kbps (low rate)']
- id: carrier_pll_bw
label: Carrier PLL BW
dtype: float
default: '0.02'
- id: subcarrier_bw
label: Subcarrier BPF BW
dtype: float
default: '150000'
- id: bpsk_loop_bw
label: BPSK Loop BW
dtype: float
default: '0.045'
- id: max_bit_errors
label: Max Sync Bit Errors
dtype: int
default: '3'
- id: output_format
label: Output Format
dtype: string
default: 'raw'
options: ['raw', 'scaled', 'engineering']
inputs:
- label: in
domain: stream
dtype: complex
outputs:
- label: frames
domain: message
optional: true
- label: telemetry
domain: message
optional: true
- label: agc_data
domain: message
optional: true
- label: raw_frame
domain: message
optional: true
templates:
imports: from apollo.usb_downlink_receiver import usb_downlink_receiver
make: >
apollo.usb_downlink_receiver.usb_downlink_receiver(
sample_rate=${sample_rate},
bit_rate=${bit_rate},
carrier_pll_bw=${carrier_pll_bw},
subcarrier_bw=${subcarrier_bw},
bpsk_loop_bw=${bpsk_loop_bw},
max_bit_errors=${max_bit_errors},
output_format=${output_format})
documentation: |-
Apollo USB Downlink Receiver — complete demodulation chain in one block.
Combines PM demod, subcarrier extraction, BPSK demod, frame sync, and
demultiplexer. Input is complex baseband at 5.12 MHz, output is decoded
PCM telemetry on message ports.
Message output ports:
frames — complete 128-word frames as PDUs
telemetry — individual word values with channel metadata
agc_data — AGC channels 34/35/57 for downlink decoder
raw_frame — unprocessed frame bytes
Parameters:
sample_rate: Baseband sample rate (default 5.12 MHz)
bit_rate: PCM bit rate — 51200 (high) or 1600 (low)
carrier_pll_bw: PM carrier recovery loop bandwidth
subcarrier_bw: 1.024 MHz subcarrier bandpass width
bpsk_loop_bw: BPSK Costas loop bandwidth
max_bit_errors: Hamming distance threshold for sync word
output_format: "raw" (codes), "scaled" (voltage), "engineering"
file_format: 1