//**************************************************************************************
// 三个传感器选择输出
//(这里没有做线性转换故需要把转换后的值传递到程序块,可以用该程序修改作一个线性转换)
//EBC-LW 2016-12-20
//1.检查通道值是否超出检测范围
//2.将不正常的仪表(超出检测范围0~32768)排除后将正常的仪表的数
//加入新的数组
//3.从新的数组判断有几个仪表是处于正常的,无正常仪表输出故障后设定值
//a.当仅一台仪表处于正常状态,则输出该仪表的值
//b.当仅有两台仪表处于正常状态,则检测两个仪表的偏差值是否小于设定的允许的偏差范围,
//在允许范围内时,将两个仪表的值取平均值输出,两个仪表的偏差超出设的允许的偏差范围时
//将对设定的故障值进行比较,哪一个仪表数组接近故障后输出的就输出哪一个仪表的值(都接近时优先
//采用最先进入数组的那个数,也就是意味着PV序号小的优先)
//c.当有三台仪表处于正常状态时,则取出三台仪表中的最大值和最小值并得出两个仪表的偏差并和设定的允许
//偏差进行比较,若小于设定的偏差则取三个仪表的平均值输出。若得出的偏差大于设定的偏差则
//将最大值和中间值,中间值和最小值分别进行偏差计算,采用得出偏差最小的那两个数值取平均值输出
//**************************************************************************************
FUNCTION FC74: VOID
TITLE = 'THREE_SL'
AUTHOR: EBC_LW
NAME: THREESL
VERSION: '0.01'
FAMILY: EBC
KNOW_HOW_PROTECT
VAR_INPUT
PV1:WORD;
PV2:WORD;
PV3:WORD;
PV1_REAL:REAL;
PV2_REAL:REAL;
PV3_REAL:REAL;
PV_DEV_SET:REAL;//仪表间的偏差
ERR_MAN_SET:REAL;
END_VAR
VAR_IN_OUT
END_VAR
VAR_OUTPUT
PV:REAL;
PV1_FAIL:BOOL;
PV2_FAIL:BOOL;
PV3_FAIL:BOOL;
PV_DEV:REAL;
END_VAR
VAR_TEMP
I:INT;//结构号查询未超量程的仪表
J:INT;//未超过量程的仪表数量
K:INT;//结构号查询小于设定偏差的仪表
L:INT;//未超过设定偏差的仪表数量
TEMP_MAX:REAL;
TEMP_MIN:REAL;
TEMP_MID:REAL;
END_VAR
VAR
ARRAY_TEMP:ARRAY[1..3] OF REAL;
STAUS_ARRAY :
ARRAY[1..3] OF STRUCT
STAUS : BOOL;//仪表状态
VALUE : REAL; //仪表对应的值
END_STRUCT;
END_VAR
// 判断值是否正常
// TEMP1:=WORD_TO_INT(PV1);
IF (WORD_TO_INT(PV1) <-1) OR (WORD_TO_INT(PV1) >27649) THEN //低于正常或者高于正常则通道标志位置1
PV1_FAIL:=1;
ELSE
PV1_FAIL:=0;
END_IF;
IF (WORD_TO_INT(PV2) <-1) OR (WORD_TO_INT(PV2) >27649) THEN //低于正常或者高于正常则通道标志位置1
PV2_FAIL:=1;
ELSE
PV2_FAIL:=0;
END_IF;
IF (WORD_TO_INT(PV3) <-1) OR (WORD_TO_INT(PV3) >27649) THEN //低于正常或者高于正常则通道标志位置1
PV3_FAIL:=1;
ELSE
PV3_FAIL:=0;
END_IF;
//对结构体赋值
STAUS_ARRAY[1].STAUS:=PV1_FAIL;
STAUS_ARRAY[2].STAUS:=PV2_FAIL;
STAUS_ARRAY[3].STAUS:=PV3_FAIL;
STAUS_ARRAY[1].VALUE:=PV1_REAL;
STAUS_ARRAY[2].VALUE:=PV2_REAL;
STAUS_ARRAY[3].VALUE:=PV3_REAL;
//循环体初始化值
I:=0;//
J:=0;//
K:=0;
L:=0;
TEMP_MAX:=0;//MAX
TEMP_MIN:=0;
//将未超过量程的仪表数据加入新的数组
FOR I:= 1 TO 3 BY 1 DO
// Statement Section
IF NOT(STAUS_ARRAY[I].STAUS) THEN //轮寻的未超量程仪表状态
J:=J+1;//未超量程仪表计数
//将未超过量程的仪表的数据加入新的数组
ARRAY_TEMP[J]:=STAUS_ARRAY[I].VALUE;
END_IF;
END_FOR;
CASE J OF
1:
//当未超过量程的设备只有一台时输出这台变送器的值
PV:=ARRAY_TEMP[J];
2:
//当未超过量程的设备有两台时判断两个值间的偏差是否超出范围
//偏差范围内取平均值
//偏差范围外,判断仪表值和设定值哪一个更接近就输出该值
IF ABS(ARRAY_TEMP[J]-ARRAY_TEMP[J-1])<= ABS(PV_DEV_SET) THEN
PV:=(ARRAY_TEMP[J]+ARRAY_TEMP[J-1])/2;
ELSE
//绝对值小的说明偏差小
IF ABS(ARRAY_TEMP[J]-ERR_MAN_SET)>=ABS(ARRAY_TEMP[J-1]-ERR_MAN_SET) THEN
PV:=ARRAY_TEMP[J-1];
ELSE
PV:=ARRAY_TEMP[J];
END_IF;
END_IF;
3:
//当未超过量程的设备有三台时判断三个数之间的偏差,三个值的均在偏差内则取三个数的平均值,两个数偏差小的就输出这两个表的数值
//将偏差最大的那个数扔掉,取接近的两个数的平均值
//选出三个当中最大值
TEMP_MAX:=MAX(IN1:=ARRAY_TEMP[J],IN2:=ARRAY_TEMP[J-1],IN3:=ARRAY_TEMP[J-2]);
//选出三个当中最小的值
TEMP_MIN:=MIN(IN1:=ARRAY_TEMP[J],IN2:=ARRAY_TEMP[J-1],IN3:=ARRAY_TEMP[J-2]);
//计算出中间值
TEMP_MID:=ARRAY_TEMP[J]+ARRAY_TEMP[J-1]+ARRAY_TEMP[J-2]-TEMP_MAX-TEMP_MIN;
//若最大值和最小值得出的偏差小于设定的偏差则三个仪表取平均值,否则选取三个当中两个数据最为接近的仪表取平均值
IF ABS(TEMP_MAX-TEMP_MIN)<=ABS(PV_DEV_SET) THEN
PV:=(ARRAY_TEMP[J]+ARRAY_TEMP[J-1]+ARRAY_TEMP[J-2])/3;
ELSE
IF ABS(TEMP_MAX-TEMP_MID) >= ABS(TEMP_MID-TEMP_MIN) THEN
PV:=(TEMP_MID+TEMP_MIN)/2;
ELSE
PV:=(TEMP_MID+TEMP_MAX)/2;
END_IF;
END_IF;
ELSE
PV:=ERR_MAN_SET;
END_CASE;
END_FUNCTION
//原创程序请多交流 QQ:275578306