包装称重值跳得像心跳图?我在PLC里写了三段滤波代码搞定——一个称重信号处理项目的实战记录

包装称重值跳得像心跳图,我差点被逼疯

去年接了个活,给一家调味料厂做自动包装秤。就是那种小袋装——一包鸡精50克,要求精度±1克。

当时想,这有啥难的?称重传感器+PLC模拟量模块,十几年的老套路了。结果一上机就傻眼了。

传送带一跑起来,称重值的波动幅度能到±5克。就是啥都不动的情况下,传感器在秤台上放一个50克的砝码,PLC读到的数值在48到52之间横跳。本来是想做定量包装的,你这读数自己都在跳舞,让PLC怎么判断”到了50克就停”?

那两天我盯着电脑屏幕上跳动的数值,眼睛都快看花了。

有没有兄弟遇到过同样的情况?

先排查机械和硬件,别急着写代码

我一开始也想着写滤波程序解决,但老工程师跟我说了一句话我到现在都记着:”软件能解决的问题,硬件上找三天可能就花三分钟解决。”

所以我先停了程序调试,回头看了机械结构和接线。

排查下来发现三个问题:

第一,秤台和传送带之间的减震没做好。传送带电机的振动直接传到了称重传感器上。解决方案:在传感器底座和秤台之间加了橡胶减震垫,传感器到秤台的固定螺丝换成软连接。

第二,称重传感器的信号线和变频器的动力线走同一个桥架。虽然仪表信号是4-20mA的,理论上抗干扰还行,但这种共模干扰还是会有影响。解决方案:信号线单独走管,屏蔽层单端接地。

第三,称重仪表到PLC模拟量模块用的是屏蔽双绞线,但屏蔽层没接到柜内的接地排上——虚接。拧紧之后,干扰小了一半。

这些硬活干完,再上电测,波动从±5克降到了±2.5克左右。好了很多,但还是不满足±1克的精度要求。

这个时候才轮到软件上场。

第一版滤波:滑动平均值,太慢了

我先试了最简单的——滑动平均值滤波。就是连续采N个值,去掉最大最小,剩下的取平均。

在PLC里写了一段:每10ms采一次称重值,缓存到数组里,取16个值的平均值输出。

// 伪代码逻辑
FOR i = 0 TO 14
    Weight_Buffer[i] := Weight_Buffer[i+1];
END_FOR
Weight_Buffer[15] := Raw_Weight_AI;
// 去掉最大最小
Sort(Weight_Buffer);
Sum := Sum - Weight_Buffer[0] - Weight_Buffer[15];
Average := Sum / 14;

一跑,信号确实稳了,从±2.5克降到了±1克左右。心里正高兴,接着发现问题了——响应太慢

你想啊,16个采样,每个10ms,16个值就是一整个扫描周期都在处理这个。从重量变化到PLC检测到,延迟了160ms。对于50克的小包装来说,0.16秒的延迟,料斗可能多放了好几克料进去。结果就是实际装进去的料,比目标值大了不少。

我测了一组数据:设定的停机点是重量≥50.0克就停止加料,但因为滤波延迟,加上机械阀门关闭的响应时间,实际最终重量在52到55克之间。超重了。

改小采样数量?8个?4个?试了试,滤波效果又不行了。

第二版:我换了个思路——一阶低通滤波

跟同行交流的时候,一个做仪表的兄弟跟我说:”你别用滑动平均,试试一阶低通滤波(也叫一阶滞后滤波),做实时控制比滑动平均好用。”

公式很简单:

Y(n) = α × X(n) + (1-α) × Y(n-1)

其中X(n)是当前采样值,Y(n-1)是上一次滤波后的值,α是滤波系数(0到1之间)。α越小,滤波越强但响应越慢;α越大,响应越快但滤波效果弱。

这个算法的好处是——不需要缓存数组,每个扫描周期只做一次乘法和一次加法。PLC算起来飞快,不占内存。

我在PLC里实现了一版:

// 一阶低通滤波
Filtered_Weight := ALPHA * Raw_Weight_AI + (1.0 - ALPHA) * Filtered_Weight_Old;
Filtered_Weight_Old := Filtered_Weight;

选了α=0.15,试了一下。稳定性和滑动平均16个值差不多,但延迟从160ms降到了大概20-30ms。效果很不错。

不过我很快又遇到了新问题——这个参数固定的滤波,在产线不同的情况下,效果不一样。

传送带空跑的时候,振动小,滤波效果好。但一上料,特别是大颗粒的物料(鸡精本身就是那种结晶体),称重台上哗啦哗啦往下掉,短时冲击很大。α=0.15时滤波偏强,对突然的冲击反应太慢,加料动作都停不下来。

这时候需要一个能自动调整的滤波策略。

第三版:自适应滤波,搞了个土办法

说实话,自适应滤波的算法论文我看过几篇,什么卡尔曼滤波、什么贝叶斯估计,理论确实漂亮,但让我在S7-1200这种PLC上写卡尔曼滤波,我只想说——大哥们,你们写论文的能不能考虑一下PLC的那点算力?

后来我用了一个土办法,虽然学术上不咋体面,但效果真不赖:

思路就是——根据当前采样值和历史平均值的偏差大小,动态调整滤波系数α。

如果采样值和滤波值的偏差很小(说明信号是平稳的噪音),α设小,重点滤波。

如果偏差突然变大(说明可能是真实的重量变化),α设大,快速跟踪。

代码大概这样:

// 计算偏差
Deviation := ABS(Raw_Weight_AI - Filtered_Weight);
// 根据偏差动态调整α
IF Deviation < 1.0 THEN
    ALPHA := 0.10;  // 偏差小,强滤波
ELSIF Deviation < 3.0 THEN
    ALPHA := 0.25;  // 偏差中等,中等滤波
ELSE
    ALPHA := 0.60;  // 偏差大,快速跟踪(可能是真的重量变化)
END_IF
// 执行滤波
Filtered_Weight := ALPHA * Raw_Weight_AI + (1.0 - ALPHA) * Filtered_Weight_Old;
Filtered_Weight_Old := Filtered_Weight;

这个土办法跑起来,效果出奇的好。稳定时能把波动压在±0.5克以内,加料时的冲击响应也比之前快得多。

我用了100包测试数据对比:

滑动平均滤波(16点):平均包装重量53.2克,超重率100%,最大偏差+5.8克
一阶低通滤波(α=0.15):平均包装重量51.5克,超重率72%,最大偏差+3.2克
自适应滤波:平均包装重量50.3克,超重率8%,最大偏差+1.1克

最后一个版本确实满足客户±1克的要求了。

后来我还加了点小技巧

除了上面的滤波策略,还有两个小细节我觉得值得分享一下:

采样时机要选对。我原来每个扫描周期都采样一次,后来发现采集应该和PLC扫描周期同步,而不是在扫描周期里随机采样。我改成在OB1的固定节拍里采,而且不在OB1里做滤波——在定时中断OB里做,采样间隔固定为10ms,这样滤波算法是基于固定时间间隔的,效果比随机采样好得多。

加料过程中区分粗加料和精加料。包装秤通常都是先快速加料到目标值的90%,然后慢速精加。我在精加阶段把滤波系数动态调得更灵敏一些(因为精加阶段容错时间窗口短),而在粗加阶段调得更稳一些。就是根据不同工况切换不同的滤波参数。

总结一下

写这个文章不是为了炫技。说实话,自适应滤波这东西,网上到处都有代码,一点也不稀罕。我写出来是想说:PLC编程里最难的从来不是语法,而是对实际情况的理解。

滤波算法本身不复杂,但你在什么时机采样、采样频率怎么选、滤波参数怎么调、不同工况怎么切换——这些才是真正决定你能不能把称做准的关键。

我见过有兄弟拿到一个振动大的称重项目,二话不说就在PLC里写了一段100个点的滑动平均,结果包装出来的东西全超重,还被客户骂了一顿。他问我怎么回事,我说你把滤波延迟算进去看看——100个点×10ms=1秒延迟,加上阀门响应时间,不超重才怪。

所以做PLC这块,一定要把算法和实际机械响应时间一起考虑,光看滤波曲线好看没用。

你们做称重项目的时候用的什么滤波方法?遇到过什么奇葩问题?欢迎评论区聊聊。

上一篇 我用AI给十万步的老PLC程序加了中文注释——从看不明白到新人也能维护
下一篇 光伏产能过剩反成了工控人的新饭碗?我跑了三个技改项目发现的机会