Working with data

Computed signals & formulas

Derive a signal from others, or edit a signal in place. Both use the same expression language.

Two kinds of formula

Computed signalIn-place edit
CreatesA new traceNothing; modifies an existing trace
ReferencesAny signalOnly the trace being edited
Original valuesUntouchedKept; reversible
Opened with⌥⌘NDouble-click a trace

The same language is used a third time, without creating anything, in the calculation pad — a scratch pane for expressions over whatever the measurement tools currently hold.

Creating a computed signal

Press ⌥⌘N, or choose File → New Computed Signal…

New Computed Signal
Library
SignalsFunctions
run_a.csv
voltage
current
run_b.csv
voltage
name
power
expression
voltage * current
+* /^( )
✓ valid
preview
TYPE floatMIN -2.41MAX 9.03MEAN 3.12
X-AXIS  12,000 samples · 0–12s
  1. Library — every signal and function, searchable. Click to insert at the caret.
  2. Expression — syntax highlighted, with autocomplete as you type.
  3. Status line — the specific error, or a green check plus any alignment warnings.
  4. Live preview — the result drawn as you type, with statistics and the merged axis.
The formula pane, with the result drawn as you type.

The Library lists every signal and function; click one to insert it. The Preview draws the result as you type. Create is enabled once the formula compiles.

Plan limit

Free allows 2 computed signals, Personal 5. Pro and Team are unlimited.

Editing and deleting

Double-click a computed signal to reopen its definition. Saving updates every track that draws it. Delete it with × or the context menu; the Computed source disappears when its last signal is deleted.

Editing a signal in place

Double-click any trace. The pane opens with the trace's own name as the formula, ready to build on: voltage * 0.001, bits(status) & 0xFF, raw - mean(raw).

  • An in-place edit may reference only the trace being edited.
  • The values as loaded are kept, so the edit can be changed or removed at any time.
  • Everything downstream sees the edited values, including formulas that reference the trace.
  • Reset to Loaded Values removes the edit.

The formula language

References

Write a signal's name. Bracket names that are not plain identifiers:

voltage
[motor current]

Qualify a name with its source when two sources share it:

[run1.csv].voltage - [run2.csv].voltage

Clicking a signal in the Library inserts the correct form.

Numbers

Decimal (1, 2.5, 1e-3) and hexadecimal (0xFF).

Operators

OperatorMeaningPrecedence
^Power (right-associative)6
* /Multiply, divide5
+ -Add, subtract4
<< >>Shift (int only)3
&Bitwise AND (int only)2
|Bitwise OR (int only)1

Bitwise operators bind less tightly than + and -; parenthesise when in doubt.

Row indexing

A reference can be narrowed to one row, or to a span of rows. Both are 0-based, and a span is inclusive at both ends, so it reads the way the row numbers do on screen.

voltage[0]      the first row
voltage[2:5]    rows 2, 3, 4 and 5

Only a reference can be indexed — wrap an expression in a signal of its own first. A row outside the data yields no value; a span is clamped to the rows that exist.

What a row is depends on where the formula is written. In a computed signal it is a sample. In the calculation pad it is a row of the measurement table, so voltage[3] is that signal's value at cursor 3.

Scalars and series

Numbers and reducer results are scalars and combine elementwise with a series, so voltage - mean(voltage) removes a DC offset.

Functions

All functions take one argument except xor. Per-sample maps each sample, series depends on neighbouring samples, and scalar reduces to one number.

The scalar functions skip samples that have no value, so a gap in a signal cannot poison a statistic. count reports how many samples were left.

FunctionKindDescription
diff(x)seriesDifference between consecutive samples. First sample is NaN.
cumsum(x)seriesRunning total.
abs(x)per-sampleAbsolute value.
sqrt(x)per-sampleSquare root. Negative samples become NaN.
log(x)per-sampleNatural logarithm.
exp(x)per-samplee to the power of each sample.
sin(x)per-sampleSine, in radians.
cos(x)per-sampleCosine, in radians.
mean(x)scalarAverage of all samples.
min(x)scalarSmallest sample.
max(x)scalarLargest sample.
sum(x)scalarTotal of all samples.
count(x)scalarHow many samples have a value.
median(x)scalarMiddle sample, averaging the two middle values for an even count.
std(x)scalarPopulation standard deviation (divides by N).
rms(x)scalarRoot mean square.
bits(x)per-sampleReinterpret each sample's float32 bit pattern as an int.
xor(a, b)per-sampleBitwise XOR of two ints.
not(x)per-sampleBitwise complement of an int.
int(x)per-sampleRound to the nearest whole number.
float(x)per-sampleRelabel an int as a float.

Types

Values are either float (a number) or int (a bit pattern). Which one a signal is comes from the type its source declared — an int32 Parquet column or a 16-bit WAV is an int, a CSV column is a float. The formula pane tags each signal with its declared type. See Sample types.

float a numeric value int a bit pattern bits(x) reinterpret the float32 bits int(x) round to the nearest whole number float(x) relabel, value unchanged
bits() reinterprets; int() converts.

Bitwise operators and bit functions accept ints only. A signal whose source declared an integer type takes them directly — counter & 0xFF needs no cast. Applying one to a float is an error: "& needs an int — wrap 'channel' in bits() or int() first". Numeric literals work with either.

bits() and int()

  • bits(x) reinterprets the sample's float32 bits as an integer. Use it when a device packs flags into a float field.
  • int(x) converts, rounding to the nearest whole number. Use it when a signal holds integers but arrived as a float — a CSV column, for instance, since delimited text declares no type.

Bitwise arithmetic is 32-bit signed.

A computed signal is tagged simply int or float — a formula result carries no declared width.

Alignment

Signals in one formula are merged onto a common x-axis before evaluation. See How axes are combined. Three consequences:

  • Inputs are forward-filled, not interpolated: a slow signal holds its value between updates.
  • Positions before an input's first sample are NaN, which propagates through arithmetic.
  • An input plotted against a non-increasing custom x-axis is sorted first. The formula pane warns when this happens.

The editor

Typing raises a suggestion list. Tab or Return accepts the highlighted entry, arrow keys cycle, Esc dismisses. With no list showing, Return commits.

The operator palette inserts + - * / ^, the bitwise operators and a parenthesis pair. Clear empties the field.

The status line reports the first error, or a green check plus any alignment warnings. The preview shows the result type, min, max, mean and NaN count, the resolved inputs, and the merged axis.

Live updates

Computed signals re-evaluate when their inputs change, including on every window update from a live stream. A computed signal counts as live if any of its inputs is live, so Follow live and the follow-a-signal y mode work with derived curves.

Renaming and broken signals

Renaming a signal updates every formula that references it.

If an input becomes unavailable — its file is closed, or a computed signal it read is deleted — the dependent signal is marked broken, dims in the browser and stops drawing. Reopen the source and re-save the formula to restore it.

Examples

magnitude of a 3-axis accelerometer
sqrt(ax^2 + ay^2 + az^2)
remove a DC offset
voltage - mean(voltage)
normalise to 0..1
(signal - min(signal)) / (max(signal) - min(signal))
integrate current at 1 kHz
cumsum(current) * 0.001
compare two runs
[run_a.csv].temperature - [run_b.csv].temperature
extract a status byte (in-place edit)
bits(status) & 0xFF