SUM = SUM + NewValue - M;
N = N+1;
Average = (SUM/N) + M;
// Each time you obtain a new sample do a put
void put(int newReading)
{
static unsigned char samples = 0; // this line executes once during program initialization
if(samples < 8) // add newReading's till adcAbs8 is sum of 8 readings
{
samples = samples + 1;
adcAbs8 = adcAbs8 + newReading;
}
else
{
ave = adcAbs8 / 8;
adcAbs8 = adcAbs8 -ave + newReading;
}
}
// to use the average value of the parameter do a get
int get(void)
{
val = adcAbs8 / 8;
return val;
}
A = ß.A + (1-ß).x
A = A + (x-A)*β
A = ß.A + (1-ß).x
True.The only difference between those is that β in one is (1-ß) in the other.
That's why it was suggested to use fractional math.Thanks also to everyone for the suggestion to separate the error value from the large static value (or "DC") I had a think last night and came to a similar conclusion. The real problem is in the implementation, I like the low pass filter accumulator but when averaging thousands of samples that differ only in 1 integer count it must have some system for handling extra resolution.
union Accumulator
{
struct
{
uint16_t fractional;
uint32_t whole;
};
struct
{
uint32_t low32;
uint16_t high16;
};
} acc;
uint32_t updateAcc(uint32_t sample)
{
int32_t error = acc.whole - sample;
// set beta scale factor here by shifting left...
error <<= 0; // beta = 2^(shift value - 16)
uint32_t old32 = acc.low32;
acc.low32 += error;
// this needs optimising
if(error < 0 && old32 < acc.low32)
acc.high16--; // borrow
else if (error > 0 && old32 > acc.low32)
acc.high16++; // carry
return acc.whole;
}
#define FILT1 40 // faster filter constant used for first 100 seconds
#define FILT2 600 // slow filter constant used after that
unsigned int filter; // holds filter constant
signed long ierror; // for calcs
signed long real_xtal_freq; // holds new sample
signed long real_xtal_av; // average, as integer
signed long real_xtal_avsub; // average extra resolution data (sub-integer)
unsigned char cycles; // how many samples were tested
unsigned char txt[14]; // for text string display
// (loop for each sample) the new sample is in; real_xtal_freq
// calculate a running average in a Low Pass Filter accumulator.
// only do averaging after it has settled down (more than 4 captures)
if(cycles < 255) cycles++; // will stop counting at 255
if(cycles == 4) real_xtal_av = real_xtal_freq; // starting value for average
if(cycles > 4)
{
// Now do the averaging. The process is to average the small integer error
// between the captured value and the integer portion of the average.
// these small integer errors are then averaged in real_xtal_avsub,
// and this becomes extra resoluton data (sub-integer data) of the average.
// the sub-integer data is kept as decimal, scaled so; 1000000 = 1 integer
if(cycles == 104)
{
filter = FILT2; // use finer filtering after first 100 samples
RomanLCD_Out(0,15,"f"); // show "fine" tag on LCD
}
ierror = (real_xtal_freq - real_xtal_av); // get small integer error
real_xtal_avsub -= ((real_xtal_avsub+(filter/2))/filter); // remove a rounded % of average
ierror = (ierror * (1000000/filter)); // scale new error to % of filter value
real_xtal_avsub += ierror; // add into sub-integer average
// if at any point the sub-integer average becomes >1 or <0 we remove
// integer counts from it and put them in the integer average.
while(real_xtal_avsub >= 1000000) // if sub is > 1 integer
{
real_xtal_avsub -= 1000000;
real_xtal_av += 1;
}
while(real_xtal_avsub < 0) // if sub is < 0 integer
{
real_xtal_avsub += 1000000;
real_xtal_av -= 1;
}
// at this point we must have an integer average in real_xtal_av
// and the 0-0.999999 sub-integer resolution in real_xtal_avsub
// display the 0-0.999999 data that will appear after the decimal point
// this is currently in a 6 digit decimal format; 0-999999
ierror = (real_xtal_avsub / 1000); // make 6 dec digits into 3 decimal digits
LongToStr(ierror,txt); // format into text string
txt[7] = '.'; // manually insert dec point
if(txt[8] == ' ') txt[8] = '0'; // add leading zeros where needed
if(txt[9] == ' ') txt[9] = '0';
RomanLCD_Out(1,4,txt); // display it
// and lastly display the integer average
LongToStr(real_xtal_av,txt); // format into text string
RomanLCD_Out(1,0,txt); // display it
RomanLCD_Out(1,0,"av");
// the result displays like this; 4000000.000
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?