- X-bar and R control chart limits
- Cp and Cpk of a turning process
- t-test of a filling machine
- Operating characteristic of a sampling plan
- Pareto chart of PCB defects with DPMO and sigma level
- Parts per million out of tolerance with the error function
- Gauge linearity and bias study from the lab database
- c chart of paint defects per car body
- Two suppliers' surface roughness: Mann-Whitney test
- MTTF, B10 life and reliability of a bearing (Weibull)
X-bar and R control chart limits
Six subgroups of five diameters are measured on a lathe. The script computes the mean and range of each subgroup, then the control limits of the X-bar and R charts.
#1. 6 subgroups of 5 diameters in mm; json load "rx_q_sub" "[[10.02, 9.98, 10.01, 10.00, 9.99], [10.03, 10.01, 9.97, 10.02, 10.00], [9.99, 10.00, 10.02, 9.98, 10.01], [10.01, 10.04, 10.00, 10.02, 10.03], [9.98, 9.99, 10.01, 10.00, 9.97], [10.00, 10.02, 9.99, 10.01, 10.00]]"; #2. Mean and range of each subgroup; -> "[means]" "["; -> "[ranges]" "["; -> "[sep]" ""; json parse_array "rx_q_sub" "/" "[g]" { -> "[means]" (concat [means] [sep] (stat mean [g])); -> "[ranges]" (concat [ranges] [sep] (stat range [g])); -> "[sep]" ","; }; -> "[xbb]" (stat mean (concat [means] "]")); -> "[rb]" (stat mean (concat [ranges] "]")); #3. Control limits with A2 = 0.577 and D4 = 2.114 for n = 5; concat "X-bar chart: CL = " (math round [xbb] 4) ", UCL = " (math round (math calc "[xbb]+0.577*[rb]") 4) ", LCL = " (math round (math calc "[xbb]-0.577*[rb]") 4) " ; R chart: CL = " (math round [rb] 4) ", UCL = " (math round (math calc "2.114*[rb]") 4) ", LCL = 0"
X-bar chart: CL = 10.0033, UCL = 10.0274, LCL = 9.9793 ; R chart: CL = 0.0417, UCL = 0.0881, LCL = 0
- Flag the subgroups outside the limits with
ifin the loop - Estimate sigma as R-bar / d2 with d2 = 2.326
- Apply the Western Electric rules on the series of means
Cp and Cpk of a turning process
A shaft diameter has a tolerance of 25.00 +- 0.05 mm. The script checks the normality of 20 parts, computes Cp and Cpk and the expected nonconforming parts per million.
#1. Shaft diameter, spec 25.00 +- 0.05 mm, 20 parts; -> "[x]" "[25.012, 24.991, 25.004, 25.018, 24.987, 25.009, 24.998, 25.021, 25.003, 24.994, 25.011, 25.006, 24.983, 25.015, 25.000, 24.996, 25.008, 25.013, 24.989, 25.002]"; -> "[lsl]" 24.95; -> "[usl]" 25.05; -> "[m]" (stat mean [x]); -> "[s]" (stat stddev [x]); #2. Normality check, required before Cp and Cpk; json load "rx_q_sw" (stat shapiro [x]); #3. Capability indices and expected nonconforming parts per million; -> "[cp]" (math calc "([usl]-[lsl])/(6*[s])"); -> "[cpk]" (math calc "min([usl]-[m], [m]-[lsl])/(3*[s])"); -> "[ppm]" (math calc (concat "1e6*(" (stat dist_cdf "normal" (concat "[" [m] ", " [s] "]") [lsl]) " + 1 - " (stat dist_cdf "normal" (concat "[" [m] ", " [s] "]") [usl]) ")")); concat "Shapiro p = " (math round (json select "rx_q_sw" /p_value) 3) ", mean = " (math round [m] 4) ", s = " (math round [s] 4) ", Cp = " (math round [cp] 2) ", Cpk = " (math round [cpk] 2) ", expected " (math round_sig [ppm] 2) " ppm"
Shapiro p = 0.926, mean = 25.003, s = 0.0107, Cp = 1.56, Cpk = 1.47, expected 5.8 ppm
- Give a confidence interval on Cpk for 20 parts
- Use
stat percentile0.135 and 99.865 for a non-normal process - Compare two machines with
stat ttest_2
t-test of a filling machine
After a setting change, 12 bottles are weighed against a 500 g target. The script tests whether the mean is off target and gives the 95 % confidence interval of the mean.
#1. Filling machine, target 500 g, 12 bottles weighed after a setting change; -> "[w]" "[501.2, 499.8, 502.1, 500.9, 501.5, 500.4, 502.3, 501.1, 499.9, 501.8, 500.7, 501.6]"; #2. One-sample t-test, H0: mean = 500 g; json load "rx_q_t" (stat ttest_1 [w] 500); #3. 95 percent confidence interval of the true mean; json load "rx_q_ci" (stat conf_interval_mean [w] 0.95); -> "[p]" (json select "rx_q_t" /p_value); concat "t = " (math round (json select "rx_q_t" /t) 2) ", p = " (math round_sig [p] 3) ", mean in [" (math round (json select "rx_q_ci" /lower) 2) ", " (math round (json select "rx_q_ci" /upper) 2) "] g -> " (if (< [p] 0.05) {"machine off target, adjust the setting"} {"no significant shift"})
t = 4.76, p = 0.000594, mean in [500.6, 501.62] g -> machine off target, adjust the setting
- Compare before and after maintenance with
stat ttest_2 - Use
stat ztestwhen the machine sigma is known - Check the legal mean requirement of prepackages
Operating characteristic of a sampling plan
Single sampling plan n = 50, c = 2: the probability of accepting a lot is a binomial tail, written with the regularized incomplete beta function. The script gives the acceptance at AQL 1 %, the producer risk, the LTPD (10 % acceptance) and the probability of a sample with no defective.
#1. Single sampling plan: sample n = 50, accept the lot if at most c = 2 defectives; -> "[n]" 50; -> "[c]" 2; #2. Operating characteristic: Pa of p = P of X <= c = I_1-p of n-c, c+1, regularized incomplete beta; -> "[Pa1]" (math calc "beta_inc([n]-[c], [c]+1, 1-0.01)"); #3. LTPD: defect rate accepted only 10 % of the time; -> "[ltpd]" (num solve "beta_inc(48, 3, 1-p)-0.10" "p" 0.01 0.3); #4. Probability of exactly 0 defective at 1 %, with the beta function; -> "[P0]" (math calc "1/(([n]+1)*beta([n]+1, 1))*0.99^[n]"); concat "Pa at AQL 1 % = " (math round [Pa1] 4) ", producer risk = " (math round (math calc "1-[Pa1]") 4) ", LTPD = " (math round (math calc "100*[ltpd]") 2) " %, P of no defective at 1 % = " (math round [P0] 4)
Pa at AQL 1 % = 0.9862, producer risk = 0.0138, LTPD = 10.3 %, P of no defective at 1 % = 0.605
- Draw the OC curve with
plot function "beta_inc(48, 3, 1-p)" "p" 0 0.15. - Search the smallest n meeting both risks with a
forloop.
Pareto chart of PCB defects with DPMO and sigma level
118 defects were found on 1200 printed circuit boards with 85 opportunities each. Sort the causes by decreasing count, build the bars and the cumulative percentage line of the Pareto chart, and put the DPMO and the short-term sigma level (with the 1.5 sigma shift) in its title.
#1. Defects found on 1200 printed circuit boards, 85 opportunities per board; json load "rx_def" "[{\"cause\": \"solder bridge\", \"n\": 46}, {\"cause\": \"missing part\", \"n\": 12}, {\"cause\": \"cold joint\", \"n\": 31}, {\"cause\": \"wrong polarity\", \"n\": 7}, {\"cause\": \"tombstoning\", \"n\": 18}, {\"cause\": \"scratch\", \"n\": 4}]"; #2. Pareto order: sort the causes by decreasing count; json sort "rx_def" / n DESC; -> "[total]" 0; for (-> "[i]" 0) (< [i] (json count "rx_def" /)) (++ "[i]") {-> "[total]" (+ [total] (json select "rx_def" (concat "/[" [i] "]/n")));}; #3. Bars of the counts and the cumulative percentage line; -> "[names]" "["; -> "[bars]" "["; -> "[cum]" "["; -> "[c]" 0; for (-> "[i]" 0) (< [i] (json count "rx_def" /)) (++ "[i]") { -> "[sep]" (if (> [i] 0) {", "} {""}); -> "[c]" (+ [c] (json select "rx_def" (concat "/[" [i] "]/n"))); -> "[names]" (concat [names] [sep] (+ [i] 1)); -> "[bars]" (concat [bars] [sep] (json select "rx_def" (concat "/[" [i] "]/n"))); -> "[cum]" (concat [cum] [sep] (math round (* 100 (/ [c] [total])) 1)); }; #4. DPMO and short-term sigma level with the 1.5 sigma shift; -> "[dpmo]" (math round (math calc "[total]/(1200*85)*1e6") 0); -> "[sigma]" (math round (+ (stat dist_inv "normal" "[0, 1]" (- 1 (/ [dpmo] 1e6))) 1.5) 2); -> "[title]" (concat "Pareto of defects - first: " (json select "rx_def" "/[0]/cause") " - DPMO " [dpmo] " - sigma level " [sigma]); plot chart (concat "{\"title\": \"" [title] "\", \"x_label\": \"cause rank\", \"y_label\": \"defects / cumulative pct\", \"series\": [{\"name\": \"defects\", \"type\": \"bars\", \"x\": " [names] "], \"y\": " [bars] "]}, {\"name\": \"cumulative pct\", \"type\": \"line\", \"x\": " [names] "], \"y\": " [cum] "]}]}")
The chart is shown in the Plot tab of the editor.
- Keep the vital few: the causes before 80 pct of the cumulative line.
- Follow the defect rate per day with a p chart (limits p +- 3 sqrt of p (1-p) / n).
Parts per million out of tolerance with the error function
A shaft is specified at 25 +- 0.015 mm; the process runs at a mean of 25.004 mm with sigma 0.006 mm. The script computes the fraction above and below the limits with erfc, the total ppm, Cpk and the sigma that would be needed for the six sigma target of 3.4 ppm on the nearest limit.
#1. Specification and process; -> "[usl]" 25.015; -> "[lsl]" 24.985; -> "[mu]" 25.004; -> "[sd]" 0.006; #2. Tails of the normal law with erfc; -> "[pu]" (* 0.5 (math erfc (/ (- [usl] [mu]) (* [sd] (math sqrt 2))))); -> "[pl]" (* 0.5 (math erfc (/ (- [mu] [lsl]) (* [sd] (math sqrt 2))))); -> "[cpk]" (/ (math min (- [usl] [mu]) (- [mu] [lsl])) (* 3 [sd])); #3. z for 3.4 ppm on one side, and the sigma it requires; -> "[z]" (* (math sqrt 2) (math erf_inv (- 1 (* 2 0.0000034)))); concat "above USL: " (math round (* 1000000 [pu]) 0) " ppm, below LSL: " (math round (* 1000000 [pl]) 1) " ppm, total: " (math round (* 1000000 (+ [pu] [pl])) 0) " ppm" [_n_] "Cpk = " (math round [cpk] 3) [_n_] "3.4 ppm needs z = " (math round [z] 3) ", so sigma <= " (math round (/ (- [usl] [mu]) [z]) 5) " mm with this mean"
above USL: 33377 ppm, below LSL: 771 ppm, total: 34147 ppm Cpk = 0.611 3.4 ppm needs z = 4.5, so sigma <= 0.00244 mm with this mean
- Center the process first: compute the ppm with mu = 25.000.
- Compare with
stat dist_cdfon the normal law.
Gauge linearity and bias study from the lab database
Reference parts of 2 to 10 mm were measured with a caliper and the readings stored in the laboratory database (an embedded H2 database here). The script loads the bias versus reference directly from SQL into a linear regression and reports the AIAG linearity, the bias and the significance of the slope.
#1. Lab database: embedded H2 file under tmp; cm set "tuto_p4g_lab" {execute "db.h2.embedded.config.get" "[database]" "./tmp/tuto_p4g_lab/msa" "[user]" "tuto" "[password]" "tuto_pwd" ;}; sql connect "tuto_p4g_s1" {cm get "tuto_p4g_lab";}; sql dml "tuto_p4g_s1" "create table caliper (ref double, bias double)"; sql dml "tuto_p4g_s1" "insert into caliper values (2, 0.012), (2, 0.010), (4, 0.006), (4, 0.008), (6, 0.001), (6, -0.002), (8, -0.006), (8, -0.004), (10, -0.011), (10, -0.013)"; sql disconnect "tuto_p4g_s1"; #2. Regression bias = a + b . reference straight from the query; pa rl load "rx_p4g_lin" "tuto_p4g_lab" "ref" "bias" "select ref, bias from caliper"; #3. AIAG: linearity = abs slope x process variation 0.6 mm; -> "[b]" (pa rl slope "rx_p4g_lin"); -> "[r]" (concat "n = " (pa rl count "rx_p4g_lin") ", bias = " (math round (pa rl intercept "rx_p4g_lin") 4) " " (math round [b] 5) " x ref, r2 = " (math round (pa rl r_square "rx_p4g_lin") 4) ", slope p-value " (if (< (pa rl significance "rx_p4g_lin") 0.001) {"< 0.001";} {pa rl significance "rx_p4g_lin";}) [_n_] "linearity = " (math round (* (math abs [b]) 0.6) 5) " mm, %linearity = " (math round (* 100 (math abs [b])) 2) " %, bias at 6 mm = " (math round (* 1000 (pa rl predict "rx_p4g_lin" 6)) 2) " um"); #4. Close and remove the temporary database; pa rl close "rx_p4g_lin"; cm remove "tuto_p4g_lab"; file delete "tmp/tuto_p4g_lab"; [r]
n = 10, bias = 0.0175 -0.0029 x ref, r2 = 0.9738, slope p-value < 0.001 linearity = 0.00174 mm, %linearity = 0.29 %, bias at 6 mm = 0.1 um
- Add a bias t-test per reference with
stat ttest_1. - Store the study result back in a table with
sql dml.
c chart of paint defects per car body
An inspector counted the paint defects on 20 consecutive car bodies. The script computes the centre line and the Poisson control limits of the c chart, the bodies out of control, the frequency table and the most frequent count.
#1. Defects per body, in production order; -> "[c]" "[3, 5, 2, 4, 6, 3, 2, 12, 4, 3, 5, 1, 4, 3, 2, 6, 4, 3, 5, 3]"; -> "[cb]" (math avg [c]); -> "[ucl]" (math calc "[cb]+3*sqrt([cb])"); -> "[lcl]" (math max 0 (math calc "[cb]-3*sqrt([cb])")); #2. Bodies above the UCL; json load "rx_p4g_c" [c]; -> "[ooc]" ""; for (-> "[i]" 0) (< [i] 20) (++ "[i]") { if (> (json select "rx_p4g_c" (concat "/[" [i] "]")) [ucl]) {-> "[ooc]" (concat [ooc] " #" (+ [i] 1));}; }; json unload "rx_p4g_c"; #3. Distribution of the counts; -> "[f]" (string regexp_replace (string regexp_replace (stat frequency [c]) "\{\"value\": ([0-9]+), \"count\": ([0-9]+)[^}]*\}" "$1:$2") "\s+" ""); concat "c-bar = " [cb] ", UCL = " (math round [ucl] 2) ", LCL = " [lcl] [_n_] "out of control: body" [ooc] [_n_] "sorted: " (math order_int [c]) [_n_] "mode: " (stat mode [c]) ", count:bodies = " [f]
c-bar = 4.0, UCL = 10, LCL = 0 out of control: body #8 sorted: [1,2,2,2,3,3,3,3,3,3,4,4,4,4,5,5,5,6,6,12] mode: [3], count:bodies = [1:1,2:3,3:6,4:4,5:3,6:2,12:1]
- Recompute the limits without body 8 once its cause is found.
- Use a u chart when the inspected area changes from body to body.
Two suppliers' surface roughness: Mann-Whitney test
Ra roughness values of turned parts from two suppliers are skewed, so the quality engineer uses the non-parametric Mann-Whitney U test instead of a t-test, and reports the medians and which supplier is smoother.
#1. Ra in micrometres; -> "[a]" "[0.82, 0.91, 0.78, 1.25, 0.88, 0.85, 1.60, 0.80, 0.95, 0.87]"; -> "[b]" "[1.05, 1.12, 0.98, 1.40, 1.09, 1.21, 0.99, 1.85, 1.15, 1.03]"; #2. Medians and test; -> "[ma]" (stat median [a]); -> "[mb]" (stat median [b]); json load "rx_p4g_mw" (stat mann_whitney [a] [b]); -> "[p]" (json select "rx_p4g_mw" /p_value); -> "[r]" (concat "U = " (json select "rx_p4g_mw" /u) ", p = " (math round_sig [p] 3) " (" (json select "rx_p4g_mw" /method) ")"); json unload "rx_p4g_mw"; #3. Direction and decision; -> "[best]" (if (== (math signum (- [mb] [ma])) 1) {"A";} {"B";}); concat "median A = " [ma] " um, median B = " [mb] " um" [_n_] [r] [_n_] (if (< [p] 0.05) {concat "significant: supplier " [best] " is smoother";} {"no significant difference";})
median A = 0.875 um, median B = 1.105 um U = 17, p = 0.0140 (asymptotic) significant: supplier A is smoother
- Check the skewness first with
stat skewnessandstat shapiro. - Add a third supplier with
stat kruskal.
MTTF, B10 life and reliability of a bearing (Weibull)
Life tests of a bearing gave a Weibull shape beta = 1.8 and a scale eta = 12000 h. The script computes the MTTF and the standard deviation with the Gamma function, the B10 life with log1p, and the reliability at the 5000 h warranty.
#1. Weibull parameters; -> "[beta]" 1.8; -> "[eta]" 12000; #2. Mean and standard deviation of the life; -> "[g1]" (math gamma (+ 1 (/ 1 [beta]))); -> "[g2]" (math gamma (+ 1 (/ 2 [beta]))); -> "[mttf]" (* [eta] [g1]); -> "[sd]" (* [eta] (math sqrt (- [g2] (math power [g1] 2)))); #3. B10: 10 % failed, ln 0.9 = log1p of -0.1; -> "[b10]" (* [eta] (math power (- 0 (math log1p -0.1)) (/ 1 [beta]))); #4. Reliability at the warranty time; -> "[R]" (math calc "exp(-(5000/[eta])^[beta])"); concat "MTTF = " (math round [mttf] 0) " h, sigma = " (math round [sd] 0) " h" [_n_] "B10 life = " (math round [b10] 0) " h" [_n_] "R at 5000 h = " (math round (* 100 [R]) 2) " %, expected returns per 1000 = " (math round (* 1000 (- 1 [R])) 0)
MTTF = 10671 h, sigma = 6135 h B10 life = 3437 h R at 5000 h = 81.32 %, expected returns per 1000 = 187
- Fit beta and eta from failure times with
pa rlon the Weibull plot. - Compute the conditional reliability of a bearing that already ran 3000 h.
