///|
fn minimum_double(left : Double, right : Double) -> Double {
if left < right {
left
} else {
right
}
}
///|
/// Calculate Cp/Cpk using sample spread plus stated uncertainty.
pub fn capability_indices(
feature~ : Feature,
values~ : Array[Double],
uncertainty~ : Double,
) -> CapabilitySummary {
let spread = sample_stddev(values) + uncertainty.abs()
let width = upper_limit(feature) - lower_limit(feature)
if values.length() == 0 || width <= 0.0 {
{
cp: 0.0,
cpk: 0.0,
adequate: false,
sample_count: values.length(),
uncertainty,
}
} else if spread == 0.0 {
{
cp: 999.0,
cpk: 999.0,
adequate: true,
sample_count: values.length(),
uncertainty,
}
} else {
let cp = width / (6.0 * spread)
let average = mean(values)
let cpu = (upper_limit(feature) - average) / (3.0 * spread)
let cpl = (average - lower_limit(feature)) / (3.0 * spread)
let cpk = minimum_double(cpu, cpl)
{
cp,
cpk,
adequate: cp >= 1.33 && cpk >= 1.33,
sample_count: values.length(),
uncertainty,
}
}
}
///|
/// Return whether a capability summary meets the common 1.33 threshold.
pub fn capability_is_acceptable(summary : CapabilitySummary) -> Bool {
summary.adequate && summary.cp >= 1.33 && summary.cpk >= 1.33
}
///|
/// Return a conservative margin to the nearest capability threshold.
pub fn capability_margin(summary : CapabilitySummary) -> Double {
let cp_margin = summary.cp - 1.33
let cpk_margin = summary.cpk - 1.33
minimum_double(cp_margin, cpk_margin)
}