2010-09-21 8 views
41

Ich schreibe gerade etwas, wo ich im Laufe der Zeit eine Reihe von Werten aus einem Hardware-Kompass nehme. Dieser Kompass ist sehr genau und wird sehr oft aktualisiert, mit dem Ergebnis, dass, wenn er leicht wackelt, ich den seltsamen Wert erhalte, der mit seinen Nachbarn völlig inkonsistent ist. Ich möchte diese Werte glätten.Werte im Zeitverlauf glätten: gleitender Durchschnitt oder etwas Besseres?

Nachdem ich etwas gelesen habe, scheint es, dass ich einen Hochpassfilter, einen Tiefpassfilter oder einen gleitenden Durchschnitt möchte. Moving Average, mit dem ich auskommen kann, behalte einfach einen Verlauf der letzten 5 Werte oder was auch immer, und verwende den Durchschnitt dieser Werte in meinem Code, wo ich einmal den letzten Wert verwendet habe.

Das sollte, denke ich, diese Jiggles schön glätten, aber es fällt mir auf, dass es wahrscheinlich ziemlich ineffizient ist, und dies ist wahrscheinlich eines der bekannten Probleme mit Proper-Programmierern, auf die es eine wirklich clevere Math-Lösung gibt.

Ich bin jedoch einer dieser schrecklichen autodidaktischen Programmierer ohne eine Spur formaler Bildung in irgendetwas auch nur vage mit CompSci oder Math verwandt. Ein wenig herumzulesen legt nahe, dass dies ein Hoch- oder Tiefpassfilter sein könnte, aber ich kann nichts finden, was einem Hack wie mir verständlich erklärt, welche Auswirkungen diese Algorithmen auf eine Reihe von Werten haben würden, geschweige denn wie die Mathematik funktioniert. Die Antwort here beispielsweise beantwortet technisch meine Frage, aber nur in Begriffen, die für diejenigen verständlich sind, die wahrscheinlich bereits wissen, wie man das Problem löst.

Es wäre in der Tat eine sehr liebenswerte und schlaue Person, die die Art von Problem erklären könnte und wie die Lösungen funktionieren, was für einen Kunstabsolventen verständlich ist.

Antwort

34

Wenn gleitender Durchschnitt lang sein muss, um die erforderliche Glättung zu erreichen, und Sie brauchen nicht wirklich eine besondere Form von Kernel, dann bist du besser dran, wenn man eine exponentiell abklingende verwenden gleitenden Durchschnitt:

Hier wählen Sie tiny als geeignete Konstante aus (wenn Sie z. B. tiny = 1- 1/N wählen, wird die Mittelung genauso groß wie bei einem Fenster der Größe N, aber anders verteilt als bei älteren Punkten).

Wie auch immer, da der nächste Wert des gleitenden Durchschnitts nur von dem vorherigen und Ihren Daten abhängt, müssen Sie keine Warteschlange oder irgendetwas behalten. Und Sie können sich folgendes vorstellen: "Nun, ich habe einen neuen Punkt, aber ich traue ihm nicht wirklich, also behalte ich 80% meiner alten Schätzung der Messung und nur vertraue diesem neuen Datenpunkt 20% ". Das ist ungefähr dasselbe wie zu sagen: "Nun, ich vertraue diesem neuen Punkt nur 20%, und ich werde 4 andere Punkte verwenden, denen ich den gleichen Betrag anvertraue", außer dass du die 4 anderen Punkte nicht explizit nimmst Nehmen wir an, dass die Mittelung, die Sie beim letzten Mal gemacht haben, sinnvoll war, damit Sie Ihre vorherige Arbeit nutzen können.

+6

Gute Erklärung, danke Rex. Würde ich recht haben, wenn ich denke, dass eine andere Art dasselbe auszudrücken wäre: workingAverage = (newValue * smoothingFactor) + (workingAverage * (1.0 - smoothingFactor))? –

+4

@Henry - Richtig, das ist der Weg, es ohne zusätzlichen Speicher zu tun. –

+2

Hey, ich weiß, das ist 5 Jahre zu spät, aber danke für eine tolle Antwort. Ich arbeite an einem Spiel, bei dem sich der Sound je nach Anschlag ändert, aber da das Spiel auf einem langsamen Computer läuft, würde die Geschwindigkeit stark schwanken, was für das Lenken gut war, aber in Bezug auf den Sound sehr nervig ist. Dies war eine wirklich einfache und billige Lösung für etwas, von dem ich dachte, dass es ein wirklich komplexes Problem sein würde. – Adam

6

Gleitender Durchschnitt Ich kann mit ... runter, aber es scheint mir, dass es wahrscheinlich ziemlich ineffizient.

Es gibt wirklich keinen Grund, dass ein gleitender Durchschnitt ineffizient sein sollte. Sie behalten die Anzahl der gewünschten Datenpunkte in einem Puffer (wie eine ringförmige Warteschlange). Auf jedem neuen Datenpunkt poppen Sie den ältesten Wert und subtrahieren ihn von einer Summe, schieben Sie das neueste und fügen Sie es zur Summe hinzu. Jeder neue Datenpunkt beinhaltet also nur einen Pop/Push, eine Addition und eine Subtraktion. Ihr gleitender Durchschnitt ist immer diese Verschiebungssumme dividiert durch die Anzahl der Werte in Ihrem Puffer.

Es wird wenig trickier, wenn Sie Daten gleichzeitig von mehreren Threads empfangen, aber da Ihre Daten von einem Hardwaregerät stammen, das sehr zweifelhaft scheint für mich.

Oh und auch: schreckliche autodidaktische Programmierer vereinen sich! ;)

+0

Der gleitende Durchschnitt schien mir ineffizient zu sein, weil Sie einen Puffer mit Werten speichern müssen - besser, nur etwas Cleveres mit Ihrem Eingabewert und dem aktuellen Arbeitswert zu tun? Ich denke, so funktioniert der exponentielle gleitende Durchschnitt. Eine Optimierung, die ich für diese Art von gleitendem Durchschnitt gesehen habe, beinhaltet die Verwendung einer Warteschlange fester Länge und eines Zeigers, wo Sie sich in dieser Warteschlange befinden, und den Zeiger einfach umschließen (mit% oder einem if). Voila! Kein teurer Push/Pop. Macht den Amateuren, Bruder! –

+0

@Henry: Für einen geradlinigen gleitenden Durchschnitt brauchen Sie den Puffer einfach, so dass Sie wissen, welcher Wert beim nächsten Wert ausgelöst wird. Das heißt, die "Warteschlange mit fester Länge & ein Zeiger", die Sie beschreiben, ist genau das, was ich mit "zirkuläre Warteschlange" meinte. Deshalb habe ich gesagt, dass es nicht ineffizient ist. Was hast du gedacht? Und wenn Ihre Antwort "ein Array ist, das seine Werte bei jeder indizierten Entfernung zurücksetzt" (wie 'std :: vector' in C++) ... nun, dann bin ich so verletzt, dass ich nicht mal mit ihm reden möchte Sie mehr;) –

+0

Nein, ich dachte, Sie meinten eine tatsächliche High-Level-array.push()/array.unshift() oder etwas, wie ein AS3 oder Java-Programmierer tun würde. Vergib mir. Kunstabsolvent, erinnerst du dich? –

53

Wenn Sie versuchen, den gelegentlichen ungeraden Wert zu entfernen, ist ein Tiefpassfilter die beste der drei Optionen, die Sie identifiziert haben. Tiefpassfilter ermöglichen Änderungen bei niedrigen Geschwindigkeiten, wie sie zum Beispiel durch das Drehen eines Kompasses von Hand verursacht werden, während Hochgeschwindigkeitsänderungen, wie sie beispielsweise durch Unebenheiten auf der Straße verursacht werden, unterdrückt werden.

Ein gleitender Durchschnitt reicht wahrscheinlich nicht aus, da die Auswirkungen eines einzelnen "Blips" in Ihren Daten abhängig von der Größe Ihres gleitenden Durchschnittsfensters mehrere nachfolgende Werte beeinflussen.

Wenn die ungeraden Werte leicht erkannt werden, können Sie sogar besser dran mit einem Glitch-removal-Algorithmus, der sie völlig ignoriert:

if (abs(thisValue - averageOfLast10Values) > someThreshold) 
{ 
    thisValue = averageOfLast10Values; 
} 

Hier ist ein Guick Diagramm zur Veranschaulichung:

graph comparison

Der erste Graph ist das Eingangssignal mit einem unangenehmen Fehler. Das zweite Diagramm zeigt den Effekt eines gleitenden Durchschnitts mit 10 Abtastungen. Der endgültige Graph ist eine Kombination aus dem Durchschnitt von 10 Abtastungen und dem oben gezeigten einfachen Glitch-Detektionsalgorithmus. Wenn der Störimpuls erkannt wird, wird der Mittelwert von 10 Abtastwerten anstelle des tatsächlichen Werts verwendet.

+0

Schön erklärt, und Bonuspunkte für die Grafik;) –

+0

Wow .. Sah selten so eine nette Antwort! – Muis

+2

Der gleitende Durchschnitt * ist * ein Tiefpassfilter. – nomen

2

Ein exponentiell abklingender gleitender Durchschnitt kann "von Hand" mit nur dem Trend berechnet werden, wenn Sie die richtigen Werte verwenden. Eine Idee, wie man dies schnell mit Stift und Papier macht, finden Sie unter http://www.fourmilab.ch/hackdiet/e4/, wenn Sie nach "exponentiell geglättetem gleitenden Durchschnitt mit 10% Glättung" suchen. Aber da Sie einen Computer haben, möchten Sie wahrscheinlich binäre Verschiebung im Gegensatz zu Dezimalverschiebung tun;)

Auf diese Weise alles, was Sie brauchen, ist eine Variable für Ihren aktuellen Wert und eine für den Durchschnitt. Der nächste Durchschnitt kann dann daraus berechnet werden.

+0

Gute Erklärung von EMA, danke. –

1

Es gibt eine Technik, die als Entfernungstor bezeichnet wird und gut mit Stichproben mit geringer Häufigkeit zusammenarbeitet. Unter der Annahme einer der oben genannten Filtertechniken (gleitender Durchschnitt, exponentiell) können Sie das neue, eingehende Datenmuster auf Angemessenheit prüfen, sobald Sie "genügend" Verlauf (eine Zeitkonstante) haben, vor es wird hinzugefügt Berechnung.

ist eine gewisse Kenntnis der maximalen vernünftigen Änderungsrate des Signals erforderlich. die Rohprobe wird mit dem letzten geglätteten Wert verglichen, und wenn der Absolutwert dieser Differenz größer als der erlaubte Bereich ist, wird diese Probe herausgeworfen (oder durch irgendeine Heuristik ersetzt, z. B. eine Vorhersage basierend auf Steigung; Differenz oder der "Trend" Vorhersagewert aus doppelter exponentieller Glättung)

Verwandte Themen