Skip to content

Instantly share code, notes, and snippets.

@bmccormack
Created March 31, 2015 01:05
Show Gist options
  • Star 48 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save bmccormack/d12f4bf0c96423d03f82 to your computer and use it in GitHub Desktop.
Save bmccormack/d12f4bf0c96423d03f82 to your computer and use it in GitHub Desktop.
Moving average example in C
#include <stdio.h>
int movingAvg(int *ptrArrNumbers, long *ptrSum, int pos, int len, int nextNum)
{
//Subtract the oldest number from the prev sum, add the new number
*ptrSum = *ptrSum - ptrArrNumbers[pos] + nextNum;
//Assign the nextNum to the position in the array
ptrArrNumbers[pos] = nextNum;
//return the average
return *ptrSum / len;
}
int main(int argc, char *argv[])
{
// a sample array of numbers. The represent "readings" from a sensor over time
int sample[] = {50, 10, 20, 18, 20, 100, 18, 10, 13, 500, 50, 40, 10};
// the size of this array represents how many numbers will be used
// to calculate the average
int arrNumbers[5] = {0};
int pos = 0;
int newAvg = 0;
long sum = 0;
int len = sizeof(arrNumbers) / sizeof(int);
int count = sizeof(sample) / sizeof(int);
for(int i = 0; i < count; i++){
newAvg = movingAvg(arrNumbers, &sum, pos, len, sample[i]);
printf("The new average is %d\n", newAvg);
pos++;
if (pos >= len){
pos = 0;
}
}
return 0;
}
@gpmanly
Copy link

gpmanly commented Sep 8, 2017

thank you very much. I applied used your code on my frequency counter machine.

@theElementZero
Copy link

Thank you for this nice piece of Code, compact and well written

@HElkhoury
Copy link

Thanks for the code. Helpful for an ADC averaging routine

@LaWarreNVR
Copy link

Thank you for the code. Worked perfectly in my application

@Sinansi
Copy link

Sinansi commented Aug 18, 2020

Thank you so much! I am much appreciated.

@leoribg
Copy link

leoribg commented Aug 18, 2020

Very good, thank you!

@malbolgee
Copy link

muito obrigado meu patrão.

@sunadraj
Copy link

sunadraj commented Apr 4, 2021

how to do this using float values as input please tell me

@locnnil
Copy link

locnnil commented Oct 10, 2021

I realize that there is a way to do that without using pointers and with only one function (whithout have to increment position in a outside way), if you declare the position variable "pos" as static and the sum variable ptrSum too you can have a code with the same funtionality like:

#include <stdio.h>

int movingAvg(int *ptrArrNumbers, int len, int nextNum)
{
  static long Sum = 0;
  static int pos = 0;
  //Subtract the oldest number from the prev sum, add the new number
  Sum = Sum - ptrArrNumbers[pos] + nextNum;
  //Assign the nextNum to the position in the array
  ptrArrNumbers[pos] = nextNum;
  //Increment position internaly
  pos++;
  if (pos >= len){
    pos = 0;
  }
  //return the average
  return *ptrSum / len;
}

int main(int argc, char *argv[])
{
  // a sample array of numbers. The represent "readings" from a sensor over time
  int sample[] = {50, 10, 20, 18, 20, 100, 18, 10, 13, 500, 50, 40, 10};
  // the size of this array represents how many numbers will be used
  // to calculate the average
  int arrNumbers[5] = {0};

  int newAvg = 0;
  int len = sizeof(arrNumbers) / sizeof(int);
  int count = sizeof(sample) / sizeof(int);

  for(int i = 0; i < count; i++){
    newAvg = movingAvg(arrNumbers, len, sample[i]);
    printf("The new average is %d\n", newAvg);
  }

  return 0;
}

@saifandro327 to do it using float values you just need to change the return(at declaration) and the last parameter from int to float like this:

float movingAvg(float *ptrArrNumbers, int len, float nextNum){
//Same code
}

OBS: Using the function with the variables pos and sum declared as static will be that the value stay preserved, if you want to reset the moving average may be usefull add a parameter to use as conditional state to clear/reset the sum of moving average like this:

int movingAvg(int *ptrArrNumbers, int len, int nextNum, bool reset)
{
  static long Sum = 0;
  static int pos = 0;
  //check for reset request
  if(reset){
    Sum = 0;
    pos = 0;
  }
  //Subtract the oldest number from the prev sum, add the new number
  Sum = Sum - ptrArrNumbers[pos] + nextNum;
  //Assign the nextNum to the position in the array
  ptrArrNumbers[pos] = nextNum;
  //Increment position internaly
  pos++;
  if (pos >= len){
    pos = 0;
  }
  //return the average
  return *ptrSum / len;
}

@RichardPar
Copy link

RichardPar commented Nov 23, 2021

OBS: Using the function with the variables pos and sum declared as static will be that the value stay preserved, if you want to reset the moving average may be usefull add a parameter to use as conditional state to clear/reset the sum of moving average like this:

int movingAvg(int *ptrArrNumbers, int len, int nextNum, bool reset)
{
  static long Sum = 0;
  static int pos = 0;
  //check for reset request
  if(reset){
    Sum = 0;
    pos = 0;
  }
  //Subtract the oldest number from the prev sum, add the new number
  Sum = Sum - ptrArrNumbers[pos] + nextNum;
  //Assign the nextNum to the position in the array
  ptrArrNumbers[pos] = nextNum;
  //Increment position internaly
  pos++;
  if (pos >= len){
    pos = 0;
  }
  //return the average
  return *ptrSum / len;
}

Using Statics completely breaks the function being used simultaneously on different arrays. Never use statics on Utility functions unless you want a world of pain

@locnnil
Copy link

locnnil commented Nov 23, 2021

@RichardPar that's a good point! I didn't think about this situation of use the function in different arrays!

@RichardPar
Copy link

@RichardPar that's a good point! I didn't think about this situation of use the function in different arrays!

Additionally..

  //return the average
  **return *ptrSum / len;**

The first run of the function will return the wrong average when there are less than LEN samples in the array.

@sabrinnanguyen
Copy link

wow u saved my life and my grade ily

@basikv
Copy link

basikv commented Mar 30, 2022

in the above code instant of this sample array
int sample[] = {50, 10, 20, 18, 20, 100, 18, 10, 13, 500, 50, 40, 10};
can we use a sensor input for continuous signal output , for example
const int analog_pin = A0;
if i need a program for continuous sensor input what changes i need to do in this code. can someone help me with that?

@spaceMan00
Copy link

Thank you for this implementation and for all the comments. Very helpful!
I rewrote the moving average using a struct.

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>


typedef struct moving_average
{
    long sum;
    int pos;
    int * buffer;
    int length;
    bool is_filled;
}moving_average_t;

int movingAvg(moving_average_t * av_obj, int new_element)
{
  //Subtract the oldest number from the prev sum, add the new number
  av_obj->sum = av_obj->sum - av_obj->buffer[av_obj->pos] + new_element;
  //Assign the nextNum to the position in the array
  av_obj->buffer[av_obj->pos] = new_element;
  //Increment position internaly
  av_obj->pos++;
  if (av_obj->pos >= av_obj->length){
    av_obj->pos = 0;
    av_obj->is_filled = true;
  }
  printf("is_filled %d", av_obj->is_filled);
  //return the average
  return av_obj->sum / (av_obj->is_filled ? av_obj->length:av_obj->pos);
}

moving_average_t * allocate_moving_average(int len)
{
    moving_average_t * av_obj = malloc(sizeof(moving_average_t));
    av_obj->sum       = 0;
    av_obj->pos       = 0;
    av_obj->length    = len;
    av_obj->is_filled = false;
    av_obj->buffer = malloc(len * sizeof(int));
    return av_obj;
}

void free_moving_average(moving_average_t * av_obj)
{
    free(av_obj->buffer);
    av_obj->buffer = NULL;
    free(av_obj);
}

int main()
{
    // a sample array of numbers. The represent "readings" from a sensor over time
    int sample[] = {50, 10, 20, 18, 20, 100, 18, 10, 13, 500, 50, 40, 10};
    // the size of this array represents how many numbers will be used
    // to calculate the average

    
    int newAvg = 0;
    int count = sizeof(sample) / sizeof(int);
    
    moving_average_t * sensor_av = allocate_moving_average(5);
    
    for(int i = 0; i < count; i++){
        newAvg = movingAvg(sensor_av, sample[i]);
        printf("The new average is %d\n", newAvg);
    }
    
    free_moving_average(sensor_av);
    sensor_av = NULL;

    return 0;
}

@Technarian
Copy link

What is sizeof(int) supposed to be the size of? "int" is a type. I am confused as to what needs to be in that field.
Thank you

@Thor-x86
Copy link

Thor-x86 commented Feb 9, 2024

What is sizeof(int) supposed to be the size of? "int" is a type

Depends on your targeted machine. On most PC, it's 4 bytes. However, other targets like Arduino Uno only have 2 bytes. So it's safer to write sizeof(int) rather than directly write 4.

For anyone who didn't familiar with C, this line

int count = sizeof(sample) / sizeof(int);

Counts how many elements in sample array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment