ST语言实数比较直接使用等号(=)导致精度误差的容差写法

发布于 2026-03-17 07:00:35 · 浏览 5 次 · 评论 0 条

在 ST(Structured Text)语言中编写电气自动化控制逻辑时,常需对实数(REALLREAL 类型)进行相等性判断,例如检测温度是否达到设定值、电机转速是否稳定在目标转速、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.100000001490116119384765625
  • 0.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 又会丧失判断意义。

三步设定法(推荐)

  1. 明确变量的工程单位与有效分辨率
    查阅传感器手册或模块规格书,确认该信号的实际最小可分辨变化量。
    例如:

    • PT100 温度模块,量程 -50...200°C,16 位 ADC,理论分辨率为 $250 / 65535 ≈ 0.0038°C$;实际噪声下,可靠分辨约 0.1°C
    • 编码器测速,脉冲当量 0.1 rpm,则速度值天然离散,0.05 rpm 即为合理容差下限。
  2. 取“分辨率的 2~5 倍”作为初始容差
    既避开量化噪声干扰,又保留足够区分度。

    • 温度示例 → 容差取 REAL#0.2REAL#0.5
    • 转速示例 → 容差取 REAL#0.2REAL#0.5
  3. 在真实工况中验证并微调
    将逻辑下载至 PLC,用示波器或趋势图观察 ABS(rA - rB) 的实际波动范围:

    • 若 99% 时间内该值 < 0.15,则 tolerance := REAL#0.2 可靠;
    • 若频繁出现 0.25 波动,则需上调至 REAL#0.3
    • 若始终 < 0.01,可保守下调至 REAL#0.05,但不建议低于传感器标称分辨率的 2 倍

常见场景容差参考表

物理量 典型量程 推荐容差(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(...).equalABS(...) <= ... 更易读懂;
  • 强制参数化:避免硬编码容差值散落在各处;
  • 支持在线修改:多数 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 中无 == 运算符,语法错误 仅用单等号 = 作赋值,比较必须用 =(但需容差)

调试验证:三步确认容差逻辑生效

  1. 仿真测试:在 PLC 编程软件中启用在线监控,手动修改 rA, rB 值,观察 ABS(rA-rB)equal 输出是否按预期切换;
  2. 注入扰动:在运行中临时叠加 ±0.05 噪声到 rB,确认 equal 不发生高频抖动;
  3. 长期运行记录:用 PLC 内置数据记录功能,持续采集 ABS(rA-rB) 一小时,统计最大值,确保其 < 0.9 × tolerance(留 10% 余量)。

最终结论:将容差比较设为团队开发规范

在电气自动化项目中,所有涉及 REAL/LREAL 的相等性判断,必须显式使用容差机制。将其写入《ST 编码规范》第一条,并作为代码审查(Code Review)的强制项。可配置 PLC IDE 的静态检查规则,自动标记未使用 ABS()REAL 等号比较。

记住:

  • =精确数学相等,只适用于整数、枚举、字符串字面量;
  • ABS(a-b) <= tol工程意义上的相等,是自动化控制的生命线。

把容差当作和“接地端子”“断路器额定电流”同等重要的设计参数——它不炫技,却决定系统是否真正可靠。

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文