7.4 KiB
7.4 KiB
CLAUDE.md
This file provides guidance to Claude Code when working with gr-apollo.
Project Overview
GNU Radio 3.10+ out-of-tree (OOT) module for decoding Apollo Unified S-Band (USB) telecommunications signals. Based on the 1965 NAA Telecommunication Systems Study Guide (Course A-624) and Virtual AGC project.
Target signals:
- Downlink: 2287.5 MHz (spacecraft → ground)
- Uplink: 2106.40625 MHz (ground → spacecraft)
- Coherent ratio: 240/221 (Tx = Rx × 240/221)
Repository Structure
gr-apollo/
├── src/apollo/ # GNU Radio Python blocks (src-layout)
│ ├── pm_demod.py # PM demodulator (0.133 rad peak)
│ ├── bpsk_subcarrier_demod.py # 1.024 MHz BPSK subcarrier
│ ├── pcm_frame_sync.py # 32-bit sync, 128-word frames
│ ├── pcm_demux.py # Frame demultiplexer
│ └── voice_subcarrier_demod.py # 1.25 MHz FM voice
├── grc/ # GRC block YAML definitions
├── docs/ # Reference documentation
├── examples/ # Example flowgraphs
├── pyproject.toml # Python package configuration
└── README.md
Development Commands
# Install in development mode
uv pip install -e .
# Install GRC block definitions
cp grc/*.yml ~/.local/share/gnuradio/grc/blocks/
# Test with gr-mcp (if available)
# Use protocol analysis tools to generate decoder chain
Signal Architecture
Downlink Signal Chain (2287.5 MHz)
RF Input → Carrier PLL → PM Demod → Subcarrier Separation
│
┌───────────────────────┼───────────────────────┐
↓ ↓ ↓
1.024 MHz BPSK 1.25 MHz FM Ranging
(PCM telemetry) (Voice) (PRN code)
↓ ↓
Symbol Sync FM Discriminator
↓ ↓
51.2 kbps NRZ 300-3000 Hz audio
↓
Frame Sync (32-bit)
↓
128-word demux
Key Parameters
| Parameter | Value | Notes |
|---|---|---|
| Downlink frequency | 2287.5 MHz | Coherent with uplink |
| PM peak deviation | 0.133 rad (7.6°) | Phase modulation |
| PCM subcarrier | 1.024 MHz | BPSK modulated |
| PCM bit rate | 51.2 kbps (high) / 1.6 kbps (low) | NRZ, MSB first |
| Voice subcarrier | 1.25 MHz | FM, ±29 kHz deviation |
| Frame length | 128 words × 8 bits | 50 fps high rate |
| Frame sync | 32-bit pattern | Complements on odd frames |
| Master clock | 512 kHz | All timing derived from this |
PCM Frame Structure
┌─────────────────────────────────────────────────────────────┐
│ Frame Sync (32 bits = 4 words) │
│ [5-bit A][15-bit core][6-bit B][6-bit frame ID] │
├─────────────────────────────────────────────────────────────┤
│ Data Words 5-128 (124 words) │
│ - High-level analog (0-5V, 8-bit) │
│ - Low-level analog (0-40mV, 8-bit with ×125 gain) │
│ - Digital parallel/serial inputs │
│ - AGC downlink data (channels 34, 35, 57) │
└─────────────────────────────────────────────────────────────┘
50 frames = 1 subframe (1 second at high rate)
Subcarrier Oscillators (FM Mode)
| SCO | Center Freq | Deviation | Use |
|---|---|---|---|
| 1 | 14,500 Hz | ±7.5% | Analog sensor |
| 2 | 22,000 Hz | ±7.5% | Analog sensor |
| 3 | 30,000 Hz | ±7.5% | Analog sensor |
| 4 | 40,000 Hz | ±7.5% | Analog sensor |
| 5 | 52,500 Hz | ±7.5% | Analog sensor |
| 6 | 70,000 Hz | ±7.5% | Analog sensor |
| 7 | 95,000 Hz | ±7.5% | Analog sensor |
| 8 | 125,000 Hz | ±7.5% | Analog sensor |
| 9 | 165,000 Hz | ±7.5% | Analog sensor |
GNU Radio Blocks to Implement
Phase 1: Core Demodulation
| Block | Type | I/O | Description |
|---|---|---|---|
pm_demod |
gr.sync_block |
complex→float | PM demodulator with carrier recovery |
subcarrier_extract |
gr.sync_block |
float→complex | Bandpass + downconvert subcarrier |
bpsk_demod |
gr.sync_block |
complex→byte | BPSK demodulation with symbol sync |
Phase 2: PCM Processing
| Block | Type | I/O | Description |
|---|---|---|---|
pcm_frame_sync |
gr.basic_block |
byte→PDU | 32-bit sync detection, frame extraction |
pcm_demux |
gr.basic_block |
PDU→PDU | Demultiplex 128-word frames by word position |
downlink_decoder |
gr.basic_block |
PDU→dict | Interpret AGC telemetry lists |
Phase 3: Voice & Analog
| Block | Type | I/O | Description |
|---|---|---|---|
fm_voice_demod |
gr.sync_block |
complex→float | 1.25 MHz FM subcarrier → audio |
sco_demod |
gr.sync_block |
float→float | FM SCO demodulator (configurable) |
Virtual AGC Integration
The Virtual AGC emulator communicates via TCP socket (port 19697+):
4-byte packet format:
Byte 0: [Channel bits 8-4][0x00]
Byte 1: [0x40 | Channel bits 3-1][Value bits 14-12]
Byte 2: [0x80 | Value bits 11-6]
Byte 3: [0xC0 | Value bits 5-0]
Key telecom channels:
- Ch 45 (INLINK): Uplink data input
- Ch 57 (OUTLINK): Downlink data output
- Ch 34/35 (DNTM1/2): Telemetry word stream
References
Code Style
- Python: Follow GNU Radio block patterns (numpy for DSP)
- Use gr-mcp protocol analysis tools for decoder chain generation
- Test blocks in Docker before integration
Docs Site Deployment
Starlight documentation site in docs/ subdirectory.
- Production: https://gr-apollo.warehack.ing
- Local dev: Set
DOMAIN=gr-apollo.l.warehack.ingindocs/.env - Git:
git@git.supported.systems:warehack.ing/gr-apollo.git - Server:
ssh -A warehack-ing@warehack.ing, repo at~/gr-apollo
Environment
Copy .env.example to .env and set:
COMPOSE_PROJECT=gr-apollo-docs
DOMAIN=gr-apollo.warehack.ing
Commands
# From docs/ directory:
make up # Production — Caddy serves static dist/
make dev # Development — Astro dev server with HMR
make down # Stop all containers
make logs # Tail container logs
Deploy to Production
# One-liner from local machine
ssh -A warehack-ing@warehack.ing "cd ~/gr-apollo && git pull && cd docs && make up"
Notes
- Uses Docker Compose profiles (
prod/dev) - Playwright + Chromium installed in build stage for mermaid diagram rendering
- caddy-docker-proxy on external
caddynetwork handles TLS automatically