[fix](trx-rds): tune RDS parameters for maximum sensitivity
- RRC_ALPHA 0.75→0.50: narrower noise BW, ~0.6 dB SNR gain - COSTAS_KI 3.5e-7: maintain ζ≈0.68 (1e-6 caused loop instability) - Soft confidence: use biphase_i.abs() instead of full vector magnitude so OSD confidence is aligned with bit-decision sign; suppresses false groups under noise with residual Costas phase error - OSD(2) in locked mode: corrects ≤2-bit errors after block sync - Search mode: hard decode only for Block A; OSD(1) in search yielded ~13% false Block A rate per bit, letting wrong clock candidates accumulate false groups as fast as the correct candidate - Incumbent candidate tracking (best_candidate_idx): the winning candidate updates best_state at equal score; challengers need strictly higher score; best_score tracks incumbent even on no-state-change groups so challengers can't leapfrog on a single false group - blocks_to_chips: add NRZI (NRZ-Mark) pre-encoding so the differential biphase decoder recovers actual data bits rather than XOR-of-pairs - Add blocks_to_chips_round_trips_all_groups test: verifies all 16 blocks across 4 PS segments round-trip correctly without BPSK modulation [fix](trx-backend-soapysdr): lower pilot lock threshold for weak-signal RDS - PILOT_LOCK_THRESHOLD 0.25→0.20, add PILOT_LOCK_ONSET=0.30 constant - Pilot reference engages at coherence ≥0.36 (was ≥0.45) WIP: end_to_end_clean_signal_decodes_ps still failing (13/15 pass). Decoder skips segment 2 due to ISI from rectangular test chips through RRC receive filter. chips_to_rds_signal needs RRC pulse shaping. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -10,7 +10,13 @@ use super::{math::demod_fm_with_prev, DcBlocker};
|
||||
|
||||
const RDS_SUBCARRIER_HZ: f32 = 57_000.0;
|
||||
/// Tech 2: pilot lock level above which the ×3 pilot reference is used.
|
||||
const PILOT_LOCK_THRESHOLD: f32 = 0.25;
|
||||
/// Effective pilot coherence threshold ≈ ONSET + THRESHOLD × 0.2 = 0.36.
|
||||
const PILOT_LOCK_THRESHOLD: f32 = 0.20;
|
||||
/// Coherence below which pilot_lock contribution is zero (linear ramp 0→1
|
||||
/// over the range [ONSET, ONSET+0.2]). Lower value → pilot ref used on
|
||||
/// weaker stations; risk: noisier reference. 0.30 vs original 0.40 means
|
||||
/// we engage at coherence ≥ 0.36 instead of ≥ 0.45.
|
||||
const PILOT_LOCK_ONSET: f32 = 0.30;
|
||||
/// Tech 9: number of complex CMA equalizer taps.
|
||||
const CMA_N_TAPS: usize = 8;
|
||||
/// Tech 9: CMA LMS step size.
|
||||
@@ -722,7 +728,7 @@ impl WfmStereoDecoder {
|
||||
let avg_mag = self.detect_pilot_mag_acc * inv_n;
|
||||
let avg_abs = self.detect_pilot_abs_acc * inv_n;
|
||||
let pilot_coherence = (avg_mag / (avg_abs + 1e-4)).clamp(0.0, 1.0);
|
||||
let pilot_lock = ((pilot_coherence - 0.4) / 0.2).clamp(0.0, 1.0);
|
||||
let pilot_lock = ((pilot_coherence - PILOT_LOCK_ONSET) / 0.2).clamp(0.0, 1.0);
|
||||
self.pilot_lock_level += 0.12 * (pilot_lock - self.pilot_lock_level);
|
||||
let stereo_drive = (avg_mag * pilot_lock * 120.0).clamp(0.0, 1.0);
|
||||
let detect_coeff = if stereo_drive > self.stereo_detect_level {
|
||||
|
||||
Reference in New Issue
Block a user