CommandFusion Wiki

Documentation Resources

User Tools

Site Tools


Sidebar

software:gui-designer:math-expressions

Math Expressions

iViewer embeds a powerful and versatile math expression engine. Math expressions can be inserted in commands and feedback items. The Math expression parser features:

  • Standard math operators
  • Parenthesis grouping
  • Logical (boolean) operators
  • Standard math functions
  • Conditional logic using the if() function (like if / then /else statements)
  • Local variables
  • Multiple math expressions in the same command
  • Flexible result output

Usage

Basic math expressions can be written in a standard way using numbers and operators. You can use tokens which are dynamically replaced by their actual value before the math evaluation begins. Multiple expressions can be separated by a comma. You will use this feature to declare local variables and reuse them in the other expressions. When multiple expressions are present, the final result is the value of the last expression.

Within commands, math expressions must be enclosed in double curly braces, the result of the math evaluation is converted to a string (and can be optionally formatted the way you need it). Math expression can also be used in the transform field of 'capture group' feedback items (where the incoming data type is set to Analog), in which case you won't use the double curly braces to enclose the expression.

Do NOT use the double curly braces in the capture group > transform property in your feedback parsing. They are not needed in the transform property because this field can only contain math expressions. Read the above paragraph for more details.

Simple addition:       {{ 1 + [currentValue] }}

Math functions:        {{ round(1.5 * [currentValue]) }}

Multiple expressions:  {{ a=100, b=2*[inputValue], max(a, b) }}

Conditions:            {{ a=[currentValue]+[delta], if(a<5, a=0, a) }}

Boolean logic:         {{ above=([currentValue] > 100), below=([currentValue]  < 0), if (above or below, 0, [currentValue]) }}

Numbers and text output formatting

When using a math expression, you can specify an output format prefixed by a colon before the closing accolades. If you omit the format, the result will be formatted as an integer.

 {{math expression}} -> will output an integer without any decimal points

 {{math expression:}} -> will output a double with full decimal points

 {{math expression:N}} -> will output double with N decimals (can be 0, in this case this amounts to outputing an int)

 {{math expression::printf format}} -> will output a string using a full printf format string, with one argument (the math expression double result).

For more info on the printf format, see here: Printf Format on Wikipedia

Math expressions can also be used in feedback 'capture group' items, within the transform field. This works same as above, but you don't have to wrap the expression in curly braces.

With transforms, one predefined constant is set (“value”) which is the value extracted from the capture group, and can be used in the math computation.

Note that the 'value' constant does not support decimal values when using an Analog data type. The constant will always be rounded to a whole number before any transform can take place.
So you need to capture it into a serial join first, then use capture group name referencing to perform any math on this value if you need the initial captured value to support decimals.

Hexadecimal output formatting

In addition to the various number formatting options shown above, math expression can generate a hexadecimal ASCII string, or even raw bytes that you can use to send to a remote system. The options should be appended to the math expression, separated by a colon, just before the closing curly braces.

Raw bytes output

 :h         Convert the result to an unsigned long value (4 bytes) then output as few raw bytes as possible to
            represent this number. Bytes are output in network order (big endian).
            Examples:
            {{12+1:h}}   -> result=0x0000000d, output = "\x0d" (1 byte)
            {{1005*2:h}} -> result=0x000007da, output="\x07\xda" (2 bytes)

 
 :h<count>  Convert the result to an unsigned long value (4 bytes) the output the requested number of bytes,
            regardless of the result value. count should be 1 to 4 inclusive.
            Examples:
            {{12+1:h3}} -> result=0x0000000d, output = "\x00\x00\x0d" (3 bytes)
            

ASCII output (Hex String)

 :hs        Convert the result to an unsigned long value (4 bytes) then output an ASCII representation, using as few
            characters as possible to represent the value, using lowercase letters when needed.

            {{12+1:hs}} -> result=0x0000000d, output = "0d" (2 characters)
            {{1005*2:hs}} -> result=0x000007da, output="07da" (4 characters)
 
 :hs<count> Convert the result to an unsigned long value (4 bytes) then output an ASCII representation,
            showing the <count> least significant bytes of the result, using lowercase letters when needed.

            {{12+1:hs3}} -> result=0x0000000d, output = "00000d" (6 characters)
            {{1005*2:hs4}} -> result=0x000007da, output="000007da" (8 characters)

 
 :Hs        Same as :hs but text is output using uppercase characters:

            {{12+1:Hs}} -> result=0x0000000d, output = "0D" (2 characters)
            {{1005*2:Hs}} -> result=0x000007da, output="07DA" (4 characters)

 
 :Hs<count> Same as :hs<count> but text is output using uppercase characters.

            {{12+1:Hs3}} -> result=0x0000000d, output = "00000D" (6 characters)
            {{1005*2:Hs4}} -> result=0x000007da, output="000007DA" (8 characters)

Finally, an additional 's' specifier asks the engine to output as few characters as possible by stripping the leading nibble (half-byte) if its value is 0:

 :hss       Same as :hs, stripping the leading nibble is possible:

            {{12+1:hss}} -> result=0x0000000d, output = "d" (2 characters)
            {{1005*2:hss}} -> result=0x000007da, output="7da" (4 characters)

 
 :Hss       Same as :Hs, stripping the leading nibble is possible:

            {{12+1:hss}} -> result=0x0000000d, output = "D" (2 characters)
            {{1005*2:hss}} -> result=0x000007da, output="7DA" (4 characters)

Operators

The math expression parser recognizes the following operators. They are listed in inverse priority order (lowest priority ones come first).

 =    assignment (creates or updates a local variable)

 and  logical AND
 or   logical OR
 xor  logical XOR
 <=   less than or equal
 >=   greater than or equal
 !=   not equal
 ==   equal
 >    greater than
 <    less than

 +    addition
 -    subtraction
 *    multiplication
 /    division
 %    modulo
 ^    power (raise x to the power of y)

Functions

The math parser provides several built-in functions. Let us know if the function you need is missing from this list! Trigonometric functions take an angle expressed in radians, use the dtor() and rtod() functions to convert between degrees and radians.

Trigonometry

 dtor(a)  convert angle from degrees to radians
 rtod(a)  convert angle from radians to degrees
 sin(a)   sine function
 cos(a)   cosine function
 tan(a)   tangent function
 asin(a)  arc sine function
 acos(a)  arc cosine function
 atan(a)  arc tangent function
 sinh(a)  hyperbolic sine function
 cosh(a)  hyperbolic cosine function
 tanh(a)  hyperbolic tangent function
 asinh(a) hyperbolic arc sine function
 acosh(a) hyperbolic arc cosine function
 atanh(a) hyperbolic arc tangent function

Math

 log(n)   natural logarithm
 log2(n)  logarithm to base 2
 log10(n) logarithm to base 10
 ln(n)    logarithm to base e (2.71828...)
 exp(n)   e raised to the power of x
 sqrt(n)  square root
 abs(n)   absolute value
 trunc(n) truncate to integral value
 rint(n)  round to integral value
 near(n)  same as rint(n)
 round(n) round to integral value, regardless of rounding direction
 ceil(n)  round to smallest integral value not less than n
 floor(n) round to largest integral value not greater than n
 sign(n)  sign function: -1 if n<0, 0 if n=0, 1 if n>0

Multiple arguments

 min(n1,n2,...) smallest of all arguments. Use as many arguments as needed.
 max(n1,n2,...) largest of all arguments. Use as many arguments as needed.
 sum(n1,n2,...) sum of all arguments. Use as many arguments as needed.
 avg(n1,n2,...) mean value of all arguments. Use as many arguments as needed.

Conditionals

 if(t,a,b) if t is > 0 then result is a, otherwise result is b.

Examples

Assuming the captured value of the feedback group = 125.266335454

 "value / 100:" -> "1.25266335454"

 "value / 100" -> "1"

 "value / 100:0" -> "1"

 "value / 100:3" -> "1.252"

 "value / 100::%03.1f" -> "001.2"

 "value / 100::your value is %.2f. Isn't it cool?" -> "your value is 1.25. Isn't it cool?"

Tokens

Token names can be used anywhere in the math expression, and will be replaced with their value before the math expression is evaluated.

For example, if you had a global token named [level] defined with a value of 125.266335454, you could create the following examples:

 "[level] / 100:" -> "1.25266335454"

 "[level] / 100" -> "1"

 "[level] / 100:0" -> "1"

 "[level] / 100:3" -> "1.252"

 "[level] / 100::%03.1f" -> "001.2"

 "[level] / 100::your value is %.2f. Isn't it cool?" -> "your value is 1.25. Isn't it cool?"

Referencing other groups

Within feedback group transform expressions, you can also reference the value of any other capture group defined in the same feedback item.

To reference a group, it must first be given a name, and must also be listed above the current group in the feedback processing order.

Reference the group by surrounding the name of the group in dollar signs. So if we had another capture group named [temp], which captured the value 1.25266335454 we could reference it like so:

 "$[temp]$ / 100:3" -> "1.252"

 "$[temp]$ / 100::%03.1f" -> "001.2"

 "$[temp]$ / 100::your temp value before transform is $[temp]$ and after transform is %.2f. Isn't it cool?" -> "your value before transform is 1.25266335454 and after transform is 1.25. Isn't it

Text evaluation notes

Commands (and commands within macros), string join assignments and token assignments are being run through the math parser which looks for any math expression(s) enclosed in double curly braces within the text. Text can include multiple math blocks, each enclosed in double curly braces. When processing the text, all math local variables are reset at beginning, then kept accross multiple math blocks. This means that you can perfectly send text with intertwined math result values, and that each calculation can reuse local variables from the previous step. Here is an example:

 "Going from [currentValue] to {{a=min(1,max(100, [currentValue]+[delta]))}}. Final delta is {{abs(a - [currentValue])}} (was [delta])."

In the case above, we compute a new value from a current value and a delta, cap it to a minimum of 1 and a maximum of 100, and output text showing the new value, as well as the delta between the capped new value and the current value. Assuming that [currentValue] is 17 and [delta] is 100, the output text will be:

 "Going from 17 to 100. Final delta is 83 (was 100)."
software/gui-designer/math-expressions.txt · Last modified: 2015/04/09 00:58 by jarrod