[fix](trx-backend-soapysdr): use precise atan2 in wfm discriminator and pll

Replace fast_atan2 polynomial approximation with f32::atan2 in the WFM
stereo decoder's FM discriminator and pilot PLL. The approximation
introduced harmonic distortion (~0.22 deg error) that manifested as
treble artifacts on strong/overdeviated broadcast 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 02:04:06 +01:00
parent 8f6a5af4ec
commit cb4b81ca94
@@ -769,7 +769,7 @@ impl WfmStereoDecoder {
for &sample in samples { for &sample in samples {
let x = if let Some(prev_sample) = self.prev_iq { let x = if let Some(prev_sample) = self.prev_iq {
let product = sample * prev_sample.conj(); let product = sample * prev_sample.conj();
fast_atan2(product.im, product.re) * inv_pi product.im.atan2(product.re) * inv_pi
} else { } else {
0.0 0.0
}; };
@@ -784,7 +784,7 @@ impl WfmStereoDecoder {
let (sin_p, cos_p) = self.pilot_phase.sin_cos(); let (sin_p, cos_p) = self.pilot_phase.sin_cos();
let i = self.pilot_i_lp.process(pilot_tone * cos_p); let i = self.pilot_i_lp.process(pilot_tone * cos_p);
let q = self.pilot_q_lp.process(pilot_tone * -sin_p); let q = self.pilot_q_lp.process(pilot_tone * -sin_p);
let phase_err = fast_atan2(q, i); let phase_err = q.atan2(i);
let pilot_phase_est = self.pilot_phase + phase_err; let pilot_phase_est = self.pilot_phase + phase_err;
self.pilot_phase += self.pilot_freq; self.pilot_phase += self.pilot_freq;
self.pilot_phase = self.pilot_phase.rem_euclid(std::f32::consts::TAU); self.pilot_phase = self.pilot_phase.rem_euclid(std::f32::consts::TAU);