Searching \ for '[PIC]: - Who is awake?' in subject line. ()
Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/devices.htm?key=pic
Search entire site for: '- Who is awake?'.

Exact match. Not showing close matches.
'[PIC]: - Who is awake?'
2000\06\15@063104 by

Plunkett, Dennis <PICLISTMITVMA.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 (fastfwdix.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.

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 - fastfwdix.netcom.com
=== Fast Forward Engineering - San Diego, California
=== http://www.geocities.com/SiliconValley/2499

On Thu, 15 Jun 2000, Andrew Warren wrote:

> Plunkett, Dennis <PICLISTMITVMA.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.

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.

{Quote hidden}

<SNIP>

If you wish to generalize this then check out:

http://www.dattalo.com/technical/software/pic/twist.asm

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

Scott

PS. I doubt it's only me, but it's really refreshing to see Andy posting PIC
code again!

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
andlw 0x0F
subwf  AVFRAC, f         ;(no carry check is performed -
;there is no carry)

swapf AVE, w            ;AVE:AVFRAC -= AVE / 16
movwf TEMP
andlw 0xF0
subwf AVFRAC, f
skpc
decf AVE, f
movf TEMP, w
andlw 0x0F
subwf AVE, f

swapf NEW, w            ;AVE:AVFRAC += NEW / 16
andlw 0xF0
skpnc
incf AVE, f
swapf NEW, w
andlw 0x0F
;AVE holds the result

Nikolai

P.S. And all that stuff could be replaced by two parts :)

|
-----
-----
|
===

On Thursday, June 15, 2000 Andrew Warren wrote:
{Quote hidden}

Hi Andrew.

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 (fastfwdix.netcom.com).
;       Optimized by Dmitry A. Kiryashov (zewsaha.ru) 06/18/2000
;       12 clocks/words

Filter:
movfw   AVE
subwf   NEW,F   ;NEW - AVE

swapf   NEW,W
andlw   0x0F    ;get /16 int part
skpc            ;result is neg?
iorlw   0xF0    ;yes

swapf   NEW,W
andlw   0xF0    ;get /16 frac part
skpnc
incf    AVE,F
;
;       low nibble of AVFRAC isn't used
;       so we can utilize it for other purposes ;)

WBR Dmitry.

{Quote hidden}

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