From f57292a65d49e6b13e4042ddf221032f21b5a33f Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 19 Apr 2026 23:10:43 +0200 Subject: [PATCH] [fix](trx-backend-soapysdr): correct WFM S-meter IIR block-rate scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-sample attack/decay alphas from smeter_alphas() were applied once per decimated block (~200 samples), inflating effective time constants by ~200x and causing a sluggish "pumping" meter. Correct with α_block = 1 − (1 − α)^N to preserve the intended IARU R.1 time constants (~2 ms attack, ~300 ms decay). Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stan Grams --- .../trx-backend/trx-backend-soapysdr/src/dsp/channel.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp/channel.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp/channel.rs index 52be6f9..68e2df6 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp/channel.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp/channel.rs @@ -798,11 +798,18 @@ impl ChannelDsp { // Asymmetric attack/decay: use the faster coefficient when // the new measurement is above the current estimate (attack), // and the slower coefficient when below (decay). - let alpha = if mean_power > self.carrier_iq_power { + // + // The per-sample alphas from smeter_alphas() assume sample-by- + // sample IIR updates, but we apply the IIR once per decimated + // block. Correct via α_block = 1 − (1 − α)^N so the + // effective time constants stay at ~2 ms / ~300 ms regardless + // of block size. + let per_sample = if mean_power > self.carrier_iq_power { self.carrier_attack_alpha } else { self.carrier_decay_alpha }; + let alpha = 1.0 - (1.0 - per_sample).powf(n); self.carrier_iq_power += alpha * (mean_power - self.carrier_iq_power); self.last_signal_db =