[fix](trx-backend-soapysdr): match sum/diff filters and simplify stereo blend

- Set STEREO_DIFF_BW_HZ = AUDIO_BW_HZ so both filter paths have
  identical group delay (improves multitone separation by ~10 dB).
- Zero out STEREO_SEPARATION_PHASE_TRIM (unnecessary with matched filters).
- Replace gradual blend ramp with binary blend: full stereo at pilot
  lock, mono when unlocked. The hysteresis thresholds already handle
  noisy signals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-01 01:48:16 +01:00
parent 13576f73aa
commit 815efdb1ae
@@ -15,9 +15,9 @@ const PILOT_HZ: f32 = 19_000.0;
/// artifacts on strong signals while preserving the useful broadcast range. /// artifacts on strong signals while preserving the useful broadcast range.
const AUDIO_BW_HZ: f32 = 15_800.0; const AUDIO_BW_HZ: f32 = 15_800.0;
/// Stereo L-R subchannel bandwidth for WFM (Hz). /// Stereo L-R subchannel bandwidth for WFM (Hz).
/// Wider than the mono path to preserve high-frequency stereo detail; the /// Must match AUDIO_BW_HZ so the sum and diff filter paths have identical
/// 19 kHz pilot is already removed by the coherent demodulation step. /// group delay, which is critical for stereo separation across all frequencies.
const STEREO_DIFF_BW_HZ: f32 = 18_000.0; const STEREO_DIFF_BW_HZ: f32 = AUDIO_BW_HZ;
/// Q values for a proper 4th-order Butterworth cascade (two 2nd-order stages). /// Q values for a proper 4th-order Butterworth cascade (two 2nd-order stages).
/// Stage 1: Q = 1 / (2 cos(π/8)) /// Stage 1: Q = 1 / (2 cos(π/8))
const BW4_Q1: f32 = 0.5412; const BW4_Q1: f32 = 0.5412;
@@ -28,7 +28,7 @@ const PILOT_NOTCH_Q: f32 = 5.0;
/// Narrow 19 kHz band-pass used to derive zero-crossings for switching stereo demod. /// Narrow 19 kHz band-pass used to derive zero-crossings for switching stereo demod.
const PILOT_BPF_Q: f32 = 20.0; const PILOT_BPF_Q: f32 = 20.0;
/// Fixed phase trim on the recovered L-R channel to compensate pilot-path delay. /// Fixed phase trim on the recovered L-R channel to compensate pilot-path delay.
const STEREO_SEPARATION_PHASE_TRIM: f32 = 0.015; const STEREO_SEPARATION_PHASE_TRIM: f32 = 0.0;
/// Fixed gain trim on the recovered L-R channel. /// Fixed gain trim on the recovered L-R channel.
const STEREO_SEPARATION_GAIN: f32 = 1.000; const STEREO_SEPARATION_GAIN: f32 = 1.000;
/// Extra headroom in the stereo matrix to reduce stereo-only clipping/IMD on /// Extra headroom in the stereo matrix to reduce stereo-only clipping/IMD on
@@ -812,10 +812,9 @@ impl WfmStereoDecoder {
self.stereo_detected = true; self.stereo_detected = true;
} }
let stereo_blend_target = if self.stereo_detected { let stereo_blend_target = if self.stereo_detected {
let width = smoothstep01((self.stereo_detect_level - 0.30) / (0.70 - 0.30)); 1.0
0.75 + 0.25 * width
} else { } else {
0.35 * smoothstep01((self.stereo_detect_level - 0.10) / (0.30 - 0.10)) 0.0
}; };
// --- RDS --- // --- RDS ---