///|
pub struct CapabilityExtended {
cp : Double
cpk : Double
cpu : Double
cpl : Double
ppm_upper : Double
ppm_lower : Double
yield_rate : Double
sigma_level : Double
capable : Bool
} derive(Debug, ToJson)
///|
fn safe_probability(value : Double) -> Double {
if value < 0.0 {
0.0
} else if value > 1.0 {
1.0
} else {
value
}
}
///|
pub fn ppm_from_rate(rate : Double) -> Double {
safe_probability(rate) * 1000000.0
}
///|
pub fn yield_from_ppm(ppm : Double) -> Double {
safe_probability(1.0 - ppm / 1000000.0)
}
///|
pub fn sigma_from_yield(yield_rate : Double) -> Double {
let y = safe_probability(yield_rate)
if y <= 0.0 {
0.0
} else if y >= 1.0 {
6.0
} else {
0.5 + 2.0 * y
}
}
///|
pub fn capability_extended(
mean~ : Double,
deviation~ : Double,
lower~ : Double,
upper~ : Double,
target~ : Double,
threshold~ : Double,
) -> CapabilityExtended {
if deviation <= 0.0 || upper <= lower {
return {
cp: 0.0,
cpk: 0.0,
cpu: 0.0,
cpl: 0.0,
ppm_upper: 0.0,
ppm_lower: 0.0,
yield_rate: 0.0,
sigma_level: 0.0,
capable: false,
}
}
let cp = (upper - lower) / (6.0 * deviation)
let cpu = (upper - mean) / (3.0 * deviation)
let cpl = (mean - lower) / (3.0 * deviation)
let cpk = cpu.min(cpl)
let ppm_upper = ppm_from_rate(
if mean > upper {
1.0
} else {
(mean - target).max(0.0) / (upper - target).max(0.000001) * 0.001
},
)
let ppm_lower = ppm_from_rate(
if mean < lower {
1.0
} else {
(target - mean).max(0.0) / (target - lower).max(0.000001) * 0.001
},
)
let yield_rate = safe_probability(1.0 - (ppm_upper + ppm_lower) / 1000000.0)
{
cp,
cpk,
cpu,
cpl,
ppm_upper,
ppm_lower,
yield_rate,
sigma_level: sigma_from_yield(yield_rate),
capable: cpk >= threshold,
}
}
///|
pub fn capability_margin(cpk : Double, threshold : Double) -> Double {
cpk - threshold
}
///|
pub fn capability_status(cpk : Double, threshold : Double) -> String {
if cpk >= threshold {
"capable"
} else if cpk >= threshold * 0.8 {
"watch"
} else {
"incapable"
}
}
///|
pub fn one_sided_capability(
mean~ : Double,
deviation~ : Double,
limit~ : Double,
upper~ : Bool,
) -> Double {
if deviation <= 0.0 {
0.0
} else if upper {
(limit - mean) / (3.0 * deviation)
} else {
(mean - limit) / (3.0 * deviation)
}
}
///|
pub fn capability_confidence_margin(
deviation : Double,
sample_count : Int,
) -> Double {
if sample_count <= 1 {
0.0
} else {
1.96 * deviation / sample_count.to_double().sqrt()
}
}
///|
pub fn observed_yield(
values : Array[Double],
lower : Double,
upper : Double,
) -> Double {
if values.length() == 0 {
return 0.0
}
let mut good = 0
for value in values {
if value >= lower && value <= upper {
good += 1
}
}
good.to_double() / values.length().to_double()
}
///|
pub fn nonconformance_ppm(
values : Array[Double],
lower : Double,
upper : Double,
) -> Double {
ppm_from_rate(1.0 - observed_yield(values, lower, upper))
}
///|
pub fn capability_band(cpk : Double) -> Int {
if cpk < 0.67 {
0
} else if cpk < 1.0 {
1
} else if cpk < 1.33 {
2
} else if cpk < 1.67 {
3
} else {
4
}
}