0

I'm trying to do a moving average with c++ to display a sensor data moving average, i want to do the moving average each 2 seconds with the last 15 values. This is what I'm trying but the array don't update correctly and the last value of the array takes stranges values. How can I do it? Thanks in advance

void loop()
{
    count = 0;
    int suma = 0;
    int mm[15];
    int suma2;

    for (int x = 0; x < 15; x++) {

        count++;
        Serial.print("[");
        Serial.print(x);
        Serial.print("] ");
        mm[x] = sensor.getTemperature();
        suma += mm[x];
        Serial.println(mm[x]);
        delay(2000);
    }

    Serial.print("------------------------The first moving average is = ");
    Serial.println(suma / 15);

    delay(1000);

    Serial.print("------------------------The first complete array is--------------------------- ");
    for (int i = 0; i < 15; i++) {

        Serial.print("[");
        Serial.print(i);
        Serial.print("] ");
        Serial.println(mm[i]);
    }

    while (true) {

        for (int y = 0; y < 15; y++) {

            mm[y] = mm[y + 1];
        }
        mm[0] = sensor.getTemperature();

        delay(2000);

        Serial.println("----------------------------The next complete array is------------------------------");
        for (int z = 0; z < 15; z++) {
            Serial.print("[");
            Serial.print(z);
            Serial.print("]");
            Serial.println(mm[z]);
        }
        for (int w = 0; w < 14; w++) {

            suma2 = 0;
            suma2 += mm[w];
        }
        Serial.print("------------------------The next moving average is = ");
        Serial.println(suma2 / 15);

        delay(2000);
    }
}

And this is the output:

13:25:40.167 -> [1] 21
13:25:42.149 -> [2] 21
13:25:44.159 -> [3] 21
13:25:46.140 -> [4] 22
13:25:48.145 -> [5] 22
13:25:50.173 -> [6] 22
13:25:52.162 -> [7] 21
13:25:54.186 -> [8] 21
13:25:56.162 -> [9] 21
13:25:58.196 -> [10] 21
13:26:00.198 -> [11] 21
13:26:02.174 -> [12] 21
13:26:04.189 -> [13] 21
13:26:06.194 -> [14] 22
13:26:08.176 -> ------------------------The first moving average is = 21
13:26:09.179 -> ------------------------The first complete array is--------------------------- [0] 21
13:26:09.179 -> [1] 21
13:26:09.179 -> [2] 21
13:26:09.179 -> [3] 21
13:26:09.179 -> [4] 22
13:26:09.179 -> [5] 22
13:26:09.179 -> [6] 22
13:26:09.179 -> [7] 21
13:26:09.179 -> [8] 21
13:26:09.179 -> [9] 21
13:26:09.179 -> [10] 21
13:26:09.226 -> [11] 21
13:26:09.226 -> [12] 21
13:26:09.226 -> [13] 21
13:26:09.226 -> [14] 1073479292
13:26:11.180 -> ----------------------------The next complete array is------------------------------
13:26:11.216 -> [0]22
13:26:11.216 -> [1]21
13:26:11.216 -> [2]21
13:26:11.216 -> [3]22
13:26:11.216 -> [4]22
13:26:11.216 -> [5]22
13:26:11.216 -> [6]21
13:26:11.216 -> [7]21
13:26:11.216 -> [8]21
13:26:11.216 -> [9]21
13:26:11.216 -> [10]21
13:26:11.216 -> [11]21
13:26:11.216 -> [12]21
13:26:11.216 -> [13]1073479292
13:26:11.216 -> [14]1073479292
13:26:11.216 -> ------------------------The next moving average is = 71565286
13:26:15.193 -> ----------------------------The next complete array is------------------------------
13:26:15.240 -> [0]22
13:26:15.240 -> [1]21
13:26:15.240 -> [2]22
13:26:15.240 -> [3]22
13:26:15.240 -> [4]22
13:26:15.240 -> [5]21
13:26:15.240 -> [6]21
13:26:15.240 -> [7]21
13:26:15.240 -> [8]21
13:26:15.240 -> [9]21
13:26:15.240 -> [10]21
13:26:15.240 -> [11]21
13:26:15.240 -> [12]1073479292
13:26:15.240 -> [13]1073479292
13:26:15.240 -> [14]1073479292
13:26:15.240 -> ------------------------The next moving average is = 71565286
13:26:19.238 -> ----------------------------The next complete array is------------------------------
13:26:19.238 -> [0]22
13:26:19.238 -> [1]22
13:26:19.238 -> [2]22
13:26:19.238 -> [3]22
13:26:19.238 -> [4]21
13:26:19.238 -> [5]21
13:26:19.238 -> [6]21
13:26:19.238 -> [7]21
13:26:19.238 -> [8]21
13:26:19.238 -> [9]21
13:26:19.238 -> [10]21
13:26:19.238 -> [11]1073479292
13:26:19.238 -> [12]1073479292
13:26:19.238 -> [13]1073479292
13:26:19.238 -> [14]1073479292
13:26:19.238 -> ------------------------The next moving average is = 71565286
mourazo
  • 127
  • 6
  • 1
    Arrays are indexed from zero, meaning that your `int mm[14]` array is only accessible up to `mm[13]`, so imagine what happens with the `x < 15` conditional expression. – Sprite Dec 22 '20 at 12:41
  • I had the array declaration wrong, I updated my question, now I have my int mm[15] and in the loops for I traverse the array with i<14 but I have the same problem, thanks – mourazo Dec 22 '20 at 13:05

1 Answers1

1

I would recommend to create a circular buffer, that you fill with your data. I used your ints, make sure, that this is the adequate data type.

#define BUF_SIZE 15

float array_calculate_avg(int * buf, int len);

int   buf[BUF_SIZE]   = {0};
int   buf_index       = 0;
float buf_avg         = 0.0;

void
loop(void)
{
    // Reset the index and start over.
    //
    if (BUF_SIZE == buf_index)
    {
        buf_index = 0;
    }

    buf[buf_index++] = sensor.getTemperature();

    buf_avg = array_calculate_avg(buf, BUF_SIZE);

    Serial.print(buf_avg, 4);

    delay(2000);
}

float
array_calculate_avg(int * buf, int len)
{
    int sum = 0;

    for (int i = 0; i < len; ++i)
    {
        sum += buf[i];
    }

    return ((float) sum) / ((float) len);
}
earthling
  • 620
  • 6
  • 20
  • I don't udestand your method, can you explain me please? Thanks – mourazo Dec 22 '20 at 14:05
  • 1
    You have the buffer `buf`, that you fill with your measured values. Once the buffer is full, you write the next value to index 0 and start over, this is done with the first if query. This way, you have a "circular" buffer. This way, you will always have the 15 most recent measurements in that buffer. You can then calculate the mean value of that buffer, and therefore get a mean average value every 2 seconds over the last 15 measurements. – earthling Dec 22 '20 at 14:22
  • 1
    I usually choose buffer size to be power of 2, so I can do simple bitmasking to not go over its boundaries. Or I use moving average aproximation - substract average value and add new measurement (for example: sum -= sum/16; sum += newValue(); ). So I don't need any array at all (just one variable big enough to contan N times max value. – KIIV Dec 22 '20 at 14:31
  • but in this case, there aren't a real moving average of the last 15 measurments, not? I want the exactly moving average of the last 15 measurments. When it finish to divide to 15 I want to replace the first value of this 15 values and displace one position all values for add at the first the new value and get the average @KIIV – mourazo Dec 22 '20 at 14:54
  • 1
    @mourazo In this answer the last value is getting overwritten by new one, so it is real moving average. Aproximation is close to it, might be even bit more smoother in some cases – KIIV Dec 22 '20 at 15:05