Merge lp:~khkim/epics-base/alarm-filter into lp:~epics-core/epics-base/3.14
- alarm-filter
- Merge into 3.14
Proposed by
Kim, Kukhee
Status: | Merged |
---|---|
Merge reported by: | Andrew Johnson |
Merged at revision: | not available |
Proposed branch: | lp:~khkim/epics-base/alarm-filter |
Merge into: | lp:~epics-core/epics-base/3.14 |
Diff against target: |
822 lines (+401/-136) 8 files modified
src/rec/aiRecord.c (+106/-46) src/rec/aiRecord.dbd (+10/-0) src/rec/calcRecord.c (+108/-44) src/rec/calcRecord.dbd (+10/-0) src/rec/longinRecord.c (+103/-42) src/rec/longinRecord.dbd (+10/-0) src/rec/mbbiRecord.c (+44/-4) src/rec/mbbiRecord.dbd (+10/-0) |
To merge this branch: | bzr merge lp:~khkim/epics-base/alarm-filter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
Review via email: mp+26278@code.launchpad.net |
Commit message
Description of the change
This branch has alarm filter for ai, calc, longin, and mbbi record types.
To post a comment you must log in.
Revision history for this message
Ralph Lange (ralph-lange) wrote : | # |
Revision history for this message
Andrew Johnson (anj) wrote : | # |
Merged into my record-updates branch which will go into 3.15 soon.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/rec/aiRecord.c' | |||
2 | --- src/rec/aiRecord.c 2010-04-05 18:49:18 +0000 | |||
3 | +++ src/rec/aiRecord.c 2010-05-28 09:22:29 +0000 | |||
4 | @@ -6,7 +6,7 @@ | |||
5 | 6 | * EPICS BASE is distributed subject to a Software License Agreement found | 6 | * EPICS BASE is distributed subject to a Software License Agreement found |
6 | 7 | * in file LICENSE that is included with this distribution. | 7 | * in file LICENSE that is included with this distribution. |
7 | 8 | \*************************************************************************/ | 8 | \*************************************************************************/ |
9 | 9 | /* $Id$ */ | 9 | /* $Id: aiRecord.c,v 1.20.2.6 2009/04/03 14:40:12 lange Exp $ */ |
10 | 10 | 10 | ||
11 | 11 | /* aiRecord.c - Record Support Routines for Analog Input records */ | 11 | /* aiRecord.c - Record Support Routines for Analog Input records */ |
12 | 12 | /* | 12 | /* |
13 | @@ -41,6 +41,9 @@ | |||
14 | 41 | #undef GEN_SIZE_OFFSET | 41 | #undef GEN_SIZE_OFFSET |
15 | 42 | #include "epicsExport.h" | 42 | #include "epicsExport.h" |
16 | 43 | 43 | ||
17 | 44 | /* Hysterisis for alarm filtering: 1-1/e */ | ||
18 | 45 | #define THRESHOLD 0.6321 | ||
19 | 46 | |||
20 | 44 | /* Create RSET - Record Support Entry Table*/ | 47 | /* Create RSET - Record Support Entry Table*/ |
21 | 45 | #define report NULL | 48 | #define report NULL |
22 | 46 | #define initialize NULL | 49 | #define initialize NULL |
23 | @@ -99,7 +102,7 @@ | |||
24 | 99 | extern unsigned int gts_trigger_counter; | 102 | extern unsigned int gts_trigger_counter; |
25 | 100 | */ | 103 | */ |
26 | 101 | 104 | ||
28 | 102 | static void checkAlarms(aiRecord *prec); | 105 | static void checkAlarms(aiRecord *prec, epicsTimeStamp *lastTime); |
29 | 103 | static void convert(aiRecord *prec); | 106 | static void convert(aiRecord *prec); |
30 | 104 | static void monitor(aiRecord *prec); | 107 | static void monitor(aiRecord *prec); |
31 | 105 | static long readValue(aiRecord *prec); | 108 | static long readValue(aiRecord *prec); |
32 | @@ -158,12 +161,15 @@ | |||
33 | 158 | aidset *pdset = (aidset *)(prec->dset); | 161 | aidset *pdset = (aidset *)(prec->dset); |
34 | 159 | long status; | 162 | long status; |
35 | 160 | unsigned char pact=prec->pact; | 163 | unsigned char pact=prec->pact; |
36 | 164 | epicsTimeStamp timeLast; | ||
37 | 161 | 165 | ||
38 | 162 | if( (pdset==NULL) || (pdset->read_ai==NULL) ) { | 166 | if( (pdset==NULL) || (pdset->read_ai==NULL) ) { |
39 | 163 | prec->pact=TRUE; | 167 | prec->pact=TRUE; |
40 | 164 | recGblRecordError(S_dev_missingSup,(void *)prec,"read_ai"); | 168 | recGblRecordError(S_dev_missingSup,(void *)prec,"read_ai"); |
41 | 165 | return(S_dev_missingSup); | 169 | return(S_dev_missingSup); |
42 | 166 | } | 170 | } |
43 | 171 | timeLast = prec->time; | ||
44 | 172 | |||
45 | 167 | status=readValue(prec); /* read the new value */ | 173 | status=readValue(prec); /* read the new value */ |
46 | 168 | /* check if device support set pact */ | 174 | /* check if device support set pact */ |
47 | 169 | if ( !pact && prec->pact ) return(0); | 175 | if ( !pact && prec->pact ) return(0); |
48 | @@ -174,7 +180,7 @@ | |||
49 | 174 | else if (status==2) status=0; | 180 | else if (status==2) status=0; |
50 | 175 | 181 | ||
51 | 176 | /* check for alarms */ | 182 | /* check for alarms */ |
53 | 177 | checkAlarms(prec); | 183 | checkAlarms(prec,&timeLast); |
54 | 178 | /* check event list */ | 184 | /* check event list */ |
55 | 179 | monitor(prec); | 185 | monitor(prec); |
56 | 180 | /* process the forward scan link record */ | 186 | /* process the forward scan link record */ |
57 | @@ -283,60 +289,114 @@ | |||
58 | 283 | return(0); | 289 | return(0); |
59 | 284 | } | 290 | } |
60 | 285 | 291 | ||
61 | 286 | 292 | ||
63 | 287 | static void checkAlarms(aiRecord *prec) | 293 | static void checkAlarms(aiRecord *prec, epicsTimeStamp *lastTime) |
64 | 288 | { | 294 | { |
67 | 289 | double val, hyst, lalm; | 295 | enum { |
68 | 290 | double alev; | 296 | range_Lolo = 1, |
69 | 297 | range_Low, | ||
70 | 298 | range_Normal, | ||
71 | 299 | range_High, | ||
72 | 300 | range_Hihi | ||
73 | 301 | } alarmRange; | ||
74 | 302 | static const epicsEnum16 range_stat[] = { | ||
75 | 303 | SOFT_ALARM, LOLO_ALARM, LOW_ALARM, | ||
76 | 304 | NO_ALARM, HIGH_ALARM, HIHI_ALARM | ||
77 | 305 | }; | ||
78 | 306 | double val, hyst, lalm, alev, aftc, afvl; | ||
79 | 291 | epicsEnum16 asev; | 307 | epicsEnum16 asev; |
80 | 292 | 308 | ||
81 | 293 | if (prec->udf) { | 309 | if (prec->udf) { |
82 | 294 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); | 310 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); |
83 | 311 | prec->afvl = 0; | ||
84 | 295 | return; | 312 | return; |
85 | 296 | } | 313 | } |
86 | 297 | 314 | ||
88 | 298 | val = prec->val; | 315 | val = prec->val; |
89 | 299 | hyst = prec->hyst; | 316 | hyst = prec->hyst; |
90 | 300 | lalm = prec->lalm; | 317 | lalm = prec->lalm; |
91 | 301 | 318 | ||
131 | 302 | /* alarm condition hihi */ | 319 | /* check VAL against alarm limits */ |
132 | 303 | asev = prec->hhsv; | 320 | if ((asev = prec->hhsv) && |
133 | 304 | alev = prec->hihi; | 321 | (val >= (alev = prec->hihi) || |
134 | 305 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 322 | ((lalm == alev) && (val >= alev - hyst)))) |
135 | 306 | if (recGblSetSevr(prec, HIHI_ALARM, asev)) | 323 | alarmRange = range_Hihi; |
136 | 307 | prec->lalm = alev; | 324 | else |
137 | 308 | return; | 325 | if ((asev = prec->llsv) && |
138 | 309 | } | 326 | (val <= (alev = prec->lolo) || |
139 | 310 | 327 | ((lalm == alev) && (val <= alev + hyst)))) | |
140 | 311 | /* alarm condition lolo */ | 328 | alarmRange = range_Lolo; |
141 | 312 | asev = prec->llsv; | 329 | else |
142 | 313 | alev = prec->lolo; | 330 | if ((asev = prec->hsv) && |
143 | 314 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 331 | (val >= (alev = prec->high) || |
144 | 315 | if (recGblSetSevr(prec, LOLO_ALARM, asev)) | 332 | ((lalm == alev) && (val >= alev - hyst)))) |
145 | 316 | prec->lalm = alev; | 333 | alarmRange = range_High; |
146 | 317 | return; | 334 | else |
147 | 318 | } | 335 | if ((asev = prec->lsv) && |
148 | 319 | 336 | (val <= (alev = prec->low) || | |
149 | 320 | /* alarm condition high */ | 337 | ((lalm == alev) && (val <= alev + hyst)))) |
150 | 321 | asev = prec->hsv; | 338 | alarmRange = range_Low; |
151 | 322 | alev = prec->high; | 339 | else { |
152 | 323 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 340 | alev = val; |
153 | 324 | if (recGblSetSevr(prec, HIGH_ALARM, asev)) | 341 | asev = NO_ALARM; |
154 | 325 | prec->lalm = alev; | 342 | alarmRange = range_Normal; |
155 | 326 | return; | 343 | } |
156 | 327 | } | 344 | |
157 | 328 | 345 | aftc = prec->aftc; | |
158 | 329 | /* alarm condition low */ | 346 | afvl = 0; |
159 | 330 | asev = prec->lsv; | 347 | |
160 | 331 | alev = prec->low; | 348 | if (aftc > 0) { |
161 | 332 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 349 | /* Apply level filtering */ |
162 | 333 | if (recGblSetSevr(prec, LOW_ALARM, asev)) | 350 | afvl = prec->afvl; |
163 | 334 | prec->lalm = alev; | 351 | if (afvl == 0) { |
164 | 335 | return; | 352 | afvl = (double)alarmRange; |
165 | 336 | } | 353 | } else { |
166 | 337 | 354 | double t = epicsTimeDiffInSeconds(&prec->time, lastTime); | |
167 | 338 | /* we get here only if val is out of alarm by at least hyst */ | 355 | double alpha = aftc / (t + aftc); |
168 | 339 | prec->lalm = val; | 356 | |
169 | 340 | return; | 357 | /* The sign of afvl indicates whether the result should be |
170 | 358 | * rounded up or down. This gives the filter hysteresis. | ||
171 | 359 | * If afvl > 0 the floor() function rounds to a lower alarm | ||
172 | 360 | * level, otherwise to a higher. | ||
173 | 361 | */ | ||
174 | 362 | afvl = alpha * afvl + | ||
175 | 363 | ((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange; | ||
176 | 364 | if (afvl - floor(afvl) > THRESHOLD) | ||
177 | 365 | afvl = -afvl; /* reverse rounding */ | ||
178 | 366 | |||
179 | 367 | alarmRange = abs((int)floor(afvl)); | ||
180 | 368 | switch (alarmRange) { | ||
181 | 369 | case range_Hihi: | ||
182 | 370 | asev = prec->hhsv; | ||
183 | 371 | alev = prec->hihi; | ||
184 | 372 | break; | ||
185 | 373 | case range_High: | ||
186 | 374 | asev = prec->hsv; | ||
187 | 375 | alev = prec->high; | ||
188 | 376 | break; | ||
189 | 377 | case range_Normal: | ||
190 | 378 | asev = NO_ALARM; | ||
191 | 379 | break; | ||
192 | 380 | case range_Low: | ||
193 | 381 | asev = prec->lsv; | ||
194 | 382 | alev = prec->low; | ||
195 | 383 | break; | ||
196 | 384 | case range_Lolo: | ||
197 | 385 | asev = prec->llsv; | ||
198 | 386 | alev = prec->lolo; | ||
199 | 387 | break; | ||
200 | 388 | } | ||
201 | 389 | } | ||
202 | 390 | } | ||
203 | 391 | prec->afvl = afvl; | ||
204 | 392 | |||
205 | 393 | if (asev) { | ||
206 | 394 | /* Report alarm condition, store LALM for future HYST calculations */ | ||
207 | 395 | if (recGblSetSevr(prec, range_stat[alarmRange], asev)) | ||
208 | 396 | prec->lalm = alev; | ||
209 | 397 | } else { | ||
210 | 398 | /* No alarm condition, reset LALM */ | ||
211 | 399 | prec->lalm = val; | ||
212 | 400 | } | ||
213 | 341 | } | 401 | } |
214 | 342 | 402 | ||
215 | 343 | 403 | ||
216 | 344 | static void convert(aiRecord *prec) | 404 | static void convert(aiRecord *prec) |
217 | 345 | 405 | ||
218 | === modified file 'src/rec/aiRecord.dbd' | |||
219 | --- src/rec/aiRecord.dbd 2005-11-15 23:35:34 +0000 | |||
220 | +++ src/rec/aiRecord.dbd 2010-05-28 09:22:29 +0000 | |||
221 | @@ -138,6 +138,11 @@ | |||
222 | 138 | promptgroup(GUI_ALARMS) | 138 | promptgroup(GUI_ALARMS) |
223 | 139 | interest(1) | 139 | interest(1) |
224 | 140 | } | 140 | } |
225 | 141 | field(AFTC,DBF_DOUBLE) { | ||
226 | 142 | prompt("Alarm Filter Time Constant") | ||
227 | 143 | promptgroup(GUI_ALARMS) | ||
228 | 144 | interest(1) | ||
229 | 145 | } | ||
230 | 141 | field(ADEL,DBF_DOUBLE) { | 146 | field(ADEL,DBF_DOUBLE) { |
231 | 142 | prompt("Archive Deadband") | 147 | prompt("Archive Deadband") |
232 | 143 | promptgroup(GUI_DISPLAY) | 148 | promptgroup(GUI_DISPLAY) |
233 | @@ -153,6 +158,11 @@ | |||
234 | 153 | special(SPC_NOMOD) | 158 | special(SPC_NOMOD) |
235 | 154 | interest(3) | 159 | interest(3) |
236 | 155 | } | 160 | } |
237 | 161 | field(AFVL,DBF_DOUBLE) { | ||
238 | 162 | prompt("Alarm Filter Value") | ||
239 | 163 | special(SPC_NOMOD) | ||
240 | 164 | interest(3) | ||
241 | 165 | } | ||
242 | 156 | field(ALST,DBF_DOUBLE) { | 166 | field(ALST,DBF_DOUBLE) { |
243 | 157 | prompt("Last Value Archived") | 167 | prompt("Last Value Archived") |
244 | 158 | special(SPC_NOMOD) | 168 | special(SPC_NOMOD) |
245 | 159 | 169 | ||
246 | === modified file 'src/rec/calcRecord.c' | |||
247 | --- src/rec/calcRecord.c 2009-04-03 14:40:13 +0000 | |||
248 | +++ src/rec/calcRecord.c 2010-05-28 09:22:29 +0000 | |||
249 | @@ -37,6 +37,9 @@ | |||
250 | 37 | #undef GEN_SIZE_OFFSET | 37 | #undef GEN_SIZE_OFFSET |
251 | 38 | #include "epicsExport.h" | 38 | #include "epicsExport.h" |
252 | 39 | 39 | ||
253 | 40 | /* Hysterisis for alarm filtering: 1-1/e */ | ||
254 | 41 | #define THRESHOLD 0.6321 | ||
255 | 42 | |||
256 | 40 | /* Create RSET - Record Support Entry Table */ | 43 | /* Create RSET - Record Support Entry Table */ |
257 | 41 | 44 | ||
258 | 42 | #define report NULL | 45 | #define report NULL |
259 | @@ -79,7 +82,7 @@ | |||
260 | 79 | }; | 82 | }; |
261 | 80 | epicsExportAddress(rset, calcRSET); | 83 | epicsExportAddress(rset, calcRSET); |
262 | 81 | 84 | ||
264 | 82 | static void checkAlarms(calcRecord *prec); | 85 | static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast); |
265 | 83 | static void monitor(calcRecord *prec); | 86 | static void monitor(calcRecord *prec); |
266 | 84 | static int fetch_values(calcRecord *prec); | 87 | static int fetch_values(calcRecord *prec); |
267 | 85 | 88 | ||
268 | @@ -111,15 +114,19 @@ | |||
269 | 111 | 114 | ||
270 | 112 | static long process(calcRecord *prec) | 115 | static long process(calcRecord *prec) |
271 | 113 | { | 116 | { |
272 | 117 | epicsTimeStamp timeLast; | ||
273 | 118 | |||
274 | 114 | prec->pact = TRUE; | 119 | prec->pact = TRUE; |
275 | 115 | if (fetch_values(prec)==0) { | 120 | if (fetch_values(prec)==0) { |
276 | 116 | if (calcPerform(&prec->a, &prec->val, prec->rpcl)) { | 121 | if (calcPerform(&prec->a, &prec->val, prec->rpcl)) { |
277 | 117 | recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM); | 122 | recGblSetSevr(prec, CALC_ALARM, INVALID_ALARM); |
278 | 118 | } else prec->udf = isnan(prec->val); | 123 | } else prec->udf = isnan(prec->val); |
279 | 119 | } | 124 | } |
280 | 125 | |||
281 | 126 | timeLast = prec->time; | ||
282 | 120 | recGblGetTimeStamp(prec); | 127 | recGblGetTimeStamp(prec); |
283 | 121 | /* check for alarms */ | 128 | /* check for alarms */ |
285 | 122 | checkAlarms(prec); | 129 | checkAlarms(prec, &timeLast); |
286 | 123 | /* check event list */ | 130 | /* check event list */ |
287 | 124 | monitor(prec); | 131 | monitor(prec); |
288 | 125 | /* process the forward scan link record */ | 132 | /* process the forward scan link record */ |
289 | @@ -243,14 +250,27 @@ | |||
290 | 243 | return 0; | 250 | return 0; |
291 | 244 | } | 251 | } |
292 | 245 | 252 | ||
294 | 246 | static void checkAlarms(calcRecord *prec) | 253 | static void checkAlarms(calcRecord *prec, epicsTimeStamp *timeLast) |
295 | 247 | { | 254 | { |
298 | 248 | double val, hyst, lalm; | 255 | |
299 | 249 | double alev; | 256 | enum { |
300 | 257 | range_Lolo = 1, | ||
301 | 258 | range_Low, | ||
302 | 259 | range_Normal, | ||
303 | 260 | range_High, | ||
304 | 261 | range_Hihi | ||
305 | 262 | } alarmRange; | ||
306 | 263 | static const epicsEnum16 range_stat[] = { | ||
307 | 264 | SOFT_ALARM, LOLO_ALARM, LOW_ALARM, | ||
308 | 265 | NO_ALARM, HIGH_ALARM, HIHI_ALARM | ||
309 | 266 | }; | ||
310 | 267 | |||
311 | 268 | double val, hyst, lalm, alev, aftc, afvl; | ||
312 | 250 | epicsEnum16 asev; | 269 | epicsEnum16 asev; |
313 | 251 | 270 | ||
314 | 252 | if (prec->udf) { | 271 | if (prec->udf) { |
315 | 253 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); | 272 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); |
316 | 273 | prec->afvl = 0; | ||
317 | 254 | return; | 274 | return; |
318 | 255 | } | 275 | } |
319 | 256 | 276 | ||
320 | @@ -258,45 +278,89 @@ | |||
321 | 258 | hyst = prec->hyst; | 278 | hyst = prec->hyst; |
322 | 259 | lalm = prec->lalm; | 279 | lalm = prec->lalm; |
323 | 260 | 280 | ||
363 | 261 | /* alarm condition hihi */ | 281 | /* check VAL against alarm limits */ |
364 | 262 | asev = prec->hhsv; | 282 | if ((asev = prec->hhsv) && |
365 | 263 | alev = prec->hihi; | 283 | (val >= (alev = prec->hihi) || |
366 | 264 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 284 | ((lalm == alev) && (val >= alev - hyst)))) |
367 | 265 | if (recGblSetSevr(prec, HIHI_ALARM, asev)) | 285 | alarmRange = range_Hihi; |
368 | 266 | prec->lalm = alev; | 286 | else |
369 | 267 | return; | 287 | if ((asev = prec->llsv) && |
370 | 268 | } | 288 | (val <= (alev = prec->lolo) || |
371 | 269 | 289 | ((lalm == alev) && (val <= alev + hyst)))) | |
372 | 270 | /* alarm condition lolo */ | 290 | alarmRange = range_Lolo; |
373 | 271 | asev = prec->llsv; | 291 | else |
374 | 272 | alev = prec->lolo; | 292 | if ((asev = prec->hsv) && |
375 | 273 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 293 | (val >= (alev = prec->high) || |
376 | 274 | if (recGblSetSevr(prec, LOLO_ALARM, asev)) | 294 | ((lalm == alev) && (val >= alev - hyst)))) |
377 | 275 | prec->lalm = alev; | 295 | alarmRange = range_High; |
378 | 276 | return; | 296 | else |
379 | 277 | } | 297 | if ((asev = prec->lsv) && |
380 | 278 | 298 | (val <= (alev = prec->low) || | |
381 | 279 | /* alarm condition high */ | 299 | ((lalm == alev) && (val <= alev + hyst)))) |
382 | 280 | asev = prec->hsv; | 300 | alarmRange = range_Low; |
383 | 281 | alev = prec->high; | 301 | else { |
384 | 282 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 302 | alev = val; |
385 | 283 | if (recGblSetSevr(prec, HIGH_ALARM, asev)) | 303 | asev = NO_ALARM; |
386 | 284 | prec->lalm = alev; | 304 | alarmRange = range_Normal; |
387 | 285 | return; | 305 | } |
388 | 286 | } | 306 | |
389 | 287 | 307 | aftc = prec->aftc; | |
390 | 288 | /* alarm condition low */ | 308 | afvl = 0; |
391 | 289 | asev = prec->lsv; | 309 | |
392 | 290 | alev = prec->low; | 310 | if (aftc > 0) { |
393 | 291 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 311 | /* Apply level filtering */ |
394 | 292 | if (recGblSetSevr(prec, LOW_ALARM, asev)) | 312 | afvl = prec->afvl; |
395 | 293 | prec->lalm = alev; | 313 | if (afvl == 0) { |
396 | 294 | return; | 314 | afvl = (double)alarmRange; |
397 | 295 | } | 315 | } else { |
398 | 296 | 316 | double t = epicsTimeDiffInSeconds(&prec->time, timeLast); | |
399 | 297 | /* we get here only if val is out of alarm by at least hyst */ | 317 | double alpha = aftc / (t + aftc); |
400 | 298 | prec->lalm = val; | 318 | |
401 | 299 | return; | 319 | /* The sign of afvl indicates whether the result should be |
402 | 320 | * rounded up or down. This gives the filter hysteresis. | ||
403 | 321 | * If afvl > 0 the floor() function rounds to a lower alarm | ||
404 | 322 | * level, otherwise to a higher. | ||
405 | 323 | */ | ||
406 | 324 | afvl = alpha * afvl + | ||
407 | 325 | ((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange; | ||
408 | 326 | if (afvl - floor(afvl) > THRESHOLD) | ||
409 | 327 | afvl = -afvl; /* reverse rounding */ | ||
410 | 328 | |||
411 | 329 | alarmRange = abs((int)floor(afvl)); | ||
412 | 330 | switch (alarmRange) { | ||
413 | 331 | case range_Hihi: | ||
414 | 332 | asev = prec->hhsv; | ||
415 | 333 | alev = prec->hihi; | ||
416 | 334 | break; | ||
417 | 335 | case range_High: | ||
418 | 336 | asev = prec->hsv; | ||
419 | 337 | alev = prec->high; | ||
420 | 338 | break; | ||
421 | 339 | case range_Normal: | ||
422 | 340 | asev = NO_ALARM; | ||
423 | 341 | break; | ||
424 | 342 | case range_Low: | ||
425 | 343 | asev = prec->lsv; | ||
426 | 344 | alev = prec->low; | ||
427 | 345 | break; | ||
428 | 346 | case range_Lolo: | ||
429 | 347 | asev = prec->llsv; | ||
430 | 348 | alev = prec->lolo; | ||
431 | 349 | break; | ||
432 | 350 | } | ||
433 | 351 | } | ||
434 | 352 | } | ||
435 | 353 | prec->afvl = afvl; | ||
436 | 354 | |||
437 | 355 | if (asev) { | ||
438 | 356 | /* Report alarm condition, store LALM for future HYST calculations */ | ||
439 | 357 | if (recGblSetSevr(prec, range_stat[alarmRange], asev)) | ||
440 | 358 | prec->lalm = alev; | ||
441 | 359 | } else { | ||
442 | 360 | /* No alarm condition, reset LALM */ | ||
443 | 361 | prec->lalm = val; | ||
444 | 362 | } | ||
445 | 363 | |||
446 | 300 | } | 364 | } |
447 | 301 | 365 | ||
448 | 302 | static void monitor(calcRecord *prec) | 366 | static void monitor(calcRecord *prec) |
449 | 303 | 367 | ||
450 | === modified file 'src/rec/calcRecord.dbd' | |||
451 | --- src/rec/calcRecord.dbd 2007-03-13 16:39:53 +0000 | |||
452 | +++ src/rec/calcRecord.dbd 2010-05-28 09:22:29 +0000 | |||
453 | @@ -153,6 +153,16 @@ | |||
454 | 153 | interest(1) | 153 | interest(1) |
455 | 154 | menu(menuAlarmSevr) | 154 | menu(menuAlarmSevr) |
456 | 155 | } | 155 | } |
457 | 156 | field(AFTC, DBF_DOUBLE) { | ||
458 | 157 | prompt("Alarm Filter Time Constant") | ||
459 | 158 | promptgroup(GUI_ALARMS) | ||
460 | 159 | interest(1) | ||
461 | 160 | } | ||
462 | 161 | field(AFVL, DBF_DOUBLE) { | ||
463 | 162 | prompt("Alarm Filter Value") | ||
464 | 163 | special(SPC_NOMOD) | ||
465 | 164 | interest(3) | ||
466 | 165 | } | ||
467 | 156 | field(HYST,DBF_DOUBLE) { | 166 | field(HYST,DBF_DOUBLE) { |
468 | 157 | prompt("Alarm Deadband") | 167 | prompt("Alarm Deadband") |
469 | 158 | promptgroup(GUI_ALARMS) | 168 | promptgroup(GUI_ALARMS) |
470 | 159 | 169 | ||
471 | === modified file 'src/rec/longinRecord.c' | |||
472 | --- src/rec/longinRecord.c 2010-04-05 18:49:18 +0000 | |||
473 | +++ src/rec/longinRecord.c 2010-05-28 09:22:29 +0000 | |||
474 | @@ -37,6 +37,8 @@ | |||
475 | 37 | #undef GEN_SIZE_OFFSET | 37 | #undef GEN_SIZE_OFFSET |
476 | 38 | #include "epicsExport.h" | 38 | #include "epicsExport.h" |
477 | 39 | 39 | ||
478 | 40 | 40 | ||
479 | 41 | |||
480 | 41 | /* Hysterisis for alarm filtering: 1-1/e */ | 42 | /* Hysterisis for alarm filtering: 1-1/e */ |
481 | 43 | #define THRESHOLD 0.6321 | ||
482 | 42 | /* Create RSET - Record Support Entry Table*/ | 44 | /* Create RSET - Record Support Entry Table*/ |
483 | 43 | #define report NULL | 45 | #define report NULL |
484 | 44 | #define initialize NULL | 46 | #define initialize NULL |
485 | @@ -87,7 +89,7 @@ | |||
486 | 87 | DEVSUPFUN get_ioint_info; | 89 | DEVSUPFUN get_ioint_info; |
487 | 88 | DEVSUPFUN read_longin; /*returns: (-1,0)=>(failure,success)*/ | 90 | DEVSUPFUN read_longin; /*returns: (-1,0)=>(failure,success)*/ |
488 | 89 | }; | 91 | }; |
490 | 90 | static void checkAlarms(longinRecord *prec); | 92 | static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast); |
491 | 91 | static void monitor(longinRecord *prec); | 93 | static void monitor(longinRecord *prec); |
492 | 92 | static long readValue(longinRecord *prec); | 94 | static long readValue(longinRecord *prec); |
493 | 93 | 95 | ||
494 | @@ -132,12 +134,14 @@ | |||
495 | 132 | struct longindset *pdset = (struct longindset *)(prec->dset); | 134 | struct longindset *pdset = (struct longindset *)(prec->dset); |
496 | 133 | long status; | 135 | long status; |
497 | 134 | unsigned char pact=prec->pact; | 136 | unsigned char pact=prec->pact; |
498 | 137 | epicsTimeStamp timeLast; | ||
499 | 135 | 138 | ||
500 | 136 | if( (pdset==NULL) || (pdset->read_longin==NULL) ) { | 139 | if( (pdset==NULL) || (pdset->read_longin==NULL) ) { |
501 | 137 | prec->pact=TRUE; | 140 | prec->pact=TRUE; |
502 | 138 | recGblRecordError(S_dev_missingSup,(void *)prec,"read_longin"); | 141 | recGblRecordError(S_dev_missingSup,(void *)prec,"read_longin"); |
503 | 139 | return(S_dev_missingSup); | 142 | return(S_dev_missingSup); |
504 | 140 | } | 143 | } |
505 | 144 | timeLast = prec->time; | ||
506 | 141 | 145 | ||
507 | 142 | status=readValue(prec); /* read the new value */ | 146 | status=readValue(prec); /* read the new value */ |
508 | 143 | /* check if device support set pact */ | 147 | /* check if device support set pact */ |
509 | @@ -148,7 +152,7 @@ | |||
510 | 148 | if (status==0) prec->udf = FALSE; | 152 | if (status==0) prec->udf = FALSE; |
511 | 149 | 153 | ||
512 | 150 | /* check for alarms */ | 154 | /* check for alarms */ |
514 | 151 | checkAlarms(prec); | 155 | checkAlarms(prec, &timeLast); |
515 | 152 | /* check event list */ | 156 | /* check event list */ |
516 | 153 | monitor(prec); | 157 | monitor(prec); |
517 | 154 | /* process the forward scan link record */ | 158 | /* process the forward scan link record */ |
518 | @@ -210,14 +214,28 @@ | |||
519 | 210 | return(0); | 214 | return(0); |
520 | 211 | } | 215 | } |
521 | 212 | 216 | ||
522 | 213 | 217 | ||
524 | 214 | static void checkAlarms(longinRecord *prec) | 218 | static void checkAlarms(longinRecord *prec, epicsTimeStamp *timeLast) |
525 | 215 | { | 219 | { |
526 | 220 | enum { | ||
527 | 221 | range_Lolo = 1, | ||
528 | 222 | range_Low, | ||
529 | 223 | range_Normal, | ||
530 | 224 | range_High, | ||
531 | 225 | range_Hihi | ||
532 | 226 | } alarmRange; | ||
533 | 227 | static const epicsEnum16 range_stat[] = { | ||
534 | 228 | SOFT_ALARM, LOLO_ALARM, LOW_ALARM, | ||
535 | 229 | NO_ALARM, HIGH_ALARM, HIHI_ALARM | ||
536 | 230 | }; | ||
537 | 231 | |||
538 | 232 | double aftc, afvl; | ||
539 | 216 | epicsInt32 val, hyst, lalm; | 233 | epicsInt32 val, hyst, lalm; |
540 | 217 | epicsInt32 alev; | 234 | epicsInt32 alev; |
541 | 218 | epicsEnum16 asev; | 235 | epicsEnum16 asev; |
542 | 219 | 236 | ||
543 | 220 | if (prec->udf) { | 237 | if (prec->udf) { |
544 | 221 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); | 238 | recGblSetSevr(prec, UDF_ALARM, INVALID_ALARM); |
545 | 239 | prec->afvl = 0; | ||
546 | 222 | return; | 240 | return; |
547 | 223 | } | 241 | } |
548 | 224 | 242 | ||
549 | @@ -225,45 +243,88 @@ | |||
550 | 225 | hyst = prec->hyst; | 243 | hyst = prec->hyst; |
551 | 226 | lalm = prec->lalm; | 244 | lalm = prec->lalm; |
552 | 227 | 245 | ||
592 | 228 | /* alarm condition hihi */ | 246 | /* check VAL against alarm limits */ |
593 | 229 | asev = prec->hhsv; | 247 | if ((asev = prec->hhsv) && |
594 | 230 | alev = prec->hihi; | 248 | (val >= (alev = prec->hihi) || |
595 | 231 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 249 | ((lalm == alev) && (val >= alev - hyst)))) |
596 | 232 | if (recGblSetSevr(prec, HIHI_ALARM, asev)) | 250 | alarmRange = range_Hihi; |
597 | 233 | prec->lalm = alev; | 251 | else |
598 | 234 | return; | 252 | if ((asev = prec->llsv) && |
599 | 235 | } | 253 | (val <= (alev = prec->lolo) || |
600 | 236 | 254 | ((lalm == alev) && (val <= alev + hyst)))) | |
601 | 237 | /* alarm condition lolo */ | 255 | alarmRange = range_Lolo; |
602 | 238 | asev = prec->llsv; | 256 | else |
603 | 239 | alev = prec->lolo; | 257 | if ((asev = prec->hsv) && |
604 | 240 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 258 | (val >= (alev = prec->high) || |
605 | 241 | if (recGblSetSevr(prec, LOLO_ALARM, asev)) | 259 | ((lalm == alev) && (val >= alev - hyst)))) |
606 | 242 | prec->lalm = alev; | 260 | alarmRange = range_High; |
607 | 243 | return; | 261 | else |
608 | 244 | } | 262 | if ((asev = prec->lsv) && |
609 | 245 | 263 | (val <= (alev = prec->low) || | |
610 | 246 | /* alarm condition high */ | 264 | ((lalm == alev) && (val <= alev + hyst)))) |
611 | 247 | asev = prec->hsv; | 265 | alarmRange = range_Low; |
612 | 248 | alev = prec->high; | 266 | else { |
613 | 249 | if (asev && (val >= alev || ((lalm == alev) && (val >= alev - hyst)))) { | 267 | alev = val; |
614 | 250 | if (recGblSetSevr(prec, HIGH_ALARM, asev)) | 268 | asev = NO_ALARM; |
615 | 251 | prec->lalm = alev; | 269 | alarmRange = range_Normal; |
616 | 252 | return; | 270 | } |
617 | 253 | } | 271 | |
618 | 254 | 272 | aftc = prec->aftc; | |
619 | 255 | /* alarm condition low */ | 273 | afvl = 0; |
620 | 256 | asev = prec->lsv; | 274 | |
621 | 257 | alev = prec->low; | 275 | if (aftc > 0) { |
622 | 258 | if (asev && (val <= alev || ((lalm == alev) && (val <= alev + hyst)))) { | 276 | /* Apply level filtering */ |
623 | 259 | if (recGblSetSevr(prec, LOW_ALARM, asev)) | 277 | afvl = prec->afvl; |
624 | 260 | prec->lalm = alev; | 278 | if (afvl == 0) { |
625 | 261 | return; | 279 | afvl = (double)alarmRange; |
626 | 262 | } | 280 | } else { |
627 | 263 | 281 | double t = epicsTimeDiffInSeconds(&prec->time, timeLast); | |
628 | 264 | /* we get here only if val is out of alarm by at least hyst */ | 282 | double alpha = aftc / (t + aftc); |
629 | 265 | prec->lalm = val; | 283 | |
630 | 266 | return; | 284 | /* The sign of afvl indicates whether the result should be |
631 | 285 | * rounded up or down. This gives the filter hysteresis. | ||
632 | 286 | * If afvl > 0 the floor() function rounds to a lower alarm | ||
633 | 287 | * level, otherwise to a higher. | ||
634 | 288 | */ | ||
635 | 289 | afvl = alpha * afvl + | ||
636 | 290 | ((afvl > 0) ? (1 - alpha) : (alpha - 1)) * alarmRange; | ||
637 | 291 | if (afvl - floor(afvl) > THRESHOLD) | ||
638 | 292 | afvl = -afvl; /* reverse rounding */ | ||
639 | 293 | |||
640 | 294 | alarmRange = abs((int)floor(afvl)); | ||
641 | 295 | switch (alarmRange) { | ||
642 | 296 | case range_Hihi: | ||
643 | 297 | asev = prec->hhsv; | ||
644 | 298 | alev = prec->hihi; | ||
645 | 299 | break; | ||
646 | 300 | case range_High: | ||
647 | 301 | asev = prec->hsv; | ||
648 | 302 | alev = prec->high; | ||
649 | 303 | break; | ||
650 | 304 | case range_Normal: | ||
651 | 305 | asev = NO_ALARM; | ||
652 | 306 | break; | ||
653 | 307 | case range_Low: | ||
654 | 308 | asev = prec->lsv; | ||
655 | 309 | alev = prec->low; | ||
656 | 310 | break; | ||
657 | 311 | case range_Lolo: | ||
658 | 312 | asev = prec->llsv; | ||
659 | 313 | alev = prec->lolo; | ||
660 | 314 | break; | ||
661 | 315 | } | ||
662 | 316 | } | ||
663 | 317 | } | ||
664 | 318 | prec->afvl = afvl; | ||
665 | 319 | |||
666 | 320 | if (asev) { | ||
667 | 321 | /* Report alarm condition, store LALM for future HYST calculations */ | ||
668 | 322 | if (recGblSetSevr(prec, range_stat[alarmRange], asev)) | ||
669 | 323 | prec->lalm = alev; | ||
670 | 324 | } else { | ||
671 | 325 | /* No alarm condition, reset LALM */ | ||
672 | 326 | prec->lalm = val; | ||
673 | 327 | } | ||
674 | 267 | } | 328 | } |
675 | 268 | 329 | ||
676 | 269 | 330 | ||
677 | 270 | /* DELTA calculates the absolute difference between its arguments | 331 | /* DELTA calculates the absolute difference between its arguments |
678 | 271 | 332 | ||
679 | === modified file 'src/rec/longinRecord.dbd' | |||
680 | --- src/rec/longinRecord.dbd 2002-07-12 21:35:43 +0000 | |||
681 | +++ src/rec/longinRecord.dbd 2010-05-28 09:22:29 +0000 | |||
682 | @@ -93,6 +93,16 @@ | |||
683 | 93 | promptgroup(GUI_ALARMS) | 93 | promptgroup(GUI_ALARMS) |
684 | 94 | interest(1) | 94 | interest(1) |
685 | 95 | } | 95 | } |
686 | 96 | field(AFTC, DBF_DOUBLE) { | ||
687 | 97 | prompt("Alarm Filter Time Constant") | ||
688 | 98 | promptgroup(GUI_ALARMS) | ||
689 | 99 | interest(1) | ||
690 | 100 | } | ||
691 | 101 | field(AFVL, DBF_DOUBLE) { | ||
692 | 102 | prompt("Alarm Filter Value") | ||
693 | 103 | special(SPC_NOMOD) | ||
694 | 104 | interest(3) | ||
695 | 105 | } | ||
696 | 96 | field(ADEL,DBF_LONG) { | 106 | field(ADEL,DBF_LONG) { |
697 | 97 | prompt("Archive Deadband") | 107 | prompt("Archive Deadband") |
698 | 98 | promptgroup(GUI_DISPLAY) | 108 | promptgroup(GUI_DISPLAY) |
699 | 99 | 109 | ||
700 | === modified file 'src/rec/mbbiRecord.c' | |||
701 | --- src/rec/mbbiRecord.c 2010-04-05 18:49:18 +0000 | |||
702 | +++ src/rec/mbbiRecord.c 2010-05-28 09:22:29 +0000 | |||
703 | @@ -36,6 +36,9 @@ | |||
704 | 36 | #include "mbbiRecord.h" | 36 | #include "mbbiRecord.h" |
705 | 37 | #undef GEN_SIZE_OFFSET | 37 | #undef GEN_SIZE_OFFSET |
706 | 38 | #include "epicsExport.h" | 38 | #include "epicsExport.h" |
707 | 39 | |||
708 | 40 | /* Hysterisis for alarm filtering: 1-1/e */ | ||
709 | 41 | #define THRESHOLD 0.6321 | ||
710 | 39 | /* Create RSET - Record Support Entry Table*/ | 42 | /* Create RSET - Record Support Entry Table*/ |
711 | 40 | #define report NULL | 43 | #define report NULL |
712 | 41 | #define initialize NULL | 44 | #define initialize NULL |
713 | @@ -84,7 +87,7 @@ | |||
714 | 84 | DEVSUPFUN get_ioint_info; | 87 | DEVSUPFUN get_ioint_info; |
715 | 85 | DEVSUPFUN read_mbbi;/*(0,2)=>(success, success no convert)*/ | 88 | DEVSUPFUN read_mbbi;/*(0,2)=>(success, success no convert)*/ |
716 | 86 | }; | 89 | }; |
718 | 87 | static void checkAlarms(mbbiRecord *); | 90 | static void checkAlarms(mbbiRecord *, epicsTimeStamp *); |
719 | 88 | static void monitor(mbbiRecord *); | 91 | static void monitor(mbbiRecord *); |
720 | 89 | static long readValue(mbbiRecord *); | 92 | static long readValue(mbbiRecord *); |
721 | 90 | 93 | ||
722 | 91 | 94 | ||
723 | @@ -146,6 +149,7 @@ | |||
724 | 146 | struct mbbidset *pdset = (struct mbbidset *)(prec->dset); | 149 | struct mbbidset *pdset = (struct mbbidset *)(prec->dset); |
725 | 147 | long status; | 150 | long status; |
726 | 148 | unsigned char pact=prec->pact; | 151 | unsigned char pact=prec->pact; |
727 | 152 | epicsTimeStamp timeLast; | ||
728 | 149 | 153 | ||
729 | 150 | if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) { | 154 | if( (pdset==NULL) || (pdset->read_mbbi==NULL) ) { |
730 | 151 | prec->pact=TRUE; | 155 | prec->pact=TRUE; |
731 | @@ -153,6 +157,8 @@ | |||
732 | 153 | return(S_dev_missingSup); | 157 | return(S_dev_missingSup); |
733 | 154 | } | 158 | } |
734 | 155 | 159 | ||
735 | 160 | timeLast = prec->time; | ||
736 | 161 | |||
737 | 156 | status=readValue(prec); /* read the new value */ | 162 | status=readValue(prec); /* read the new value */ |
738 | 157 | /* check if device support set pact */ | 163 | /* check if device support set pact */ |
739 | 158 | if ( !pact && prec->pact ) return(0); | 164 | if ( !pact && prec->pact ) return(0); |
740 | @@ -184,7 +190,7 @@ | |||
741 | 184 | else if(status == 2) status = 0; | 190 | else if(status == 2) status = 0; |
742 | 185 | 191 | ||
743 | 186 | /* check for alarms */ | 192 | /* check for alarms */ |
745 | 187 | checkAlarms(prec); | 193 | checkAlarms(prec, &timeLast); |
746 | 188 | 194 | ||
747 | 189 | /* check event list */ | 195 | /* check event list */ |
748 | 190 | monitor(prec); | 196 | monitor(prec); |
749 | @@ -274,14 +280,20 @@ | |||
750 | 274 | return(S_db_badChoice); | 280 | return(S_db_badChoice); |
751 | 275 | } | 281 | } |
752 | 276 | 282 | ||
754 | 277 | static void checkAlarms(mbbiRecord *prec) | 283 | static void checkAlarms(mbbiRecord *prec, epicsTimeStamp *timeLast) |
755 | 278 | { | 284 | { |
756 | 285 | |||
757 | 286 | double aftc, afvl; | ||
758 | 287 | |||
759 | 288 | unsigned short alarm; | ||
760 | 289 | epicsEnum16 asev; | ||
761 | 279 | unsigned short *severities; | 290 | unsigned short *severities; |
762 | 280 | unsigned short val=prec->val; | 291 | unsigned short val=prec->val; |
763 | 281 | 292 | ||
764 | 282 | /* check for udf alarm */ | 293 | /* check for udf alarm */ |
765 | 283 | if(prec->udf == TRUE ){ | 294 | if(prec->udf == TRUE ){ |
766 | 284 | recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM); | 295 | recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM); |
767 | 296 | prec->afvl = 0; | ||
768 | 285 | } | 297 | } |
769 | 286 | 298 | ||
770 | 287 | /* check for state alarm */ | 299 | /* check for state alarm */ |
771 | @@ -291,8 +303,36 @@ | |||
772 | 291 | } else { | 303 | } else { |
773 | 292 | /* in a state which is an error */ | 304 | /* in a state which is an error */ |
774 | 293 | severities = (unsigned short *)&(prec->zrsv); | 305 | severities = (unsigned short *)&(prec->zrsv); |
775 | 306 | /* | ||
776 | 294 | recGblSetSevr(prec,STATE_ALARM,severities[prec->val]); | 307 | recGblSetSevr(prec,STATE_ALARM,severities[prec->val]); |
778 | 295 | } | 308 | */ |
779 | 309 | alarm = severities[prec->val]; | ||
780 | 310 | |||
781 | 311 | } | ||
782 | 312 | |||
783 | 313 | aftc = prec->aftc; | ||
784 | 314 | afvl = 0.; | ||
785 | 315 | |||
786 | 316 | if(aftc > 0.) { | ||
787 | 317 | afvl = prec->afvl; | ||
788 | 318 | if(afvl == 0.) { | ||
789 | 319 | afvl = (double) alarm; | ||
790 | 320 | } else { | ||
791 | 321 | double t = epicsTimeDiffInSeconds(&prec->time, timeLast); | ||
792 | 322 | double alpha = aftc / (t + aftc); | ||
793 | 323 | |||
794 | 324 | afvl = alpha * afvl + | ||
795 | 325 | ((afvl>0.)?(1.-alpha):(alpha-1.)) * alarm; | ||
796 | 326 | if(afvl - floor(afvl) > THRESHOLD) | ||
797 | 327 | afvl = -afvl; | ||
798 | 328 | |||
799 | 329 | alarm = abs((int)floor(afvl)); | ||
800 | 330 | } | ||
801 | 331 | } | ||
802 | 332 | |||
803 | 333 | |||
804 | 334 | asev = alarm; | ||
805 | 335 | recGblSetSevr(prec, STATE_ALARM, asev); | ||
806 | 296 | 336 | ||
807 | 297 | /* check for cos alarm */ | 337 | /* check for cos alarm */ |
808 | 298 | if(val == prec->lalm) return; | 338 | if(val == prec->lalm) return; |
809 | 299 | 339 | ||
810 | === modified file 'src/rec/mbbiRecord.dbd' | |||
811 | --- src/rec/mbbiRecord.dbd 2009-06-08 19:55:49 +0000 | |||
812 | +++ src/rec/mbbiRecord.dbd 2010-05-28 09:22:29 +0000 | |||
813 | @@ -394,6 +394,16 @@ | |||
814 | 394 | interest(1) | 394 | interest(1) |
815 | 395 | menu(menuAlarmSevr) | 395 | menu(menuAlarmSevr) |
816 | 396 | } | 396 | } |
817 | 397 | field(AFTC, DBF_DOUBLE) { | ||
818 | 398 | prompt("Alarm Filter Time Constant") | ||
819 | 399 | promptgroup(GUI_ALARMS) | ||
820 | 400 | interest(1) | ||
821 | 401 | } | ||
822 | 402 | field(AFVL, DBF_DOUBLE) { | ||
823 | 403 | prompt("Alarm Filter Value") | ||
824 | 404 | special(SPC_NOMOD) | ||
825 | 405 | interest(3) | ||
826 | 406 | } | ||
827 | 397 | field(UNSV,DBF_MENU) { | 407 | field(UNSV,DBF_MENU) { |
828 | 398 | prompt("Unknown State Severity") | 408 | prompt("Unknown State Severity") |
829 | 399 | promptgroup(GUI_MBB) | 409 | promptgroup(GUI_MBB) |
I can easily see this for the "numerical" calc and the longin records.
But what does the new behavior for the "enum" mbbi record mean? Suppressing spikes? How does that interact with the ACKT field?