creating an average in arduino
Moderators: adafruit_support_bill, adafruit

creating an average in arduino

by otis on Tue Jul 21, 2009 11:13 pm

i need help with finding the average input of a sensor on my arduino how would i write it up in code otis
otis
 
Posts: 19
Joined: Sat Jul 11, 2009 4:03 pm

Re: creating an average in arduino

by s133p on Wed Jul 22, 2009 12:31 am

The basic process i would use is to define an array for a series of readings, then you make all the readings:

Code: Select all | TOGGLE FULL SIZE
int readings[5]
int i;
for(i=0; i<5; i++){
readings[i] = analogRead(sensorPin);
}

int avgReading = (readings[0] + readings[1] + readings[2] + readings[3] + readings[4])/5;


That should give you an idea of what you need to do. Obviously you need to make that work with your current code. One thing you also probably want to change is the delay between the readings to give you a more meaningful average. Hope that helps!
s133p
 
Posts: 9
Joined: Wed Jul 15, 2009 12:37 am

Re: creating an average in arduino

by Zener on Wed Jul 22, 2009 1:37 am

Another way is keep adding succesive reads to a total. Increment a counter every time you add a read. At some point divide the total by the counter.
Zener
 
Posts: 2537
Joined: Sat Feb 21, 2009 1:38 am

Re: creating an average in arduino

by mtbf0 on Wed Jul 22, 2009 8:58 am

if your number of samples happens to be power of two you can use a shift instead of a divide and save a hell of a lot of time. i.e.

Code: Select all | TOGGLE FULL SIZE
  reading = 0;
  for (i=0; i<4; i++) {
    reading += analogRead(sensorPin);
  }
  reading >>= 2;
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1645
Joined: Fri Nov 09, 2007 11:59 pm
Location: oakland ca

Re: creating an average in arduino

by Zener on Wed Jul 22, 2009 12:06 pm

mtbf0 wrote:if your number of samples happens to be power of two you can use a shift instead of a divide and save a hell of a lot of time. i.e.

I wondered about that. I assume you are talking processor cycles? How much faster is it? How much smaller does it make your code?
Zener
 
Posts: 2537
Joined: Sat Feb 21, 2009 1:38 am

Re: creating an average in arduino

by fat16lib on Wed Jul 22, 2009 1:23 pm

The division time doesn't matter. The Arduino analogRead() takes about 100 microseconds. The Arduino library uses an ADC prescaler of 128 and it takes 13 ADC clocks for a normal conversion so that is 1664 cpu clocks.

You might save a few bytes of flash for the divide but not enough to really matter.

Edit:
I tried several cases and the shift is generally bigger

This takes 1828 bytes:
Code: Select all | TOGGLE FULL SIZE
void setup()
{
  Serial.begin(9600); 
  uint8_t n = 4;
  uint16_t v = 0;
  for (uint8_t i = 0 ; i < n; i++) {
    v += analogRead(0);
  }
  v = v >> 2;
  Serial.println(v);
}

void loop(){}


This takes 1794 bytes (note n = 5):

Code: Select all | TOGGLE FULL SIZE
void setup()
{
  Serial.begin(9600); 
  uint8_t n = 5;
  uint16_t v = 0;
  for (uint8_t i = 0 ; i < n; i++) {
    v += analogRead(0);
  }
  v = v/n;
  Serial.println(v);
}

void loop(){}


But this take 1828 bytes (note n = 4):
Code: Select all | TOGGLE FULL SIZE
void setup()
{
  Serial.begin(9600); 
  uint8_t n = 4;
  uint16_t v = 0;
  for (uint8_t i = 0 ; i < n; i++) {
    v += analogRead(0);
  }
  v = v/n;
  Serial.println(v);
}

void loop(){}


Who knows what the compiler will do!
fat16lib
 
Posts: 593
Joined: Wed Dec 24, 2008 12:54 pm

Re: creating an average in arduino

by macegr on Thu Jul 30, 2009 1:42 pm

A simple way to do a moving average is to use floating point math.
Code: Select all | TOGGLE FULL SIZE
float adcResult = 0;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  adcResult = adcResult * 0.95 + analogRead(0) * 0.05;
  Serial.println(adcResult);
  delay(50);
}

It's computationally a little heavier but gives pretty good results. The filter above is similar to a 20-point moving average, meaning that changes will appear instantly on the output, but will be moderated by previous values. It's good when you want smoothed values with minimal lag; you don't have to wait to collect 20 samples, you just throw away a small piece of the old value and add in a small piece of the new value.

You could do this with integers too, 7*adcResult + analogRead(0) and then divide by 8 or shift right by 3. You just have to make sure not multiply by too much or you'll have to switch to longs.

A true moving average, based on a rolling buffer, does have some advantages too. You can decide how to weight older values, or try to throw away outlying data points from sporadic noise. But it does use up more memory.
macetech LLC - http://www.macetech.com
User avatar
macegr
 
Posts: 288
Joined: Fri Apr 04, 2008 3:46 pm