在电气自动化系统中,模拟量信号(如温度、压力、流量、电压等)常受现场电磁干扰、传感器噪声或传输线路耦合影响,导致采集值跳变、抖动。这种波动若直接用于控制逻辑(如PID调节、报警判断、趋势记录),会引发误动作、频繁启停、控制震荡甚至设备损伤。因此,对模拟量做实时滤波是工程实施中的基础且关键环节。
结构化文本语言(Structured Text,ST)作为IEC 61131-3标准定义的五大PLC编程语言之一,语法简洁、可读性强、支持浮点运算与复杂数学表达式,非常适合实现数字滤波算法。其中,一阶指数加权移动平均(First-order Exponential Weighted Moving Average,简称EWMA)因其计算量小、内存占用低、响应特性可控,成为工业现场最常用的方法。其核心公式即为:
$$ \text{Avg} := (\text{OldAvg} \times 0.9) + (\text{NewVal} \times 0.1) $$
该式看似简单,但要真正可靠、可复用、可维护地部署于真实PLC项目中,需系统解决变量声明、初始化、数据类型匹配、抗饱和处理、使能控制、参数配置化等十余个实操细节。本文将全程以ST语言为载体,不依赖任何特定品牌PLC(如西门子S7-1200/1500、罗克韦尔ControlLogix、倍福TwinCAT),仅使用IEC 61131-3通用语法,手把手带你写出一段可直接粘贴进工程、经得起长期运行考验的模拟量滤波程序。
一、理解公式背后的物理意义与工程参数
公式 Avg := (OldAvg * 0.9) + (NewVal * 0.1) 不是随意设定的系数,它对应一个明确的时间常数(Time Constant)τ,决定滤波器对突变信号的“迟滞”程度。
设采样周期为 T(单位:秒),则滤波系数 α = 0.1 与时间常数 τ 的关系为:
$$ \alpha = 1 - e^{-T/\tau} $$
当 α = 0.1 时,解得 τ ≈ 9.5T。这意味着:
- 若PLC主任务扫描周期
T = 100 ms,则该滤波器的时间常数约为950 ms; - 输入信号发生阶跃变化后,输出需约
3τ ≈ 2.85 s才能到达终值的95%; - 高频噪声(周期远小于
τ)被显著衰减,而缓慢变化的过程量得以保留。
关键结论:0.1 不是固定值,而是可调参数。工程中应根据信号特性与控制要求动态配置。例如:
- 压力变送器(响应慢、噪声小)→
α = 0.05(τ ≈ 19T,更平滑); - 热电偶冷端补偿(易受工频干扰)→
α = 0.2(τ ≈ 4.5T,更快响应); - 频繁开关负载引起的电压毛刺 →
α = 0.3(τ ≈ 2.5T,强抑制)。
因此,绝不能将 0.9 和 0.1 写死在代码里。必须将其抽象为可配置变量。
二、ST程序结构设计:模块化、可复用、防错
一个健壮的滤波功能块(FB)应包含以下要素:
| 要素 | 说明 | 必要性 |
|---|---|---|
Input |
原始模拟量输入(REAL) | ★★★★☆ |
Enable |
使能信号(BOOL),控制滤波是否生效 | ★★★★☆ |
Alpha |
滤波系数 α(REAL,范围 0.0–1.0) | ★★★★★ |
Reset |
复位信号(BOOL),强制清零历史值 | ★★★★☆ |
Output |
滤波后输出(REAL) | ★★★★☆ |
OldAvg |
内部保持变量,存储上一周期滤波值 | ★★★★★ |
| 初始化保护 | 首次执行时避免 OldAvg 为未定义值(如0.0或NaN) |
★★★★★ |
注:“必要性”星级表示该要素缺失将导致功能失效(★★★★★)或可靠性下降(★★★☆)
三、完整ST代码实现(符合IEC 61131-3,无品牌依赖)
以下代码可直接复制到支持ST的PLC编程环境(如Codesys、TIA Portal ST编辑器、Unity Pro ST视图)中,作为独立功能块(Function Block)使用。
FUNCTION_BLOCK FB_AnalogFilter
VAR_INPUT
Input : REAL; // 原始模拟量(如PT100转换后的℃值)
Enable : BOOL := TRUE; // 默认启用滤波
Alpha : REAL := 0.1; // 默认滤波系数(α=0.1 → τ≈9.5T)
Reset : BOOL := FALSE;// 复位请求(上升沿有效)
END_VAR
VAR_OUTPUT
Output : REAL; // 滤波后输出
END_VAR
VAR
OldAvg : REAL := 0.0; // 静态变量:保持上一周期滤波值
bReset : BOOL := FALSE;// 内部复位标志(检测上升沿)
bFirst : BOOL := TRUE; // 首次执行标志(确保OldAvg安全初始化)
END_VAR
// ===== 步骤1:检测Reset上升沿 =====
bReset := Reset AND NOT bReset;
bReset := bReset OR (NOT Reset AND bReset); // SR触发器防抖(可选,增强鲁棒性)
// ===== 步骤2:复位处理 =====
IF bReset THEN
OldAvg := Input; // 复位时直接加载当前值,避免突变
bFirst := TRUE;
ELSIF bFirst THEN
// 首次执行:用Input初始化OldAvg,避免0.0导致初始偏差
OldAvg := Input;
bFirst := FALSE;
END_IF;
// ===== 步骤3:使能判断与滤波计算 =====
IF Enable THEN
// 关键:先检查Alpha有效性,防止除零或溢出
IF (Alpha >= 0.0) AND (Alpha <= 1.0) THEN
Output := (OldAvg * (1.0 - Alpha)) + (Input * Alpha);
OldAvg := Output; // 更新历史值供下周期使用
ELSE
// Alpha越界:直通原始值,并可选置位诊断位(此处省略)
Output := Input;
END_IF;
ELSE
// 使能关闭:直通原始值,OldAvg保持不变(维持状态)
Output := Input;
END_IF;
四、关键细节逐行解析(为什么这么写?)
-
VAR中OldAvg := 0.0的初始化含义
:=是IEC 61131-3的初始赋值操作符,仅在功能块首次实例化时执行一次。后续每次调用,OldAvg保持上周期结束时的值(即“静态变量”行为)。这是实现递归滤波的基础。 -
bFirst := TRUE与首次赋值逻辑
PLC上电后,某些平台可能将REAL变量初始化为NaN(非数字)。若直接执行(NaN * 0.9) + (Input * 0.1),结果仍为NaN,导致整个滤波链失效。bFirst标志确保第一周期用Input安全填充OldAvg,彻底规避NaN风险。 -
Reset上升沿检测的双稳态写法bReset := Reset AND NOT bReset; bReset := bReset OR (NOT Reset AND bReset);这是经典的SR触发器(置位-复位锁存器)ST实现。它将瞬时
Reset信号锁存为一个持续周期的bReset脉冲,确保复位动作只执行一次,避免因Reset信号持续多个周期导致反复覆盖OldAvg。 -
Alpha越界保护的必要性
若误将Alpha设为1.5,则(1.0 - Alpha)为负数,滤波器变为发散型(输出振荡放大);若设为-0.2,则1.0 - Alpha = 1.2,同样导致不稳定。该判断是工业代码的必备防御措施。 -
Enable = FALSE时OldAvg保持不变的设计意图
当滤波被禁用(如维护模式),输出直通Input,但OldAvg不更新。一旦重新启用,滤波从上次保存的状态继续,避免输出跳变。这是平滑切换的关键。
五、工程部署建议(不止于代码)
1. 参数配置方式
- 在HMI或上位机中,为每个滤波实例提供
Alpha设置框,标注对应τ/T值(如“α=0.1 → 平滑时间≈9.5个扫描周期”); - 对同一类传感器(如所有PT100),在项目库中预设典型
Alpha值,减少现场调试工作量。
2. 诊断与监控
- 在功能块中增加
Status输出(如BOOL数组),标记AlphaOutOfRange、NaNDetected等状态; - 将
OldAvg、Input、Output同时映射至HMI趋势图,直观对比滤波效果。
3. 多通道批量处理
若需同时滤波10路温度信号,不要复制10次功能块代码。正确做法:
- 声明数组:
arrTempRaw : ARRAY[1..10] OF REAL; - 实例化单个功能块:
FB_Filter10 : FB_AnalogFilter; - 循环调用:
FOR i := 1 TO 10 DO FB_Filter10(Input := arrTempRaw[i], Alpha := 0.1, Enable := TRUE); arrTempFiltered[i] := FB_Filter10.Output; END_FOR;
4. 与硬件滤波协同
ST软件滤波不能替代前端硬件措施:
- 传感器屏蔽线必须单点接地;
- 模拟量输入模块应启用内置的50/60Hz陷波(如S7-1200的“Filter frequency”设置);
- 强干扰环境加装信号隔离器。
软件滤波是硬件滤波的补充,而非替代。
六、性能验证方法(现场必做)
编写测试用例,在真实PLC中验证滤波器行为:
-
阶跃响应测试
- 给定
Input从25.0突变至35.0(Δ=10.0); - 记录
Output每周期值; - 验证第1周期:
Output = 25.0×0.9 + 35.0×0.1 = 26.0; - 第2周期:
26.0×0.9 + 35.0×0.1 = 26.9; - 依此类推,确认收敛曲线符合
Output = 35.0 - 10.0×e^(-n×0.1)(n为周期数)。
- 给定
-
抗噪能力测试
- 叠加±0.5℃随机噪声到稳定30.0℃信号;
- 观察
Output波动幅度是否压缩至±0.05℃以内(理论衰减比≈α=0.1)。
-
边界压力测试
Alpha := 0.0→Output应恒等于初始OldAvg(直通关闭);Alpha := 1.0→Output应恒等于Input(无滤波);Input := NAN→Output应保持上一有效值(不传播NaN)。
七、常见错误及修正方案
| 错误现象 | 根本原因 | 修正动作 |
|---|---|---|
滤波输出缓慢爬升,始终追不上 Input |
OldAvg 未正确更新(如漏写 OldAvg := Output;) |
检查代码末尾赋值语句 |
| 上电后输出为0或极大值 | OldAvg 初始值未保护,遇NaN |
强制添加 bFirst 初始化逻辑 |
Reset 一次后,后续再按无效 |
bReset 未在执行后清零 |
在 IF bReset THEN ... END_IF; 块内末尾添加 bReset := FALSE; |
HMI显示 Output 跳变 |
Enable 信号在切换瞬间抖动 |
在 Enable 输入前增加100ms硬件消抖或软件延时滤波 |
八、进阶:自适应滤波(可选扩展)
当过程动态特性变化大(如加热阶段 vs 恒温阶段),固定 Alpha 效果不佳。可升级为自适应版本:
// 计算输入变化率
Delta := ABS(Input - OldAvg);
// 动态调整Alpha:变化大时增大Alpha(快响应),变化小时减小Alpha(强滤波)
IF Delta > 0.5 THEN
Alpha := 0.25;
ELSIF Delta < 0.05 THEN
Alpha := 0.05;
ELSE
Alpha := 0.1;
END_IF;
此逻辑需谨慎评估CPU负载——每毫秒级任务中避免过多分支计算。
九、总结:一条可落地的黄金准则
所有模拟量进入控制逻辑前,必须经过显式、参数化、带诊断的滤波;滤波系数
Alpha必须作为可配置参数暴露给调试人员,严禁硬编码;首次运行与复位场景必须有确定性初始化,杜绝NaN与不确定状态。
这一准则不是理想主义,而是数十年工业现场故障分析沉淀出的血泪经验。当你写下 Avg := (OldAvg * 0.9) + (NewVal * 0.1) 时,你写的不仅是一行数学表达式,更是一道守护系统稳定性的逻辑闸门。

暂无评论,快来抢沙发吧!