use crate::stats::{stddev, stdevp, variance, variancep};
pub struct Spc {
pub data: Vec<f64>,
pub data_len: usize,
pub group_len: usize,
pub upper: f64,
pub lower: f64,
pub value: f64,
pub max: f64,
pub min: f64,
pub avg: f64,
pub total: f64,
pub group_avg: Vec<f64>,
pub group_range: Vec<f64>,
pub group_range_max: f64,
pub group_range_min: f64,
pub group_data: Vec<Vec<f64>>,
pub avg_r: f64,
pub decimal: usize,
pub cpu: f64,
pub cpl: f64,
pub d2: f64,
pub cp: f64,
pub cpk: f64,
pub cr: f64,
pub stdev: f64,
pub stdevp: f64,
pub var: f64,
pub varp: f64,
pub pp: f64,
pub pr: f64,
pub ppk: f64,
}
impl Spc {
pub fn new(upper: f64, lower: f64, value: f64, array: Vec<f64>, group_len: usize, decimal: usize) -> Self {
Self {
data: array.clone(),
data_len: array.len(),
total: 0.0,
upper,
value,
lower,
max: 0.0,
min: 0.0,
avg: 0.0,
group_len: group_len.clone(),
group_avg: vec![],
group_range: vec![],
group_range_max: 0.0,
group_range_min: 0.0,
group_data: vec![],
avg_r: 0.0,
decimal,
cpu: 0.0,
cpl: 0.0,
d2: d2(group_len),
cp: 0.0,
cpk: 0.0,
cr: 0.0,
stdev: 0.0,
stdevp: 0.0,
var: 0.0,
varp: 0.0,
pp: 0.0,
pr: 0.0,
ppk: 0.0,
}
}
pub fn compute(&mut self) -> &mut Self {
self.max = 0.0;
self.min = self.data[0].to_string().parse::<f64>().unwrap();
let mut group_list = vec![];
let _list: Vec<f64> = self.data.clone().iter().map(|x|
{
let y = x.to_string().parse::<f64>().unwrap();
self.total += y.clone();
if y > *&self.max {
self.max = y.clone();
}
if y < *&self.min {
self.min = y.clone();
}
group_list.push(y.clone());
if group_list.len() == self.group_len {
self.get_group_list_info(group_list.clone());
self.group_data.push(group_list.clone());
group_list = vec![];
}
y.clone()
}
).collect();
if !group_list.is_empty() {
self.get_group_list_info(group_list.clone());
self.group_data.push(group_list.clone());
}
self.group_range_max = self.avg_r * 2.282;
self.group_range_min = 0.0;
self.group_range_max = format!("{0:.1$}", self.group_range_max, self.decimal).parse::<f64>().unwrap();
self.avg = format!("{0:.1$}", self.total / self.data_len as f64, self.decimal).parse::<f64>().unwrap();
self.total = format!("{0:.1$}", self.total, self.decimal).parse::<f64>().unwrap();
self.cpu = (self.upper - self.avg) / (3.0 * (self.avg_r / self.d2));
self.cpu = format!("{0:.1$}", self.cpu, self.decimal).parse::<f64>().unwrap();
self.cpl = (self.avg - self.lower) / (3.0 * (self.avg_r / self.d2));
self.cpl = format!("{0:.1$}", self.cpl, self.decimal).parse::<f64>().unwrap();
self.cpk = self.cpl.min(self.cpu);
self.cp = (self.upper - self.lower) / (6.0 * (self.avg_r / self.d2));
self.cp = format!("{0:.1$}", self.cp, self.decimal).parse::<f64>().unwrap();
self.cr = 6.0 * self.avg_r / self.d2 / (self.upper - self.lower);
self.cr = format!("{0:.1$}", self.cr, self.decimal).parse::<f64>().unwrap();
self.stdev = stddev(self.data.clone());
self.stdev = format!("{0:.1$}", self.stdev, self.decimal).parse::<f64>().unwrap();
self.stdevp = stdevp(self.data.clone());
self.stdevp = format!("{0:.1$}", self.stdevp, self.decimal).parse::<f64>().unwrap();
self.stdevp = stdevp(self.data.clone());
self.stdevp = format!("{0:.1$}", self.stdevp, self.decimal).parse::<f64>().unwrap();
self.pp = (self.upper - self.lower) / (6.0 * self.stdev);
self.pp = format!("{0:.1$}", self.pp, self.decimal).parse::<f64>().unwrap();
self.pr = (6.0 * self.stdev) / (self.upper - self.lower);
self.pr = format!("{0:.1$}", self.pr, self.decimal).parse::<f64>().unwrap();
let ppu = (self.upper - self.avg) / (3.0 * self.stdev);
let ppl = (self.avg - self.lower) / (3.0 * self.stdev);
self.ppk = ppu.min(ppl);
self.ppk = format!("{0:.1$}", self.ppk, self.decimal).parse::<f64>().unwrap();
self.var = variance(self.data.clone());
self.var = format!("{0:.1$}", self.var, self.decimal).parse::<f64>().unwrap();
self.varp = variancep(self.data.clone());
self.varp = format!("{0:.1$}", self.varp, self.decimal).parse::<f64>().unwrap();
self
}
fn get_group_list_info(&mut self, mut group_list: Vec<f64>) {
group_list.sort_by(|a, b| a.partial_cmp(b).unwrap());
let max = group_list.last().unwrap();
let min = group_list.first().unwrap();
let mut range = max - min;
let binding = format!("{0:.1$}", range, self.decimal.clone()).parse::<f64>().unwrap();
range = *&binding;
self.group_range.push(range.clone());
let mut avg_r_total = 0.0;
for item in self.group_range.iter() {
avg_r_total += item;
}
self.avg_r = avg_r_total / self.group_range.len() as f64;
let binding = format!("{0:.1$}", self.avg_r, self.decimal.clone()).parse::<f64>().unwrap();
self.avg_r = binding;
self.group_avg.push(self.avg_r.clone());
}
pub fn cpk_rating_criteria(&self) -> (&'static str, &'static str) {
if self.cpk >= 2.0 {
return ("A++", "特优,可考虑降低成本。");
} else if 1.67 <= self.cpk && self.cpk < 2.0 {
return ("A+", "优,应当保持之。");
} else if 1.33 <= self.cpk && self.cpk < 1.67 {
("A", "良,能力好,状态稳定,但应尽力提升到A+级。")
} else if 1.00 <= self.cpk && self.cpk < 1.33 {
("B", "一般,制程因素稍有变异即有生产不良的危险,应利用各种资源及方法将其提升为A级。")
} else if 0.67 <= self.cpk && self.cpk < 1.00 {
("C", "差,制程不良较多。须提升其能力。")
} else {
("D", "不可接受,其能力太差,应考虑重新整改设计制程。")
}
}
pub fn cp_rating_criteria(&self) -> (&'static str, &'static str) {
if self.cp >= 1.67 {
("A+", "无缺点,可考虑降低成本。")
} else if 1.33 <= self.cp && self.cp <= 1.67 {
("A", "状态良好维持现状。")
} else if 1.00 <= self.cp && self.cp <= 1.33 {
("B", "可以改进为A级。")
} else if 0.67 <= self.cp && self.cp <= 1.00 {
("C", "制程不良较多。须提升能力。")
} else {
("D", "制程能力好差,应考虑重新整改设计制程。")
}
}
}
fn d2(len: usize) -> f64 {
match len {
0..=2 => 1.128,
3 => 1.693,
4 => 2.059,
5 => 2.3250,
6 => 2.534,
7 => 2.704,
8 => 2.847,
9 => 2.970,
10 => 3.078,
11 => 3.173,
12 => 3.258,
13 => 3.336,
14 => 3.407,
15 => 3.472,
16 => 3.532,
17 => 3.588,
18 => 3.640,
19 => 3.689,
20 => 3.735,
21 => 3.778,
22 => 3.819,
23 => 3.858,
24 => 3.895,
25..=29 => 3.931,
30..=34 => 4.086,
35..=39 => 4.213,
40..=44 => 4.322,
45..=49 => 4.415,
50 => 4.498,
55 => 4.572,
60 => 4.639,
65 => 4.699,
70 => 4.755,
75 => 4.806,
80 => 4.854,
85 => 4.898,
90 => 4.939,
95 => 4.978,
100 => 5.015,
_ => 0.0
}
}