diff --git a/lib/average.h b/lib/average.h index 4649eb79df..d491b533ab 100644 --- a/lib/average.h +++ b/lib/average.h @@ -18,41 +18,62 @@ struct AVERAGE { double n; // double to avoid integer overflow + double weight; + // if n < MIN_SAMPLES, sum of weights + // else recent average weight double mean; - double sum_var; - // sample variance is this divided by (n-1) - double recent_mean; - double recent_var; + // if n < MIN_SAMPLES, weighted sum of samples + // else recent average + double var; + // if n < MIN_SAMPLES, weighted sum of vars + // else recent var - void update(double sample) { + void update(double sample, double w) { + double delta; if (sample < 0) return; if (n > MIN_SAMPLES) { - if (sample > recent_mean*SAMPLE_LIMIT) { - sample = recent_mean*SAMPLE_LIMIT; + if (sample > mean*SAMPLE_LIMIT) { + sample = mean*SAMPLE_LIMIT; } } n++; - double delta = sample - mean; - mean += delta/n; - sum_var += delta*(sample-mean); if (n < MIN_SAMPLES) { - recent_mean = mean; - recent_var = sum_var/n; + weight += w; + mean += w*sample; + delta = (sample - mean/weight); + var += delta*delta*w; + } else if (n == MIN_SAMPLES) { + mean /= weight; + var /= weight; + weight /= n; } else { // update recent averages - delta = sample - recent_mean; - recent_mean += SAMPLE_WEIGHT*delta; - double d2 = delta*delta - recent_var; - recent_var += SAMPLE_WEIGHT*d2; + if (w > weight*10) w = weight*10; + double rel_weight = w/weight; + double sample_weight = SAMPLE_WEIGHT * rel_weight; + + delta = sample - mean; + mean += sample_weight*delta; + + double d2 = delta*delta - var; + var += sample_weight*d2; + + weight += SAMPLE_WEIGHT*(w - weight); + } + } + double get_mean() { + if (n < MIN_SAMPLES) { + return mean/weight; + } else { + return mean; } } void clear() { n = 0; + weight = 0; mean = 0; - sum_var = 0; - recent_mean = 0; - recent_var = 0; + var = 0; } };