use blr_active::{
CalibrationSession, IterationOutcome, NoiseCalibrationSession, PrecisionLevel, SessionConfig,
};
use blr_core::noise_estimation::{NoiseEstimate, SensorType};
fn true_sensor(x: f64) -> f64 {
0.5 * x + 0.1 * x * x
}
fn noisy_sensor(x: f64, noise_std: f64, rng_state: &mut u64) -> f64 {
*rng_state = rng_state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
let noise = noise_std * (*rng_state as i64 as f64) / (i64::MAX as f64);
true_sensor(x) + noise
}
fn main() {
let sigma_true = 0.02_f64;
let mut rng: u64 = 0xcafe_dead_beef_1234;
println!("=== blr-active Quick Start ===\n");
let noise_est = NoiseEstimate {
point_estimate: sigma_true,
lower_bound: sigma_true * 0.9,
upper_bound: sigma_true * 1.1,
confidence: "stable".to_string(),
};
println!(" Estimated noise std: {:.4}", noise_est.point_estimate);
println!(" Confidence: {}", noise_est.confidence);
let mut noise_session = NoiseCalibrationSession::new(SensorType::Hall, noise_est);
println!("\n Available precision tiers:");
for tier in noise_session.precision_tiers.iter() {
println!(
" {:?} target std = {:.4} (~{} samples est.)",
tier.level, tier.absolute_tolerance, tier.estimated_samples
);
}
noise_session
.set_goal(PrecisionLevel::Moderate)
.expect("Moderate should be feasible for this sensor");
let al_config = noise_session
.to_active_learning_config()
.expect("should produce valid AL config after goal is set");
println!(
"\n Selected: Moderate — target std = {:.4}",
al_config.target_std
);
println!("\nPhase 1–3: Active learning");
let feature_fn = |x: f64| vec![1.0_f64, x, x * x];
let feature_dim = 3;
let session_config = SessionConfig {
target_precision: al_config.target_std,
max_iterations: 40,
top_k: 1,
input_range: (0.0, 3.0),
grid_resolution: 50,
..SessionConfig::default()
};
let mut session = CalibrationSession::new(session_config, feature_fn, feature_dim);
println!(" Seeding with 8 initial measurements...");
for i in 0..8 {
let x = 0.0 + 3.0 * (i as f64) / 7.0;
let y = noisy_sensor(x, sigma_true, &mut rng);
session.add_measurement(x, y);
}
let mut final_std = f64::INFINITY;
loop {
match session.next_iteration() {
IterationOutcome::RecommendNext(recs) => {
let x = recs[0].input_value;
let y = noisy_sensor(x, sigma_true, &mut rng);
println!(
" Iter {:2} N={:3} measure at x={:.3} y={:.4}",
session.iteration,
session.sample_count(),
x,
y
);
session.add_measurement(x, y);
}
IterationOutcome::PrecisionMet => {
if let Some(last) = session.precision_history.last() {
final_std = last.percentile_95_std;
}
println!("\n ✓ Precision goal met!");
break;
}
IterationOutcome::NoiseFloorHit(floor) => {
println!("\n ✗ Noise floor hit at {:.4} — stopping.", floor);
break;
}
IterationOutcome::MaxIterationsReached => {
println!("\n ✗ Max iterations reached.");
break;
}
IterationOutcome::FitError(e) => {
println!(" Fit error (need more data first): {}", e);
}
}
}
println!("\nPhase 3: Summary");
println!(" Total measurements: {}", session.sample_count());
println!(" Iterations: {}", session.iteration);
if final_std.is_finite() {
println!(
" Final precision std: {:.4} (target: {:.4})",
final_std, al_config.target_std
);
}
println!("\nDone. See `cargo run --example multi_sensor_workflow` for multi-sensor demo.");
}