Inhaltsverzeichnis:

Laufender Durchschnitt für Ihre Mikrocontroller-Projekte - Gunook
Laufender Durchschnitt für Ihre Mikrocontroller-Projekte - Gunook

Video: Laufender Durchschnitt für Ihre Mikrocontroller-Projekte - Gunook

Video: Laufender Durchschnitt für Ihre Mikrocontroller-Projekte - Gunook
Video: Videovögel, digitale Bienen, Raspi und der CalliopeBot – Pi and More 11½ 2024, November
Anonim
Laufender Durchschnitt für Ihre Mikrocontroller-Projekte
Laufender Durchschnitt für Ihre Mikrocontroller-Projekte

In diesem anweisbaren werde ich erklären, was ein laufender Durchschnitt ist und warum Sie sich darum kümmern sollten, sowie Ihnen zeigen, wie er für maximale Recheneffizienz implementiert werden sollte (keine Sorge um die Komplexität, es ist sehr einfach zu verstehen und ich werde Bieten Sie auch eine einfach zu verwendende Bibliothek für Ihre Arduino-Projekte an:)

Der laufende Durchschnitt, auch als gleitender Durchschnitt, gleitender Mittelwert oder laufender Mittelwert bezeichnet, ist ein Begriff, der verwendet wird, um den Durchschnittswert der letzten N Werte in Datenreihen zu beschreiben. Sie kann als normaler Durchschnitt berechnet werden oder Sie können einen Trick anwenden, um die Leistung Ihres Codes minimal zu beeinträchtigen.

Schritt 1: Anwendungsfall: Glätten von ADC-Messungen

Anwendungsfall: Glätten von ADC-Messungen
Anwendungsfall: Glätten von ADC-Messungen

Arduino hat einen anständigen 10-Bit-ADC mit sehr wenig Rauschen. Beim Messen von Werten an einem Sensor wie Potentiometer, Fotowiderstand oder anderen stark rauschenden Komponenten ist es schwer zu glauben, dass die Messung korrekt ist.

Eine Lösung besteht darin, jedes Mal mehrere Messungen durchzuführen, wenn Sie Ihren Sensor auslesen und mitteln möchten. In einigen Fällen ist dies eine praktikable Lösung, aber nicht immer. Wenn Sie ADC 1000 Mal pro Sekunde lesen wollten, müssten Sie 10 000, wenn Sie durchschnittlich 10 Messungen durchführen. Eine enorme Rechenzeitverschwendung.

Meine vorgeschlagene Lösung besteht darin, 1000-mal pro Sekunde Messungen durchzuführen, den laufenden Durchschnitt jedes Mal zu aktualisieren und als aktuellen Wert zu verwenden. Diese Methode führt zu einer gewissen Latenz, verringert jedoch die Rechenkomplexität Ihrer Anwendung, sodass Sie viel mehr Zeit für die zusätzliche Verarbeitung haben.

Im Bild oben habe ich den laufenden Durchschnitt der letzten 32 Messungen verwendet. Sie werden sehen, dass diese Methode nicht 100 % ausfallsicher ist, aber die Genauigkeit erheblich verbessert (sie ist nicht schlechter als der Durchschnitt von 32 Samples jedes Mal). Wenn Sie jedes Mal durchschnittlich 32 Messungen berechnen möchten, würde dies auf Arduino UNO allein für Messungen über 0,25 ms dauern!

Schritt 2: Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals

Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals
Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals
Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals
Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals
Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals
Anwendungsfall: Messung der DC-Komponente des Mikrofonsignals

Arduino kann Spannungen zwischen 0 und Vcc (normalerweise 5 V) messen. Das Audiosignal ist vollständig AC und wenn Sie es auf einem Mikrocontroller messen möchten, müssen Sie es um 1/2 Vcc vorspannen. In einem Arduino UNO-Projekt würde das ungefähr 2,5 V (DC) + Audiosignal (AC) bedeuten. Bei Verwendung eines 10-Bit-ADC und einer 5-V-Stromversorgung sollten 2,5 V Vorspannung der Messung von 512 entsprechen. Um also einen AC-Wert des Signals zu erhalten, sollte 512 von der ADC-Messung abgezogen werden, und das ist es, oder?

In einer idealen Welt wäre das wahr. Leider ist das wirkliche Leben komplizierter und unser Signal-Bias neigt dazu, zu driften. Sehr häufig sind 50-Hz-Rauschen (60 Hz, wenn Sie in den USA leben) aus dem Stromnetz. Normalerweise ist es nicht allzu problematisch, aber es ist gut zu wissen, dass es existiert. Problematischer ist die lineare Drift durch Erwärmung von Bauteilen. Sie stellen die DC-Offset-Korrektur beim Start sorgfältig ein und sie driftet langsam ab, während Ihre Anwendung ausgeführt wird.

Ich werde dieses Problem mit einem (Musik-)Beat-Detektor veranschaulichen. Sie richten Ihre Bias-Entfernung ein und die Beats sind klar (Bild 2). Nach einiger Zeit sind DC-Bias-Bewegungen und -Beats für den Mikrocontroller kaum wahrnehmbar (Bild 3). Der Beat-Erkennungsalgorithmus wird in einem zukünftigen anweisbaren eingehend untersucht, da er den Rahmen dieses Artikels überschreitet.

Glücklicherweise gibt es eine Möglichkeit, den DC-Offset von Audio ständig zu berechnen. Es wird nicht überraschen, dass der laufende Durchschnitt, das Thema dieses instructable, eine Lösung bietet.

Wir wissen, dass der Durchschnittswert jedes AC-Signals 0 ist. Mit diesem Wissen können wir ableiten, dass der Durchschnittswert des AC+DC-Signals der DC-Bias ist. Um es zu entfernen, können wir einen laufenden Durchschnitt der letzten paar Werte nehmen und ihn vom aktuellen ADC-Messwert subtrahieren. Beachten Sie, dass Sie einen ausreichend langen laufenden Durchschnitt verwenden müssen. Für Audio sollte eine Zehntelsekunde (Anzahl der Samples hängt von Ihrer Samplerate) ausreichen, aber wissen Sie, dass längere Durchschnitte besser funktionieren. Im ersten Bild sehen Sie ein Beispiel für eine echte DC-Bias-Berechnung mit einem laufenden Durchschnitt mit 64 Elementen bei einer Abtastrate von 1 kHz (weniger als ich empfohlen habe, aber es funktioniert immer noch).

Schritt 3: Berechnung

Berechnung
Berechnung

Sie können sich vorstellen, dass das Durchschnittsgewicht der Personen im Wartezimmer des Arztes durchschnittlich ist. Der Arzt beendet die Untersuchung eines Patienten und gleichzeitig kommt ein neuer ins Wartezimmer.

Um das Durchschnittsgewicht aller wartenden Patienten im Wartezimmer herauszufinden, könnte die Pflegekraft jeden Patienten nach seinem Gewicht fragen, diese Zahlen addieren und durch die Anzahl der Patienten dividieren. Jedes Mal, wenn der Arzt einen neuen Patienten annimmt, wiederholt die Krankenschwester den gesamten Vorgang.

Sie denken vielleicht: "Das klingt nicht allzu effizient… Es muss einen besseren Weg geben." Und du hättest recht.

Um diesen Prozess zu optimieren, könnte die Pflegekraft das Gesamtgewicht der aktuellen Patientengruppe aufzeichnen. Sobald der Arzt einen neuen Patienten anrief, fragte ihn die Krankenschwester nach seinem Gewicht, zog es von der Gruppensumme ab und ließ ihn gehen. Die Krankenschwester fragte dann den Patienten, der gerade das Wartezimmer betrat, nach seinem Gewicht und addierte es zur Gesamtsumme. Das durchschnittliche Gewicht der Patienten nach jeder Schicht wäre die Summe der Gewichte dividiert durch die Anzahl der Patienten (ja, wie zuvor, aber jetzt fragte die Krankenschwester nur zwei Personen nach ihrem Gewicht statt aller). Mir ist klar, dass dieser Absatz vielleicht etwas verwirrend war, also sehen Sie sich die Abbildung oben für zusätzliche Klarheit an (oder stellen Sie Fragen in Kommentaren).

Aber selbst wenn Sie den letzten Absatz nicht verwirrend fanden, könnten Sie Fragen haben, wie zum Beispiel, was am Anfang im Akkumulator stehen sollte, wie füge ich das, was ich gerade gelesen habe, in einen tatsächlichen C-Code ein? Darauf wird im nächsten Schritt eingegangen, wo Sie auch meinen Quellcode erhalten.

Schritt 4: Der Code

Der Code
Der Code

Um den laufenden Durchschnitt zu berechnen, müssen Sie zunächst die letzten N Werte speichern. Sie könnten ein Array mit N Elementen haben und den gesamten Inhalt jedes Mal, wenn Sie ein Element hinzufügen, um eine Stelle verschieben (bitte tun Sie dies nicht), oder Sie könnten ein altes Element überschreiben und den Zeiger auf das nächste zu entfernende Element anpassen (bitte tun Sie dies:)

Akkumulator sollte initialisiert auf 0 starten, gleiches gilt für alle Elemente in der Verzögerungsleitung. In anderen Fällen wird Ihr laufender Durchschnitt immer falsch sein. Sie werden sehen, dass delayLine_init sich um die Initialisierung der Delay-Line kümmert, um Akkumulator sollten Sie sich selbst kümmern.

Das Hinzufügen eines Elements zur Verzögerungsleitung ist so einfach wie das Verringern des Index des neuesten Elements um 1 und stellen Sie sicher, dass es nicht auf die Seite des Verzögerungsleitungs-Arrays zeigt. nach dem Dekrementieren des Indexes, wenn er 0 ist, wird er auf 255 herumgeschleift (da es sich um eine 8-Bit-Ganzzahl ohne Vorzeichen handelt). Der Modulo-Operator (%) mit der Größe des Delay-Line-Arrays stellt sicher, dass der Index auf ein gültiges Element zeigt.

Die Berechnung eines laufenden Durchschnitts sollte leicht zu verstehen sein, wenn Sie meiner Analogie im vorherigen Schritt gefolgt sind. Subtrahiere das älteste Element vom Akkumulator, füge den neuesten Wert zum Akkumulator hinzu, schiebe den neuesten Wert auf die Verzögerungsleitung, gebe den Akkumulator geteilt durch die Anzahl der Elemente zurück.

Einfach richtig?

Bitte experimentieren Sie mit dem beigefügten Code, um besser zu verstehen, wie dies alles funktioniert. Wie es derzeit aussieht, liest Arduino den Analogwert am analogen Pin A0 und druckt "[ADC-Wert], [laufender Durchschnitt]" am seriellen Port mit einer Baudrate von 115200. Wenn Sie den seriellen Plotter von Arduino mit der richtigen Baudrate öffnen, sehen Sie zwei Zeilen: ADC-Wert (blau) und geglätteter Wert (rot).

Schritt 5: Extras

Extras
Extras

Es gibt ein paar Dinge, die Sie nicht unbedingt wissen müssen, um den laufenden Durchschnitt in Ihrem Projekt zu verwenden, aber es kann nicht schaden, es zu wissen.

Verzögerung: Ich werde damit beginnen, über die Veranschaulichung dieses Schrittes zu sprechen. Sie werden feststellen, dass der laufende Durchschnitt von mehr Elementen zu einer größeren Verzögerung führt. Wenn Ihre Reaktionszeit auf eine Wertänderung kritisch ist, können Sie einen kürzeren laufenden Durchschnitt verwenden oder die Abtastrate erhöhen (häufiger messen).

Weiter geht's.

Initialisieren: Als ich über das Initialisieren von Akkumulator- und Verzögerungselementen sprach, sagte ich, Sie sollten sie alle auf 0 initialisieren ist die Anzahl der Elemente in Ihrem laufenden Durchschnitt). Wenn Akkumulator wie ein anderer Wert beginnt, ist der berechnete Durchschnitt falsch - entweder zu niedrig oder zu hoch, immer um den gleichen Betrag (unter der Annahme gleicher Anfangsbedingungen). Ich schlage vor, dass Sie versuchen, herauszufinden, warum dies so ist, indem Sie eine "Stift-und-Papier-Simulation" verwenden.

Akkumulatorgröße: Sie sollten auch beachten, dass der Akkumulator groß genug sein sollte, um die Summe aller Elemente in der Verzögerungsleitung zu speichern, wenn sie alle positiv oder negativ sind. Praktisch bedeutet dies, dass der Akkumulator einen Datentyp größer als die Verzögerungsleitungselemente und vorzeichenbehaftet sein sollte, wenn die Verzögerungsleitungselemente vorzeichenbehaftet sind.

Trick: Lange Delay-Lines beanspruchen viel Speicher. Das kann schnell zum Problem werden. Wenn Sie sehr eingeschränkt sind und sich nicht um Genauigkeit kümmern, können Sie den laufenden Durchschnitt annähern, indem Sie die Verzögerung vollständig weglassen und stattdessen Folgendes tun: 1/N * Akkumulator vom Akkumulator subtrahieren und neuen Wert hinzufügen (am Beispiel von 8 lang laufenden Durchschnitten: Akkumulator = Akkumulator * 7 / 8 + neuerWert). Diese Methode liefert ein falsches Ergebnis, ist aber eine anständige Methode zur Berechnung des laufenden Durchschnitts, wenn der Speicher knapp wird.

Linguistik: "laufender Durchschnitt/Mittelwert" wird normalerweise verwendet, wenn es um die Echtzeit-Mittelung geht, während "gleitender Durchschnitt/Mittelwert" normalerweise bedeutet, dass der Algorithmus auf einem statischen Datensatz wie einer Excel-Tabelle ausgeführt wird.

Schritt 6: Fazit

Ich hoffe, dass dieses instructable leicht genug zu verstehen war und dass es Ihnen bei Ihren zukünftigen Projekten helfen wird. Bitte zögern Sie nicht, Fragen in den Kommentaren unten zu posten, wenn etwas unklar ist.

Empfohlen: