add the alarm filter for ai, calc, longin, mbbi type records

This commit is contained in:
Kukhee Kim
2010-05-28 02:16:45 -07:00
committed by Andrew Johnson
parent 0af48f5a29
commit 824d378117
6 changed files with 274 additions and 79 deletions
+103 -39
View File
@@ -37,6 +37,9 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table */
#define report NULL
@@ -79,7 +82,7 @@ rset calcRSET={
};
epicsExportAddress(rset, calcRSET);
static void checkAlarms(calcRecord *prec);
static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast);
static void monitor(calcRecord *prec);
static int fetch_values(calcRecord *prec);
@@ -111,6 +114,8 @@ static long init_record(calcRecord *prec, int pass)
static long process(calcRecord *prec)
{
epicsTimeStamp timeLast;
prec->pact = TRUE;
if (fetch_values(prec) == 0) {
if (calcPerform(&prec->a, &prec->val, prec->rpcl)) {
@@ -118,9 +123,11 @@ static long process(calcRecord *prec)
} else
prec->udf = isnan(prec->val);
}
timeLast = prec->time;
recGblGetTimeStamp(prec);
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec, &timeLast);
/* check event list */
monitor(prec);
/* process the forward scan link record */
@@ -273,14 +280,27 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
return 0;
}
static void checkAlarms(calcRecord *prec)
static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast)
{
double val, hyst, lalm;
double alev;
enum {
range_Lolo = 1,
range_Low,
range_Normal,
range_High,
range_Hihi
} alarmRange;
static const epicsEnum16 range_stat[] = {
SOFT_ALARM, LOLO_ALARM, LOW_ALARM,
NO_ALARM, HIGH_ALARM, HIHI_ALARM
};
double val, hyst, lalm, alev, aftc, afvl;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
@@ -288,45 +308,89 @@ static void checkAlarms(calcRecord *prec)
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
/* check VAL against alarm limits */
if ((asev = prec->hhsv) &&
(val >= (alev = prec->hihi) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_Hihi;
else
if ((asev = prec->llsv) &&
(val <= (alev = prec->lolo) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Lolo;
else
if ((asev = prec->hsv) &&
(val >= (alev = prec->high) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_High;
else
if ((asev = prec->lsv) &&
(val <= (alev = prec->low) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Low;
else {
alev = val;
asev = NO_ALARM;
alarmRange = range_Normal;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
aftc = prec->aftc;
afvl = 0;
if (aftc > 0) {
/* Apply level filtering */
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double)alarmRange;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
/* The sign of afvl indicates whether the result should be
* rounded up or down. This gives the filter hysteresis.
* If afvl > 0 the floor() function rounds to a lower alarm
* level, otherwise to a higher.
*/
afvl = alpha * afvl +
((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl; /* reverse rounding */
alarmRange = abs((int)floor(afvl));
switch (alarmRange) {
case range_Hihi:
asev = prec->hhsv;
alev = prec->hihi;
break;
case range_High:
asev = prec->hsv;
alev = prec->high;
break;
case range_Normal:
asev = NO_ALARM;
break;
case range_Low:
asev = prec->lsv;
alev = prec->low;
break;
case range_Lolo:
asev = prec->llsv;
alev = prec->lolo;
break;
}
}
}
prec->afvl = afvl;
if (asev) {
/* Report alarm condition, store LALM for future HYST calculations */
if (recGblSetSevr(prec, range_stat[alarmRange], asev))
prec->lalm = alev;
return;
} else {
/* No alarm condition, reset LALM */
prec->lalm = val;
}
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
}
static void monitor(calcRecord *prec)
+10
View File
@@ -153,6 +153,16 @@ recordtype(calc) {
interest(1)
menu(menuAlarmSevr)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(HYST,DBF_DOUBLE) {
prompt("Alarm Deadband")
promptgroup(GUI_ALARMS)
+98 -37
View File
@@ -37,6 +37,8 @@
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -87,7 +89,7 @@ struct longindset { /* longin input dset */
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_longin; /*returns: (-1,0)=>(failure,success)*/
};
static void checkAlarms(longinRecord *prec);
static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast);
static void monitor(longinRecord *prec);
static long readValue(longinRecord *prec);
@@ -132,12 +134,14 @@ static long process(longinRecord *prec)
struct longindset *pdset = (struct longindset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_longin==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_longin");
return(S_dev_missingSup);
}
timeLast = prec->time;
status=readValue(prec); /* read the new value */
/* check if device support set pact */
@@ -148,7 +152,7 @@ static long process(longinRecord *prec)
if (status==0) prec->udf = FALSE;
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec, &timeLast);
/* check event list */
monitor(prec);
/* process the forward scan link record */
@@ -230,14 +234,28 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad)
return(0);
}
static void checkAlarms(longinRecord *prec)
static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast)
{
enum {
range_Lolo = 1,
range_Low,
range_Normal,
range_High,
range_Hihi
} alarmRange;
static const epicsEnum16 range_stat[] = {
SOFT_ALARM, LOLO_ALARM, LOW_ALARM,
NO_ALARM, HIGH_ALARM, HIHI_ALARM
};
double aftc, afvl;
epicsInt32 val, hyst, lalm;
epicsInt32 alev;
epicsEnum16 asev;
if (prec->udf) {
recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM);
prec->afvl = 0;
return;
}
@@ -245,45 +263,88 @@ static void checkAlarms(longinRecord *prec)
hyst = prec->hyst;
lalm = prec->lalm;
/* alarm condition hihi */
asev = prec->hhsv;
alev = prec->hihi;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIHI_ALARM, asev))
prec->lalm = alev;
return;
/* check VAL against alarm limits */
if ((asev = prec->hhsv) &&
(val >= (alev = prec->hihi) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_Hihi;
else
if ((asev = prec->llsv) &&
(val <= (alev = prec->lolo) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Lolo;
else
if ((asev = prec->hsv) &&
(val >= (alev = prec->high) ||
((lalm == alev) && (val >= alev - hyst))))
alarmRange = range_High;
else
if ((asev = prec->lsv) &&
(val <= (alev = prec->low) ||
((lalm == alev) && (val <= alev + hyst))))
alarmRange = range_Low;
else {
alev = val;
asev = NO_ALARM;
alarmRange = range_Normal;
}
/* alarm condition lolo */
asev = prec->llsv;
alev = prec->lolo;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOLO_ALARM, asev))
prec->lalm = alev;
return;
}
aftc = prec->aftc;
afvl = 0;
/* alarm condition high */
asev = prec->hsv;
alev = prec->high;
if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) {
if (recGblSetSevr(prec, HIGH_ALARM, asev))
prec->lalm = alev;
return;
}
if (aftc > 0) {
/* Apply level filtering */
afvl = prec->afvl;
if (afvl == 0) {
afvl = (double)alarmRange;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
/* alarm condition low */
asev = prec->lsv;
alev = prec->low;
if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) {
if (recGblSetSevr(prec, LOW_ALARM, asev))
prec->lalm = alev;
return;
}
/* The sign of afvl indicates whether the result should be
* rounded up or down. This gives the filter hysteresis.
* If afvl > 0 the floor() function rounds to a lower alarm
* level, otherwise to a higher.
*/
afvl = alpha * afvl +
((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange;
if (afvl - floor(afvl) > THRESHOLD)
afvl = -afvl; /* reverse rounding */
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
alarmRange = abs((int)floor(afvl));
switch (alarmRange) {
case range_Hihi:
asev = prec->hhsv;
alev = prec->hihi;
break;
case range_High:
asev = prec->hsv;
alev = prec->high;
break;
case range_Normal:
asev = NO_ALARM;
break;
case range_Low:
asev = prec->lsv;
alev = prec->low;
break;
case range_Lolo:
asev = prec->llsv;
alev = prec->lolo;
break;
}
}
}
prec->afvl = afvl;
if (asev) {
/* Report alarm condition, store LALM for future HYST calculations */
if (recGblSetSevr(prec, range_stat[alarmRange], asev))
prec->lalm = alev;
} else {
/* No alarm condition, reset LALM */
prec->lalm = val;
}
}
/* DELTA calculates the absolute difference between its arguments
+10
View File
@@ -93,6 +93,16 @@ recordtype(longin) {
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(ADEL,DBF_LONG) {
prompt("Archive Deadband")
promptgroup(GUI_DISPLAY)
+43 -3
View File
@@ -36,6 +36,9 @@
#include "mbbiRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Hysterisis for alarm filtering: 1-1/e */
#define THRESHOLD 0.6321
/* Create RSET - Record Support Entry Table*/
#define report NULL
#define initialize NULL
@@ -84,7 +87,7 @@ struct mbbidset { /* multi bit binary input dset */
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi;/*(0,2)=>(success, success no convert)*/
};
static void checkAlarms(mbbiRecord *);
static void checkAlarms(mbbiRecord *, epicsTimeStamp *);
static void monitor(mbbiRecord *);
static long readValue(mbbiRecord *);
@@ -146,6 +149,7 @@ static long process(mbbiRecord *prec)
struct mbbidset *pdset = (struct mbbidset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
epicsTimeStamp timeLast;
if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) {
prec->pact=TRUE;
@@ -153,6 +157,8 @@ static long process(mbbiRecord *prec)
return(S_dev_missingSup);
}
timeLast = prec->time;
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
@@ -184,7 +190,7 @@ static long process(mbbiRecord *prec)
else if(status == 2) status = 0;
/* check for alarms */
checkAlarms(prec);
checkAlarms(prec, &timeLast);
/* check event list */
monitor(prec);
@@ -279,14 +285,20 @@ static long put_enum_str(DBADDR *paddr, char *pstring)
return(S_db_badChoice);
}
static void checkAlarms(mbbiRecord *prec)
static void checkAlarms(mbbiRecord *prec, epicsTimeStamp *timeLast)
{
double aftc, afvl;
unsigned short alarm;
epicsEnum16 asev;
unsigned short *severities;
unsigned short val=prec->val;
/* check for udf alarm */
if(prec->udf == TRUE ){
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
prec->afvl = 0;
}
/* check for state alarm */
@@ -296,9 +308,37 @@ static void checkAlarms(mbbiRecord *prec)
} else {
/* in a state which is an error */
severities = (unsigned short *)&(prec->zrsv);
/*
recGblSetSevr(prec,STATE_ALARM,severities[prec->val]);
*/
alarm = severities[prec->val];
}
aftc = prec->aftc;
afvl = 0.;
if(aftc > 0.) {
afvl = prec->afvl;
if(afvl == 0.) {
afvl = (double) alarm;
} else {
double t = epicsTimeDiffInSeconds(&prec->time, timeLast);
double alpha = aftc / (t + aftc);
afvl = alpha * afvl +
((afvl>0.)?(1.-alpha):(alpha-1.)) * alarm;
if(afvl - floor(afvl) > THRESHOLD)
afvl = -afvl;
alarm = abs((int)floor(afvl));
}
}
asev = alarm;
recGblSetSevr(prec, STATE_ALARM, asev);
/* check for cos alarm */
if(val == prec->lalm) return;
recGblSetSevr(prec,COS_ALARM,prec->cosv);
+10
View File
@@ -394,6 +394,16 @@ recordtype(mbbi) {
interest(1)
menu(menuAlarmSevr)
}
field(AFTC, DBF_DOUBLE) {
prompt("Alarm Filter Time Constant")
promptgroup(GUI_ALARMS)
interest(1)
}
field(AFVL, DBF_DOUBLE) {
prompt("Alarm Filter Value")
special(SPC_NOMOD)
interest(3)
}
field(UNSV,DBF_MENU) {
prompt("Unknown State Severity")
promptgroup(GUI_MBB)