Truncated match.
PICList
Thread
'A/D filter'
1998\10\02@011349
by
Gianni
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+(Kf1)*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 (255Kf1).
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

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+(Kf1)*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 (255Kf1).
>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*42. 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

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+(Kf1)*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 (255Kf1).
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

Hi Gianni,
I think this is a classic little problem. The solution is simple, just
rearrange the calculation as follows:
FILTRO = (a_d+(Kf1)*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}> 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+(Kf1)*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 (255Kf1).
> 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\05@204106
by
Scott Dattalo
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+(Kf1)*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

Hi,
Sorry for my last posting (too late in the evening I guess). The rearrangement
should be like below:
FILTRO = (a_d+(Kf1)*FILTRO)) / Kf
= (a_d + (Kf1)*FILTRO + Kf*a_d  Kf*a_d))/Kf // add and subtract Kf*a_d in
numerator !
= a_d + ((Kf1)(FILTROa_d))/Kf
The second term in the last expression will be zero for small values of the
difference (FILTROa_d) and the final FILTRO will be 100%.
Regards,
Anders Friberg
Scott Dattalo wrote:
{Quote hidden}> 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+(Kf1)*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@091755
by
lilel
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...