logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Uśrednianie wyników ADC (BASCOM)

grzecho_h 06 Maj 2019 23:01 957 19
REKLAMA
  • #1 17947429
    grzecho_h
    Poziom 9  
    Witam

    Chciałbym w miarę zoptymalizować swój programik, ale nie mam w tym dużego doświadczenia, więc prośba o wskazówki ;)
    Układ składa się z 4 potencjometrów (poniżej fragment kodu z dwoma w celu uproszczenia), jeden potencjometr służy jako czujnik wysokości ramienia, które porusza się z szybkością od dołu do góry w jakieś 3, 4s , ale jednak istotne jest by w miarę na bieżąco odczytywało położenie, duża zwłoka psuje wszystko, to już stwierdziałem ;). Pozostałe czujniki służą jedynie do ustalenia wysokości itp, jako takie nie biorą udziału w ruchu, tu może być duże uśrednienie, zwłoka itp. bardziej liczy się stabilność.

    Poniżej dość prosty fragment kodu jak to powinno działać, jak widać dokładność nie jest wymagana i już samo przełożenie na procenty jest sporym uśrednieniem, ale nawet tak duże uśrednienie nic nie daje bo są czasem problemy z przeskakiwaniem wyniku gdy wartośc jest bliska wartości granicznej np. 40 i 41 minimalne poruszenie pokrętła i wynik jest jak wryty. Czy da się temu jakoś zaradzić nie spowolniając mocno pracy programu? Jakieś inne uśrednianie, wybieranie wyników? Jak widać program porównuje ze sobą wartości z ADC i tez pytanie czy lepiej porównywać bezpośrednio wyniki z ADC czy po przełożeniu na procenty? Porównując wartości ze sobą zrobiłem "bufor" i działa to dość fajnie, pomimo iz wyniki czasem przeskakują (maksymalnie o 1%)

    Kod: VB.net
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #2 17947803
    Andrzej__S
    Poziom 28  
    Nie bardzo rozumiem Twoje uśrednianie:
    grzecho_h napisał:
    Kod: VB.net
    Zaloguj się, aby zobaczyć kod

    Skoro U2=C to po pętli For U2 będzie równe U2*9.
    Następnie dzielisz to przez 8 za pomocą operacji Shift, więc w efekcie końcowym U2=U2*9/8.
    Czyli tak naprawdę to nie jest uśrednianie, tylko przemnożenie pobranej próbki przez współczynnik 9/8.

    Uśrednianie (na zasadzie filtra dolnoprzepustowego) powinno wyglądać raczej jakoś tak:
    Kod: VB.net
    Zaloguj się, aby zobaczyć kod

    Należy oczywiście pamiętać o tym, że wartość U2 zbliży się zadowalająco do faktycznej wartości ADC dopiero po pobraniu kilkudziesięciu próbek, więc raczej wymaga cyklicznego próbkowania, a nie pobierania pojedynczych próbek. Osiągniecie pełnej wartości ADC może wymagać zaokrąglania po operacji dzielenia. Stała czasowa takiego filtrowania jest zależna od ilości uśrednianych próbek (w tym przypadku 8) i częstotliwości próbkowania sygnału.

    Ewentualna optymalizacja to inna sprawa, ale w tym języku programowania to raczej nie pomogę.
  • #3 17947936
    grzecho_h
    Poziom 9  
    Andrzej__S napisał:
    Skoro U2=C to po pętli For U2 będzie równe U2*9.
    Następnie dzielisz to przez 8 za pomocą operacji Shift, więc w efekcie końcowym U2=U2*9/8.
    Czyli tak naprawdę to nie jest uśrednianie, tylko przemnożenie pobranej próbki przez współczynnik 9/8.

    Może i masz racje... coś tu jest pokręcone

    U mnie próbkowanie jest w sumie stałe, program cały czas sprawdza wartości potencjometrów.
    Znalezłem też taką metode uśredniania:
    "Wyświetl pierwszą wartość, a następnie zignoruj ​​kolejne wartości, które są mniejsze niż n zliczeń powyżej / poniżej pierwszej wartości. Gdy nowa wartość przekracza limity, należy ustawić nową wartość bazową. Możesz to zmienić, dodając / odejmując procent różnicy między przechowywaną wartością a nową kwalifikowaną wartością do wartości przechowywanej. (histereza)"
    Tyle, że tak na prawdę nie wiem nawet o co chodzi i jak by to miało wyglądać, ale brzmi dość ciekawie. Niestety autor nie podał jakby to miało wyglądać w żadnym kodzie. Spróbuję podaną przez ciebie metodę filtra dolnoprzepustowego.

    Mam też filtr na wejściach ADC 1k i 100nf, może by też zwiększyć wartość rezystancji?
  • #4 17948734
    Andrzej__S
    Poziom 28  
    grzecho_h napisał:
    U mnie próbkowanie jest w sumie stałe, program cały czas sprawdza wartości potencjometrów.

    Podejrzewam, że próbkujesz w pętli głównej programu. Lepszym rozwiązaniem byłoby startować konwersję cyklicznie w stałych odstępach czasu, na przykład w przerwaniach timera.

    grzecho_h napisał:
    Mam też filtr na wejściach ADC 1k i 100nf, może by też zwiększyć wartość rezystancji?

    Przedstawiony przeze mnie filtr cyfrowy działa podobnie jak filtr RC, ale myślę, że dodatkowa filtracja sprzętowa nie powinna zaszkodzić. Pamiętaj jednak o tym, że takie filtry powodują pewne opóźnienie wartości odczytu w stosunku do faktycznej wartości mierzonego sygnału (błąd tym większy, im większa stała czasowa filtra). Jeśli za pomocą ADC mierzysz pozycję szybko poruszającego się elementu, zbyt duża stała czasowa filtra może powodować powstanie nieakceptowalnej różnicy pomiędzy pozycją zmierzoną a faktyczną.

    Odnośnie optymalizacji. Skoro przeliczasz odczyt na procenty, to najprawdopodobniej wystarczyłaby Ci rozdzielczość 8-bitowa (zamiast 10-bitowej), czyli można z ADC odczytywać tylko najstarsze 8 bitów. Zarówno operacje porównania jak i obliczenia na liczbach 1-bajtowych będą na pewno szybsze. Dodatkowo zrezygnowałbym z przeliczania odczytu na procenty. To też zaoszczędziłoby nieco czasu. Wartości do porównań można sobie odpowiednio przeliczyć i operować bezpośrednio wartościami ADC. Niestety nie znam ani Bascoma, ani szczegółów Twojego projektu, więc dokładniej Ci nie podpowiem.
  • REKLAMA
  • #5 17948830
    grzecho_h
    Poziom 9  
    Andrzej__S napisał:
    Podejrzewam, że próbkujesz w pętli głównej programu. Lepszym rozwiązaniem byłoby startować konwersję cyklicznie w stałych odstępach czasu, na przykład w przerwaniach timera.

    Owszem póki co wszystkie próbkowania znajdują sie w pętli głównej... Trzy z czterech kanałów faktycznie mozna by próbkować z dużo mniejszą częstotliwością, bo te wartości mało kiedy się zmieniają, Odczyt aktualnej wysokości raczej musi siedzieć w pętli głównej bo to się czesto zmienia i z dość dużą szybkością. Generalnie precyzja nie jest wymagana, a raczej stabilność. Aby mi nie skakało na przekaźnikach. Z tą rozdzielczością ADC chodzi o ustawienia przetwornika czy trzeba te niepotrzebne bity jakoś inaczej odcinać?
  • #6 17948864
    Andrzej__S
    Poziom 28  
    grzecho_h napisał:
    Z tą rozdzielczością ADC chodzi o ustawienia przetwornika czy trzeba te niepotrzebne bity jakoś inaczej odcinać?

    Należy ustawić bit ADLAR (ADC Left Adjust Result) w rejestrze ADMUX i później odczytywać tylko rejestr ADCH (będzie zawierał najstarsze 8 bitów).
  • REKLAMA
  • #7 17949646
    grzecho_h
    Poziom 9  
    Dzięki za rady, z tym odczytem 8 bitowym w Bascomie to widzę, że nie taka prosta sprawa... Podobno sie da, ale trzeba operować odpowiednimi rejestrami..
  • REKLAMA
  • #8 17950394
    LChucki
    Poziom 31  
    Andrzej__S napisał:
    grzecho_h napisał:
    Z tą rozdzielczością ADC chodzi o ustawienia przetwornika czy trzeba te niepotrzebne bity jakoś inaczej odcinać?

    Należy ustawić bit ADLAR (ADC Left Adjust Result) w rejestrze ADMUX i później odczytywać tylko rejestr ADCH (będzie zawierał najstarsze 8 bitów).

    AVR ma buforowanie zapisu/odczytu rejestrów 16-bit. Jak dobrze pamiętam, trzeba odczytać ADCL, to spowoduje zatrzaśnięcie danych, po tym odczytuje się ADCH. Fakt, ze AVR od dłuższego czasu nie zajmuję się ale jak pamiętam, taki mechanizm odczytu funkcjonuje nie tylko w timerach ale także w ADC>
  • #9 17950810
    Andrzej__S
    Poziom 28  
    LChucki napisał:
    AVR ma buforowanie zapisu/odczytu rejestrów 16-bit. Jak dobrze pamiętam, trzeba odczytać ADCL, to spowoduje zatrzaśnięcie danych, po tym odczytuje się ADCH. Fakt, ze AVR od dłuższego czasu nie zajmuję się ale jak pamiętam, taki mechanizm odczytu funkcjonuje nie tylko w timerach ale także w ADC>

    Jaki to ma związek z tym co napisałem? Ty piszesz o odczycie 16-bitowego rejestru, a ja o odczycie 8-bitowego.

    Wcześniej w tym wątku:
    Cytat:
    Skoro przeliczasz odczyt na procenty, to najprawdopodobniej wystarczyłaby Ci rozdzielczość 8-bitowa (zamiast 10-bitowej), czyli można z ADC odczytywać tylko najstarsze 8 bitów.
    ...
    Należy ustawić bit ADLAR (ADC Left Adjust Result) w rejestrze ADMUX i później odczytywać tylko rejestr ADCH (będzie zawierał najstarsze 8 bitów).

    Atmel napisał:
    Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH.
  • #10 17950843
    LChucki
    Poziom 31  
    Andrzej__S napisał:
    LChucki napisał:
    AVR ma buforowanie zapisu/odczytu rejestrów 16-bit. Jak dobrze pamiętam, trzeba odczytać ADCL, to spowoduje zatrzaśnięcie danych, po tym odczytuje się ADCH. Fakt, ze AVR od dłuższego czasu nie zajmuję się ale jak pamiętam, taki mechanizm odczytu funkcjonuje nie tylko w timerach ale także w ADC>

    Jaki to ma związek z tym co napisałem? Ty piszesz o odczycie 16-bitowego rejestru, a ja o odczycie 8-bitowego.

    ADC ma rejestr 16-bit.
  • Pomocny post
    #11 17950919
    bart-projects
    Poziom 29  
    Do Autora wątku:
    Proszę. Nie taki diabeł straszny. Nie napisałeś jaki to procesor więc napisałem przykład dla Mega8.
    Funkcja odczytuje ADC(0-5) z włączony ADLAR czyli tylko osiem bitów. Wynik od 0 do 255.
    Zapewne działa nawet w symulatorze. To taki podstawowy. Można nie czekać a ustawić przerwanie, ale to pewnie jeszcze nie dla Ciebie :D

    Wpisz w Google "uśrednianie wyników ADC bascom" a może znajdziesz moją stronkę gdzie opisałem kilka sposobów uśredniania wyników ADC w Bascom.

    Kod: VB.net
    Zaloguj się, aby zobaczyć kod
  • #12 17950941
    Andrzej__S
    Poziom 28  
    LChucki napisał:
    Fakt, ze AVR od dłuższego czasu nie zajmuję się

    To może jednak nie wypowiadaj się w temacie, lub przynajmniej, zanim coś napiszesz, poczytaj dokumentację.
  • #13 17951003
    grzecho_h
    Poziom 9  
    Póki co i tak nie bardzo wiem jak to zrobić w bascomie, dopiero szukam informacji w necie, ale za to wziąłem się za licznik by odczytywać ADC co jakis czas, a którego dotąd też jeszcze nie używałem. W sumie nic trudnego w tym, tylko co teraz wykonywać w tym przerwaniu?Jedynie odczyty z ADC, a obliczenie w głównej pętli czy właściwie wszystko tam umieścić czyli odczyt, konwersja na procenty, uśrednianie i obsługa LCD?

    Dodano po 6 [minuty]:

    grzecho_h napisał:
    Do Autora wątku:
    Proszę. Nie taki diabeł straszny. Nie napisałeś jaki to procesor więc napisałem przykład dla Mega8.
    Funkcja odczytuje ADC(0-5) z włączony ADLAR czyli tylko osiem bitów. Wynik od 0 do 255.
    Zapewne działa nawet w symulatorze. To taki podstawowy. Można nie czekać a ustawić przerwanie, ale to pewnie jeszcze nie dla Ciebie :D


    A no jeszcze nie dla mnie ;), ale dzięki za przykład . Rozumie, że nie ma problemu by ustawiać tak tylko wybrane kanały?
  • #14 17951064
    bart-projects
    Poziom 29  
    Nie chodziło mi o przerwanie od Timera tylko o coś takiego że odpalasz konwersję/pomiar oraz przerwanie kiedy będzie już wynik czyli procesor nie czeka a może w tym czasie zrobić coś innego. Jednak ta funkcja wykonuje się w 107 taktów zegara w 0.01ms więc myślę, że nie masz co kombinować.
    Lepiej byś napisał co to za procesor i jakie ma taktowanie bo niektóre nowsze mają bardziej rozwinięte nazwy rejestrów i szkoda potem pisać coś dwa razy. Np. Mega8 i Mega32 mają chyba tylko jeden TIFR a już Mega328P, Mega88, Mega644P mają osobny TIFR na każdy timer czyli TIFR0, TIFR1, TIFR2 itd...
    Dla Mega8 przy 8MHz możesz sobie mierzyć czas nie używając przerwań. Np. tak:
    Kod: VB.net
    Zaloguj się, aby zobaczyć kod


    Co do odczytu innych wejść z dokładnością 10bit to musiałbyś na końcu funkcji kasować bit ADLAR bo Bascom tego sam nie zrobi.
    Czyli albo na końcu funkcji albo gdzieś przed normalnym Word = Getadc() musiałbyś napisać "Reset ADMUX.ADLAR"
  • #15 17951103
    grzecho_h
    Poziom 9  
    Procesor to Atmega328p jeśli o to chodzi. Czyli jak dobrze rozumie zrezygnować z timera odmierzającego czas próbkowania np. co 2ms a zastosowac powyższą funkcje? No przyznam, że nieco się już pogubiłem jesli chodzi o tą optymalizacje odczytów z ADC i jego przeliczeń, robić je w okresowo czy pozastawić w głównej pętli?
  • #16 17951149
    bart-projects
    Poziom 29  
    Nie wiem co tam chcesz optymalizować bo nie wiemy na co się program uskarża :D
    Najczęstszym spowalniaczem nie jest ADC tylko zbyt częste odświeżanie/mielenie po wyświetlaczu. Jeśli nie wykorzystujesz pinu WR wyświetlacza to jest on obsługiwany stałymi opóźnieniami czasowymi. Wtedy warto po nim pisać tylko jeśli coś co ma być widoczne się zmieniło.
    Np. masz tam te swoje procenty. Dodajesz kolejną zmienną Prev_procent i tylko kiedy nowy procent różni się od poprzedniego to go wyświetlasz.
    Kod: VB.net
    Zaloguj się, aby zobaczyć kod


    Jeśli uśredniasz to lepiej jest czytać ADC często. Musisz wiedzieć jaki potrzebujesz najkrótszy czas w programie i tak sobie ustawić Timer.
    Dla płytki Arduino 10ms przy 16MHz uzyskasz tak:
    Kod: VB.net
    Zaloguj się, aby zobaczyć kod
  • #17 17951530
    grzecho_h
    Poziom 9  
    Pin WR akurat wykorzystuje i faktycznie samo to znacznie przyspieszyło prace, choć chętnie bym skonsultował czy prawidłowo (wieczorem pokaże kod), ale i tak twój pomysł z tymi procentami jest bardzo ciekawy i tez powinien przyspieszyć prace. Na razie wszystko miałem wrzucone w główną pętle bez timerów także było sporo mielenia.

    Edit
    Widzę, że kolega zjadł zęby na Bascomie ;). Widziałem Twoje przykłady uśredniania, na pewno z nimi poćwiczę, zastosowałeś nawet mediane, a dominate (najczęściej występujące w zbiorze) kolega próbował? Trudno coś takiego zrobić?
  • #19 17953023
    dondu
    Moderator na urlopie...
    LChucki napisał:
    AVR ma buforowanie zapisu/odczytu rejestrów 16-bit. Jak dobrze pamiętam, trzeba odczytać ADCL, to spowoduje zatrzaśnięcie danych, po tym odczytuje się ADCH. Fakt, ze AVR od dłuższego czasu nie zajmuję się ale jak pamiętam, taki mechanizm odczytu funkcjonuje nie tylko w timerach ale także w ADC>

    Nie w przypadku ustawienia bitu ADLAR.
    Po to jest wyrównanie do lewej, by nie trzeba było odczytywać w odpowiedniej kolejności, bo ideą wyrównania do lewej jest z reguły odczyt tylko 8 najbardziej znaczących bitów, a te znajdą się w rejestrze ADCH:

    Uśrednianie wyników ADC (BASCOM)
  • #20 17954070
    LChucki
    Poziom 31  
    dondu napisał:
    LChucki napisał:
    AVR ma buforowanie zapisu/odczytu rejestrów 16-bit. Jak dobrze pamiętam, trzeba odczytać ADCL, to spowoduje zatrzaśnięcie danych, po tym odczytuje się ADCH. Fakt, ze AVR od dłuższego czasu nie zajmuję się ale jak pamiętam, taki mechanizm odczytu funkcjonuje nie tylko w timerach ale także w ADC>

    Nie w przypadku ustawienia bitu ADLAR.

    Dokładniej nie w przypadku ADC. Buforowane są rejestry timerów 16-bit (TCNTx, ICRx). W dokumentacji nie znalazłem nic o buforowaniu rejestru ADC, które byłoby przydatne tylko w trybie FreeRun.

    Moderowany przez dondu:

    Skoro wreszcie kolega przeczytał dokumentację, to proszę to robić przed udzielaniem podpowiedzi, ponieważ to kolega sugerował buforowanie i konieczności odczytu ADCL przy ustawieniu ADLAR.

    Sugeruję także uderzyć się czasami w piersi i przy złej własnej podpowiedzi zacząć ją dementować, od zwrotu: "Przepraszam pomyliłem się. Sprawdziłem w dokumentacji i ..."

REKLAMA