From 8f6a5af4ec1097c59fab87ee681d307fd85feea0 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 1 Mar 2026 01:58:16 +0100 Subject: [PATCH] [fix](trx-backend-soapysdr): hard-limit iq magnitude before wfm discriminator Normalize IQ samples exceeding unit magnitude before the FM discriminator. The discriminator only uses phase, so clamping amplitude prevents overdeviated signals from producing clipped composite baseband without losing frequency information. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stan Grams --- .../trx-backend/trx-backend-soapysdr/src/dsp.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs index 2c785cd..2602dbd 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs @@ -852,6 +852,17 @@ impl ChannelDsp { } } + // Hard-limit IQ magnitude before the WFM discriminator so overdeviated + // signals don't produce clipped composite baseband. + if self.wfm_decoder.is_some() { + for sample in decimated.iter_mut() { + let mag = (sample.re * sample.re + sample.im * sample.im).sqrt(); + if mag > 1.0 { + *sample /= mag; + } + } + } + // --- 4. Demodulate + post-process ----------------------------------- // WFM: full composite decoder (handles its own DC blocks + deemphasis), // then apply post-audio AGC on the decoded PCM. Other modes use the