> Plunkett, Dennis <
PICLIST
spam_OUTMITVMA.MIT.EDU> wrote:
>> A short time ago there was a thread on filters, and a suggestion
>> for a long term averaging filter was proposed that went along the
>> lines of:-
>>
>> average = (((temp*width)-average)+newsample)/width
> Actually, Dennis, it was probably:
> average = (((average*width)-average)+newsample)/width
> which is usually simplified to:
> average = (average * (width-1) + newsample) / width.
>> 1/ This filter assumes that the processor is a floating point
> No; the equation is EASILY implemented using integer math. It
> works like this:
> 1. Since integer division by a power of 2 is trivial, we make
> "width" equal to a power of 2.
> 2. Since multiplication by a power of 2 is also trivial, we
> rewrite the equation thusly:
> average = ((newsample-average) + (width*average)) / width
> If we can make width = 256, the code is absurdly simple... But
> that's a special case. Here's the code for width = 16, which is
> more representative of what'll usually be required:
> ; Written by Andrew Warren (
@spam@fastfwdKILLspam
ix.netcom.com).
> ;
> ; (NEW - AVE) + 16*AVE
> ; AVE = --------------------
> ; 16
> NEW EQU [ANY FILE REGISTER] ;HOLDS NEW SAMPLE [0-255].
> AVE EQU [ANY FILE REGISTER[ ;HOLDS THE AVERAGE [0-255].
> AVFRAC EQU [ANY FILE REGISTER] ;HOLDS THE FRACTIONAL PART
> ;OF THE AVERAGE [0-15].
> TEMP EQU [ANY FILE REGISTER] ;TEMPORARY STORAGE.
> FILTER:
> MOVLW 00001111B ;MASK OFF ALL BUT THE FRACTIONAL
> ANDWF AVFRAC ;PART OF THE OLD AVERAGE
> ;(AVFRAC'S HI-NIBBLE CAN
> ;CONTAIN GARBAGE).
> MOVF AVE,W ;NEW = NEW - AVE.
> SUBWF NEW ;CARRY = 0 IF THE DIFFERENCE IS
> ;NEGATIVE, CARRY = 1 IF POSITIVE.
> SWAPF AVE,W ;HI-NIBBLE OF W = MIDDLE NIBBLE
> ;OF 16*AVE.
> MOVWF TEMP ;LO-NIBBLE OF TEMP = HI-NIBBLE
> ;OF 16*AVE (LO-NIBBLE OF 16*AVE
> ;IS ALWAYS 0000).
> ; NEW CONTAINS (NEW - AVE) AND [TEMP:W] HOLDS 16*AVE.
> ; ADD THEM TOGETHER.
> SKPC ;IF (NEW - AVE) WAS NEGATIVE,
> DECF TEMP ;ADJUST THE HI-NIBBLE OF 16*AVE.
> ANDLW 11110000B ;W = LO-BYTE OF 16*AVE.
> IORWF AVFRAC,W ;(INCLUDE AVE'S FRACTIONAL
> ;PART).
> ADDWF NEW,W ;W = LO-BYTE OF
> ;((NEW-AVE) + 16*AVE).
> ;CARRY = 1 IF SUM > 255,
> ;CARRY = 0 OTHERWISE.
> MOVWF AVFRAC ;LO-NIBBLE OF AVFRAC =
> ;FRACTIONAL PART OF FINAL
> ;RESULT. HI-NIBBLE = GARBAGE.
> ANDLW 11110000B ;W = (LO-NIBBLE OF
> ;((15*AVE+NEW)/16)) * 16.
> MOVWF AVE ;AVE = (LO-NIBBLE OF
> ;((15*AVE+NEW)/16)) * 16.
> SWAPF AVE ;AVE = LO-NIBBLE OF
> ;((15*AVE+NEW)/16).
> ; AVE'S LO-NIBBLE CONTAINS THE LO-NIBBLE OF THE FINAL RESULT.
> ; AVE'S HI-NIBBLE = 0000.
> SKPNC ;LO-NIBBLE OF TEMP =
> INCF TEMP ;HI-NIBBLE OF ((15*AVE+NEW)/16).
> SWAPF TEMP,W ;HI-NIBBLE OF W = HI-NIBBLE OF
> ANDLW 11110000B ;((15*AVE+NEW)/16).
> ;LO-NIBBLE OF W = 0000.
> ; W'S HI-NIBBLE CONTAINS THE HI-NIBBLE OF THE FINAL RESULT.
> ; LO-NIBBLE = 0000.
> IORWF AVE ;COMBINE THE HI- AND LO-NIBBLES
> ;AND STORE THE FINAL RESULT IN
> ;AVE.
> ; AVE CONTAINS THE NEW AVERAGE.
> See? That wasn't too hard; just 20 words of program space and
> 20 instruction cycles... And not a single floating-point
> operation anywhere in there.
>> 2/ The filter is great for downward changing signals only, as an
>> upward change will not be reflected until the delta is greater
>> than the width
> Untrue. In the code above, AVFRAC accumulates deltas smaller
> than the width until their sum is large enough to affect the
> average.
>> 3/ The impulse response is dependant on the width etc.
> No kidding. Isn't that, um, THE POINT?
> -Andy
> === Andrew Warren -
KILLspamfastfwdKILLspam
ix.netcom.com
> === Fast Forward Engineering - San Diego, California
> ===
http://www.geocities.com/SiliconValley/2499