519 lines
15 KiB
Plaintext
519 lines
15 KiB
Plaintext
#*************************************************************************
|
|
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
|
# National Laboratory.
|
|
# Copyright (c) 2002 The Regents of the University of California, as
|
|
# Operator of Los Alamos National Laboratory.
|
|
# EPICS BASE is distributed subject to a Software License Agreement found
|
|
# in file LICENSE that is included with this distribution.
|
|
#*************************************************************************
|
|
|
|
=title Compression Record (compress)
|
|
|
|
The data compression record is used to collect and compress data from arrays.
|
|
When the INP field references a data array field, it immediately compresses the
|
|
entire array into an element of an array using one of several algorithms,
|
|
overwriting the previous element. If the INP field obtains its value from a
|
|
scalar-value field, the compression record will collect a new sample each time
|
|
the record is processed and add it to the compressed data array as a circular
|
|
buffer.
|
|
|
|
The INP link can also specify a constant; however, if this is the case, the
|
|
compression algorithms are ignored, and the record support routines merely
|
|
return after checking the FLNK field.
|
|
|
|
=head2 Record-specific Menus
|
|
|
|
=head3 Menu compressALG
|
|
|
|
The ALG field which uses this menu controls the compression algorithm used by
|
|
the record.
|
|
|
|
=menu compressALG
|
|
|
|
=head3 Menu bufferingALG
|
|
|
|
The BALG field which uses this menu controls whether new values are inserted at
|
|
the beginning or the end of the VAL array.
|
|
|
|
=menu bufferingALG
|
|
|
|
|
|
=head2 Parameter Fields
|
|
|
|
The record-specific fields are described below, grouped by functionality.
|
|
|
|
=recordtype compress
|
|
|
|
=cut
|
|
|
|
menu(compressALG) {
|
|
choice(compressALG_N_to_1_Low_Value,"N to 1 Low Value")
|
|
choice(compressALG_N_to_1_High_Value,"N to 1 High Value")
|
|
choice(compressALG_N_to_1_Average,"N to 1 Average")
|
|
choice(compressALG_Average,"Average")
|
|
choice(compressALG_Circular_Buffer,"Circular Buffer")
|
|
choice(compressALG_N_to_1_Median,"N to 1 Median")
|
|
}
|
|
menu(bufferingALG) {
|
|
choice(bufferingALG_FIFO, "FIFO Buffer")
|
|
choice(bufferingALG_LIFO, "LIFO Buffer")
|
|
}
|
|
recordtype(compress) {
|
|
|
|
=head3 Scanning Parameters
|
|
|
|
The compression record has the standard fields for specifying under what
|
|
circumstances the record will be processed. Since the compression record
|
|
supports no direct interfaces to hardware, its SCAN field cannot be set to C<<<
|
|
I/O Intr >>>.
|
|
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
|
|
|
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
|
|
|
=head3 Algorithms and Related Parameters
|
|
|
|
The user specifies the algorithm to be used in the ALG field. There are six possible
|
|
algorithms which can be specified as follows:
|
|
|
|
=head4 Menu compressALG
|
|
|
|
=menu compressALG
|
|
|
|
The following fields determine what channel to read and how to compress the data:
|
|
|
|
=fields ALG, INP, NSAM, N, ILIL, IHIL, OFF, RES, PBUF
|
|
|
|
As stated above, the ALG field specifies which algorithm to be performed on the data.
|
|
|
|
The INP should be a database or channel access link. Though INP can be a
|
|
constant, the data compression algorithms are supported only when INP is a
|
|
database link. See L<Address
|
|
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
|
for information on specifying links.
|
|
|
|
|
|
IHIL and ILIL can be set to provide an initial value filter on the input array.
|
|
If ILIL E<lt> IHIL, the input elements will be skipped until a value is found
|
|
that is in the range of ILIL to IHIL. Note that ILIL and IHIL are used only in
|
|
C<<< N to 1 >>> algorithms.
|
|
|
|
OFF provides the offset to the current beginning of the array data.
|
|
Note that OFF is used only in C<<< N to 1 >>> algorithms.
|
|
|
|
The RES field can be accessed at run time to cause the algorithm to reset
|
|
itself before the maximum number of samples are reached.
|
|
|
|
=head4 Algorithms
|
|
|
|
B<Circular Buffer> algorithm keeps a circular buffer of length NSAM.
|
|
Each time the record is processed, it gets the data referenced by INP and puts
|
|
it into the circular buffer referenced by VAL. The INP can refer to both scalar or
|
|
array data and VAL is just a time ordered circular buffer of values obtained
|
|
from INP.
|
|
Note that N, ILIL, IHIL and OFF are not used in C<<< Circular Buffer >>> algorithm.
|
|
|
|
B<Average> takes an average of every element of the array obtained from
|
|
INP over time; that is, the entire array referenced by INP is retrieved, and for
|
|
each element, the new average is calculated and placed in the corresponding
|
|
element of the value buffer. The retrieved array is truncated to be of length
|
|
NSAM. N successive arrays are averaged and placed in the buffer. Thus, VAL[0]
|
|
holds the average of the first element of INP over N samples, VAL[1] holds the
|
|
average of the next element of INP over N samples, and so on. The following
|
|
shows the equation:
|
|
|
|
=for comment Latex form of equation bellow : VAL[i] \leftarrow \frac{1}{N}\sum_{n=1}^NINP_{n}[i]
|
|
|
|
=begin html
|
|
|
|
<img src="image/compress-1.png">
|
|
|
|
=end html
|
|
|
|
B<N to 1> If any of the C<<< N to 1 >>> algorithms are chosen, then VAL is a circular
|
|
buffer of NSAM samples.
|
|
The actual algorithm depends on whether INP references a scalar or an array.
|
|
|
|
If INP refers to a scalar, then N successive time ordered samples of INP are taken.
|
|
After the Nth sample is obtained, a new value determined by the algorithm
|
|
(Lowest, Highest, or Average), is written to the circular buffer referenced by
|
|
VAL. If C<<< Low Value >>> the lowest value of all the samples is written; if
|
|
C<<< High Value >>> the highest value is written; and if C<<< Average >>>, the
|
|
average of all the samples are written. The C<<< Median >>> setting behaves
|
|
like C<<< Average >>> with scalar input data.
|
|
|
|
If INP refers to an array, then the following applies:
|
|
|
|
=over
|
|
|
|
=item C<<< N to 1 Low Value >>>
|
|
|
|
Compress N to 1 samples, keeping the lowest value.
|
|
|
|
=item C<<< N to 1 High Value >>>
|
|
|
|
Compress N to 1 samples, keeping the highest value.
|
|
|
|
=item C<<< N to 1 Average >>>
|
|
|
|
Compress N to 1 samples, taking the average value.
|
|
|
|
=item C<<< N to 1 Median >>>
|
|
|
|
Compress N to 1 samples, taking the median value.
|
|
|
|
=back
|
|
|
|
The behaviour of the record for partially filled buffers depends on the field PBUF.
|
|
If PBUF is set to NO, then the record will wait until the buffer is completely full
|
|
before processing. If PBUF is set to YES, then it will start processing immediately.
|
|
|
|
For example, if ALG is set to C<<< N to 1 Average >>> with NSAM equal to 4, N equal
|
|
to 1, and PBUF set to NO, then the first three times that the compress record is
|
|
processed it will remain in an undefined state. On the fourth process, the average
|
|
of all four records will be calculated and placed into the VAL field.
|
|
|
|
If PBUF is set to YES, then after each process the average of the first several
|
|
elements will be calculated.
|
|
|
|
Note that PBUF has no impact on the C<<< Average >>> method. If one wishes to have a
|
|
rolling average computed, then the best way to achieve that is with two compress
|
|
records: a C<<< Circular buffer >>> which is linked to an C<<< N to 1 Average >>>
|
|
record with PBUF set to YES.
|
|
|
|
The compression record keeps NSAM data samples.
|
|
|
|
The field N determines the number of elements to compress into each result.
|
|
|
|
Thus, if NSAM was 3, and N was also equal to 3, then the algorithms would work
|
|
as in the following diagram:
|
|
|
|
=begin html
|
|
|
|
<img src="image/compress-2.png">
|
|
|
|
=end html
|
|
|
|
|
|
=head3 Operator Display Parameters
|
|
|
|
These parameters are used to present meaningful data to the operator. They
|
|
display the value and other parameters of the record either textually or
|
|
graphically.
|
|
|
|
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
|
|
|
|
The EGU field should be given a string that describes the value of VAL, but is
|
|
used whenever the C<<< get_units >>> record support routine is called.
|
|
|
|
The HOPR and LOPR fields only specify the upper and lower display limits for
|
|
VAL, HIHI, HIGH, LOLO and LOW fields.
|
|
|
|
PREC controls the floating-point precision whenever C<<< get_precision >>> is
|
|
called, and the field being referenced is the VAL field (i.e., one of the values
|
|
contained in the circular buffer).
|
|
|
|
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
|
|
Parameters> for more on the record name (NAME) and description (DESC) fields.
|
|
|
|
|
|
=head3 Alarm Parameters
|
|
|
|
The compression record has the alarm parameters common to all record types
|
|
described in L<Alarm Fields|dbCommonRecord/Alarm Fields>.
|
|
|
|
=head3 Run-time Parameters
|
|
|
|
These parameters are used by the run-time code for processing the data
|
|
compression algorithm. They are not configurable by the user, though some are
|
|
accessible at run-time. They can represent the current state of the algorithm or
|
|
of the record whose field is referenced by the INP field.
|
|
|
|
=fields NUSE, OUSE, BPTR, SPTR, WPTR, CVB, INPN, INX
|
|
|
|
NUSE and OUSE hold the current and previous number of elements stored in VAL.
|
|
|
|
BPTR points to the buffer referenced by VAL.
|
|
|
|
SPTR points to an array that is used for array averages.
|
|
|
|
WPTR points to the buffer containing data referenced by INP.
|
|
|
|
CVB stores the current compressed value for C<<< N to 1 >>> algorithms when INP
|
|
references a scalar.
|
|
|
|
INPN is updated when the record processes; if INP references an array and the
|
|
size changes, the WPTR buffer is reallocated.
|
|
|
|
INX counts the number of readings collected.
|
|
|
|
=head2 Record Support
|
|
|
|
=head3 Record Support Routines
|
|
|
|
long init_record(struct dbCommon *precord, int pass)
|
|
|
|
Space for all necessary arrays is allocated. The addresses are stored in the
|
|
appropriate fields in the record.
|
|
|
|
long process(struct dbCommon *precord)
|
|
|
|
See L</"Record Processing"> below.
|
|
|
|
long special(struct dbAddr *paddr, int after)
|
|
|
|
This routine is called when RSET, ALG, or N are set. It performs a reset.
|
|
|
|
long cvt_dbaddr(struct dbAddr *paddr)
|
|
|
|
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
|
|
actual buffer holding the result.
|
|
|
|
long get_array_info(struct dbAddr *paddr, long *no_elements, long *offset)
|
|
|
|
Obtains values from the circular buffer referenced by VAL.
|
|
|
|
long put_array_info(struct dbAddr *paddr, long nNew);
|
|
|
|
Writes values into the circular buffer referenced by VAL.
|
|
|
|
long get_units(struct dbAddr *paddr, char *units);
|
|
|
|
Retrieves EGU.
|
|
|
|
long get_precision(const struct dbAddr *paddr, long *precision);
|
|
|
|
Retrieves PREC.
|
|
|
|
long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *p);
|
|
|
|
Sets the upper display and lower display limits for a field. If the field is
|
|
VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower
|
|
limits defined they will be used, else the upper and lower maximum values for
|
|
the field type will be used.
|
|
|
|
long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *p);
|
|
|
|
Sets the upper control and the lower control limits for a field. If the field is
|
|
VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower
|
|
limits defined they will be used, else the upper and lower maximum values for
|
|
the field type will be used.
|
|
|
|
=head3 Record Processing
|
|
|
|
Routine process implements the following algorithm:
|
|
|
|
=over
|
|
|
|
=item 1.
|
|
|
|
If INP is not a database link, check monitors and the forward link and return.
|
|
|
|
=item 2.
|
|
|
|
Get the current data referenced by INP.
|
|
|
|
=item 3.
|
|
|
|
Perform the appropriate algorithm:
|
|
|
|
=over
|
|
|
|
=item *
|
|
|
|
Average: Read N successive instances of INP and perform an element by element
|
|
average. Until N instances have been obtained it just return without checking
|
|
monitors or the forward link. When N instances have been obtained complete the
|
|
algorithm, store the result in the VAL array, check monitors and the forward
|
|
link, and return.
|
|
|
|
=item *
|
|
|
|
Circular Buffer: Write the values obtained from INP into the VAL array as a
|
|
circular buffer, check monitors and the forward link, and return.
|
|
|
|
=item *
|
|
|
|
N to 1 xxx when INP refers to a scalar: Obtain N successive values from INP and
|
|
apply the N to 1 xxx algorithm to these values. Until N values are obtained
|
|
monitors and forward links are not triggered. When N successive values have been
|
|
obtained, complete the algorithm, check monitors and trigger the forward link,
|
|
and return.
|
|
|
|
=item *
|
|
|
|
N to 1 xxx when INP refers to an array: The ILIL and IHIL are honored if ILIL
|
|
E<lt> IHIL. The input array is divided into subarrays of length N. The specified
|
|
N to 1 xxx compression algorithm is applied to each sub-array and the result
|
|
stored in the array referenced by VAL. The monitors and forward link are
|
|
checked.
|
|
|
|
=back
|
|
|
|
=item 4.
|
|
|
|
If success, set UDF to FALSE.
|
|
|
|
=item 5.
|
|
|
|
Check to see if monitors should be invoked:
|
|
|
|
=over
|
|
|
|
=item *
|
|
|
|
Alarm monitors are invoked if the alarm status or severity has changed.
|
|
|
|
=item *
|
|
|
|
NSEV and NSTA are reset to 0.
|
|
|
|
=back
|
|
|
|
=item 6.
|
|
|
|
Scan forward link if necessary, set PACT FALSE, and return.
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
include "dbCommon.dbd"
|
|
field(VAL,DBF_NOACCESS) {
|
|
prompt("Value")
|
|
asl(ASL0)
|
|
special(SPC_DBADDR)
|
|
pp(TRUE)
|
|
extra("void * val")
|
|
#=type DOUBLE[]
|
|
#=read Yes
|
|
#=write Yes
|
|
}
|
|
field(INP,DBF_INLINK) {
|
|
prompt("Input Specification")
|
|
promptgroup("40 - Input")
|
|
interest(1)
|
|
}
|
|
field(RES,DBF_SHORT) {
|
|
prompt("Reset")
|
|
asl(ASL0)
|
|
special(SPC_RESET)
|
|
interest(3)
|
|
}
|
|
field(ALG,DBF_MENU) {
|
|
prompt("Compression Algorithm")
|
|
promptgroup("30 - Action")
|
|
special(SPC_RESET)
|
|
interest(1)
|
|
menu(compressALG)
|
|
}
|
|
field(PBUF,DBF_MENU) {
|
|
prompt("Use Partial buffers")
|
|
promptgroup("30 - Action")
|
|
special(SPC_RESET)
|
|
interest(1)
|
|
menu(menuYesNo)
|
|
initial("NO")
|
|
}
|
|
field(BALG,DBF_MENU) {
|
|
prompt("Buffering Algorithm")
|
|
promptgroup("30 - Action")
|
|
special(SPC_RESET)
|
|
interest(1)
|
|
menu(bufferingALG)
|
|
}
|
|
field(NSAM,DBF_ULONG) {
|
|
prompt("Number of Values")
|
|
promptgroup("30 - Action")
|
|
special(SPC_NOMOD)
|
|
interest(1)
|
|
initial("1")
|
|
}
|
|
field(N,DBF_ULONG) {
|
|
prompt("N to 1 Compression")
|
|
promptgroup("30 - Action")
|
|
special(SPC_RESET)
|
|
interest(1)
|
|
initial("1")
|
|
}
|
|
field(IHIL,DBF_DOUBLE) {
|
|
prompt("Init High Interest Lim")
|
|
promptgroup("30 - Action")
|
|
interest(1)
|
|
}
|
|
field(ILIL,DBF_DOUBLE) {
|
|
prompt("Init Low Interest Lim")
|
|
promptgroup("30 - Action")
|
|
interest(1)
|
|
}
|
|
field(HOPR,DBF_DOUBLE) {
|
|
prompt("High Operating Range")
|
|
promptgroup("80 - Display")
|
|
interest(1)
|
|
prop(YES)
|
|
}
|
|
field(LOPR,DBF_DOUBLE) {
|
|
prompt("Low Operating Range")
|
|
promptgroup("80 - Display")
|
|
interest(1)
|
|
prop(YES)
|
|
}
|
|
field(PREC,DBF_SHORT) {
|
|
prompt("Display Precision")
|
|
promptgroup("80 - Display")
|
|
interest(1)
|
|
prop(YES)
|
|
}
|
|
field(EGU,DBF_STRING) {
|
|
prompt("Engineering Units")
|
|
promptgroup("80 - Display")
|
|
interest(1)
|
|
size(16)
|
|
prop(YES)
|
|
}
|
|
field(OFF,DBF_ULONG) {
|
|
prompt("Offset")
|
|
special(SPC_NOMOD)
|
|
}
|
|
field(NUSE,DBF_ULONG) {
|
|
prompt("Number Used")
|
|
special(SPC_NOMOD)
|
|
}
|
|
field(OUSE,DBF_ULONG) {
|
|
prompt("Old Number Used")
|
|
special(SPC_NOMOD)
|
|
}
|
|
field(BPTR,DBF_NOACCESS) {
|
|
prompt("Buffer Pointer")
|
|
special(SPC_NOMOD)
|
|
interest(4)
|
|
extra("double *bptr")
|
|
}
|
|
field(SPTR,DBF_NOACCESS) {
|
|
prompt("Summing Buffer Ptr")
|
|
special(SPC_NOMOD)
|
|
interest(4)
|
|
extra("double *sptr")
|
|
}
|
|
field(WPTR,DBF_NOACCESS) {
|
|
prompt("Working Buffer Ptr")
|
|
special(SPC_NOMOD)
|
|
interest(4)
|
|
extra("double *wptr")
|
|
}
|
|
field(INPN,DBF_LONG) {
|
|
prompt("Number of elements in Working Buffer")
|
|
special(SPC_NOMOD)
|
|
interest(4)
|
|
}
|
|
field(CVB,DBF_DOUBLE) {
|
|
prompt("Compress Value Buffer")
|
|
special(SPC_NOMOD)
|
|
interest(3)
|
|
}
|
|
field(INX,DBF_ULONG) {
|
|
prompt("Current number of readings")
|
|
special(SPC_NOMOD)
|
|
interest(3)
|
|
}
|
|
}
|