Page 1 of 1
Moving average of 200 readings
Posted: 24 Apr 2023, 17:05
by Zidanoff
Greetings! Right now I'm using the standard averaging of readings, but is it possible to get a moving average of 200 readings? Variables are limited to 16, so the problem is not trivial.
Code: Select all
Let,10,[VAR#9]
Let,9,[VAR#8]
Let,8,[VAR#7]
Let,7,[VAR#6]
Let,6,[VAR#5]
Let,5,[VAR#4]
Let,4,[VAR#3]
Let,3,[VAR#2]
Let,2,[VAR#1]
Let,1,%eventvalue2%
TaskValueSet,3,4,([VAR#1]+[VAR#2]+[VAR#3]+[VAR#4]+[VAR#5]+[VAR#6]+[VAR#7]+[VAR#8]+[VAR#9]+[VAR#10])/10
Re: Moving average of 200 readings
Posted: 24 Apr 2023, 18:59
by Ath
Zidanoff wrote: ↑24 Apr 2023, 17:05
Variables are limited to 16, so the problem is not trivial.
Nope, variables are limited only by the amount of memory available, but processing speed will be the biggest limiting factor, repeatedly processing those 200+ script lines will put quite some stress on the CPU (but it won't protest about that), making other tasks on that unit possibly delayed in execution.
Re: Moving average of 200 readings
Posted: 24 Apr 2023, 19:41
by TD-er
Are you using an ESP32 or ESP8266?
When using "stats" for task values, you can perform computations over upto N readings using those plugin stats.
N is 16 for ESP8266 and 64 for ESP32 due to memory limitations on ESP8266.
See:
https://espeasy.readthedocs.io/en/lates ... statistics
In recent code changes (not yet in an official build) you can also use this for Dummy tasks.
So maybe you could use some tricks to average over the last 200 samples from a task.
For example by adding every sample from a task to a dummy task value, but then modulo 4 to the next dummy task value.
Then you can simply use the average over the last 50 values for each task value of this dummy task to work with (assuming you're using an ESP32)
On ESP8266 this may be a bit tricky, but I guess you really don't need to have the exact 200 readings, but more like the average over the period of the last 200 reading?
Re: Moving average of 200 readings
Posted: 24 Apr 2023, 20:14
by TD-er
Just an idea for a relatively efficient moving average:
Code: Select all
on MyEvent do
// %v201% = average
// %v202% = last element
// %v203% = nr Elements
// %v204% = sum
if %v203% < 200
let,202,%v202%+1 // Update index of "last element"
let,203,%v203%+1 // Update nr Elements
else
let,204,%v204%-[var#%v202%] // Subtract oldest element from the sum
let,202,%v202%+1
if %v202% >= 200
let,202,0 // Index of "last element" should be modulo 200
endif
endif
let,%v202%,%eventvalue% // Store the new value in the array
let,204,%v204%+[var#%v202%] // Add new value to the sum
let,201,%v204%/%v203% // Average
endon
Not tested, just a quick dump of some idea I had when thinking about the question.
Re: Moving average of 200 readings
Posted: 24 Apr 2023, 20:37
by Ath
Did a small refinement of that code (in coordination with TD-er), making the number of elements configurable (but max. 200)
Code: Select all
on MyEvent do
// %v201% = max elements
// %v202% = last element
// %v203% = nr Elements
// %v204% = sum
// %v205% = average
if %v201%=0 // Not yet set?
let,201,200 // Set max number of elements, don't set > 200!!!
endif
if %v203% < %v201%
let,202,%v202%+1 // Update index of "last element"
let,203,%v203%+1 // Update nr Elements
else
let,204,%v204%-[var#%v202%] // Subtract oldest element from the sum
let,202,%v202%+1
if %v202% >= %v201%
let,202,0 // Index of "last element" should be modulo max elements
endif
endif
let,%v202%,%eventvalue1% // Store the new value in the array
let,204,%v204%+[var#%v202%] // Add new value to the sum
let,205,%v204%/%v203% // Average
endon
Major difference: Output average is available in %v205% (instead of 201)
Minor difference: No tabs used in the code (that somewhat confuses the code formatting)
Instead of the last 'let', you can also use:
Code: Select all
TaskValueSet,3,4,%v204%/%v203% // Average
Re: Moving average of 200 readings
Posted: 25 Apr 2023, 11:20
by Zidanoff
Many thanks to TD-er and Ath! Indeed, the option with statistics combined with a dummy device will work. Also, the tricky trick with variables works great! I am using ESP32.
Re: Moving average of 200 readings
Posted: 25 Apr 2023, 12:01
by TD-er
Great, so I guess we should add this rules example to the documentation.
Re: Moving average of 200 readings
Posted: 25 Apr 2023, 20:14
by Ath
I've created a PR
#4626 to add this as an example to the rules-documentation
Re: Moving average of 200 readings
Posted: 26 Apr 2023, 10:42
by Zidanoff
Your wonderful examples inspired to modify them a little so that everything works correctly when stepping over the maximum element. Otherwise, the last element from the sum was not removed and the error accumulated with each new transition cycle through the higher variable.
Code: Select all
on MyEvent do
// %v201% = max elements
// %v202% = last element
// %v203% = nr Elements
// %v204% = sum
// %v205% = average
if %v201%=0 // Not yet set?
let,201,200 // Set max number of elements, don't set > 200!!!
endif
if %v203% < %v201% // writes until the last element is filled
let,202,%v202%+1 // Update index of "last element"
let,203,%v203%+1 // Update nr Elements
else // writes after the first filling cycle starting from the number of the highest element
if %v202% = %v201% // “The last will be first, and the first last” (Matthew 20:16)
let,202,1 // Index of "last element" should be modulo max elements
let,204,%v204%-[var#1] // Subtract oldest element from the sum
else // new sequential write cycle
let,202,%v202%+1
let,204,%v204%-[var#%v202%] // Subtract oldest element from the sum
endif
endif
let,%v202%,%eventvalue1% // Store the new value in the array
let,204,%v204%+%eventvalue1% // Add new value to the sum
let,205,%v204%/%v203% // Average
endon
Re: Moving average of 200 readings
Posted: 26 Apr 2023, 11:26
by TD-er
Always really nice to see when the user finds bugs in the examples:
- Meaning they really understand it
- General improvement of the code/docs