Derzeit entwickle ich ein grafisches LCD-System zur Anzeige von Temperaturen, Durchflüssen, Spannungen, Leistung und Energie in einem Wärmepumpensystem. Die Verwendung eines grafischen LCD bedeutet, dass die Hälfte meines SRAM und ~ 75% meines Blitzes von einem Bildschirmpuffer und Zeichenfolgen verbraucht wurden.
Ich zeige derzeit Min / Max / Durchschnittswerte für Energie an. Um Mitternacht, wenn der Tageswert zurückgesetzt wird, prüft das System, ob der Verbrauch für den Tag über oder unter dem vorherigen Minimum oder Maximum liegt, und speichert den Wert. Der Durchschnitt wird berechnet, indem der kumulierte Energieverbrauch durch die Anzahl der Tage dividiert wird.
Ich möchte den Tagesdurchschnitt der letzten Woche und des letzten Monats (der Einfachheit halber 4 Wochen) anzeigen, dh einen gleitenden Durchschnitt. Derzeit umfasst dies die Verwaltung eines Array von Werten für die letzten 28 Tage und die Berechnung eines Durchschnitts über das gesamte Array für monatlich und die letzten 7 Tage für wöchentlich.
Anfangs habe ich dies mit einem Array von Floats gemacht (da die Energie in der Form "12,12 kWh" vorliegt), aber dies war mit 28 * 4 Bytes = 112 Bytes (5,4% des SRAM). Es macht mir nichts aus, nur einen Dezimalpunkt der Auflösung zu haben, also habe ich uint16_t verwendet und die Zahl mit 100 multipliziert. Dies bedeutet, dass 12.12 als 1212 dargestellt wird und ich für Anzeigezwecke durch 100 dividiere.
Die Größe des Arrays beträgt jetzt 56 Bytes (viel besser!).
Es gibt keine triviale Möglichkeit, die Zahl auf ein uint8_t zu reduzieren, das ich sehen kann. Ich könnte den Verlust einer Dezimalstelle ("12,1 kWh" anstelle von "12,12 kWh") tolerieren, aber der Verbrauch ist häufig höher als 25,5 kWh (255 ist der höchste Wert, der durch eine vorzeichenlose 8-Bit-Ganzzahl dargestellt wird). Der Verbrauch war noch nie unter 10,0 kWh oder über 35,0 kWh, daher könnte ich möglicherweise 10 von den gespeicherten Zahlen abziehen, aber ich weiß, dass wir eines Tages diese Grenzwerte überschreiten werden.
Ich habe dann Code getestet, um 9-Bit-Werte in ein Array zu packen. Dies ergibt einen Bereich von 0-51,2 kWh und verwendet insgesamt 32 Bytes. Der Zugriff auf ein solches Array ist jedoch ziemlich langsam, insbesondere wenn Sie alle Werte durchlaufen müssen, um einen Durchschnitt zu berechnen.
Meine Frage lautet also: Gibt es eine effizientere Methode zur Berechnung eines gleitenden Durchschnitts mit drei Fenstern - Lebensdauer, 28 Tage und 7 Tage? Effizienz bedeutet weniger SRAM-Nutzung, jedoch ohne die Strafe für großen Code. Kann ich vermeiden, alle Werte zu speichern?
quelle
Antworten:
Wenn Ihre Daten eine geringe Standardabweichung aufweisen, besteht eine Methode darin, Werte über das Fenster zu summieren und dann den Mittelwert von der Summe zu subtrahieren, während der neue Wert addiert wird.
Dies würde gut funktionieren, wenn es keine Ausreißer gibt , was dazu führen würde, dass der Gesamtfehler im Laufe der Zeit gegen Null tendiert.
quelle
Sie können eine andere Methode verwenden, Sie behalten den aktuellen Durchschnitt bei und tun dies dann
Es ist kein echter gleitender Durchschnitt und hat eine andere Semantik, aber es kann trotzdem Ihren Anforderungen entsprechen
Für eine effizientere Berechnungsmethode für Ihre Lösung mit 9 Bits pro Wert können Sie die 8 höchsten Bits der Werte in einem Array behalten und die niedrigstwertigen Bits trennen:
Um einen Wert festzulegen, müssen Sie ihn aufteilen
was zu 2 Verschiebungen führt, ein UND und ein ODER und ein Nicht
Um den Durchschnitt zu berechnen, können Sie verschiedene Bit-Tricks verwenden, um ihn zu beschleunigen:
Sie können eine effiziente parallele Bitanzahl für die verwenden
bitcount()
quelle
Wie wäre es, nur die Differenz zum vorherigen Wert zu speichern? In der Elektronik gibt es ein ähnliches Konzept namens Delta Sigma-Wandler, das für DA / AD-Wandler verwendet wird. Es beruht auf der Tatsache, dass die vorherige Messung ziemlich nahe an der aktuellen liegt.
quelle
Warum können Sie die Werte nicht einfach addieren, sobald Sie sie erhalten haben? Ich meine also, Sie erhalten den Wert für Tag 1, teilen ihn durch 1 und speichern ihn und die 1 irgendwo. Dann multiplizieren Sie die 1 mit dem Wert und addieren sie zum nächsten Wert und teilen beide durch 2.
Diese Methode würde einen gleitenden Durchschnitt mit zwei oder drei Variablen erzeugen, wie ich mir vorstellen kann. Ich würde Code schreiben, aber ich bin neu im Stackexchange. Bitte nehmen Sie Kontakt mit mir auf.
quelle
Sie könnten nah genug dran sein, um 11 statt 28 Werte zu speichern, vielleicht so etwas wie:
Mit anderen Worten, anstatt jedes Detail eines jeden Tages in den letzten 27 Tagen zu speichern, (a) 7 oder so Werte detaillierter täglicher Informationen für die letzten 7 oder so Tage speichern und (b) 4 oder so "zusammengefasst" speichern. Werte der Gesamt- oder Durchschnittsinformationen für jede der letzten 4 oder so Wochen.
quelle