资讯动态

基于C#的SPC产品质量在线分析系统:完整源码与实时判异实现

发布时间:2026/10/9 5:59:57 来源:尧图企业网站定制
简介这是一套面向计算机、自动化等专业学生与从业者的SPC产品质量在线分析系统C#完整源码可直接用于毕业设计、期末课程设计或课程大作业也可作为质量管理类桌面应用的入门参考。项目基于Visual Studio 2013与SQL Server 2012开发内置admin/admin登录账号功能覆盖员工、产品、车间、工序、设备等信息维护以及分类搜索、控制图判异准则设置、测量数据备注与失控受理处理等模块并实现Xbar-R、Xmedian-R、X-Rs、X控制图、直方图和Cpk图等统计过程控制图表。压缩包共165个文件以79个png界面截图、36个cs源码、12个resx与12个resources资源文件为主另含config配置、exe可执行文件、dll与sln解决方案等整体约3.02MB结构完整便于二次开发。该资源已有202人学习下载评审分达95分且调试运行正常读者可据此掌握SPC判异逻辑、控制图绘制与数据库交互的完整实现思路。1. 从一张失控的质检报表说起SPC 在线分析系统到底解决什么问题车间里最常见的场景是这样的早班交接时质检员把一叠手写的测量记录交给工艺员工艺员再敲进 Excel等算出均值、极差、控制限往往已经过去两三个小时。如果这批产品其实在上午十点就已经开始偏移等报表出来时可能已经堆了几百件超差品。基于 SPC 的产品质量在线分析系统要干的事就是把这段延迟压到秒级——测量数据一进系统控制图立刻更新判异规则实时触发异常在变成批量废品之前就被拦下来。这个标题里几个词各有分量。SPC 是统计过程控制核心不是画图而是用控制限区分「正常波动」和「异常波动」在线意味着数据采集、计算、判异、报警形成闭环而不是事后补录C# 完整源码说明这是一套可编译、可二次开发的桌面或服务端程序常见形态是 WinForm/WPF 上位机加数据库对接量具、PLC 或扭矩枪这类采集源。适合谁看做计算机毕业设计想找一个有真实业务逻辑、能讲清楚算法又不太虚的题目的人工厂里想自己搭一套轻量质检看板的设备或工艺工程师以及刚学完c#入门、想找一个完整项目练手的开发者。它不追求大而全的 MES而是把 SPC 这一件事做透。2. 拆解 SPC 在线分析系统的技术骨架从采集到判异的数据流2.1 为什么选 C# 做上位机而不是脚本语言工业现场的上位机软件选型时绕不开三个现实约束要能稳定对接串口、网口、OPC、数据库要能长时间运行不崩要能打包成一个双击就能跑的 exe 交给产线。C# 在这三点上都很顺手。.NET 的System.IO.Ports处理串口、System.Net.Sockets处理 TCP、System.Data.SqlClient或 EF Core 处理数据库都是成熟方案WinForm/WPF 做界面工艺员上手成本低。相比之下Python 写采集脚本快但打包成独立 exe 体积大、依赖多产线电脑装环境容易翻车C 性能好但开发效率低毕业设计周期内很难既做界面又做算法。另一个常被忽略的点是c#上位机生态里现成的工业控件和通信库很多比如做扭矩采集时对接c#读power focus 6000扭矩值这类设备厂商通常提供 .NET 的 SDK 或示例直接调用比从零写协议解析省事得多。所以这套系统的技术栈我一般会定成C# WinForm或 WPF SQLite/SQL Server 自研 SPC 计算模块。数据库选 SQLite 适合单机部署和毕业设计演示选 SQL Server 适合多工位联网。2.2 数据模型一张测量表要存哪些字段SPC 系统的地基是数据表设计。很多同学一上来就建一张大宽表结果做控制图时发现分组、子组、时间戳全乱。正确的做法是按「产品-特性-子组-测量值」四层建模。下面是最小可用的建表脚本用 SQLite 语法SQL Server 稍作类型调整即可。-- 产品表一个产品有多个质量特性 CREATE TABLE Product ( ProductId INTEGER PRIMARY KEY AUTOINCREMENT, ProductCode TEXT NOT NULL UNIQUE, -- 产品编号如 AX-2024 ProductName TEXT NOT NULL ); -- 质量特性表每个特性对应一张控制图 CREATE TABLE Characteristic ( CharId INTEGER PRIMARY KEY AUTOINCREMENT, ProductId INTEGER NOT NULL, CharName TEXT NOT NULL, -- 如 外径 USL REAL, -- 上规格限 LSL REAL, -- 下规格限 Target REAL, -- 目标值 SubgroupSize INTEGER DEFAULT 5, -- 子组大小 n FOREIGN KEY (ProductId) REFERENCES Product(ProductId) ); -- 测量明细表每条记录是一次测量 CREATE TABLE Measurement ( MeasId INTEGER PRIMARY KEY AUTOINCREMENT, CharId INTEGER NOT NULL, SubgroupNo INTEGER NOT NULL, -- 子组序号同组共享 MeasValue REAL NOT NULL, MeasTime TEXT NOT NULL, -- ISO8601 时间戳 Operator TEXT, FOREIGN KEY (CharId) REFERENCES Characteristic(CharId) ); -- 控制图参数表缓存当前控制限避免每次重算 CREATE TABLE ControlLimit ( CharId INTEGER PRIMARY KEY, XbarUCL REAL, XbarLCL REAL, XbarCL REAL, RUCL REAL, RLCL REAL, RCL REAL, CalcTime TEXT, FOREIGN KEY (CharId) REFERENCES Characteristic(CharId) );逻辑说明SubgroupSize决定子组大小Xbar-R 图常用 4~5Xbar-S 图用 10 以上。SubgroupNo是关键字段同一子组的多条测量共享同一个编号计算均值时按它分组。ControlLimit表做缓存是因为控制限在数据量稳定后不需要每次刷新实时判异时直接读缓存能省掉大量重复计算。参数上USL/LSL是客户规格限和后面算出来的控制限 UCL/LCL 是两回事新手最容易把这两个概念混在一起——规格限是「产品合不合格」控制限是「过程稳不稳定」判异只看控制限。2.3 采集层串口、TCP 和文件三种接入方式在线系统的「在线」体现在采集。常见接入方式有三种按现场条件选接入方式适用场景C# 关键类注意点串口卡尺、千分尺、老式量具SerialPort波特率/校验位要和量具一致TCP扭矩枪、PLC、智能仪表TcpClient注意粘包要按协议分帧文件/数据库已有系统导出、离线补录FileSystemWatcher注意文件占用和编码串口采集的最小实现如下重点是开一个后台线程持续读读到完整帧再解析不要在主线程里ReadLine阻塞界面。private SerialPort _port; private void StartSerial(string portName, int baud) { _port new SerialPort(portName, baud, Parity.None, 8, StopBits.One); _port.DataReceived OnDataReceived; // 事件在后台线程触发 _port.Open(); } private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) { try { string line _port.ReadLine(); // 假设量具以换行结尾 if (double.TryParse(line.Trim(), out double value)) { // 交给业务层注意跨线程更新 UI 要用 Invoke _buffer.Enqueue(new MeasRecord { Value value, Time DateTime.Now }); } } catch (TimeoutException) { /* 读超时忽略继续等下一帧 */ } }参数说明baud必须和量具手册一致常见 9600 或 19200ReadLine依赖设备发送换行符如果设备是定长帧要改用Read配合字节计数。DataReceived在非 UI 线程触发直接更新控件会抛跨线程异常这是新手第一个必踩的坑。TCP 接入时TcpClient的NetworkStream是字节流一次Read可能拿到半帧或多帧必须自己维护缓冲区按协议头尾切分不能假设一次读到一条完整数据。3. 把控制图算对Xbar-R 的公式、代码与三个必调参数3.1 Xbar-R 控制限的计算逻辑控制图种类很多计量型数据最常用的是 Xbar-R均值-极差图。它的思路是子组内变异用极差 R 衡量子组间变异用均值 Xbar 衡量分别对两者设控制限。公式不复杂但系数容易记错。设子组大小 n第 i 个子组的均值为 Xbar_i极差为 R_i共 k 个子组总均值 Xbar̄ (Σ Xbar_i) / k平均极差 R̄ (Σ R_i) / kXbar 图控制限UCL Xbar̄ A2·R̄LCL Xbar̄ − A2·R̄R 图控制限UCL D4·R̄LCL D3·R̄A2、D3、D4 是随 n 变化的常数n5 时 A20.577、D30、D42.114。这些系数必须查表不能自己推。下面用 C# 实现核心计算。// 控制图常数表n - (A2, D3, D4) private static readonly Dictionaryint, (double A2, double D3, double D4) Coef new Dictionaryint, (double, double, double) { {2, (1.880, 0, 3.267)}, {3, (1.023, 0, 2.574)}, {4, (0.729, 0, 2.282)}, {5, (0.577, 0, 2.114)}, {6, (0.483, 0, 2.004)}, {7, (0.419, 0.076, 1.924)}, {8, (0.373, 0.136, 1.864)}, {9, (0.337, 0.184, 1.816)}, {10,(0.308, 0.223, 1.777)} }; public ControlLimit CalcXbarR(Listdouble[] subgroups) { int n subgroups[0].Length; var (a2, d3, d4) Coef[n]; double xbarBar subgroups.Average(g g.Average()); double rBar subgroups.Average(g g.Max() - g.Min()); return new ControlLimit { XbarCL xbarBar, XbarUCL xbarBar a2 * rBar, XbarLCL xbarBar - a2 * rBar, RCL rBar, RUCL d4 * rBar, RLCL d3 * rBar }; }逻辑说明subgroups是已经按SubgroupNo分好组的二维结构每组长度必须等于 n否则系数取错、控制限全废。xbarBar用所有子组均值的平均不是所有测量值的平均——当各子组大小相等时两者相等但子组大小不等时结果不同SPC 标准做法要求子组大小一致。参数上n 必须落在系数表范围内n1 时不能用 Xbar-R 图要改用单值-移动极差I-MR图这是选型边界。3.2 判异规则八条准则里哪几条必须实现控制图画出控制限只是第一步真正报警靠判异准则。国标和 AIAG 手册里列了八条实际系统里我建议至少实现前四条因为后四条对数据量要求高、误报也多。准则含义实现难度建议11 点超出 A 区超控制限低必做2连续 9 点在中心线同侧低必做3连续 6 点递增或递减低必做4连续 14 点上下交替中建议做5连续 3 点中 2 点在 A 区或以外中选做6连续 5 点中 4 点在 B 区或以外中选做7连续 15 点在 C 区以内中选做8连续 8 点在中心线两侧但无人在 C 区高选做准则 1 的实现最简单遍历每个点判断是否越界。准则 2 和 3 需要滑动窗口写一个通用窗口检查函数即可。下面给出准则 2 的实现其余同理。// 判断最近 9 点是否都在中心线同侧 public bool Rule2_Shift(Listdouble values, double cl, int window 9) { if (values.Count window) return false; var recent values.Skip(values.Count - window).ToList(); return recent.All(v v cl) || recent.All(v v cl); }参数说明window默认 9是准则 2 的标准值不要随意改小改小会显著增加误报。cl传中心线值。注意判异要基于「当前最新点」触发即每次新数据进来后检查以它为结尾的窗口而不是全量重扫否则同一异常会反复报警。实际系统里我会给每条准则加一个「报警冷却时间」比如同一特性 5 分钟内只报一次避免产线被刷屏。3.3 过程能力指数 Cp/Cpk 的在线计算控制图看稳定性过程能力指数看满足规格的能力。Cp 衡量潜在能力Cpk 衡量实际能力公式Cp (USL − LSL) / (6σ)Cpk min((USL − Xbar̄) / (3σ), (Xbar̄ − LSL) / (3σ))σ 的估计用 R̄/d2d2 也是随 n 变化的常数n5 时 d22.326。在线计算时要注意Cp/Cpk 只有在过程受控控制图无异常时才有意义如果过程本身在漂移算出来的 Cpk 是假的。所以系统里我会把 Cpk 显示和判异状态绑定有未处理异常时 Cpk 标灰并提示「过程未受控能力指数仅供参考」。这个细节在毕业设计答辩时是加分项因为它体现了对 SPC 逻辑的理解而不只是套公式。4. 避坑与排查这套系统上线后最容易翻车的五个地方4.1 现象控制图一打开就满屏红点原因把规格限 USL/LSL 当成了控制限 UCL/LCL 来判异。规格限通常比控制限宽用规格限判异会漏报反过来如果误把控制限当规格限又会把正常波动判成超差。更隐蔽的情况是子组划分错误比如把不同班次、不同设备的数据混进同一个子组导致组内变异被人为放大控制限算得过宽。解决在Characteristic表里明确区分规格限和控制限字段界面上用不同颜色标注。子组划分要绑定「班次设备时间窗」三个维度采集时自动打标签不要靠人工事后分组。上线前用一批已知稳定的历史数据验证控制限看是否和历史结论一致。4.2 现象数据明明在采集界面就是不刷新原因跨线程更新 UI。串口或 TCP 的接收回调在后台线程执行直接给TextBox.Text或DataGridView.DataSource赋值WinForm 会抛InvalidOperationException但异常常被吞掉表现为「没反应」。另一个原因是DataReceived事件里做了耗时计算阻塞了后续数据接收。解决所有 UI 更新走Control.Invoke或BeginInvoke把计算和界面分离接收线程只负责入队另起一个消费线程或定时器做计算和刷新。下面是一个安全的更新封装。private void SafeUpdate(Action action) { if (this.InvokeRequired) this.BeginInvoke(action); // 异步不阻塞采集线程 else action(); } // 调用SafeUpdate(() chart1.Series[0].Points.AddY(value));4.3 现象控制限每次刷新都在变图看起来在「漂移」原因每次新数据进来都全量重算控制限导致控制限随数据滚动。SPC 的标准做法是控制限一旦建立就固定除非过程发生已知的永久性变化如换料、换模才重新计算。滚动重算会让判异失去基准异常永远追不上。解决控制限分两阶段。第一阶段试运行用 20~25 个子组建立初始控制限存入ControlLimit表第二阶段受控运行控制限冻结只做判异不做重算。需要重算时由工艺员手动触发并记录重算原因和时间。这个「控制限冻结」机制是很多自制系统忽略的关键点。4.4 现象Cpk 算出来 2.0 以上但客户投诉不断原因σ 的估计方法用错。有人直接用所有测量值的标准差而不是用 R̄/d2 或 S̄/c4 估计。当过程存在特殊原因波动时整体标准差会被放大Cpk 反而偏小反过来如果数据是挑选过的「好数据」整体标准差偏小Cpk 虚高。另外Cpk 计算前没有确认过程受控也是常见错误。解决统一用组内变异估计 σ即 R̄/d2Xbar-R 图或 S̄/c4Xbar-S 图。计算前先跑判异有异常先处理异常再谈能力。界面上把「过程受控」作为 Cpk 显示的前置条件。4.5 现象数据库越跑越慢几个月后查询要等十几秒原因Measurement表只增不删没有索引判异时又频繁按CharId SubgroupNo查询。数据量到百万级后全表扫描拖垮性能。另一个原因是每次判异都从数据库拉全量历史而不是只拉最近窗口。解决在Measurement表的(CharId, SubgroupNo)上建复合索引判异只查最近 N 个子组N 取判异窗口最大值加缓冲比如 30历史数据按时间分区或定期归档到历史表。如果用的是 SQLite注意它写操作会锁库采集写入和查询要错开或用 WAL 模式。5. 让系统真正好用实时报警推送与二次开发接口5.1 报警不能只靠界面变红产线工人不会一直盯着屏幕报警必须主动推送。最轻量的做法是本地声音加弹窗进阶做法是推送到车间看板或企业微信/钉钉机器人。C# 里发 HTTP 请求很简单下面是一个推送到 webhook 的最小实现注意异常要吞掉不能因为推送失败影响主流程。private static readonly HttpClient _http new HttpClient(); public async Task PushAlarm(string charName, string rule, double value) { try { var payload new { msgtype text, text new { content $SPC报警{charName} 触发{rule}当前值 {value:F3} } }; var json JsonSerializer.Serialize(payload); await _http.PostAsync(https://your-webhook-url, new StringContent(json, Encoding.UTF8, application/json)); } catch (Exception ex) { // 推送失败只记日志不影响判异主流程 Log.Warn($报警推送失败: {ex.Message}); } }参数说明webhook 地址按实际平台填请求体格式各平台不同这里用通用的 text 类型。HttpClient要静态复用不要每次 new否则连接池耗尽。推送频率要限流同一特性同一准则在冷却期内不重复推。5.2 留出二次开发接口别把逻辑焊死在界面里毕业设计常见的问题是所有逻辑写在 Form 的按钮事件里想换个控制图类型就得改界面代码。正确做法是把 SPC 计算、判异、采集都抽成独立的类库界面只做展示和调用。这样后续想加 Xbar-S 图、加新的判异准则、换数据库都只动类库不动界面。我一般会定义这样的接口public interface IControlChart { string ChartType { get; } // Xbar-R / Xbar-S / I-MR ControlLimit Calculate(Listdouble[] subgroups); ListAlarm Judge(Listdouble points, ControlLimit limit); } public interface IDataCollector { event ActionMeasRecord OnDataReceived; void Start(); void Stop(); }有了这层抽象采集层可以今天用串口、明天换 TCP控制图可以今天用 Xbar-R、明天加 Xbar-S互不影响。这也是这套源码值得二次开发的价值所在——它不是一次性演示而是一个能长大的骨架。5.3 验证系统算得对不对三个自检方法写完不能只看界面好看要验证算法。第一用手算数据对拍取 25 个子组、n5 的标准数据集手算 Xbar̄、R̄、UCL、LCL和程序输出比对误差应在小数点后三位内。第二用已知判异案例测试构造一组「连续 9 点同侧」的数据看系统是否准确触发准则 2且不误触发其他准则。第三做边界测试子组大小 n1、n11超出系数表、数据量不足 25 组时系统应给出明确提示而不是崩溃或算出错误控制限。我自己的习惯是每加一条判异准则就先写一组能触发它的最小数据做单元测试跑通了再接进主流程。血泪经验是判异逻辑的 bug 往往不是算错而是窗口边界处理错——比如数据刚好 9 个点时该不该触发、最新点算不算在窗口内这些边界不测上线后就是玄学报警。这套系统值不值得做如果你需要一个能讲清楚统计原理、又能真实跑起来的项目它比增删改查的管理系统有含量得多。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑