RDS Decoder Overhaul
Fixes RDS Programme Service (PS) station name and RadioText (RT) not decoding despite the station transmitting valid RDS data. Commercial receivers decode the same stations correctly.
Root Cause
The 57kHz RDS subcarrier NCO was free-running with no carrier tracking. Crystal frequency error (10-50 ppm typical for RTL-SDR) caused progressive phase drift that made Block D (which carries PS characters) consistently fail CRC — the block furthest from sync point accumulated the most error.
Fixes (applied to both TypeScript client and Go server)
- Pilot-locked NCO: RDS mixer now uses
3 × pilotPhasefrom the 19kHz pilot PLL, eliminating carrier drift entirely - Gardner TED: Replaced weak zero-crossing timing nudge (+0.01) with a proper Gardner Timing Error Detector + PI loop filter for robust symbol synchronization
- Single-bit error correction: Pre-computed syndrome lookup table recovers ~30% of blocks that previously failed CRC
- RDS in mono path: WFM mono path now feeds the RDS decoder (previously only stereo path did)
- Rate-change safety: RDS decoder recreated when IQ sample rate changes
Performance
Go benchmarks unchanged: 28µs per 20ms block, 678 MB/s, 0 allocations.