累计流量库的改进
1. 累计流量库的改进
项目中有大量的计量加注的应用,系统设计使用模拟量4-20mA 读取瞬时流量, PLC再根据瞬时流量累计计算总流量。就此应用我们最初借鉴使用了西门子“Totalizer”流量累计库。但该库使用过程中发现该库的累计流量累计数值累计到较大数值后,会出现累计流量不增加的现象。分析查找原因发现,该库设计使用REAL 数据类型相加的方式,但是在计算机中,实数的表示是有限的,而且有精度限制。当一个很大的实数与一个很小的实数直接相加或相减时,可能会导致小数部分被截断或丢失,从而导致计算结果偏差。其在统计累计流量应用中的具体表现为流量累积程序在运行之初是正常的,因为累计流量初始值及流量瞬时值都为一个很小的浮点数,两数相加后,结果正确。但是当一段时间后,累计流量的数值逐渐增大,当它与瞬时流量的数值相差很远的时候,两者执行加法操作后,瞬时流量的数值将被忽略掉(如9999990.0与0.2做加法操作)。
通常我们解决上述问题时,可使用拆分数据小数部分和整数部分分别相加的方式,但此方式编程比较复杂,此项目中我们使用Kahan 算法解决流量累加误差问题,Kahan 算法的原理是通过一个中间变量记录累计误差,当下次计算时,把累计误差补上,并且把累计误差更新到求和结果,如果累计误差值过小不能被正常累加上,则累加误差值将继续增加,等到达可以计算的精度后再累加,具体代码呈现如下所示。
IF #reset THEN //复位清零
#statValUpd := 0.0;
#sum := 0.0;
#statDetaVal := 0.0;
END_IF;
#statValUpd := #val - #statDetaVal; //累计误差,同阶相减,更新累计误差
#statTempSum := #sum + #statValUpd; //累计求和临时值,异阶会出现偏差
#statDetaVal := #statTempSum - #sum - #statValUpd; // 求累计误差值,同阶相减,出现偏差时,产生累计值
#sum := #statTempSum; // 累加求和结果输出