[fix](trx-rs): show signal strength with decimal precision

Change RigRxStatus.sig from i32 to f64 and add get_signal_strength_db
to RigCat trait so SDR backends can bypass the coarse 0..15 quantisation.
Compensate for decimation processing gain so the meter matches the
spectrum peak. Display with one decimal place in all units.

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-27 20:06:36 +01:00
parent d468a96448
commit 0efdb5e360
6 changed files with 44 additions and 13 deletions
+6 -4
View File
@@ -887,7 +887,9 @@ async fn refresh_state_from_cat(rig: &mut Box<dyn RigCat>, state: &mut RigState)
state.status.vfo = vfo;
if state.status.tx_en {
state.status.rx.get_or_insert(RigRxStatus { sig: None }).sig = Some(0);
state.status.rx.get_or_insert(RigRxStatus { sig: None }).sig = Some(0.0);
} else if let Some(db) = rig.get_signal_strength_db().await {
state.status.rx.get_or_insert(RigRxStatus { sig: None }).sig = Some(db);
} else if let Ok(meter) = rig.get_signal_strength().await {
let sig = map_signal_strength(&state.status.mode, meter);
state.status.rx.get_or_insert(RigRxStatus { sig: None }).sig = Some(sig);
@@ -1015,12 +1017,12 @@ async fn prime_vfo_state(
}
/// Map raw signal strength to S-meter value based on mode.
fn map_signal_strength(mode: &RigMode, raw: u8) -> i32 {
fn map_signal_strength(mode: &RigMode, raw: u8) -> f64 {
// FT-817 returns 0-15 for signal strength
// Map to approximate dBm / S-units
match mode {
RigMode::FM | RigMode::WFM | RigMode::AIS | RigMode::VDES => -120 + (raw as i32 * 6),
_ => -127 + (raw as i32 * 6),
RigMode::FM | RigMode::WFM | RigMode::AIS | RigMode::VDES => -120.0 + (raw as f64 * 6.0),
_ => -127.0 + (raw as f64 * 6.0),
}
}
@@ -757,7 +757,13 @@ impl ChannelDsp {
}
// Signal strength measurement (before AGC).
//
// The decimated samples carry the total power of the channel bandwidth,
// which is higher than the per-bin spectral density shown on the
// spectrum display by approximately 10·log10(decim_factor). Subtract
// that so the meter and the spectrum peak agree.
{
let decim_correction = 10.0 * (self.decim_factor as f32).max(1.0).log10();
if self.mode == RigMode::WFM {
// WFM: smooth envelope power directly.
// FM is constant-envelope, so I²+Q² is inherently stable
@@ -769,7 +775,8 @@ impl ChannelDsp {
let pwr = s.re * s.re + s.im * s.im;
self.carrier_iq_i += alpha * (pwr - self.carrier_iq_i);
}
self.last_signal_db = 10.0 * self.carrier_iq_i.max(1e-12).log10();
self.last_signal_db =
10.0 * self.carrier_iq_i.max(1e-12).log10() - decim_correction;
} else {
// Other modes: peak IQ magnitude with EMA smoothing.
const SIGNAL_EMA_ALPHA: f32 = 0.4;
@@ -777,7 +784,7 @@ impl ChannelDsp {
.iter()
.map(|s| s.re * s.re + s.im * s.im)
.fold(0.0_f32, f32::max);
let peak_db = 10.0 * peak_power.max(1e-12).log10();
let peak_db = 10.0 * peak_power.max(1e-12).log10() - decim_correction;
self.last_signal_db += SIGNAL_EMA_ALPHA * (peak_db - self.last_signal_db);
}
}
@@ -567,6 +567,19 @@ impl RigCat for SoapySdrRig {
})
}
fn get_signal_strength_db<'a>(
&'a mut self,
) -> Pin<Box<dyn std::future::Future<Output = Option<f64>> + Send + 'a>> {
Box::pin(async move {
self.pipeline
.channel_dsps
.read()
.unwrap()
.get(self.primary_channel_idx)
.and_then(|dsp| dsp.lock().ok().map(|d| d.signal_db() as f64))
})
}
// -- TX / unsupported methods -------------------------------------------
fn set_ptt<'a>(