[fix](trx-backend-soapysdr): preserve RDS subcarrier with narrow WFM bandwidth
The IQ prefilter cutoff was audio_bandwidth_hz/2, so any setting below ~120 kHz would cut off the 57 kHz RDS subcarrier before FM demod. - Clamp IQ prefilter cutoff to >= 60 kHz for WFM in both new() and rebuild_filters() — audio quality is unaffected since WfmStereoDecoder applies its own 18 kHz lowpass internally - Ensure pipeline target rate >= 120 kHz for WFM so the decimated IQ sample rate can represent the 60 kHz cutoff Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -328,7 +328,11 @@ impl ChannelDsp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let target_rate = match mode {
|
let target_rate = match mode {
|
||||||
RigMode::WFM => audio_bandwidth_hz.max(audio_sample_rate.saturating_mul(4)),
|
// Ensure composite rate is at least 120 kHz so the IQ filter can
|
||||||
|
// pass the 57 kHz RDS subcarrier regardless of the user's audio BW.
|
||||||
|
RigMode::WFM => audio_bandwidth_hz
|
||||||
|
.max(audio_sample_rate.saturating_mul(4))
|
||||||
|
.max(120_000),
|
||||||
RigMode::VDES => audio_sample_rate.max(96_000),
|
RigMode::VDES => audio_sample_rate.max(96_000),
|
||||||
_ => audio_sample_rate.max(1),
|
_ => audio_sample_rate.max(1),
|
||||||
};
|
};
|
||||||
@@ -346,10 +350,20 @@ impl ChannelDsp {
|
|||||||
self.audio_sample_rate,
|
self.audio_sample_rate,
|
||||||
self.audio_bandwidth_hz,
|
self.audio_bandwidth_hz,
|
||||||
);
|
);
|
||||||
let cutoff_hz = self
|
let cutoff_hz = {
|
||||||
.audio_bandwidth_hz
|
let raw = self
|
||||||
.min(channel_sample_rate.saturating_sub(1)) as f32
|
.audio_bandwidth_hz
|
||||||
/ 2.0;
|
.min(channel_sample_rate.saturating_sub(1)) as f32
|
||||||
|
/ 2.0;
|
||||||
|
// For WFM, always pass at least the 57 kHz RDS subcarrier.
|
||||||
|
// Audio bandwidth is handled inside WfmStereoDecoder, so widening
|
||||||
|
// the IQ prefilter here does not affect output audio quality.
|
||||||
|
if self.mode == RigMode::WFM {
|
||||||
|
raw.max(60_000.0)
|
||||||
|
} else {
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
};
|
||||||
let cutoff_norm = if self.sdr_sample_rate == 0 {
|
let cutoff_norm = if self.sdr_sample_rate == 0 {
|
||||||
0.1
|
0.1
|
||||||
} else {
|
} else {
|
||||||
@@ -424,7 +438,14 @@ impl ChannelDsp {
|
|||||||
|
|
||||||
let (decim_factor, channel_sample_rate) =
|
let (decim_factor, channel_sample_rate) =
|
||||||
Self::pipeline_rates(mode, sdr_sample_rate, audio_sample_rate, audio_bandwidth_hz);
|
Self::pipeline_rates(mode, sdr_sample_rate, audio_sample_rate, audio_bandwidth_hz);
|
||||||
let cutoff_hz = audio_bandwidth_hz.min(channel_sample_rate.saturating_sub(1)) as f32 / 2.0;
|
let cutoff_hz = {
|
||||||
|
let raw = audio_bandwidth_hz.min(channel_sample_rate.saturating_sub(1)) as f32 / 2.0;
|
||||||
|
if *mode == RigMode::WFM {
|
||||||
|
raw.max(60_000.0)
|
||||||
|
} else {
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
};
|
||||||
let cutoff_norm = if sdr_sample_rate == 0 {
|
let cutoff_norm = if sdr_sample_rate == 0 {
|
||||||
0.1
|
0.1
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user