use std::f64::consts::PI;
use json::{JsonValue, object};
use log::info;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Pa {
pub data_whole: Vec<f64>,
data: Vec<f64>,
data_groups: Vec<Vec<f64>>,
pub total: f64,
pub center_value: f64,
pub usl: f64,
pub lsl: f64,
pub std_dev_zt: f64,
pub std_dev_zn: f64,
pub std_dev_zn_data: Vec<f64>,
pub average_zn: f64,
pub average_zt: f64,
pub pp: f64,
pub ppl: f64,
pub ppu: f64,
pub ppk: f64,
pub cpk: f64,
pub cp: f64,
pub cpu: f64,
pub cpl: f64,
pub ppm: f64,
pub defects: f64,
pub offset_center: f64,
pub ca: f64,
pub scv: f64,
pub max_value: f64,
pub min_value: f64,
pub avg_r: Vec<f64>,
pub group_count: usize,
pub average_zn_data: Vec<f64>,
pub range_zn_data: Vec<f64>,
pub range_zn: f64,
}
impl Pa {
pub fn new(mut data: Vec<f64>, usl: f64, lsl: f64, mut group_count: usize, types: bool) -> Pa {
let data_whole = data.clone();
if group_count == 0 {
group_count = data.len().to_string().parse::<f64>().unwrap().sqrt() as usize;
}
if !types {
group_count = 0;
}
let total = data_whole.len() as f64;
let max_value = data_whole.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
let min_value = data_whole.iter().cloned().fold(f64::INFINITY, f64::min);
let center_value = (max_value + min_value) / 2.0;
let filtered_records: Vec<f64> = data_whole.clone().into_iter()
.filter(|&x| x > usl || x < lsl)
.collect::<Vec<f64>>();
let defects = filtered_records.len() as f64;
let mut average_zt = data_whole.iter().sum::<f64>() / data_whole.clone().len() as f64;
average_zt = format!("{:.4}", average_zt).parse::<f64>().unwrap();
let std_dev_zt = standard_deviation(data_whole.clone(), average_zt);
let mut data_groups = vec![];
let mut range_zn_data = vec![];
let mut average_zn_data = vec![];
let mut std_dev_zn_data = vec![];
let mut average_zn = 0.0;
let mut range_zn = 0.0;
let mut std_dev_zn = 0.0;
let mut variance_list = vec![];
if group_count > 0 {
data_groups = data_whole.chunks(group_count)
.map(|chunk| {
let group = chunk.to_vec();
let max_value = group.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
let min_value = group.iter().cloned().fold(f64::INFINITY, f64::min);
range_zn_data.push(max_value - min_value);
let average = group.iter().sum::<f64>() / group.len() as f64;
average_zn_data.push(average);
let subgroup_variance = group.iter().map(|&x| (x - average).powi(2)).sum::<f64>() / (group.len() - 1) as f64;
std_dev_zn_data.push(subgroup_variance.sqrt());
variance_list.push(subgroup_variance);
group
}).collect::<Vec<Vec<f64>>>();
range_zn = range_zn_data.iter().sum::<f64>() / range_zn_data.len() as f64;
range_zn = format!("{:.4}", range_zn).parse::<f64>().unwrap();
average_zn = average_zn_data.iter().sum::<f64>() / average_zn_data.len() as f64;
average_zn = format!("{:.4}", average_zn).parse::<f64>().unwrap();
let total_dof = data_groups.iter().map(|n| (n.len() - 1) as f64).sum::<f64>();
let c4_value = c4(total_dof as usize + 1);
let within_group_variance = variance_list.iter().sum::<f64>() / variance_list.len() as f64;
std_dev_zn = within_group_variance.sqrt();
std_dev_zn = format!("{:.5}", std_dev_zn).parse::<f64>().unwrap();
}
Self {
data_whole,
data: data.clone(),
average_zn,
range_zn,
total,
usl,
lsl,
std_dev_zt,
std_dev_zn,
pp: 0.0,
ppl: 0.0,
ppu: 0.0,
ppk: 0.0,
cpk: 0.0,
cp: 0.0,
cpu: 0.0,
cpl: 0.0,
ppm: 0.0,
defects,
offset_center: 0.0,
ca: 0.0,
scv: 0.0,
max_value,
min_value,
avg_r: vec![],
group_count,
average_zt,
center_value,
data_groups,
std_dev_zn_data,
average_zn_data,
range_zn_data,
}
}
pub fn ca(&mut self) {
if self.ca != 0.0 {
return;
}
self.scv = (self.usl + self.lsl) / 2.0;
self.offset_center = (self.scv - self.average_zn).abs();
self.ca = self.offset_center / ((self.usl - self.lsl) / 2.0);
self.ca = format!("{:.3}", self.ca).parse::<f64>().unwrap();
}
pub fn cpk(&mut self) {
if self.cpk != 0.0 {
return;
}
self.cp();
self.ca();
let cpk = f64::min(self.cpu, self.cpl);
self.cpk = format!("{:.3}", cpk).parse::<f64>().unwrap();
}
pub fn cpk_desc(&mut self) -> (&'static str, &'static str) {
self.cpk();
return match self.cpk {
2.0.. => {
("A++", "过程非常稳定,质量控制良好,可考虑降低成本。")
}
1.67..=2.0 => {
("A+", "质量控制良好,过程基本稳定,但仍有改进的潜力。")
}
1.33..=1.67 => {
("A", "过程基本稳定,但存在改进的空间,质量控制较为良好。")
}
1.00..=1.33 => {
("B", "过程接近边界,质量控制需要改进,但可能仍能满足一些标准。")
}
0.67..=1.00 => {
("C", "过程不稳定,质量控制问题严重,需要立即调整和改进。")
}
_ => ("D", "不可接受,其能力太差,应考虑重新整改设计制程。")
};
}
pub fn ppm(&mut self) {
if self.ppm != 0.0 {
return;
}
self.ppm = (self.defects / self.total) * 1_000_000.0;
self.ppm = format!("{:.0}", self.ppm).parse::<f64>().unwrap();
}
pub fn cp(&mut self) {
if self.cp != 0.0 {
return;
}
self.cp = (self.usl - self.lsl) / (6.0 * self.std_dev_zn);
if self.average_zn >= self.usl {
self.cpu = 0.0
} else {
self.cpu = (self.usl - self.average_zn) / (3.0 * self.std_dev_zn)
}
if self.average_zn <= self.lsl {
self.cpl = 0.0
} else {
self.cpl = (self.average_zn - self.lsl) / (3.0 * self.std_dev_zn)
}
self.cp = format!("{:.3}", self.cp).parse::<f64>().unwrap();
self.cpu = format!("{:.3}", self.cpu).parse::<f64>().unwrap();
self.cpl = format!("{:.3}", self.cpl).parse::<f64>().unwrap();
}
pub fn cp_desc(&mut self) -> ((f64, &'static str, &'static str), (f64, &'static str, &'static str), (f64, &'static str, &'static str)) {
self.cp();
let cp = match self.cp {
2.0.. => {
(self.cp, "A++", "过程非常稳定,质量控制良好,可考虑降低成本。")
}
1.67..=2.0 => {
(self.cp, "A+", "质量控制良好,过程基本稳定,但仍有改进的潜力。")
}
1.33..=1.67 => {
(self.cp, "A", "过程基本稳定,但存在改进的空间,质量控制较为良好。")
}
1.00..=1.33 => {
(self.cp, "B", "过程接近边界,质量控制需要改进,但可能仍能满足一些标准。")
}
0.67..=1.00 => {
(self.cp, "C", "过程不稳定,质量控制问题严重,需要立即调整和改进。")
}
_ => (self.cp, "D", "不可接受,其能力太差,应考虑重新整改设计制程。")
};
let cpu = match self.cpu {
2.0.. => {
(self.cpu, "A++", "过程非常稳定,质量控制良好,可考虑降低成本。")
}
1.67..=2.0 => {
(self.cpu, "A+", "质量控制良好,过程基本稳定,但仍有改进的潜力。")
}
1.33..=1.67 => {
(self.cpu, "A", "过程基本稳定,但存在改进的空间,质量控制较为良好。")
}
1.00..=1.33 => {
(self.cpu, "B", "过程接近边界,质量控制需要改进,但可能仍能满足一些标准。")
}
0.67..=1.00 => {
(self.cpu, "C", "过程不稳定,质量控制问题严重,需要立即调整和改进。")
}
_ => (self.cpu, "D", "不可接受,其能力太差,应考虑重新整改设计制程。")
};
let cpl = match self.cpl {
2.0.. => {
(self.cpl, "A++", "过程非常稳定,质量控制良好,可考虑降低成本。")
}
1.67..=2.0 => {
(self.cpl, "A+", "质量控制良好,过程基本稳定,但仍有改进的潜力。")
}
1.33..=1.67 => {
(self.cpl, "A", "过程基本稳定,但存在改进的空间,质量控制较为良好。")
}
1.00..=1.33 => {
(self.cpl, "B", "过程接近边界,质量控制需要改进,但可能仍能满足一些标准。")
}
0.67..=1.00 => {
(self.cpl, "C", "过程不稳定,质量控制问题严重,需要立即调整和改进。")
}
_ => (self.cpl, "D", "不可接受,其能力太差,应考虑重新整改设计制程。")
};
return (cpu, cp, cpl);
}
pub fn normal_distribution_plot(&mut self) -> Vec<Vec<f64>> {
let mut list = vec![];
list.push(vec![self.scv - self.std_dev_zt * 3.0, self.scv - self.std_dev_zt * 2.0]);
list.push(vec![self.scv - self.std_dev_zt * 2.0, self.scv - self.std_dev_zt * 1.0]);
list.push(vec![self.scv - self.std_dev_zt * 1.0, self.scv]);
list.push(vec![self.scv, self.scv + self.std_dev_zt * 1.0]);
list.push(vec![self.scv + self.std_dev_zt * 1.0, self.scv + self.std_dev_zt * 2.0]);
list.push(vec![self.scv + self.std_dev_zt * 2.0, self.scv + self.std_dev_zt * 3.0]);
let mut counts = vec![0.0; list.len()];
for &value in self.data.iter() {
for (index, item) in list.iter().enumerate() {
if value >= item[0].clone() && value < item[1] {
counts[index] += 1.0;
break;
}
}
}
return list;
}
pub fn xbar_r(&mut self) -> JsonValue {
let x_ucl = self.average_zn + a2(self.group_count) * self.range_zn;
let x_ucl = format!("{:.3}", x_ucl).parse::<f64>().unwrap();
let x_lcl = self.average_zn - a2(self.group_count) * self.range_zn;
let x_lcl = format!("{:.3}", x_lcl).parse::<f64>().unwrap();
let r_ucl = format!("{:.3}", d4(self.group_count) * self.range_zn).parse::<f64>().unwrap();
let r_lcl = 0.00;
object! {
group_count:self.group_count,
usl:self.usl,
lsl:self.lsl,
x_double_bar:self.average_zn,
x_ucl:x_ucl,
x_lcl:x_lcl,
average_zn_data:self.average_zn_data.clone(),
r_double_bar:self.range_zn,
r_ucl:r_ucl,
r_lcl:r_lcl,
range_data: self.range_zn_data.clone()
}
}
pub fn xbar_s(&mut self) -> JsonValue {
let mut std_dev_zn = self.std_dev_zn_data.iter().sum::<f64>() / self.std_dev_zn_data.len() as f64;
std_dev_zn = format!("{:.3}", std_dev_zn).parse::<f64>().unwrap();
if std_dev_zn.is_nan() {
std_dev_zn = 0.0;
}
let x_ucl = self.average_zn + a3(self.group_count) * std_dev_zn;
let x_lcl = self.average_zn - a3(self.group_count) * std_dev_zn;
let x_ucl = format!("{:.3}", x_ucl).parse::<f64>().unwrap();
let x_lcl = format!("{:.3}", x_lcl).parse::<f64>().unwrap();
let s_ucl = b4(self.group_count) * std_dev_zn;
let s_ucl = format!("{:.3}", s_ucl).parse::<f64>().unwrap();
let s_lcl = b3(self.group_count) * std_dev_zn;
object! {
group_count:self.group_count,
usl:self.usl,
lsl:self.lsl,
x_double_bar:self.average_zn,
x_ucl:x_ucl,
x_lcl:x_lcl,
average_zn_data:self.average_zn_data.clone(),
s_double_bar:std_dev_zn,
s_ucl:s_ucl,
s_lcl:s_lcl,
std_dev_zn_data: self.std_dev_zn_data.clone()
}
}
pub fn xbar(&mut self) -> (f64, f64, f64) {
let x_ucl = self.average_zn + a2(self.group_count) * self.range_zn;
let x_ucl = format!("{:.3}", x_ucl).parse::<f64>().unwrap();
let x_lcl = self.average_zn - a2(self.group_count) * self.range_zn;
let x_lcl = format!("{:.3}", x_lcl).parse::<f64>().unwrap();
(self.average_zn, x_ucl, x_lcl)
}
pub fn i_mr(&mut self) -> JsonValue {
object! {
}
}
pub fn u(&mut self) -> (f64, Vec<f64>) {
(self.average_zt.clone(), self.data.clone())
}
pub fn p(&mut self) -> (f64, Vec<f64>) {
let len = self.data.len() as f64;
let p_list = self.data.clone().iter().map(|&x| {
x / len
}).collect::<Vec<f64>>();
let p = p_list.iter().sum::<f64>() / p_list.len() as f64;
(p, p_list)
}
pub fn np(&mut self) -> (f64, f64, Vec<f64>) {
let u6 = self.average_zt + 4.0 * self.std_dev_zt;
(self.average_zt, u6, self.data.clone())
}
fn get_pp(&mut self) {
if self.pp != 0.0 {
return;
}
self.pp = (self.usl - self.lsl) / (6.0 * self.std_dev_zt);
self.pp = format!("{:.3}", self.pp).parse::<f64>().unwrap()
}
fn get_ppl(&mut self) {
if self.ppl != 0.0 {
return;
}
self.ppl = (self.average_zt - self.lsl) / (3.0 * self.std_dev_zt);
self.ppl = format!("{:.3}", self.ppl).parse::<f64>().unwrap()
}
fn get_ppu(&mut self) {
if self.ppu != 0.0 {
return;
}
self.ppu = (self.usl - self.average_zt) / (3.0 * self.std_dev_zt);
self.ppu = format!("{:.3}", self.ppu).parse::<f64>().unwrap()
}
fn get_ppk(&mut self) {
if self.ppk != 0.0 {
return;
}
self.get_ppl();
self.get_ppu();
self.ppk = f64::min(self.ppu, self.ppl);
self.ppk = format!("{:.3}", self.ppk).parse::<f64>().unwrap()
}
pub fn histogram(&mut self) -> JsonValue {
self.get_pp();
self.get_ppl();
self.get_ppu();
self.get_ppk();
self.cp();
self.cpk();
self.ppm();
let bin_width = (self.max_value - self.min_value) / 6.0;
let mut histogram = object! {};
for &value in self.data_whole.iter() {
if histogram[value.to_string()].is_empty() {
histogram[value.to_string()] = 1.0.into();
} else {}
histogram[value.to_string()] = (histogram[value.to_string()].as_f64().unwrap() + 1.0).into();
}
object! {
usl:self.usl,
lsl:self.lsl,
histogram:histogram,
std_dev_zn_data:self.std_dev_zn_data.clone()
}
}
pub fn normal_distribution(&mut self) -> JsonValue {
let mut normal_distribution = object! {};
for item in self.data_whole.clone().iter_mut() {
if normal_distribution[item.clone().to_string().as_str()].is_empty() {
normal_distribution[item.clone().to_string().as_str()] = 1.into();
} else {
normal_distribution[item.clone().to_string().as_str()] = JsonValue::from(normal_distribution[item.clone().to_string().as_str()].clone().to_string().parse::<i32>().unwrap() + 1);
}
}
object! {
usl:self.usl,
lsl:self.lsl,
min:self.min_value,
max:self.max_value,
std_dev_zt:self.std_dev_zt,
average_zt:self.average_zt,
normal_distribution:normal_distribution,
}
}
}
fn standard_deviation(data: Vec<f64>, mean: f64) -> f64 {
let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (data.len() as f64 - 1.0);
format!("{:.5}", variance.sqrt()).parse::<f64>().unwrap()
}
fn a2(len: usize) -> f64 {
match len {
2 => 1.880,
3 => 1.023,
4 => 0.729,
5 => 0.577,
6 => 0.483,
7 => 0.149,
8 => 0.373,
9 => 0.337,
10 => 0.308,
11 => 0.285,
12 => 0.266,
13 => 0.249,
14 => 0.235,
15 => 0.223,
16 => 0.212,
17 => 0.203,
18 => 0.194,
19 => 0.187,
20 => 0.180,
21 => 0.173,
22 => 0.167,
23 => 0.162,
24 => 0.157,
25 => 0.153,
_ => 0.0
}
}
fn a3(len: usize) -> f64 {
match len {
2 => 2.659,
3 => 1.954,
4 => 1.628,
5 => 1.427,
6 => 1.287,
7 => 1.182,
8 => 1.099,
9 => 1.032,
10 => 0.975,
11 => 0.927,
12 => 0.886,
13 => 0.850,
14 => 0.817,
15 => 0.789,
16 => 0.763,
17 => 0.739,
18 => 0.718,
19 => 0.698,
20 => 0.680,
_ => 0.0
}
}
fn b3(len: usize) -> f64 {
match len {
2 => 0.0,
3 => 0.0,
4 => 0.0,
5 => 0.0,
6 => 0.03,
7 => 0.118,
8 => 0.185,
9 => 0.239,
10 => 0.284,
11 => 0.321,
12 => 0.354,
13 => 0.382,
14 => 0.406,
15 => 0.428,
16 => 0.448,
17 => 0.446,
18 => 0.482,
19 => 0.497,
20 => 0.510,
_ => 0.0
}
}
fn b4(len: usize) -> f64 {
match len {
2 => 3.267,
3 => 2.568,
4 => 2.266,
5 => 2.089,
6 => 1.970,
7 => 1.882,
8 => 1.815,
9 => 1.761,
10 => 1.716,
11 => 1.679,
12 => 1.646,
13 => 1.618,
14 => 1.594,
15 => 1.572,
16 => 1.552,
17 => 1.534,
18 => 1.518,
19 => 1.503,
20 => 1.490,
_ => 0.0
}
}
fn c4(len: usize) -> f64 {
match len {
2 => 0.79785,
3 => 0.87153,
4 => 0.905763,
5 => 0.925222,
6 => 0.937892,
7 => 0.946837,
8 => 0.953503,
9 => 0.958669,
10 => 0.962793,
11 => 0.966163,
12 => 0.968968,
13 => 0.971341,
14 => 0.973375,
15 => 0.975137,
16 => 0.976679,
17 => 0.978039,
18 => 0.979249,
19 => 0.980331,
20 => 0.981305,
21 => 0.982187,
22 => 0.982988,
23 => 0.98372,
24 => 0.984391,
25 => 0.985009,
26 => 0.985579,
27 => 0.986107,
28 => 0.986597,
29 => 0.987054,
30 => 0.98748,
31 => 0.987878,
32 => 0.988252,
33 => 0.988603,
34 => 0.988934,
35 => 0.989246,
36 => 0.98954,
37 => 0.989819,
38 => 0.990083,
39 => 0.990333,
40 => 0.990571,
41 => 0.990797,
42 => 0.991013,
43 => 0.991218,
44 => 0.991415,
45 => 0.991602,
46 => 0.991782,
47 => 0.991953,
48 => 0.992118,
49 => 0.992276,
50 => 0.992427,
51 => 0.992573,
52 => 0.992713,
53 => 0.992848,
54 => 0.992978,
55 => 0.993103,
56 => 0.993224,
57 => 0.99334,
58 => 0.993452,
59 => 0.993561,
60 => 0.993666,
61 => 0.993767,
62 => 0.993866,
63 => 0.993961,
64 => 0.994053,
65 => 0.994142,
66 => 0.994229,
67 => 0.994313,
68 => 0.994395,
69 => 0.994474,
70 => 0.994551,
71 => 0.994626,
72 => 0.994699,
73 => 0.994769,
74 => 0.994838,
75 => 0.994905,
76 => 0.99497,
77 => 0.995034,
78 => 0.995096,
79 => 0.995156,
80 => 0.995215,
81 => 0.995272,
82 => 0.995328,
83 => 0.995383,
84 => 0.995436,
85 => 0.995489,
86 => 0.995539,
87 => 0.995589,
88 => 0.995638,
89 => 0.995685,
90 => 0.995732,
91 => 0.995777,
92 => 0.995822,
93 => 0.995865,
94 => 0.995908,
95 => 0.995949,
96 => 0.99599,
97 => 0.996030,
98 => 0.996069,
99 => 0.996108,
100 => 0.996145,
101 => 0.996182,
102 => 0.996218,
103 => 0.996253,
104 => 0.996288,
105 => 0.996322,
106 => 0.996356,
107 => 0.996389,
108 => 0.996421,
109 => 0.996452,
110 => 0.996483,
111 => 0.996514,
112 => 0.996544,
113 => 0.996573,
114 => 0.996602,
115 => 0.996631,
116 => 0.996658,
117 => 0.996686,
118 => 0.996713,
_ => 0.0,
}
}
fn d2(len: usize) -> f64 {
match len {
2 => 1.128,
3 => 1.693,
4 => 2.059,
5 => 2.326,
6 => 2.534,
7 => 2.704,
8 => 2.847,
9 => 2.97,
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.64,
19 => 3.689,
20 => 3.735,
21 => 3.778,
22 => 3.819,
23 => 3.858,
24 => 3.895,
25 => 3.931,
_ => 0.0,
}
}
fn d3(len: usize) -> f64 {
match len {
2 => 0.8525,
3 => 0.8884,
4 => 0.8798,
5 => 0.8641,
6 => 0.848,
7 => 0.8332,
8 => 0.8198,
9 => 0.8078,
10 => 0.7971,
11 => 0.7873,
12 => 0.7785,
13 => 0.7704,
14 => 0.763,
15 => 0.7562,
16 => 0.7499,
17 => 0.7441,
18 => 0.7386,
19 => 0.7335,
20 => 0.7287,
21 => 0.7242,
22 => 0.7199,
23 => 0.7159,
24 => 0.7121,
25 => 0.7084,
_ => 0.0,
}
}
fn d4(len: usize) -> f64 {
match len {
2 => 3.267,
3 => 2.574,
4 => 2.282,
5 => 2.114,
6 => 2.004,
7 => 1.924,
8 => 1.864,
9 => 1.816,
10 => 1.777,
11 => 1.744,
12 => 1.717,
13 => 1.693,
14 => 1.672,
15 => 1.653,
16 => 1.637,
17 => 1.622,
18 => 1.608,
19 => 1.597,
20 => 1.585,
21 => 1.575,
22 => 1.566,
23 => 1.557,
24 => 1.548,
25 => 1.541,
_ => 0.0
}
}
#[test]
fn test() {
let cp = (10.0 - 8.0) / (6.0 * 0.5);
let cp = format!("{:.3}", cp).parse::<f64>().unwrap();
assert_eq!(cp, 0.667)
}
#[test]
fn ppm_test() {
let cp = (10.0 - 8.0) / (6.0 * 0.5);
let cp = format!("{:.3}", cp).parse::<f64>().unwrap();
assert_eq!(cp, 0.667)
}