From 5060522541b89f392c72d9b099c907937161ba42 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 1 Mar 2026 00:02:19 +0100 Subject: [PATCH] [fix](trx-backend-soapysdr): add wfm limiter and restore cutoffs Co-authored-by: OpenAI Codex Signed-off-by: Stan Grams --- .../trx-backend/trx-backend-soapysdr/src/demod.rs | 9 +++++---- .../trx-backend/trx-backend-soapysdr/src/dsp.rs | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs index 1d0b026..98596ad 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs @@ -11,13 +11,14 @@ const RDS_BPF_Q: f32 = 10.0; /// Pilot tone frequency (Hz). const PILOT_HZ: f32 = 19_000.0; /// Audio bandwidth for WFM (Hz). -/// 17 kHz preserves more top-end while still leaving guard band below the -/// 19 kHz pilot. -const AUDIO_BW_HZ: f32 = 17_000.0; +/// 15.8 kHz leaves more guard band below the 19 kHz pilot and reduces +/// top-end artifacts on strong signals while still preserving the useful +/// broadcast audio range. +const AUDIO_BW_HZ: f32 = 15_800.0; /// Stereo L-R subchannel bandwidth for WFM (Hz). /// Keep this a bit lower than the mono path because the recovered difference /// signal is noisier and more prone to high-frequency artifacts. -const STEREO_DIFF_BW_HZ: f32 = 15_800.0; +const STEREO_DIFF_BW_HZ: f32 = 14_500.0; /// Q values for a proper 4th-order Butterworth cascade (two 2nd-order stages). /// Stage 1: Q = 1 / (2 cos(π/8)) const BW4_Q1: f32 = 0.5412; 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 0077531..6d2b4c8 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 @@ -267,12 +267,15 @@ impl BlockFirFilter { /// 500 ms / 5 s only reacts to slow carrier-amplitude fading, not audio. /// /// CW uses a fast attack/release to follow individual dots and dashes. +/// WFM uses a linked downward-only peak limiter (max gain = 1.0) so louder +/// stations are tamed without boosting quieter ones. /// All other modes use 5 ms / 500 ms, suitable for SSB voice and FM. fn agc_for_mode(mode: &RigMode, audio_sample_rate: u32) -> SoftAgc { let sr = audio_sample_rate.max(1) as f32; match mode { RigMode::CW | RigMode::CWR => SoftAgc::new(sr, 1.0, 50.0, 0.5, 30.0), RigMode::AM => SoftAgc::new(sr, 500.0, 5_000.0, 0.5, 30.0), + RigMode::WFM => SoftAgc::new(sr, 0.2, 80.0, 0.92, 0.0), _ => SoftAgc::new(sr, 5.0, 500.0, 0.5, 30.0), } }