Filtracja Danych Metodą Średniej Kroczącej: Algorytmy i Implementacja

Filtry cyfrowe to algorytmy, które służą do przetwarzania sygnałów cyfrowych. Pozwalają na usuwanie lub redukowanie niepożądanych składników sygnału, takich jak szum i zniekształcenia. Istnieje wiele różnych rodzajów filtrów stosowanych w technice mikroprocesorowej.

Filtr uśredniający to jeden z najprostszych rodzajów filtrów cyfrowych. Działa na zasadzie obliczania średniej wartości sygnału w czasie i użycia tej wartości jako nowego sygnału na wyjściu.

Jednym z najpopularniejszych typów filtrów uśredniających jest filtr z ruchomą średnią (ang. Moving Average Filter), który oblicza średnią wartość sygnału w określonym oknie czasowym, a następnie przesuwa okno czasowe i ponownie oblicza średnią wartość dla nowych próbek sygnału.

Przedstawiony powyżej wzór zakłada liczenie średniej z M próbek, które były pobrane wcześniej niż aktualnie obliczany sygnał wyjściowy. Jest to najczęściej stosowana forma, chociaż można równie dobrze obliczać średnią tzw. symetryczną, czyli średnią z kilku próbek przed i kilku próbek po obliczanym sygnale wyjściowym.

Rys.1. Zaszumiony sygnał (a) może być z powodzeniem wygładzony (b) przy użyciu filtru dolnoprzepustowego średniej kroczącej.

Przeczytaj także: Definicja i pomiar filtracji kłębuszkowej

Wygładzanie sygnału z przetwornika dokonywane jest w następujący sposób. W pierwszej fazie próbki sygnału z przetwornika zbierane są z częstotliwością próbkowania, następnie dokonywane jest uśrednianie w obrębie grupy lub ustalonej liczby próbek, a cały proces jest powtarzany na wielu grupach w całym czasie obserwacji (rys. 2). W kategoriach filtrowania, uśrednianie to jest niczym innym jak tylko filtrowaniem sygnału filtrem dolnoprzepustowym.

Efektywność filtracji sterowana jest liczbą próbek w uśrednianej grupie. Większa liczba próbek w grupach polepsza efekt wygładzania. Innym skutkiem ubocznym tej filtracji jest zwiększenie precyzji przefiltrowanych danych.

W idealnym przypadku, średnia czterech próbek sygnału stałego zwiększa efektywną rozdzielczość przetwornika o jeden bit. A to z kolei, zgodnie ze znanym twierdzeniem poprawi stosunek sygnał szum na wyjściu przetwornika o 6 dB. Uśrednianie 16 próbek zwiększy rozdzielczość o 2 bity, a stosunek sygnał szum o 12 dB. Teoretycznie, liczba próbek w grupie równa 4N zwiększy efektywną liczbę bitów o N.

Zwiększanie efektywnej liczby bitów przetwornika analogowo cyfrowego możliwe jest dopóty, dopóki: liczba ta jest realna i nieidealności przetwornika brane są pod uwagę. Przykładowo, polepszenie rozdzielczości 12-bitowego przetwornika do 16 bitów wymaga zgodnie z wcześniejszymi rozważaniami uśredniania 256 próbek w każdym bloku.

Rodzi się, więc pytanie czy jest wystarczająco dużo czasu na zaimplementowanie tego algorytmu w procesorze lub kontrolerze? Jeśli docelowa rozdzielczość jest większa niż 16 bitów, liczba próbek rośnie bardzo szybko. Czynniki nieidealne, które wpływają na liczbę próbek w grupie to przede wszystkim dryft wejść w czasie, zmiany napięcia zasilania, niestabilności napięcia referencyjnego oraz efekty termiczne. Każde z wymienionych zjawisk może wpłynąć na błąd przetwarzania.

Przeczytaj także: Webber AP8400 - wymiana filtrów

Liczba próbek w systemie nieidealnym może się zmniejszyć z 2000 do kilkuset, gdyż zwiększanie liczby próbek w systemie nieidealnym „zaszumia” wynik i efekt jest odwrotny do zamierzonego. Można jednak stosując metodę wariancji Allana wyliczyć optymalną liczbę próbek do uśredniania tak, aby wypośrodkować między filtracją a zaszumieniem. W końcu ważny jest moment ustalenia sygnału wejściowego przetwornika oraz jego czystość widmowa. Składowe harmoniczne pochodzące np.

Rys. 2. Algorytm obliczania średniej kroczącej. Liczba próbek w grupie wynosi tu 4.

Nie zawsze można i należy filtrować z maksymalną liczbą próbek w grupie. Wszystko zależy od sygnału na wyjściu przetwornika. Inaczej, gdy jest to sygnał szybkozmienny, inaczej, gdy jest to sygnał stały. Częstotliwość graniczna filtru ze średnią kroczącą jest odwrotnie proporcjonalna do liczby próbek w grupie. Im większa liczba próbek przy stałej częstotliwości próbkowania tym niższa częstotliwość graniczna.

Istnieją również oszczędniejsze w czasie algorytmy uśredniające, które wykraczają poza brutalną metodę zbierania danych, a później obliczania z nich średniej. Przykładowo kolejka FIFO (First In First Out) może być użyta do tego celu poprzez dodanie nowej danej i odejmowanie wartości pierwszej danej w grupie. Dodatkowo rozmiar grupy tak się wybiera by umożliwić operację dzielenia jako przesuwania w prawo, a więc liczba wartości w grupie wynosi 8, 16, 32 lub więcej.

Zaletą filtru uśredniającego jest jego prostota, łatwość implementacji i niskie wymagania co do mocy obliczeniowej. Jedną z wad filtru uśredniającego jest fakt, że wprowadza on pewne opóźnienie sygnału, co może być niepożądane w niektórych aplikacjach.

Przeczytaj także: Optymalne rozcieńczenie bimbru

Poznaliśmy niezbędną dawkę teorii potrzebną do zrozumienia działania filtru uśredniającego. Znamy jego wady i zalety. Teraz pora na przykład w języku C. Ja filtr uśredniający często stosuję, gdy chcę w szybki sposób przefiltrować dane otrzymane z pomiarów sygnałów analogowych, czyli wyjście z konwertera ADC.

Do dzisiejszego przykładu wykorzystamy mikrokontroler STM32L476RG dostępny w zestawie Nucleo-L476RG. Tworzymy nowy projekt wybierając „File->New->STM32 Project”. Przechodzimy przez wstępną konfigurację projektu i zabieramy się za konfigurację wyjść mikrokontrolera. Ja wygenerowałem projekt z domyślną konfiguracją dla płytki Nucleo, dlatego część pinów mam już skonfigurowane. Do obsługi potencjometru będziemy potrzebowali wejścia analogowego. W tej roli wykorzystamy wejście 5 przetwornika ADC1 (ADC1_IN5) podłączone do pinu PA0.

Teraz możemy przejść do konfiguracji ustawień przetwornika. Konwerter ADC w mikrokontrolerach STM32 to zaawansowany i dość rozbudowany system. Daje nam wiele możliwości, ale co za tym idzie, na początku trudniej jest się odnaleźć w „gąszczu” ustawień. Podstawowym wyborem jest wybór rodzaju konwersji. Mamy do dyspozycji dwa tryby: regularny (regular) i wstrzykiwany (injected). Podstawową różnicą jest to, że tryb wstrzykiwany ma wyższy priorytet i w przypadku wywołania jednoczesnej konwersji na kanale regularnym i wstrzykiwanym, to kanał wstrzykiwany będzie obsłużony w pierwszej kolejności. Poza wyniki konwersji kanałów wstrzykiwanych są przechowywane w indywidualnych rejestrach, a kanałów regularnych w jednym wspólnym rejestrze, który trzeba dostatecznie szybko odczytać, aby nie został nadpisany przez kolejny pomiar.

Ustawienia ogólne ADC (ADC Settings):

  • Clock Prescaler - dzielnik zegara taktującego przetwornik. Wyższa wartość spowoduje, że pomiary będą wykonywane wolniej.
  • Resolution - rozdzielczość pomiaru (6, 8, 10 lub 12 bitów).
  • Data alignment - sposób wyrównania bitów danych w rejestrze wyjściowym (do prawej lub do lewej).
  • Scan Conversion Mode - tryb skanowania dostępny w przypadku wykonywania pomiarów na kilku kanałach. Powoduje, że pomiar wykonywany jest na całej grupie kanałów jeden po drugim, czyli po wykonaniu pomiaru na jednym kanale, przetwornik automatycznie wykona pomiar na kolejnym (i tak aż przejdzie wszystkie kanały).
  • Continuous Conversion Mode - tryb ciągły pomiarów, umożliwia automatyczne wystartowanie pomiarów na kanale (grupie kanałów) zaraz po ukończeniu poprzedniego.
  • Discontinuous Conversion Mode - umożliwia wykonanie pojedynczo pomiarów w grupie. W naszym przypadku będziemy wykonywali pomiar tylko na jednym kanale.

W celu poprawnego skonfigurowania przetwornika wybieramy zatem brak dodatkowego Prescalera, rozdzielczość 12-bitów oraz wyrównanie danych do prawej. Ponieważ mamy tylko jeden pomiar, nie będziemy potrzebowali trybu skanowania. Pomiar ADC będziemy chcieli mieć wywoływany co 10 ms przez timera, dlatego tryb ciągły też nie będzie nam potrzebny. Analogicznie nie potrzebujemy też trybu Discontinuous. W ustawieniach trybu regularnej konwersji, wybieramy zewnętrzne zdarzenie jako Timer 3 Trigger Out Event (czyli przepełnienie od timera 3 - lista dostępnych źródeł przerwań jest dostępna w liście rozwijanej obok parametru External Trigger Conversion Source oraz w dokumentacji „Reference Manual” na stronie 528 w tabeli 108.) oraz zbocze narastające. W ustawieniach pomieru wybieramy kanał 5 (wejście na pinie PA0) oraz najdłuższy czas konwersji, czyli 640,5 cykli, co zapewni nam większą dokładność.

Żeby wykorzystać przesyłanie danych za pomocą DMA, w zakładce DMA Settings wybieramy ADC1 i DMA1 Channel 1.

Teraz powinniśmy skonfigurować jeszcze Timer 3 w taki sposób, aby wywoływał nam pomiar na ADC co 10 ms. Wybieramy zatem Timers->TIM3. Aby skonfigurować licznik, musimy odpowiednio ustawić wartości: Prescaler i Counter Period.

Potrzebujemy zatem informacji o częstotliwości taktowania Timera 3. Aby Timer mógł generować zdarzenie dla ADC, zaznaczamy jeszcze opcję Trigger Event Selection TRGO jako Update Event.

Jak będzie wyglądał kod dla filtru uśredniającego? Jak już wspominałem na wstępie, funkcja będzie składała się w dwóch operacjach. Najpierw musimy przesunąć dane w buforze tak, aby wypadła z niego najstarsza dana, a pojawiła się najnowsza. Potem policzymy średnią z zapisanych w buforze pomiarów. Pierwszą operację możemy wykonać na dwa sposoby. Zgodnie z opisem możemy wszystkie dane w buforze przesunąć o jeden do przodu (tracąc w ten sposób ostatnią, czyli najstarszą daną w buforze) i na początku tablicy wpisać najnowszą daną. Będzie to jednak wymagało za każdym razem wykonania tylu operacji, ile danych w buforze przechowujemy. Znacznie lepszym wyjście będzie zastosowanie bufora kołowego. Dane będziemy dopisywali do bufora, jednocześnie zwiększając zmienną wskazującą na jego koniec. W momencie jak dojdziemy do końca tablicy, wrócimy na jej początek i będziemy nadpisywać najstarszą daną. Przy liczeniu średniej nie ma znaczenia w jakiej kolejności pobierzemy dane z bufora - wynik będzie taki sam. A zaoszczędzimy w ten sposób sporo czasu, ponieważ dodanie nowego pomiaru do bufora będzie polegało jedynie na zapisie jej w tablicy w odpowiednim miejscu.

Na początku musimy zapewnić, że w tablicy nie ma żadnych przypadkowych danych. Dodanie danej do bufora będzie polegało na wpisaniu jej do tablicy w miejsce aktualnego końca bufora oraz zwiększenie licznika. W ten sposób mamy wykonaną pierwszą część zadnia - nowa dana jest w buforze. Teraz pozostało policzyć średnią z pomiarów.

Przed rozpoczęciem filtrowania musimy jeszcze stworzyć nasz filtr oraz go zainicjalizować w funkcji main(). W funkcji main() wywołujemy przed pętlą while(1) start pomiaru DMA oraz uruchamiamy Timer. Program gotowy. Czas przejść do sprawdzenia działania filtru.

Oscylacje wartości w przypadku potencjometru nie są bardzo duże, ale bardzo dobrze widać, że pomiar nie jest stabilny. Pomimo tego, że nie dotykam gałki potencjometru, wartości pojedynczych pomiarów różnią się nawet o kilkanaście jednostek ADC. Wynikać to może z wielu rzeczy - słabej jakości przewodów, zbyt długich przewodów lub złego styku.

Jak można było się spodziewać, największe oscylacje są widoczne przy filtrze o najmniejszym buforze danych. Mimo wszystko nawet kilkuelementowy filtry potrafi skutecznie wygładzić dane. Długość bufora wpływa jednak nie tylko na jakość filtrowania. Zwiększanie ilości danych branych do liczenia średniej ma niestety także negatywny skutek. Im więcej danych w buforze, tym widoczne jest większe opóźnienie sygnału wyjściowego filtra. Musimy tutaj dobierać wartości w zależności od tego, do czego stosujemy filtr. Jeżeli potrzebujemy przefiltrować np. wartość napięcia z baterii, opóźnienie raczej nie będzie nam przeszkadzało - poziom baterii rzadko kiedy zmienia się szybko. Ale gdy odczytujemy dane np.

W materiale przedstawiłem podstawowe założenia i zasadę działania filtru oraz jego implementację z języku C. Pokazane przykłady filtrowania sygnału potencjometru pokazują zarówno zalety, jak i wady działania prostego, ale jakże przydatnego i często stosowanego filtru uśredniającego.

tags: #filtracja #danych #metoda #średniej #kroczącej #algorytmy

Popularne posty: