The Calculation Server, or Calc Server, is a useful tool for adding additional context to your historical tag data. System administrators use the the Calc Server to create new calculated tags that are derived from a series of expressions.
These expressions can be created using various tag values from both the historical archive or from Virtual Views, as well as use any metadata associated with those tag records. In addition to basic NCalc functions, OPC Foundation aggregates as well as custom Canary functions are provided.
Based on the configuration of the calculated tag, new calculated values can be scheduled to occur periodically (e.g., every 30 seconds, every 4 hours, once per day, etc.) or when one or more tags contained within the expression(s) experience a value change.
Once a calculated tag has been defined, it can then be written to the Canary Historian, either as a single tag or as part of an asset type. When applied to an asset type, all associated asset instances will receive the new calculated tag.
The Calculation Server writes tags to the Historian using the Sender/Receiver service, thus following the same data flow as tags that are being logged using Canary Data Collectors.
Additionally, the tag may be backfilled using the existing historical records in the Canary Historian. The action of backfilling provides immediate validation of the calculation and has proven to be very useful.
There are many different ways you can use calculated tags and many types of calculations. Here are a few common calculation types.
Completes a data transformation of a single tag value. For instance, converting a temperature from Celsius to Fahrenheit.
Using data from more than one tag to create a new tag value; such as using two pressure tags to calculate an average pressure.
Creates an output based on the condition of another tag or tag group using logic statements. This could be as simple as 'If the line is running and temperature is less than 212, output a FALSE, otherwise output TRUE'. Multiple nested logic statements may be used, as may other tag transformations and/or calculations.
Multiple functions are provided that allow calculations to be made that output maximums, minimums, means, standard deviations, variances, and other standard statistical calculations. These calculations can be run over specific time frames and have many configurable settings.
Allows for a value to be output that determines the amount of time that has passed since or until a point in time. This output can then be used in other calculations. For instance, if the shift started when the process status tag equaled TRUE, you can calculate the amount of time since the shift started and then use that as a variable in other calculations.
The functions available within the Calculation Server can be categorized in three different ways:
- Standard OPC Foundation aggregates
- NCALC functions and operators
- Custom functions developed by Canary
For most aggregates, the expression syntax is simply:
Duration can be expressed in various ways using the each of the following syntax:
- Now - represents current time; used often for rolling calculations 'Now-1h' or 'Now-5 minutes'
- Second(s) or s - typically used to represent a period of time '30s' or '30 seconds'
- Minute(s) or m - typically used to represent a period of time '5m' or '30 minutes'
- Hour(s) or h - typically used to represent a period of time '8h' or '1 hour'
- Day(s) or d - typically used to represent a period of time '1d' or '7 days'
- Today - midnight of the current day; can be combined with other syntax 'Today+8h' arrives at 08:00:00 of the current day
- Yesterday - midnight of the previous day; can be combined with other syntax 'Yesterday+10h' arrives at 10:00:00 of the previous day
- Day of Week – midnight of the day specified; ‘Monday’ or ‘Saturday’; can be combined with other syntax 'Monday+8h' arrives at the previous Monday at 08:00:00
- Week(s) - midnight on Sunday of current week; can be combined with other syntax 'Week-1d' would shift to midnight of Saturday
- Month(s) - midnight of the first day of the current month; can be combined with other syntax 'Today-3months' arrives at today's day of the month shifted three months prior
- Year(s) - midnight of the first day of the current year; can be combined with other syntax 'Year-3 months + 1h' arrives 01:00:00 on October 1st of the previous year
- Date – a precise date; ‘3/1/2021’ or ‘February 21, 2021’
- Time – a precise time; ‘3/1/2021 10:00AM’ or ’10:00AM’
- Variable - time can be based off the variable of another expression
For aggregates with a unique syntax, that syntax is listed in the 'Additional Information' section.
|OPC Standard Aggregates||Basic Definition||Additional Information|
|Count||Retrieves the number of raw values over the interval.||A user may want to know how many values have been returned in a given period of time as opposed to what the values were.|
|CountInStateZero/NonZero||Retrieves the number of times a Boolean or numeric
value was in a zero or nonzero state.
|Can be used to track how many times a piece of equipment was turned on or off.|
|DeltaBounds||Retrieves the difference between the StartBound
and EndBound value in a given interval.
|This is a good aggregate for tags that return progressively increasing/decreasing data.|
|DurationBad||Retrieves the total duration of time in the interval during which the data outputs continuous bad quality scores without interruption.||The DurationGood and DurationBad tags save users from having to trend their data to find out how long field devices ran without issue. These two aggregates can be useful when troubleshooting field devices. Returns a value in milliseconds.|
|DurationGood||Retrieves the total duration of time in the interval during which the data outputs continuous good quality scores without interruption.||The DurationGood and DurationBad tags save users from having to trend their data to find out how long field devices ran without issue. These two aggregates can be useful when troubleshooting field devices. Returns a value in milliseconds.|
|DurationInStateZero/NonZero||Retrieves the time a Boolean or numeric was in a
zero or nonzero state using Simple Bounding Values.
|Returns a value in milliseconds.|
|EndBound||EndBound - Retrieves the last value in the interval using Simple Bounding Values.||The last value in the interval can be used in the DeltaBound equation to determine the difference between the last and first values recorded to understand the 'spread' of the data.|
|IEEERemainder||Returns the remainder resulting from the division of a specified number by another specified number||The IEEE prefix of the function name refers to the technical standard for floating point arithmetic established in 1985 by the Institute of Electronic and Electrical (IEEE) engineers.
|Interpolative||At the beginning of each interval, retrieve the calculated values from the data points on either side of the requested timestamp.||This aggregate can take an unevenly spaced set of raw values and approximate that data at regular
|Max||Returns the larger of two specified numbers||This aggregate is especially helpful when comparing expressions, the end value of an expression can be represented by a variable. Two variables can be entered for the Max aggregate.
|Max2||Returns the larger of two specified numbers using Simple Bounding Values.||The maximum value of an interval can be a good indicator of Asset health in some situations.|
|Minimum||Returns the larger of two specified numbers||This aggregate is especially helpful when comparing expressions, the end value of an expression can be represented by a variable. Two variables can be entered for the Min aggregate.
|Minimum2||Retrieves the minimum value in the interval including the Simple Bounding values||The minimum value of an interval can be a good indicator of Asset health in some situations.|
|NumberOfTransitions||Retrieves the number of changes between zero and non-zero that a Boolean or numeric value experienced in the interval||This can be useful for determining when a value went from zero to a nonzero number, it is useful to track the activity or lackthereof of certain processes.|
|PercentBad||Retrieves the percentage of data (0 - 100) in the interval which has a Bad status code.||This function tells the user how much of the data from the specified interval can be trusted. This can be used with the WorstQuality2 aggregate to find out how untrustworthy the data is.|
|PercentGood||Retrieves the percentage of data (0 - 100) in the interval which has a Good status code.||This function tells the user how trustworthy a batch of data is.|
|Range2||Returns the difference between the Minimum2 and Maximum2 values.||This function is useful for finding out how spread apart the data is. In contrast to the Range function, the Range2 function finds the range of Simple Bounding Values as opposed to interpolated values.|
|StandardDeviationPopulation / Sample||Retrieves the standard deviation for the interval for a complete population (n) which includes Simple Bounding values||Standard deviation is used to measure the dispersion of data values in a given interval. This is for the statistical analysis of all values in an interval whereas StandardDeviationSample calculates only a portion of the data in an interval.|
|StartBound||StartBound - Retrieves the first value in the interval using Simple Bounding values.||The first value in the interval can be used in the DeltaBound
equation to determine the difference between the last and first values recorded to understand the 'spread' of the data.
|TimeAverage2||Retrieves the time weighted average data over the interval using Simple Bounding values.||The TimeAverage2 aggregate is different from the original TimeAverage because it calculates an average of raw data values as opposed to interpolated values.|
|Total2, TotalPerMinute, TotalPerHour, TotalPer24Hours||Retrieves the total (time integral in seconds/minutes/hours/days) of the data over the interval using Simple Bounding values||Total2 = TimeAverage2 x ProcessingInterval of good data in seconds. The ProcessingInterval is the timespan for which derived values are produced based on a specified Aggregate.|
|VariancePopulation||Retrieve the variance for the interval as calculated by the StandardDeviationPopulation which includes Simple Bounding values.||This function is useful for finding out how spread apart the data is.|
|VarianceSample||Retrieves the variance for the interval as calculated by the StandardDeviationSample||Variance is the average squared deviation from the mean.
This aggregate is applied to the values returned by
|WorstQuality2||Retrieves the worst status code of data in the interval including the Simple Bounding values||The usefulness of this aggregate depends on the capabilities of the OPC Server, some OPC Servers are capable of returning nuanced and precise Bad Quality values that yield important diagnostic information while others only give a simple Bad Quality value.|
Standard NCalc functions that are also used in popular software like Microsoft Excel.
|Microsoft Functions||Basic Definition||Additional Information|
|Absolute Value||Returns the absolute value of a specified number.||This aggregate is useful to add to expressions where the distance from zero is more important than the real number. This can be used in more complicated expressions to avoid dealing with negative numbers.|
||Evaluates an array of expressions and returns true if all expressions are true.||To use a real use case as an example, this aggregate can be used with the 'If' function and applied to several diagnostic tags to easily monitor the state of many Assets. With this Aggregate, users no longer have to comb through each Asset to look up the info for each diagnostic tag and decipher what that value means. This saves time and energy.
SYNTAX: And([tag1] = 1, [tag2] = 1, [tagN} = 1)
|Average||Retrieve the average value of the data over the interval.||The most basic measurement that is a building block of much more complicated expressions. An average or mean gives a the general overview of many data points.|
|Ceiling||Returns the smallest integer greater to or equal than the specified number.||Also called rounding towards positive infinity, this function is useful for rounding decimal numbers up to the next integer away from zero. Ceiling is similar to but not to be confused with truncate or floor.|
|Floor||Retrieves the largest integer less than or equal to the specified number||Sometimes called rounding towards negative infinity,
this is a way to get rid of decimal places by rounding
down. Not to be confused with truncating, the floor
function rounds towards negative infinity.
|Functions of Trigonometry||Returns the cos, sin, tan, abs, and||Functions such as cos, sine, tan, and abs are trigonometric functions that will not be explained here.|
|If||Returns a value based on a condition||The 'if' statement is an extremely versatile aggregate.
SYNTAX: if(3 % 2 = 1, 'value is true', 'value is false')
|In||Returns whether an element is in a set of values.
in(element, x value, y value, z value,...)
|This can be used to determine whether a value equals one of several values. So if you had a tag '[tag1]' you could it to find out if it equals one or more specified numbers For example: "in([tag1], 5, 7, 10, 15)" . This expression will return true if [tag1] equals any of 5, 7, 10, or 15. While similar to the 'Switch' function, this is different because it returns a true or false instead of a user-defined string or value.
SYNTAX: in(1 + 1, 1, 2, 3)
|Log and Log10||Returns the logarithm of the specified base.||Logarithmic expressions are used for advanced statistical analysis.|
|Or||Evaluates an Array of values and returns true if at least one is true.
||The OR function is a logical function to test multiple conditions at the same time. OR returns either TRUE or FALSE. For example, to test A1 for either "x" or "y", use =OR(A1="x",A1="y"). Its useful for checking the validity of certain things.
SYNTAX: Or([tag1] = 1, [tag2] = 1, [tagN] = 1)
|Sqrt||Returns the square root of a specified number||The square root of a tag value is valuable for more
advanced statistical functions such as variance.
|Switch||Select an output value based on which match contains the same value as the compare key.||The Switch aggregate can be used to convert status codes into a human readable format. Instead of reading the value and resorting to the status codex to find the meaning of the value, the switch aggregate will return a string that explains what is happening.
SYNTAX: Switch(compareKey, match1, value1 [,match2,value2]... [,defaultValue])
Any number of matches and values are allowed, but each match needs a value and vice-versa. For each of the parameters in the function, any expression is allowed. You can use constant values, aggregates, variables, tag values, etc.
Example: "Switch ([localhost.Testing.Tag1], 1,[localhost.Testing.Tag2], var1 + 2, [localhost.Testing.Tag3], [localhost.Testing.Tag4])"
Where Tag2 is the output when Tag1 is equal to 1, Tag 3 is the output when Tag1 is equal to var1 + 2, and Tag4 is the default value that is output when none of the other conditions are met.
|Truncate||Calculates the integral part of a number||This function discards the long decimal values of
a number, leaving only the whole number.
Sometimes the additional decimal precision is not
|Round||Rounds a value to the nearest integer or specified number of decimal places||This aggregate has unique syntax as well.
SYNTAX: Round('x', Number Of Decimal Places to Round to ')
For Example: Round('3.222','3') Output: '3'
|Pow||Returns a number raised to the specified power.||The term 'power' refers to how many times a number is multiplied by itself.
SYNTAX: Pow(3,2) Output = 9
The following have been built by Canary to address typical historian based analytics.
|Canary Functions||Basic Definition||Additional Information|
|AssetInstanceCount||Returns the total number of asset instances of the specified type under a source path.||This tag keeps the admin from tediously counting what could be dozens of assets. This aggregate is helpful for operations that are constantly taking Assets online and offline.
SYNTAX: AssetInstanceCount(string sourcePath, string assetType)
|DeltaTotalCount||Retrieves the total delta (change) of values for an accumulation tag that resets periodically.||The DeltaTotalCount aggregate returns the total positive increase of the value over an interval, ignoring any decreases. Some tags increase, then decrease, then increase some more, then decrease. The DeltaTotalCount reveals the total increase across a specified time period.|
|DurationSinceLastTVQ||Retrieve the time in milliseconds since a tag has received an update.||This aggregate returns the time since the last updated value, not the last updated timestamp. This can be used to indicate whether the settings of a logging session must be changed for a specific tag.
SYNTAX: DurationSinceLastTVQ (string tagPath[, bool ignoreBadValueChanges])
If ignoreBadValueChanges is set to true, it changes the behavior of the function so that bad or NoData quality TVQs do not reset the duration and instead only set the output quality to uncertain. Additionally, it keeps the function from resetting the duration because of an uncertain quality.
|NoOutput||Does not output tag values.||The NoOutput function can be used in conjunction with an 'If' function to return nothing when another tag returns a specific value. For example, a user could write the value of Tag2 only when Tag1 is true. When Tag1 is false it won't output anything, not even a NoData TVQ, so if you look at it in Axiom it will look like a flat line.|
|Property||Retrieves the value of a tag property.||The only function that deals with
Metadata properties, this returns the value entered for the specified property of tag. Metadata values can be changed within a tag's logging session. This will return text and numbers.
SYNTAX: Property(string tagName, string propertyName)
|Quality||Retrieves the latest quality for a tag.||The value of this tag depends on the capabilities of the OPC Server or data source that is writing data to the tag.
SYNTAX: Quality(string tagName)
|ResettingAnchoredInterval||Calculates an aggregate with an interval that continues to grow over a length of time, and then resets after a certain duration.||This function is typically used in conjunction with others. A target interval is specified, and as the calculation runs the actual interval that is used to calculate the aggregate continually grows until it reaches the target interval. At that point the aggregate interval resets back to zero and then continues to grow until it reaches the target again and so on.
SYNTAX: ResettingAnchoredInterval(string aggregateName, string tagName, string resetInterval, [string resetOffset])
|Rollup||Calculates a sum, count, average, or min/max of all like tags in every Asset. Unlike normal aggregates, the Rollup interfaces with the Virtual Views service.||Typically, Assets within a Virtual have the same type of tags. For example, every Pump Asset in a View may have a speed tag. A rollup can be used in conjunction with other aggregates to create a calculated tag that yields information about the state/health of many Assets.
SYNTAX: Rollup (String sourcePath, string operation, string assetType, string rollupTag)
Operation: SUM, COUNT, AVERAGE, MINIMUM,
|SetOutputQuality||Sets the output tag value quality.||This is useful is overwrite the default quality code set by some OPC Servers. Furthermore, some functions require the 'Good' quality to work properly, such as TimeAverage2. SetOutputQuality can guarantee that tags prone to the occasional uncertain or bad quality, can still be compatible with other functions in a multi-step expression.
For most use cases, the quality will be set to 'Good'.
|TagIfExists||Returns the value of the tag if it exists, otherwise returns the fallback value.||This aggregate is useful to when dealing with many Assets and the Admin does not remember if a particular tag resides in many Assets or just one. This is helpful when creating more complicated expressions that require many tags. Use the TagIfExists to allow the calculation to run without error even if an incorrect or nonexistent tag name was entered.
SYNTAX: TagIfExists (string tagName, fallbackValue)
fallbackValue can be a number or a string but can't be a tag, an aggregate, or a variable.