当前位置:首页 > Python 工业工具 > 正文内容

SPC控制图入门:用Python替代Excel

SPC控制图入门:用Python替代Excel

一、问题背景:15分钟一张图,20张就是5小时

工艺工程师老张每天早上做SPC控制图,流程如下:

1. 从MES导出CSV —— 5分钟

2. 在Excel里插入折线图 —— 5分钟

3. 手动算均值+3σ线,画上去 —— 3分钟

4. 肉眼找异常点 —— 2分钟

5. 20张图做完 = 5小时,一上午就没了

而且Excel有个致命问题:控制限忘了更新。用了测试阶段的数据当基准,过了两个月才发现不对。客户投诉说"你们的质量监控是摆设"。

老张来找我:"能不能用Python一键生成?"

我说能。20行代码的事。

学完这一篇,你能做到:

1. 用numpy算控制图的均值和3σ限

2. 用matplotlib画出专业控制图

3. 程序自动标出异常点,不用肉眼看

---

二、技术原理:控制图只有3条线

SPC控制图看起来复杂,拆开看就3条线:

| 线条 | 含义 | 怎么算 |

|------|------|--------|

| CL(中心线) | 数据均值 | `np.mean(data)` |

| UCL(上控制限) | 均值 + 3×标准差 | `mean + 3*std` |

| LCL(下控制限) | 均值 - 3×标准差 | `mean - 3*std` |

为什么是"子组"(Subgroup)?

FAB里不是取每个单片Wafers的数据做控制图,而是5片一组取均值。为什么呢?

单片波动太大了。 一片1249.8、下一片1252.1,差值2.3——但这可能只是正常的测量噪声,不代表过程有问题。

5片一组取均值:均值把随机波动抵消了,能看出过程的真实变化。

好比看一个人体温:单次测量36.5℃和37.2℃差别不大,但连续5天都在37.2℃以上——这才说明有问题。

```python

import numpy as np

模拟100个数据点(5片一组,共20组)

np.random.seed(42)

raw_data = np.random.normal(1250, 3, 100)

重新排列成20组×5片

subgroups = raw_data.reshape(20, 5)

每组算均值(这就是X-bar)

xbars = np.mean(subgroups, axis=1)

print(f"20个子组的均值:\n{xbars.round(2)}")

每组算极差(max - min)

ranges = np.ptp(subgroups, axis=1)

print(f"20个子组的极差:\n{ranges.round(2)}")

```

为什么这样写? `reshape(20, 5)` 把一维数组变成20行5列的表格——Python里叫"多维数组"。`axis=1` 表示"沿着行方向算",就是每组的5个数据算一个均值。`np.ptp` 是"peak to peak",就是 `max - min`,用来衡量组内波动。

---

三、实战案例:20行代码出完整控制图

3.1 先画X-bar图(看均值变化)

```python

import numpy as np

import matplotlib.pyplot as plt

数据准备

np.random.seed(42)

raw = np.random.normal(1250, 3, 100)

subgroups = raw.reshape(20, 5)

xbars = np.mean(subgroups, axis=1)

算控制限

cl = np.mean(xbars) # 中心线 = 均值的均值

std = np.std(xbars) # 子组均值的标准差

ucl = cl + 3 * std # 上控制限

lcl = cl - 3 * std # 下控制限

画图

plt.figure(figsize=(12, 5))

x = range(1, 21) # 子组编号1-20

画折线和数据点

plt.plot(x, xbars, 'o-', color='#1976D2', linewidth=2, markersize=6, label='子组均值')

画控制线

plt.axhline(y=ucl, color='red', linestyle='--', linewidth=2, label=f'UCL={ucl:.2f}')

plt.axhline(y=cl, color='green', linestyle='-', linewidth=2, label=f'CL={cl:.2f}')

plt.axhline(y=lcl, color='red', linestyle='--', linewidth=2, label=f'LCL={lcl:.2f}')

标出异常点(超出控制限的)

for i, val in enumerate(xbars):

if val > ucl or val < lcl:

plt.plot(i+1, val, 'ro', markersize=10, zorder=5)

plt.title('膜厚X-bar控制图', fontsize=14)

plt.xlabel('子组序号')

plt.ylabel('膜厚均值 (Å)')

plt.legend(loc='upper right')

plt.grid(True, alpha=0.3)

plt.tight_layout()

plt.show()

```

为什么这样写? `axhline` 画水平线,三条线(UCL/CL/LCL)加上图就是完整的X-bar控制图。最后的 `for` 循环找出所有超出控制限的点,用 `'ro'`(红色圆点)标记出来,一目了然。

3.2 再画R图(看波动变化)

X-bar图看均值,R图看波动。均值正常不代表波动正常。 比如设备老化时,均值可能稳定在1250,但波动从±3σ变成了±6σ——R图能捕捉到这种隐患。

```python

R图:监控组内波动

ranges = np.ptp(subgroups, axis=1)

r_cl = np.mean(ranges) # 极差的均值

r_ucl = r_cl * 2.114 # 子组5时的D4常数

r_lcl = r_cl * 0 # 子组5时的D3常数=0

plt.figure(figsize=(12, 4))

plt.plot(x, ranges, 'o-', color='#FF9800', linewidth=2, markersize=6, label='子组极差')

plt.axhline(y=r_ucl, color='red', linestyle='--', linewidth=2, label=f'UCL={r_ucl:.2f}')

plt.axhline(y=r_cl, color='green', linestyle='-', linewidth=2, label=f'CL={r_cl:.2f}')

plt.title('膜厚R控制图', fontsize=14)

plt.xlabel('子组序号')

plt.ylabel('极差 (Å)')

plt.legend(); plt.grid(True, alpha=0.3)

plt.tight_layout()

plt.show()

```

为什么R图要乘以2.114? 这是统计学的常数(D4),因为极差的分布不是正态分布,直接用3-sigma会算偏。D4常数根据子组大小查表得到,子组5时是2.114。这不是可以随便调的——国标GB/T 4091和汽车行业IATF 16949都规定了这些常数。

3.3 封装成函数

```python

def make_spc_chart(data, subgroup_size=5):

"""

一键生成X-bar + R控制图

参数:

data: numpy数组,原始数据

subgroup_size: 每组的样本数(默认5片一组)

返回:

dict: 控制限和异常信息

"""

# 重组数据

n_groups = len(data) // subgroup_size

groups = data[:n_groups * subgroup_size].reshape(n_groups, subgroup_size)

# 计算统计量

xbars = np.mean(groups, axis=1)

rs = np.ptp(groups, axis=1)

# X-bar控制限

cl = np.mean(xbars)

xbar_std = np.std(xbars)

x_ucl = cl + 3 * xbar_std

x_lcl = cl - 3 * xbar_std

# 找出异常点

anomalies = []

for i, val in enumerate(xbars):

if val > x_ucl or val < x_lcl:

anomalies.append({'group': i+1, 'value': val})

return {

'center': cl,

'ucl': x_ucl,

'lcl': x_lcl,

'total_groups': n_groups,

'anomaly_count': len(anomalies),

'in_control': len(anomalies) == 0,

'anomalies': anomalies

}

使用

result = make_spc_chart(raw)

print(f"控制状态: {'✓ 受控' if result['in_control'] else '⚠ 失控'}")

print(f"异常点数: {result['anomaly_count']}")

if result['anomalies']:

for a in result['anomalies']:

print(f" 子组{a['group']}: 值{a['value']:.2f}超出控制限")

```

为什么这样写? 封装成函数后,每天只需导入数据、调用 `make_spc_chart()`,5分钟的工作变成1秒。函数还返回了业务需要的核心信息——"是否受控"和"哪些组异常",可以直接集成到邮箱报警等后续流程。

---

四、效果对比

| 维度 | Excel手动版 | Python自动版 | 提升 |

|------|-----------|-------------|------|

| 每张控制图耗时 | 15分钟 | 0.5秒 | 1800倍 |

| 20张图总耗时 | 5小时 | 10秒 | 全自动化 |

| 异常点检测 | 人工眼找 | 程序自动标记 | 零遗漏 |

| 控制限更新 | 手动(容易忘) | 每次自动重算 | 100%准确 |

| 异常发现延迟 | 2-6小时 | 实时 | 及时止损 |

| 新人培训成本 | 2小时教Excel操作 | 30秒导入数据 | 极低 |

关键认知:Excel做SPC最大的问题不是慢,而是不可靠。人工操作总是会漏(老张用的还是两个月前的控制限)。用Python后,每次运行都是最新数据、最新控制限,想出错都难。

---

五、自己动手

```python

练习:用你自己的数据做控制图

import numpy as np

import matplotlib.pyplot as plt

1. 把数据贴进来(替换为真实工艺数据)

my_data = [

1248.5, 1251.2, 1249.8, 1250.1, 1252.0, # 子组1

1247.5, 1250.8, 1249.1, 1251.5, 1248.2, # 子组2

1250.3, 1249.6, 1251.0, 1248.9, 1250.7, # 子组3

]

2. 转成numpy数组

data = np.array(my_data)

3. 用上面的make_spc_chart函数检测

✏️ 添加:调用make_spc_chart,打印控制限和异常状态

4. ✏️ 思考:子组大小改成3会怎样?改成10呢?

```

思考题

1. 样本量多少合适?子组大小一般5-10,太小组内噪声大,太大掩盖短期波动

2. 控制限多久更新一次?我的建议:每次新测25组数据后更新一次,至少每月一次

3. 控制图只有3条线吗?还有1σ、2σ的辅助线(Rule 2-8需要),但新手先学会3线就够了

---

六、常见误区

新手常犯的错误

  • 子组大小不一致:一组5片下一组3片——每组的均值标准差不一致,控制限不准。固定大小
  • 数据混了不同产品:不同型号的厚度目标值不同,不能混在一起做控制图。同产品同工站做一张图
  • 控制限一次用到黑:设备换parts、换材料后,旧控制限不适用。要重新计算
  • 忽略R图:X-bar图看起来正常,但R图可能已经报警。两个图要一起看

数据量参考

| 阶段 | 最少数据量 | 说明 |

|------|-----------|------|

| 初始建限 | 20个子组(100个数据) | 过程稳定期数据 |

| 日常监控 | 每个子组5个数据 | 每天或每班次一组 |

| 重新建限 | 设备维护/换型后 | 重新收集20组 |

---

> 💬 你们FAB还在用Excel做SPC吗?换Python最大的阻力是什么?评论区聊

> 📚 收藏+点赞,下一篇讲自动生成日报用得上 👆

相关文章

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图) 我带过一个实习生,非科班出身,学了3个月Python,第一个月工资就涨了2000。 也有干了5年的工艺工程师,手动导数据画图画了5年,月薪还是那点钱...

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战) 经常有人问我:我想学Python做FAB数据分析,从哪里开始? 今天我把完整路线画出来,从零基础到能独立做项目,按这个走,90天能出师。...

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集 我在FAB干了15年,最值钱的东西不是经验,是一个攒了多年的Python工具箱。 今天把这个工具箱的核心部分分享出来,从数据采集到SP...

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码) 1. 我的血泪史:每天2小时的日报工作 2018年,我在FAB做整合工程师的时候,每天早上第一件事不是分析数据,而是做日报。从M...

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动 1. 问题背景:被动维修的代价 FAB里最贵的不是设备,是设备宕机造成的产能损失。一台光刻机价值$100M+,停机1小时损失约$...

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码) 1. 问题背景:我的第一次良率分析 2016年,我在FAB做工艺工程师的时候,第一次被要求分析一批良率异常。工程师把数据发给我——一个E...