# Project Plan - fm-rds-tx

## 1. Mission

Create a Go-based UKW/FM stereo transmitter with RDS that can run on Windows, Linux, and, where feasible, on Raspberry Pi / SBC-class hardware.

Primary design goals:
- reliable CPU implementation first
- Windows-first bring-up and development ergonomics
- clean architecture for real-time DSP
- optional CUDA path for selected heavy DSP blocks
- practical control interfaces for audio, RDS, frequency, and TX settings
- portability across Windows x86_64, Linux x86_64, and ARM Linux

---

## 2. Non-negotiable constraints

### Legal / operational
- Use only inside the licensed event window and within the license conditions.
- No assumption that software-only limiting of TX power is sufficient; real RF power control depends on hardware.
- Emissions, pilot level, deviation, RDS injection, harmonics/spurs, and filtering must be measured on real equipment.
- The software must support safe defaults and explicit operator confirmation for potentially risky RF settings.

### Technical
- Go as the primary implementation language.
- Windows is the initial bring-up target.
- Cross-platform portability must be preserved from day one.
- Raspberry Pi / ARM compatibility must be preserved for the CPU path.
- CUDA is optional and must be runtime-detectable, never mandatory.

---

## 3. High-level architecture

```text
Audio In  ─┐
           ├─> audio preprocessing ─> stereo encoder ─┐
RDS In   ──┘                                          ├─> MPX generator ─> output backend ─> exciter / SDR / DAC
                                                      │
Config/API/CLI ───────────────────────────────────────┘
```

Core components:
1. **Audio ingest**
   - file / playlist input
   - live PCM input
   - optional network audio input later
2. **Audio preprocessing**
   - sample-rate conversion
   - gain staging
   - limiter / clipper (careful, broadcast chain quality matters)
   - optional pre-emphasis
3. **Stereo encoder**
   - L+R baseband
   - 19 kHz pilot
   - L-R double-sideband suppressed-carrier at 38 kHz
4. **RDS encoder**
   - PS, RT, PI, PTY, TA/TP basics
   - group scheduler
   - 57 kHz subcarrier insertion
5. **MPX generator**
   - combine mono/stereo + pilot + RDS
   - deviation / injection calibration hooks
6. **Output backend**
   - IQ output for SDR-based transmit chain
   - composite/MPX output if supported by hardware
   - test file output for offline analysis
7. **Control plane**
   - config file
   - CLI
   - HTTP API
   - optional small web UI later

---

## 4. Proposed phased roadmap

## Phase 0 - Research & requirements freeze

Deliverables:
- supported hardware/backend shortlist
- target sample rates and timing model
- legal/operational assumption document
- MVP feature freeze

Tasks:
- decide primary output mode:
  - SDR IQ output
  - direct MPX/composite output
  - both
- freeze first backend direction:
  - SoapySDR as preferred abstraction for hardware flexibility
  - optional vendor-native backend later if required for performance/features
- shortlist hardware targets:
  - Windows PC + SDR
  - Linux PC + SDR
  - Raspberry Pi 4/5 + SDR
  - other ARM SBC
- define minimum RDS feature set for MVP
- define exact operator parameters and safe ranges

Open question:
- which TX hardware/exciter are we driving?
  - HackRF / Pluto / Lime / bladeRF / RTL-SDR not suitable for TX / custom DAC / external exciter input

---

## Phase 1 - Repository bootstrap

Deliverables:
- initial Go module
- package layout
- build/test/lint scripts
- baseline docs

Suggested structure:

```text
cmd/fmrtx/
internal/audio/
internal/dsp/
internal/stereo/
internal/rds/
internal/mpx/
internal/output/
internal/control/
internal/config/
internal/platform/
internal/telemetry/
docs/
examples/
scripts/
```

Tasks:
- initialize module
- define config schema
- add structured logging
- add benchmark harness for DSP blocks
- add deterministic test vectors where possible

---

## Phase 2 - CPU MVP pipeline

Goal: produce valid offline MPX / IQ output from known inputs.

Deliverables:
- stereo encoder MVP
- RDS encoder MVP
- MPX combiner
- WAV/file output for verification
- offline spectrum / pilot / RDS validation tooling

Tasks:
- implement audio resampler path
- generate 19 kHz pilot with stable phase
- implement L+R and L-R paths
- implement 57 kHz RDS subcarrier generation
- implement basic group 0A / 2A support
- build verification scripts for:
  - pilot amplitude
  - stereo separation sanity
  - RDS subcarrier presence
  - modulation headroom checks

Acceptance criteria:
- generated composite can be decoded by reference analysis tools
- RDS PS and RadioText can be recovered reliably from recorded output
- CPU use acceptable on Windows x86 and Linux x86 for real-time operation

---

## Phase 3 - Real-time output backend

Goal: real-time transmit-capable software chain.

Deliverables:
- live audio input path
- real-time scheduler/buffering
- first real output backend
- underrun/overrun telemetry

Backend options to evaluate:
1. **SoapySDR backend** as the preferred first backend for broad SDR support and flexibility
2. **Vendor-native backend** for selected hardware where latency/control is better
3. **Composite audio backend** for hardware exciters that accept MPX input

Tasks:
- define backend abstraction
- implement timing-safe ring buffers
- implement frequency/config control surfaces
- expose operator-safe start/stop + status endpoints

Acceptance criteria:
- stable continuous real-time output for multi-hour tests
- no audible glitches under expected load
- backend reports lock/state/errors cleanly

---

## Phase 4 - Broadcast chain quality work

Deliverables:
- gain staging and limiter improvements
- pre-emphasis options
- calibration tools
- monitoring/telemetry dashboards or endpoints

Tasks:
- tune audio processing to avoid ugly overmodulation
- add regional pre-emphasis selection if needed
- add composite level calibration workflow
- add spectrum snapshots / diagnostics hooks

Acceptance criteria:
- operator can set conservative legal operating point
- composite behavior measurable and repeatable

---

## Phase 5 - CUDA acceleration (optional)

Goal: accelerate only the blocks that are actually worth offloading.

Candidates:
- FIR/filter banks
- resampling kernels
- vector mixing / waveform generation at higher rates
- possibly stereo/RDS composite generation if profiling justifies it

Rules:
- CPU path remains canonical and fully functional
- CUDA path selected at runtime
- identical output targets within defined tolerance
- no CUDA dependency on ARM/SBC builds

Tasks:
- benchmark CPU hotspots first
- define clean Go <-> native/CUDA boundary
- prototype one block at a time
- compare latency overhead vs throughput gain

Acceptance criteria:
- measurable real benefit on supported GPU hosts
- no regression for non-CUDA systems

---

## Phase 6 - SBC / Raspberry Pi optimization

Deliverables:
- tuned CPU profile for ARM
- deployment docs
- systemd service example

Tasks:
- test on Pi 4/5 or equivalent ARM SBC
- reduce allocation churn and GC pressure
- use fixed-size buffers where practical
- document thermal/load expectations

Acceptance criteria:
- stable real-time operation on target SBC profile for chosen backend and sample rate

---

## 5. Interfaces to expose

## Audio input
MVP:
- local WAV/PCM file
- local audio device or pipe input

Later:
- RTP/UDP
- Icecast/HTTP pull
- JACK/PipeWire integration

## RDS input/control
MVP:
- static config for PI, PS, PTY
- dynamic RadioText update API
- TA/TP flags

Later:
- event/queue-based RDS scheduler
- external automation bridge

## TX / RF controls
Important: actual supported parameters depend on hardware backend.

Expose where meaningful:
- center frequency
- sample rate
- output gain / drive level
- stereo enable/disable
- pilot level
- RDS injection level
- pre-emphasis mode
- backend device selection

Be careful with naming:
- use **drive level / output gain** in software
- do not promise true absolute RF power control unless hardware can measure/control it

---

## 6. Risks and unknowns

1. **Hardware backend choice dominates complexity**
   - the whole design changes depending on SDR vs composite exciter
2. **Raspberry Pi real-time headroom may be tight**
   - especially at higher sample rates and with extra DSP
3. **CUDA may be unnecessary for MVP**
   - profiling may show good CPU performance already
4. **Broadcast-quality audio processing is deeper than "just encode stereo"**
   - limiter/clipper/processing can become a whole subproject
5. **Regulatory and RF compliance live outside the codebase too**
   - filters, clocks, linearity, and measurement gear matter

---

## 7. Recommended MVP definition

Ship this first:
- Windows-first CLI daemon in Go, kept cross-platform from the start
- CPU-only path
- stereo MPX generation
- basic RDS (PS + RT + PI + PTY)
- file output + one real hardware backend
- config file + HTTP status/control API
- test/analysis tooling for composite validation

Defer until proven necessary:
- CUDA
- fancy web UI
- advanced audio processing
- many hardware backends at once

---

## 8. Immediate next steps

1. Decide the first output backend/hardware target.
2. Freeze MVP feature list.
3. Bootstrap the Go module and package skeleton.
4. Implement offline composite generation first.
5. Add verification tooling before real TX tests.
6. Only then bring up live hardware output.

---

## 9. Suggested first milestone

**Milestone A: Offline stereo + RDS composite generator**

Definition of done:
- takes WAV input + simple RDS config
- emits composite/baseband output file
- reference tools can decode pilot + stereo + RDS correctly
- architecture is ready for later real-time backend insertion

This is the safest and smartest place to start.
