# Solver

A solver process allows the user to define a mathematical expression that will be computed in real time at a configured rate. The expression produces an output signal from 0 to 16 input signals or 0 to 32 constant values.

The solver is most useful for running custom controllers and models on the actual devices.

## JCS Network Configuration

### structure.yaml Configuration

type | proc_solver |

### Signals - From Process

Signal name | Type | Required | Description |
---|---|---|---|

user defined | float32 | required | Computed expression output Signal name shall be defined by the user |

### Signals - To Process

Signal name | Type | Required | Description |
---|---|---|---|

user defined | float32 | optional | Expression input Signal name shall be defined by the user |

### Configuration Parameters

No parameters.

## Operation

An expression is defined in the process configuration file. At system startup JCS host converts the expression to a byte code, which is transferred to the device. Once all required signals become available, a byte code interpreter on the device evaluates the expression at each rate tick.

The solver is configured by defining any constants, any input variables and any expressions.

### Constants and intermediate values

`storage`

is used to store any constants or any intermediate values.

The solver does not interpret any numerical values in the expression. Any constants must be pre-allocated, given a name and value, then referenced by the name in the expression.

Intermediate values should have an initial value defined.

Example of intermediate value storage:

(In this example `th_offset`

is used as storage to pre-compute an angle offset, which is then used multiple times in a complex expression)

```
storage:
# Constant angle offset
- name: angle_offset
val: 1.443
# Variable storage to pre-compute theta offset
- name: th_offset
val: 0.0
signals:
- name: theta
expressions:
- name: th_offset
expr: theta - angle_offset
- name: tau
expr: sin(th_offset) / 2*cos(th_offset)
```

A maximum of 32 constant values is supported.

### Signals

`signals`

defines any input signals into the solver from the outside world.
Once defined, a signal may be referenced as an input signal into the solver within the 'structure.yaml' configuration file.

A maximum of 16 input signals is supported.

### Expressions

`expressions`

defines any actual expressions used by the solver.

The expression is given a name and an equation. The expression name becomes the output signal name and can be referenced within the 'structure.yaml' configuration file.

A maximum of 16 expressions is supported.

## Available Operators

Name | Function | Example | Description |
---|---|---|---|

+ | \(x + y\) | `x+y` |
Computes the addition of \(x\) and \(y\). |

- | \(x - y\) | `x-y` |
Computes the subtraction of \(y\) from \(x\). |

- | \(-y\) | `-y` |
Computes the unary minus of \(y\). |

* | \(x \times y\) | `x*y` |
Computes the multiplication of \(x\) and \(y\). |

/ | \(x \over y\) | `x/y` |
Computes the division of \(x\) and \(y\). Will return an error and possibly estop if \(y\) is equal to \(0\). |

^ | \(x^y\) | `x^y` |
Computes \(x\) raised to the power of \(y\). Approximated. |

## Available Functions

### Exponential functions

Name | Function | Example | Description |
---|---|---|---|

log2 | \(y = \log_2{x}\) | `log2(x)` |
Computes the approximated base-2 logarithm of \(x\). |

ln | \(y = \ln{x}\) | `ln(x)` |
Computes the approximated natural (base-\(e\)) logarithm of \(x\). |

log10 | \(y = log_{10}(x)\) | `log10(x)` |
Computes the approximated base-10 logarithm of \(x\). |

exp | \(y = e^{x}\) | `exp(x)` |
Computes approximated \(e\) raised to the power \(x\). |

exp2 | \(y = 2^{x}\) | `exp2(x)` |
Computes approximated \(2\) raised to the power \(x\). |

### Power functions

Name | Function | Example | Description |
---|---|---|---|

sqrt | \(y = \sqrt{x}\) | `sqrt(x)` |
Returns the square root of \(x\). Will return an error and possibly cause an estop if \(x\) is negative. |

hypot | \(z = \sqrt{x^2 + y^2}\) | `hypot(x,y)` |
Computes the square root of the sum of square of the two arguments. |

### Trigonometric functions

Name | Function | Example | Description |
---|---|---|---|

sin | \(y = sin{x}\) | `sin(x)` |
Approximated sine function. Computed with lookup table and cubic interpolation. Valid input range \([0, 2\pi]\). |

cos | \(y = cos{x}\) | `cos(x)` |
Approximated cosine function. Computed with lookup table and cubic interpolation. Valid input range \([0, 2\pi]\). |

tan | \(y = tan{x}\) | `tan(x)` |
Approximated tangent function. Computed as \(tanx = {sinx \over cosx}\). Valid input range \([0, 2\pi]\). |

atan2 | \(y = arctan({{y}\over{x}})\) | `atan2(y, x)` |
Approximated arc tangent of \(y \over x\) using the signs of the arguments to determine the correct quadrant. |

### Hyperbolic functions

Name | Function | Example | Description |
---|---|---|---|

sinh | \(y = sinh{x}\) | `sinh(x)` |
Approximated hyperbolic sine function. |

cosh | \(y = cosh{x}\) | `cosh(x)` |
Approximated hyperbolic cosine function. |

tanh | \(y = tanh{x}\) | `tanh(x)` |
Approximated hyperbolic tangent function. |

### Functions

Name | Function | Example | Description |
---|---|---|---|

abs | \(y = \lvert x \rvert\) | `abs(x)` |
Computes the absolute value of the argument. |

sgn | \(y = \begin{cases} -1, & \text{if } x\lt 0, \\ 0 , & \text{if } x = 0,\\ 1 , & \text{if } x\gt 0\\ \end{cases}\) | `sgn(x)` |
Returns the sign of the argument \(x\). |

max | \(y =\begin{cases} a, & \text{if } a\gt b, \\ b, & \text{if } b\gt a.\\ \end{cases}\) | `max(a,b)` |
Returns the maximum of a or b. |

min | \(y =\begin{cases} a, & \text{if } a\lt b, \\ b, & \text{if } b\lt a.\\ \end{cases}\) | `min(a,b)` |
Returns the minimum of a or b. |

clamp | \(y =\begin{cases} a, & \text{if } x\geq a,\\ x, & b \lt x \lt a,\\ b, & \text{if } y\leq b\\ \end{cases}\) | `clamp(x,a,b)` |
Clamps the value \(x\) to be between the maximum value \(a\) and the minimum value \(b\). |

normpi | \(y = \lvert x \rvert\) | `normpi(x)` |
Normalise an angle to the range \([-\pi, \pi]\). |

norm2pi | \(y = \lvert x \rvert\) | `norm2pi(x)` |
Normalise an angle to the range \([0, 2\pi]\). |

## Special sources

Note: \(dt\) is defined by the rate at which the solver process is ticked at.

`time`

Monotonically increasing time (seconds) in increments of \(dt\).

Notes:

`time`

will get large.`time`

will wrap to \(0\) at \(uint32\) max.- Approximated functions, such as sin / cos can fail at very large values of time (Fast angle normalisation has been used for speed).

`time_p`

Periodic time (seconds).

Counts from \(0\) to \(2\pi\) in increments of \(dt\).

`dt`

Timestep \(dt\) (seconds) at which the solver is called at.

## Practical Notes:

#### Functions must have parentheses

`sin x`

is not valid.

`sin(x)`

is valid.

#### Implicit multiplication not supported

`twox`

is not valid (this will be interpreted as a constant called twox).

`two*x`

is valid.

#### Unicode characters not supported

Only `*/-+><=`

are supported.

#### Divide by 0

Divide by zero will return an error from the solver and may result in an E-stop.

#### All trigonometric functions are in radians

#### Most trigonometric functions are approximations

and are optimised for the range \([0, 2\pi]\).

#### Boolean conditions return 1.0f or 0.0f (float)

Conditional statements (if, etc) compare floats.

#### Only CamelCase or snake_case variable or constant names are allowed

#### Expressions take a finite amount of time to be evaluated.

If the expression is too complex, it may not be evaluated in time before the next tick comes around.
In this case the solver will overrun and the system may shut down.
The time taken by the solver can be found by calling JCS host function `process_timing_print`

.

#### The solver does not yet do any optimisation of the expression.

It is recommended to pre-compute any constants. For example:

```
expr: A * sin(two * pi * f * time_p)
```

```
expr: A * sin(two_pi_f * time_p)
```

`two * pi * f`

is precomputed and stored as `two_pi_f`

.