[fix](trx-backend-soapysdr): slow down WFM S-meter to 200 ms attack / 600 ms decay

50 ms attack was still too twitchy for WFM — block-to-block power
noise in the constant-envelope FM signal made the meter jitter.
200 ms attack (~6 frames) and 600 ms decay (~18 frames) give a
smooth, traditional meter feel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-04-19 23:23:43 +02:00
parent 350d7e0c3f
commit aed9483659
@@ -308,20 +308,18 @@ pub struct ChannelDsp {
impl ChannelDsp {
/// Compute asymmetric IIR coefficients for S-meter envelope tracking.
///
/// Attack: ~50 ms time constant (responsive but visually stable).
/// Decay: ~300 ms time constant (slow fall for stable reading).
/// Attack: ~200 ms time constant (~6 frames at 30 Hz refresh).
/// Decay: ~600 ms time constant (~18 frames — smooth fallback).
///
/// Note: these alphas are applied once per decimated *block*, not per
/// sample, with block-rate correction (`1 (1−α)^N`). The 50 ms
/// attack gives ~3-frame settling at 30 Hz meter refresh — fast
/// enough to follow signal changes, smooth enough to avoid jitter.
/// sample, with block-rate correction (`1 (1−α)^N`).
fn smeter_alphas(channel_sample_rate: u32) -> (f32, f32) {
if channel_sample_rate == 0 {
return (0.3, 0.01);
}
let sr = channel_sample_rate as f32;
let attack = (1.0 - (-1.0 / (sr * 0.050)).exp()).min(1.0); // τ = 50 ms
let decay = (1.0 - (-1.0 / (sr * 0.300)).exp()).min(1.0); // τ = 300 ms
let attack = (1.0 - (-1.0 / (sr * 0.200)).exp()).min(1.0); // τ = 200 ms
let decay = (1.0 - (-1.0 / (sr * 0.600)).exp()).min(1.0); // τ = 600 ms
(attack, decay)
}