Running Average Over 30- or N-Seconds?

Hi, I am not a programmer but just (an older) self-taught hobbyist, so please excuse my ignorance. I've struggled all evening trying to derive a 30- or N-second running average from an analog pressure sensor. I'm using the RunningAverage.h library but cannot seem to find any instruction for how to accomplish that.

So, I borrowed the below code that I found online. It produces a running average but one that seems verrrry languid and resistant to my attempts to change it. In other words, the average seems to compute over the same (long) period regardless of whether I change RA_HIST_SECONDS from 30 down to 5 or even increase it to 60. I'll add that it's not important whether we take, say, 60 samples per second or a few as 2 or 3; I mention this because I have a feeling the frequency is part of the caper here.

I'd like to be able to adjust RA_HIST_SECONDS up or down to elongate or shorten how long of a running average I'm keeping each time I upload the sketch. I feel like I'm missing something totally basic. I'd appreciate any help you can give a newbie. Thanks!

//pressure vars
int pressure;
int pressureForRA;
int avgPressure = 0;

// pin vars
int pressurePin = A0;

#include "RunningAverage.h"
#define OVERSAMPLE 4
#define ADC_MAX 1023
#define FREQUENCY 60
#define period (1000/FREQUENCY)
#define RA_HIST_SECONDS 30
#define RA_FREQUENCY 6
#define RA_TICK_PERIOD (FREQUENCY / RA_FREQUENCY)
RunningAverage raPressure(RA_FREQUENCY*RA_HIST_SECONDS);

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

void loop()
{
pressure = analogRead(pressurePin);

static int sampleTick = 0;
if (millis() % period == 0) {
delay(1);
sampleTick++;
if (sampleTick % RA_TICK_PERIOD == 0) {
raPressure.addValue(pressureForRA);
avgPressure = raPressure.getAverage();
}
pressureForRA=0;
for(uint8_t i=OVERSAMPLE; i; --i) {
pressureForRA = pressure;
if(i) {
delay(1);
}
}
}
Serial.print(pressure);
Serial.print(",");
Serial.println(avgPressure);
}

HalloweenRunningAvgPressureTest.ino (951 Bytes)

I looked through the code. I Never used the runningavarage-library.
I'm pretty good in mathematics but I did not get my head around it in some minutes.
So trying to help would mean to go and search for the documentation of the library.

I decided to not take this effort, because it is something you could provide as a link together with some demo-code that is running and you could provide serial output posted as a code-section so the others can see what the output looks like

best regards Stefan

When you are trying to filter out the vibrations of an airpump, then you need a mechanical damper.

So please tell us: What is your Arduino board ? Which pressure sensor is it ? What is your project ? Are there valves or long tubes and pressure peaks and is it with air or underwater and so on.

Tell us what you will do with the value of the pressure. Why do you need a average ? How much noise does it have ? Is the pressure value stored for a graph or is it only displayed and so on.

Here's a simple running average that samples 16 times in 400 ms and displays every 1 second.

unsigned long startTime, displayTime;
const byte numSamples = 16, // number of samples for smoothing
           aInPin = A0;
int total,
    endTime = 25,
    displayEnd = 1000,
    avg;           
void setup()
{
  Serial.begin(9600);
  analogRead(aInPin);
  for(int i = 0;i < numSamples;i++) // for smoothing, fill total
    total += analogRead(aInPin);   // with numSamples * current
  avg = total / numSamples;        // reading
}
void loop()
{
   if(millis() - displayTime > displayEnd)
   {
    displayTime += displayEnd;
     Serial.println(avg);
   }
   if(millis() - startTime > endTime)
   {
      startTime += endTime; // reset timer 
      total -= avg; // make room for new reading
      total += analogRead(aInPin); // add new reading
      avg = total / numSamples;
    }  
}

leaky integration

Avg += (samp - Avg) * K where K < 1

when K = 1/N, the average will become a constant samp value after ~3*N sample

#define PressurePin A1      // my hardware

#define ADC_MAX     1023.0
#define FREQUENCY   60
#define PERIOD      (1000/FREQUENCY)

#define K           (1.0 / 10)

float avgPressure = 0.123;
char  s [80];

void setup (void)
{
    Serial.begin (115200);

    pinMode (PressurePin, INPUT_PULLUP);    // using button my hardware

    avgPressure = analogRead (PressurePin) / ADC_MAX;
}

void loop (void)
{
    if (millis () % PERIOD == 0) {
        float samp = analogRead (PressurePin) / ADC_MAX;

        avgPressure += K * (samp - avgPressure);

        Serial.print   (samp);
        Serial.print   (", ");
        Serial.println (avgPressure);
    }
}

I use the SimpleKalmanFilter for data smoothing, GitHub - denyssene/SimpleKalmanFilter: A basic implementation of Kalman Filter for single variable models.

Whiles it is recommended of selecting a 'small' value for q does work, it's better to determine the amount of time passed since last calculation and update the q value before calculation. See posted example:

void TrackSun( void * pvParameters )
{
  log_i( "Startup TrackSun" );
  int64_t EndTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
  int64_t StartTime = esp_timer_get_time(); // but rolls over every 207 years.
  int Altitude = 1500;
  int Azimuth = 900;
  int maxAltitudeRange = 2144;
  int minAltitudeRange = 900;
  int maxAzimuthRange = 2144;
  int minAzimuthRange = 900;
  float AltitudeThreashold = 10.0f;
  float AzimuthThreashold = 10.0f;
  float kalmanThreshold = 80.0f;
  // initial q value setting as a small value, .01.
  SimpleKalmanFilter kfAltitude0( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 0
  SimpleKalmanFilter kfAltitude1( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 1
  SimpleKalmanFilter kfAzimuth0( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 0
  SimpleKalmanFilter kfAzimuth1( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 1
  float filteredAltitude_0 = 0.0f;
  float filteredAltitude_1 = 0.0f;
  float filteredAzimuth_0 = 0.0f;
  float filteredAzimuth_1 = 0.0f;
  uint64_t AzimuthEndTime = esp_timer_get_time();
  uint64_t AzimuthStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
  uint64_t AltitudeEndTime = esp_timer_get_time();
  uint64_t AltitudeStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
  int StartupCount = 0;
  int TorqueAmmount = 5;
  while (1)
  {
    if ( EnableTracking )
    {
      //Altitude
      AltitudeEndTime = esp_timer_get_time() - AltitudeStartTime; // produce elapsed time for the simpleKalmanFilter
      kfAltitude0.setProcessNoise( float(AltitudeEndTime) / 1000000.0f ); //q value being updated
      kfAltitude1.setProcessNoise( float(AltitudeEndTime) / 1000000.0f );
      filteredAltitude_0 = kfAltitude0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_6) );
      filteredAltitude_1 = kfAltitude1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_5) );
      if ( (filteredAltitude_0 > filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold))
      {
        Altitude -= TorqueAmmount;
        if ( Altitude < minAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      if ( (filteredAltitude_0 < filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold) )
      {
        Altitude += TorqueAmount;
        if ( Altitude >= maxAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      //// AZIMUTH
      AzimuthEndTime = esp_timer_get_time() - AzimuthStartTime; // produce elapsed time for the simpleKalmanFilter
      kfAzimuth0.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      kfAzimuth1.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      filteredAzimuth_0 = kfAzimuth0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_3) );
      filteredAzimuth_1 = kfAzimuth1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_0) );
      if ( (filteredAzimuth_0 > filteredAzimuth_1) && (abs(filteredAzimuth_0 - filteredAzimuth_1)) > AzimuthThreshold )
      {
        Azimuth += TorqueAmmount;
        if ( Azimuth >= maxAzimuthRange )
        {
          Azimuth = 900;
        }
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      }
      if ( (filteredAzimuth_0 < filteredAzimuth_1) && (abs(filteredAzimuth_1 - filteredAzimuth_0)) > AzimuthThreshold )
      {
        Azimuth -= TorqueAmount; // make new position to torque to
        if ( (Azimuth >= maxAzimuthRange) || (Azimuth <= minAzimuthRange) )
        {
          Azimuth = 900;
        }
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      } //azmiuth end
      if ( StartupCount < 500 )
      {
        ++StartupCount;
      } else {
        TorqueAmount = 1;
      }
    }
     vTaskDelay( 65 ); //non blocking delay.
  } // while(1)
} //void TrackSun()

Thank you to all for the thoughtful responses. I learned quite a bit working through your suggestions. In the end, it seems like the problem was the serial communication rate! At 9600 the printouts to monitor or plotter were not at all matching the 30-second length of the running average I am trying to keep. At 115200, they sync up perfectly. Any ideas how could I adjust my code so they sync up at 9600? Thanks again to all.