The RPN Calculator for HydraFerret

Enfield Cat's Blog: Arduino and other projects.


Introduction

RPN stands for "Reverse Polish Notation", or a "stack calculator". Many early HP calculators used rpn notation and it is relatively simple to implement yet powerful which is why it is used in HydraFerret.

The rpn calculator uses the concept of a last in last out (LIFO) stack. Numbers are placed on the stack and then some operation (such as add or subtract) is applied to the numbers on the stack and the result is placed back on the stack. At the end of the calculation there should just be one number left on the stack which is the result. Using this concepts it is possible to specify calculation without having to place terms inside brackets. The downside is many people find the format counter intuative.

How does it work?

  1. A space is used to separate each term in the expression
  2. The rpn expression is applied from left to right.
  3. Any value or variable is pushed on to the stack.
  4. When an operator is encountered (these will be single characters), the operation is applied the the values at the top of the stack.
  5. As many items as are required by the operator are popped off the stack
  6. The result is pushed on to the stack

Here is an example of the an rpn expression in HydraFerret:

bme280.temp 2 - bme280.dewp < bme280.temp 3 < &

This uses 2 variables from the first bm280 sensor, one of which is accessed twice.

  1. The temperature and a constant are pushed on to the stack.
  2. The constant is subtracted from the temperature, and the difference is placed on the stack.
  3. The dew-point is pushed on to the stack
  4. A comparison is made, and if (the temperature less 2 degrees) is less than the dewpoint 1 is put on the stack, 0 otherwise
  5. The temperature and another constant is put on the stack
  6. These are compared and a 1 is put on the stack if the temperature is less than the constant, 0 otherwise
  7. A logical "and" is performed, if both tests had returned 1 then 1 is left on the stack, or 0 otherwise. ie to get a 1 returned the temprature is within 2 degress of the dewpoint AND the temperature is less than 3 degrees.

Effectively we've created a frost warning calculation. NB: Your frost formation warning conditions may be different!

Let's now see the same calculation performed at the console prompt to step through it. When done like this we can see the operation performed, where a blank prefix show a constant pushed on to the stack and a "~" indicates a variable lookup. This allows us to test if a calculation is valid and performs as we expect before creating an output or alert using it. A trace is given when using the "rpn" command showing each step of the calculation. This trace is not produced for outputs or alerts. The trace shows the stack state after the operation has been performed. In the example the temperature is 22.6 Celsius with a dew-point of 12.2 Celcius. Once confirmed like this the expression could be used to set a warning threshold or control an output.

rpn bme280.temp 2 - bme280.dewp < bme280.temp 3 < &
Op   Older <-- Stack --> Newer
 ~    22.6340
      22.6340    2.0000
 -    20.6340
 ~    20.6340   12.2120
 <     0.0000
 ~     0.0000   22.6340
       0.0000   22.6340    3.0000
 <     0.0000    0.0000
 &     0.0000

Using an index, the following is equivalent to the preceding calculation:

rpn bme280.0.temp 2 - bme280.0.dewp < bme280.0.temp 3 < &

Supported Operations

OperationOperandsdescription
2 number operators
+2Add 2 numbers
*2Multiply 2 numbers
-2Subtract a number from the previous number on the stack
/2Divide the previous number on the stack by the last number on the stack
%2Modulus division, result is the remainder of the previous divided by the last number on the stack
^2Raise the previous number on the stack by the power of the last number on the stack
d2Return the dewpoint based on temperature in Celcius and relative humidity
h2Return the hypotenuse of the last 2 numbers on the stack
Q2Return the altitude compensated pressure given measure pressure and altitude
x2Exchange the last two numbers on the stack
&2Return 1 if both of the last 2 numbers on the stack are greater than 0, otherwise return 0
|2Return 1 if either of the last 2 numbers on the stack are greater than 0, otherwise return 0
=2Return 1 if the last two numbers on the stack are equal, otherwise return 0
<2Return 1 if the previous number on the stack is less than the last number on the stack
>2Return 1 if the previous number on the stack is greater than the last number on the stack
1 number operators
!1Inverse of the last number on the stack
a1Absolute value of the last number on the stack
f F1Convert the last number on the stack between Fahrenheit and Celcius (Capital to Fahrenheit)
i I1Round to next integer, i next integer nearest 0, I next integer furthest from zero
l1Log base 10 of the last number on the stack
k1retreive the numbered constant value.
n1Natural log of the last number on the stack
q1Cubed root of the last number on the stack
r R1Convert the last number on the stacki between radians and degrees and reverse (Capital to Radians)
v1Square root of the last number on the stack
s S1Sin of the last number on the stack, or Capital for inverse
c C1Cos of the last number on the stack, or Capital for inverse
t T1Tan of the last number on the stack, or Capital for inverse
Constants
e0e
g0Earth gravitaional acceleration 9.8066 m/s/s
p0Pi

Variables

The general format for variables in HydraFerret is <sensor><index><measurement> where the index numbers start from zero, but can be omitted for the zero-ith sensor of the type. The measurement is normally limited to the first 4 characters of the variable. This may seem long winded, yet terse. But allow variables to be very specific. The "memory" sensor refers to internal measurements of the HydraFerret unit, and allow for time dependency to be built in to calculations.

Memory Variables

Variable NameDescription
memory.freeTotal free heap size, note the largest available block of memory may be much smaller.
memory.minfThe minimum free heap size seen since system start
memory.sizeThe size of the system heap memory
memory.timeThe system up-time in minutes
memory.freqThe processor speed
memory.xtalThe system crystal speed
memory.yearThe current year
memory.montThe month: Jan=1, Dec=12
memory.dowThe day of week: Sun=0, Sat=6
memory.domThe day of month
memory.doyThe day of year
memory.hourThe hour of day: 00 - 23
memory.minThe minute of the hour: 00 - 59
memory.mindThe minute of day: 0 - 1439
memory.secsThe seconds of the minute: 00 - 59

Sensor Variables

There are a number of varibales which are not explicitly documented per server. In the table below "xxxx" indicates the device type (and number), while "*" indicates the first letter a a variable name, eg "t" for temperature. These variables will be included when running: list vars

Variable namedescription
xxxx.devThe count of the number of "xxxx" devices attached to the unit.
xxxx.las*The last reading taken on the device. This is updated on evry monitoring interval, and may be used for calculations where the latest measurement is required, eg to set an output variable, or diagnosing issues at the connsole.
xxxx.*staThe status from the last 5 minute period. 0 = OK, 1 = Warning, 2 = Critical, 3 = Extreme. The numeric value can be used as a mutiplier for a hysteresis value to be added to warning or critical threshold to prevent "flapping" in and out of warning and critical states.

NB: These are shown in their abbreviated form eg bme280.temp, rather than the longer form with device index, eg: bme280.0.temp or bme280.1.temp. The abbreviated form refers to device index 0.

Variable NameDescription
adc.valAveraged reading from last 5 minute interval
adc.multmultiplier for raw values
adc.offsoffset to add to raw values, typically left at 0.000
bh1750.luxLight level in Lux (Lumins / m2)
bh1750.opacWindow opacity, 1.2 = no window
bme280.altiAltitude in meters
bme280.dewpDewpoint in centigrade/Celcius
bme280.humiRelative humidity
bme280.presPressure in hectoPascals
bme280.uncoUncompensated pressure in hectoPascals
bme280.sosSpeed of sound in meters per second. Speed of sound varies with temperature
bme280.tempTemperature in Centigrade/Celcuis
counter.diffReading difference is last 5 minute period
counter.totaTotal count from reset to last period
counter.multmultiplier for raw values
counter.offsoffset to add to raw values, typically left at 0.000
css811.co2CO2 levels in parts per million
css811.tvoctvoc (Total Volatile Organic Compound) levels in parts per billion
hdc1080.dewpDewpoint in centigrade/Celcius
hdc1080.humiRelative humidity
hdc1080.sosSpeed of sound in meters per second. Speed of sound varies with temperature
hdc1080.tempTemperature in Centigrade/Celcuis
ina2xx.ampsCurrent in amps
ina2xx.shunShunt resistor in milli-ohms
ina2xx.voltBus voltage level
ina2xx.wattwattage reading
output.valThe result of an output calculation
veml6075.uvaUVA component
veml6075.uvbUVB component
veml6075.uviUV index



Thank you for visiting camelthorn.cloudHome