在 ST(Structured Text)语言中编写电气自动化控制逻辑时,常需对实数(REAL 或 LREAL 类型)进行相等性判断,例如检测温度是否达到设定值、电机转速是否稳定在目标转速、PID 输出是否收敛等。直接使用 = 运算符比较两个实数,极易因浮点数固有精度缺陷导致逻辑误判——本应“相等”的值被判定为“不等”,进而引发控制跳变、状态卡滞、报警误触发等问题。这不是程序 bug,而是 IEEE 754 浮点表示法的必然结果。
为什么 A = B 在 ST 中不能用于实数相等判断?
ST 语言遵循 IEC 61131-3 标准,其 REAL 类型通常对应 IEEE 754 单精度(32 位),LREAL 对应双精度(64 位)。这类格式用有限二进制位表示十进制小数,多数常见十进制数(如 0.1, 0.3, 3.14)无法被精确表达。
例如,在大多数 PLC 中执行以下语句:
r1 := 0.1 + 0.2;
r2 := 0.3;
bEqual := (r1 = r2); // 结果为 FALSE!
原因在于:
0.1的二进制近似值为0.1000000014901161193847656250.2的二进制近似值为0.20000000298023223876953125- 二者相加得
0.300000004470348358154296875 - 而直接赋值的
0.3实际存储为0.299999999999999988897769753748434595763683319091796875
二者差值约为 $4.47 \times 10^{-9}$,虽微小,但 = 判断要求逐位完全相同,因此返回 FALSE。
该现象在闭环控制中尤为危险:
- 若用
IF speedActual = speedSet THEN ...触发“已达目标”动作,该条件几乎永不会成立; - 若用
IF error = 0.0 THEN ...判断 PID 收敛,则系统永远无法进入稳态处理分支。
正确解法:引入容差(Tolerance)的绝对误差比较
核心思想:不判断“是否完全相等”,而判断“是否足够接近”。即验证两实数之差的绝对值是否小于预设阈值(tolerance)。
标准写法如下(以 REAL 类型为例):
bIsEqual := ABS(rA - rB) <= tolerance;
其中:
rA,rB是待比较的REAL变量或表达式;ABS()是 ST 内置绝对值函数(IEC 61131-3 标准函数块ABS,支持REAL);tolerance是用户定义的容差值,类型须与rA,rB一致(如REAL#0.001);<=是安全的非严格不等式,覆盖“差值恰好等于容差”的边界情况。
✅ 此写法完全符合 IEC 61131-3 语法,所有主流 PLC 平台(倍福 TwinCAT、西门子 TIA Portal、罗克韦尔 Studio 5000、施耐德 EcoStruxure、汇川 AutoShop)均原生支持。
如何科学设定容差值(tolerance)?
容差不是越小越好,也不是越大越安全。它必须与物理量纲、测量精度、控制需求匹配。盲目设为 REAL#0.000001 可能仍无法解决误差,而设为 REAL#1.0 又会丧失判断意义。
三步设定法(推荐)
-
明确变量的工程单位与有效分辨率
查阅传感器手册或模块规格书,确认该信号的实际最小可分辨变化量。
例如:- PT100 温度模块,量程
-50...200°C,16 位 ADC,理论分辨率为 $250 / 65535 ≈ 0.0038°C$;实际噪声下,可靠分辨约0.1°C。 - 编码器测速,脉冲当量
0.1 rpm,则速度值天然离散,0.05 rpm即为合理容差下限。
- PT100 温度模块,量程
-
取“分辨率的 2~5 倍”作为初始容差
既避开量化噪声干扰,又保留足够区分度。- 温度示例 → 容差取
REAL#0.2至REAL#0.5; - 转速示例 → 容差取
REAL#0.2至REAL#0.5。
- 温度示例 → 容差取
-
在真实工况中验证并微调
将逻辑下载至 PLC,用示波器或趋势图观察ABS(rA - rB)的实际波动范围:- 若 99% 时间内该值 <
0.15,则tolerance := REAL#0.2可靠; - 若频繁出现
0.25波动,则需上调至REAL#0.3; - 若始终 <
0.01,可保守下调至REAL#0.05,但不建议低于传感器标称分辨率的 2 倍。
- 若 99% 时间内该值 <
常见场景容差参考表
| 物理量 | 典型量程 | 推荐容差(REAL) | 说明 |
|---|---|---|---|
| 温度(PT100) | -50…200°C | REAL#0.3 |
覆盖工业级传感器 ±0.3°C 精度 |
| 压力(4–20mA) | 0…10 bar | REAL#0.02 |
对应 0.2% FS,兼顾 12 位采集卡噪声 |
| 电机转速 | 0…3000 rpm | REAL#2.0 |
编码器 1000 PPR 下,1 rpm 当量 ≈ 0.033 Hz |
| 模拟输出(AO) | 0…10 V | REAL#0.01 |
DAC 16 位,LSB ≈ 150 µV,取 66× LSB |
| PID 控制误差 | ±100% | REAL#0.5 |
以工艺允许稳态偏差为基准(如 ±0.5%) |
⚠️ 注意:表中数值为起点,必须结合现场信号质量实测调整。电磁干扰强的场合(如变频器旁),容差需上浮 30%~100%。
封装为可复用函数块(FB)提升可靠性与可维护性
重复书写 ABS(a-b) <= tol 易出错且难统一管理。建议封装为标准函数块,例如命名 FB_RealEqual:
FUNCTION_BLOCK FB_RealEqual
VAR_INPUT
a : REAL;
b : REAL;
tolerance : REAL := REAL#0.01; // 默认容差,可覆盖
END_VAR
VAR_OUTPUT
equal : BOOL;
END_VAR
VAR
diff : REAL;
END_VAR
diff := a - b;
equal := ABS(diff) <= tolerance;
调用方式简洁清晰:
// 判断温度是否进入设定带(±0.3°C)
bTempStable := FB_RealEqual(a:=tempActual, b:=tempSet, tolerance:=REAL#0.3).equal;
// 使用默认容差(0.01)比较两个计算中间值
bCalcOK := FB_RealEqual(a:=val1, b:=val2).equal;
优势:
- 一处修改,全局生效:调整默认容差或算法(如后续升级为相对容差),只需改 FB 内部;
- 语义明确:
FB_RealEqual(...).equal比ABS(...) <= ...更易读懂; - 强制参数化:避免硬编码容差值散落在各处;
- 支持在线修改:多数 PLC 支持运行时修改
tolerance输入值,便于调试。
进阶技巧:相对容差(Relative Tolerance)适用场景
绝对容差(ABS(a-b) <= tol)适用于量级稳定的变量。但当比较值跨度极大时(如 a=1000.0, b=1000.001 vs a=0.001, b=0.001001),同一绝对容差可能对大值过松、对小值过严。
此时应采用相对容差:
$$
\text{equal} := \frac{|a - b|}{\max(|a|, |b|, \varepsilon)} \leq \text{relTol}
$$
其中 $\varepsilon$ 是极小正数(如 REAL#1.0E-12),防止分母为零。
ST 实现(含防零保护):
FUNCTION FB_RealEqualRel : BOOL
VAR_INPUT
a : REAL;
b : REAL;
relTol : REAL := REAL#1.0E-5; // 默认 10 ppm
END_VAR
VAR
absDiff : REAL;
maxAbs : REAL;
denominator : REAL;
END_VAR
absDiff := ABS(a - b);
maxAbs := MAX(ABS(a), ABS(b));
denominator := MAX(maxAbs, REAL#1.0E-12);
FB_RealEqualRel := (absDiff / denominator) <= relTol;
✅ 适用场景:
- 标幺化(pu)值比较(如电压 0.95~1.05 pu);
- 动态范围 > 1000:1 的模拟量(如电流从 0.01A 到 50A);
- 数学库函数验证(如
SIN(x)近似精度)。
❌ 不适用场景:- 接近零的值(如偏差信号),此时相对容差失效,必须回退到绝对容差。
避坑指南:5 个高危错误写法及修正
| 错误写法 | 问题分析 | 正确写法 |
|---|---|---|
IF r1 = r2 THEN |
浮点直接等号,必失效 | IF ABS(r1 - r2) <= REAL#0.1 THEN |
IF r1 - r2 = 0.0 THEN |
差值仍为浮点,未消除精度误差 | 同上,必须用 ABS() 包裹后比较 |
IF r1 = REAL#3.14 THEN |
字面量 3.14 本身是近似值 |
改用 REAL#3.1415926(更高精度字面量)或容差比较 |
tolerance := 0.01; |
缺少类型声明,部分平台报错(如 TwinCAT) | tolerance := REAL#0.01; |
equal := (a == b); |
ST 中无 == 运算符,语法错误 |
仅用单等号 = 作赋值,比较必须用 =(但需容差) |
调试验证:三步确认容差逻辑生效
- 仿真测试:在 PLC 编程软件中启用在线监控,手动修改
rA,rB值,观察ABS(rA-rB)和equal输出是否按预期切换; - 注入扰动:在运行中临时叠加
±0.05噪声到rB,确认equal不发生高频抖动; - 长期运行记录:用 PLC 内置数据记录功能,持续采集
ABS(rA-rB)一小时,统计最大值,确保其 <0.9 × tolerance(留 10% 余量)。
最终结论:将容差比较设为团队开发规范
在电气自动化项目中,所有涉及 REAL/LREAL 的相等性判断,必须显式使用容差机制。将其写入《ST 编码规范》第一条,并作为代码审查(Code Review)的强制项。可配置 PLC IDE 的静态检查规则,自动标记未使用 ABS() 的 REAL 等号比较。
记住:
=是精确数学相等,只适用于整数、枚举、字符串字面量;ABS(a-b) <= tol是工程意义上的相等,是自动化控制的生命线。
把容差当作和“接地端子”“断路器额定电流”同等重要的设计参数——它不炫技,却决定系统是否真正可靠。

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