///|
pub struct HealthFlag {
name : String
value : Double
lower : Double
upper : Double
healthy : Bool
} derive(Debug, Eq)
///|
pub fn health_flag(
name : String,
value : Double,
lower : Double,
upper : Double,
) -> HealthFlag {
{ name, value, lower, upper, healthy: value >= lower && value <= upper }
}
///|
pub fn health_flags(
values : Array[(String, Double)],
lower : Double,
upper : Double,
) -> Array[HealthFlag] {
values.map(item => health_flag(item.0, item.1, lower, upper))
}
///|
pub fn healthy_fraction(flags : Array[HealthFlag]) -> Double {
if flags.length() == 0 {
0.0
} else {
Double::from_int(flags.filter(flag => flag.healthy).length()) /
Double::from_int(flags.length())
}
}
///|
pub fn health_is_nominal(flags : Array[HealthFlag]) -> Bool {
flags.length() > 0 && flags.all(flag => flag.healthy)
}
///|
pub fn health_score(flags : Array[HealthFlag]) -> Double {
healthy_fraction(flags) * 100.0
}
///|
pub fn health_margin(flag : HealthFlag) -> Double {
if flag.value < flag.lower {
flag.value - flag.lower
} else if flag.value > flag.upper {
flag.upper - flag.value
} else {
(flag.value - flag.lower).min(flag.upper - flag.value)
}
}
///|
pub fn health_worst_margin(flags : Array[HealthFlag]) -> Double {
if flags.length() == 0 {
0.0
} else {
flags.fold(init=1.0e300, (value, flag) => value.min(health_margin(flag)))
}
}
///|
pub fn health_summary(flags : Array[HealthFlag]) -> String {
"healthy=\{healthy_fraction(flags)},score=\{health_score(flags)},worst_margin=\{health_worst_margin(flags)}"
}
///|
pub fn thermal_health(power_budget : Double, load : Double) -> HealthFlag {
health_flag("power", load, 0.0, power_budget)
}
///|
pub fn attitude_health(error_rad : Double, limit_rad : Double) -> HealthFlag {
health_flag("attitude", error_rad, -limit_rad.abs(), limit_rad.abs())
}
///|
pub fn navigation_health(
position_error_km : Double,
limit_km : Double,
) -> HealthFlag {
health_flag("navigation", position_error_km, 0.0, limit_km.abs())
}
///|
pub fn propulsion_health(
remaining_km_s : Double,
required_km_s : Double,
) -> HealthFlag {
health_flag("propellant", remaining_km_s, required_km_s, 1.0e300)
}
///|
pub fn communication_health(
margin_db : Double,
required_db : Double,
) -> HealthFlag {
health_flag("link", margin_db, required_db, 1.0e300)
}