Fast Averaging in PASM
Philldapill
Posts: 1,283
I've got a really nice ADC object for the TLV2543 from TI. The driver was written by Tim Moore, but I'd like to change it up a little. First off, the driver keeps an average of every channel. Basically, it gets the last "average", multiplies it by 7, adds the new sample to it, then divides the total by 8. I don't like this kind of average because it takes a while for the true average value to stabilize. What I have in mind, is to keep a running average - i.e. a buffer of the last 8 samples.
I think I've got the concept down, but I'm just wondering if there is a faster way to do it. In my approach, the last 8 samples would be stored in contiguous memory blocks, call them $00, $01, $02...$07. My approach would be to move the sample in block $01 into block $00(dumping the sample in $00), then moving $02 into $01, etc... $07 into $06, then move my new sample into $07. Once I have the updated sample list, I would add all 8 samples, and shift right three bits to divide by eight. Is there a faster/better way to do this?
I think I've got the concept down, but I'm just wondering if there is a faster way to do it. In my approach, the last 8 samples would be stored in contiguous memory blocks, call them $00, $01, $02...$07. My approach would be to move the sample in block $01 into block $00(dumping the sample in $00), then moving $02 into $01, etc... $07 into $06, then move my new sample into $07. Once I have the updated sample list, I would add all 8 samples, and shift right three bits to divide by eight. Is there a faster/better way to do this?
Comments
·
Why·move the values from 01-->00 ... 02-->01 ... etc.. in the first place?· Just keep a pointer where you’re writing in the·most recent sample.
·
The Average doesn't care what order the numbers are in... Just add them all together and divide.· If you use a buffer that is a power of two, then all you need is a·shift instruction for the division after you add the numbers.
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tom
-Phil
When doing this type of averaging, whether the exponential smoothing filter or the window average, I like to maintain the integer accumulator at a multiple of the input value. This helps to maintain precision or also to improve the resolution if desired due to the interpolation effect. If done in floating point, all the extra digits of precision allow the average to slop around. But with integer math, it is easier to go down than to go up and that introduces a bias. For example, suppose the value has been 100 for a long time, and suddenly changes to 101. If the window is 8 readings long, the entire buffer will have to fill with 101 before the average (with integer division /8) jumps up to 101. But on the way down, if the buffer is full of 101s, it only takes one 100 to make the resulting average to jump back down. There is a similar effect with the exponential filter. Instead, initialize the accumulator with at least 8 times the initial value. Then take the accumulator * 7/8 and add the new value. The state of the accumulator effectively has three fractional bits that can slop around or can be used for interpolation. The more extra bits the better.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com
If you OR %0100 with %0010, you get %0110. This is essentially turning a certain bit to a 1.
If you "andn" %1101 with %0010, you get %1111 which toggles the bit. If you andn again on the result, you get the original binary number.
Since I know how to toggle, and turn on a certain bit, how do you turn OFF a bit? i.e. set it to zero regardless of the state?
andn is what you use to clear a bit: given destination %1111 and source %0010, andn leaves %1101 in the destination.
INITIALIZE THE VARIABLES
for i = 0 to 7
buffer(i)=0
next i
sum = 0
average = 0
READ AND CALCULATE THE AVERAGE
and i %0111
sum = (sum - buffer(i)) + adcreading
buffer(i) = adcreading
average = ( sum + 4 ) >> 3
i = i + 1
EDIT: Is this what I'm looking for?
············· test····· datainm,ina············ wc····· 'read > 250ns (Td(I/O-Data)) after clock low
············· rcr······ datain,#1······················ 'read LSB, ends up in top 12 bits
Post Edited (Philldapill) : 4/17/2009 1:21:30 AM GMT
you have the right idea... set the pin mask so that it is all "zeros" except for the pin you are interested in
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/17/2009 2:53:41 PM GMT