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

General documentation

How to support PMP

Manuals

Tips

Other stuff

Documentation

How to support PMP

Off Topic

Today's favourites

Search

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.

Example:

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

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

Connection...
Members : 79

Member online :
Anonymous online : 8

Total visits: 1218995

Most ever online
Total : 170

The 01/01/2021 @ 17:50

Webmaster - Infos

Ip: 3.238.99.243

Search

Friends News
Where are you from?

Sentence to think about :  The enterprise's computing [...] is just like of an archaeological site. [...] Deep inside, you find real fossils, calcified: the punched card is no longer physically there,
but one can find
its "footprint" on the latest hard drives, up to traces of organization in eighty "columns".

Top