///|
/// Event-level engineering metrics derived from mixed lifetime records.
pub fn mttf(records : Array[LifeObservation]) -> Double {
let failures = records.filter_map(record => {
if record.is_failure() {
Some(record.time)
} else {
None
}
})
if failures.is_empty() {
0.0
} else {
mean(failures)
}
}
///|
pub fn mtbf_from_events(event_times : Array[Double]) -> Double {
if event_times.length() < 2 {
abort("MTBF requires two event times")
}
let intervals = Array::makei(event_times.length() - 1, i => {
event_times[i + 1] - event_times[i]
})
mean(intervals)
}
///|
pub fn failure_fraction(records : Array[LifeObservation]) -> Double {
if records.is_empty() {
return 0.0
}
observed_event_count(records).to_double() / records.length().to_double()
}
///|
pub fn expected_remaining_life(
model : ReliabilityModel,
age : Double,
horizon : Double,
) -> Double {
if age < 0.0 || horizon <= age {
abort("invalid remaining-life interval")
}
let step = (horizon - age) / 400.0
let mut total = 0.0
for i in 0..<400 {
let x0 = age + i.to_double() * step
let x1 = x0 + step
let conditional0 = model.survival(x0) / model.survival(age).max(1.0e-300)
let conditional1 = model.survival(x1) / model.survival(age).max(1.0e-300)
total += (conditional0 + conditional1) * step / 2.0
}
total
}
///|
pub fn percentile_life(
model : ReliabilityModel,
percentiles : Array[Double],
) -> Array[MetricEstimate] {
percentiles.map(p => {
let life = model_quantile(model, p)
metric_estimate(estimate=life, lower=life, upper=life, confidence_level=1.0)
})
}
///|
pub fn life_ratio(
model : ReliabilityModel,
first_probability : Double,
second_probability : Double,
) -> Double {
model_quantile(model, first_probability) /
model_quantile(model, second_probability)
}
///|
pub fn reliability_margin(
model : ReliabilityModel,
mission_time : Double,
target : Double,
) -> Double {
model.survival(mission_time) - target
}
///|
pub fn mission_success_probability(
models : Array[ReliabilityModel],
mission_time : Double,
) -> Double {
series_reliability(models.map(model => model.survival(mission_time)))
}
///|
pub fn downtime_budget_from_availability(
horizon : Double,
target_availability : Double,
) -> Double {
if horizon < 0.0 || target_availability < 0.0 || target_availability > 1.0 {
abort("invalid availability budget")
}
horizon * (1.0 - target_availability)
}