Skip to main content

Formula Expressions

Several OctoMesh features let you enter a formula — a small numeric expression that references one or more input values and produces a single value. All of them share the same formula engine (mXparser, wrapped as IFormulaEngine), so the syntax below is identical everywhere a formula is accepted.

Where formulas are used

FeatureInput variable(s)Notes
DataPointMapping MappingExpressionvalue — the polled source valueEvaluated by the adapter when a control value is mapped onto a target attribute. Validate before saving with the validate-expression API.
Archive computed columnseach source column, bound by its column name (e.g. activepower, apparentpower)Evaluated at archive-ingest time (and during backfill / rollup) for every row. A null / NaN result stores SQL NULL. The ResultType is stored with the column and drives the cast-back (see below).
Runtime-query @-expressions(none — constants + functions)A query search term prefixed with @ is evaluated as a formula (e.g. a time bound @startOfDay(0)).
Numeric engine

The engine computes with double. Inputs and results are numbers; booleans are 0 / 1 and date/times are .NET ticks. There is no string handling in formulas.

Variables

A formula references its inputs by name. For a DataPointMapping the single input is value; other features bind their own names (e.g. an archive computed column binds each source column by its column name). A name that is not provided by the feature is a syntax error.

Operators

CategoryOperators
Arithmetic+ - * / ^ (power) % (modulo)
Comparison< <= > >= == !=
Grouping( … )

Comparison results combine with the logical operators && (and), || (or) and ! (not).

Conditionals

Both forms are accepted and are equivalent:

value > 0 ? value : 0
if(value > 0, value, 0)

The C-style ternary cond ? a : b is normalized to mXparser's if(cond, a, b) before evaluation. Nesting is supported; use parentheses for clarity:

value > 100 ? 100 : (value < 0 ? 0 : value)

Built-in functions (mXparser)

The engine is the full mXparser parser (v6.x) — nothing is disabled — so the entire mXparser math collection is available, not just the handful most formulas use. Because every input and the result are double (see the numeric-engine note above), the numeric part of that collection is what's practically useful; the string / unit / probability-distribution helpers exist but have no string or unit inputs to work on here.

The most commonly used functions:

FunctionMeaning
abs(x)absolute value
sgn(x)sign (-1 / 0 / +1)
min(a, b, …) / max(a, b, …)minimum / maximum (any number of arguments)
round(x, n)round to n decimals
floor(x) / ceil(x)round down / up
sqrt(x)square root
exp(x)e^x
ln(x) / log2(x) / log10(x)natural / base-2 / base-10 logarithm
log(a, b)logarithm with an explicit base (see the reference for argument order)
mod(a, b)modulo (same as the % operator)
if(cond, a, b)conditional
iff(c1, v1, c2, v2, …)multi-branch conditional — first true condition wins

Other categories from the collection that work on numeric inputs:

CategoryExamples
Trigonometry (radians)sin(x) cos(x) tan(x) cot(x) sec(x) csc(x)
Inverse / hyperbolicasin(x) acos(x) atan(x), sinh(x) cosh(x) tanh(x)
Angle conversionrad(deg) (degrees→radians), deg(rad) (radians→degrees)
Rounding / partsfloor(x) ceil(x) round(x,n), frac(x) (fractional part)
Combinatorics / number theorygcd(a,b,…) lcm(a,b,…) C(n,k) (binomial), n! (factorial)
Aggregationmin(…) max(…), gcd(…) lcm(…)
Full catalogue

This table is a curated subset. The authoritative, version-matched list of every function, operator and constant the parser accepts is the mXparser math collection. Anything listed there that takes only numeric arguments works in an OctoMesh formula.

Constants

mXparser ships a large set of mathematical and physical constants. The ones you are most likely to use:

ConstantValue
piπ ≈ 3.14159
eEuler's number ≈ 2.71828
[phi]golden ratio ≈ 1.61803
[gam]Euler–Mascheroni constant ≈ 0.57722
true / false1 / 0 (handy with the logical operators)

(Physical constants such as the speed of light are also defined — see the reference. As with functions, only their numeric values are relevant here.)

OctoMesh extensions

These three are registered by OctoMesh on top of the standard collection (see OctoExpression / NowFunction / StartOfDayFunction in Runtime.Engine.Formulas):

Function / constantMeaning
now(addMinutes)current timestamp as .NET ticks, offset by addMinutes minutes (negative = past)
startOfDay(dayCount)local midnight as .NET ticks, shifted by dayCount days (startOfDay(0) = today, startOfDay(-1) = yesterday)
nullthe null sentinel — see below

Both date functions return ticks, so they are designed for a DateTime result type or for comparisons against other tick values (e.g. a runtime-query time bound @startOfDay(0)).

Null and error handling

  • A missing / null input binds to the null sentinel.
  • If a formula evaluates to NaN (e.g. 0 / 0) or to the null sentinel, the value is treated as no result — features map this to a fallback (DataPointMapping keeps the raw numeric value; an archive computed column stores NULL).
  • A syntax error (unbalanced parentheses, unknown variable, malformed expression) is reported at validation time, before the formula is ever used.

Examples

ExpressionMeaning
value / 100scale percent to ratio
value * 100scale ratio to percent
value - 2.5calibration offset
abs(value)magnitude
min(max(value, 0), 100)clamp to 0…100
value > 0 ? value : 0positive part only
value < 0 ? abs(value) : 0magnitude of the negative part (e.g. discharge power)

Validating a formula

For DataPointMapping, the Communication Controller exposes an authoritative validation endpoint that runs the same engine the adapter uses at runtime, so a formula that validates will also run:

POST {tenantId}/v1/communication/validate-expression
{ "expression": "value > 0 ? value : 0", "testValue": 42.0 }

It returns { valid, error, result, normalizedExpression }result is the value for the supplied testValue, and normalizedExpression shows the ternary-to-if rewrite.

Result types

Features that persist a formula result (notably archive computed columns) store a result type alongside the expression. The engine evaluates to double and then casts back:

Result typeCast-back
Doublethe raw value
Inttruncated to a 32-bit integer
Int64truncated to a 64-bit integer
Booleanfalse if the value is 0, otherwise true
DateTimethe value is interpreted as .NET ticks (pairs naturally with now() / startOfDay())

A null-sentinel or NaN result always maps to null regardless of the chosen type.

For developers

The engine itself — the IFormulaEngine service contract, the mXparser dependency, the DI registration and the shared ternary / null / cast-back conventions — is documented in the developer guide: Formula Engine.