code wiki / (root) / nx_qc_spc.nx

nx_qc_spc.nx source

↩ module page · 111 lines · 3776 B

1// nx_qc_spc.nx -- FOOD-SCIENCE SUITE / QUALITY CONTROL rung. Statistical 2// process control for a production line: Shewhart X-bar / R control charts, 3// process capability (Cp / Cpk), and proximate-analysis conservation + 4// Kjeldahl protein. Turns "looks fine" into a measured, in-/out-of-control 5// verdict and a capability index. 6// 7// INTEGER-EXACT via the range method: sigma is estimated as Rbar/d2 using 8// the tabulated Shewhart constants (x1000), so NO square root is needed. 9// Control limits carried in milli-units for precision; Cp/Cpk x1000. 10// 11// X-bar: UCL/LCL = Xbarbar +/- A2 * Rbar 12// R: UCL = D4 * Rbar, LCL = D3 * Rbar 13// Cp = (USL-LSL)/(6 sigma), sigma = Rbar/d2 14// Cpk = min(USL-mean, mean-LSL)/(3 sigma) (capable if Cpk >= 1.33) 15// 16// THE exceed: an out-of-control point and a capability index are COMPUTED 17// from the subgroup ranges, not eyeballed; and proximate composition is 18// conserved to 100% by construction. 19// 20// grounded: shewhart_control_charts + astm_process_capability_cpk 21// + kjeldahl_nitrogen_to_protein_6.25 22// genealogy_id: statistical_process_control + nishi_food_science_suite 23 24import "nx_syscalls.nx" 25const QC_MAGIC_2282: i64 = 2282 26const QC_MAGIC_2114: i64 = 2114 27const QC_MAGIC_2059: i64 = 2059 28const QC_MAGIC_2326: i64 = 2326 29 30const QC_CAPABLE_CPK_MILLI: i64 = 1330 // Cpk >= 1.33 = capable 31const QC_KJELDAHL_FACTOR_X100: i64 = 625 // general N->protein factor 6.25 32 33// ===== Shewhart constants (x1000) for subgroup size n ============= 34 35func qc_a2(n: i64) -> i64 { 36 if n == 4 { return 729 } 37 if n == 5 { return 577 } 38 return 577 39} 40func qc_d3(n: i64) -> i64 { 41 return 0 // 0 for n <= 6 42} 43func qc_d4(n: i64) -> i64 { 44 if n == 4 { return QC_MAGIC_2282 } 45 if n == 5 { return QC_MAGIC_2114 } 46 return QC_MAGIC_2114 47} 48func qc_d2(n: i64) -> i64 { 49 if n == 4 { return QC_MAGIC_2059 } 50 if n == 5 { return QC_MAGIC_2326 } 51 return QC_MAGIC_2326 52} 53 54// ===== X-bar / R control limits (milli-units) ===================== 55 56func qc_xbar_ucl_milli(xbarbar: i64, a2: i64, rbar: i64) -> i64 { 57 return xbarbar * 1000 + a2 * rbar 58} 59func qc_xbar_lcl_milli(xbarbar: i64, a2: i64, rbar: i64) -> i64 { 60 return xbarbar * 1000 - a2 * rbar 61} 62 63// Is a subgroup mean x (base units) within the control limits? 64func qc_in_control(x: i64, ucl_milli: i64, lcl_milli: i64) -> i64 { 65 let xm: i64 = x * 1000 66 if xm > ucl_milli { return 0 } 67 if xm < lcl_milli { return 0 } 68 return 1 69} 70 71func qc_r_ucl_milli(d4: i64, rbar: i64) -> i64 { 72 return d4 * rbar 73} 74 75// ===== Process capability (x1000) ================================= 76 77func qc_cp_milli(usl: i64, lsl: i64, d2: i64, rbar: i64) -> i64 { 78 if rbar <= 0 { return 0 } 79 return (usl - lsl) * d2 / (6 * rbar) 80} 81 82func qc_cpk_milli(usl: i64, lsl: i64, mean: i64, d2: i64, rbar: i64) -> i64 { 83 if rbar <= 0 { return 0 } 84 var a: i64 = usl - mean 85 let b: i64 = mean - lsl 86 if b < a { a = b } 87 return a * d2 / (3 * rbar) 88} 89 90func qc_is_capable(cpk_milli: i64) -> i64 { 91 if cpk_milli >= QC_CAPABLE_CPK_MILLI { return 1 } 92 return 0 93} 94 95// ===== Proximate analysis + Kjeldahl ============================== 96 97// Carbohydrate by difference: 100 - (moisture + protein + fat + ash). 98func qc_carb_by_difference(moist: i64, protein: i64, fat: i64, ash: i64) -> i64 { 99 return 100 - moist - protein - fat - ash 100} 101 102// Proximate fractions must conserve to 100%. 103func qc_proximate_conserves(moist: i64, protein: i64, fat: i64, ash: i64, carb: i64) -> i64 { 104 if moist + protein + fat + ash + carb == 100 { return 1 } 105 return 0 106} 107 108// Kjeldahl: crude protein % = nitrogen % x 6.25 (nitrogen given x10). 109func qc_protein_from_nitrogen(nitrogen_x10: i64) -> i64 { 110 return nitrogen_x10 * QC_KJELDAHL_FACTOR_X100 / 100 111}