creating an average in arduino

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
otis
 
Posts: 19
Joined: Sat Jul 11, 2009 5:03 pm

creating an average in arduino

Post by otis »

i need help with finding the average input of a sensor on my arduino how would i write it up in code otis

s133p
 
Posts: 9
Joined: Wed Jul 15, 2009 1:37 am

Re: creating an average in arduino

Post by s133p »

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

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!

User avatar
zener
 
Posts: 4567
Joined: Sat Feb 21, 2009 2:38 am

Re: creating an average in arduino

Post by zener »

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.

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: creating an average in arduino

Post by mtbf0 »

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

  reading = 0;
  for (i=0; i<4; i++) {
    reading += analogRead(sensorPin);
  }
  reading >>= 2;

User avatar
zener
 
Posts: 4567
Joined: Sat Feb 21, 2009 2:38 am

Re: creating an average in arduino

Post by zener »

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?

User avatar
fat16lib
 
Posts: 595
Joined: Wed Dec 24, 2008 1:54 pm

Re: creating an average in arduino

Post by fat16lib »

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

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

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

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!

User avatar
macegr
 
Posts: 293
Joined: Fri Apr 04, 2008 4:46 pm

Re: creating an average in arduino

Post by macegr »

A simple way to do a moving average is to use floating point math.

Code: Select all

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.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”