A running average for a pressure sensor.

Hey everyone,

I have a pressure sensor that is being used dynamically with moving air. As a result, the values can be erratic between different airspeeds, but the averages give good read outs.

I am not sure if a running average is the right way to go, I have not used it with Arduino.

What I would like to do is take a certain amount of values read from the pressure sensor(lets say 20, but the more the better) and take an average. Then, the 20 readings would restart for another average.

How do I go about this, or is code already done for this?

Thanks for any help!

Sam

This is where I am as of now with my code. Normally it reads fine to the serial monitor in pascals, however my new coding has somehow messed up that value and I cannot figure out why.

#define PRESSURE_PIN A1

int ADCvalue;
float pressureValue;

void readPressure()
{
ADCvalue=analogRead(PRESSURE_PIN);
pressureValue= ((ADCvalue/1024.0)+0.095)/0.000009;
}

void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println(“pascals”);

}
void loop()
{

readPressure();

static int currentSample; //current sensor sample
static int currentValue; // current sensor value

// current value works as a sum counter
currentValue = 0;

//get sensor samples with delay and calculate the sum
for (int i = 0; i < 30; i++) {
// get sensor sample.
currentSample = pressureValue;

// add sample to the sum counter.
currentValue += currentSample;

// delay some time for the next sample.
delay(10);
}

//get the average sensor value (ignore the fraction).
Serial.print(currentValue / 30);

}

simple running average
ave=ave*.9 + new_reading*.1;

readPressure should return a value, not use a global.
Simply summing the same value over and over again is pointless.

You will have to move the call to readPressure() to inside the loop if you want to average 30 DIFFERENT readings. The current design is averaging the same pressureValue 30 times. It would be clearer if you returned a value from the readPressure() function:

float readPressure() {
  ADCvalue=analogRead(PRESSURE_PIN);
  return ((ADCvalue/1024.0)+0.095)/0.000009;
}

Then you can eliminate the global “pressureValue” and call the function when you want a new value:

    long averageValue = 0; // current sensor value
   
    //get sensor samples with delay and calculate the sum
    for (int i = 0; i < 30; i++) {
    // add sample to the sum counter.
    averageValue += readPressure();

    // delay some time for the next sample.
    delay(10);
  }
  averageValue /= 30;

You seem to be mixing integers and floats. What sort of values are you expecting? It looks like your minimum value is 10555. An ‘int’ can only go up to 32767 so if your samples average more than 1092 your integer will overflow when you add 30 of them together.

Ok, I tried using what you recommended, but I was given an error message:

sketch_apr01f.ino: In function ‘void loop()’:
sketch_apr01f:19: error: a function-definition is not allowed here before ‘{’ token
sketch_apr01f:35: error: void value not ignored as it ought to be
sketch_apr01f:35: error: in evaluation of ‘operator+=(long int, void)’

The ADC value from the sensor is between 800-900. After conversion, its supposed to be in pascals.

#define PRESSURE_PIN A1

int ADCvalue;

void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println(“pascals”);

}
void loop()
{

float readPressure() {

ADCvalue=analogRead(PRESSURE_PIN);
return ((ADCvalue/1024.0)+0.095)/0.000009;
}

long averageValue = 0; // current sensor value

//get sensor samples with delay and calculate the sum
for (int i = 0; i < 30; i++) {

// add sample to the sum counter.
averageValue += readPressure();

// delay some time for the next sample.
delay(10);
}
averageValue /= 30;

//get the average sensor value (ignore the fraction).
Serial.println(averageValue);

}

a function-definition is not allowed here

Massive clue there.

Well I changed some curly braces, but received a new error:

sketch_apr01f.ino: In function ‘void loop()’:
sketch_apr01f:22: error: return-statement with a value, in function returning ‘void’

#define PRESSURE_PIN A1

int ADCvalue;
float pressureValue;

void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println(“pascals”);

}
void loop()
{

float readPressure();

ADCvalue=analogRead(PRESSURE_PIN);
return ((ADCvalue/1024.0)+0.095)/0.000009;

long averageValue = 0; // current sensor value

//get sensor samples with delay and calculate the sum
for (int i = 0; i < 30; i++)

// add sample to the sum counter.
averageValue += readPressure();

// delay some time for the next sample.
delay(10);

averageValue /= 30;

//get the average sensor value (ignore the fraction).
Serial.println(averageValue);

}

return-statement with a value, in function returning 'void'

And there's another masseeve clue

void loop()
  {
    
    float readPressure();

  ADCvalue=analogRead(PRESSURE_PIN);
  return ((ADCvalue/1024.0)+0.095)/0.000009;

hey M8 here is a simple running average of a potentiometer, it can be adjusted for pressure I'im sure.

They don't teach you C or java in your engineering 1st and 2nd years? I guess maybe they're throwing matlab at you?

The issue you're getting is from including a 'return' statement inside a function block (in your case main) that has a void return type - as AWOL and your compiler are trying to suggest: that don't make sense :slight_smile:

My suggestion is to follow racpi's advice and use a simple running average filter - my implementation is:

double LPF(double newSampleValue, double oldAverage, double alpha){
                return =  oldAverage + alpha * (newSampleValue - oldAverage);
}

A better version uses references to the original data and a void return type, but I omitted that for clarity.

The 'alpha' value should be between 0 and 1 - 0 will give you no change, 1 will (eventually) return the newSampleValue itself with no 'historical' effect from the oldAverage, so by varying it to say 0.9 (like in racpi's version) you'll have a reasonable 'trust' of newSampleValue but with a little left over from the oldAverage, this effectively is a Low Pass Filter, which is exactly what you want to get rid of noise. The price you pay is a delay or lag in the signal (hence PI controllers and LPF are sometimes referred to as 'phase lag').

More complex are running averages with 'windows' larger than one sample (more inherent lag, but smoother response). Even more interesting is a Kalman filter, that automagically adjusts alpha on the fly according to some mathy carry on - but given no 'dynamics' information a Kalman filter will collapse into a vanilla LPF itself. So you could say that you were actually running a first order Kalman filter (or zeroth? only just woke up, I forget which)

But don't let my technical #ank talk scare you - just look at the function, try an alpha of 0.9, write down a series of measurements on paper, e.g. 0,1,2,11,4,7,8,10,10,10,20,10,5,0 then run the code yourself, see what happens to the numbers - then try an alpha of 0.5 with the same series, note the differences.
(init the oldAverage as 0)
pretend like the 11 and the 20 were 'noise'
Pretty neat huh?