## moving average on micro controller...

20 posts / 0 new
Author
Message

ok so I am trying to do moving average on voltage and current values for my bldc motor circuit...

I have an array of 8 elements for both the analogues...Its arranged as a FIFO, with indexes being incremented and capped by modular arithmatic.

I am getting average value that is less than what I expected...

Basically I have Sum_n = Sum_(n-1) + NewValue - EarliestValue.

The above formula makes sure the oldes value is dropped and new value is added to the FIFO sum. I then calculate:

Avg_n = Sum_n/8

It seems if I do Avg_n = Sum_n/7, I would get the currect figure. Am I missing something? I initialize the array with zero values to start with... :|

luvocean1 wrote:
Basically I have Sum_n = Sum_(n-1) + NewValue - EarliestValue.
Why "n-1"? Doesn't that mean
7 values + 1 value - 1 value = 7 values
?

Stefan Ernst

Quote:

Basically I have [...]

An essay on "what you have" will not help us find bugs in your code. Show real code, and we can dig into it!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

hhm... i took a pen n paper n it seems I am only summing over 7 items... since when the 8th one comes in, it is added and then the first most one is deducted...so effectively I get the sum of 7 items.... hhm.. deviding by 7 is not desirable...

See AVR222 .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

sorry n-1 was placed there to represent the sum from previous calculation.

Ok so as per above explanation it looks like I was operating on 7 items...the 8th item was really having no effect as it was being added the 0th item was being removed...so the sum remained summed over 7 items effectively. So to come up with an average figure I would have had to devide by 7.

In order to avoid this, need to make sure my sum spans over all 8 items...for this I adopt a new policy, which is to consider a FIFO of 8 items. So I sum like this:

Sum_k = Sum_(k-1) - OldItem at my current index.
Sum_k += Array[CurrentIndex]

This sum now has sum of all previous 7 items and the new adc value.

So it seems to be working now :)

You have a collection of eight intdividual values at any time - e.g. in a circular buffer.

You have a sum of those eight values at any time.

When a new value "arrives" you
1. Subtract the oldest value from the collection of values.
2. Insert the newly arrived value in its place.
3. Add the newly arrived value to the sum.
4. Set the "pointer" to the oldes value one position forward from the value you just inserted.

Rolling average is the sum divided by eight (i.e. >>3).

EDIT: Sketchy, untested:

```int rollingAverage(int newValue)
{
static int values[8];
static int nextPosition;
static int sum;

sum -= values[nextPosition];
sum += newValue;
values[nextPosition] = newValue;
nextPosition++;
return sum/8;
}```

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Do you remember back in the 50's and 60's the fathers of computing (Wirth, Knuth, Dijkstra, Turing, etc) analysed just about every "common" task you might do in computing and wrote down well thought out algorithms for various implementations of each one? Do you think they might have thought of looking at rolling averages? I wonder...

If not them I bet 100,000+ engineers have considered the problem since (perhaps 1,000,000+ ? or even 10,000,000+ ?)

I smell a hint of wheel re-invention here ;-)

lol Johan thanks your solution is what I showed in my last post :)

The issue was in getting the "oldest" item from the FIFO. If this is the 0th (which is the 8th item, wrapped around) Item then the sum and avg occurs on 8 items. Whereas if the oldest item was based on a FIFO of (n-1) element (which was the case with my first implementation) then we need to be careful as the sum and avg occurs on 7 items. Thats where I went wrong :)

Clawson, when it comes to algorithms, I am never happy, I always think we can do better, regardless of how many engineers tried it before, including me. I wonder if there is such a thing as "best" algorithm. I am alway searching for one for every problem I come across. :)

'Best' algorithm is mostly likely the algorithm that fits the needs best. Sometimes that's just an average of two readings, sometimes an eloborate multistage IIR filter, maybe a Kalman filter. If you know upfront that list is almost always already sorted, a simple bubble sort is the best instead of a more complex shell- or quicksort.

For speed it's usually a trade of between complexity and memory requirements. If you need a compact CRC32 routine, you won't use an algorithm that uses a 256 entry lookup table, but if you need speed you can't do without.

For smoothing I usually use an exponential filter.

Quote:
then we need to be careful as the sum and avg occurs on 7 items. Thats where I went wrong

Also known as a fence post error or off-by-one error. I guess that happens to all of us every now and then ;)

This compiles on my mt128 using iccv7avr. Edit: in the readadchan routine, replace ADSC with (1 << ADSC) in 2 places. (Guess I'd better compile and run this stuff before I post it...)

## Attachment(s):

Imagecraft compiler user

Last Edited: Sat. Nov 12, 2011 - 04:56 PM

Quote:

I wonder if there is such a thing as "best" algorithm. I am alway searching for one for every problem I come across.

The engineering principle is to find one that is good enough, but not more than that.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

In an embedded app, the best moving average will be tailored/adapted to match the application. If the signal is 'a little jittery' then moving avg over 8 or 16 samples might be a good compromise between response time and bits of dither. It also must run fast and not use too much space. Crikey! Where can I find this great piece of c source? (hint: its 2 messages up)

Imagecraft compiler user

A median filter might work well if the input is otherwise nice and stable but suffers from spikes (salt and pepper noise).

I like a three point filter, for some applications.

` fp = (p[n] + p[n+1]<<1 + p[n+2])>>2;`

It all starts with a mental vision.

I have also done it this way:

```avg = ( avg * 6 + new_reading ) / 7;
```

This method reduces storage requirements.

Jeff Dombach, JLD Systems
"We do the stuff behind the buttons!"
Your source for embedded solutions with a 100% Guarantee.
http://www.jldsystems.com
Phone 717.892.1100

That's an exponential filter, I use them too.

jldsystems wrote:
I have also done it this way:

```avg = ( avg * 6 + new_reading ) / 7;
```

This method reduces storage requirements.

That is essentially an IIR filter, isnt it?

Yn = {A*X_(n-1) + B*X_n}/(A+B)

Where A = 6 and B = 1.
I use it for my BLDC commutation timer computation...like shown in AVR444 I think it was...