2009-11-04 21:23:56 +00:00
|
|
|
// structure for tracking the recent mean and variance
|
|
|
|
// of a distribution that may change over time
|
|
|
|
//
|
|
|
|
// We maintain the mean/var in two ways:
|
|
|
|
// 1) over the entire history of samples, using the algorithm from
|
|
|
|
// http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
|
|
|
|
// 2) as an exponentially-smoothed recent average
|
|
|
|
//
|
|
|
|
// When the number of samples is small we use 1).
|
|
|
|
// Then we switch to 2).
|
|
|
|
|
|
|
|
#define MIN_SAMPLES 50
|
|
|
|
// after this many samples, use exponential average
|
|
|
|
#define SAMPLE_WEIGHT 0.005
|
|
|
|
// new samples get this weight in exp avg
|
|
|
|
#define SAMPLE_LIMIT 10
|
|
|
|
// cap samples at recent_mean*10
|
|
|
|
|
|
|
|
struct AVERAGE {
|
2009-11-04 23:04:07 +00:00
|
|
|
double n; // double to avoid integer overflow
|
2009-11-04 23:23:19 +00:00
|
|
|
double weight;
|
|
|
|
// if n < MIN_SAMPLES, sum of weights
|
|
|
|
// else recent average weight
|
2009-11-04 21:23:56 +00:00
|
|
|
double mean;
|
2009-11-04 23:23:19 +00:00
|
|
|
// if n < MIN_SAMPLES, weighted sum of samples
|
|
|
|
// else recent average
|
|
|
|
double var;
|
|
|
|
// if n < MIN_SAMPLES, weighted sum of vars
|
|
|
|
// else recent var
|
2009-11-04 21:23:56 +00:00
|
|
|
|
2009-11-04 23:23:19 +00:00
|
|
|
void update(double sample, double w) {
|
|
|
|
double delta;
|
2009-11-04 21:23:56 +00:00
|
|
|
if (sample < 0) return;
|
|
|
|
if (n > MIN_SAMPLES) {
|
2009-11-04 23:23:19 +00:00
|
|
|
if (sample > mean*SAMPLE_LIMIT) {
|
|
|
|
sample = mean*SAMPLE_LIMIT;
|
2009-11-04 21:23:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n < MIN_SAMPLES) {
|
2009-11-04 23:23:19 +00:00
|
|
|
weight += w;
|
|
|
|
mean += w*sample;
|
|
|
|
delta = (sample - mean/weight);
|
|
|
|
var += delta*delta*w;
|
|
|
|
} else if (n == MIN_SAMPLES) {
|
|
|
|
mean /= weight;
|
|
|
|
var /= weight;
|
|
|
|
weight /= n;
|
2009-11-04 21:23:56 +00:00
|
|
|
} else {
|
|
|
|
// update recent averages
|
2009-11-04 23:23:19 +00:00
|
|
|
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;
|
2009-11-04 21:23:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
n = 0;
|
2009-11-04 23:23:19 +00:00
|
|
|
weight = 0;
|
2009-11-04 21:23:56 +00:00
|
|
|
mean = 0;
|
2009-11-04 23:23:19 +00:00
|
|
|
var = 0;
|
2009-11-04 21:23:56 +00:00
|
|
|
}
|
|
|
|
};
|