This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Need to know what code to use to take an average

Hello, I am trying to find out how to write a program which will take the average over the day. I dont want it to just take the average over the last 24 hours, I know how to do that, rather I want to find the average from 12 midnight to 12 midnight the next day, and to have this average displayed throughout the day and changing as the day progresses. This is to be written in C code

Parents
  • Stefan,

    I don't have the code written but for averaging over the last 24 hours i would:

    static double average = 0;
    count = 0;

    average = (average + radiation)/24;
    count++;
    if (count > 23)
    {
    result = SetCtrlVal (mainpanel, MAINPANEL_WSAV, average);
    count = 0;
    wind_av = 0;
    }


    This would take the 24 values recieved once the prgram is run and then take the average after all values have been recieved.

    I need to instead have a running average which displays the average over the day and changes as the day goes on. For example whatever the value is when the system is first truned on, that average would appear in the display until another value was recieved, then it would be modified accordingly. Then average then must return to zero at midnight and the program can start again for the next days average. As I need to know how to take the average from 12 midnight one day to 12 midnight the next day.

Reply
  • Stefan,

    I don't have the code written but for averaging over the last 24 hours i would:

    static double average = 0;
    count = 0;

    average = (average + radiation)/24;
    count++;
    if (count > 23)
    {
    result = SetCtrlVal (mainpanel, MAINPANEL_WSAV, average);
    count = 0;
    wind_av = 0;
    }


    This would take the 24 values recieved once the prgram is run and then take the average after all values have been recieved.

    I need to instead have a running average which displays the average over the day and changes as the day goes on. For example whatever the value is when the system is first truned on, that average would appear in the display until another value was recieved, then it would be modified accordingly. Then average then must return to zero at midnight and the program can start again for the next days average. As I need to know how to take the average from 12 midnight one day to 12 midnight the next day.

Children
  • Just as you said: At midnight, reset average and count to zero, and display the running average from that time.

    The last-24-hour running average is reset once when the program starts and you initialize the variables. There's no reason you can't reset the average any time you like, though.

    You'll have to have some way to set the time of day in your device so that it knows when "midnight" comes around. You could manually set it and use an 8051 timer to track the progress of time. Or perhaps your project includes a real-time clock that can maintain the TOD for you.

  • Thanks, but Im having problems figuring out how to do the running average itslef. I know its probably simple, but i havent done it before

  • Im having problems figuring out how to do the running average itself.

    I.e. it's exactly opposite to what you originally seemed to be saying: you know how to do a fixed-interval average, but not how to compute the average over the last 24 hours (that one is a running average).

    Well, you need to store all hourly input values from inside the running average's sliding window in an array. Then you do one of these:

    *) re-compute the sum over that array each time you update the display

    *) re-compute the sum over the array only when it actually changes

    *) compute the array a little more cleverly, subtracting the value that fell out the back end of the window, and adding the new reading, each time a new value comes in

  • Thanks everybody, nobody really knew what I was asking but I figured it out. This is what I did:

    GetSystemTime (&hour, &minute, &second);

    if((second == 0 ) & (datecount == 0))
    {
    datecount = 1;
    sumday = 0;
    }
    if (second != 0)
    {
    sumday = (sumday + radiation);
    datecount++;
    result = SetCtrlVal(mainpanel, MAINPANEL_SUM_DAY, sumday);
    datecount = 0;

  • Divide by the number of samples you have.
    1 sample divide by 1. 2 samples 2.

    you could divide by "count in you example.
    Avoid dividing by zero.

  • I don't know if I understand well what your problem exactly is but would the following help you?

    A little bit of theory first:
    
    // ==========================================
    // The Running Average Equation for N Samples
    // ==========================================
    
    // Let's assume "running" values x(i), sampled in equidistant time instants:
    //             x(1), x(2), ..., x(i), x(i+1), ... etc.
    
    // The arithmetic average for first N samples is defined as:
    //    AVG(N) = [x(1) + x(2) + ... + x(N-1) + x(N)] / N                       (1)
    
    // The formula for i-th arithmetic average from N samples is then as follows:
    //    AVG(i)   = [x(1+i-N) + x(2+i-N) + ... + x(i-2) + x(i-1) + x(i)] / N    (2)
    
    // thus the previous average value was:
    //    AVG(i-1) = [x(i-N) + x(1+i-N) + x(2+i-N) + ... + x(i-2) + x(i-1)] / N  (3)
    
    // subtracting eq.(3) from eq.(2) yields:
    //    AVG(i) - AVG(i-1) = [x(i) - x(i-N)] / N                                (4)
    
    // and therefore:
    //    AVG(i) = AVG(i-1) + [x(i) - x(i-N)] / N                                (5)
    
    //------------------------------------------------------------------------------
    //    An example of the above theory applied:   (generic 8052)
    //------------------------------------------------------------------------------
    
    #include <string.h>                       // memset(...
    #include <stdio.h>                        // printf(...
    #include <REG52.H>                        // printf_init
    
    #define SAMPLE_COUNT     24               // number of averaged samples (N)
    #define INIT_AVG_VALUE   0                // initial AVG value (arbitrary)
    
    #define Fxtal            11059200.0       // 8052 XTAL Frequency [Hz]
    
      // provided that: Fxtal/(32*65536) <= rate <= Fxtal/32
    #define RCAP2_CNF(rate)  (0x10000-((unsigned int)((float)Fxtal/rate/32+0.5)))
    
    //------------------------------------------------------------------------------
    
    signed char Ring_Buffer[SAMPLE_COUNT];    // ring buffer to store last N samples
    signed char * current_minus_N;            // pointer to (current-N) sample
                                              // in the above Ring_Buffer
    signed int Avg;                           // current value of running average
    signed int Avg_1;                         // previous value of running average
    signed int Rem;                           // remainder after division
    unsigned char reset_time;                 // "reset instant"
    
    signed char GetCurrentSample(void)        // gets current sample and returns it
    {
      signed char sample;
      // bla, bla
      return(sample);
    }
    
    void printf_init(Bdrate)                  // sets Bdrate [Bd] for printf
    {                                         // defined in REG52.H:
      RCAP2 = RCAP2_CNF(Bdrate);              // sfr16 RCAP2=0xCA; sfr T2CON=0xC8;
      C_T2 = 0;                               // sbit C_T2 = T2CON^1;
      TCLK = 1;                               // sbit TCLK = T2CON^4;
      TR2 = 1;                                // sbit TR2  = T2CON^2;
      SCON = 0xC0;                            // sfr SCON  = 0x98;
      TI = 1;                                 // sbit T1   = P3^5;
    }
    
    void Display_Average_Value(void)
    {                                         // displays the calculated average
      printf("%u o'clock - ",(unsigned int)(reset_time+1));
      printf("The average value is: %d\n",Avg);
    }
    
    void InitAvgCalc(signed char init_value, unsigned int sample_count)
    {
      reset_time = 0;                           // reset time init
      Rem = 0;                                  // remainder init
      Avg_1 = init_value;                       // AVG(i-1) init
      current_minus_N = &Ring_Buffer[0];        // pointer to (current-N) sample
      memset(&Ring_Buffer[0],init_value,sample_count);  // fills ring buffer
    }                                                   // with initial value
    
    void CalculateAverageValue(void)            // running average calculation
    {
      signed int sample = GetCurrentSample();   // x(i)
      signed int diff;
    
      diff = sample - *current_minus_N + Rem;   // [x(i)-x(i-N)] corr. (remainder)
      *current_minus_N = sample;                // saves x(i-N)
      Avg = Avg_1 + diff / SAMPLE_COUNT;        // calculation itself
      Rem = diff % SAMPLE_COUNT;
      Avg_1 = Avg;                              // AVG(i-1) for next sample instant
    
      if (++current_minus_N == &Ring_Buffer[SAMPLE_COUNT]) {
        current_minus_N = &Ring_Buffer[0];      // pointer correction
      }                                         // @ the end of ring buffer
    }
    
    void main(void)
    {
      unsigned char sample_time = 1;            // in a real program determined
                                                // by a timer or RTC
    
      printf_init(19200.0);                     // 19200 [Bd]
    
      InitAvgCalc(INIT_AVG_VALUE,SAMPLE_COUNT); // calculation init
    
      do {
        if (sample_time) {                      // time for calculation ?
          CalculateAverageValue();
          Display_Average_Value();
          ++reset_time;
        }
        if (reset_time == SAMPLE_COUNT) {       // time to reset calculation ?
          InitAvgCalc(INIT_AVG_VALUE,SAMPLE_COUNT);
        }
      } while(1);
    }
    
    btw. your
    
    if((second == 0 ) & (datecount == 0))
    
    probably should have been
    
    if((second == 0 ) && (datecount == 0))
    
    as '&' is bitwise AND,
    am I right?

  • I'm sorry, in my example the variable

    signed int Avg_1;                         // previous value of running average
    
    is redundant, so the essential functions should be as follows:
    void InitAvgCalc(signed char init_value, unsigned int sample_count)
    {
      reset_time = 0;                           // reset time init
      Rem = 0;                                  // remainder init
      Avg = init_value;                         // "AVG(i-1)" init
      current_minus_N = &Ring_Buffer[0];        // pointer to (current-N) sample
      memset(&Ring_Buffer[0],init_value,sample_count);  // fills ring buffer
    }                                                   // with initial value
    
    void CalculateAverageValue(void)            // running average calculation
    {
      signed int sample = GetCurrentSample();   // x(i)
      signed int diff;
    
      diff = sample - *current_minus_N + Rem;   // [x(i)-x(i-N)] corr. (remainder)
      *current_minus_N = sample;                // saves x(i-N)
      Avg = Avg + diff / SAMPLE_COUNT;          // calculation itself
      Rem = diff % SAMPLE_COUNT;
    
      if (++current_minus_N == &Ring_Buffer[SAMPLE_COUNT]) {
        current_minus_N = &Ring_Buffer[0];      // pointer correction
      }                                         // @ the end of ring buffer
    }
    
    Eric