Stamp logic to find maximum and minimum of several values
mica
Posts: 23
I setup a test device for a TSL230 light sensor (not that relevant to the question). For a given light input I would like to take 10 reads then have the stamp output the average, maximum and minimum.
Average is easy, or at least straightforward in that I can add up the 10 reads then divide by 10. But is there any shortcut to the logic of finding the max/min for the 10 reads?
I can see taking one number then comparing it to another with a series of < or > commands to ‘filter’ for the max. But this seems kind of… tedious is one word, and really eats into the memory.
Any suggestions?
Average is easy, or at least straightforward in that I can add up the 10 reads then divide by 10. But is there any shortcut to the logic of finding the max/min for the 10 reads?
I can see taking one number then comparing it to another with a series of < or > commands to ‘filter’ for the max. But this seems kind of… tedious is one word, and really eats into the memory.
Any suggestions?
Comments
Min so far, max so far, total so far, and count.
And the new measurement, of course.
Start by setting min to MAX_INT, max to MIN_INT, total and count to zero.
For each measurement:
If greater than max, save in max.
If less than min, save in min.
Add to total.
And increment count by one.
Personally, though, I'd consider an exponentially-decayed moving average.
You've seen moving averages on the stock market pages of the newspaper - a figure showing 20-day moving average would chart for each day the average of the previous 20 days' stock prices,
An exponentially-decayed moving average is similar, but instead of averaging a fixed number of measurements, it averages all measurements, but gives them different weights according to an exponentially decreasing function. Most recent measurements count the most, older ones less.
The forum software seems to lack the basic mathematics symbols, so we'll skip all of that, but what makes this computationally simple is that the ratio between one period's average and that period's contribution to the next period's average is fixed.
You only need one variable to hold the average, plus the variable that holds the measurement.
For each new measurement, you add to the previous average a fraction of the difference between it and the previous average. Working pen-and-paper, accountants used to use 1/10th as the fraction because it's easy.
The moving average will lag behind changes in the measurement - if the measurement suddenly and permanently increases, the average will gradually increase, and will eventually reach the measurement. It will wash out spikes - a single spurious measurement will move the average only slightly.
The larger the fraction, the less the lag and the more influence spikes will have. If the fraction is 1, you're doing no averaging at all.
The two aspects you control are how often you take the measurement, and how large the fraction is. Both will need to be tuned to your particular environment.
Regarding the exponentially-decayed, I didn’t give you enough information on what I’m doing. Your suggestion is appropriate for an average take over time… or I guess frequency as well. I’m looking for accuracy or predictability for one set of conditions.
What I’m working on is an AOA (Angle of Attack) sensor. An air vain moves a ‘light valve’, if you will. So depending on the position of the fin in the air the light sensor will see more or less light. My need for the max/min is that for a given setting or a given angle of attack, I want to see how much variation I get. So if the max/min overlap a previous set of reads for the angle before or after, I know I still have some work to do. Once I get a constant change in reading and the ‘noise’ doesn’t overlap the reads before and after, I’m done…. and I can go work on something fun[noparse]:)[/noparse]
Thanks again. Good info.
maxvalue var word
minvalue var word
value var word
maxvalue=65530 ' > or max expected value
miinvalue=-65530 ' < or min expected value
do
'calculate value...
if value>maxvalue then maxvalue=value
if value<minvalue then minvalue=value
.
.
.
loop
First, you want your minvalue to be initialized to something larger than any possible measurement, and your maxvalue to something smaller. You have it the other way round.
And second, the values you're using are wrong. Words in Stamp Basic are 16-bit unsigned integers.
Should be:
maxvalue=0
minvalue=65535
It may seem strange to use the MIN operator to keep the maximum and MAX to keep the minimum, but that is the way it works. The operators are more like a floor and a ceiling: If the value is above the current floor, then move the floor up, and if the value is less than the current ceiling, move the ceiling down. You can read about MAX and MIN in the Stamp manual. The operators are commutative, that is, x MAX y = y MAX x.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com