Exact match. Not showing close matches.
'[PIC]: - Who is awake?'
|Plunkett, Dennis <MITVMA.MIT.EDU> wrote: PICLIST
> 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 (ix.netcom.com). fastfwd
; (NEW - AVE) + 16*AVE
; AVE = --------------------
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.
MOVLW 00001111B ;MASK OFF ALL BUT THE FRACTIONAL
ANDWF AVFRAC ;PART OF THE OLD AVERAGE
;(AVFRAC'S HI-NIBBLE CAN
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
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
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
; 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 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
> 3/ The impulse response is dependant on the width etc.
No kidding. Isn't that, um, THE POINT?
=== Andrew Warren - ix.netcom.comfastfwd
=== Fast Forward Engineering - San Diego, California
|On Thu, 15 Jun 2000, Andrew Warren wrote:
> Plunkett, Dennis <MITVMA.MIT.EDU> wrote: PICLIST
> > 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.
Which is EXACTLY the form discussed just a few weeks ago! E.g.:
avg = (K1*avg + K2*newsample)/(K1+K2)
In this case, K1 = 15, K2 = 1 and their sum is 16.
If you wish to generalize this then check out:
Which weighs in at 22 cycles for a divisor of 16. Pros: the filter coefficients
are arbitrary and the filter is scalable. Cons: The 'Average' is only 8-bits
instead of 12.
PS. I doubt it's only me, but it's really refreshing to see Andy posting PIC
|I would use all 8 bits available in AVEFRAC for fractional part. This
will reduce the round-off error to almost nothing. And I would like to
keep the input value in NEW not changed.
Also note that the averaging algorithm works only with unsigned
values. To work with signed you need first to bias the signed number
(add 2^(n-1) or xor sign bit), then calculate the average, and remove
bias (substract 2^(n-1) or xor sign bit).
And, to increase precision (or accuracy ?) I would round the final
result before using it by:
btfsc AVEFRAC, 7
incf AVE, w ;w holds rounded result
The modified routine takes also 20 instruction/cycles:
swapf AVFRAC, w ;AVFRAC -= AVFRAC / 16
subwf AVFRAC, f ;(no carry check is performed -
;there is no carry)
swapf AVE, w ;AVE:AVFRAC -= AVE / 16
subwf AVFRAC, f
decf AVE, f
movf TEMP, w
subwf AVE, f
swapf NEW, w ;AVE:AVFRAC += NEW / 16
addwf AVFRAC, f
incf AVE, f
swapf NEW, w
addwf AVE, f
;AVE holds the result
P.S. And all that stuff could be replaced by two parts :)
-----/\/\/\----o----- to PIC ADC input
On Thursday, June 15, 2000 Andrew Warren wrote:
I got some time and tried to rewrite your filter code to optimize
it a little bit.
The formula can be rewritten as: Ave' = Ave + ( New - Ave )/16 ;
Used the same names for variables. TEMP cell isn't used.
I having more and more believing that 12 is some magical number
for small completed code fragments. ;)
; Initially written by Andrew Warren (ix.netcom.com). fastfwd
; Optimized by Dmitry A. Kiryashov (aha.ru) 06/18/2000 zews
; 12 clocks/words
subwf NEW,F ;NEW - AVE
andlw 0x0F ;get /16 int part
skpc ;result is neg?
iorlw 0xF0 ;yes
andlw 0xF0 ;get /16 frac part
; low nibble of AVFRAC isn't used
; so we can utilize it for other purposes ;)
More... (looser matching)
- Last day of these posts
- In 2000
, 2001 only
- New search...