Searching \ for 'A/D filter' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/logic/dsps.htm?key=filter
Search entire site for: 'A/D filter'.

Truncated match.
PICList Thread
'A/D filter'
1998\10\02@011349 by Gianni

flavicon
face
Hi !
In my application with a PIC16C84 I have to filter a continuos data stream
from an A/D converter.
The following algorythm         FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf

       where         a_d = value supplied by A/D converter (range 0 - 255)
                       Kf  = filtering coefficient  ( 4 - 16 )

It doesn't supplies exact results, because of the rounding introduced by
integer math.  In fact the maximum value that FILTRO reaches is (255-Kf-1).
I use the AN526 unsigned 16 bit math routines .
Some suggestion to fix this problem ?
Or someone has a good solution for my aim ?

Thanks
Gianni

1998\10\02@075115 by Chip Weller

flavicon
face
Gianni wrote:

>Hi !
>In my application with a PIC16C84 I have to filter a continuos data stream
>from an A/D converter.
>The following algorythm         FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf
>
>        where         a_d = value supplied by A/D converter (range 0 - 255)
>                        Kf  = filtering coefficient  ( 4 - 16 )
>
>It doesn't supplies exact results, because of the rounding introduced by
>integer math.  In fact the maximum value that FILTRO reaches is (255-Kf-1).
>I use the AN526 unsigned 16 bit math routines .
>Some suggestion to fix this problem ?
>Or someone has a good solution for my aim ?

When implementing infinite impulse response filters I attempt to do two
things, first I keep the output data scaled by my filter factor (skipping
the divide) and I try to use simple powers of 2 when possible. For example
to provide a 1/4th decay rate (time constant of about 2.4 sample periods) is
implemented with:

FilterWordValue = FilterWordValue - (FilterWordValue + 2)/4;    // decay
filter
FilterWordValue = FilterWordValue + ADCSample;                  // charge
filter

The filter word value will have a range of 0..255*4. It will tend to stick
on the last bit of ADC resolution, if starting from 0 with a constant value
X the filter will charge only up to X*4-2. or if settling from a higher
value it will only run down to X*4+1.

When using the filter result you can simply divide by the decay factor (with
rounding is prefered), or use the extra bits. I have also implemented two
pole filters for better frequency and phase responses and have use odd decay
rates such as 23/32. (You often need odd decay rates to tune a multiple pole
filter for best phase response.)

I have never tried to implement a filter with a run time changeable filter
constant. If that is what you need to do I would look at using a n/256 decay
rate which allows simple multiplication instead of division to update the
filter each cycle.

Chip

1998\10\03@151920 by Steve Smith

picon face
In a message dated 02/10/98  05:16:55, you write:

<<
Hi !
In my application with a PIC16C84 I have to filter a continuos data stream
from an A/D converter.
The following algorythm         FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf

        where         a_d = value supplied by A/D converter (range 0 - 255)
                        Kf  = filtering coefficient  ( 4 - 16 )

It doesn't supplies exact results, because of the rounding introduced by
integer math.  In fact the maximum value that FILTRO reaches is (255-Kf-1).
I use the AN526 unsigned 16 bit math routines .
Some suggestion to fix this problem ?
Or someone has a good solution for my aim ?
 >>
a possable soulition which uses two consecutive reads and rounding this could
be expanded to 4  8 16 bits easy its for a '74 but will port across easy

CALL    GET_VOLTAGE     ; GET THE ANALOGUE VOLTAGE REPRESENTING VOLTAGE
       MOVFW   ADRES           ; MOVE ADC RESULT INTO W REG
       MOVWF   VOLTAGE_0       ; SAVE RESULT IN VOLTAGE REG

       BCF     STATUS,C        ; CLEAR THE CARRY FLAG
       CALL    GET_VOLTAGE     ; GET THE ANALOGUE VOLTAGE REPRESENTING
VOLTAGE
       MOVFW   ADRES           ; MOVE ADC RESULT INTO W REG
       ADDWF   VOLTAGE_0,F     ; ADD NEW VALUE TO LAST READING IN VOLTAGE REG
       RRF     VOLTAGE_0,F     ; DIVIDE VOLTAGE BY 2 TO AVERAGE
       BTFSC   STATUS,C        ; CHECK THE CARRY BIT
       INCF    VOLTAGE_0,F     ; IF THE CARRY IS SET, INC THE VOLTAGE REG

Cheers Steve..........

1998\10\05@173955 by Anders Friberg

flavicon
face
Hi Gianni,

I think this is a classic little problem. The solution is simple, just
rearrange the calculation as follows:

FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf =
= (a_d + Kf*FILTRO - FILTRO)/Kf
= FILTRO + (a_d - FILTRO)/Kf

This way, the rounding error will affect the second term only (which will
aproach zero) and the final output value FILTRO will be 100% as expected.

Good luck,
Anders Friberg


Gianni wrote:

{Quote hidden}

1998\10\05@204106 by Scott Dattalo

face
flavicon
face
Anders Friberg wrote:
>
> Hi Gianni,
>
> I think this is a classic little problem. The solution is simple, just
> rearrange the calculation as follows:
>
> FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf =
> = (a_d + Kf*FILTRO - FILTRO)/Kf
> = FILTRO + (a_d - FILTRO)/Kf
>
> This way, the rounding error will affect the second term only (which will
> aproach zero) and the final output value FILTRO will be 100% as expected.

Not quite. Consider a Kf of 4. As long as there is a difference between
a_d and FILTRO that's smaller than 4, the new value FILTRO will be the
same as the old (I'm assuming integer arithmetic, of course). However,
you could integrate the error in another variable:


integrated_error = integrated_error + (a_d - FILTRO)
FILTRO = FILTRO + integrated_error / Kf

As long as there is a difference between FILTRO and the a_d, you'll
accumulate it in the integrated error and eventually update FILTRO.

Scott

1998\10\06@025348 by Anders Friberg

flavicon
face
Hi,

Sorry for my last posting (too late in the evening I guess). The rearrangement
should be like below:

FILTRO = (a_d+(Kf-1)*FILTRO)) / Kf

= (a_d + (Kf-1)*FILTRO + Kf*a_d - Kf*a_d))/Kf    // add and subtract Kf*a_d in
numerator !
= a_d + ((Kf-1)(FILTRO-a_d))/Kf

The second term in the last expression will be zero for small values of the
difference (FILTRO-a_d) and the final FILTRO will be 100%.

Regards,
Anders Friberg


Scott Dattalo wrote:

{Quote hidden}

1998\10\06@091755 by lilel

flavicon
face
Looks to me like you are trying to average the data stream.  Every 2
weeks I say something about averaging versus median filtering.  You
have come up with the problem we face in averaging in a PIC - math
errors and complexity.


I've loaded a nice median routine on my web page cited below - take a
look at it.


-- Lawrence Lile

"Nyquist was an optimist."

=> Median Filter Source Code
=> AutoCad blocks for electrical drafting

at:  http://home1.gte.net/llile/index.htm

More... (looser matching)
- Last day of these posts
- In 1998 , 1999 only
- Today
- New search...