Thursday 2 March 2017

Moving Average Circular Puffer

Ich weiß, das ist erreichbar mit Boost wie pro. But ich wirklich gerne vermeiden, Boost Ich habe gegoogelt und nicht gefunden, keine geeigneten oder lesbaren Beispiele. Basisch möchte ich den gleitenden Durchschnitt eines laufenden Streams von einem Strom von Gleitkommazahlen zu verfolgen Mit den neuesten 1000 Nummern als Datenbeispiel. Was ist der einfachste Weg, dies zu erreichen. Ich experimentierte mit der Verwendung eines kreisförmigen Arrays, exponentiell gleitenden Durchschnitt und ein einfacher gleitender Durchschnitt und festgestellt, dass die Ergebnisse aus dem kreisförmigen Array passte meine Bedürfnisse am besten Wenn Sie Ihre Bedürfnisse einfach sind, können Sie nur versuchen, einen exponentiellen gleitenden Durchschnitt zu verwenden. Einfach nur, Sie machen eine Akkumulatorvariable, und wie Ihr Code bei jedem Sample sieht, aktualisiert der Code den Akkumulator mit dem Neuer Wert Du wählst eine konstante Alpha, die zwischen 0 und 1 ist, und berechnen dies. Sie müssen nur einen Wert von Alpha finden, wo die Wirkung einer bestimmten Probe nur für etwa 1000 Proben dauert. Hmm, ich bin nicht wirklich sicher, dass dies ist Passend für dich, jetzt da ich es hier hingelegt Das Problem ist, dass 1000 ein ziemlich langes Fenster für einen exponentiellen gleitenden Durchschnitt ist Ich bin mir nicht sicher, dass es ein Alpha gibt, das den Durchschnitt über die letzten 1000 Zahlen verbreiten würde, ohne Unterströmung im Floating Punkt-Berechnung Aber wenn Sie einen kleineren Durchschnitt wünschen, wie 30 Zahlen oder so, ist dies eine sehr einfache und schnelle Art und Weise zu tun it. answered Jun 12 12 bei 4 44. 1 auf Ihrem Beitrag Der exponentielle gleitende Durchschnitt kann das Alpha zu sein Variable So ermöglicht dies die Berechnung von Zeitbasis-Mittelwerten zB Bytes pro Sekunde Wenn die Zeit seit dem letzten Akkumulator-Update mehr als 1 Sekunde ist, lassen Sie alpha 1 1 sein. Andernfalls können Sie alpha be usecs seit letztem Update 1000000 jxh Jun 12 12 at 6 21.Basically Ich möchte den gleitenden Durchschnitt eines laufenden Streams von einem Strom von Gleitkommazahlen mit den neuesten 1000 Zahlen als Datenbeispiel verfolgen. Hinweis, dass die unten die Gesamtsumme als Elemente als hinzugefügt ersetzt ersetzt, vermeiden Kostspielig, um die Summe zu berechnen, die für den Durchschnitt benötigt wird - auf Nachfrage. Total ist ein anderer Parameter von T zu unterstützen, zB mit einer langen langen, wenn insgesamt 1000 lang s, ein int für char s oder ein doppeltes zu total float s. Dies ist ein bisschen fehlerhaft, dass Numsamples an INTMAX vorbeikommen könnten - wenn Sie sich vorstellen können, dass Sie eine lange Zeit langer Zeit verwenden können oder ein zusätzliches bool Datenelement verwenden, um aufzuzeichnen, wann der Container zum ersten Mal gefüllt wird, während er Numsamples um das Array herumtreibt und dann etwas Unschuldiges umbenannt hat Wie pos. answered 12. Juni 12 bei 5 19.on geht davon aus, dass void Operator T Probe tatsächlich void Operator T Probe oPless Jun 8 14 bei 11 52. oPless ahhh gut gesichtet tatsächlich ich bedeutete, dass es void Betreiber T Probe aber natürlich Du könntest was Notation, die du mochst, beheben, danke Tony D Jun 8 14 bei 14 27. Der Wissenschaftler und Ingenieur s Guide to Digitale Signalverarbeitung Von Steven W Smith, Ph D. Kapitel 28 Digitale Signalprozessoren. Digital Signal Prozessoren sind entworfen, um Schnell FIR-Filter und ähnliche Techniken durchführen Um die Hardware zu verstehen, müssen wir zuerst die Algorithmen verstehen. In diesem Abschnitt werden wir eine detaillierte Liste der notwendigen Schritte zur Implementierung eines FIR-Filters erstellen. Im nächsten Abschnitt werden wir sehen, wie DSPs diese ausführen sollen Schritte so effizient wie möglich. Um zu starten, müssen wir zwischen Offline-Verarbeitung und Echtzeit-Verarbeitung unterscheiden. In der Offline-Verarbeitung befindet sich das gesamte Eingangssignal gleichzeitig im Computer. Zum Beispiel könnte ein Geophysiker ein Seismometer verwenden Um die Bodenbewegung während eines Erdbebens aufzuzeichnen Nachdem das Schütteln vorbei ist, können die Informationen in einen Computer eingelesen und in irgendeiner Weise analysiert werden. Ein anderes Beispiel für die Offline-Verarbeitung ist die medizinische Bildgebung, wie z. B. Computertomographie und MRT. Der Datensatz wird erworben Der Patient ist in der Maschine, aber die Bildrekonstruktion kann bis zu einem späteren Zeitpunkt verzögert werden Der Schlüsselpunkt ist, dass alle Informationen gleichzeitig dem Verarbeitungsprogramm zur Verfügung stehen. Dies ist in der wissenschaftlichen Forschung und in der Technik üblich, aber nicht in den Konsumgütern Off - Line-Verarbeitung ist das Reich von Personal Computern und Mainframes. In Echtzeit-Verarbeitung wird das Ausgangssignal zur gleichen Zeit produziert, dass das Eingangssignal erfaßt wird. Zum Beispiel ist dies in der Telefonkommunikation, Hörgeräte und Radar Diese Anwendungen erforderlich Muss die Informationen sofort zur Verfügung stellen, obwohl es um einen kurzen Betrag verzögert werden kann. Zum Beispiel kann eine 10-Millisekunden-Verzögerung in einem Telefonanruf nicht vom Sprecher oder Hörer erkannt werden. Ebenso macht es keinen Unterschied, ob ein Radarsignal um ein paar verzögert wird Sekunden, bevor sie dem Bediener angezeigt werden Realzeitanwendungen geben einen Sample ein, führen den Algorithmus aus und geben ein Sample aus, über-und-over Alternativ können sie eine Gruppe von Samples eingeben, den Algorithmus ausführen und eine Gruppe von Samples ausgeben Dies ist die Welt der digitalen Signalprozessoren. Nun blicken zurück auf Abb. 28-2 und stellen Sie sich vor, dass dies ein FIR-Filter in Echtzeit implementiert ist Um die Ausgabe Probe zu berechnen, müssen wir Zugriff auf eine bestimmte Anzahl der neuesten Samples haben Aus der Eingabe Angenommen, wir verwenden acht Koeffizienten in diesem Filter, a 0 a 1 a 7 Dies bedeutet, dass wir den Wert der acht letzten Samples aus dem Eingangssignal xn, xn -1, xn -7 kennen müssen. Diese acht Samples müssen im Speicher abgelegt und laufend aktualisiert werden, wenn neue Samples gewonnen werden. Was ist der beste Weg, um diese gespeicherten Samples zu verwalten Die Antwort ist die zirkuläre Pufferung. Abbildung 28-3 veranschaulicht einen acht Sample Circular Puffer Wir haben diesen Circular Puffer in acht aufeinanderfolgenden Speicher platziert Standorte, 20041 bis 20048 Abbildung a zeigt, wie die acht Samples aus der Eingabe zu einem bestimmten Zeitpunkt in der Zeit gespeichert werden können, während b die Änderungen nach dem nächsten Sample zeigt. Die Idee der zirkularen Pufferung ist, dass das Ende dieses linearen Arrays ist Verbunden mit seinem Anfang Speicherplatz 20041 wird als neben 20048 betrachtet, genauso wie 20044 ist neben 20045 Sie verfolgen den Array durch einen Zeiger eine Variable, deren Wert eine Adresse ist, die angibt, wo das aktuellste Beispiel wohnt Ein Zeiger enthält die Adresse 20044, während in b es enthält. 20045 Wenn ein neues Sample erworben wird, ersetzt es das älteste Sample im Array und der Zeiger wird eine Adresse vorwärts verschoben. Rundpuffer sind effizient, da nur ein Wert geändert werden muss Wenn ein neuer Sample erfaßt wird. Freue Parameter werden benötigt, um einen Zirkularpuffer zu verwalten. Zuerst muss es einen Zeiger geben, der den Anfang des Zirkularpuffers im Speicher in diesem Beispiel anzeigt. 20041 Zweitens muss ein Zeiger sein, der das Ende des Array zB 20048 oder eine Variable, die ihre Länge z. B. 8 Drittens hat, muss die Schrittweite der Speicheradressierung angegeben werden In Abb. 28-3 ist die Schrittweite eine zum Beispiel Adresse 20043 enthält eine Stichprobe, Adresse 20044 enthält das nächste Sample, Und so weiter Dies ist häufig nicht der Fall Zum Beispiel kann die Adressierung auf Bytes verweisen, und jede Sample kann zwei oder vier Bytes benötigen, um ihren Wert zu halten. In diesen Fällen müsste die Schrittgröße zwei oder vier sein Drei Werte definieren die Größe und die Konfiguration des kreisförmigen Puffers und werden sich während der Programmoperation nicht ändern. Der vierte Wert, der Zeiger auf das aktuellste Sample, muss geändert werden, da jedes neue Sample erfasst wird. Mit anderen Worten, es muss Programmlogik vorhanden sein Das steuert, wie dieser vierte Wert basierend auf dem Wert der ersten drei Werte aktualisiert wird Während diese Logik ganz einfach ist, muss es sehr schnell sein. Dies ist der ganze Punkt dieser Diskussion DSPs sollten bei der Verwaltung von Kreispuffern optimiert werden, um das Höchstmögliche zu erreichen Durchführungsgeschwindigkeit. Eine beiseite, zirkuläre Pufferung ist auch bei der Offline-Verarbeitung nützlich. Betrachten Sie ein Programm, bei dem sowohl die Eingangs - als auch die Ausgangssignale vollständig im Speicher enthalten sind. Für eine Faltungsberechnung ist eine zirkuläre Pufferung erforderlich, da jede Probe sofort aufgerufen werden kann Allerdings werden viele Algorithmen in Stufen implementiert, wobei ein Zwischensignal zwischen jeder Stufe erzeugt wird. Beispielsweise dient ein rekursives Filter, das als eine Reihe von Biquads ausgeführt wird, auf diese Weise. Das Brute-Force-Verfahren besteht darin, die gesamte Länge jedes Zwischensignals im Speicher zu speichern Circular Pufferung bietet eine weitere Option speichern nur die Zwischenproben für die Berechnung zur Hand benötigt Dies reduziert die erforderliche Menge an Speicher, auf Kosten eines komplizierteren Algorithmus Die wichtigste Idee ist, dass zirkuläre Puffer sind nützlich für Offline-Verarbeitung, aber kritisch für Echtzeit-Applikationen. Jetzt können wir die notwendigen Schritte zur Implementierung eines FIR-Filters mit kreisförmigen Puffern für das Eingangssignal und die Koeffizienten anschauen. Diese Liste mag trivial und überheblich sein - es geht nicht Die effiziente Handhabung dieser einzelnen Aufgaben ist das, was sich trennt Ein DSP von einem traditionellen Mikroprozessor Für jede neue Probe müssen alle folgenden Schritte durchgeführt werden. Das Ziel ist es, diese Schritte schnell auszuführen Da die Schritte 6-12 viele Male einmal für jeden Koeffizienten im Filter wiederholt werden, muss besondere Aufmerksamkeit sein Diesen Operationen gegeben werden. Traditionelle Mikroprozessoren müssen diese 14 Stufen in der Regel nacheinander durchführen, während DSPs dazu ausgelegt sind, sie parallel auszuführen. In einigen Fällen können alle Operationen innerhalb der Schleifenstufen 6-12 in einem einzigen abgeschlossen werden Taktzyklus Lassen Sie sich die interne Architektur anschauen, die diese großartige Leistung ermöglicht. Einer der Hauptanwendungen für die Arduino-Platine liest und protokolliert die Sensordaten. Zum Beispiel überwacht man den Druck jede Sekunde des Tages, da hohe Abtastraten oft Spikes erzeugen Graphen man will auch einen Durchschnitt der Messungen haben Da die Messungen nicht statisch in der Zeit sind, was wir oft brauchen, ist ein laufender Durchschnitt Dies ist der Durchschnitt einer bestimmten Periode und sehr wertvoll bei der Trendanalyse. Simplest Form eines laufenden Durchschnitts kann Durch Code, der auf dem vorherigen laufenden Durchschnitt aufbaut. Wenn man nicht wollen, um Floating-Point-Mathematik zu verwenden - da dies Speicher aufnimmt und die Geschwindigkeit verringert - kann man das gleiche vollständig in der Integer-Domain tun Die Division von 256 im Beispielcode Ist eine Verschiebungsrechts-8, die schneller ist als die Teilung durch z. B. 100 Das gilt für jede Kraft von 2 als Teiler und man muss nur darauf achten, dass die Summe der Glieder gleich der Kraft von 2 ist. Und natürlich sollte man dort darauf achten Ist kein Zwischenüberlauf in der Verwendung von unsigned long. If benötigen Sie einen genaueren laufenden Durchschnitt, in concreto aus den letzten 10 Messungen, benötigen Sie ein Array oder verknüpfte Liste, um sie zu halten Dieses Array fungiert als kreisförmiger Puffer und mit jeder neuen Messung die älteste Einer wird entfernt Der laufende Durchschnitt wird berechnet als die Summe aller Elemente geteilt durch die Anzahl der Elemente im Array Der Code für den laufenden Durchschnitt wird so etwas wie dies sein. Drawback dieses Codes ist, dass das Array, um alle Werte zu halten, ganz werden kann Groß Wenn Sie eine Messung pro Sekunde haben und Sie wollen einen laufenden Durchschnitt pro Minute benötigen Sie ein Array von 60 ein Durchschnitt pro Stunde würde ein Array von 3600 Das könnte nicht auf diese Weise auf einem Arduino getan werden, da es nur 2K RAM hat Durch den Aufbau eines 2-stufigen Durchschnitts kann es ganz gut Haftungsausschluss nicht für alle Messungen In psuedo code. As ein neues internes statisches Array wird für jede runningAverage-Funktion benötigt, diese schreit als eine class. RunningAverage-Bibliothek implementiert werden. Die runningAverage-Bibliothek macht Eine Klasse der Funktion oben, so kann es mehrfach in einer Skizze verwendet werden Es entkoppelt die add und die avg-Funktion ein bisschen flexibler sein, zB kann man den Durchschnitt mehrfach anrufen, ohne eine Sache hinzuzufügen Bitte beachten Sie, dass jede Instanz der Klasse Fügt ein eigenes Array hinzu, um Messungen zu halten, und das fügt dem Speicherverbrauch hinzu Die Schnittstelle der Klasse wird so klein wie möglich gehalten. Hinweis mit Version 0 2 Die Namen der Methoden werden alle beschreibender gemacht. Eine kleine Skizze zeigt, wie Es kann verwendet werden Ein zufälliger Generator wird verwendet, um einen Sensor zu imitieren. In Setup ist die myRA gelöscht, so dass wir mit dem Hinzufügen neuer Daten beginnen können. In der Schleife wird zuerst eine zufällige Zahl generiert und in einen Float umgewandelt, um zu myRA hinzugefügt zu werden. Dann ist das runningAverage Gedruckt auf die serielle Schnittstelle Man könnte es auch auf einem LCD anzeigen oder über Ethernet versenden usw. Wenn 300 Artikel hinzugefügt werden, ist myRA gelöscht, um wieder von vorne zu beginnen. Um die Bibliothek zu benutzen, mach einen Ordner in deiner SKETCHBOOKPATH libaries mit dem Namen RunningAverage und stelle den H und dort Optional ein Beispiel-Unterverzeichnis, um die Probe zu platzieren app.2011-01-30 initial version.2011-02-28 fester fehlender destruktor in h file.2011-02-28 entfernt standard constructor.2012- - trimValue Yuval Naveh hinzugefügt TrimValue gefunden auf web.2012-11-21 refactored.2012-12-30 hinzugefügt fillValue refactored für publishing.2014-07-03 hinzugefügt Memory-Schutz-Code - wenn interne Array nicht zugeordnet werden kann Größe wird 0 Dies ist zu lösen Problem hier beschrieben. Testen Sie ausführlich. Template class. RunningAverage h. RunningAverage.


No comments:

Post a Comment