累计流量(西门子程序)

FUNCTION "FLUXbase" : VOID
VAR_INPUT
    PV : REAL ;         //瞬时流量
    CYC : REAL ;        //采样时间(MS)
    PLL : REAL ;        //最小瞬时流量
END_VAR
VAR_IN_OUT
    OV_ER1 : REAL ;      //累计偏差
    OV_ER2 : REAL ;      //累计偏差
    PV_ALT : REAL ;     //上周期瞬时流量
    OV : REAL ;         //流量累积输出
END_VAR
VAR_TEMP
    tmpReal1 : REAL ;
    tmpReal2 :REAL ;
    OValt : REAL ;
END_VAR
BEGIN

    OValt := OV ;   
    IF PV >= PLL THEN
        tmpReal1 := PV * (CYC / 3.6E+6 ) + OV_ER1 ;       
        tmpReal2 := tmpReal1 + OV_ER2 ;       
        OV    := tmpReal2  + OValt ;
        OV_ER1 := OV_ER2 - tmpReal2 + tmpReal1 ;
        OV_ER2 := OValt - OV + tmpReal2 ;
    ELSE
        OV := OValt ;
    END_IF ;
   
    IF OV >= 1.000000e+009 THEN
        OV := 0.000000e+000;
    END_IF ;
   
END_FUNCTION

这是我的累积计算,程序简单,精度也比较高


 

 

OValt  = 1.0e+006

tmpReal2  = 0.1

OV  =  OValt   +  tmpReal2  =  1.0e+006 + 0.1 =  1.0e+006

OV_ER2 := OValt - OV + tmp Real2 = 1.0e+006 - 1.0e+006  + 0.1 = 0.1

 

 

 

 


 qlhcco
2008-5-13 18:36:36

我把我的家底都抖给你了,这是浮点数在执行加减法时产生的误差,我把每次运算的误差再加的本次的积分里,不管再小的数,累加定量以后,他就可以加到OV里了,所以我的这个算法不会因为OV值大了而不能累积。

你可以模拟一下,有偏差变量和没有偏差变量的区别。你会发现其中的奥妙了。


 yzdatou
2008-5-14 7:11:04

模拟了一下确实是对的。

谢谢ls指教。

你的思路很独特,受教了。


 qlhcco
2008-5-14 9:56:14

我这个思路也不是完全是我自己的,其实是我在研究SETP7 FB41的PID功能是发现的,最后我就应用在累积计算的算法里了


 yzdatou
2008-5-14 19:20:34

很佩服你的钻研精神,自愧弗如。

另外,我思考再三,仍然要给你来个鸡蛋里面挑骨头,呵呵。

假定累积量越来越大,最终达到8位数,而实际有效数字仅7位,那么这个累计量的个位数将不再变化了。


 qlhcco
2008-5-15 0:07:57

确实是这样的,这是由于浮点数的问题,这个问题不是不可以解决,dint型数据可以显示2147483647;可以将OV结果转换为DINT类型数据,OV_ER2也转换成DINT类型数据,OV(dint)+ OV_ER2( dint )= OUT(显示用)该输出不用于计算只是用于显示。你认为如何?


 yzdatou
2008-5-15 16:26:57

你说的没错。我就是用dint类型变量来存储累积量,再用一个real变量存储小于1的累积量到1就进位。


FUNCTION_BLOCK FB618

//

TITLE = 'LEIJI'

//

know_how_protect

VERSION: '6.0'

AUTHOR: nyj

NAME: nyj

FAMILY: china

{S7_m_c:='true'}

// Block Parameters

VAR_INPUT

  // Input Parameters

TongDaoDiZhi{S7_m_c:='true'}:WORD:=0;// AI adress

XunHuanShiJian{S7_m_c:='true'}:REAL:=100;// unit:ms

Liangcheng{S7_m_c:='true'}:REAL:=0.0;// m3/h(max) , t/h(max)

QingLing{S7_m_c:='true';S7_string_0:='false';S7_string_1:='true'}:BOOL:=0;// back to zero

END_VAR

VAR_OUTPUT

 // Output Parameters

ShunShiZhi{S7_m_c:='true'}:REAL;//m3/h , t/h

LeiJiZhi{S7_m_c:='true'}:DINT;//m3 , t

END_VAR

VAR_IN_OUT

LeiJiHH:DINT:=0;//(1e--??ee)

LeiJiH:DINT:=0;//(1--1e)

LeiJiL:REAL:=0.0;//(0.0--1.0)

END_VAR

BEGIN

     IF WORD_TO_INT(TongDaoDiZhi)< 0 OR WORD_TO_INT(TongDaoDiZhi)= 32767 OR WORD_TO_INT(TongDaoDiZhi)= -32767 THEN

     TongDaoDiZhi:=0;

     END_IF;

     IF WORD_TO_INT(TongDaoDiZhi)> 27648 AND WORD_TO_INT(TongDaoDiZhi)<> 32767 AND WORD_TO_INT(TongDaoDiZhi)<> -32767 THEN

     TongDaoDiZhi:=27648;

     END_IF;

  ShunShiZhi:=WORD_TO_INT(TongDaoDiZhi)*Liangcheng/27648.0;

  LeiJiL:=LeiJiL+ShunShiZhi*XunHuanShiJian/3600000.0;

  IF LeiJiL >= 1.0 AND  LeiJiL < 100000000.0 THEN

  IF REAL_TO_DINT(LeiJiL)<=LeiJiL THEN

  LeiJiH:= LeiJiH +  REAL_TO_DINT(LeiJiL / 1.0);

  LeiJiL:= LeiJiL- REAL_TO_DINT(LeiJiL / 1.0);

  ELSE

  LeiJiH:= LeiJiH +  REAL_TO_DINT(LeiJiL / 1.0)-1;

  LeiJiL:= LeiJiL - REAL_TO_DINT(LeiJiL / 1.0)+1;

  END_IF;

  END_IF;

  IF  LeiJiL >= 100000000.0 THEN

  IF REAL_TO_DINT(LeiJiL/100000000.0)<=(LeiJiL/100000000.0) THEN

  LeiJiHH:= LeiJiHH +  REAL_TO_DINT(LeiJiL / 100000000.0);

  LeiJiL:= LeiJiL- REAL_TO_DINT(LeiJiL / 100000000.0)*100000000.0;

  ELSE

  LeiJiHH:= LeiJiHH +  REAL_TO_DINT(LeiJiL / 100000000.0)-1;

  LeiJiL:= LeiJiL - (REAL_TO_DINT(LeiJiL / 100000000.0)-1.0)*100000000.0;

  END_IF;

  END_IF;

  IF LeiJiH >= 100000000.0 THEN

  LeiJiHH:= LeiJiHH+(LeiJiH DIV 100000000);

  LeiJiH:= LeiJiH-(LeiJiH DIV 100000000)*100000000;

  END_IF;

    IF LeiJiL < 0.0 THEN

     LeiJiL:=0.0;

  END_IF;

    IF LeiJiH < 0 THEN

     LeiJiH:=0;

  END_IF;

      IF LeiJiHH < 0 THEN

     LeiJiHH:=0;

  END_IF;

  LeiJiZhi:=REAL_TO_DINT(LeiJiHH*100000000.0+LeiJiH+LeiJiL);

       IF QingLing = true THEN

     QingLing := false   ;

     LeiJiHH:= 0 ;

     LeiJiH:= 0 ;

     LeiJiL:= 0.0 ;

  END_IF;

  END_FUNCTION_BLOCK

―――――――――――――――――――――――――――――――――

粗粗看了下,程序先进行量程转换,得出瞬时流量,然后进行累加。在累加的时候,考虑到运算精度问题,也就是两个real数据运算的误差问题,所以作者考虑的很周到,采用低位累加再向高位进位的办法。其实我采用的思路跟作者类似但是更简单:直接把瞬时量分解为整数和小数部分,整数部分进行累加自然不存在精度问题,而小数部分进行累积满1以后再进位给整数部分,小数部分的运算会存在一点点误差但是基本可以忽略,这样程序要简单的多。

另外量程转换也没有必要写在这个模块里面,而是应当统一进行转换,程序的模块化是个仁者见仁智者见智的问题,这是题外话了。

 

你可能感兴趣的:(累计流量(西门子程序))