Plunkett, Dennis 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 (fastfwd@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 - fastfwd@ix.netcom.com === Fast Forward Engineering - San Diego, California === http://www.geocities.com/SiliconValley/2499