Item type: Function item - C# calculator
This Item is a calculated value based on existing items in Hive. The calculation uses an expression with C# syntax to perform a calculation based on inputs from external Items.
Make sure to select C# for the function item Calculator attribute.
Looking for the Advanced content?
Calculation
The Expression is the body of a method with the following definition:
VQT Compute(VQT[] ex, VQT[][] arr)
{
//Your expression will be placed here by the framework
}
ex is an array of the external items. The order is the same as the order of the external items in Hive.
arr is an array of arrays of the external items that are a part of arrays. These arrays are defined on the Expressions attribute. (See more on arrays below)
The parameters ex and arr are variants of type VQT with Value, Quality and Timestamp:
public readonly struct VQT
{
public object Value // The value of the item
//One of the primitive types: float, double, int, short, byte, sbyte, decimal, uint, ulong, ushort, long, bool
public OpcDaQuality Quality // OPC DA quality. enum : ushort. OPC DA qualities are 2 bytes
public ulong Timestamp // FILETIME
public double DblVal //Value as double, can be used if you know the value is of type double or it's ok to convert to double
public int IntVal // Value as int, can be used if you know the value is of type int
public bool BoolVal // Value as bool, can be used if you know the value is of type bool
}
The datatype of the variants Value is the same as in Hive.
The C# function items has built in operators for these variants, so they can be used as if they are normal primitive values. I.e. the following expression adds the first 2 items in the external items array:
return ex[0] + ex[1];
You can even omit the 'return' and the ';' if you have a oneliner and just type:
ex[0] + ex[1]
The expression can include various operators, functions, loops and logic operators. The item type of the returned value is usually the same as the inputs. A lot of the built in methods will return an 8 byte float.
In most cases when using expressions of kind All*, e.g. AllGoodCount, you will most likely need to have the module property ExtItem pass-through quality is set to Any quality.
Otherwise, one or more external item having a bad quality will prevent the Function item from being evaluated completely.
See also: ExtItem pass-through quality.
Operator | Description | Example |
---|---|---|
+ | The sum of two values | ex[0] + ex[1] |
- | The subtraction of one value from another | ex[0] - ex[1] |
* | The multiplication of two values | ex[0] * ex[1] |
/ | The division of one value by another | ex[0] / ex[1] |
% | The modulus of one value by another | ex[0] % ex[1] |
Function | Description | Example | Item Type |
---|---|---|---|
Abs | The absolute value | Abs(ex[0]) | 8 byte float |
Sin | The sine of a value, in radians | Sin(ex[0]) | 8 byte float |
Asin |
Returns the angle, θ, measured in radians, such that -π/2 ≤θ≤π/2 . The argument is a number must be greater than or equal to -1, but less than or equal to 1
Remarks: A positive return value represents a counterclockwise angle from the x-axis; a negative return value represents a clockwise angle. Multiply the return value by 180/Math.PI to convert from radians to degrees |
Asin(ex[0]) | 8 byte float |
Sinh |
The hyperbolic sine of value. If value is equal to NegativeInfinity. The parameter is an angle, measured in radians.
Remarks: The angle, value, must be in radians. Multiply by Math.PI/180 to convert degrees to radians. |
Sinh(ex[0]) | 8 byte float |
Asinh | Returns the angle whose hyperbolic sine is the specified number | Asinh(ex[0]) | 8 byte float |
Cos | The cosine of a value, in radians | Cos(ex[0]) | 8 byte float |
Acos |
Returns the angle, θ, measured in radians, such that 0 ≤θ≤π. The argument is a number must be greater than or equal to -1, but less than or equal to 1
Remarks: Multiply the return value by 180/Math.PI to convert from radians to degrees. |
Acos(ex[0]) | 8 byte float |
Cosh |
The hyperbolic cosine of value. If value is equal to NegativeInfinity or PositiveInfinity, PositiveInfinity is returned. If value is equal to NaN, NaN is returned. The parameter is an angle, measured in radians. Remarks: The angle, value, must be in radians. Multiply by Math.PI/180 to convert degrees to radians. |
Cosh(ex[0]) | 8 byte float |
Acosh | Returns the angle whose hyperbolic cosine is the specified number | Acosh(ex[0]) | 8 byte float |
Tan | The tangent of a value, in radians | Tan(ex[0]) | 8 byte float |
Atan |
Returns the angle, θ, measured in radians, such that -π/2 ≤θ≤π/2. -or- NaN if d equals NaN, -π/2 rounded to double precision (-1.5707963267949) if d equals NegativeInfinity, or π/2 rounded to double precision (1.5707963267949) if d equals PositiveInfinity.
Remarks: A positive return value represents a counterclockwise angle from the x-axis; a negative return value represents a clockwise angle. Multiply the return value by 180/Math.PI to convert from radians to degrees |
Atan(ex[0]) | 8 byte float |
Tanh |
The hyperbolic tangent of value. If value is equal to NegativeInfinity, this method returns -1. If value is equal to PositiveInfinity, this method returns 1. If value is equal to NaN, this method returns NaN. The parameter is an angle, measured in radians. Remarks: The angle, value, must be in radians. Multiply by Math.PI/180 to convert degrees to radians. |
Tanh(ex[0]) | 8 byte float |
Atanh | Returns the angle whose hyperbolic tangent is the specified number | Atanh(ex[0]) | 8 byte float |
Exp | Exponent of an expression | Exp(ex[0]) | 8 byte float |
Floor | Rounds the value to nearest integer towards minus infinity | Floor(ex[0]) | 8 byte float |
Ceiling | Returns the smallest integral value that is greater than or equal to the specified | Ceiling(ex[0]) | 8 byte float |
Log | The natural (base e) logarithm of a specified number | Log(ex[0]) | 8 byte float |
Neg | Invert sign | Neg(ex[0]) | 8 byte float |
Bit | The bit value at specified index | Bit(ex[0], 3) (returns 0 or 1) |
int32 |
Pow | The first value raised to the power of the second value | Pow(ex[0] , 2) | 8 byte float |
Sqrt | The square root of a value | Sqrt(ex[0]) | 8 byte float |
Max |
Return max value of an array of values |
Max(ex) | 8 byte float |
Max (scalars) |
Return max value of two values |
Max(ex[0], ex[1]) | 8 byte float |
Min |
Return min value of an array of values |
Min(ex) | 8 byte float |
Min (scalars) |
Return min value of two values. |
Min(ex[0],ex[1]) | 8 byte float |
AllGoodMin |
Return the minimum of an array that have good quality. If no good value exists, then double.MaxValue and bad quality is returned. |
AllGoodMin(ex) | 8 byte float |
Avg |
Return the average of an array of values Quality will be the worst quality. |
Avg(ex) | 8 byte float |
AllGoodAvg |
Return the average of an array that have good quality. If no good value exists, then 0.0 and bad quality is returned. |
AllGoodAvg(ex) | 8 byte float |
AllGoodMax |
Return the maximum of an array that have good quality. If no good value exists, then double.MinValue and bad quality is returned. |
AllGoodMax(ex) | 8 byte float |
Median |
Return the median of an array |
Median(ex) | 8 byte float |
AllGoodMed |
Return the median of an array that have good quality. If no good value exists, then NAN and bad quality is returned. |
AllGoodMed(ex) | 8 byte float |
Var |
Return the variance of an array. Normalized with N, this provides the square root of the second moment around the mean |
Var(ex) | 8 byte float |
AllGoodVar |
Return the variance of the elements in an array that have good quality. Normalized with N, this provides the square root of the second moment around the mean If no good value exists, then NAN and bad quality is returned. |
AllGoodVar(ex) | 8 byte float |
Std |
Return the standard deviation of an array. Normalized with N, this provides the square root of the second moment around the mean If no good value exists, then NAN and bad quality is returned. |
Std(ex) | 8 byte float |
AllGoodStd |
Return the standard diviation of all external items that have good quality. If no good value exists, then NAN and bad quality is returned. |
AllGoodStd(ex) | 8 byte float |
AllCount |
Return the size of an array. |
AllCount(ex) | int |
AllGoodCount |
Return the number of all external items that have good quality. |
AllGoodCount(ex) | int |
Sum |
Return the sum of an array. Quality will be the worst quality. |
Sum(ex) | 8 byte float |
AllGoodSum |
Return the sum of all external items that have good quality. If no good value exists, 0.0 and bad quality is returned. |
AllGoodSum(ex) | 8 byte float |
AllGoodGreatherThanAvg |
Return the the average of all good values greather than x. If no good value exists, then NAN and bad quality is returned. |
AllGoodGreatherThanAvg(ex, x) | 8 byte float |
AllGoodLessThanAvg |
Return the the average of all good values less than x. If no good value exists, then NAN and bad quality is returned. |
AllGoodLessThanAvg(ex, limit) | 8 byte float |
Delay |
Delay a signal a number of steps (number of external item transfers). Maximum number of delays is 3600. |
Delay(5, ex[0]) This will delay the first external item 5 steps. |
Same as input |
LowPassFilter |
Will lowpass filter a signal with the specified time constant. Only inputs with quality Good will be used in the filter. If input is not Good, output will have Uncertain quality |
LowPassFilter(60.0, ex[0]) The time constant here is 60 seconds. dT in the filter is the time difference between current and previous external item timestamp. |
8 byte float |
MovingAvg |
Moving average for a specified window size. Computed on every external item transfer. Maximum window size is 3600. Only inputs with quality Good will be used in the algoritm. If some inputs are not Good, output will have Uncertain quality. If all inputs are not Good, output will be Bad |
MovingAvg(5, ex[0]) The window size here is 5. |
8 byte float |
MovingTimeAvg |
Moving average for a period of time (window). Computed on every external item transfer. Maximum window size is 3600 seconds. Only inputs with quality Good will be used in the algoritm. If some inputs are not Good, output will have Uncertain quality. If all inputs are not Good, output will be Bad. Tip: If your intension is to low pass filter a signal, use the LowPassFilter method instead, it is much more efficient. |
MovingTimeAvg(5.0, ex[0]) The window size here is 5 seconds. |
8 byte float |
Hysteresis |
Hysteresis for a specified deadband. The output value will not change before the input value moves outside of the deadband. The timestamp will change even if the value does not |
Hysteresis(2, ex[0]) The deadband here is 2. Example of inputs/outputs: Input 1 output 1 Input 2 output 1 Input 3 output 3 Input 4 output 4 Input 5 output 5 Input 4 output 5 Input 3 output 5 Input 2 output 2 Input 1 output 1 Input 0 output 0 |
Same as input |
PosFlankDelay |
For a boolean input signal, any positive flank (from false to true) will have to stay positive (true) for certain amount of time before the output goes positive (true). NB! This method requires at least one extra external item that changes continuously. The first element in the external item array must be the signal to filter. This is a requirement do to the fact that the external item update mechanism only happens on external item change. |
PosFlankDelay(5.0, ex) The delay period here is 5 seconds. Note that the whole external item array, ex, is used as an argument. |
Boolean |
NegFlankDelay |
For a boolean input signal, any negative flank (from true to false) will have to stay negative (false) for certain amount of time before the output goes negative (false). NB! This method requires at least one extra external item that changes continuously. The first element in the external item array must be the signal to filter. This is a requirement do to the fact that the external item update mechanism only happens on external item change. |
NegFlankDelay(5.0, ex) The delay period here is 5 seconds. Note that the whole external item array, ex, is used as an argument. |
Boolean |
GetDateTime |
The value of this function item is the timestamp, in OLE Automation date format, of the external item (UTC). The datatype of this function item must be Date. |
GetDateTime(ex[0]) | DATE |
GetUnixTime |
The value of this function item is the timestamp, in milliseconds since 1.1.1970, of the external item (UTC). The value is a double including milliseconds as decimals. |
GetUnixTime(ex[0]) | 8 byte float (default) |
Logic | Description | Example |
---|---|---|
> | Greater than | ex[0] > ex[0] |
>= | Greater than or equal | ex[0] >= 2.5 |
< | Smaller than | ex[0] < 3.4 |
<= | Smaller than or equal | ex[0] <= ex[1] |
== | Equal | ex[0] == ex[1] |
<> | Not equal | ex[0] != ex[1] |
!= | Not equal | ex[0] != ex[1] |
! | Not | !( ex[0] > ex[1] ) |
Loops
Standard C# loops can be used in an Expression:
For loop:
for (int i = 0; i < ex.Length; i++)
{
if (ex[i] > 10.0)
return true;
}
While loop:
bool hit = false;
int index = 0;
while(index < ex.Length && !hit)
{
if (ex[index] > 10.0)
hit = true;
index++;
}
return hit;
Array External Items
The external items can be organized into arrays (arr) that enter the Compute method:
VQT Compute(VQT[] ex, VQT[][] arr)
Sometimes it's natural to organize some of the external items into arrays. Example: we have one status item and 3 temperature measurements as inputs, it might be natural to place the temperatures in a separate array, to i.e. compute the average temperature.
By using the Expressions attribute (note that it ends with an s, different attribute from Expression) on the function item, you can organize the external items into arrays. In the example we have 4 external items, say the first three are temperatures and the last is Status. The Expressions attribute then becomes:
[1] ex1, ex2, ex3;
'[1]' means 1 array, consisting of external items ex1, ex2 and ex3. The array content is separated by ';', so two arrays would be:
[2] ex1, ex2; ex3, ex4;
The external items that are in arrays will not be a part of ex parameter. In our example, ex will be 1 long.
if (ex[0] == 0) // Status check, note index is 0 even though status is the forth external item
return 0; // Status indicated error
var tempMean = Avg(arr[0]); // Temp average, the first array (and only, in this case)
if (tempMean > 30.0) // Temp too high
return 3;
return 1; // Ok
Example 1
Expression:
ex[0] + ex[1] + 5.14
Example 2
Expression:
if(ex[1] > 0.0 && ex[2] > 0.0)
return 100.0*1000.0*ex[0]/(ex[1]*ex[2]);
return 0.0;
Example 3
Expression:
if (ex[0] == true) return 3; //Waiting
if (arr[0].Length > 0)
{
if (arr[0].Any(a => a == 4)) return 4; //Leak detected
var tankCount = 0.0;
var tankOkCount = 0.0;
for (int i = 0; i < arr[0].Length; i++)
{
tankCount++;
if (arr[0][i] == 0)
tankOkCount++;
}
if (tankCount == 0.0)
return 0; //Ignore
var tanksProdusingFrac = tankCount > 0.0 ? tankOkCount / tankCount : 0.0;
if (tanksProdusingFrac < 0.9) return 2; //Error
if (tanksProdusingFrac < 1.0) return 1; //Warning
}
return 0;
Specifying a non-existing External Item
If you want to specify a dummy/non-existing external item in the list of external items, you can specify external item(s) named ##DummyExternalItem.
Items having this name will be given special handling inside APIS and will not be used in the calculation.
This is useful when you want to use the same expression for multiple items, but some of the items have different number of external items.
Note that to achieve this, you must apply the configuration by import from a text file. Using the Add items dialog in Apis Management Studio together with File add will also work.
See the Advanced content for more information.