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.

OperatorDescriptionExample
+The sum of two valuesex[0] + ex[1]
-The subtraction of one value from anotherex[0] - ex[1]
*The multiplication of two valuesex[0] * ex[1]
/The division of one value by anotherex[0] / ex[1]
%The modulus of one value by anotherex[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)
LogicDescriptionExample
>Greater thanex[0] > ex[0]
>=Greater than or equalex[0] >= 2.5
<Smaller thanex[0] < 3.4
<=Smaller than or equalex[0] <= ex[1]
==Equalex[0] == ex[1]
<>Not equalex[0] != ex[1]
!=Not equalex[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.