From 821f441af019066095e7e0e02452ea748f5df6e6 Mon Sep 17 00:00:00 2001 From: ruv Date: Sun, 31 May 2026 06:26:48 -0400 Subject: [PATCH] =?UTF-8?q?fix(signal/cir):=20causal-delay-window=20rms=20?= =?UTF-8?q?spread=20=E2=80=94=20resolves=20last=20ADR-134=20P2=20cir=20tes?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found the principled fix for the rms-delay-spread inflation (superseding my prior 'needs ISTA work' note): the spurious ~15-20% tap at ~bin 150 is an ALIAS of the near-zero dominant tap — the ISTA delay grid is circular (Φ is DFT-like), so bins >= G/2 are non-causal negative delays. Computing the delay spread over only the causal half [0, G/2) drops rms from 389ns to 65ns (true value), cleanly and robustly (no fragile magnitude threshold). Un-ignores should_produce_positive_rms_delay_spread. ADR-134 P2 cir_synthetic now FULLY resolved: all 5 previously-ignored tests pass via two physics-justified fixes (windowed dominant-ratio for super- resolution leakage + causal-window rms for circular-grid aliasing). signal+cir: 471 pass / 0 fail / 0 ignored in cir_synthetic. Co-Authored-By: claude-flow --- v2/crates/wifi-densepose-signal/src/ruvsense/cir.rs | 6 +++++- v2/crates/wifi-densepose-signal/tests/cir_synthetic.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/v2/crates/wifi-densepose-signal/src/ruvsense/cir.rs b/v2/crates/wifi-densepose-signal/src/ruvsense/cir.rs index 38ae6035..79a3dc86 100644 --- a/v2/crates/wifi-densepose-signal/src/ruvsense/cir.rs +++ b/v2/crates/wifi-densepose-signal/src/ruvsense/cir.rs @@ -452,7 +452,11 @@ impl CirEstimator { let active_tap_count = x.iter().filter(|c| c.norm() >= cutoff).count(); // RMS delay spread: √(Σ τ²P(τ)/ΣP(τ) − τ̄²), with P(τ) = |tap|². - let power: Vec = x.iter().map(|c| (c.norm() as f64).powi(2)).collect(); + // Only causal delays [0, G/2) contribute: the ISTA delay grid is circular + // (Φ is DFT-like), so bins ≥ G/2 are aliased *negative* (non-causal) delays — + // an alias of the near-zero dominant tap otherwise inflates the spread (ADR-134 P2). + let causal_bins = x.len() / 2; + let power: Vec = x[..causal_bins].iter().map(|c| (c.norm() as f64).powi(2)).collect(); let p_sum: f64 = power.iter().sum(); let rms_delay_spread_s = if p_sum > 1e-24 { let mean_tau: f64 = power diff --git a/v2/crates/wifi-densepose-signal/tests/cir_synthetic.rs b/v2/crates/wifi-densepose-signal/tests/cir_synthetic.rs index b72af04c..a4ce8d1b 100644 --- a/v2/crates/wifi-densepose-signal/tests/cir_synthetic.rs +++ b/v2/crates/wifi-densepose-signal/tests/cir_synthetic.rs @@ -155,6 +155,7 @@ fn save_fixture(path: &str, k_active: usize, csi: &[Complex64], expected_dominan // --------------------------------------------------------------------------- + // Shared test logic: inject 3-tap channel, run estimator, assert // --------------------------------------------------------------------------- @@ -341,7 +342,6 @@ fn should_return_tof_at_40mhz() { // --------------------------------------------------------------------------- #[test] -#[ignore = "ADR-134 P2 (remaining): ISTA emits a spurious ~15-20%-of-dominant tap at an implausible far delay (~bin 150, ~3us) that inflates rms_delay_spread to ~390ns. Too close to tap2 (~30%) for a safe magnitude cutoff; needs ISTA recovery-quality work (grid de-aliasing / stronger far-tap suppression), not a band-aid. Dominant-ratio tuning landed separately."] fn should_produce_positive_rms_delay_spread() { let cfg = CirConfig::for_bandwidth_mhz(20); let k_active = cfg.delay_bins / 3;