Calculated Channels
Overview
Calculated Channels in Sift enable real-time transformation of time-series sensor data for precise anomaly detection, root cause analysis, and predictive maintenance. Engineers can extract actionable insights by applying expressions defined using CEL (Common Expression Language) directly to raw telemetry streams, known as Channels. This allows you to define custom metrics, derive new signals, or apply logic without modifying the original data. Sift supports the following two types of transformations that work across all supported data types:
- Stateless transformations: Stateless transformations process each data point independently, making them ideal for real-time computations like unit conversions or threshold checks.
- Stateful transformations: Stateful transformations retain context over time, enabling engineers to analyze historical trends, detect gradual system degradation, identify performance shifts, and uncover evolving failure patterns.
- Unlike Rules, which enforce logic and trigger automated actions, Calculated Channels refine raw sensor data for deeper analysis. This distinction allows engineers to identify trends, compare system behaviors, and make data-driven decisions before failures occur.
- Calculated Channels can be created through the UI and API.
Settings
To create a Calculated Channel, you must define its properties (settings), including which Assets it applies to, which Channels it uses, and the logic (expression) it follows. The following table describes each setting available when creating a Calculated Channel:
Field | Required | Description |
---|---|---|
Name | Yes | The display name for the Calculated Channel. Must be between 1 and 253 ASCII characters. |
Description | No | Optional field to describe the purpose or logic behind the Calculated Channel. |
Assets | Yes | Specifies which Assets the Calculated Channel applies to. You can select specific Assets, use a tag filter, or apply it to all Assets. |
Input Channels | Yes | Channels used as inputs in the calculation. Each selected Channel is automatically assigned a shorthand variable (for example, $1, $2) for use in the query expression. |
Query (expression syntax) | Yes | The CEL-based expression that defines the calculation logic. References shorthand variables (for example, $1) assigned to input Channels. |
Units | No | The unit of measurement shown for the result of the calculated Channel (for example, Celsius). |
Expression syntax
Calculated Channels are defined by expressions written in Common Expression Language (CEL). These expressions describe how raw telemetry should be transformed, using logic that is evaluated on each incoming row of data.
An expression can include references to input Channels (for example, $1
), constants, operators, and functions. Expressions may return numeric or string results and are used to compute derived values, apply thresholds, or combine multiple inputs in real time.
This section explains how expressions work in Sift, including how to reference Channels, use timestamps, apply math and logic, and work with built-in and User-defined Functions. Examples are provided using the CreateCalculatedChannel REST API endpoint to illustrate how expressions are structured when programmatically defining a Calculated Channel.
Channel references
When configuring a Calculated Channel, each selected input Channel is automatically assigned a shorthand variable such as $1
, $2
, $3
, and so on, based on the order in which the Channels are chosen in the input Channels field. These variables act as placeholders in the expression editor and can be used to define transformation logic using CEL.
- This example shows how to define a Channel reference using the Sift REST API's CreateCalculatedChannel endpoint. While Calculated Channels can also be created through the UI or gRPC API, this format reflects the REST-specific schema for mapping input Channels to shorthand variables like
$1
. The snippet focuses on thequeryConfiguration
section of the request; other fields such as authorization, metadata, and asset selection are omitted for clarity. - This example defines a Calculated Channel that converts temperature from Celsius to Fahrenheit. The expression uses the shorthand variable
$1
to reference the input ChannelTEMPERATURE.CELSIUS
, and applies the formula$1 * 1.8 + 32
to transform each data point. TheexpressionChannelReferences
field links$1
to the actual input Channel used in the calculation.
Bitfield Channels are not supported as inputs for Calculated Channels.
Current t
timestamp (ms)
When defining the expression of a Calculated Channel, the special variable t
is always available. It represents the timestamp of the current telemetry point, expressed in milliseconds. This can be used in conjunction with functions like previous()
to calculate time-based metrics such as sampling rate.
Below is a focused example of the queryConfiguration
section that computes the time difference between consecutive data points. This example maps $1
to a pressure Channel and calculates the time delta between the current and previous telemetry point. The rest of the request payload is omitted for clarity.
Static scalar values
Calculated Channels support static scalar values such as numbers, strings, and booleans. These constants can be embedded directly in CEL expressions to define fixed thresholds, nominal baselines, or comparison values.
The following example demonstrates how to subtract a static numeric value (100
) from the input Channel $1
within a Calculated Channel expression.
Mathematical operators
Calculated Channels support standard arithmetic (+
, -
, *
, /
), comparison (>
, <
, >=
, <=
, ==
, !=
), boolean (!
, &&
, ||
), and ternary (? :
) operators in CEL expressions. These allow you to define rich, row-wise transformations across telemetry data. The following examples use the CreateCalculatedChannel
REST API endpoint to demonstrate how these operators can be applied.
Arithmetic
You can use arithmetic operators to combine numeric Channels using +
, -
, *
, and /
. For powers and remainders, use the pow()
and mod()
functions respectively. In the example below, the voltage and current input Channels are assigned to $1
and $2
, and multiplied to calculate power.
Boolean and comparison
You can combine multiple logical and comparison operators to define complex conditions. In the example below, two Channels are used: temperature and pressure. Temperature is assigned to $1
, and pressure to $2
. The expression checks whether the temperature is between 20 and 30 degrees Celsius and whether the pressure is between 90 and 110 PSI. If all conditions are met, the result is true
.
Ternary
The ternary operator uses the syntax condition ? option_1 : option_2
to return one of two values based on a boolean condition. In the example below, the temperature Channel is assigned to $1
. The expression checks whether the temperature is greater than 30°C. If the condition is true, it returns High
; otherwise, it returns Normal
.
Combining multiple time series with different timestamps
When an expression involves multiple time series, such as $1 + $2
, Sift must join those series to compute each result. In typical systems, this would require exact timestamp matches between data points, meaning any values without aligned timestamps would be excluded from the calculation.
Sift uses an As Of join strategy to handle timestamp differences. Instead of requiring perfect alignment, it evaluates each unique timestamp across all input Channels and uses the most recent available value from each series as of that point in time. This approach allows expressions to compute meaningful results even when data streams arrive at different rates or with gaps. The example expression below adds the energy usage from two systems, regardless of whether their telemetry points are recorded at the exact same times.
Functions
Calculated Channels support a wide range of functions that can be used in expressions to process and analyze time-series data. These functions allow you to transform raw inputs, evaluate conditions, and compute derived values in real time. They are organized into several categories based on the type of data or operation they target. You can view the full list of available functions directly in the expression editor when creating or editing a Calculated Channel.
Category | Description | Example |
---|---|---|
Math functions | These functions handle numeric calculations including trigonometry, rounding, powers, roots, logarithms, and bitwise operations. They are used to transform or compare numerical input values directly within expressions. | pow($1, 2) |
String functions | These functions allow you to manipulate and evaluate string values. You can check for substrings, match regular expressions, and calculate string length. | contains($1, "error") |
List functions | These functions operate on lists, such as checking whether a list contains a specific value. Useful when working with sets of known values. | contains(["a", "b", "c"], $1) |
Iteration functions | These functions apply an expression conditionally based on a logical test. They are used to include or exclude results based on a dynamic condition. | filter($1, $1 > 0) |
Stateful functions | These functions compute values over time using rolling windows or past data. They are used to calculate moving averages, rates of change, or time-based aggregates. | avg($1, rolling(300)) |
User-defined Functions | These are custom functions defined in your environment. They allow you to reuse complex logic across multiple Calculated Channels. | function($1) |
Other | These functions provide utility behavior such as accessing the current timestamp or converting data types like enum or numeric formats. | t , double(x) , enumKeyValue(x) |
Math functions
These functions handle numeric calculations including trigonometry, rounding, powers, roots, logarithms, and bitwise operations. They are used to transform or compare numerical input values directly within expressions.
Function | Description | Example expression |
---|---|---|
sin(x) | Returns the sine of x (in radians) | sin($1) |
sinh(x) | Returns the hyperbolic sine of x | sinh($1) |
asin(x) | Returns the arcsine of x as an angle in radians | asin($1) |
asinh(x) | Returns the inverse hyperbolic sine of x | asinh($1) |
cos(x) | Returns the cosine of x (in radians) | cos($1) |
cosh(x) | Returns the hyperbolic cosine of x | cosh($1) |
acos(x) | Returns the arccosine of x as an angle in radians | acos($1) |
acosh(x) | Returns the inverse hyperbolic cosine of x | acosh($1) |
tan(x) | Returns the tangent of x (in radians) | tan($1) |
tanh(x) | Returns the hyperbolic tangent of x | tanh($1) |
atan(x) | Returns the arctangent of x as an angle in radians | atan($1) |
atanh(x) | Returns the inverse hyperbolic tangent of x | atanh($1) |
atan2(x, y) | Returns the arctangent of y/x , preserving quadrant | atan2($2, $1) |
abs(x) | Returns the absolute (non-negative) value of x | abs($1) |
ceil(x) | Rounds x up to the nearest whole number | ceil($1) |
floor(x) | Rounds x down to the nearest whole number | floor($1) |
round(x) | Rounds x to the nearest whole number | round($1) |
sqrt(x) | Returns the square root of x | sqrt($1) |
cbrt(x) | Returns the cube root of x | cbrt($1) |
log(x) | Returns the natural logarithm (base e ) of x | log($1) |
log10(x) | Returns the base-10 logarithm of x | log10($1) |
exp(x) | Returns e raised to the power of x | exp($1) |
pow(x, y) | Raises x to the power of y (that is, x^y ) | pow($1, 2) |
mod(x, y) | Returns the remainder of x divided by y | mod($1, 2) |
min(...args) | Returns the smallest value among the inputs | min($1, $2, $3) |
max(...args) | Returns the largest value among the inputs | max($1, $2, $3) |
bitand(x, y) | Performs a bitwise AND operation on x & y | bitand($1, 0x04) |
bitor(x, y) | Performs a bitwise OR operation on x | y | bitor($1, 0xF0) |
bitxor(x, y) | Performs a bitwise XOR operation on x ^ y | bitxor($1, 8) |
pi | Mathematical constant π | pi |
e | Mathematical constant e | e |
String fuctions
These functions allow you to manipulate and evaluate string values. You can check for substrings, match regular expressions, and calculate string length.
Function | Description | Example expression |
---|---|---|
contains(x, y) | Returns true if string x contains substring y | contains($1, "error") |
startsWith(x, y) | Returns true if string x begins with y | startsWith($1, "TEMP:") |
endsWith(x, y) | Returns true if string x ends with y | endsWith($1, ".log") |
length(x) | Returns the number of characters in string x | length($1) > 20 |
matches(x, y) | Returns true if string x matches the regular expression y | matches($1, "^[A-Z]+[0-9]{3}$") |
List functions
These functions operate on lists, such as checking whether a list contains a specific value. Useful when working with sets of known values.
Function | Description | Example expression |
---|---|---|
contains(x, y) | Returns true if list x contains value y | contains(["red", "blue", "green"], $1) |
Iteration functions
These functions apply an expression conditionally based on a logical test. They are used to include or exclude results based on a dynamic condition.
Function | Description | Example expression |
---|---|---|
filter(expression, condition) | Evaluates the expression and emits its value only when the condition is true. No value is emitted when the condition is false. | filter($1, $1 > 0) |
Stateful functions
These functions compute values over time using rolling windows or past data. They are used to calculate moving averages, rates of change, or time-based aggregates.
Function | Description | Example expression |
---|---|---|
avg(x, rolling(y)) | x is averaged over the past y duration (in seconds or time string) | avg($1, rolling(300)) |
median(x, rolling(y)) | Computes the median of x values seen within the rolling y window | median($1, rolling(60)) |
min(x, rolling(y)) | Returns the minimum of x over the last y duration | min($1, rolling(10)) |
max(x, rolling(y)) | Returns the maximum of x over the last y duration | max($1, rolling(10)) |
stdev(x, rolling(y)) | Computes the standard deviation of x over a rolling window of y | stdev($1, rolling(10)) |
sum(x, rolling(y)) | Calculates the total sum of x within the last y seconds | sum($1, rolling(60)) |
count(x, rolling(y)) | Counts how many values of x have appeared in the past y | count($1, rolling(10)) |
all(x, rolling(y)) | Returns true if all x values in the last y period are true | all($1, rolling(5)) |
any(x, rolling(y)) | Returns true if any value of x is true within the past y | any($1, rolling(5)) |
first(x, rolling(y)) | Returns the first value of x in the most recent y seconds | first($1, rolling(60)) |
last(x, rolling(y)) | Returns the last observed value of x in the past y seconds | last($1, rolling(60)) |
rolling(y) | Defines a rolling window of y seconds or a duration string (that is, "5m10s" ) to use with stateful functions | rolling("5m30s") |
previous(x) | Returns the value of x from the row immediately before the current one | previous($1) |
delta(x) | Computes the difference between the current and previous values of x | delta($1) |
deriv(x) | Calculates the rate of change of x per millisecond | deriv($1) |
persistence(x, y) | Returns true if x has remained true for at least y duration | persistence($1, "10s") |
- Aggregation windows: Rolling windows used in stateful functions can be up to 10 minutes long and apply only to rows that come before the current row. Future values are never included.
- Aggregations: All stateful functions require an input and a window definition, such as
avg($1 + 10, rolling(5))
. Only rolling windows are supported at this time.
User-defined Functions
User-defined Functions in Sift are reusable Common Expression Language (CEL) expressions that can be used in both Calculated Channels and Rules. They allow teams to define shared logic in one place and reference it across multiple expressions to ensure consistency and reduce duplication. To learn more, see User-defined Functions.
Other
These functions provide utility behavior such as accessing the current timestamp or converting data types like enum or numeric formats.
Function | Description | Example expression |
---|---|---|
t | Returns the timestamp of the current row in milliseconds | t |
enumKeyValue(x) | Returns the underlying numeric value of an enum input | enumKeyValue($1) |
double(x) | Converts a numeric value x to double precision | double($1) |