数值转换链

每个点位共用的那条带类型的转换链,从原始读数到工程值、两条无效读数策略、越限之后的处理方式、布尔和文本的变换,以及一次写入是怎么把各个环节反算回去的。

以 Markdown 查看

每个点位都共用同一条带类型的转换链,把原始读数变成工程值。这条链住在点位自己身上:点位页面上的“转换”卡片和设备表格显示的是同样那些环节,而落到 Logic、仪表画面、记录器和对外 OPC UA 节点上的那个值,就是从最后一个环节出来的那个。

先有原始值

这条链是从按点位数据类型强制转换过的原始值开始的,不是从驱动自己的那个对象开始的:一个驱动把 3.7 交给一个 Int32 点位,卡片顶上读到的就是 4,而后面每一个环节都从这个 4 往下走。声明的类型根本装不下的读数(声明为数值却来了文本)算作一次空读数,绝不会变成一个凑数的零。到了另一头,工程值又被强制转换回同一种类型,所以一个 Float 点位会舍入到 float 能表示的那个值。

各个环节

对数值类型来说,这条链是一串环节,每个环节各有自己的勾选框;关掉的环节把输入原样放过去,而卡片会在每个环节末尾显示当时的值,好让你跟着一次实时读数走完整套算法:

环节 默认 作用
量程换算 scaled = raw × Angular + Linear。斜率默认 1,截距默认 0。斜率填 0 会在打字的地方就被拒绝(“换算系数为 0 会把每一次读数都归零。请填入要乘的那个系数(填 1 保持原值)。”),因为它会把每一次读数都归零,而预览和存下来的转换链绝不能互相矛盾。
校准 作用在换算结果上的第二对线性系数:calibrated = scaled × Angular + Linear。它和量程换算分开,好让一次校前/校后修正不去搅动量程那套算法,而且它由自己的权限把守,见校准。斜率填 0 同样被拒绝。
无效读数 始终显示 给拿不出可用数字的读数用的两条策略(见下)。它不是勾选框:它的“关”本身就是其中一个答案。
限值 拿这个值去和下限(默认 0)与上限(默认 100)比较,并执行选中的越限处理方式(见下)。上下界会被规整,所以下限填得比上限高也不会出错:两者中小的那个就是底。
小数位 舍入到小数位数,默认 2,接受 0 到 15。

两个线性环节都带一个两点法助手,用两个参考点算出那一对系数;它在校准里一步一步地讲。

设备答了,但没给出数字

热电偶断了,某个通道上没接传感器:读数到了,现场设备也在说话,但这次测量是 NaN。只对数值点位有效,而且不管选哪一条,质量都保持良好:

策略 效果
原样放过去(默认) 这个 NaN 原封不动地往下走,并且完全跳过限值环节,不管那个环节带的是哪种处理方式:限值判的是数字,而这里没有数字。无穷不是 NaN,仍然会在量程上饱和。
用一个值替代 从这个环节起,声明的那个数字顶上去,并且像任何一次读数一样进入限值、小数位和最后的强制转换。

设备根本没答

一次超时,一根被切断的线缆,一台被关掉的现场设备,一次驱动异常。所有类型都适用,只不过读时间戳、标识符或字节块的点位只提供前两条策略:声明的替代值是一个数字,而那三种类型都不能从一个数字造出来。

策略 效果
把错误显出来(默认) 点位读作空,它的质量转为不可用,于是这次失败一下子在所有地方都浮现出来。
保持最近一次好的值 最后一次落地的读数继续显示,不设过期,直到现场设备重新应答为止。时间戳仍然指着那次读数,因为那才是这个数字被测出来的时刻。第一次读数落地之前什么都不保持,那时点位读作空。
用一个值替代 声明的那个数字按声明的样子呈现:没有读数可以走完各个环节,所以它不做量程换算、不做校准、也不做舍入,只是被强制转换成点位的类型。凡是强制转换能把一个数字带进去的类型都提供这一条,也就是除 DateTime、Guid 和 ByteString 之外的每一种类型。

替代值从不悄无声息:“实时数值”卡片会打出原因(“最近一次好的值,在设备不应答期间保持。”),实时圆点转成琥珀色,内置 OPC UA 服务器发布这个值时带的是“替代”状态,而不是单纯的 Good。策略要求它待多久,它就一直被发布多久:一台一直不应答的设备,不会让外部客户端在替代值和读取失败之间来回跳,所以那个客户端读到的就是面板显示的东西。设备一应答,读数本身立刻把这个点收回去;把替代值关掉也一样。选择一个替代值就是选择可用性,所以报警和表达式会继续把这个点当作有值来判;这么做的代价是摆在明面上还的,因为诊断日志照样记下那次失败的读取,设备健康状态也照样报告设备离线。替代值回答的是“这个点应该显示什么”,从来不是“现场设备在不在”。声明的替代值落在已启用的限值之外时,会在打字的地方就被提醒:“超出限值范围 [0, 100]:这是替代一次失败读取的那个值。”

越限的值

值落在下限和上限之外时,限值的处理方式有:

处理方式 值变成 质量
空值 一个空档(没有值)。 良好
钳位(默认) 最近的那个界。 良好
报错并置空 一个空档。 不可用(越限故障)
报错并钳位 最近的那个界。 不可用(越限故障)
NaN NaN。 良好。只对 Float 和 Double 点位提供,因为只有这两种类型表示得了它;它让一个 Process 通道能把这个无效值分门别类。整数点位上被一次代理写入或一次还原的备份留下的 NaN 处理方式,会退化成“空值”那个空档。

越限故障会并进点位的实际质量,所以实时圆点、属性表达式和报警都直接看到这个越限的值是不可用的,不必再接什么线,“转换”卡片也会打出“数值 130 超出限值范围 [0, 100]。”不过它终究是一个过程状况,而不是连接问题,设备健康状态不会因此把设备算成离线。

布尔、文本和其他类型

非数值类型在同一张“转换”卡片里有自己的变换:

  • 布尔取反报告原始值的逻辑非。
  • 文本子串起点(从 0 起)和长度从原始字符串里切一个窗口出来;长度留空就一直切到末尾,越界的边界会被钳位而不是报错。
  • 其余每一种类型(DateTime、Guid、ByteString)都原样直通,不显示“转换”卡片。

“把错误显出来”和“保持最近一次好的值”对每一种类型都适用;“用一个值替代”只在声明的数字能变成一次读数的地方提供,所以 DateTime、Guid 和 ByteString 的点位不列它。NaN 那条策略只对数值点位适用。

写入把转换链反过来走

“实时数值”卡片上的写入字段接收一个工程值,并按顺序把那些已启用、可反算的环节反过来走一遍:限值环节启用时先按下限和上限钳位(写入永远是钳位,绝不丢弃,不管越限处理方式是哪一种),再反校准((value − Linear) ÷ Angular),再照样反换算,最后强制转换成点位的类型。舍入是有损的,不做反算。布尔输入会重新应用一次取反。文本的子串只影响显示,所以写文本时是把整个值原样发出去;DateTime、Guid 和 ByteString 直通。外部 OPC UA 客户端写到对外节点上的值本来就是原始值,这一整套一个都不经过。