Skocz do zawartości

Liczenie średniej z pomiarów ACS712


Ra5273x

Pomocna odpowiedź

Jeśli "bez opóźnień" oznacza, że nie chcesz za każdym razem wykonywać 20 pomiarów tj. czekać na ich zrobienie, to spróbuj tego:

  1. Stwórz tablicę/bufor na 20 wyników pomiarów
  2. Zrób miejsce na nowy wynik na początku tablicy, przesuwając jej zawartość o 1 pozycję w górę. Najstarszy wynik (ten w ostatniej komórce) tym samym ulega zapomnieniu.
  3. Zrób pomiar i wstaw go do pustego miejsca w tablicy.
  4. Policz średnią przez zsumowanie i podzielenie przez długość tablicy i użyj jej jak uważasz.
  5. Tu jest "dalsza część programu"..
  6. Zawróć do pkt. 2

Oczywiście to nic innego jak tzw.filtr moving average. Jego historię można trzymać w tzw. buforze kołowym dzięki czemu unikamy przesuwania zawartości tablicy, ale powyższy schemat jest chyba prostszy do wytłumaczenia idei.Reszta to szczegóły implementacji.Czy to jest mniej więcej to o czym myślałeś?

BTW: Oczywiście przez pierwszych 20 pomiarów średnia wyjściowa będzie zaniżona, bo tablica na początku będzie wypełniona zerami i wynik będzie musiał "dociągnąć" do poprawnej wartości. Żeby przyspieszyć "rozbieg" filtra możesz np. na początku wykonać jeden pomiar "startowy" i nim wypełnić całą tablicę (np. w punkcie 1).

Im dłuższy filtr zrobisz tym lepiej będzie uśredniał i wycinał szumy, ale też odpowiedź na zmiany wartości prądu będzie wolniejsza.Musisz wybrać jakiś kompromis.

Jeśli walczysz z konkretnym zakłóceniem (np. tętnienia sieci 50Hz) to musisz staranne dobrać długość filtra i częstość nowych pomiarów tak, by zapełnienie całej tablicy trwało dokładnie tyle ile okres zakłóceń. Wtedy będziesz je miał tłumione najlepiej. Przykładowo dla sieci 50Hz (okres 20ms) i tablicy o długości 20 musiałbyś kolejne pomiary robić co 1ms.

Jeżeli szkoda Ci lub brakuje pamięci RAM na długą tablicę, możesz użyć filtra np. IIR pierwszego rzędu, gdzie przechowujesz tylko jedną liczbę, ale ten z kolei wymaga użycia nieco bardziej przemyślanej arytmetyki żeby głupio nie wpaść.

  • Lubię! 2
Link do komentarza
Share on other sites

Nie mam pojęcia jak to zrobić aktualnie mam zrobione tak jak w poniższym kodzie ale nie działa to jak należy bo robi średnia i przechodzi dopiero dalej a musi to w czasie rzeczywistym być i najlepiej w odstępach 100ms 10 pomiarów. Mój kod nie ma żadnego delay(oprócz 5ms na średniej) bo nie może być i musi mierzyć prąd silnika w czasie jego pracy. Nie może to chyba być w pętli for bo ona blokuje program na chwile.

  for(int i = 0; i < 10; i++){
    Suma3 = Suma3 + I3 ;
    delay(5);                              ///////////////////     TEST
  }
  Prad3 = Suma3 / 10 ;
  Suma3 = 0;
  Serial.print("Prad I3 = ");
  Serial.print(Prad3);
  Serial.print(" Odczyt ADC ");
  Serial.println( I3 );

 

A najlepiej jakby średnia była z 20-30 pomiarów + usuwanie śmieci poniżej 0.5A

Link do komentarza
Share on other sites

Przecież Ci napisałem jak masz to zrobić. Jeśli zastąpisz tę swoją pętlę for punktami 2-4, to za każdym jednym pomiarem dostajesz nową średnią z tylu ostatnich ile chcesz. O czym nie masz pojęcia? Nie umiesz przełożyć tych kilku prostych  punktów na kod czy nie rozumiesz jak to wpleść do tego co już masz? Nigdzie nie pisałem o opóźnieniach więc jeśli Twój program też ich nie używa to chyba dobrze?

Może napisz w punktach co dokładnie robi cały Twój kod i jak go zorganizowałeś albo po prostu go wklej. Napisz co to za urządzenie i co ma robić, bo jak na razie to musimy się domyślać, że mierzysz prądy jakiegoś silnika, że masz duże kłopoty z zakłóceniami i że nie możesz utknąć na pomiarach. Pytanie podstawowe: czy nie rozumiesz zaproponowanej metody rozwiązania czy też może po prostu masz problemy z samym językiem i programowaniem w nim? To dwie różne rzeczy.

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)

Nie wiem za bardzo jak używać tablic, a program działa po prostu tak że silnik jest sterowany w pewnych momentach a pomiar prądu ma być ciągle wykonywany co około 100ms i uśredniany.

Zrobiłem coś takiego i chyba działa 

  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
    
  if (roznicaCzasu >= 10UL) {
    //Zapamietaj aktualny czas
    I3[x] = analogRead(A6);
    x++;
    if(x > 9){
      x = 0;
      Suma3 = 0;
    }

  }
  Suma3 = I3[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  Prad3 = Suma3 / 10 ;
  Serial.print("Prad I3 = ");
  Serial.print(Prad3);
  Serial.print(" Odczyt ADC ");
  Serial.println( I3[x] );

 

Edytowano przez radex324
Link do komentarza
Share on other sites

Nie wiem, w ogóle tego nie rozumiem.

19 minut temu, radex324 napisał:

pomiar prądu ma być ciągle wykonywany co około 100ms i uśredniany

Co to znaczy? Ciągle czyli co 5ms, ale uśrednianie za ostanie 100ms? Czy ciągle oznacza raz na 100ms?

Wiesz, to trochę jest tak: jeśli nie chce Ci się wysilić i dokładnie opisać funkcjonalności swojego programu, to nikomu nie będzie się chciało odpowiadać na mętne pytania, bo to strata czasu i można strzelić kulą w płot. Ja mogę jedynie przepisać te moje punkty bardziej na C, może to w czymś pomoże:

1. Stwórz tablicę/bufor na 20 wyników pomiarów:

#define FILTER_LENGTH  20
uint16_t filter_core[FILTER_LENGTH];

2. Zrób miejsce na nowy wynik na początku tablicy, przesuwając jej zawartość o 1 pozycję w górę. Najstarszy wynik (ten w ostatniej komórce) tym samym ulega zapomnieniu:

for (uint8_t n=FILTER_LENGTH-1; n>0; n--)
  filter_core[n-1] = filter_core[n];

3. Zrób pomiar i wstaw go do pustego miejsca w tablicy:

filter_core[0] = analogRead(CURRENT_CHANNEL);

4. Policz średnią przez zsumowanie i podzielenie przez długość tablicy i użyj jej jak uważasz.

Uwaga: 16-bitowa zmienna sum pomieści maksymalnie sumę co najwyżej 63 pomiarów ADC więc bez jej wydłużenia tylko taki filtr możesz tutaj obsłużyć:

uint16_t sum = 0;
for (uint8_t n=0; n<FILTER_LENGTH; n++)
   sum += filter_core[n];
sum /= FILTER_CORE;

5 Tu jest "dalsza część programu".. czyli korzystasz ze zmiennej sum, np. przeliczasz ją na fizyczne Ampery, coś tam włączasz lub sterujesz itp.

6. I tu wracasz do początku. Jeżeli zapewnisz, by całość programu będzie się wykonywać powiedzmy 5ms a filtr ma długość 20 to średnia będzie liczona za każdym razem za ostatnie 100ms, proste.

Czy to jakoś rozjaśnia mroki?

  • Lubię! 2
Link do komentarza
Share on other sites

Zrobiłem to po swojemu ale dzięki za pomoc, jeszcze trochę potrwa zanim ogarnę bardziej.

void loop() {
  
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;
  
    //Jeśli różnica wynosi 10ms
  if (roznicaCzasu >= 10UL) {
    //Zapamietaj aktualny czas
    I3[x] = analogRead(A6);
    I4 = analogRead(A6);
    x++;
    if(x > 9){
      x = 0;
      Suma3 = 0;
    }

  }
  Suma3 = I3[0] + I3[1] + I3[2] + I3[3] + I3[4] + I3[5] + I3[6] + I3[7] + I3[8] + I3[9];
  Prad3 = Suma3 / 10 ;
  Serial.print("Prad I3 = ");
  Serial.print(Prad3);
  Serial.print(" Odczyt ADC ");
  Serial.println( I4 );

 

Link do komentarza
Share on other sites

Zrobiłeś bufor kołowy i dobrze. Niepotrzebnie czasem zerujesz zmienną Suma3, bo przecież i tak za każdym razem liczysz do niej sumę wszystkiego.

Jedyną poważną głupotą jest podwójne wywołanie funkcji analogRead(), bo przecież prawie na pewno oba pomiary oddadzą dwa różne wyniki - przecież z tym właśnie walczysz. Jeden wynik wstawiasz do tablicy a drugi wypisujesz jako aktualny co jest oczywistym kłamstwem. Może wystarczy tak?

I4 = I3[x] = analogRead(A6);

EDIT: I jeszcze jedno: Serial.print nie wykonuje się w zerowym czasie. Co więcej, jeśli przekroczysz możliwości swojego UARTa (a te zależą od przyjętej prędkosci transmisji) to ta funkcja może być absurdalnie wolna. Z tego powodu ograniczaj do minimum wypisywanie czegokolwiek w takich szybkich pętlach, bo inaczej o tych 10ms to będziesz mógł tylko pomarzyć. Wszelkie teksty są zbędne, pisz tylko wyniki liczbowe. Przecież teraz, przy oczekiwanym obrocie pętli = 10ms  musiałbyś dostawać (i czytać?) 100 linii tekstu na sekundę. Jaką ustawiłeś prędkość? Nawet na 115200 możesz wysłać tylko 11000 znaków/s.

Edytowano przez marek1707
  • Lubię! 2
Link do komentarza
Share on other sites

 

Masz racje z tym podwójnym pomiarem, przerobiłem sobie kod który już działa na 2 czujnikach ale wywala mi błąd. Nie mam pojęcia co robię źle obie zmienne są tego samego typu.

 //Pobierz liczbe milisekund od startu
  aktualnyCzas = millis();
  roznicaCzasu = aktualnyCzas - zapamietanyCzas;

    /*odczyt pradu z czujnikow */
  float I1 = sensor1.getCurrentDC();
  float I2 = sensor2.getCurrentDC();
  /*odczyt pradu z czujnikow */
  
    
  if (roznicaCzasu >= 1UL) {
    //Zapamietaj aktualny czas
    Prad1[x] = I1;
    Prad2[x] = I2;

    x++;
    if(x > 9){
      x = 0;
      Suma1 = 0;
      Suma2 = 0;
    }

  }
  Suma1 = Prad1[0] + Prad1[1] + Prad1[2] + Prad1[3] + Prad1[4] + Prad1[5] + Prad1[6] + Prad1[7] + Prad1[8] + Prad1[9];
  Prad1 = Suma1 / 10 ;

  Suma2 = Prad2[0] + Prad2[1] + Prad2[2] + Prad2[3] + Prad2[4] + Prad2[5] + Prad2[6] + Prad2[7] + Prad2[8] + Prad2[9];
  Prad2 = Suma2 / 10 ;
incompatible types in assignment of 'float' to 'float [10]'

 

Te wysyłanie na serial  to tylko test potem to będzie wyłączone jak podłącze silniki i będę na żywo testował.

Link do komentarza
Share on other sites

roznicaCzasu >= 1UL

Chcesz zejść do 1ms???

Nie możesz zrobić czegoś takiego:

Prad1 = Suma1 / 10 ;

Przecież Prad1 to tablica. Wymyśl sobie jakaś inna zmienna na średni prąd, np.

float sredniPrad1 = Suma1 / 10.0;

Po co nadal zerujesz sumy?

  • Lubię! 2
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.