Obecnie opracowuję graficzny system LCD do wyświetlania temperatur, przepływów, napięć, mocy i energii w systemie pompy ciepła. Zastosowanie graficznego wyświetlacza LCD oznacza, że połowa mojej pamięci SRAM i ~ 75% mojej pamięci flash została wykorzystana przez bufor ekranu i łańcuchy.
Obecnie wyświetlam min / maks / średnie wartości energii O północy, kiedy dzienna liczba resetuje się, system sprawdza, czy zużycie w danym dniu jest wyższe lub niższe od poprzedniego minimum lub maksimum i zapisuje wartość. Średnia jest obliczana poprzez podzielenie skumulowanego zużycia energii przez liczbę dni.
Chciałbym wyświetlić średnią dzienną z ostatniego tygodnia i miesiąca (dla uproszczenia 4 tygodnie), tj. Średnią kroczącą. Obecnie obejmuje to utrzymywanie tablicy wartości z ostatnich 28 dni i obliczanie średniej dla całej tablicy dla miesiąca i ostatnich 7 dni dla tygodnia.
Początkowo robiłem to przy użyciu tablicy pływaków (ponieważ energia ma postać „12,12 kWh”), ale wykorzystywało to 28 * 4 bajtów = 112 bajtów (5,4% SRAM). Nie mam nic przeciwko posiadaniu tylko jednego miejsca po przecinku, więc zmieniłem na użycie uint16_t i pomnożenie liczby przez 100. Oznacza to, że 12.12 jest reprezentowane jako 1212 i dzielę przez 100 dla celów wyświetlania.
Rozmiar tablicy spadł do 56 bajtów (znacznie lepiej!).
Nie ma żadnego trywialnego sposobu na zmniejszenie liczby do uint8_t, który widzę. Mogłem tolerować utratę miejsca po przecinku („12,1 kWh” zamiast „12,12 kWh”), ale zużycie jest często wyższe niż 25,5 kWh (255 to najwyższa wartość reprezentowana przez 8-bitową liczbę całkowitą bez znaku). Zużycie nigdy nie było niższe niż 10,0 kWh lub wyższe niż 35,0 kWh, więc możliwe, że mógłbym odjąć 10 od przechowywanych liczb, ale wiem, że pewnego dnia przekroczymy te limity.
Następnie przetestowałem kod, aby spakować wartości 9-bitowe do tablicy. Daje to zakres 0-51,2 kWh i zużywa łącznie 32 bajty. Jednak dostęp do takiej tablicy jest dość powolny, szczególnie gdy trzeba iterować wszystkie wartości, aby obliczyć średnią.
Moje pytanie brzmi zatem - czy istnieje bardziej skuteczny sposób obliczania średniej ruchomej z trzema oknami - czas życia, 28 dni i 7 dni? Wydajność oznacza mniejsze wykorzystanie SRAM, ale bez kary za ogromny kod. Czy mogę uniknąć przechowywania wszystkich wartości?
źródło
Odpowiedzi:
Jeśli dane mają niskie odchylenie standardowe, jedną z metod byłoby zsumowanie wartości w oknie, a następnie odejmowanie średniej od sumy, dodając nową wartość.
Działałoby to dobrze, gdyby nie było wartości odstających , prowadząc w ten sposób do błędu agregacji zmierzającego do zera w czasie.
źródło
możesz użyć innej metody, utrzymasz bieżącą średnią, a następnie zrobisz to
nie jest to prawdziwa średnia krocząca i ma inną semantykę, ale może jednak pasować do twoich potrzeb
dla bardziej wydajnej metody obliczania dla rozwiązania 9 bitów na wartość możesz przechowywać 8 najwyższych bitów wartości w tablicy i oddzielić najmniej znaczące bity:
aby ustawić wartość, musisz ją podzielić
powodując 2 przesunięcia AND i OR i nie
aby obliczyć średnią, możesz użyć różnych sztuczek bitowych, aby ją przyspieszyć:
możesz użyć wydajnej równoległej liczby bitów dla
bitcount()
źródło
A może zachowasz tylko różnicę od poprzedniej wartości? W elektronice istnieje podobna koncepcja zwana konwerterem Delta Sigma, która jest stosowana w przetwornikach DA / AD. Opiera się na fakcie, że poprzedni pomiar jest dość zbliżony do bieżącego.
źródło
Dlaczego nie możesz po prostu dodać wartości razem, jak tylko je uzyskasz. Mam na myśli to, że otrzymujesz wartość z pierwszego dnia, dzielisz ją przez 1 i przechowujesz gdzieś. Następnie mnożymy 1 przez wartość i dodajesz ją do następnej wartości i dzielisz je oba przez 2.
Wykonanie tej metody stworzyłoby średnią kroczącą z dwiema lub trzema zmiennymi, o ile mogę myśleć. Napisałbym trochę kodu, ale jestem nowy w stosie wymiany, więc proszę o wyrozumiałość.
źródło
Może być wystarczająco blisko, przechowując 11 wartości zamiast 28 wartości, być może coś w stylu:
Innymi słowy, zamiast przechowywać każdy szczegół każdego dnia przez ostatnie 27 dni, (a) przechowuj około 7 wartości szczegółowych informacji dziennych z ostatnich 7 dni, a także (b) przechowuj około 4 „podsumowane” wartości całkowitej lub średniej informacji dla każdego z ostatnich 4 lub kilku tygodni.
źródło