梯形图模拟量转换公式中整型除法导致精度丢失的类型转换

发布于 2026-03-17 10:18:45 · 浏览 5 次 · 评论 0 条

在PLC编程中,梯形图(LAD)是工业现场最常用的编程语言之一。当处理模拟量信号(如4–20 mA电流、0–10 V电压)时,常需将PLC采集到的整型原始值(如AIW0寄存器中的16位无符号整数0–65535)转换为工程单位(如温度℃、压力bar、液位m)。这一过程看似简单,但若直接使用整型除法,极易因截断式舍入(truncating division) 导致精度丢失——轻则显示值跳变±0.5℃,重则闭环控制失稳、PID调节振荡。本文直击该问题本质,提供可立即落地的五步排查与四类修正方案,所有操作均基于西门子S7-1200/S7-1500、三菱FX系列、欧姆龙CP系列等主流PLC通用逻辑,无需额外硬件或高级指令。


一、问题定位:为什么整型除法会“悄悄”吃掉精度?

PLC梯形图中,DIV(整数除法)指令对两个整数执行向零取整运算。例如:

  • 1000 ÷ 3 = 333(而非333.333…)
  • 65535 ÷ 100 = 655(而非655.35)

该特性在模拟量转换公式中放大为系统性误差。典型转换公式如下:

$$ \text{工程值} = \frac{\text{原始值} - \text{下限原始}}{\text{上限原始} - \text{下限原始}} \times (\text{上限工程} - \text{下限工程}) + \text{下限工程} $$

以某压力变送器为例:

  • 输入范围:4–20 mA → PLC AD模块映射为整数 0–65535
  • 工程范围:0–16 bar
  • 原始下限 = 0,原始上限 = 65535,工程下限 = 0,工程上限 = 1600(单位:0.01 bar,即保留两位小数)

若按常规整型思路编写梯形图:

  1. 计算分子原始值 - 0 = 原始值(无损)
  2. 计算分母65535 - 0 = 65535(无损)
  3. 执行整除原始值 × 1600 ÷ 65535

问题就出在第三步——× 1600÷ 65535 的顺序。由于PLC不支持浮点中间结果,若先乘后除,中间值可能溢出(如 65535 × 1600 = 104,856,000 > 32位有符号整数最大值2,147,483,647);若先除后乘,则 原始值 ÷ 65535 恒为 0(当原始值 < 65535),彻底归零。

更隐蔽的是“伪安全”写法:用32位整数(DINT)暂存,再做 DIV。此时虽避免溢出,但 DIV 仍强制截断小数部分。例如原始值 32768(对应理论压力8.00 bar):

  • 理论计算:$ \frac{32768}{65535} \times 1600 = 799.996 $ → 应显示 7.99996 bar ≈ 8.00 bar
  • 整型执行:32768 × 1600 = 52,428,80052,428,800 ÷ 65535 = 800(精确!)
  • 但原始值 3276732767 × 1600 = 52,427,20052,427,200 ÷ 65535 = 799(理论应为 799.992,被截为 799 → 显示 7.99 bar,误差 0.008 bar)

误差虽小,但在0–100%全程累计后,最大偏差可达 ±0.5 工程单位(取决于量程缩放系数),且呈阶梯状跳变——这正是现场仪表显示“抖动”、趋势图呈锯齿状的根本原因。


二、四类实操修正方案(按推荐优先级排序)

方案1:改用浮点除法(首选,兼容性最佳)

所有主流PLC均支持浮点指令,且S7-1200/1500、FX5U、CP1E等已默认启用浮点运算单元。关键在于显式声明数据类型并调用浮点指令

  1. 声明变量为REAL类型:在变量表中,将中间变量(如 RawValueScaledValue)的数据类型设为 REAL,而非 INTDINT
  2. 使用浮点除法指令
    • 西门子:拖入 DIV_R 指令(非 DIV),输入端 IN0REAL 型原始值,IN1REAL 型分母(如 65535.0)。
    • 三菱:使用 DDIV(双字除法)配合浮点转换,或直接调用 FRD(Float Read)→ FDIV(Float Divide)→ FWR(Float Write)。
    • 欧姆龙:用 @DIVF 指令(F后缀表示浮点)。
  3. 公式重构为单步浮点运算
    ScaledValue := (RawValue - 0.0) / 65535.0 * 1600.0;
    (注意:所有常数加 .0 强制为浮点,避免编译器隐式转为整型)

✅ 优势:精度达IEEE 754单精度(约6–7位有效数字),完全覆盖工业需求;逻辑清晰,易于审计。
⚠️ 注意:确保PLC固件版本支持浮点(S7-1200 V2.0+、FX3U+、CP1E-A等均原生支持);避免在高速扫描周期(<10 ms)内大量浮点运算(影响CPU负载)。

方案2:比例缩放法(零浮点,抗干扰强)

当PLC不支持浮点或需极致确定性时,采用预计算缩放系数+定点移位

  1. 计算最优缩放因子
    目标是让 RawValue × K 的结果在32位整数范围内,且 K 尽可能接近真实比例 1600 / 65535 ≈ 0.02441445
    K = 1000000(10⁶),则:
    $$ \text{ScaledValue} = \left\lfloor \frac{\text{RawValue} \times 1000000}{65535} \right\rfloor \div 1000000 \times 1600 $$
    但此式仍有两处整除。优化为:
    $$ \text{ScaledValue} = \left\lfloor \frac{\text{RawValue} \times 1600 \times 10000}{65535} \right\rfloor \div 10000 $$
    此时分子最大值:65535 × 1600 × 10000 = 1,048,560,000,000 → 超32位,故改用64位(LREAL或DINT组合)。

  2. PLC实现(以S7-1200为例)

    • 声明 Temp_DWORDDWORD(32位无符号),Temp_LINTLINT(64位有符号)。
    • 第一步MOV 原始值 AIW0Temp_DWORD
    • 第二步D_INT 指令将 Temp_DWORD 转为 LINT 存入 Temp_LINT
    • 第三步MUL_R(64位乘法)Temp_LINT × 1600 → 结果存 Result_LINT
    • 第四步DIV_R(64位除法)Result_LINT ÷ 65535 → 得 Scaled_LINT(单位:0.0001 bar)。
    • 第五步DIV Scaled_LINT ÷ 10000 → 最终 INT 值(单位:bar,小数点后4位隐含)。

✅ 优势:全程整数运算,无浮点误差累积;结果可直接用于HMI整数显示控件。
⚠️ 注意:需确认PLC支持64位算术(S7-1200 V4.2+、FX5U全系支持);手动管理小数点位置,调试时需同步修改HMI解析逻辑。

方案3:查表插值法(超低速场景终极方案)

适用于更新率<1 Hz、精度要求极高(如实验室称重)的场合:

  1. 预生成转换表:在PC上用Excel或Python计算 RawValue065535 对应的全部 ScaledValue(REAL型),保存为CSV。
  2. 导入PLC数据块:将CSV转为PLC数组(如 DB1.DBW[0]DB1.DBW[131070],每个元素占2字节,共65536×2=131072字节)。
  3. 梯形图查表
    • 读取索引RawValue 直接作为数组下标(DB1.ARRAY[RawValue])。
    • 线性插值(可选):若 RawValue 非整数(如经滤波后为小数),取 Floor(RawValue)Ceil(RawValue) 对应值,按比例加权。

✅ 优势:绝对精度(查表值可预计算至任意精度);CPU占用趋近于零。
⚠️ 注意:占用大量内存(65536×4字节=256KB REAL数组);仅适用于量程固定、无需动态调整的传感器。

方案4:硬件补偿法(规避软件缺陷)

当PLC老旧无法升级、且现场允许硬件介入时:

  1. 选用带预处理功能的信号隔离器:如Weidmüller ACT20P、Phoenix Contact MINI MCR-SL,配置其内部DSP直接执行浮点转换,输出标准4–20 mA或0–10 V信号。
  2. PLC侧简化为线性映射:此时输入信号已是工程值(如0–16 bar对应0–10 V),PLC只需 SCALE 指令做一次 0–10000 → 0–1600 整数缩放(误差<0.01%)。

✅ 优势:彻底卸载PLC计算负担;抗EMI能力强(模拟信号经隔离)。
⚠️ 注意:增加采购与接线成本;需重新校准整个信号链路。


三、避坑指南:5个高频错误操作(附正确写法)

以下行为在工程现场出现率超80%,务必对照自查:

错误操作 后果 正确做法
DIV 指令前未将 INT 转为 DINT,且 原始值 × 系数 > 32767 中间结果溢出,数值突变为负数 使用 CONV 指令先转 DINT,再 MULDIV
公式写成 (RawValue / 65535) * 1600(先除后乘) RawValue < 65535 时结果恒为 0 必须保证乘法在除法前,或改用浮点
使用 ROUND 指令对整除结果四舍五入 无法修复根本截断误差,仅掩盖现象 删除 ROUND,从源头改用浮点或定点缩放
HMI画面绑定 INT 型变量直接显示,未设置小数位 显示 8 而非 8.00,掩盖精度问题 在HMI变量属性中强制设置“小数位数=2”,或PLC侧输出 REAL
依赖PLC系统时钟做毫秒级定时除法(如每10ms触发一次转换) CPU扫描周期抖动导致除法时机不稳,引入时序误差 将转换逻辑置于主循环OB1,禁用条件触发

四、验证方法:三步确认精度达标

  1. 边界值测试

    • 输入 RawValue = 0 → 输出应为 0.00(工程下限)
    • 输入 RawValue = 65535 → 输出应为 16.00(工程上限)
    • 输入 RawValue = 32768 → 输出应为 8.00 ± 0.005(理论中点)
  2. 斜坡测试
    用信号发生器以 1 单位/秒速度线性增加模拟量,观察HMI趋势图:

    • ✅ 正常:平滑直线,无阶梯、无跳变
    • ❌ 异常:每隔若干点出现 0.01 级跳变(整除截断特征)
  3. 反向验证
    任取一个转换后值(如 ScaledValue = 7.99),代入逆公式:
    $$ \text{RawValue} = \left\lfloor \frac{7.99 \times 65535}{16.00} \right\rfloor $$
    计算得 RawValue = 32766,再以此值正向转换,确认结果仍为 7.99(闭环一致)。


五、延伸提醒:其他易被忽视的精度陷阱

  • AD模块分辨率≠有效位数:标称16位AD(65536级)受噪声、温漂影响,实际有效位常为13–14位。若强行按16位满量程计算,底层数值本身已含±2 LSB误差。
  • 冷端补偿干扰热电偶:使用热电偶时,PLC内部冷端补偿温度若未校准,会叠加至转换结果,此时整除误差与补偿误差耦合放大。
  • HMI刷新率低于PLC扫描周期:即使PLC计算精准,HMI每500ms才更新一次,人眼看到的仍是离散值——需在HMI侧开启“平滑过渡”或增加本地滤波。

修改梯形图中的一处 DIVDIV_R,或增加一个 CONV 指令,即可消除整型除法带来的系统性精度丢失。

评论 (0)

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

扫一扫,手机查看

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