Zwykła średnia
Najprostszym sposobem jest zebranie kilku próbek i podzielenie ich. Na przykład, wynik z ADC ma maksymalnie 1023 a Word pomieści 65536. Można więc spokojnie w jednym takim Word dodać do siebie 64 pomiary i potem szybko podzielić przez 64.
Wadą tego rozwiązania jest to, że program się tu zatrzymuje na czas pomiarów. Czyli musi 64 razy zmierzyć...
Można zbierać mniej próbek... W zależności od programu nie musi to wcale przeszkadzać. Kod takiego rozwiązania, gotowy do przetestowania w Bascomowym symulatorze, poniżej. Zwróć uwagę że Bascom pod suwakiem ADC pokazuje co ustawiłeś a na wyświetlaczu masz wynik
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $regfile = "m8def.dat"
- $crystal = 8000000
- $hwstack = 40
- $swstack = 16
- $framesize = 32
- $sim
- 'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
- Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
- Config Lcd = 16x2
- Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
- Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
- Cursor Off
- Cls
- Config Adc = Single , Prescaler = Auto , Reference = Avcc
- Const Ilosc_probek = 50
- Dim Adc_read As Word , Idx As Byte
- Do
- Adc_read = 0
- For Idx = 1 To 64
- Adc_read = Adc_read + Getadc(0)
- Next
- Shift Adc_read , Right , 6
- Locate 1 , 1 : Lcd Adc_read ; " "
- Loop
Średnia ciągniona
Innym sposobem jest przechowywanie większej ilości poprzednich wyników a nowe odczyty pomału wpływają na na całość średniej.
W tym celu musimy mieć tablicę Wordów(n) i to jest po części wadą tego rozwiązania jeśli mamy uC z małą ilością SRAM.
Sposób działania jest prosty. Mamy zmienną która pokazuje do której komórki tablicy zapiszemy sobie nowy wynik (tutaj Idx).
Zawsze odczytujemy nowy wynik i zawsze sumujemy wszystkie próbki a potem dzielimy przez ilość próbek. To jakby drugi minus tego rozwiązania.
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $regfile = "m8def.dat"
- $crystal = 8000000
- $hwstack = 40
- $swstack = 16
- $framesize = 32
- $sim
- 'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
- Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
- Config Lcd = 16x2
- Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
- Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
- Cursor Off
- Cls
- Config Adc = Single , Prescaler = Auto , Reference = Avcc
- Const Ilosc_probek = 50
- Dim Tablica(ilosc_probek) As Word
- Dim Idx As Byte , Iteration As Byte
- Dim Sum As Dword , Wynik As Word
- Do
- Incr Idx : If Idx > Ilosc_probek Then Idx = 1
- Tablica(idx) = Getadc(0)
- Sum = 0
- For Iteration = 1 To Ilosc_probek
- Sum = Sum + Tablica(iteration)
- Next
- Sum = Sum / Ilosc_probek
- Wynik = Sum
- Locate 1 , 1 : Lcd Wynik ; " "
- Loop
Inne rozwiązanie
Kolejne rozwiązanie nie potrzebuje ani czekać na dużo pomiarów, ale też nie potrzebuje tablicy. Poprzednia suma jest przechowywana w zmiennej typu DWORD.
Wystarczy popatrzeć żeby zobaczyć jak to działa Jeśli masz więcej kanałów ADC do uśrednienia to dla każdego potrzebujesz osobną Sumę DWORD (cztery bajty).
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- $regfile = "m8def.dat"
- $crystal = 8000000
- $hwstack = 40
- $swstack = 16
- $framesize = 32
- $sim
- 'OZNACZA PRZYGOTOWANIE KODU DO SYMULACJI - USUNĄĆ DLA PRAWDZIWEGO MIKROKONTROLERA
- Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
- Config Lcd = 16x2
- Deflcdchar 0 , 32 , 32 , 14 , 17 , 31 , 16 , 14 , 1
- Deflcdchar 2 , 32 , 32 , 14 , 1 , 15 , 17 , 15 , 1
- Cursor Off
- Cls
- Config Adc = Single , Prescaler = Auto , Reference = Avcc
- Dim Adc_read As Word
- Dim Suma As Dword
- Dim Wynik As Word
- Dim Help As Dword
- Do
- Adc_read = Getadc(0)
- Help = Suma
- Shift Help , Right , 3
- Suma = Suma - Help
- Suma = Suma + Adc_read
- Help = Suma
- Shift Help , Right , 3
- Wynik = Help
- Locate 1 , 1 : Lcd Wynik ; " "
- Loop
- End
Oczywiście metodą średniej ciągnionej przyspieszymy kod zmniejszając ilość próbek (wielkość tablicy).
Można też użyć ilośc próbek która będzie potęgą dwójki czyli 16,32,64 i skorzystać z szybkiego dzielenia przesunięciem bitowym Shift.
Mediana
Mediana - odsyłam do Wikipedii jeśli nie uda mi się tego przedstawić jaśniej - to "zebranie kilku próbek, posortowanie ich w kolejności rosnącej/malejącej i wybranie środkowej"
Najprościej pisząc. Jeśli mamy zbiór pięciu odczytów z ADC (do tego musimy je przechowywać w tablicy) to na końcu sortujemy je.. i tak powiedzmy, że odczyty były 512, 511, 120, 513,511 to widać że odczyty głównie mają 512, ale jeden odczyt 120 zaburza cała sprawę i dla średniej arytmetycznej miałby duży wpływ..
Natomiast mediana to posortowanie tych wyników od najmniejszego do największego i wybranie środkowego. To odrzuca anomalie.
Sortujmy 120,511,511,512,513 i wynikiem tej mediany będzie 511 kiedy średnia arytmetyczna wyniosłaby...433! (dodaj wszystkie do siebie i podziel/5)
Najprostszy kod mediany poniżej. Sort to funkcja Bascoma
Code: [Zaznacz cały] [Rozwiń/Zwiń]
- Const Ilosc_probek_adc = 5
- Const Mediana_adc =(ilosc_probek_adc + 1) / 2
- Dim Adcy(ilosc_probek_adc) As Word
- N = Ilosc_probek_adc : Adc_sum = 0
- Do
- Adcy(n) = Getadc(adca , 3 )
- Decr N
- Loop Until N = 0
- Sort Adcy(1)
- Adc_result = Adcy(mediana_adc)