#![cfg_attr(target_arch = "arm", no_std)]
#![cfg_attr(target_arch = "arm", no_main)]
#[cfg(target_arch = "arm")]
use cortex_m_rt::entry;
#[cfg(target_arch = "arm")]
use cortex_m_semihosting::hprintln;
#[cfg(target_arch = "arm")]
use panic_halt as _;
#[cfg(target_arch = "arm")]
use irithyll_core::drift::ddm::Ddm;
#[cfg(target_arch = "arm")]
use irithyll_core::drift::pht::PageHinkleyTest;
#[cfg(target_arch = "arm")]
use irithyll_core::drift::DriftSignal;
#[cfg(target_arch = "arm")]
fn deterministic_value(centre: f64, jitter: f64, index: u32) -> f64 {
let t = index as f64;
centre + jitter * irithyll_core::math::sin(t * 0.7)
}
#[cfg(target_arch = "arm")]
#[entry]
fn main() -> ! {
hprintln!("irithyll-core Cortex-M0+ drift detection test");
hprintln!("--- DDM ---");
let mut ddm = Ddm::new();
hprintln!(
"DDM created: warn={}, drift={}, min_inst={}",
ddm.warning_level() as u32,
ddm.drift_level() as u32,
ddm.min_instances()
);
let mut ddm_warnings = 0u32;
let mut ddm_drifts = 0u32;
for i in 0..100 {
let value = deterministic_value(0.1, 0.02, i);
let signal = ddm.update(value);
match signal {
DriftSignal::Warning => ddm_warnings += 1,
DriftSignal::Drift => ddm_drifts += 1,
DriftSignal::Stable => {}
}
}
hprintln!(
"DDM phase 1 (normal): warnings={}, drifts={}",
ddm_warnings,
ddm_drifts
);
let mut ddm_phase2_warnings = 0u32;
let mut ddm_phase2_drifts = 0u32;
for i in 0..50 {
let value = deterministic_value(0.8, 0.02, 100 + i);
let signal = ddm.update(value);
match signal {
DriftSignal::Warning => ddm_phase2_warnings += 1,
DriftSignal::Drift => ddm_phase2_drifts += 1,
DriftSignal::Stable => {}
}
}
hprintln!(
"DDM phase 2 (drifted): warnings={}, drifts={}",
ddm_phase2_warnings,
ddm_phase2_drifts
);
if ddm_phase2_drifts > 0 {
hprintln!("[OK] DDM detected drift after shift");
} else if ddm_phase2_warnings > 0 {
hprintln!("[WARN] DDM detected warning but not drift (short baseline)");
} else {
hprintln!("[INFO] DDM did not trigger on short sequence (expected with 100+50 samples)");
}
hprintln!("--- DDM extended (500 + 200) ---");
let mut ddm2 = Ddm::with_params(2.0, 3.0, 30);
for i in 0..500 {
ddm2.update(deterministic_value(0.05, 0.005, i));
}
let mut ddm2_drifts = 0u32;
for i in 0..200 {
let signal = ddm2.update(deterministic_value(0.8, 0.01, 500 + i));
if signal == DriftSignal::Drift {
ddm2_drifts += 1;
}
}
if ddm2_drifts > 0 {
hprintln!("[OK] DDM extended detected {} drift(s)", ddm2_drifts);
} else {
hprintln!("[FAIL] DDM extended did not detect drift");
}
ddm2.reset();
hprintln!("DDM after reset: mean={}", ddm2.estimated_mean() as u32);
hprintln!("--- PageHinkleyTest ---");
let mut pht = PageHinkleyTest::new();
hprintln!(
"PHT created: delta={}, lambda={}",
pht.delta() as u32,
pht.lambda() as u32
);
let mut pht_warnings = 0u32;
let mut pht_drifts = 0u32;
for i in 0..100 {
let value = deterministic_value(0.1, 0.02, i);
let signal = pht.update(value);
match signal {
DriftSignal::Warning => pht_warnings += 1,
DriftSignal::Drift => pht_drifts += 1,
DriftSignal::Stable => {}
}
}
hprintln!(
"PHT phase 1 (normal): warnings={}, drifts={}",
pht_warnings,
pht_drifts
);
let mut pht_phase2_warnings = 0u32;
let mut pht_phase2_drifts = 0u32;
for i in 0..50 {
let value = deterministic_value(0.8, 0.02, 100 + i);
let signal = pht.update(value);
match signal {
DriftSignal::Warning => pht_phase2_warnings += 1,
DriftSignal::Drift => pht_phase2_drifts += 1,
DriftSignal::Stable => {}
}
}
hprintln!(
"PHT phase 2 (drifted): warnings={}, drifts={}",
pht_phase2_warnings,
pht_phase2_drifts
);
if pht_phase2_drifts > 0 {
hprintln!("[OK] PHT detected drift after shift");
} else if pht_phase2_warnings > 0 {
hprintln!("[WARN] PHT detected warning but not drift (short sequence)");
} else {
hprintln!("[INFO] PHT did not trigger on short sequence");
}
hprintln!("--- PHT extended (500 + 200) ---");
let mut pht2 = PageHinkleyTest::with_params(0.005, 50.0);
for i in 0..500 {
pht2.update(deterministic_value(0.0, 0.01, i));
}
let mut pht2_drifts = 0u32;
for i in 0..200 {
let signal = pht2.update(deterministic_value(10.0, 0.01, 500 + i));
if signal == DriftSignal::Drift {
pht2_drifts += 1;
}
}
if pht2_drifts > 0 {
hprintln!("[OK] PHT extended detected {} drift(s)", pht2_drifts);
} else {
hprintln!("[FAIL] PHT extended did not detect drift");
}
pht2.reset();
hprintln!(
"PHT after reset: count={}, mean={}",
pht2.count(),
pht2.estimated_mean() as u32
);
hprintln!("--- DriftSignal Display ---");
hprintln!("Stable: {}", DriftSignal::Stable);
hprintln!("Warning: {}", DriftSignal::Warning);
hprintln!("Drift: {}", DriftSignal::Drift);
hprintln!("DRIFT_COMPLETE");
cortex_m_semihosting::debug::exit(cortex_m_semihosting::debug::EXIT_SUCCESS);
loop {}
}
#[cfg(not(target_arch = "arm"))]
fn main() {}