I am working with an averaging function following the formula
new average = old average * (n-1) / n + (new value / n)
When passing in doubles this works great. My example code for a proof of concept is as follows.
double avg = 0;
uint16_t i;
for(i=1; i<10; i++) {
int32_t new_value = i;
avg = avg*(i-1);
avg /= i;
avg += new_value/i;
printf("I %d New value %d Avg %f\n",i, new_value, avg);
}
In my program I am keeping track of messages received. Each time I see a message its hit count is increased by 1, it is them timestamped using a timespec. My goal is to keep a moving average (like above) of the average time between messages of a certain type being received.
My initial attempt was to average the tv_nsec and tv_sec separately as follows
static int32_t calc_avg(const int32_t current_avg, const int32_t new_value, const uint64_t n) {
int32_t new__average = current_avg;
new__average = new__average*(n-1);
new__average /= n;
new__average += new_value/n;
return new__average;
}
void average_timespec(struct timespec* average, const struct timespec new_sample, const uint64_t n) {
if(n > 0) {
average->tv_nsec = calc_avg(average->tv_nsec, new_sample.tv_nsec, n);
average->tv_sec = calc_avg(average->tv_sec, new_sample.tv_sec, n);
}
}
My issue is I am using integers, the values are always rounded down and my averages are way off. Is there a smarter/easier way to average the time between timespec readings?
Below is some code that I've used a lot [in production S/W] for years.
The main idea is that just because
clock_gettimeusesstruct timespecdoes not mean this has to be "carried around" everywhere:It's easier to convert to a
long longordoubleand propagate those values as soon as they're gotten fromclock_gettime.All further math is simple add/subtract, etc.
The overhead of the
clock_gettimecall dwarfs the multiply/divide time in the conversion.Whether I use the fixed nanosecond value or the fractional seconds value depends upon the exact application.
In your case, I'd probably use the
doublesince you already have calculations that work for that.Anyway, this is what I use: