Find average in an array (SPECIAL)

Hi Community, this is a special kind of averaging.

I am thinking of this, but am not sure if there is a program possible to implement this:
My data array will look something like:

| Item1 1000 |
| Item2 1500 |
| Item2 1510 |
| Item3 2000 |
| Item3 1900 |
| Item2 1508 |
| Item1 1050 |
| Item1 1010 |

Then the results I am looking for is:

AvgItem1 = 1020
AvgItem2 = 1506
AvgItem3 = 1950

Thanks in advance!

There are plenty of ways to do it but the Arduino UNO it probably not a good place to do it unless your total data size is quite limited. Where is the data coming from? Where are the results going? How many data items do you need to support? How many categories? What’s the average and maximum size of a category name?

per item you need an identifier, a sum and a count. That is 4 -16 bytes (assumption).

As the Arduino has approx 1800 bytes RAM free you can have between 100 - 300 items max and let the Arduino
calculate the average.

Do you know the number of items before you get the data?

It’s not rocket science - try something like this (typed here, untested)

enum dataType : byte {item1 = 0, item2, item3, maxItems};

struct measure_t {
  dataType type;
  int value;
};

measure_t measures[] = {
  {item1, 1000},
  {item2, 1500},
  {item2, 1510},
  {item3, 2000},
  {item3, 1900},
  {item2, 1508},
  {item1, 1050},
  {item1, 1010},
};

const uint16_t nbMeasures = sizeof(measures) / sizeof(measures[0]);

int32_t  measureSum[maxItems]  = {0L};
uint16_t measureCount[maxItems] = {0};

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

  for (uint16_t i = 0; i < nbMeasures; i++) {
    measureSum[measures[i].type] += measures[i].value;
    measureCount[measures[i].type]++;
  }

  for (byte i = 0; i < maxItems; i++) {
    if (measureCount[i] != 0) {
      Serial.print(F("Average for Item"));
      Serial.print(i+1);
      Serial.print(F(" = "));
      Serial.println(measureSum[i] / measureCount[i]);
    } else {
      Serial.print(F("No measure exists for Item"));
      Serial.println(i+1);
    }
  }
}

void loop() {}

the serial console set at 115200 bauds should print whatever is the real average for each item…

of course you need to listen to @robtillaart advice and ensure you have enough memory for what you want to achieve

As @johnwasser says, storing the data if this is just to compute the sum and average later on is not a good idea. Just sum them in a variable as they come (a bit like I do in the code above) and count how many you got for each bucket as they come in and then you don’t have a memory constraint (make sure you use the right data type able to represent the sum of all the samples correctly)

Thanks for the replies johnwasser and robtillaart!

The data will come in from an external radio connected through the Serial Port, as well as a Pixhawk's altitude through an Analog Port. Unfortunately I'm stuck with the UNO for this project.

As for the data location, is it alright for me to leave it in SRAM? The UNO will be constantly powered by the Pixhawk drone's battery, but when it lands, UNO will be connected to a computer by USB to run a sketch for this program to find the averages.

Lastly, each Item are labelled as "bikeObike1" , 2, 3, so on.. I am expecting a max of 5 items with no more than 6 rows of data each. The data array will be in the 2 columns shown, and from what i just mentioned, max of 30 rows.

Thank you J-M-L as well!

I'm looking through and trying to understand the code you posted. Thanks for the help, I will update

I would suggest using a Teensy 3.5 and do the datalogging on the native SD card slot. You can then do averaging on your computer. Easy.

Plus, the Teensy 3.5 is better than any regular Arduino IMHO. Faster, better ADC, more memory, etc.

AdrianCFL:
Thank you J-M-L as well!

I'm looking through and trying to understand the code you posted. Thanks for the help, I will update

Did you try to run it ? Curious to see if that works :slight_smile:

Yes J-M-L, I just tried it, it works well! You're pretty good at this!

Just to check, this code requires me to input the S/N of my items in the first line?
Also, if i have another sketch which writes its data to an array in SRAM, does this code read from the SRAM as well?

If you would like, I can elaborate more on how this project actually works.

Thank you!

Good

This is just a demo code

of course I would expect you to have non static data defined at compile time and acquire the data at run time - similqrr code will work as long as

  • your array is large enough to hold your samples
  • you maintain an index of where is the last data
  • you don’t write data past the end of the array
  • you don’t go past this end of good data index to calculate the averages (my code uses the full array because I know it’s full)

Give it a try and share back

Hi J-M-L, thank you for your help around 2 weeks ago on this forum,

I have updated the code but I am not sure if i am doing this correctly.

uint8_t numOfFloor = {12};      // Input number of floors
// Declare item1, item2, item3, etc. (Do Not Remove "maxItems")
enum {bikeObike1 , bikeObike2, bikeObike3, bikeObike4, maxItems};


String dataIn;                  // String to temporarily store data from UART
int cueToOutput = 8;            // Pin 8 indicates drone has landed
int altInput = 4;               // Pin 4 used for Altitude input from pixhawk
float altIn;                    // altIn stores current altitude of pixhawk
int sonarInput = 5;             // Pin 5 activated when signal received from sonar
int rows = 1;                   // Variables for rows/columns of data array
float maxAlt;                   // maxAlt stores height of building


struct measure_t 
{
    String serialNum;
    float alt;
};

struct measure_t measures[0][2];

void setup() 
{
  pinMode(cueToOutput, INPUT_PULLUP);
  pinMode(altInput, INPUT);
  pinMode(sonarInput, INPUT_PULLUP);
  Serial.begin(57600);
  Serial.println("Start");
}

void loop() 
{ 
/*  measure_t measures[] = {
  {bike1, 10},
  {bike2, 22},
  {bike2, 22.5},
  {bike3, 31},
  {bike3, 33},
  {bike2, 21},
  {bike1, 11.2},
  {bike1, 10.7},
};
*/
  altIn = analogRead(altInput);

  while (Serial.available())
  {  
    char UART;
    UART = Serial.read();
    dataIn += UART;

    //Process message only when new line character is received
    if (UART == '\n')
    {
//      Serial.print(dataIn);
//struct measure_t 
      measures[rows][2];
      rows ++;
      measures[rows][1].serialNum = dataIn;
      measures[rows][2].alt = altIn;
      
      dataIn = "";            // Clear received buffer
    }
    
  }

  if (digitalRead(sonarInput) == 0)
  {
    maxAlt = altIn;
  }

  if (digitalRead(cueToOutput) == 0)
  {
  const uint16_t nbMeasures = sizeof(measures) / sizeof(measures[0]);

  float  measureSum[maxItems]  = {0L};
  float  measureCount[maxItems] = {0};  

  for (uint16_t i = 0; i < nbMeasures; i++) 
  {
    measureSum[measures[i].serialNum] += measures[i].alt;
    measureCount[measures[i].serialNum]++;
  }

  for (byte i = 0; i < maxItems; i++) 
  {        
    if (measureCount[i] != 0) 
    {

      float avgAltPerItem = {measureSum[i] / measureCount[i]};
      float estFloorPerItem = {(avgAltPerItem / maxAlt)*numOfFloor};

      Serial.print(F("Average Alt for Item"));
      Serial.print(i+1);
      Serial.print(F(" = "));
      Serial.println(avgAltPerItem);
      Serial.print(F("Estimated floor for Item"));
      Serial.print(i+1);
      Serial.print(F(" is "));
      Serial.println(estFloorPerItem);
      Serial.println();
    } 
    else 
    {
      Serial.print(F("No measure exists for Item"));
      Serial.println(i+1);
      Serial.println();
    }
  }
  Serial.print(F("Total height of building is "));
  Serial.print(maxAlt);
  Serial.println(F(" meters."));

    while(1){}
}
}

I get the error message (request for member ‘serialNum’ in ‘measures’, which is of non-class type ‘measure_t [2]’) at line 82. - measureCount[measures*.serialNum]++;
This is the kind of data my UNO is receiving: (Ignore the “Start”, its just my indicator)
_
UART rx data*_
Best Regards,
Adrian

I have updated the code

But you didn't post it

UKHeliBob:
But you didn't post it

Oops, sorry, my mistake. Links have been updated, thank you for spotting that XD

I have updated the code but I am not sure if i am doing this correctly.

You are not. You need to post your questions and your issues at the same place you post your code. If you want help on dropbox, move your questions there.

If you want help HERE, post your code HERE.

I get the error message (request for member ‘serialNum’ in ‘measures’, which is of non-class type ‘measure_t [2]’) at line 82. - measureCount[measures.serialNum]++;

uint8_t numOfFloor = {12};      // Input number of floors
// Declare item1, item2, item3, etc. (Do Not Remove "maxItems")
enum {bikeObike1 , bikeObike2, bikeObike3, bikeObike4, maxItems};


String dataIn;                  // String to temporarily store data from UART
int cueToOutput = 8;            // Pin 8 indicates drone has landed
int altInput = 4;               // Pin 4 used for Altitude input from pixhawk
float altIn;                    // altIn stores current altitude of pixhawk
int sonarInput = 5;             // Pin 5 activated when signal received from sonar
int rows = 1;                   // Variables for rows/columns of data array
float maxAlt;                   // maxAlt stores height of building


struct measure_t 
{
    String serialNum;
    float alt;
};

struct measure_t measures[0][2];

void setup() 
{
  pinMode(cueToOutput, INPUT_PULLUP);
  pinMode(altInput, INPUT);
  pinMode(sonarInput, INPUT_PULLUP);
  Serial.begin(57600);
  Serial.println("Start");
}

void loop() 
{ 
/*  measure_t measures[] = {
  {bike1, 10},
  {bike2, 22},
  {bike2, 22.5},
  {bike3, 31},
  {bike3, 33},
  {bike2, 21},
  {bike1, 11.2},
  {bike1, 10.7},
};
*/
  altIn = analogRead(altInput);

  while (Serial.available())
  {  
    char UART;
    UART = Serial.read();
    dataIn += UART;

    //Process message only when new line character is received
    if (UART == '\n')
    {
//      Serial.print(dataIn);
//struct measure_t 
      measures[rows][2];
      rows ++;
      measures[rows][1].serialNum = dataIn;
      measures[rows][2].alt = altIn;
      
      dataIn = "";            // Clear received buffer
    }
    
  }

  if (digitalRead(sonarInput) == 0)
  {
    maxAlt = altIn;
  }

  if (digitalRead(cueToOutput) == 0)
  {
  const uint16_t nbMeasures = sizeof(measures) / sizeof(measures[0]);

  float  measureSum[maxItems]  = {0L};
  float  measureCount[maxItems] = {0};  

  for (uint16_t i = 0; i < nbMeasures; i++) 
  {
    measureSum[measures[i].serialNum] += measures[i].alt;
    measureCount[measures[i].serialNum]++;
  }

  for (byte i = 0; i < maxItems; i++) 
  {        
    if (measureCount[i] != 0) 
    {

      float avgAltPerItem = {measureSum[i] / measureCount[i]};
      float estFloorPerItem = {(avgAltPerItem / maxAlt)*numOfFloor};

      Serial.print(F("Average Alt for Item"));
      Serial.print(i+1);
      Serial.print(F(" = "));
      Serial.println(avgAltPerItem);
      Serial.print(F("Estimated floor for Item"));
      Serial.print(i+1);
      Serial.print(F(" is "));
      Serial.println(estFloorPerItem);
      Serial.println();
    } 
    else 
    {
      Serial.print(F("No measure exists for Item"));
      Serial.println(i+1);
      Serial.println();
    }
  }
  Serial.print(F("Total height of building is "));
  Serial.print(maxAlt);
  Serial.println(F(" meters."));

    while(1){}
}
}
measure_t measures[0][2];

What's the point of that?

struct measure_t measures[rows][2];
      rows ++;

This allocates a complete new array, every time. It does NOT change the size of an existing array.

    }

That local array just went out of scope.

  const uint16_t nbMeasures = sizeof(measures) / sizeof(measures[0]);

Now, you are back to dealing with the global variable.

Oh, wait, you commented out the declaration of the global variable, so you don't have one.

Post some code that ACTUALLY compiles.

TolpuddleSartre:

measure_t measures[0][2];

What's the point of that?

I can't declare as measure_t measures[rows][2];
They would not let me use a non-integer?

PaulS:

struct measure_t measures[rows][2];

rows ++;



This allocates a complete new array, every time. It does NOT change the size of an existing array.

Post some code that ACTUALLY compiles.

I am having problem compiling it. How do I have an array which I don't know the size of, but increases a row everytime i receive data?

They would not let me use a non-integer?

Nonsense. You can't use a non-constant integer. That is NOT the same thing.

You REALLY need to decide how big that array needs to be and stop trying to invent new syntax to make a dynamically sizable array.

PaulS:
You REALLY need to decide how big that array needs to be and stop trying to invent new syntax to make a dynamically sizable array.

For what I am trying to do, I would not know the size of the array at compilation time. That's why I'm trying to make it dynamic