Expression Functions
Expressions are evaluated wherever a value is computed from tags — expression tags in the namespace, expression bindings on a property, transforms on a binding, and map-transform rows.
Expressions are quality-aware: every operand carries a quality, and a result carries the worst quality of its inputs. A computed value can never appear healthier than the data behind it.
Numeric functions
| Function | Signature | Returns |
|---|---|---|
abs | abs(x) | Absolute value |
min | min(a, b) | The smaller of two values |
max | max(a, b) | The larger of two values |
sqrt | sqrt(x) | Square root |
clamp | clamp(x, lo, hi) | x bounded to [lo, hi] |
clamp(Tank1/Level, 0, 100)
max(Motor1/Current, Motor2/Current)
sqrt(abs(DeltaP)) * KFactor
clamp takes the worst quality of all three operands — a bad limit makes the result bad, which is
the correct behaviour when a limit comes from a tag.
Bit manipulation
Industrial data packs many booleans into one integer — status words, alarm words, fault registers. These functions unpack them without a script.
| Function | Signature | Returns |
|---|---|---|
bitAnd | bitAnd(a, b) | Bitwise AND |
bitOr | bitOr(a, b) | Bitwise OR |
bitXor | bitXor(a, b) | Bitwise XOR |
bitNot | bitNot(a) | Bitwise NOT |
shiftLeft | shiftLeft(a, n) | a << n |
shiftRight | shiftRight(a, n) | a >> n |
getBit | getBit(value, pos) | Bit pos as a boolean |
setBit | setBit(value, pos, on) | value with bit pos set or cleared |
Bit positions are 0-based and valid for 0..63. An out-of-range position produces a bad-quality
result rather than a silently wrong one.
getBit(PLC1/StatusWord, 3) is fault bit 3 set?
bitAnd(PLC1/AlarmWord, 0x00FF) != 0 any alarm in the low byte?
setBit(PLC1/CommandWord, 5, true) build a command word
Integer operations are performed at 64-bit width, so a status word wider than 32 bits behaves correctly.
Arithmetic and comparison
Standard operators are available: + - * / %, == != < <= > >=, && || !, and parentheses.
(Motor1/Current / Motor1/RatedCurrent) * 100
Tank1/Level > 80 && Pump1/Running
Quality propagation
| Situation | Result quality |
|---|---|
All inputs Good | Good |
Any input Uncertain | Uncertain |
Any input Bad or NotFound | Bad |
| Non-numeric input to a numeric function | Bad |
Bit position out of 0..63 | Bad |
This is why a widget bound to an expression can be relied upon to show bad quality: the expression layer does not launder it.
Where expressions appear
| Place | Notes |
|---|---|
| Expression tag | A tag whose value is an expression — computed once, then usable anywhere a tag is |
| Expression binding on a property | Computes the property's value from one or more tags |
| Expression transform on a binding | Reshapes a value the binding already fetched |
| Map transform — expression input | The row matches when the expression is truthy |
| Map transform — expression output | Computes the mapped output |
| Threshold transform | Band boundaries |
The three differ by where the value lives, which is the decision worth getting right. An expression tag is computed once in the namespace and can be trended, alarmed and reused anywhere. An expression binding computes a property's value on one screen. An expression transform reshapes a value some other binding already fetched.
If the same expression appears on a second screen, it wanted to be a tag.
→ Expression tags · Property bindings
When to reach for a script instead
Expressions are the right tool for arithmetic, bit unpacking and simple conditionals. Use a script transform or a Gateway script when you need:
- Iteration or data structures
- Database or historian access
- Multi-step logic with intermediate state
- Anything you would want to unit-test
An expression that needs a comment explaining it has usually outgrown being an expression.