[fix](trx-backend-soapysdr): widen WFM IQ filter to preserve RDS subcarrier

The FIR LPF cutoff was audio_bandwidth_hz/2; with wfm_bandwidth_hz=75000
this gave 37.5 kHz, stripping the 57 kHz RDS subcarrier before FM
demodulation. Clamp the IQ filter bandwidth to at least 130 kHz (cutoff
≥ 65 kHz) for WFM so the RDS subcarrier always reaches the decoder,
regardless of the configured audio bandwidth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-02-28 09:10:14 +01:00
parent e1ab2ae9dc
commit d5b1b6f020
@@ -323,10 +323,14 @@ impl ChannelDsp {
self.audio_sample_rate, self.audio_sample_rate,
self.audio_bandwidth_hz, self.audio_bandwidth_hz,
); );
let cutoff_hz = self // For WFM, widen the IQ filter enough to pass the RDS subcarrier at
.audio_bandwidth_hz // 57 kHz (requires cutoff ≥ 65 kHz → bandwidth ≥ 130 kHz).
.min(channel_sample_rate.saturating_sub(1)) as f32 let iq_filter_bw = if self.mode == RigMode::WFM {
/ 2.0; self.audio_bandwidth_hz.max(130_000)
} else {
self.audio_bandwidth_hz
};
let cutoff_hz = iq_filter_bw.min(channel_sample_rate.saturating_sub(1)) as f32 / 2.0;
let cutoff_norm = if self.sdr_sample_rate == 0 { let cutoff_norm = if self.sdr_sample_rate == 0 {
0.1 0.1
} else { } else {
@@ -384,7 +388,14 @@ impl ChannelDsp {
let taps = fir_taps.max(1); let taps = fir_taps.max(1);
let (decim_factor, channel_sample_rate) = let (decim_factor, channel_sample_rate) =
Self::pipeline_rates(mode, sdr_sample_rate, audio_sample_rate, audio_bandwidth_hz); Self::pipeline_rates(mode, sdr_sample_rate, audio_sample_rate, audio_bandwidth_hz);
let cutoff_hz = audio_bandwidth_hz.min(channel_sample_rate.saturating_sub(1)) as f32 / 2.0; // For WFM, widen the IQ filter enough to pass the RDS subcarrier at
// 57 kHz (requires cutoff ≥ 65 kHz → bandwidth ≥ 130 kHz).
let iq_filter_bw = if *mode == RigMode::WFM {
audio_bandwidth_hz.max(130_000)
} else {
audio_bandwidth_hz
};
let cutoff_hz = iq_filter_bw.min(channel_sample_rate.saturating_sub(1)) as f32 / 2.0;
let cutoff_norm = if sdr_sample_rate == 0 { let cutoff_norm = if sdr_sample_rate == 0 {
0.1 0.1
} else { } else {