I know it doesn't meet your needs to find out the AC value in 1/50th or 1/60th of a second - this needs 1/10th.
However, here's what I was indirectly ranting about...
The update when you get a new sample is very simple:
static void include_new_sample(uint16_t new_data) {
// Remove the oldest sample
running_total -= data[index];
running_squared_total -= data[index]*data[index];
// Add the new sample
running_total += new_data;
running_squared_total += new_data*new_data;
// Store the new data for when we remove it
data[index] = new_data;
// Update the index
index = (index == N_POINTS-1) ? 0 : index+1;
}
Extracting the DC and AC RMS values is pretty simple too, (but only if you can use floating point, with integers only it will be a bit more tricky):
static void output_results(void) {
double avg, total_power, dc_power, ac_power, ac_rms;
avg = running_total/(double)(N_POINTS);
total_power = running_squared_total/((double)(N_POINTS));
dc_power = avg*avg;
ac_power = total_power - dc_power;
ac_rms = sqrt(ac_power);
printf("%4i: Average is %6.2f, dc power is %9.1f, ac power is %8.1f, ac_rms %6.2f\n",
sample_no, avg, dc_power, ac_power, ac_rms);
}
Here's the full test, in case you want to play with it. Note that it will of course take 100 samples to 'ramp up', and is using unsigned int values:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <time.h>
#define N_POINTS 100
static uint16_t data[N_POINTS];
static uint16_t index;
static uint32_t running_total;
static uint32_t running_squared_total;
static uint32_t sample_no = 0;
static void include_new_sample(uint16_t new_data) {
// Remove the oldest sample
running_total -= data[index];
running_squared_total -= data[index]*data[index];
// Add the new sample
running_total += new_data;
running_squared_total += new_data*new_data;
// Store the new data for when we remove it
data[index] = new_data;
// Update the index
index = (index == N_POINTS-1) ? 0 : index+1;
}
static void output_results(void) {
double avg, total_power, dc_power, ac_power, ac_rms;
avg = running_total/(double)(N_POINTS);
total_power = running_squared_total/((double)(N_POINTS));
dc_power = avg*avg;
ac_power = total_power - dc_power;
ac_rms = sqrt(ac_power);
printf("%4i: Average is %6.2f, dc power is %9.1f, ac power is %8.1f, ac_rms %6.2f\n",
sample_no, avg, dc_power, ac_power, ac_rms);
}
uint16_t get_sample(int waveform) {
uint16_t new_val = 0;
switch(waveform) {
case 1: // Random of +/- 50, DC of 100 , RMS of about 30
new_val = rand()/(RAND_MAX/100)-50 + 100;
break;
case 2: // Sine of 20 samples (50Hz at 1kS/s), 70.7 units RMS, DC 200
new_val = sin(2.0*M_PI * sample_no/20)*100 + 200;
break;
case 3: // Sine of 16.6 samples (60Hz @ 1kS/s) 70.7 units RMS DC 512
new_val = sin(2.0*M_PI * sample_no/16.66)*100 + 512;
break;
default:
new_val = 0;
break;
}
sample_no++;
return new_val;
}
int main(int argc, char *argv[]) {
srand(time(NULL)); // Just in case we use rand()
for(int i = 0; i < 1000; i++) {
include_new_sample(get_sample(3));
// Results only every 10 samples
if(i %10 == 0) output_results();
}
}