|
|
|
@@ -0,0 +1,359 @@ |
|
|
|
# Project Plan - fm-rds-tx |
|
|
|
|
|
|
|
## 1. Mission |
|
|
|
|
|
|
|
Create a Go-based UKW/FM stereo transmitter with RDS that can run on standard Linux systems and, where feasible, on Raspberry Pi / SBC-class hardware. |
|
|
|
|
|
|
|
Primary design goals: |
|
|
|
- reliable CPU implementation first |
|
|
|
- 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 x86_64 Linux 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. |
|
|
|
- Linux is the primary target. |
|
|
|
- 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 |
|
|
|
- shortlist hardware targets: |
|
|
|
- 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 x86 Linux 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** for broad SDR support |
|
|
|
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: |
|
|
|
- Linux CLI daemon in Go |
|
|
|
- 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. |