Expression Editor
The expression editor assists you in creating local and global expressions for your GENESIS64™ applications.
The Expression Editor opens whenever you see the tag icon showing the expression editor button options. View image
Each button in the Expression Editor displays a list of available functions. For example, the Variables button displays a list of defined inputs you can use in an expression. Variables require curly brackets within the syntax of the expression. For example: {{DataSource}} >= {{HiValue}}. With this editor, you can build an expression and then use the check syntax button (bottom left) to check your expression syntax, but it does not check whether the expression is correctly applied.
The Data Browser has an Expression tab, also giving you access to the expression editor. The Data Browser Expression keeps track of the last 50 expressions you have entered. View image
In the Data Browser, the expression you create is a local one, suited solely for a local purpose. For information about the differences between local and global expressions, see Expressions in the Data Browser.
Writing Expressions
An expression is a string that defines and evaluates data connectivity between a client and an OPC server. During runtime mode, OPC servers resolve the data value for the expression. To indicate that a data connection is an expression, precede the string with the "x=" token, as shown below:
x={{ICONICS.Simulator.1\SimulatePLC.PumpSpeed}}
The OPC tag is surrounded by curly brackets {{ and }}. Parameters are surrounded by double carets << and >>. For example, the expression for calculating a conversion from Celsius to Fahrenheit reads:
x= (<<Thermometer>>*1.8)+32
Where the <<Thermometer>> parameter is substituted when the expression is in use.
When writing expressions, you can type your expressions directly into the edit expression dialog box, including string expressions, string comparison, data type conversion and point extension syntax. The expression editor provides buttons to assist you in writing expressions using the proper syntax. For example, click the Logical button to show available selections. Hover over a function to display descriptive tooltips. View image
See the details for each expression editor button function:
- Arithmetic
- Relational
- Logical
- Bitwise
- Code Blocks
- Functions
- Variables - opens the Data Browser containing a list defined inputs you can use in an expression. Variables require curly brackets within the syntax of the expression. Refer to Data Type Conversion and Point Extension System (PES).
Strings in Expressions: Strings examples:
- “Hello World” is a constant string delimited with double quotation marks.
- $”Hello World”$ is a constant strings enclosed between $” and “$ characters.
String Comparison: When comparing strings or numeric data coming from the server as strings, the comparison is based on the character order. For example, the expression x="world" > "hello"
evaluates as true, because the character “w” comes after the character “h” in alphabetical order.
Sometimes, the string comparison may be misleading. Example: x="20" > "100" evaluates as true because the character "2" comes after the character "1" in the character table. Of course, if there were an expectation of a numeric comparison, 20 < 100 and the above expressions might seem to be evaluated incorrectly, but they are not.
Data Type Conversion: Expressions allow calculations on incoming data. An OPC server can provide data in one or more data types, such as "float," "long," "integer," or "string." Some OPC servers provide numeric data as a string. For example, the numeric value 20 may be presented as the string “20” (character "2" followed by character "0"), leading an incorrect expression evaluation (see the String Comparison section above).
The workaround is to add a numerical zero to each of the tags to enable the logic operators to work properly. For example:
x=({{JC.N1OPC.1.0\HDQTRS\sys2\ad-3.Present Value}}+0) > ({{JC.N1OPC.1.0\HDQTRS\sys2\ad-4.Present Value}}+0)
Some of the functions provided in the expression editor use numeric type parameters. When possible, the expression editor automatically converts the string into a number. For example, the string “20” is automatically converted to the number 20. However, the automatic conversion is impossible if the string contains alphabetic characters or symbols. For example, the string “20hello” cannot be converted into a number.
Even if the string contains only numeric characters and valid symbols, there may still be cases where an automatic conversion is not possible. For example, the string “123.45.23” cannot be converted into a number because it contains two decimal separators.
Sometimes, strings and numbers are mixed in expressions. In this case, the expression editor attempts to convert the string into a number. For example, Str+Number string is not convertible into a number, resulting in a bad quality. The following is an example of a valid expression: x=5+”6”
Point Extension Syntax: The Point Extension Syntax (PES) allows for retrieving additional information related to OPC tags, such as quality and timestamp.
- To use the PES:
- Prefix your tag name with “tag:”
- Postfix your tag name with “#” followed by a PES token.
The following are example expressions using a valid PES request:
- tag:ICONICS.Simulator\SimulatePLC.Ramp#timestamp
- tag:ICONICS.Simulator\SimulatePLC.Ramp#quality
- tag:\\pc1\ICONICS.Simulator\SimulatePLC.Ramp#timestamp
tag:\\pc1\ICONICS.Simulator\SimulatePLC.Ramp#quality
Sometimes it may be necessary to enforce the "request data type" to a specific type, such as "string," in order to display the extended syntax information in a process point.
Arithmetic Expressions
The symbols +,-, *, /and % use the parameter symbol parameter format. Where parameter is a local variable, an OPC tag, a constant, or another expression. The expression results in a number of any type (float, long, etc.). Some examples are shown in the table.
Symbol | Description | Example | Result |
---|---|---|---|
+ | Addition - adds one value to another | ~~var1~~ + ~~var2~~ | 8 + 3 = 11 |
- | Subtraction - subratcts one value from another | ~~var1~~ - ~~var2~~ | 8 - 3 = 5 |
* | Multiplication - multiplies one value by another | ~~var1~~ * ~~var2~~ | 8 * 3 = 24 |
/ | Division - divides one value by another | ~~var1~~ / ~~var2~~ | 8/3 = 2.6667 |
% | Modulus - calculates the remainder after division | ~~var1~~ % ~~var2~~ | 8 % 3 = 2 |
( | Open Parenthesis - designates the start of a group of operations and gives precedence to parts of the calcualtion |
|
|
) | Close Parenthesis - designates the end of a group of operations and gives precedence to parts of the calculation | ~~var1~~ /(~~var2~~ + ~~var3~~) | 8 / (3 + 2) = 1.6 |
sin(angleInRadians) | Sine -returns the sine of a specified angel where parameter 1 is angle in radians. |
|
|
cos(angleInRadians) | Cosine - returns the cosine of a specified angel where parameter 1 is angle in radians. |
|
|
tan(angleinRadians) | Tangent - returns the tangent of a specified angel where parameter 1 is angle in radians. |
|
|
asin(number) | Arcsine - returns the angle where the sine is the specified number. |
|
|
acos(number) | Arccosine - returns the angle where the cosine is the specified number. | ||
atan(number) | Arctangent - returns the angle where the tangent is the specified number. | ||
sqrt(number) | Square Root - returns the square root of a specified number. | ||
pow(base, exponent) | Raise to Power - returns a number raised to the power. | ||
log(number) | Logarithm - returns the base 10 logarithm of a specified number. | ||
ln(number) | Natural Logarithm - returns the natural (base e) logarithm of a specified number. | ||
exp(number) | Exponential - returns e (natural logarithmic base constant) raised to the specified power. | ||
abs(number) | Absolute Value - returns the absolute value of a specified number. | ||
ceil(number) | Integer Ceiling - returns the smallest whole number that is greater than or equal to the specified number. | ||
floor(number) | Integer Floor - returns the largest whole number that is less than or equal to the specified number. | ||
round(number) | Integer Round- the value is rounded to the nearest integer. | ||
round to(number, decimalPlaces) | Round to Decimal Places - the value is rounded to nearest integer. | ||
min(number1, ..., numberN) | Minimum - returns the smallest value of two or more numbers. | ||
max(number1, ..., numberN) | Maximum - returns the largest value of two or more numbers. | ||
sum(number1, ..., numberN) | Sum - returns the total value of of two or more numbers. | ||
avg(number1, ...numberN) | Average - returns the average value of of two or more numbers. | ||
isnan(number) | Is Not a Number - returns true if the specified value is a floating point representation of not-a-number in arithmetic operations, such as zero-divided by-zero. | ||
isinfinity(number) | Is Infinity - returns true if the specified value is a floating point representation of infinity, such as dividing a non-zero number by zero. | ||
pi | Circumference / Diameter Constant - the ratio of the circumference of a circle to it's diameter. | ||
e | Natural Logarithmic Base Constant - represents the natural logarithmic base |
Relational Expression
The symbols<, >, <=, >=, == and != use the parameter symbol parameter format. Where parameter is local variable, an OPC tag, a constant, or another expression. The result of the expression results in a Boolean value (0 or 1). The following are examples of relational expressions.
Symbol | Description | Example | Result |
---|---|---|---|
< | Less Than | ~~var1~~ <+ ~~var2~~ | 8 < 3 = 0 |
> | Greater Than | ~~var1~~ > ~~var2~~ | 8 > 3 = 1 |
<= | Less Than or Equal | ~~var1~~ <= ~~var2~~ | 8 <= 3 = 0 |
>= | Greater than or Equal | ~~var1~~ >=/ ~~var2~~ | 8 >= 3 = 1 |
== | Equal T | ~~var1~~ == ~~var2~~ | 8 == 3 = 0 |
!= | Not Equal To | ~~var1~~ != ~~var2~~ | 8 != 3 = 1 |
Logical Expressions
The symbols && and || use the parameter symbol parameter format. Where parameter is local variable, an OPC tag, a constant, or another expression. The result of the expression results in a Boolean value (0 or 1). The following are examples of relational expressions.
Symbol | Description | Example | Result |
---|---|---|---|
IF THEN ELSE | Conditional Branch |
|
|
IFQ THEN ELSE | Conditional Branch (Strict Quality) |
|
|
CASE WHEN THEN | See Switch Statement |
|
|
&& | And | ~~var1~~ && ~~var2~~ | 8 && 3 = 1 |
|| | Or | ~~var1~~ || ~~var2~~ | 8 || 3 = 1 |
/| | Or (Strict Quality) |
|
|
! | Not | !~~var1~~ | !8 = 0 |
true | Boolean Constant True |
|
|
false | Boolean Constant False |
|
|
Bitwise Expressions
The Bitwise symbols &, |, and ^ use use the parameter symbol parameter format. Where parameter is local variable, an OPC tag, a constant, or another expression. Other Bitwise symbols are:
- Symbol ~ uses ~ parameter
- Symbols shl uses (number, shiftBy), where number must be a local variable, an OPC tag, a constant, or another expression and shiftBy sets the number of bits to shift left by the specified number of positions.\
Symbol for Bit Test bittest function uses bittest(number, bitIndex). Where number is a local variable, an OPC tag, a constant, or another expression; and bitIndex sets is the position of the bit to test. A bit position of 0 indicates the less significant bit.
The BitTest() function in the Expression Editor evaluates only positive numbers from 0 to 2,147,483,648 or in hex from 00000000 to 7FFFFFFF. Negative numbers between -2,147,483,647 and 0 will be converted to the corresponding positive numbers prior to testing. Numbers above the outside ranges will give you unexpected results.
The following table uses two examples of variables ~~var1~~ and ~~var2~~ in expressions using the bitwise symbols.
- In Example 1, the decimal values for these variables are:
~~var1~~ = 8
~~var2~~ = 10 - Example 2, the decimal values for these variables are:
~~var1~~ = 96
~~var2~~ = 8
Symbol | Description | Example | Result |
---|---|---|---|
& | And | ~~var1~~ & ~~var2~~ | 8 & 3 = 0 |
| | Or | ~~var1~~ |~~var2~~ | 8 | 3 = 11 |
~ | Not | ~(~~var1~~) | !8 = -9 |
^ | Xor | ~~var1~~ ^~~var2~~ | 8 ^ 3 = 11 |
shl(number, shiftBy) | Shift Left | shl(~~var1~~,3) | 8 << 3 = 64 |
shr(number, shiftBy) | Shift Right | shr(~~var1~~,3) | 8 >> 3 = 1 |
bittest(number, bitIndex) | Bit Test | (5 , 0) | 1 |
setbit(number, bitIndex, bitValue) | Set Bit |
|
|
togglebit(number, bitIndex) | Toggle Bit | ||
0x | Hexadecimal Constant |
|
|
0t | Octal Constant |
|
|
0b | Binary Constant |
|
|
Code Blocks
Users can optionally use Code Blocks to help simplify complex expressions. Each code block returns a single value. Code blocks can be used by themselves or in line with standard expression editor functions. Code blocks can provide looping functionality and fast access to internal variables. See Code Blocks and Looping.
Functions Expression
Symbol | Description |
---|---|
quality(value) | Quality of Value |
setvalue(variable, value) | Assign a Value to a Variable |
tostring(value) | Convert to String (Invariant Culture) |
tostringculture(value) | Convert to String (Current Culture) |
toformat(value, stringFormat) | Convert to Formatted String (Invariant Culture) |
toformatculture(value, stringFormat) | Converted to Formatted String (Current Culture) |
tonumber(value) | Convert to Number (Invariant Culture) |
tonumberculture(value) | Convert to Number (Current Culture) |
tonumberbase(value, base) | Convert to Number from Base |
toboolean(value) | Convert to Boolean (Invariant Culture) |
tobooleanculture(value) | Convert to Boolean (Current Culture) |
asciitochar(number) | Convert Ascii Value(s) to Character(s) |
asciitowchar(number) | Convert Unicode Value(s) to Character(s) |
chartoascii(string) | Convert Character(s) to Ascii Value(s) |
wchartoascii(string) | Convert Character(s) to Unicode Value(s) |
| |
| |
| |
|
Symbol | Description |
---|---|
tringSource, stringMatchPattern,booleanCaseSensitive) | Wildcard String Compare |
len(string) | String Length |
getat(string, index) | Get Character at Index |
substring(string, startIndex, length) | Extract Substring |
left(string, length) | Left Substring |
right(string, length) | Right Substring |
concat(string1, string2) | Concatenate Strings |
indexof(stringToSearch, stringToFind, startIndex) | String Search. Note: as of 10.95.4, the indexof() function was modified to make the "startIndex" parameter (the third parameter) optional, and to add a fourth optional parameter for "count". This keeps indexof() consistent with the new functions but will not affect pre-existing projects. |
Lastindexof | Returns the zero-based index of the last occurrence of a substring within a string or returns the zero-based index of the last occurrence of an item in an array. |
Indexofany | Returns the zero-based index of the first occurrence within a string of any character from a specific set of characters. |
Lastindexofany | Returns the zero-based index of the last occurrence within a string of any character from a specific set of characters. |
replace(sourceString, stringFindWhat, stringReplaceWith) | String Replace |
trim(stringToTrim,charactersToRemove) | Trim Left and Right |
trimleft(stringToTrim, charactersToRemove) | Trim Left |
trimright(stringToTrim, charactersToRemove) | Trim Right |
tolower(string) | To Lowercase |
toupper(string) | To Uppercase |
null | Null Value Constant |
/*comment*/ | Comment |
Symbol | Description |
---|---|
isarray(value) | Is Array Value |
array(value1, ..., valueN) | Create Array |
Creates an Empty Array with the Specified Length | |
typedarray(elementType, value1, ..., valueN) | Create Typed Array |
Create an Array with the Specified Length Where All Elements are of the Specified Data type | |
qarray(excludeBad, excludeUncertain, value1, ..., valueN) | Create Array with Quality Options |
qtypedarray(excludeBad, excludeUncertain, elementType, value1, ..., valueN) | Create Typed Array with Quality Options |
len(array) | Array Length |
Modify the Number of Elements Stored in the Array | |
getat(array, index) | Get Value at Array Index |
Set the Value at the Specific Index (Zero-based) | |
indexof(arrayToSearch, valueToFind, optionalStartIndex, optionalCount) | Array Item Search |
lastindexof(arrayToSearch, valueToFind, optionalStartIndex, optionalCount) | Reverse Array Item Search |
min(array) | Minimum |
max(array) | Maximum |
sum(array) | Sum |
avg(array) | Average |
stddev(array) | Standard deviation |
stddev2(array) | Standard deviation 2 |
variance(array) | Variance |
variance2(array) | Variance 2 |
median(array) | Median |
range(array) | Range |
Symbol | Description |
---|---|
totimespan(value) | Convert to Timespan (Invariant Culture) |
totimespanculture(value) | Convert to Timespan (Current Culture) |
frommilliseconds(number) | Timespan from Milliseconds |
fromseconds(number) | Timespan from Seconds |
fromminutes(number) | Timespan from Minutes |
fromhours(number) | Timespan from Hours |
fromdays(number) | Timespan from Days |
totalmilliseconds(timespan) | Total Milliseconds from Timespan |
totalseconds(timespan) | Total Seconds from Timespan |
totalminutes(timespan) | Total Minutes from Timespan |
totalhours(timespan) | Total Hours from Timespan |
totaldays(timespan) | Total Days from Timespan |
timesincelastchange(variable, valueDelta, refreshRateTimeSpan) | Elapsed Time Since Value Changed |
trueforduration(booleanCondition, timespanDuration) | True for Duration |
Symbol | Description |
---|---|
todatetime(value) | Convert to DateTime (Invariant Culture) |
todatetimeculture(value) | Convert to DateTime (Current Culture) |
tolocal(dateTime) | Convert to Local Time |
toutc(dateTime) | Convert to UTC Time |
gettimeofday(datetime) | Get Time of Day from DateTime |
getdate(datetime) | Get Date from DateTime |
millisecond(dateTime) | Millisecond Fragment |
second(dateTime) | Second Fragment |
minute(dateTime) | Minute Fragment |
hour(dateTime) | Hour Fragment |
weekday(dateTime) | Day of Week |
day(dateTime) | Day of Month |
yearday(dateTime) | Day of Year |
month(dateTime) | Month Fragment |
year(dateTime) | Year Fragment |
dayseconds(dateTime) | Day Total Seconds |
now() | Get Current Local Date and Time |
utcnow() | Get Current UTC Date and Time |
currentdatetime(refreshRateTimeSpan) | Periodically Get Current Date and Time |
currentdatetimeutc(refreshRateTimeSpan) | Periodically Get Current UTC Date and Time |
today() | Today |
yday() | Yesterday |
mintime() | Minimum Time |
maxtime() | Maximum Time |
noon(dateTime) | Noon Time |
bday(dateTime) | Beginning of Day |
bweek(dateTime) | Beginning of Week |
bmonth(dateTime) | Beginning of Month |
byear(dateTime) | Beginning of Year |
eweek(dateTime) | End of Week |
emonth(dateTime) | End of Month |
eyear(dateTime) | End of Year |
Time conversion functions are implemented by forwarding the calls to the .NET equivalents. In .NET a DateTime object can be of 3 possible kinds (determined by the Kind property). Conversions may have different results depending on the Kind property. For example, this is the conversion table for tolocal based on the Kind property:
Kind | Result |
Local | No conversion |
UTC | Converted to local time |
Unspecified | Assumed UTC is converted to local |
For the toutc function:
Kind | Result |
---|---|
Local | Converted to UTC |
UTC | No conversion |
Unspecified | Assumed local is converted to UTC |
As you can see the Kind.Unspecified has 2 opposite behaviors depending on the function you are calling. Even converting from string to datetime can give you different kinds. Consider:
tolocal(todatetime("2022-03-29T15:00:00"))àreturns 17:00 because the conversion from string returns 15:00 with Kind.Unspecified (assumed UTC).
tolocal(todatetime("2022-03-29T15:00:00Zàreturns 17:00 because the conversion from string returns 15 with Kind.Utc (UTC).
tolocal(todatetime("2022-03-29T15:00:00+02")) à returns 15:00 because the conversion from string returns 15:00 with Kind.Local (local, so no conversion).
See Also: