I want to filter deviations from an ADC over time (low pass), not very critical. So I first tried exponential averaging, something like y= (7*y+x)/8. That gave useful results, but there is an obvious rounding issue (no increase as long as x smaller than y+8, decrease if x smaller than y). Adding +4 doesn't really solve the problem.

So I implemented a fixed-point lowpass Butterworth third order filter, with various cutoff frequencies, based on coefficients extracted from http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html (unfortunately down since a few months).

The code looks as follows for 0.033 sampling cutoff

byte dtTI[4], // filter input (0 newest)
 dtTIFast[8]; // filter output, [0]=y, [1]=8 bit decimals
// dtTIFast[2,4,6]= previous filter outputs
dtTIFast[7]=dtTIFast[5]; dtTIFast[5]=dtTIFast[3]; dtTIFast[3]=dtTIFast[1];
dtTIFast[6]=dtTIFast[4]; dtTIFast[4]=dtTIFast[2]; dtTIFast[2]=dtTIFast[0];
unsigned long modifier = 30UL*64*(dtTI[0] + dtTI[3] + 3*dtTI[1] + 3*dtTI[2]);
modifier += 84739UL*(dtTIFast[3]/4+64*dtTIFast[2]); 
modifier -= 73839UL*(dtTIFast[5]/4+64*dtTIFast[4]); 
modifier += 21628UL*(dtTIFast[7]/4+64*dtTIFast[6]); 
dtTIFast[0]=modifier>>21;  dtTIFast[1]=modifier>>13;  // No need to add 2^12, 0.0004deg

The output seemed to give correct results at first, but if I iterate the filter 50 times with the same input(s), I see it keeps oscillating instead of converging to a steady value, and not centered around the x input. For other values (for example 0.001 cutoff), its way worse !

Can you tell me where I'm wrong ? I checked that the sum of my coefficient is 32768, and it looks like there can't be any overflow. I use 14bits y values now, and the real values of coeffs are 2.586028659, -2.253398256 0.660048953 and 0,000915081. Should I need more precision ?

Thanks for your help

  • $\begingroup$ Have you analyzed the "real valued" impulse response of your filter? This is an IIR, and that name means something! $\endgroup$ – Marcus Müller Apr 14 '16 at 10:04
  • $\begingroup$ Also, with an 1/30 low pass filter, and assuming you have enough memory for coefficients and values, you might just go the route of a FIR, and do a decimation=30 (or just 15) polyphased implementation of your FIR, reducing complexity to 1 (or 2) MACs per input sample. $\endgroup$ – Marcus Müller Apr 14 '16 at 10:06
  • $\begingroup$ One guess could be that your states (the dtTIFast array) is truncated to 16 bits....You could gain alot in clarity and also efficiency if you stored all your variables and coefficients in shorts (short arrays) instead of chars and constants. $\endgroup$ – niaren Apr 14 '16 at 11:40
  • $\begingroup$ The FIR suggestion seems slightly dubious to me. Is it really possible to take a VERY long LP FIR filter and reduce its implementation to 1 or 2 MACs per sample without introducing alising distortion? $\endgroup$ – niaren Apr 14 '16 at 11:52
  • $\begingroup$ My states are indeed truncated to 16 bits. Now that means physically 1/2560th of a Celsius degree ... The reason or using arrays of chars/bytes is that it's the way those are sent over air (RF packets). Regarding memory, I use several "daily" memories (1 byte/hour) and arrays such as dtTI are actually holding the 16 last (byte) values. About the "real valued" response, I did some Excel simulations, but with a "noisy" input, so the oscillation character was not visible there. $\endgroup$ – Tochinet Apr 14 '16 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.