ReferenceConsoleCalculated Channels

Calculated Channels

Process live telemetry with calculated channels.

Calculated channels derive real-time data from existing channels. They enable live data processing and analysis, such as:

  • Scaling, converting or filtering raw data
  • Implementing sensor voting algorithms
  • Creating channels to conditionally trigger alarms or warnings.

Calculated channels now use the Arc language. Existing Lua-based channels will continue to work but should be migrated to Arc.

Creating Calculated Channels

To create a calculated channel, open the Search and Command Palette and run the “Create Calculated Channel” command.

  • Click the search bar at the top and type > to open the palette.
  • Alternatively, press Ctrl+Shift+P (Windows) / Cmd+Shift+P (macOS).

Channel Parameters

When creating a calculated channel, you will be prompted to fill in the following fields:

FieldDescription
NameA name for the channel.
ExpressionThe Arc expression that calculates the value to be written to the calculated channel. This expression must end with a return statement. Channel dependencies are automatically detected from the expression.
Operation (Optional)Post-processing operation applied to the expression result. Options include min, max, and avg for running aggregations.
Window (Optional)Time duration for operation resets. When the duration expires, the operation state is reset. Set to 0 for no duration-based reset. Only applies when an operation is selected.
Reset Channel (Optional)A uint8 channel that triggers operation reset when its value equals 1. Only applies when an operation is selected.

Writing Expressions

Calculated channels use the Arc language for expressions. Arc is a domain-specific language designed for real-time telemetry processing.

Basic Syntax

Channel References

Reference channels directly by name without any prefix or special syntax:

return temperature
return sensor_a + sensor_b
return voltage * current

Channel names are automatically detected and used as inputs to the calculation.

Return Statement

Every expression must end with a return statement:

return pressure * 1.5

Variables

Use := to declare intermediate variables:

scaled := pressure * 2.5
offset := scaled + 10
return offset

Operators

Arc supports standard operators for calculations:

Arithmetic: +, -, *, /, %

return (temp_1 + temp_2 + temp_3) / 3  // Average

Comparison: ==, !=, <, >, <=, >=

return pressure > 100  // Returns 1 (true) or 0 (false)

Logical: and, or, not

return temp > 100 and pressure > 50

Conditionals

Use if statements with curly braces for conditional logic:

if (temperature > 100) {
    return 1
} else {
    return 0
}

Multi-condition example:

if (temp > 100 and pressure > 50) {
    return 2
} else if (temp > 50) {
    return 1
} else {
    return 0
}

Data Types

The calculated channel’s data type is automatically inferred from the Arc expression’s return value. The system analyzes your expression to determine the appropriate data type (e.g., float64, int32, etc.).

Editing Calculations

To edit a calculated channel, right-click it in the Channels Toolbar and select “Edit Calculation” from the context menu:

Operations

Operations are optional post-processing steps that apply aggregations to your calculated channel. They enable stateful computations like running minimums, maximums, and averages.

How Operations Work

Operations process the expression result before writing to the output channel:

Expression Result → Operation → Output Channel
                     ↑
                Reset Channel

The operation maintains internal state across executions, outputting a single aggregated value rather than processing individual samples.

Supported Operations

OperationDescription
noneNo operation (default). Passes expression result directly to output.
minRunning minimum. Tracks the smallest value seen since the last reset.
maxRunning maximum. Tracks the largest value seen since the last reset.
avgRunning average. Computes the mean of all values since the last reset.

Reset Mechanisms

Operations can reset their state through three mechanisms (any can trigger a reset):

  1. Duration-based (Window): Resets after a specified time duration based on input timestamps
  2. Signal-based (Reset Channel): Resets when a uint8 channel receives value 1
  3. Never: Set duration to 0 and omit reset channel for a continuous operation

Example Configurations

Running average over 10 seconds:

  • Operation: avg
  • Window: 10 seconds
  • Reset Channel: (none)

The average resets every 10 seconds based on data timestamps.

Maximum until manual reset:

  • Operation: max
  • Window: 0 (no duration reset)
  • Reset Channel: manual_reset_button

The maximum runs indefinitely until the reset channel triggers.

Minimum with both reset types:

  • Operation: min
  • Window: 60 seconds
  • Reset Channel: cycle_complete

The minimum resets either after 60 seconds OR when the reset channel triggers—whichever comes first.

Reset Channels

Reset channels provide signal-based control over operation state and must have data type uint8. When a reset channel receives a value of 1, the associated operation clears its accumulated state and restarts.

Use Cases

Manual Reset Button:

Create a virtual uint8 channel that you can write to from a schematic button or control panel to manually reset the calculation.

Periodic Reset Signal:

Use a timer or sequence to generate periodic reset pulses for regular operation resets.

Conditional Reset Logic:

Create a calculated channel that outputs 1 when a certain condition is met (e.g., “cycle complete” flag from another system).

Behavior Example

Time:           0s → 5s  → 10s → 10.1s (reset=1) → 15s → 20s
Pressure:       50 → 100 → 75  → 75              → 90  → 110
Max Operation:  50 → 100 → 100 → (reset to 75)   → 90  → 110

At 10.1s, the reset channel triggers, clearing the max value. The operation restarts from the current input (75) and continues tracking the new maximum.

Examples

Simple Operations

Scaling a sensor:

return pressure * 1.5

Adding an offset:

return temperature + 273.15  // Convert Celsius to Kelvin

Power calculation:

return voltage * current

Multi-Channel Calculations

Sum of multiple sensors:

return sensor_1 + sensor_2 + sensor_3

Average (in expression):

return (temp_1 + temp_2 + temp_3) / 3

Differential measurement:

return inlet_pressure - outlet_pressure

Conditional Logic

Threshold detection:

if (pressure > 100) {
    return 1  // High alarm
} else {
    return 0  // Normal
}

Multi-level thresholds:

if (temp > 100 and pressure > 50) {
    return 2  // Critical
} else if (temp > 50) {
    return 1  // Warning
} else {
    return 0  // Normal
}

Safe division (avoid divide-by-zero):

if (denominator == 0) {
    return 0
} else {
    return numerator / denominator
}

Multi-Step Calculations

Unit conversion with intermediate variables:

celsius := sensor_temp
fahrenheit := celsius * 9 / 5 + 32
return fahrenheit

Pressure compensation:

raw_pressure := sensor_reading
temp_correction := temperature * 0.01
compensated := raw_pressure - temp_correction
return compensated

Using Operations

Running maximum with manual reset:

  • Expression: return pressure
  • Operation: max
  • Window: 0 (no duration reset)
  • Reset Channel: reset_button

This tracks the maximum pressure value until the reset button is triggered.

10-second rolling average:

  • Expression: return temperature
  • Operation: avg
  • Window: 10 seconds
  • Reset Channel: (none)

This computes the average temperature over 10-second windows.

How Calculated Channels Work

Calculated channels are virtual, meaning their data is computed on-demand rather than stored permanently to disk. This section explains how they work under the hood.

On-Demand Computation

Calculated channels don’t run continuously in the background. Instead, they only execute when someone actively reads or streams the channel. When you start visualizing a calculated channel in a line plot or request its data through the API, Synnax automatically activates the calculation. When you stop streaming, the calculation pauses.

This on-demand approach conserves system resources: calculations only consume CPU and memory when their results are actually needed.

Historical Evaluation

Calculated channels can be evaluated historically, allowing you to query past data as if the calculation had been running at that time. For this to work:

  • All input channels must have data available in the time range you’re querying
  • Simple expressions (like return pressure * 1.5) work reliably with historical data
  • Operations (min, max, avg) with time-based windows may have limitations with historical queries

Example: If your calculation depends on sensor_1 and sensor_2, you can query historical data for any time range where both sensors have recorded data. The calculation will be applied to the historical data as if it had been running continuously.

Nested calculations also work historically. If calc_2 depends on calc_1, and calc_1 depends on persisted channels, you can query calc_2 historically as long as the underlying data exists.

Nested Calculations

Calculated channels can depend on other calculated channels, creating calculation chains:

sensor_raw → temp_celsius → temp_fahrenheit → temp_status

When data arrives at sensor_raw, it automatically propagates through the chain:

  1. temp_celsius calculates and outputs its result
  2. temp_fahrenheit receives that output and calculates its result
  3. temp_status receives that output and produces the final result

There’s no limit to nesting depth, but keep in mind that each level adds computation time. Design your calculations thoughtfully to balance clarity and performance.

Handling Different Arrival Rates

Calculated channels operate on series (arrays of samples), not individual scalar values. When you write return temperature + pressure, you’re performing an elementwise operation on arrays.

When inputs have different numbers of samples, Arc uses last-value-hold semantics:

  • The output length equals the maximum of the input lengths
  • Shorter series repeat their last value for remaining positions
  • This happens per frame, not across time

Example: Consider a frame where:

return temperature + pressure

If the frame contains:

  • temperature: 10 samples [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
  • pressure: 5 samples [30, 31, 32, 33, 34]

The calculation produces 10 output samples:

  1. pressure’s last value (34) repeats for positions 6-10
  2. Elementwise addition: [50, 52, 54, 56, 58, 59, 60, 61, 62, 63]

What this means for different rates:

If temperature updates at 100 Hz and pressure at 10 Hz, when a frame arrives with 100 temperature samples and 10 pressure samples, the calculated channel produces 100 output samples. pressure’s 10th value is used for output samples 11-100.

Note: This is not interpolation; it’s a last-value-hold. The system doesn’t create new pressure values; it reuses the most recent one.

Migration from Lua

If you have existing Lua-based calculated channels, here’s how to migrate them to Arc:

Syntax Comparison

FeatureLua (Legacy)Arc (Current)
Channel Accesschannels.name or get("name")name
Variableslocal x = 5x := 5
Conditionalsif x then ... endif (x) { ... }
Logical ANDandand
Logical ORoror
Logical NOTnotnot
Not Equal~=!=
Returnreturn valuereturn value

Migration Examples

Simple scaling:

-- Lua
return channels.sensor * 2
// Arc
return sensor * 2

Conditional logic:

-- Lua
if channels.temp > 100 then
    return 1
else
    return 0
end
// Arc
if (temp > 100) {
    return 1
} else {
    return 0
}

Multi-step with variables:

-- Lua
local scaled = channels.pressure * 2.5
local offset = scaled + 10
return offset
// Arc
scaled := pressure * 2.5
offset := scaled + 10
return offset

Key Differences

  1. No channel prefix needed - Reference channels by name directly
  2. Curly braces for blocks - Use {} instead of then...end
  3. Keyword operators - Arc uses the same and, or, not keywords as Lua
  4. Auto-detected dependencies - No need to manually specify requires field

Channel Naming for Arc

Important: Arc identifiers can only contain letters, digits, and underscores, and must start with a letter or underscore. Channel names with special characters (like dashes, spaces, or dots) cannot be directly referenced in Arc expressions.

Best Practice: When creating channels that will be used in Arc calculated channels, use underscores instead of special characters:

  • sensor_1, temp_reading, channel_a
  • sensor-1, temp reading, channel.a

For complex calculations involving loops or tables, consider breaking them into multiple calculated channels.