use dsfb_rf::{
engine::{DsfbRfEngine, DecimationAccumulator},
fixedpoint::{PeriodicResyncConfig, apply_periodic_resync, quantize_q16_16},
platform::PlatformContext,
};
const N: usize = 1_000_000;
const DECIM_FACTOR: u32 = 1_000;
const EXPECTED_EPOCHS: usize = N / DECIM_FACTOR as usize;
#[inline(always)]
fn synthetic_norm(i: usize) -> f32 {
let phase = (i % 1024) as f32 / 1024.0;
let triangle = if phase < 0.5 {
4.0 * phase - 1.0
} else {
3.0 - 4.0 * phase
};
0.4 + 0.4 * triangle
}
#[test]
fn grammar_and_dsa_stable_over_one_million_samples() {
let mut eng = DsfbRfEngine::<10, 4, 8>::new(
0.05, 3.0, );
let ctx = PlatformContext::operational();
let mut nan_count = 0usize;
let mut inf_count = 0usize;
let mut obs_count = 0usize;
for i in 0..N {
let norm = synthetic_norm(i);
let result = eng.observe(norm, ctx);
obs_count += 1;
let s = result.dsa_score;
if s.is_nan() {
nan_count += 1;
}
if s.is_infinite() {
inf_count += 1;
}
}
assert_eq!(obs_count, N, "observation count mismatch");
assert_eq!(
nan_count, 0,
"DSA score produced NaN on {} of {} observations",
nan_count, N
);
assert_eq!(
inf_count, 0,
"DSA score produced Inf on {} of {} observations",
inf_count, N
);
}
#[test]
fn decimator_fires_exact_epoch_count() {
let mut eng = DsfbRfEngine::<10, 4, 8>::new(0.05, 3.0)
.with_decimation(DECIM_FACTOR);
let ctx = PlatformContext::operational();
let mut epoch_count = 0usize;
for i in 0..N {
let norm = synthetic_norm(i);
if eng.observe_decimated(norm, ctx).is_some() {
epoch_count += 1;
}
}
assert_eq!(
epoch_count, EXPECTED_EPOCHS,
"DecimationAccumulator fired {} epochs; expected {}",
epoch_count, EXPECTED_EPOCHS
);
}
#[test]
fn periodic_resync_bounds_fixedpoint_drift() {
let config = PeriodicResyncConfig::DEFAULT;
let reference_q = quantize_q16_16(0.5);
let mut accumulator: i32 = reference_q;
let mut max_observed_drift: i32 = 0;
let mut resync_count: u32 = 0;
for step in 0usize..(N) {
accumulator = accumulator.saturating_add(1);
let obs_mod = (step as u32).wrapping_add(1) % config.period;
if config.should_resync(obs_mod) {
let (new_acc, was_resynced) =
apply_periodic_resync(accumulator, reference_q, config.max_drift_ulps);
if was_resynced {
let drift = (new_acc - reference_q).abs();
if drift > max_observed_drift {
max_observed_drift = drift;
}
accumulator = new_acc;
resync_count += 1;
}
}
}
assert!(
max_observed_drift <= config.max_drift_ulps,
"post-resync drift {} exceeds max_drift_ulps {}",
max_observed_drift,
config.max_drift_ulps
);
let expected_min_resyncs = (N as u32) / config.period;
assert!(
resync_count >= expected_min_resyncs.saturating_sub(1),
"too few resyncs: got {}, expected at least {}",
resync_count,
expected_min_resyncs
);
}
#[test]
fn decimation_accumulator_standalone_exact() {
let mut acc = DecimationAccumulator::new(500);
let mut fires = 0usize;
for i in 0..10_000usize {
let norm = synthetic_norm(i);
if acc.push(norm).is_some() {
fires += 1;
}
}
assert_eq!(fires, 10_000 / 500, "standalone accumulator epoch count");
}