# fm-rds-tx docs ## Build & Test ### Root CLI - `go test ./...` - `go run ./cmd/fmrtx -print-config` - `go run ./cmd/fmrtx -config docs/config.sample.json` - `go run ./cmd/fmrtx --dry-run --dry-output build/dryrun/frame.json` - `go run ./cmd/fmrtx --simulate-tx --simulate-output build/sim/simulated-soapy.iqf32 --simulate-duration 250ms` - `go run ./cmd/offline -duration 500ms -output build/offline/composite.iqf32` ### Audio source modes Current no-hardware sources: - generated stereo tones via config - 16-bit PCM WAV file input via `audio.inputPath` (robust chunk-scanning loader) - linear-interpolation sample-rate conversion for WAV sources - transparent tone fallback if the configured WAV source cannot be loaded ### Tone configuration The current no-hardware source can be parameterized via config: - `audio.toneLeftHz` - `audio.toneRightHz` - `audio.toneAmplitude` ### DSP chain The full signal chain from audio input to IQ output: 1. **Audio ingest** — tone generator or WAV file with linear-interpolation resampler 2. **Gain staging** — configurable audio gain 3. **Pre-emphasis** — first-order IIR high-shelf filter, configurable τ (50 µs EU / 75 µs US / 0 = off) 4. **Stereo encoder** — L+R mono, L-R on stateful 38 kHz DSB-SC subcarrier, phase-coherent 19 kHz pilot 5. **RDS encoder** — standards-grade group framing (0A/2A), CRC-10 per IEC 62106, differential encoding, 57 kHz BPSK subcarrier, group scheduler cycling PS and RadioText 6. **MPX combiner** — configurable gains for mono, stereo, pilot, and RDS components 7. **Output drive** — configurable output level scaling 8. **MPX limiter** — smooth attack/release peak limiter with hard-clip safety net 9. **FM modulator** — composite-to-IQ via phase integration, configurable ±75 kHz deviation, unit-magnitude IQ output ### Pre-emphasis FM broadcast requires pre-emphasis to boost high frequencies before transmission. The receiver applies complementary de-emphasis to restore flat response while reducing noise. - Europe/World: τ = 50 µs (`preEmphasisUS: 50`) - North America/South Korea: τ = 75 µs (`preEmphasisUS: 75`) - Disabled: `preEmphasisUS: 0` ### FM modulation modes - `fmModulationEnabled: true` — output is baseband FM-modulated IQ (I² + Q² = 1). This is what SDR transmitters expect. - `fmModulationEnabled: false` — output is raw composite MPX (I = composite, Q = 0). Useful for analysis or composite exciters. ### Limiter The MPX limiter prevents overmodulation by applying smooth gain reduction when the composite signal exceeds the configured ceiling. A hard clipper acts as a safety net after the limiter. - `limiterEnabled: true/false` - `limiterCeiling: 1.0` (max composite level before FM modulation) ### HTTP control surface Available endpoints: - `GET /healthz` - `GET /status` - `GET /dry-run` - `GET /config` - `POST /config` Current patchable runtime fields via `POST /config`: - `frequencyMHz` - `outputDrive` - `toneLeftHz` - `toneRightHz` - `toneAmplitude` - `ps` - `radioText` - `preEmphasisUS` - `limiterEnabled` - `limiterCeiling` ### Internal DSP module - `cd internal` - `go test ./...` ### Examples module - `cd examples` - `go test ./...` - `go run ./soapy_simulated` ## Dry run The dry-run mode generates a synthetic, hardware-free frame summary based on the current config. It reports the active source label, pre-emphasis setting, limiter state, and FM modulation mode. The HTTP control plane also exposes `GET /dry-run` for quick inspection. ## Simulated transmit `--simulate-tx` runs the offline generator through the Soapy-oriented simulated backend path and writes an IQ-style artifact to disk. ## Offline generation `cmd/offline` generates a deterministic no-hardware IQ/composite file using the full DSP chain (pre-emphasis, stereo encoding, RDS, limiter, FM modulation). ## Release posture Current honest release posture: **pre-v1**. Recommended milestone tag: `v0.4.0-pre`. See `CHANGELOG.md` and `RELEASE.md`.