Calculate rolling / moving average in C++

前端 未结 10 2057
攒了一身酷
攒了一身酷 2020-12-02 08:09

I know this is achievable with boost as per:

Using boost::accumulators, how can I reset a rolling window size, does it keep extra history?

But I really would

相关标签:
10条回答
  • 2020-12-02 08:55

    You could implement a ring buffer. Make an array of 1000 elements, and some fields to store the start and end indexes and total size. Then just store the last 1000 elements in the ring buffer, and recalculate the average as needed.

    0 讨论(0)
  • 2020-12-02 08:56

    I use this quite often in hard realtime systems that have fairly insane update rates (50kilosamples/sec) As a result I typically precompute the scalars.

    To compute a moving average of N samples: scalar1 = 1/N; scalar2 = 1 - scalar1; // or (1 - 1/N) then:

    Average = currentSample*scalar1 + Average*scalar2;

    Example: Sliding average of 10 elements

    double scalar1 = 1.0/10.0;  // 0.1
    double scalar2 = 1.0 - scalar1; // 0.9
    bool first_sample = true;
    double average=0.0;
    while(someCondition)
    {
       double newSample = getSample();
       if(first_sample)
       {
        // everybody forgets the initial condition *sigh*
          average = newSample;
          first_sample = false;
       }
       else
       {
          average = (sample*scalar1) + (average*scalar2);
       }
     }
    

    Note: this is just a practical implementation of the answer given by steveha above. Sometimes it's easier to understand a concrete example.

    0 讨论(0)
  • 2020-12-02 09:07

    You can approximate a rolling average by applying a weighted average on your input stream.

    template <unsigned N>
    double approxRollingAverage (double avg, double input) {
        avg -= avg/N;
        avg += input/N;
        return avg;
    }
    

    This way, you don't need to maintain 1000 buckets. However, it is an approximation, so it's value will not match exactly with a true rolling average.

    Edit: Just noticed @steveha's post. This is equivalent to the exponential moving average, with the alpha being 1/N (I was taking N to be 1000 in this case to simulate 1000 buckets).

    0 讨论(0)
  • 2020-12-02 09:10

    One way can be to circularly store the values in the buffer array. and calculate average this way.

    int j = (int) (counter % size);
    buffer[j] = mostrecentvalue;
    avg = (avg * size - buffer[j - 1 == -1 ? size - 1 : j - 1] + buffer[j]) / size;
    
    counter++;
    
    // buffer[j - 1 == -1 ? size - 1 : j - 1] is the oldest value stored
    

    The whole thing runs in a loop where most recent value is dynamic.

    0 讨论(0)
提交回复
热议问题