Here's a sample MEDM display of some of the the aCalcout record fields.
The number of elements actually used is specified as NUSE. The value of NUSE will forced into the range 0,NELM (inclusive). If NUSE==0, the record will take it as NELM.
When a CA client connects to an array, the acalcout record can tell the client that the array size is either NELM, or NUSE, depending on the setting of the SIZE field, which takes values "NELM" and "NUSE". "NELM" is the default, and it's the safer choice. "NELM" is less efficient than "NUSE", in some cases. If SIZE is set to "NUSE", the CA connection must be broken and reestablished when the NUSE field increases.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor 

NELM  Number of allocated array elements  DBF_ULONG  Yes  1  Yes  No  N/A 
NUSE  Number of array elements actually to be used  DBF_ULONG  Yes  0  Yes  Yes  Yes 
SIZE  Specified whether NELM or NUSE is the array size declared to clients  MENU("NELM","NUSE")  Yes  "NELM"  Yes  Yes  N/A 
See the EPICS Record Reference Manual for information on how to specify database links.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor 

INPA  Input Link A  INLINK  Yes  0  Yes  Yes  N/A 
INPB  Input Link B  INLINK  Yes  0  Yes  Yes  N/A 
...  ...  ...  ...  ...  ...  ...  ... 
INPL  Input Link L  INLINK  Yes  0  No  No  N/A 
INAA  Input Link AA  INLINK  Yes  0  Yes  Yes  N/A 
INBB  Input Link BB  INLINK  Yes  0  Yes  Yes  N/A 
...  ...  ...  ...  ...  ...  ...  ... 
INLL  Input Link LL  INLINK  Yes  0  Yes  Yes  N/A 
The CALC expression is converted to opcodes and stored in postfix
notation in the RPCL field. It is the postfix expression which is actually
evaluated when the record processes. When the CALC field is changed at
runtime, the recordsupport routine special()
calls a function
to check it and convert it to postfix.
The record also has a second set of calculationrelated fields described in
Section 6, Output Parameters.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

CALC  Calculation  STRING[36]  Yes  0  Yes  Yes  Yes  No 
VAL  Value  DOUBLE  No  0  Yes  Yes  Yes  No 
RPCL  Postfix  NOACCESS  No  0  No  No  N/A  No 
AVAL  Array value  DOUBLE  No  0  Yes  Yes  Yes  No 
Expressions supported by the array calculation record can involve scalar and/or array operands, algebraic operators and functions, trigonometric functions, relational operators, logical operators, array operators and functions, parentheses and commas, and the conditional '?:' operator. All are described in sections to follow, but first, we need to talk about how operators and functions behave when presented with scalar, array, and mixed operands.
Unless otherwise stated, functions and operators behave as follows:
aa+bb =
aa[0]+bb[0], aa[1]+bb[1],...
)
A*BB
is the array
a*bb[0], a*bb[1], a*bb[3],...
?:
, ^
, **
, >>
, and
<<
), the scalar value used is the value of the first array
element. In the following expressions, the array argument in color will be converted implicitly to scalar:
The number of elements of the array operands AALL is set at boot time by the field NELM. If an array value is received by the record with more or fewer elements, the array used by the aCalcout record will be truncated or padded at the end with zeros.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

A  Input Value A  DOUBLE  No  0  Yes  Yes/No*  Yes  Yes 
B  Input Value B  DOUBLE  No  0  Yes  Yes/No*  Yes  Yes 
...  ...  ...  ...  ...  ...  ...  ...  ... 
L  Input Value L  DOUBLE  No  0  Yes  Yes/No*  Yes  Yes 
AA  Input array AA  DOUBLE ARRAY  No  0  Yes  Yes/No*  Yes  Yes 
BB  Input array BB  DOUBLE ARRAY  No  0  Yes  Yes/No*  Yes  Yes 
...  ...  ...  ...  ...  ...  ...  ...  ... 
LL  Input array LL  DOUBLE ARRAY  No  0  Yes  Yes/No*  Yes  Yes 
* If a valid input link is associated with this field, then the record will not not permit it to be modified by a 'put' operation.
There are a few special operands not associated with input fields, but
defined by the record (more exactly, defined by the calc engine the record uses
to evaluate expressions). All but RNDM
, NRNDM
, and ARNDM
are
constants.
PI  3.141592654 
D2R  Degrees to radians (PI/180) 
R2D  Radians to degrees (1/D2R) 
S2R  Arc seconds to radians (D2R/3600) 
R2S  Radians to arc seconds (1/S2R) 
NRNDM  Random number from a normal (Gaussian) distribution about 0, with a standard deviation of 1. 
RNDM  Random number between 0 and 1. 
ARNDM  Array of random numbers between 0 and 1. 
IX  The array (0,1,2,...,NUSE). 
VAL  The previous value of the VAL field. (In an OCAL expression, "VAL" is the previous value of the OVAL field.) 
AVAL  The previous value of the AVAL field. (In an OCAL expression, "AVAL" is the previous value of the OAV field.) 
Op  Description  Example 

ABS  Absolute value (oneargument function)  ABS(A)

DBL  Convert (array) to double (oneargument function)  DBL(AA)

FINITE  True if all arguments are finite (variableargument function)  FINITE(A,B,...)

ISINF  True if argument is infinite (oneargument function)  ISINF(A)

ISNAN  True if argument is not a number (oneargument function)  ISNAN(A)

SQRT  Square root (oneargument function) (SQR is deprecated)  SQRT(A)

MIN  Minimum (variableargument function)  MIN(A,B,...)

MAX  Maximum (variableargument function)  MAX(A,B,...)

CEIL  Ceiling (oneargument function)  CEIL(A)

FLOOR  Floor (oneargument function)  FLOOR(A)

INT  Nearest integer (oneargument function)  INT(A)

NINT  Nearest integer (oneargument function)  NINT(A)

LOG  Log base 10 (oneargument function)  LOG(A)

LN  Natural logarithm (oneargument function)  LN(A)

LOGE  Deprecated synonym for 'LN'  LOGE(A)

EXP  Exponential function (unary)  EXP(A)

^  Exponential (binary) (Same as '**'.)  A^B

**  Exponential (binary) (Same as '^'.)  A**B

+  Addition (binary)  A+B

  Subtraction (binary)  AB

*  Multiplication (binary)  A*B

/  Division (binary)  A/B

%  Modulo (binary)  A%B

  Negate (unary)  A

NOT  Negate (unary)  NOT A

>&  Max (binary)  A>?B

<&  Min (binary)  A<?B

Op  Description  Example 

SIN  Sine (oneargument function)  SIN(A)

SINH  Hyperbolic sine (oneargument function)  SINH(A)

ASIN  Arc sine (oneargument function)  ASIN(A)

COS  Cosine (oneargument function)  COS(A)

COSH  Hyperbolic cosine (oneargument function)  COSH(A)

ACOS  Arc cosine (oneargument function)  ACOS(A)

TAN  Tangent (oneargument function)  TAN(A)

TANH  Hyperbolic tangent (oneargument function)  TANH(A)

ATAN  Arc tangent (oneargument function)  ATAN(A)

ATAN2  Alternate form of arctangent (twoargument function)  ATAN2(A,B)

Op  Description  Example 

>=  Greater than or equal to  A>=B

>  Greater than  A>B

<=  Less than or equal to  A<=B

<  Less than  A<B

!=  Not equal to (same as '#')  A!=B

#  Not equal to (same as '!=')  A#B

==  Equal to (same as '=')  A==B

=  Equal to (same as '==')  A=B

Op  Description  Example 

&&  Logical AND  A&&B

  Logical OR  AB

!  Logical NOT  !A

Op  Description  Example 

  Bitwise OR  AB

OR  Bitwise OR  A OR B

&  Bitwise AND  A&B

AND  Bitwise AND  A AND B

XOR  Bitwise Exclusive OR  A XOR B

~  One's Complement  ~A

<<  Left shift  A<<B

>>  Right shift  A>>B

A AND B
could be shortened to A ANDB
,
because ANDB
will be parsed as AND B
. However,
A AND B
may not be shortened to AAND B
, because
AAND
would be parsed as AA ND
.
?:
") operator is supported. The format is:
<expression> ? <expressiontrue result> : <expressionfalse result>
Op  Description  Example 

[  Subarray  AA[1,3] > aa(1),aa(2),aa(3)

{  Subarray in place  AA[1,3] > 0, aa(1),aa(2),aa(3), 0,...

>>  Array shift right. Move array elements by index. If index is not an integer, the array is interpolated to move by the fractional part.  AA>>2

<<  Array shift left. Move array elements by index. If index is not an integer, the array is interpolated to move by the fractional part.  AA<<2 (same as AA>>2 )

AMIN  Minimal element of array (oneargument function)  AMIN(AA) > scalar

AMAX  Maximal element of array (oneargument function)  AMAX('a','b','c') > 'c'

ARR  Convert argument to array (oneargument function)  ARR(1) > 1, 1, 1,...

AVG  Average of array values  AVG(AA)

CUM  Running sum of array values. For example, if AA=(1,2,3), CUM(AA)=(1,3,6).  CUM(AA)

DERIV  Derivative of array values, with respect to array index. Equivalent to NDERIV(AA,2).  DERIV(AA)

FWHM  Full width at half max of array values  FWHM(AA)

FITPOLY  Fit array to second order polynomial a + b*x + c*x^2.  FITPOLY(AA)

FITMPOLY  Fit masked array to second order polynomial. First argument is inputdata array, second argument is the mask array. If maskarray element value is true (greater than zero), corresponding dataarray element will be used to compute bestfit polynomial a + b*x + c*x^2.  FITPOLY(AA,AA>0)

IX  The array (0,1,2,3,...,NUSE)  IX

NDERIV  Derivative of array values, with respect to array index. Derivative is calculated in the following way: at each array point, fit N surrounding array points to a secondorder polynomial, take the derivative of the polynomial analytically, and evaluate it at the index of the array point. The number of points, on either side of the array point, to be used in the fit, is specified by the second argument to NDERIV(). (I.e., if N is specified, 2*N+1 points will be fit.) Array elements less than N points from the beginning or end of the array will get a less effectively calculated derivative, since the fit will not be centered on the point.  NDERIV(AA,B)

NSMOO  Smooth array values, using multiple applications of SMOO()  NSMOO(AA,B)

STD  Standard deviation of array values  STD(AA)

SMOO  Smooth array values, using a 5point binomial formula y'(i) = y(i2)/16 + y(i1)/4 + 3*y(i)/8 + y(i+1)/4 + y(i+2)/16  SMOO(AA)

SUM  Sum of array values.  SUM(AA)

These operators represent the scalar/array fields of the aCalcout record as arrays of scalars/arrays. They are an alternative way of specifying the fields AL and AALL.
Op  Description  Example 

@  Scalar array element. Regard the numeric fields AL as an array whose
elements are numbered 011, and return the element whose number follows.
Thus, @0 is another way of saying A .
(unary operator)
 @A

@@  Array array element. Regard the array fields AALL as an array of arrays whose
elements are numbered 011, and return the element whose number follows.
Thus, @@1 is another way of saying BB .
(unary operator)
 @@A

Op  Description  Examples 

:=  Store value of right hand side in location specified by left hand side. (binary)  A:=1.2

UNTIL  Execute expression until its value is TRUE. (binary) The total number of iterations is limited to the iocshell variable sCalcLoopMax, which defaults to 1000.  until(1)

A + B + 10
A + B + 10
(A + B) < (C + D)
1
if (A+B) < (C+D)
0
if (A+B) >= (C+D)
(A+B)<(C+D)?E:F+L+10
E
if (A+B) < (C+D)
F+L+10
if (A+B) >= (C+D)
(A+B)<(C+D)?E
E
if (A+B) < (C+D)
(A+B) >= (C+D)
A&B
A
to integer
B
to integer
AND
of A
and B
Notation: I'll use (1,2,3)
to indicate an array. Note that
[1,2] is not an array, but the subrange operator with arguments 1 and 2.
The subrange operator must follow an array, like so: AA[2,5]
.
Similarly, {1,2} is not an array, but the subrangeinplace operator.
A + AA
(2,3,4)
.
A + DBL(AA)
2
. DBL returns the first array element.
AA+BB
(8,10,12)
. Elementbyelement sum. Most operators
behave in this way.
AA[2,4]
(3,4,5)
. (The first element of an array is
numbered "0".)
AA[3,1]
(2,3,4)
. (The last element of an array is
numbered "1".)
AA{2,4}
(0,0,3,4,5,0)
. (Similar to the [] operator,
but the selected subrange is left in place.)
@0
A
. ("@0
"
is just another name for A
.)
@@0
@(A+B)
a:=0
is an incomplete and therefore illegal calc expression,
because it leaves us with nothing to write to the record's VAL
field.
A:=A1;7
A1
, store the result in the input
variable A
, set the VAL field to 7.
@0:=A1;7
@0
is just another name for A
D:=0;@D:=A1;7
D==0
.
AA:=IX;7
AA
with the array (0,1,2...), and set the VAL field to 7.
AA:=IX;b:=0;1
1
.
A+(AA:="abc";b:=0;1)
1
, which is added to
A
.
@0:=A1;7
A1
, store the result in the input
variable A
, and set the VAL field to 7.
UNTIL
function evaluates its expression repeatedly until the
expression returns a nonzero value, or the allowed number of iterations
sCalcLoopMax
has been reached. When looping is done, or aborted,
the expression value is returned.
UNTIL(1)
(1)
.
B:=10;UNTIL(B:=B1;B<1)
BB:=1; B:=1; AA:=BB; UNTIL(AA:=AA+(BB>>B); B:=B+1; B>10)
BB
to (1,1,1...)
. Loop to integrate
over BB
, so that the N'th element of AA
will be the
sum of all elements of BB[0,N]
.This expression is useful for converting an array of step pulses accumulated by a multichannel scaler into an array of positions at which the multichannel scaler's channeladvance signal was triggered. (The "CUM" function does this operation.)
AA:=0;L:=0;UNTIL(AA:=AA+(ARR(@L)[0,0]>>L);L:=L+1;L>10)
AJ
to the first 10 elements of the array AA
.(This quite an inefficient way to do the job. An asub record would be much more efficient.)
L:=0;AA:=IX;UNTIL(@L:=AA[L,L];L:=L+1;L>10)
AA
to the scalar input variables AJ
.(Again, this is quite an inefficient way to do the job.)
Here's a more complete example of array calcs in use. Suppose we want to analyze results from a series of edge scans to find the conditions that produce the sharpest edge. Lacking any hardware, we'll also have to make fake data to analyze. We'll use three aCalcout records:
aCalc1
to compute artificial edgescan data,
aCalc2
to take the derivative of that data,
aCalc3
to compute the FWHM of the derivative.
Here are field values that do the job:
aCalc1.CALC = "tanh((ixa)/b)+c*arndm" aCalc1.A = <edge position> aCalc1.B = <edge width control> aCalc1.C = <amount of noise added to data> aCalc1.OUT = "aCalc2.AA PP" aCalc2.CALC = "nderiv(aa,20)" aCalc2.OUT = "aCalc3.AA PP" aCalc3.CALC = "fwhm(aa)"
Every Time  write output every time record is processed. 
On Change  write output every time VAL changes, i.e., every time the result of the expression changes. 
When Zero  when record is processed, write output if VAL is zero. 
When Nonzero  when record is processed, write output if VAL is nonzero. 
Transition to Zero  when record is processed, write output only if VAL is zero and last value was nonzero. 
Transition to Nonzero  when record is processed, write output only if VAL is nonzero and last value was zero. 
Never  Don't write output ever. 
The DOPT field determines what data is written to the output link when the output is executed. The field is a menu field with two options: Use CALC or Use OCAL. If Use CALC is specified, when the record writes its output it will write the result of the expression in the CALC field, that is, it will write the value of the VAL [AVAL] field to a scalar [array] destination. If Use OCAL is specified, the record will instead write the result of the expression in the OCAL field, which result is contained in the OVAL field (array result in the OAV field). The OCAL field is exactly analogous to the CALC field and has the same functionality: it can contain an expression which is evaluated at runtime. Thus, if necessary, the record can use the result of the CALC expression to determine if data should be written and can use the result of the OCAL expression as the data to write.
If the OEVT field specifies a nonzero integer and the condition in the
OOPT field is met, the record will post a corresponding event. If the ODLY field
is nonzero, the record pauses for the specified number of seconds before
executing the OUT link or posting the output event. During this waiting period
the record is "active" and will not be processed again until the wait is over.
The field DLYA is equal to 1 during the delay period. The resolution of the
delay entry is one clock tick, where the clock frequency is defined elsewhere
(see epicsThreadSleepQuantum()
in the EPICS Application Developer's Guide).
The IVOA field specifies what action to take with the OUT link if the aCalcout record enters an INVALID alarm status. The options are Continue normally, Don't drive outputs, and Set output to IVOV. If the IVOA field is Set output to IVOV, the data entered into the IVOV field is written to the OUT link if the record alarm severity is INVALID.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

OUT  Output Specification  OUTLINK  Yes  0  Yes  Yes  N/A  No 
OOPT  Output Execute Option  Menu  Yes  0  Yes  Yes  No  No 
DOPT  Output Data Option  Menu  Yes  0  Yes  Yes  No  No 
OCAL  Output Calculation  STRING[36]  Yes  Null  Yes  Yes  No  No 
OVAL  Output Value  DOUBLE  No  0  Yes  Yes  Yes  No 
OEVT  Event To Issue  SHORT  Yes  0  Yes  Yes  No  No 
ODLY  Output Execution Delay  FLOAT  Yes  0  Yes  Yes  No  No 
IVOV  Invalid Output Action  Menu  Yes  0  Yes  Yes  No  No 
IVOA  Invalid Output Value  DOUBLE  Yes  0  Yes  Yes  No  No 
OAV  Output array value  DOUBLE ARRAY  NO  0  Yes  Yes  Yes  No 
WAIT  Wait for completion?  Menu  Yes  "NoWait"  Yes  Yes  Yes  No 
The aCalcout record uses device support to write to the
OUT
link. Soft device supplied with the record is selected with
the .dbd specification
field(DTYP,"Soft Channel")This device support uses the record's
WAIT
field to determine
whether to wait for completion of processing initiated by the OUT
link before causing the record to execute its forward link. The mechanism by
which this waiting for completion is performed requires that the
OUT
link have the attribute CA
 i.e., the link text
looks something like
xxx:record.field CA NMS
Currently, the record does not try to ensure that WAIT
and
OUT
are compatibly configured. If WAIT
== "Wait",
but the link looks like
xxx:record.field PP NMS
for example, then the record will not wait for completion before executing its forward link.
The EGU field contains a string of up to 16 characters which is supplied by the user and which describes the values being operated upon. The string is retrieved whenever the routine get_units is called. The EGU string is solely for an operator's sake and does not have to be used.
The HOPR and LOPR fields only refer to the limits of the VAL, HIHI, HIGH, LOW, and LOLO fields. PREC controls the precision of the VAL field.
The INAVINLV and IAAVILLV fields indicate the status of the link to the PVs specified in the INPAINPL and INAAINLL fields, respectively. The fields can have three possible values:
Ext PV NC  the PV wasn't found on this IOC and a Channel Access link hasn't been established. 
Ext PV OK  the PV wasn't found on this IOC and a Channel Access link has been established. 
Local PV  the PV was found on this IOC. 
Constant  the corresponding link field is a constant. 
The OUTV field indicates the status of the OUT link. It has the same possible values as the INAVINLV fields.
The CLCV and OLCV fields indicate the validity of the expression in the CALC and OCAL fields, respectively. If the expression is invalid, the field is set to one.
The DLYA field is set to one during the delay interval specified in ODLY.
See the EPICS Record Reference Manual, for more on the record name (NAME) and description (DESC) fields.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

EGU  Engineering Units  STRING [16]  Yes  Null  Yes  Yes  No  No 
PREC  Display Precision  SHORT  Yes  0  Yes  Yes  No  No 
HOPR  High Operating Range  FLOAT  Yes  0  Yes  Yes  No  No 
LOPR  Low Operating Range  FLOAT  Yes  0  Yes  Yes  No  No 
INAV  Link Status of INPA  Menu  No  1  Yes  No  No  No 
INBV  Link Status of INPB  Menu  No  1  Yes  No  No  No 
...  ...  ...  ...  ...  ...  ...  ...  ... 
INLV  Link Status of INPL  Menu  No  1  Yes  No  No  No 
OUTV  OUT PV Status  Menu  No  0  Yes  No  No  No 
CLCV  CALC Valid  LONG  No  0  Yes  Yes  No  No 
OCLV  OCAL Valid  LONG  No  0  Yes  Yes  No  No 
DLYA  Output Delay Active  USHORT  No  0  Yes  No  No  No 
NAME  Record Name  STRING [29]  Yes  0  Yes  No  No  No 
DESC  Description  STRING [29]  Yes  Null  Yes  Yes  No  No 
IAAV  Link Status of INAA  Menu  No  1  Yes  No  No  No 
IBBV  Link Status of INBB  Menu  No  1  Yes  No  No  No 
...  ...  ...  ...  ...  ...  ...  ...  ... 
ILLV  Link Status of INLL  Menu  No  1  Yes  No  No  No 
The following alarm parameters which are configured by the user define the limit alarms for the VAL field and the severity corresponding to those conditions.
The HYST field defines an alarm deadband for each limit. See the EPICS Record Reference Manual for a complete explanation of alarms and these fields.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

HIHI  Hihi Alarm Limit  FLOAT  Yes  0  Yes  Yes  No  Yes 
HIGH  High Alarm Limit  FLOAT  Yes  0  Yes  Yes  No  Yes 
LOW  Low Alarm Limit  FLOAT  Yes  0  Yes  Yes  No  Yes 
LOLO  Lolo Alarm Limit  FLOAT  Yes  0  Yes  Yes  No  Yes 
HHSV  Severity for a Hihi Alarm  Menu  Yes  0  Yes  Yes  No  Yes 
HSV  Severity for a High Alarm  Menu  Yes  0  Yes  Yes  No  Yes 
LSV  Severity for a Low Alarm  Menu  Yes  0  Yes  Yes  No  Yes 
LLSV  Severity for a Lolo Alarm  Menu  Yes  0  Yes  Yes  No  Yes 
HYST  Alarm Deadband  DOUBLE  Yes  0  Yes  Yes  No  No 
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

ADEL  Archive Deadband  DOUBLE  Yes  0  Yes  Yes  No  No 
MDEL  Monitor, i.e. value change, Deadband  DOUBLE  Yes  0  Yes  Yes  No  No 
The LALM field is used to implement the hysteresis factor for the alarm limits.
The LALL fields are used to decide when to trigger monitors for the corresponding fields. For instance, if LA does not equal the value for A, monitors for A are triggered. The MLST and MLST fields are used in the same manner for the VAL field.
Field  Summary  Type  DCT  Initial  Access  Modify  Rec Proc Monitor  PP 

LALM  Last Alarmed Value  DOUBLE  No  0  Yes  No  No  No 
ALST  Archive Last Value  DOUBLE  No  0  Yes  No  No  No 
MLST  Monitor Last Value  DOUBLE  No  0  Yes  No  No  No 
LA  Previous Input Value for A  DOUBLE  No  0  Yes  No  No  No 
LB  Previous Input Value for B  DOUBLE  No  0  Yes  No  No  No 
...  ...  ...  ...  ...  ...  ...  ...  ... 
LL  Previous Input Value for A  DOUBLE  No  0  Yes  No  No  No 
LAA  Previous Input Value for AA  DOUBLE ARRAY  No  0  Yes  No  No  No 
LBB  Previous Input Value for BB  DOUBLE ARRAY  No  0  Yes  No  No  No 
...  ...  ...  ...  ...  ...  ...  ...  ... 
LLL  Previous Input Value for LL  DOUBLE ARRAY  No  0  Yes  No  No  No 
A routine postfix is called to convert the infix expression in CALC and OCAL to reverse polish notation. The result is stored in RPCL and ORPC, respectively.
upper_alarm_limit = HIHI
upper_warning_limit = HIGH
lower_warning_limit = LOW
lower_alarm_limit = LOLO