SPC 统计过程控制
概述
SPC (Statistical Process Control) 用统计方法识别工艺过程是否处于受控状态。与简单的"上下限报警"相比, SPC 通过控制图捕捉偏移趋势、周期性、非随机模式, 能在产品真正超差之前就给出预警。
DarraRT Darra.SPC.Service 内置 X-bar / R / Xmr / CUSUM / EWMA 五种控制图 + Nelson 8 条判异规则 + Cp/Cpk/Pp/Ppk 过程能力计算, 支持直接嵌入 PLC 扫描周期或作为后台服务运行。
适用场景
| 场景 | 控制图 | 采样 |
|---|---|---|
| 批量机加工 (尺寸) | X-bar / R | 每批 5 件 |
| 注塑 / 压铸 (重量) | X-bar / S | 每小时 5 件 |
| 连续过程 (温度/压力) | Xmr / EWMA | 每分钟 1 点 |
| 缓慢漂移 (刀具磨损) | CUSUM | 每件 1 点 |
| 多变量 (复合品质) | Hotelling T² | 每件多维 |
控制图选型决策树
采样方式?
├── 子组 (n>1)
│ └── n=2..10 → X-bar R 图
│ n>10 → X-bar S 图
└── 单点 (n=1)
├── 关心小偏移 → CUSUM
├── 关心平滑趋势 → EWMA
└── 通用 → Xmr 图
架构图
┌── PLC ──────────────┐ ┌── Service ─────────┐
│ 工艺值: D01.weight │──► │ SPC.Service │
│ 工艺值: D01.length │ │ - 控制图计算 │
│ 子组计数: D01.idx │ │ - Nelson 判异 │
│ 测量触发: M10.0 │ │ - Cp/Cpk 能力 │
└──────┬──────────────┘ │ - 报警 / 日志 │
│ └──────┬──────────────┘
│ │
│ ┌──── REST / MQTT ────┘
│ │
▼ ▼
┌──────────────────────────┐
│ <darra-spc-chart> │ ← HMI 控制图
│ <darra-cpk-indicator> │ ← Cpk 能力指数
└──────────────────────────┘
前置条件
- 已标定产品规格限 USL / LSL (工程公差, 不是控制限)
- 历史至少 20-25 个子组用于计算初始控制限
- PLC 每个工艺值有测量完成触发位, 避免在读数变化时采样
控制限计算
X-bar R 图 (子组 n=5)
采用 Shewhart 系数法 (标准 GB/T 17989.2-2005, 对应 ASTM E2587):
CL_X = X̄̄ (总均值)
UCL_X = X̄̄ + A2 * R̄
LCL_X = X̄̄ - A2 * R̄
CL_R = R̄
UCL_R = D4 * R̄
LCL_R = D3 * R̄ (n≤6 时为 0)
系数 (n=5 时): A2=0.577, D3=0, D4=2.114
Xmr 图 (单点)
CL_X = X̄
UCL_X = X̄ + 2.66 * MR̄ (MR̄: 移动极差均值)
LCL_X = X̄ - 2.66 * MR̄
CL_MR = MR̄
UCL_MR = 3.267 * MR̄
FB_SPCMonitor (X-bar R)
FUNCTION_BLOCK FB_SPCMonitor_XbarR
VAR_INPUT
newSample : REAL;
trigger : BOOL; // 测量完成上升沿
subgroupSize : INT := 5;
reset : BOOL; // 重置初始化
END_VAR
VAR_OUTPUT
Xbar : REAL; // 当前子组均值
R : REAL; // 当前子组极差
UCL_X : REAL;
LCL_X : REAL;
UCL_R : REAL;
OutOfControl : BOOL;
NelsonRule : INT; // 违反的 Nelson 规则号 1-8, 0=无
END_VAR
VAR
subgroup : ARRAY[0..19] OF REAL; // 最大 20
idx : INT;
subgroups : ARRAY[0..24] OF STRUCT
Xbar : REAL;
R : REAL;
END_STRUCT;
sgCount : INT;
XbarBar : REAL;
Rbar : REAL;
A2_table : ARRAY[2..10] OF REAL :=
[1.880, 1.023, 0.729, 0.577, 0.483, 0.419, 0.373, 0.337, 0.308];
D4_table : ARRAY[2..10] OF REAL :=
[3.267, 2.574, 2.282, 2.114, 2.004, 1.924, 1.864, 1.816, 1.777];
D3_table : ARRAY[2..10] OF REAL :=
[0.0, 0.0, 0.0, 0.0, 0.0, 0.076, 0.136, 0.184, 0.223];
triggerEdge: R_TRIG;
phase1Done : BOOL; // 前 25 个子组算 Phase I, 定限
END_VAR
triggerEdge(CLK := trigger);
IF triggerEdge.Q THEN
subgroup[idx] := newSample;
idx := idx + 1;
IF idx = subgroupSize THEN
// 子组完成: 计算 Xbar 与 R
VAR sum, mn, mx : REAL; END_VAR
sum := 0.0; mn := subgroup[0]; mx := subgroup[0];
FOR i := 0 TO subgroupSize - 1 DO
sum := sum + subgroup[i];
IF subgroup[i] < mn THEN mn := subgroup[i]; END_IF;
IF subgroup[i] > mx THEN mx := subgroup[i]; END_IF;
END_FOR;
Xbar := sum / INT_TO_REAL(subgroupSize);
R := mx - mn;
// Phase I: 前 25 个子组累积
IF sgCount < 25 THEN
subgroups[sgCount].Xbar := Xbar;
subgroups[sgCount].R := R;
sgCount := sgCount + 1;
IF sgCount = 25 THEN
// 计算 X̄̄ 与 R̄
VAR sXbar, sR : REAL; END_VAR
sXbar := 0.0; sR := 0.0;
FOR i := 0 TO 24 DO
sXbar := sXbar + subgroups[i].Xbar;
sR := sR + subgroups[i].R;
END_FOR;
XbarBar := sXbar / 25.0;
Rbar := sR / 25.0;
UCL_X := XbarBar + A2_table[subgroupSize] * Rbar;
LCL_X := XbarBar - A2_table[subgroupSize] * Rbar;
UCL_R := D4_table[subgroupSize] * Rbar;
phase1Done := TRUE;
END_IF;
END_IF;
// Phase II: 判异
IF phase1Done THEN
IF Xbar > UCL_X OR Xbar < LCL_X THEN
NelsonRule := 1;
OutOfControl := TRUE;
ELSE
// ... 规则 2-8 (需历史子组窗口), 省略代码
NelsonRule := 0;
OutOfControl := FALSE;
END_IF;
END_IF;
idx := 0; // 开始下一个子组
END_IF;
END_IF;
IF reset THEN
idx := 0; sgCount := 0; phase1Done := FALSE;
END_IF;
Nelson 8 条判异规则
| 规则 | 描述 | 含义 |
|---|---|---|
| 1 | 1 点超 ±3σ | 突发异常, 强信号 |
| 2 | 连续 9 点同一侧 | 均值偏移 |
| 3 | 连续 6 点单调上升或下降 | 趋势 (刀具磨损/老化) |
| 4 | 连续 14 点交替 | 周期性 (双机交替/夹具松动) |
| 5 | 连续 3 点中 2 点超 ±2σ | 变化增大 |
| 6 | 连续 5 点中 4 点超 ±1σ | 小幅偏移累积 |
| 7 | 连续 15 点都在 ±1σ 内 | 分层不足 / 过度调整 |
| 8 | 连续 8 点都在 ±1σ 外 | 双峰分布 (混批) |
Nelson 判异通常需要历史子组环形缓冲区 (至少 25 个), 在 Service 侧实现更方便, PLC 只负责触发采样与提供原始子组。
过程能力 Cp / Cpk / Pp / Ppk
过程稳定 (受控) 时才算能力指数。
Cp = (USL - LSL) / (6 * σ̂) (σ̂ 用 R̄/d2 估计, 短期能力)
Cpk = min( (USL - X̄̄) / (3σ̂),
(X̄̄ - LSL) / (3σ̂) )
Pp = (USL - LSL) / (6 * s) (s 用全部数据总体标准差, 长期能力)
Ppk = min( (USL - X̄) / (3s),
(X̄ - LSL) / (3s) )
判级:
| Cpk 值 | 等级 | 对策 |
|---|---|---|
<1.0 | 不合格 | 产品随时可能超差 |
1.0-1.33 | 勉强 | 需要强控制 |
1.33-1.67 | 合格 | 常规管控 |
>1.67 | 优秀 | 可放宽检验频率 |
API
POST /api/spc/register
{
"chart_id": "L1.Part.Weight",
"chart_type": "xbar_r",
"subgroup_size": 5,
"usl": 105.0,
"lsl": 95.0,
"target": 100.0
}
POST /api/spc/sample
{ "chart_id":"L1.Part.Weight", "value":100.2 }
GET /api/spc/state?chart_id=L1.Part.Weight
→ {
"xbar":100.1, "ucl_x":102.3, "lcl_x":97.9,
"cpk":1.45, "cp":1.50,
"out_of_control":false, "nelson_rule":0
}
GET /api/spc/history?chart_id=L1.Part.Weight&range=8h
HMI 组件
<darra-spc-chart
chart-id="L1.Part.Weight"
chart-type="xbar_r"
ucl-color="red"
lcl-color="red"
mean-color="green"
points="200"
title="零件重量 X-bar 图">
</darra-spc-chart>
<darra-cpk-indicator
chart-id="L1.Part.Weight"
thresholds='{"red":1.0,"yellow":1.33,"green":1.67}'>
</darra-cpk-indicator>
排错
| 现象 | 原因 | 处理 |
|---|---|---|
| 控制限太窄, 点常超限 | Phase I 子组量不够 | 拿满 25 组再判异 |
| 控制限太宽 | 子组内包含异常 | 剔除后重算 |
| Nelson 规则 7 经常触发 | 过度调机 / 测量精度不足 | 减少人为干预 |
| Cpk 高但实际不良多 | 测量系统本身不准 | 先做 MSA (Gage R&R) |
| PLC 触发采样遗漏 | 触发位宽度小于扫描周期 | 用锁存 / 计数器 |
高级技巧
- Phase I / II 分离: 初始限定下来后锁定, 不要每采一个点就重新算限
- 双图联动: X-bar 与 R 同时看, R 异常 → 先查过程变差, 再看均值
- CUSUM 补盲: X-bar 对小偏移不敏感, CUSUM 能捕捉 0.5σ 级别的漂移
- 按批次分段: 批次切换自动开新图, 避免批间差异混淆
- 判异推送: 连续 2 次 Nelson 规则 1 → 推送告警到钉钉 / 飞书 (工单 / 维修派工由上层 MES 处理)