From 6440f67d940c7304804d9b58701c2a8fc15f3fdd Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Fri, 27 Mar 2026 15:24:18 +0100 Subject: [PATCH] [fix](trx-rs): add EMA smoothing to signal strength and fix freq input clobbering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EMA (α=0.4) smooths the carrier power estimate across DSP blocks. Custom PartialEq on VchanRdsEntry excludes signal_db so rapidly-changing levels do not trigger main state SSE updates that overwrite the frequency input. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stan Grams --- src/trx-core/src/rig/state.rs | 12 +++++++++++- .../trx-backend-soapysdr/src/dsp/channel.rs | 6 ++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/trx-core/src/rig/state.rs b/src/trx-core/src/rig/state.rs index b4e88d7..b2b0efc 100644 --- a/src/trx-core/src/rig/state.rs +++ b/src/trx-core/src/rig/state.rs @@ -430,7 +430,11 @@ pub struct RdsData { } /// RDS metadata snapshot for a virtual channel. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +/// +/// `PartialEq` intentionally ignores `signal_db` so that rapidly-changing +/// signal levels do not cause the main state snapshot to diff on every poll +/// cycle (signal_db flows through the spectrum SSE instead). +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct VchanRdsEntry { /// Virtual channel UUID. pub id: Uuid, @@ -442,6 +446,12 @@ pub struct VchanRdsEntry { pub signal_db: Option, } +impl PartialEq for VchanRdsEntry { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.rds == other.rds + } +} + /// Read-only projection of state shared with clients. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct RigSnapshot { 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 877c555..ab6ec55 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 @@ -675,12 +675,14 @@ impl ChannelDsp { // Carrier power: DC component of the mixed signal (narrow-band estimate // at the tuned frequency). Correlates with the spectrum FFT peak. + // EMA smoothing (α ≈ 0.4) for fast response with light jitter reduction. { + const SIGNAL_EMA_ALPHA: f32 = 0.4; let inv_n = 1.0 / n as f32; let dc_i: f32 = mixed_i.iter().sum::() * inv_n; let dc_q: f32 = mixed_q.iter().sum::() * inv_n; - let carrier_power = dc_i * dc_i + dc_q * dc_q; - self.last_signal_db = 10.0 * carrier_power.max(1e-12).log10(); + let carrier_db = 10.0 * (dc_i * dc_i + dc_q * dc_q).max(1e-12).log10(); + self.last_signal_db += SIGNAL_EMA_ALPHA * (carrier_db - self.last_signal_db); } self.lpf_iq.filter_block_into(