use crate::precision_tiers::PrecisionLevel;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum GoalFeasibility {
Achievable,
Marginal,
Unachievable,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalibrationGoal {
pub precision_level: PrecisionLevel,
pub target_std: f64,
pub estimated_noise: f64,
pub feasibility: GoalFeasibility,
pub message: String,
}
pub fn assess_goal_feasibility(level: PrecisionLevel, sigma_noise: f64) -> CalibrationGoal {
let factor = level.factor();
let target_std = sigma_noise * factor;
let estimated_samples = level.estimated_samples();
let (feasibility, message) = if factor > 1.5 {
(
GoalFeasibility::Achievable,
format!(
"Goal ±{:.4} ({:.1}× noise) is achievable. \
Estimated ~{} samples needed.",
target_std, factor, estimated_samples
),
)
} else if factor >= 0.9 {
(
GoalFeasibility::Marginal,
format!(
"Goal ±{:.4} ({:.1}× noise) is close to the sensor noise floor \
(±{:.4}). Calibration may not converge. \
Estimated ~{} samples; consider a less demanding tier.",
target_std, factor, sigma_noise, estimated_samples
),
)
} else {
(
GoalFeasibility::Unachievable,
format!(
"Goal ±{:.4} ({:.1}× noise) is below the sensor noise floor \
(±{:.4}). This precision is physically impossible — \
choose a less demanding tier.",
target_std, factor, sigma_noise
),
)
};
CalibrationGoal {
precision_level: level,
target_std,
estimated_noise: sigma_noise,
feasibility,
message,
}
}
#[cfg(test)]
mod tests {
use super::*;
const SIGMA: f64 = 0.008;
#[test]
fn test_feasibility_low_is_achievable() {
let goal = assess_goal_feasibility(PrecisionLevel::Low, SIGMA);
assert_eq!(
goal.feasibility,
GoalFeasibility::Achievable,
"Low tier (5.0×) must be Achievable"
);
}
#[test]
fn test_feasibility_moderate_is_achievable() {
let goal = assess_goal_feasibility(PrecisionLevel::Moderate, SIGMA);
assert_eq!(
goal.feasibility,
GoalFeasibility::Achievable,
"Moderate tier (3.0×) must be Achievable"
);
}
#[test]
fn test_feasibility_high_is_marginal() {
let goal = assess_goal_feasibility(PrecisionLevel::High, SIGMA);
assert_eq!(
goal.feasibility,
GoalFeasibility::Marginal,
"High tier (1.5×) must be Marginal (at the 1.5 boundary)"
);
}
#[test]
fn test_feasibility_max_is_marginal() {
let goal = assess_goal_feasibility(PrecisionLevel::Max, SIGMA);
assert_eq!(
goal.feasibility,
GoalFeasibility::Marginal,
"Max tier (1.0×) must be Marginal (< 1.5×, ≥ 0.9×)"
);
}
#[test]
fn test_feasibility_target_std_correct() {
let goal = assess_goal_feasibility(PrecisionLevel::Moderate, SIGMA);
assert!(
(goal.target_std - 0.024).abs() < 1e-10,
"Moderate target = 3.0 × 0.008 = 0.024"
);
}
#[test]
fn test_feasibility_achievable_message_contains_keyword() {
let goal = assess_goal_feasibility(PrecisionLevel::Low, SIGMA);
assert!(
goal.message.contains("achievable"),
"Achievable message must contain 'achievable'"
);
}
#[test]
fn test_feasibility_marginal_message_contains_noise_floor() {
let goal = assess_goal_feasibility(PrecisionLevel::Max, SIGMA);
assert!(
goal.message.contains("noise floor"),
"Marginal message must mention 'noise floor'"
);
}
#[test]
fn test_feasibility_message_contains_sample_estimate() {
let goal = assess_goal_feasibility(PrecisionLevel::Moderate, SIGMA);
assert!(
goal.message.contains("25"),
"Message must include estimated sample count (~25 for Moderate)"
);
}
#[test]
fn test_feasibility_estimated_noise_stored() {
let goal = assess_goal_feasibility(PrecisionLevel::Moderate, SIGMA);
assert!(
(goal.estimated_noise - SIGMA).abs() < 1e-15,
"estimated_noise must equal sigma_noise input"
);
}
}