Created
January 21, 2014 08:36
-
-
Save numberoverzero/8536341 to your computer and use it in GitHub Desktop.
rolling average of a float for a given duration + resolution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class RollingAverage { | |
private float resolution; | |
private float remainderDt; | |
private float remainder; | |
private float[] samples; | |
private int nsamples; | |
private int oldest; | |
private float rollingAverage; | |
public RollingAverage(float duration, int samples) { | |
this.samples = new float[samples]; | |
nsamples = samples; | |
resolution = duration / samples; | |
} | |
private void advance() { | |
rollingAverage -= samples[oldest] / nsamples; // Remove oldest from rolling avg | |
samples[oldest] = remainder; // Store newest sample in place of oldest | |
rollingAverage += samples[oldest] / nsamples; // Apply newest sample to rolling avg | |
oldest = (++oldest) % nsamples; // Advance oldest pointer; | |
remainder = remainderDt = 0; // Reset remainder | |
} | |
public void update(float v, float stepDt) { | |
float stepWeight, delta = remainderDt + stepDt; | |
while(delta >= resolution) { | |
delta -= resolution; | |
stepWeight = resolution - remainderDt; // Amount of this dt needed | |
// to complete a sample | |
remainder = ( // Weighted average of remainder from | |
(remainder * remainderDt) // previous step and partial value | |
+ (v * stepWeight)) // from current step. Total weight | |
/ resolution; // equals single sample resolution | |
advance(); // Store the new sample and update rolling | |
} | |
remainder = ( // When we enter the above loop at least once, | |
(remainder * remainderDt) // remainder and remainderDt will both be 0 | |
+ (v * (delta - remainderDt))) // and this simplifies to: | |
/ delta; // (0 + v * delta) / delta = v | |
remainderDt = delta; // When we don't enter the loop, it becomes a | |
// simple weighted average: | |
// (delta - remainderDt) | |
// = (remainderDt + stepDt - remainderDt) | |
// = stepDt | |
// remainder = ( | |
// (remainder * remainderDt) | |
// + (v * stepDt) | |
// / (remainderDt + stepDt); | |
} | |
public float getAverage() { | |
float partialSample = ( // Still need to include | |
(remainder * remainderDt) // the remainder, by | |
+ (samples[oldest] * (resolution - remainderDt))) // weighted averaging | |
/ resolution; // with oldest sample. | |
float correction = (partialSample - samples[oldest]) / nsamples; // Delta between partial | |
// and oldest, scaled | |
return rollingAverage + correction; // to number of samples | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment