help with average calculation and arrays

Hi,

I have a few sensors and for each of them I need to calculate the average. For each sensor I'm using an array to store the last 10 read values and updating it whenever the new incoming value is read.

However it looks to me that there's something wrong as I am not obtaining correct values in the end but I cannot spot the bug. At the moment I have 3 sensors (I'll have 20 at the end).
Help?

thank you :slight_smile:

const byte SENSORS = 3;

int sensors[SENSORS];

int readings[SENSORS];

int arrays[SENSORS][10];
 
float avgs[SENSORS];

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

  // arrays init
 for(int i = 0; i < SENSORS; i++){
   for(int j = 0; j < 10; j++)
      arrays[i][j] = 0;
      
   sensors[i] = i;
   readings[i] = 0;
   avgs[i] = 0.0;
 }
 
} //setup


void loop() { 
  int i = 0;
  int int_avgs[SENSORS] = {0, 0, 0};

  //read from sensors
  for(int x = 0; x < SENSORS; x++)
    readings[x] = analogRead(sensors[x]);
  
  //sum values
  for(;i<10;i++){
    for(int j = 0; j < SENSORS; j++)
    avgs[j] += arrays[j][i];
  }

  //calculate avg
  for(int z = 0; z < SENSORS; z++)
    int_avgs[z] = (int)avgs[z]/10;

  
  Serial.print(readings[0]);
  Serial.print(" - ");
  Serial.print(readings[1]);
  Serial.print(" - ");
  Serial.println(readings[2]);
  Serial.println();
  delay(100);
 

//shift array
  for(int y = 0; y < SENSORS; y++){
    arrShift(arrays[y], 10);
    arrays[y][9] = readings[y];
  }

  // update with incoming readings
  for(int a = 0; a < SENSORS; a++)
    arrays[a][9] = readings[a];


  //reset avgs
  for(int q = 0; q < SENSORS; q++)
    avgs[q] = 0; //reset

}

void arrShift(int *a, int n) {
  int i;
  for(i=0;i!=n-1;i++)
  *(a+i)=*(a+i+1);
}

I have 3 sensors (I'll have 20 at the end).

On which Arduino are you planning to read 20 analog sensors?

You are aware, are you not, that there is only one analog to digital converter? Reading two different pins with no delay between readings often results in garbage readings. The usual solution is to read the pin twice and discard the first reading.

What do your serial prints tell you is happening? Why don't you have any?

you can try to use a circular buffer for the three sensors

I made a little class you can try, I tested this and I think it may do what you want:

#include "CircularBuffer.h"

#define SENSOR_COUNT 3
#define READINGS 10

CircularBuffer *sensorReadings[SENSOR_COUNT];  // create a global array of pointers to CircularBuffer objects

byte sensor[] = {A0, A1, A2};

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < SENSOR_COUNT; i++)
  {
    sensorReadings[i] = new CircularBuffer(READINGS);  // Constructor call makes buffers of size = READINGS
  }
}

void loop()
{
  for (byte i = 0; i < SENSOR_COUNT; i++)
  {
    analogRead(sensor[i]);
    sensorReadings[i]->addElement(analogRead(sensor[i]));
  }
  for (byte i = 0; i < SENSOR_COUNT; i++)
  {
    Serial.print(F("Sensor "));
    Serial.print(i);
    Serial.println(F(" readings:"));
    Serial.print("\tAverage: ");
    Serial.println((int)sensorReadings[i]->mean());
    Serial.print("\tAverage of ");
    Serial.print(sensorReadings[i]->numElements());
    Serial.println(F(" readings"));
  }
  delay(5000);
}

header file (CircularBuffer.h):

#ifndef CircularBuffer_h
#define CircularBuffer_h

#include <Arduino.h>

class CircularBuffer {
  public:
    CircularBuffer(size_t size);
    void addElement(float newElement);
    float mean();
    float maxVal();
    float minVal();
    float sigma();
    size_t numElements();
    float arrayElement(int location);

  private:
    float* array;
    float* next;
    size_t size;
    int index = 0;
    int num_elements = 0;
};

#endif

implementation file (CircularBuffer.cpp):

#include "CircularBuffer.h"
#include <Arduino.h>

CircularBuffer::CircularBuffer(size_t arraySize)
{
  size = arraySize;
  array = new float[arraySize];
  next = &array[0];
}

void CircularBuffer::addElement(float newElement)
{
  *next = newElement;
  index++;
  if (index >= size)
  {
    index = 0;
  }
  next = &array[index];
  if (++num_elements > size)
  {
    num_elements = size;
  }
}

float CircularBuffer::arrayElement(int location)
{
  return array[location];
}


float CircularBuffer::mean()
{
  float average = 0;
  for (int i = 0; i < num_elements; i++)
  {
    average += array[i];
  }
  return average / num_elements;
}

size_t CircularBuffer::numElements()
{
  return num_elements;
}

float CircularBuffer::maxVal()
{
  float maximum;
  for (int i = 0; i < num_elements; i++)
  {
    if (i == 0)
    {
      maximum = array[0];
    }
    else if (array[i] > maximum)
    {
      maximum =  array[i];
    }
  }
  return maximum;
}
float CircularBuffer::minVal()
{
  float minimum;
  for (int i = 0; i < num_elements; i++)
  {
    if (i == 0)
    {
      minimum = array[0];
    }
    else if (array[i] < minimum)
    {
      minimum =  array[i];
    }
  }
  return minimum;
}
float CircularBuffer::sigma()
{
  float average = mean();
  float sigma = 0;
  for(int i = 0; i < min(size, num_elements) ; i++)
  {
    sigma += ((array[i] - average) * (array[i] - average));
  }
  return sqrt(sigma / min(size, num_elements));
}

put both files in the same directory as your sketch to compile.