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.