ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TIA博途SCL实现滑动平均值滤波FB库文件实战详解

TIA博途SCL实现滑动平均值滤波FB库文件实战详解 简介工业自动化现场模拟量信号常伴有随机噪声与毛刺直接影响控制系统的稳定性。滑动平均值滤波作为一种经典算法通过维护固定长度队列对采样值求平均能够有效平滑信号。其高效实现依赖环形队列与增量求和技巧使运算开销保持恒定非常适合PLC这类资源受限的实时系统。在工程实践中基于TIA博途的SCL语言可将该算法封装为标准FB函数块并通过库文件实现跨项目复用显著提升开发效率。该方案适用于液位、温度、压力等模拟量信号的预处理也支持多通道扩展与参数实时调整。围绕滑动平均值滤波FB的设计、编码与调试全流程进行拆解为电气工程师提供一套可落地的信号处理工程方案。 处理工业现场的模拟量信号最烦的就是那种“看似平稳、实则毛刺一堆”的测量值。液位波动、压力脉动、称重传感器受振动干扰这些场景我基本都遇到过。早期做项目为了把波动压下去不少人直接在程序里写个平均值却发现要么反应迟钝要么滤波完还是一条“锯齿”。后来在TIA博途里用SCL写了一个滑动平均值滤波的FB封进库文件这些问题才真正解决。这篇文章就把这个FB从原理、建模、编码到调试的经验完整拆开讲清楚照着做你也能在博途里复现一个属于自己的滤波库。这个项目核心就是“TIA博途SCL语言_滑动平均值滤波算法_FB库文件”适合正在做过程控制、设备配套调试的电气工程师也适合刚接触SCL想找一个能落地的练习案例的朋友。它的价值不在于代码多复杂而在于把“采样—队列—求均值”这套逻辑做成标准块工程上直接复用参数可调节省大量重复开发时间。老规矩先讲设计思路再上代码细节最后是调试实录。1. 项目概述与设计思路拆解1.1 为什么要专门做一个滑动平均值滤波FB模拟量信号进PLC之后第一步不是急着去比较、报警而是先“洗干净”。滑动平均值滤波是性价比最高的入门选择它不像一阶惯性滤波那样存在相位滞后较大的问题也不像中值滤波那样对采样点数敏感它做的事情很简单维护一个固定长度的数据队列每次新采样进来丢到队尾队头挤出去然后对队列里所有数据求算术平均输出这个平均值。听起来容易但工程上有几个绕不开的痛点。第一博途的FB是支持多实例背景数据块的如果你把数组、指针、循环逻辑都揉在一个大块里实例化两三个通道之后PLC的内存和扫描周期都会肉眼可见地恶化。第二SCL里做队列移位如果用FOR循环逐个移动数组元素窗口长度一旦上到几十甚至上百每次扫描的指令开销就非常可观这是初学者最容易踩的坑。第三滤波效果和响应速度天然冲突窗口越长越平滑但跟随真实值变化越慢这个参数怎么调、放给用户还是写死本身就是设计决策。所以这个FB在设计上要解决三件事一是用环形队列替代数据搬移让运算开销基本恒定二是把窗口长度、滤波使能、输出模式做成参数灵活适应不同工况三是封装成标准库文件方便跨项目复用。后面所有代码都是围绕这三点展开的。1.2 滑动平均滤波的适用边界与技术选型不是所有场景都适合上滑动平均。我一般这样判断现场类型如果是缓慢变化的液位、温度滑动平均很合适它能把小幅随机噪声磨平如果是快速变化的流量、压力滑动平均会带来明显的响应滞后这时候要考虑加权滑动平均或者一阶惯性滤波如果是偶发性的尖峰干扰比如设备启停瞬间的电磁干扰滑动平均反而会把尖峰“拖”成一个宽平台看起来更难受这种应该优先用中值滤波或者限幅滤波。做技术选型不能只看算法本身还得看PLC的扫描周期和采样频率。举个例子某台设备的模拟量模块刷新周期是200ms而你OB1的扫描周期是20ms那同一个通道连续两次读到的值可能根本没变化。这种情况下滑动平均的窗口再大也只是对同一个“旧值”反复求均值并没有增加有效信息量。所以我在做这个FB时特意留了一个采样间隔计数器用户可以设定每隔N个扫描周期才采集一次数据进队列这样既不影响扫描周期又能保证队列里的数据是真正有意义的采样点。2. 核心细节解析与实操要点2.1 FB接口定义与参数设计这个FB我命名为“FB_SlideAvg”接口设计如下参数名类型方向说明bEnableBoolIN滤波使能TRUE时执行FALSE时输出直接等于输入rRawValueRealIN原始采样值iWindowLenIntIN滤波窗口长度2~256运行时可调iSampleCycleIntIN采样间隔周期数1表示每个扫描周期都采样rAvgValueRealOUT滤波输出值rRawValueMirrorRealOUT原始值镜像输出方便监控和比较iQueueUsedIntOUT当前队列有效点数填充不满时输出实际点数均值stInitDoneBoolOUT完成初始化标志内部静态变量变量名类型说明arQueueArray[0..255] of Real环形队列存储区iHeadInt队头指针iLenInt当前队列长度rSumReal队列元素之和增量维护iSampleCntInt采样间隔计数器bInitBool初始化标志有两个点是刚开始写代码时特别容易忽略的。第一个是窗口长度 iWindowLen 的范围合法性如果用户不小心填了0或负值程序运行时数组下标直接越界轻则数据错乱重则报编程错误停机。第二个是 iSampleCycle 的语义很多人会把它误解成“每隔几个扫描周期取一次平均值”但真正的含义是“每隔几个扫描周期向队列里塞一个新数据”这个区别直接决定滤波效果。2.2 环形队列结构与增量求和环形队列是实现高效滑动平均的核心。普通做法是每次新数据进来把数组里所有元素往前移一格然后把新值放到最后。窗口长度是N时每次操作的时间复杂度是O(N)。如果用环形队列通过头指针和尾指针的循环移动每次操作的时间复杂度是O(1)跟窗口大小无关。这对于在PLC这种资源受限环境下运行尤其重要。增量求和是另一个关键技巧。常规做法是每次求平均时把队列所有元素重新加一遍时间复杂度也是O(N)。增量维护的意思是只在入队时把新值加到 rSum 上把被覆盖的旧值从 rSum 里减掉这样求均值时只需要做一次除法直接把 rSum 除以当前队列长度即可。在大窗口场景下这个优化直接决定了FB还能不能跑在高速中断OB里。3. 实操过程与核心环节实现3.1 TIA博途里新建FB并编写SCL代码打开TIA博途在PLC数据类型或者程序块的“添加新块”里选择“函数块”语言选“SCL”命名FB_SlideAvg。下面这段代码是完整实现我逐段解释IF NOT #bInit THEN #iHead : 0; #iLen : 0; #rSum : 0.0; #bInit : TRUE; #stInitDone : TRUE; END_IF; IF #bEnable THEN #iSampleCnt : #iSampleCnt 1; IF #iSampleCnt #iSampleCycle THEN #iSampleCnt : 0; // 窗口长度合法性限制 #iWindowLen : MIN(MAX(#iWindowLen, 2), 256); // 队列已满时先减去将被覆盖的旧值 IF #iLen #iWindowLen THEN #rSum : #rSum - #arQueue[#iHead]; #arQueue[#iHead] : #rRawValue; #iLen : #iWindowLen; ELSE #arQueue[#iHead] : #rRawValue; #iLen : #iLen 1; END_IF; #rSum : #rSum #rRawValue; // 环形指针前进 #iHead : #iHead 1; IF #iHead #iWindowLen THEN #iHead : 0; END_IF; END_IF; // 输出均值队列未满时按实际长度平均 IF #iLen 0 THEN #rAvgValue : #rSum / INT_TO_REAL(#iLen); ELSE #rAvgValue : #rRawValue; END_IF; ELSE #rAvgValue : #rRawValue; END_IF; #rRawValueMirror : #rRawValue; #iQueueUsed : #iLen;3.2 每一段代码的设计意图解读初始化段不是可有可无的因为FB的背景数据块断电保持后静态变量可能是旧值。上电第一次扫描如果不初始化队列里全是垃圾数据rSum 也不是队列元素的和输出结果必然错误。所以 bInit 标志配合第一个扫描循环把队列清干净这是长期运行稳定性的第一道保险。使能判断在外层的原因很直接当 bEnable 为 FALSE 时我们希望系统表现得像个“直通”通道用户给什么输出就是什么方便调试时把滤波旁路掉。这个设计在工程调试阶段非常实用可以在不断电的情况下对比滤波前后的信号。窗口长度限制那段代码是防御性编程。你永远想象不到操作员会往画面里填什么数字所以把窗口长度限制在2到256之间非常必要。256也是静态数组定长的上限这样就不需要动态内存管理。// 指针的循环回绕是关键这段代码决定环形队列是否正确工作 #iHead : #iHead 1; IF #iHead #iWindowLen THEN #iHead : 0; END_IF;这里有人会问为什么不直接用取模运算 #iHead : (#iHead 1) MOD #iWindowLen因为SCL里的MOD运算在博途里生成的代码比比较跳转要耗资源高速循环里不值得。用IF语句实现回绕逻辑更直观指令也更少。3.3 在OB1中调用FB并绑定背景数据块调用这个FB非常简单在OB1中拖入FB_SlideAvg系统会提示你分配背景数据块。建议给每个通道单独分配一个背景DB例如 DB_Ch1_SlideAvg、DB_Ch2_SlideAvg这样监控时每个通道的数据隔离清晰互不干扰。调用代码示意如下DB_Ch1_SlideAvg( bEnable : TRUE, rRawValue : HMI_RawPressure, iWindowLen : 16, iSampleCycle : 2, rAvgValue HMI_FilteredPressure, rRawValueMirror HMI_RawPressure_Monitor, iQueueUsed HMI_QueueUsed, stInitDone HMI_InitDone );3.4 如何将FB封装为库文件并打包为rar写好的FB如果不做库换项目重写一遍代码那就失去了一次开发多次复用的意义了。在博途的“库”选项卡里右键你的项目库选择“添加新库”把FB_SlideAvg拖进去记得附带版本信息。然后在全局库中保存就可以导出为 .zal 文件。用压缩工具打成rar是为了方便在微信、网盘里传播附件名“TIA博途SCL语言_滑动平均值滤波算法_FB库文件.rar”就是这么来的。导入方拿到rar后先解压得到.zal库文件再在博途里打开库选项卡点击“全局库”—“打开”—选择.zal文件。打开后就能在库视图里看到FB_SlideAvg拖进项目即可使用。要注意的是源项目中FC、DB、UDT等依赖对象要一起导出否则光有个FB块引用关系断了照样跑不起来。4. 从仿真到现场调试方法与常见问题排查实录4.1 仿真时如何验证滤波效果博途的PLCSIM可以模拟这个FB的运行。我在验证时习惯先在DB里给 arQueue 预置一组已知数据然后在监控表里强制 rRawValue 从0逐步跳到100观察 rAvgValue 的变化曲线。滑动平均的响应应该是一个“斜坡”而不是“台阶”斜坡的长度取决于窗口大小。如果输出直接跟着输入跳变说明队列没生效大概率是采样间隔计数器没走或者使能端没通。仿真时还要重点看 iQueueUsed 的变化。注意观察它从0逐步增长到窗口长度最终稳定在窗口长度。如果它一直停在0说明 rRawValue 变化时 bEnable 是FALSE或者在循环里被复位了要去查调用处的接口绑定不要一头扎进算法内部找问题。窗口大小对响应速度的影响也可以直接用 PLCSIM 测试。窗口长度从4调到64输出的平滑程度和跟随速度一眼就能看出来。现场工程师如果分不清该调哪个参数我会建议他先看两张趋势图一张是原始信号一张是滤波输出调窗口长度直到噪声被压到可接受范围再看跟随性是否满足工艺要求。如果两者矛盾那就是窗口太大已到滑动平均的性能极限该换算法了。4.2 现场运行时的典型坑与排查表现象可能原因排查方法输出一直等于输入滤波无效bEnable没置位iSampleCycle填了0导致取模异常强制bEnable为TRUE确认iSampleCycle1输出波动反而变大窗口长度太小环形指针回绕条件写错调大iWindowLen查看iHead是否在0~窗口范围内输出跳变到巨大值rSum被污染队列被越界写入检查数组索引边界查看iLen是否超过窗口长度数据堵塞、PLC扫描周期暴涨窗口长度太大且存在大数组循环将窗口降到64以内确认使用了环形队列而非搬移法断电重启后第一次输出异常静态变量未初始化确保bInit初始化段逻辑存在并检查数据块保持属性多通道实例互相干扰背景DB共用导致数据串扰改用多实例方式每个通道单独实例化FB我尤其想提醒一点现场调试时如果发现滤波输出值偶尔出现“毛刺直冲”的现象先不要怀疑算法先查OB1的扫描顺序和模拟量模块的转换时间。我遇到过一次某个模拟量通道在模块量程设置错误时会间歇性输出一个很大的瞬时值。滑动平均不会剔除这种异常值反而会把它平均进队列导致滤波后的信号依然出现一个凸起。这种情况就该配合限幅滤波或者品质位判断来用。4.3 独家避坑技巧窗口长度与采样周期怎么配合工程上最容易调出“又平滑又迟钝”效果的原因是只调了窗口长度而没管采样周期。这两者的乘积才是真正的时间常数。假设你希望滤波的时间常数为10秒窗口长度是50那采样周期就应该设为200ms如果你保持窗口50但采样周期设成了1秒时间常数就变成了50秒现场操作员就会抱怨“阀门反应太慢了”。所以我建议在HMI上把 iWindowLen 和 iSampleCycle 都开放给工艺人员而不是只给一个窗口长度。同时在FB内部计算并输出一个“等效时间常数”rTimeConst : INT_TO_REAL(#iWindowLen * #iSampleCycle) * 0.001; // 需要结合OB1扫描周期这样的话工艺人员看到的是“时间常数几秒”而不是“窗口长度多少个”沟通成本大幅降低调试效率也更高。5. 滤波算法选型对比与扩展建议5.1 滑动平均、一阶惯性与中值滤波的实测对比很多工程师在同一项目里反复纠结要不要换算法。我整理了一张对比表算法平滑能力滞后程度尖峰抑制资源占用适用场景滑动平均强中等差低环形队列增量求和液位、温度、一般压力一阶惯性中低中极低快速流量、阀门控制反馈中值滤波中低强中需要排序称重、振动、偶发干扰滑动平均限幅强中等中低现场信号品质较差的通用场景我自己的经验是现场不知道选什么的时候默认滑动平均然后把限幅判断加上。限幅判断很简单如果当前采样值偏离上次滤波值超过某个阈值就认为这是偶发干扰直接丢弃不进队列。这个思路能弥补滑动平均在尖峰抑制上的弱点代码量增加很少但实用性提升非常明显。5.2 基于此FB扩展多通道与分组滤波这个FB支持多实例化所以通道扩展只需要复制实例并绑定不同输入输出即可。但如果项目里有十几个通道每次手动配置会比较繁琐。你可以在FB内部再套一层比如FB_SlideAvgGroup里面定义多个FB_SlideAvg实例统一管理通道使能和参数。这样对外接口就变成了一个数组输入、一个数组输出。博途的SCL支持数组作为FB的IN/OUT参数这在批量处理模拟量时非常方便。5.3 变量记录与趋势分析优化调试滤波算法的效果最好配合PLC的变量记录功能。在博途里新建变量记录把 rRawValue、rAvgValue 和 rRawValueMirror 同时记录下来导出CSV后到Excel里画趋势线。这样能直观看到滤波前后的信号波形对齐时间轴后还能评估滞后量。这个习惯能帮你积累大量现场数据以后写滤波选型报告、或者跟工艺部门沟通时都很有说服力。6. 写在最后的实操心得我实际用这个FB跑了几个项目最深的体会是滤波算法本身并不复杂难点往往在工程化和现场适配。第一参数一定要开放给用户但要加安全限制第二环形队列和增量求和必须坚持用否则窗口一大PLC性能就崩给你看第三初始化逻辑不能省否则断电重启后的第一次输出就可能带来设备误动作。最后再分享一个小技巧如果你需要快速判断滑动平均是否适合当前信号先用博途的Trace功能录制一段原始信号的波形观察噪声的频率和幅值。如果噪声幅值稳定、频率较高滑动平均几乎肯定够用如果噪声是低频漂移滑动平均不但没用还会让真实信号的趋势变得更钝这时候就该考虑高通滤波或者别的信号处理手段了。拿这个FB做底子你在博途里的信号处理能力会一下子丰富不少。本文还有配套的精品资源点击获取
返回列表