Ve článku 1-Wire barometr s ADS1100 je místo problematické filtrace RC článkem zmiňována její digitální náhrada.
Jak na to s omezenými prostředky PIC ? V úvahu přichází
- průměrování N posledních hodnot
- použít medián tj. prostřední hodnotu z N posledních hodnot
- použít vážený průměr z předchozího průměru a naměřené hodnoty
Průměrování z N posledních hodnot je celkem běžně používané, jeho dynamická odezva na změnu je konstantní a start je dána jen naplněním pole N vzorků. Z HW vyžaduje jen paměť na N vzorků, z SW realizovat kruhový buffer a operaci sčítání a dělení (resp. typičtěji posuv, při N zvoleném jako mocnina 2). Medián může být někdy jednodušší a u některých měření i vhodnější, když výsledná hodnota může nabývat jen několika diskrátních hodnot. Spočívá v tom, že se naměřené hodnoty setřídí a jako výsledná hodnota se použije prostřední hodnota.
Nicméně naonec jsem použil vážený průměr z předchozího průměru a naměřené hodnoty. Tento algoritmus více-méně napodobuje chování klasického integračního RC článku. Nicméně stejně jako analogové počítače používají obvody pro nastavení výchozích podmínek na integračním článku, tak je i při použití tohoto algoritmu vhodné počítat s obdobným řešením. Zrychlí se tím start po výpadku napájení.
Konkrétně algoritmus používá 16ti bitový, 16ti stupňový filtr realizující funkci
AVE = (15*AVE +NEW)/16
tj. ze nová hodnota se uplatní ve výsledku pouze z 1/16 a z 15/16 se uplatní předchozí průměr.
; 16 bit 1/2/../16/../256 step Averageing filter by Radek Benedikt
;
; input
; new1(MSB)new0(LSB)
; output
; ave2(MSB)ave1(LSB)
; AVE = (15*AVE +NEW)/16
; the formula can be rewrite as:
; AVE = AVE + (NEW - AVE)/16
;
avg clrf new2 ; expand 16 bit to 24 bit
btfsc new1,7 ; expand sign
decf new2,f
clrf ave3 ; expand 16(24) bit to 24(32) bit
btfsc ave2,7 ; expand sign
decf ave3,f
; new' = new - ave
movf ave1,w ; sub low bytes
subwf new0,f
movf ave2,w ; sub mid bytes
skpc ; carry_in, so just sub
incfsz ave2,w ; add carry_in to ave2
subwf new1,f ; sub and propagate carry_out
movf ave3,w ; sub high bytes
skpc ; carry_in, so just sub
incfsz ave3,w ; add carry_in to ave3
subwf new2,f ; sub and propagate carry_out
btfss skipOutVar
goto avggo
btfsc new2,7 ; test sign
goto avggoM
movf new2,w
btfss STATUS,Z
return
movf new1,w
btfss STATUS,Z
return
goto avggo
avggoM incf new2,w
btfss STATUS,Z
return
incf new1,w
btfss STATUS,Z
return
avggo
; avg precision, std *16/256
movf avgPR,w
movwf avgCNT
avglop bcf STATUS,C
rlf new0,f ; *2
rlf new1,f
rlf new2,f
decfsz avgCNT,f
goto avglop
;
; (std mode) ave = ave + 16*(new - ave)/256
movf new0,w ; add low bytes
addwf ave0,f
movf new1,w ; add mid bytes
skpnc ; no carry_in, so just add
incfsz new1,w ; add carry_in to new1
addwf ave1,f ; add and propagate carry_out
movf new2,w ; add high bytes
skpnc ; no carry_in, so just add
incfsz new2,w ; add carry_in to new2
addwf ave2,f ; add and propagate carry_out
return
Detailní pohled do kódu ukáže dvě proměnné, složící k "tunningu" algoritmu¨
avgPR - udává počet vzorků použitých pro průměrování, pro 16 vzorků je roven 4, pro nastartování algoritmu tj. 1 vzorek je roven 8, pro 4 vzorky je roven 6
skipOutVar - bitová proměnná, pokud je On, tak se do průměru nezahrne hodnota lišící se od průměru o více než 255.
Jejich použití je vidět nejlépe ze startovací sekvence po zapnutí
movlw 0x08
movwf avgPR ; init averageing filter
call adscan9 ; exec Convert Sensor
movlw 0x06
movwf avgPR
call adscan ; exec Convert Sensor
call adscan ; exec Convert Sensor
movlw 0x04
movwf avgPR
bsf skipOutVar
Nejprve se de facto vypne průměrování a do průměru se nakopíruje i když trochu složitě naměřená hodnota z A/D převodníku. Teoreticky může být tato hodnota "ulétnutá" komunikace s A/D převodníkem nemá žádnou kontrolu na chyby. Proto se vzápětí přejde na režim průměrování s váhou 1/4 a s touto váhou se provedou dvě měření. Poté se přejde na režim průměrováni 1/16 a zapne se režim ignorování hodnot lišících se o více než 255.
Ve zdrojovém textu baro.asm je vidět detailně celý kód pro komunikaci s ADS1100 a zpracování dat z něj. Popis 1-wire komunikace (modul 1wire675.inc) zas někdy příště.