cool Welcome PIC fans!
(to Pascal language fans too!)

Close General documentation

Close How to support PMP

Close Manuals

Close Tips

Other stuff

Close Documentation

Close How to support PMP

Close Off Topic

Close Today's favourites



Tips - Implementing a low pass filter for ADC or any value

To minimize noise or to limit the response to a disturbing phenomenon, the ADC values may be processed by a LPF (Low Pass Filter) that may be easily implemented with a very common exponential single pole filter:

Value := Value + K*(New - Value);

Where K is of the form 1/N.

if N is chosen as a multiple of 2, the effective implementation with simple integers will be simplified a lot:

Value := (Value * (N - 1) + New) div N;

Which should be optimized by the compiler by using a final right shift.

What are the differences with a classic averaging like Value := (Sample_0 + Sample_1 + ... + Sample_n) div n?

First, if N=2 the filter is strictly equivalent to a classic average:

Value := Value + (New - Value) div 2 == Value := (Value + New) div 2 ;

Then you don't have to accumulate the values in an array or in a larger variable.
Then the response is very different (exponential instead of linear) and the exponential single pole filter will output a value as soon as the first sample is crunched.
Finally a better response may be achieved by cascading several poles with a smaller N value.

Common drawback of a pure integer implementation: The small values accuracy is lowered and Value may suffer from ceiling in the Value-N .. Value + N range.


To workaround this, we may use a scaled accumulator, say: a 32-bit accumulator for filtering 16-bit values.


We may use values scaled by P32 = 65536; this is optimal because 65536 = (1 shl 16).

The formula becomes:

AccValue32 := (AccValue32 * (N - 1) + NewValue32 * P32) div N;

Value16 := AccValue32 div P32;

With N = 16, and P32 = 65536 and 16-bit New16 input value, it comes:

AccValue32 := (AccValue32 * 15 + (longword(New16) shl 16) shr 4;

Value16 := hiword(AccValue32); // The filtered 16-bit output value is simply the high word of the accumulator.

At initialization (or at first input value), we do:

AccValue32 := longword(New16) shl 16;

Value16 := New16;

This is easy for the compiler's optimizer to generate fast code and there is no floor or ceiling phenomenon.

Creation date : 2010.08.13 3:44 PM
Last update : 2014.03.19 1:41 PM
Category : Tips
Page read 8323 times

Print the article Print the article

react.gifReactions to this article

Nobody gave a comment yet.
Be the first to do so!

 Members List Members : 145
Visits of the day: Visits of the day: (4)
              funlw65              PPA              Peter              koesters60   

Your Username:


[ Password lost ? ]

[ Join us ]

Member online :  Member online :
Anonymous online :  Anonymous online : 9

Total visits Total visits: 613646  

Most ever online
Most ever onlineTotal : 75

The 06/09/2013 @ 08:37

Webmaster - Infos



Friends News
Where are you from?

Sentence to think about :  Slow and methodical testing like this will eventually get you to a point where you will either be able to spot the bug, or go quietly insane. Maybe both.  Persistence of Vision 2.1 software documentation.
^ Top ^