Friday 12 May 2017

Fast Moving Average C ++


In meinem Trading-Antrag habe ich Live-Ticks der Aktienkurse. Ich muss SMA pflegen. Nehmen wir an, ich möchte SMA von 20 Kerzen, wo die Dauer jeder Kerze 10 Sekunden beträgt. Dies bedeutet, dass alle 10 Sekunden habe ich Checkpoint wo: Ich schließe aktuelle Kerze und speichern durchschnittlichen Preis für die letzten 10 Sekunden. Durchschnitt ist (max - min) 2 Ich beginne neue Kerze und lasse den letzten Preis. Ich habe eine veraltete Kerze aufgeräumt. Ich aktualisiere den letzten Preis der aktuellen Kerze und rezitiere SMA. Also auf jeden Tick muss ich SMA neu berechnen. In den meisten Fällen wird nur der Preis der letzten Kerze geändert (weil wir den letzten Preis verwenden). Einmal pro 10 Sekunden brauche ich ein bisschen mehr Arbeit - ich muss den Durchschnitt der veralteten Kerze vergessen und den Durchschnitt der gerade erstellten Kerze speichern. Können Sie vorschlagen, wie dies mit der geringsten Latenz umzusetzen Niedrige Latenz ist primäre Voraussetzung. Fragte am 28.04 bei 10:21 Ich bin mir nicht sicher, ob das der Ansatz ist, den du suchst, aber hier ist der Pseudocode für sehr schnelle SMAs. Simple Moving Average: Ich gehe davon aus, dass Ihre Daten in Form eines Streams kommen und in einer kontinuierlichen Speicherposition gespeichert werden (zumindest mit kontinuierlich zugreifbaren Adressen). Mit zwei Hinzufügungen und einer Multiplikation (mit 12000) können Sie nachfolgende gleitende Mittelwerte generieren Die neuen Zecken. Exponentieller gleitender Durchschnitt: Das ist eine anständige Alternative, wie oben erwähnt: Hier ist es nicht wirklich ein N-Tag gleitender Durchschnitt. Sein nur ein gewichteter gleitender Durchschnitt mit 87 Gewicht zu den letzten N-Tagen, also fast N-Tage ist mehr wie es. Hinweis auf Compiler-Optimierungen: Beachten Sie, dass das Einschalten von SSE - oder AVX-Optionen, falls verfügbar, eine massive Beschleunigung dieser Algorithmen ermöglicht, da mehrere Berechnungen in einem einzigen CPU-Zyklus ausgegeben werden können. Der Algorithmus ist unwahrscheinlich, einen Fehler zu erzeugen, es sei denn, die verwendeten Speicherbereiche werden auch durch einen anderen Thread verändert. In Bezug auf die Voll-Neuberechnung. Ein Weg, um Ihren Code zu beschleunigen ist, diesen Prozess zu einem alternativen Thread zu übertragen, damit es nicht die Ausführung Ihrer Haupt-MA-Berechnung blockiert. Da das eine unabhängige Operation ist, wäre es sehr einfach, diesen Code zu parametrieren ndash hnk Jul 14 14 um 12:30 So brauchst du eine Warteschlange, von ziemlich viel fester Größe, wo du effizient neue Artikel hinzufügen und das älteste Item entfernen kannst ( Um es von deiner laufenden Summe zu entfernen). Warum nicht std :: Warteschlange Dies kann sitzen auf der Oberseite der verschiedenen Container, aber wenn Sie wirklich nur 20 Elemente Ich vermute, ein Vektor würde gut funktionieren. (Das Entfernen eines Elements erfordert das Verschieben aller anderen Elemente nach unten - aber das Bewegen von zusammenhängenden Blöcken des Gedächtnisses ist schnell.) Vielleicht möchten Sie die Leistung gegen einen Deque oder eine Liste vergleichen. (Die Antwort kann davon abhängen, was Sie für jede Kerze speichern - nur eine einzige floatdoubleint oder eine komplexere Struktur) Ich weiß, das ist erreichbar mit Boost wie pro: Aber ich möchte wirklich vermeiden, Boost. Ich habe gegoogelt und fand keine geeigneten oder lesbaren Beispiele. Grundsätzlich möchte ich den gleitenden Durchschnitt eines laufenden Stroms eines Stroms von Gleitkommazahlen mit den aktuellsten 1000 Zahlen als Datenmuster verfolgen. Was ist der einfachste Weg, um dies zu erreichen, experimentierte ich mit einem kreisförmigen Array, einem exponentiellen gleitenden Durchschnitt und einem einfacheren gleitenden Durchschnitt und fand, dass die Ergebnisse aus dem kreisförmigen Array meinen Bedürfnissen am besten entsprechen. Gefragt am 12. Juni 12 um 4:38 Wenn Ihre Bedürfnisse einfach sind, können Sie nur versuchen, einen exponentiellen gleitenden Durchschnitt. Setzen Sie einfach, Sie machen eine Akkumulator-Variable, und wie Ihr Code bei jedem Sample sieht, aktualisiert der Code den Akkumulator mit dem neuen Wert. Sie wählen eine konstante Alpha, die zwischen 0 und 1 ist, und berechnen Sie diese: Sie müssen nur einen Wert von Alpha zu finden, wo die Wirkung einer bestimmten Probe nur für etwa 1000 Proben dauert. Hmm, Im nicht wirklich sicher, dass dies für Sie geeignet ist, jetzt, dass Ive es hier. Das Problem ist, dass 1000 ist ein ziemlich langes Fenster für einen exponentiellen gleitenden Durchschnitt Im nicht sicher, es gibt ein Alpha, die den Durchschnitt über die letzten 1000 Zahlen, ohne Unterlauf in der Gleitkomma Berechnung zu verbreiten würde. Aber wenn du einen kleineren Durchschnitt wünschst, wie 30 Zahlen oder so, das ist eine sehr einfache und schnelle Möglichkeit, es zu tun. Antwortete Jun 12 12 um 4:44 1 auf deinem Post. Der exponentielle gleitende Durchschnitt kann das Alpha variabel sein. So kann es verwendet werden, um Zeitbasis-Mittelwerte (z. B. Bytes pro Sekunde) zu berechnen. Wenn die Zeit seit dem letzten Akkumulator-Update mehr als 1 Sekunde ist, lassen Sie Alpha 1,0 sein. Andernfalls kannst du alpha sein (usecs seit letztem update1000000). Ndash jxh Grundsätzlich möchte ich den gleitenden Durchschnitt eines laufenden Stroms eines Stroms von Gleitkommazahlen mit den aktuellsten 1000 Zahlen als Datenmuster verfolgen. Beachten Sie, dass die unten genannte Gesamtsumme als Elemente als addreplaced, Vermeidung kostspieliger O (N) Traversal, um die Summe zu berechnen - benötigt für die durchschnittliche - on demand. Insgesamt wird ein anderer Parameter von T verwendet, um z. B. Mit einer langen langen, wenn insgesamt 1000 lang s, ein int für char s, oder ein doppeltes bis total float s. Dies ist ein bisschen fehlerhaft, dass Numsamples an INTMAX vorbeikommen könnten - wenn man sich vorstellt, dass man eine langjährige langjährige langwierige Zeit haben könnte. Oder verwenden Sie ein zusätzliches bool Datenelement, um aufzuzeichnen, wenn der Container zum ersten Mal gefüllt wird, während er Numsamples um das Array herumtreibt (am besten dann umbenannt etwas Unschuldiges wie Pos). Antwortete am 12. Juni 12 um 5:19 man geht davon aus, dass der Quanten-Operator (T-Stichprobe) tatsächlich quasi Operator (T-Probe) ist. Ndash oPless Jun 8 14 um 11:52 oPless ahhh. Gut beobachtet. Eigentlich habe ich gedacht, dass es nicht leer ist () (T Probe), aber natürlich könntest du auch immer Notizen verwenden, die du mochst. Werde reden, danke Wenn du andere erwähnt hast, solltest du einen Filter von IIR (unendliche Impulsantwort) als den FIR (Finite Impulse Response) Filter, den du jetzt benutzt hast, betrachten. Deutsch:. Englisch: v3.espacenet. com/textdoc? DB = EPODOC & ... PN = Es gibt mehr dazu, aber auf den ersten Blick sind FIR-Filter als explizite Windungen und IIR-Filter mit Gleichungen implementiert. Der spezielle IIR-Filter, den ich viel in den Mikrocontrollern verwende, ist ein einpoliger Tiefpassfilter. Dies ist das digitale Äquivalent eines einfachen R-C-Analogfilters. Für die meisten Anwendungen, diese haben bessere Eigenschaften als die Box-Filter, die Sie verwenden. Die meisten Verwendungen eines Kastenfilters, dem ich begegnet haben, sind ein Ergebnis von jemand, der nicht in der digitalen Signalverarbeitung Klasse auffällt, nicht als Ergebnis der Notwendigkeit ihrer besonderen Eigenschaften. Wenn du nur hohe Frequenzen abschwächen willst, die du kennst, ist Rauschen, ein einpoliger Tiefpassfilter ist besser. Der beste Weg, um ein digital in einem Mikrocontroller zu implementieren, ist in der Regel: FILT lt-- FILT FF (NEU - FILT) FILT ist ein Stück persistenten Zustand. Dies ist die einzige persistente Variable, die Sie benötigen, um diesen Filter zu berechnen. NEU ist der neue Wert, den der Filter mit dieser Iteration aktualisiert. FF ist die Filterfraktion. Die die Schwere des Filters anpasst. Schauen Sie sich diesen Algorithmus an und sehen Sie, dass für FF 0 der Filter unendlich schwer ist, da sich die Ausgabe niemals ändert. Für FF 1 ist das eigentlich kein Filter, da der Ausgang gerade dem Eingang folgt. Nützliche Werte sind dazwischen. Bei kleinen Systemen wählst du FF auf 12 N, so dass die Multiplikation mit FF als rechte Verschiebung durch N Bits erreicht werden kann. Zum Beispiel könnte FF 116 sein und die Multiplikation mit FF daher eine rechte Verschiebung von 4 Bits. Andernfalls braucht dieser Filter nur einen Subtrakt und man fügt hinzu, obwohl die Zahlen in der Regel breiter als der Eingabewert sein müssen (mehr auf numerische Genauigkeit in einem separaten Abschnitt unten). Ich nehme normalerweise AD-Lesungen deutlich schneller als sie benötigt werden und wenden Sie zwei dieser Filter kaskadiert. Dies ist das digitale Äquivalent von zwei R-C-Filtern in Serie und dämpft um 12 dBoctave über der Rolloff-Frequenz. Allerdings ist für AD-Lesungen in der Regel mehr relevant, um den Filter im Zeitbereich zu betrachten, indem man seine Schrittantwort berücksichtigt. Dies sagt Ihnen, wie schnell Ihr System eine Veränderung sehen wird, wenn das, was Sie Änderungen messen. Um das Entwerfen dieser Filter zu erleichtern (was nur bedeutet, FF zu wählen und zu entscheiden, wie viele von ihnen zu kaskaden), verwende ich mein Programm FILTBITS. Sie legen die Anzahl der Schaltbits für jede FF in der kaskadierten Filterreihe fest und berechnet die Sprungantwort und andere Werte. Eigentlich laufe ich in der Regel über mein Wrapper-Skript PLOTFILT. Dies führt FILTBITS, die eine CSV-Datei macht, dann die CSV-Datei. Zum Beispiel ist hier das Ergebnis von PLOTFILT 4 4: Die beiden Parameter zu PLOTFILT bedeuten, dass es zwei Filter gibt, die von der oben beschriebenen Art kaskadiert sind. Die Werte von 4 geben die Anzahl der Verschiebungsbits an, um die Multiplikation mit FF zu realisieren. Die beiden FF-Werte sind also in diesem Fall 116. Die rote Spur ist die Einheit Schritt Antwort, und ist die Hauptsache zu betrachten. Zum Beispiel sagt Ihnen dies, dass, wenn sich die Eingabe sofort ändert, die Ausgabe des kombinierten Filters auf 90 des neuen Wertes in 60 Iterationen absetzen wird. Wenn Sie sich um 95 Zeit entscheiden, dann müssen Sie auf 73 Iterationen warten, und für 50 Einschwingzeit nur 26 Iterationen. Die grüne Spur zeigt Ihnen die Ausgabe von einer einzigen Amplitude. Dies gibt Ihnen eine Vorstellung von der zufälligen Geräuschunterdrückung. Es sieht so aus, als würde kein einzelnes Beispiel mehr als eine 2,5-Änderung in der Ausgabe verursachen. Die blaue Spur ist, ein subjektives Gefühl zu geben, was dieser Filter mit weißem Rauschen macht. Dies ist kein rigoroser Test, da es keine Garantie gibt, was genau der Inhalt von den zufälligen Zahlen war, die als der weiße Rauschen Eingang für diesen Lauf von PLOTFILT ausgewählt wurden. Sein nur, um Ihnen ein grobes Gefühl zu geben, wie viel es zerquetscht wird und wie glatt es ist. PLOTFILT, vielleicht FILTBITS, und viele andere nützliche Sachen, vor allem für PIC Firmware-Entwicklung ist in der PIC Development Tools Software-Version auf meiner Software-Downloads-Seite verfügbar. Hinzugefügt über numerische Präzision sehe ich aus den Kommentaren und nun eine neue Antwort, dass es Interesse an der Diskussion über die Anzahl der Bits, die benötigt werden, um diesen Filter zu implementieren. Beachten Sie, dass die Multiplikation mit FF log 2 (FF) neue Bits unterhalb des Binärpunktes erzeugt. Bei kleinen Systemen wird FF gewöhnlich als 12 N gewählt, so daß diese Multiplikation tatsächlich durch eine rechte Verschiebung von N Bits realisiert wird. FILT ist also meist ein Fixpunkt ganzzahlig. Beachten Sie, dass dies nicht ändern, eine der Mathematik aus der Prozessoren Sicht. Wenn Sie z. B. 10-Bit-AD-Messwerte und N 4 (FF 116) filtern, benötigen Sie 4 Bruchbits unterhalb der 10-Bit-Integer-AD-Messwerte. Eine der meisten Prozessoren, youd machen 16-Bit-Integer-Operationen aufgrund der 10-Bit-AD-Messwerte. In diesem Fall können Sie immer noch genau die gleichen 16-Bit-Integer-Opertionen, aber beginnen mit der AD-Lesungen links um 4 Bits verschoben. Der Prozessor kennt den Unterschied nicht und muss nicht. Die Mathematik auf ganzen 16-Bit-Ganzzahlen zu machen, funktioniert man, wenn man sie als 12,4 Fixpunkt oder wahre 16-Bit-Ganzzahlen betrachtet (16,0 Fixpunkt). Im Allgemeinen müssen Sie N Bits jeden Filterpol hinzufügen, wenn Sie nicht möchten, dass Rauschen aufgrund der numerischen Darstellung hinzufügen. Im obigen Beispiel müsste der zweite Filter von zwei 1044 18 Bits haben, um keine Informationen zu verlieren. In der Praxis auf einer 8-Bit-Maschine, die bedeutet, dass Sie 24-Bit-Werte verwenden. Technisch würde nur der zweite Pol von zwei den größeren Wert benötigen, aber für die Firmware-Einfachheit verwende ich gewöhnlich dieselbe Darstellung und damit denselben Code für alle Pole eines Filters. Normalerweise schreibe ich eine Unterroutine oder ein Makro, um einen Filterpolbetrieb durchzuführen, dann das auf jeden Pol anwenden. Ob eine Subroutine oder ein Makro davon abhängt, ob Zyklen oder Programmspeicher in diesem Projekt wichtiger sind. So oder so, ich benutze einen Scratch-Zustand, um NEU in den Subroutinemacro zu übergeben, der FILT aktualisiert, aber auch Lasten, die in den gleichen Kratzer Zustand NEU war in. Dies macht es einfach, mehrere Pole anzuwenden, da die aktualisierte FILT von einem Pole die NEU ist Der nächsten. Wenn eine Subroutine, ist es nützlich, einen Zeiger auf FILT auf dem Weg in, die aktualisiert wird, um nur nach FILT auf dem Ausweg. Auf diese Weise arbeitet die Subroutine automatisch auf aufeinanderfolgenden Filtern im Speicher, wenn sie mehrmals aufgerufen wird. Mit einem Makro brauchst du keinen Zeiger, da du die Adresse passierst, um bei jeder Iteration zu operieren. Code Beispiele Hier ist ein Beispiel für ein Makro wie oben für ein PIC 18 beschrieben: Und hier ist ein ähnliches Makro für ein PIC 24 oder dsPIC 30 oder 33: Beide Beispiele werden als Makros mit meinem PIC Assembler Preprocessor implementiert. Die mehr fähig ist als die eingebauten Makroanlagen. Clabacchio: Ein anderes Problem, das ich erwähnt habe, ist die Firmware-Implementierung. Sie können einmal ein einzelnes Pole-Tiefpassfilter-Subroutine schreiben, dann mehrmals anwenden. In der Tat schreibe ich normalerweise eine solche Unterroutine, um einen Zeiger in den Speicher auf den Filterzustand zu bringen, dann schalte ihn der Zeiger vor, damit er nacheinander einfach aufgerufen werden kann, um mehrpolige Filter zu realisieren. Ndash Olin Lathrop 20. April um 15:03 1. Vielen Dank für eure Antworten - alle von ihnen. Ich habe mich entschlossen, diesen IIR Filter zu verwenden, aber dieser Filter wird nicht als Standard LowPass Filter verwendet, da ich die Zählerwerte durchschnittlich vergleichen und sie vergleichen muss, um Änderungen in einem bestimmten Bereich zu erkennen. Da diese Werte von sehr unterschiedlichen Dimensionen je nach Hardware abhängen, wollte ich einen Durchschnitt nehmen, um auf diese Hardware-spezifischen Änderungen automatisch reagieren zu können. Ndash sensslen Wenn Sie mit der Beschränkung einer Macht von zwei Anzahl von Gegenständen zu durchschnittlich (dh 2,4,8,16,32 usw.) leben können, dann kann die Kluft einfach und effizient auf einem getan werden Low-Performance-Mikro mit keine dedizierten Divide, weil es als Bit-Shift durchgeführt werden kann. Jede Schicht rechts ist eine Potenz von zwei zB: Das OP dachte, er habe zwei Probleme, die sich in einem PIC16 und Speicher für seinen Ringpuffer teilen. Diese Antwort zeigt, dass die Teilung nicht schwer ist. Zugegeben, es adressiert nicht das Speicherproblem, aber das SE-System erlaubt teilweise Antworten, und Benutzer können etwas von jeder Antwort für sich selbst nehmen oder sogar bearbeiten und kombinieren other39s Antworten. Da einige der anderen Antworten eine Aufteilungsoperation erfordern, sind sie ähnlich unvollständig, da sie nicht zeigen, wie man dies effizient auf einem PIC16 erreichen kann. Ndash Martin Apr 20 12 at 13:01 Es gibt eine Antwort für eine echte gleitende durchschnittliche Filter (aka boxcar Filter) mit weniger Speicherbedarf, wenn Sie nicht Bedenken Downsampling. Es heißt ein kaskadierter Integrator-Kamm-Filter (CIC). Die Idee ist, dass Sie einen Integrator haben, den Sie Unterschiede über einen Zeitraum nehmen, und das Schlüssel speichersparendes Gerät ist, dass durch Downsampling, müssen Sie nicht jeden Wert des Integrators zu speichern. Es kann mit dem folgenden Pseudocode implementiert werden: Ihre effektive gleitende durchschnittliche Länge ist decimationFactorstatesize, aber Sie müssen nur umzustandsmuster zu halten. Offensichtlich können Sie eine bessere Leistung erzielen, wenn Ihr stateize und decimationFactor Potenzen von 2 sind, so dass die Division und Restbetreiber durch Verschiebungen und Masken ersetzt werden. Postscript: Ich bin einverstanden mit Olin, dass Sie immer einfache IIR-Filter vor einem gleitenden durchschnittlichen Filter beachten sollten. Wenn Sie nicht die Frequenznulls eines Boxcar Filters benötigen, wird ein 1-poliger oder 2-poliger Tiefpassfilter wahrscheinlich gut funktionieren. Auf der anderen Seite, wenn Sie für die Zwecke der Dezimierung filtern (wobei ein High-Sample-Rate-Input und Mittelwertbildung für die Verwendung durch einen Low-Rate-Prozess) dann ein CIC-Filter kann genau das, was Sie suchen. (Vor allem, wenn Sie stateize1 verwenden und den Ringpuffer insgesamt mit nur einem vorherigen Integrator-Wert vermeiden können). Hierbei handelt es sich um eine eingehende Analyse der Mathematik hinter dem ersten Auftrags-IIR-Filter, den Olin Lathrop bereits auf der Digital Signal Processing Stack Exchange beschrieben hat (Enthält viele schöne Bilder.) Die Gleichung für diesen IIR-Filter ist: Dies kann mit nur Integern und keine Teilung mit dem folgenden Code implementiert werden (könnte einige Debugging, wie ich aus dem Speicher war.) Dieser Filter nähert sich einem gleitenden Durchschnitt von Die letzten K-Samples durch Setzen des Wertes von alpha auf 1K. Führen Sie dies im vorherigen Code durch, indem Sie BITS auf LOG2 (K) definieren, dh für K 16 gesetzt BITS bis 4, für K 4 gesetzt BITS bis 2, etc. (Ill überprüfen Sie den hier aufgeführten Code, sobald ich eine Änderung bekomme und Beantworten Sie diese Antwort, wenn nötig.) Beantwortet Jun 23 12 um 4:04 Heres ein einpoliger Tiefpassfilter (gleitender Durchschnitt mit Cutoff-Frequenz CutoffFrequenz). Sehr einfach, sehr schnell, funktioniert super und fast kein Speicher oben. Hinweis: Alle Variablen haben Umfang über die Filterfunktion hinaus, mit Ausnahme der übergebenen newInput Hinweis: Dies ist ein einstufiger Filter. Mehrere Stufen können zusammenkaskadiert werden, um die Schärfe des Filters zu erhöhen. Wenn Sie mehr als eine Stufe verwenden, müssen Sie den DecayFactor (bezogen auf die Cutoff-Frequency) anpassen, um zu kompensieren. Und offensichtlich alles, was Sie brauchen, ist die beiden Linien irgendwo platziert, sie brauchen nicht ihre eigene Funktion. Dieser Filter hat eine Rampenzeit, bevor der gleitende Mittelwert des Eingangssignals entspricht. Wenn Sie diese Rampenzeit umgehen müssen, können Sie MovingAverage einfach auf den ersten Wert von newInput anstelle von 0 initialisieren und hoffen, dass der erste newInput kein Ausreißer ist. (CutoffFrequencySampleRate) hat einen Bereich zwischen 0 und 0,5. DecayFactor ist ein Wert zwischen 0 und 1, in der Regel in der Nähe von 1. Single-Präzision Schwimmer sind gut genug für die meisten Dinge, ich bevorzuge einfach Doppelzimmer. Wenn du mit Ganzzahlen haften musst, kannst du DecayFactor und Amplitude Factor in gebrochene Ganzzahlen umwandeln, in denen der Zähler als Integer gespeichert ist und der Nenner eine ganzzahlige Potenz von 2 ist (also kannst du dich nach rechts verschieben Nenner anstatt sich während der Filterschleife zu teilen). Zum Beispiel, wenn DecayFactor 0,99, und du willst ganze Zahlen verwenden, kannst du DecayFactor 0,99 65536 64881 einstellen. Und dann, wenn du dich von DecayFactor in deiner Filterschleife vermehrst, verschiebst du einfach das Ergebnis 16. Für weitere Informationen dazu ein exzellentes Buch thats Online, Kapitel 19 auf rekursive Filter: dspguidech19.htm PS Für das Moving Average-Paradigma, ein anderer Ansatz zur Einstellung DecayFactor und AmplitudeFactor, die möglicherweise mehr relevant für Ihre Bedürfnisse, sagen wir, dass Sie wollen die vorherigen, etwa 6 Punkte gemittelt zusammen, tun es diskret, youd fügen Sie 6 Elemente und teilen durch 6, so Sie können den AmplitudeFactor auf 16 und DecayFactor auf (1.0 - AmplitudeFactor) einstellen. Antwortete am 14. Mai 12 um 22:55 Alle anderen haben sich gründlich über den Nutzen von IIR vs. FIR und auf Power-of-Two Division kommentiert. Id nur gerne einige Implementierungsdetails zu geben. Die unten funktioniert gut auf kleinen Mikrocontrollern ohne FPU. Theres keine Multiplikation, und wenn Sie N eine Macht von zwei halten, ist die ganze Teilung Single-Cycle-Bit-Shifting. Grundlegende FIR-Ringpuffer: Halten Sie einen laufenden Puffer der letzten N-Werte und eine laufende SUM aller Werte im Puffer. Jedes Mal, wenn ein neues Sample hereinkommt, subtrahieren Sie den ältesten Wert im Puffer von SUM, ersetzen ihn mit dem neuen Sample, fügen Sie das neue Sample zu SUM hinzu und geben Sie SUMN aus. Modifizierter IIR-Ringpuffer: Halten Sie einen laufenden SUM der letzten N-Werte. Jedes Mal, wenn ein neues Sample kommt, SUM - SUMN, fügen Sie das neue Sample hinzu und geben Sie SUMN aus. Antwortete am 28. August 13 um 13:45 Wenn ich dich gerade richtig lese, beschreibst du einen ersten IIR-Filter, der den Wert, den du subtrahierst, nicht auf den ältesten Wert, der herausfällt, sondern stattdessen der Durchschnitt der vorherigen Werte ist. Erstklassige IIR-Filter können sicherlich nützlich sein, aber ich bin mir nicht sicher, was du meinst, wenn du vorschreibst, dass die Ausgabe für alle periodischen Signale gleich ist. Bei einer Abtastrate von 10 kHz liefert die Zuführung einer 100-Hz-Rechteckwelle in einen 20-stufigen Kastenfilter ein Signal, das für 20 Proben gleichmäßig ansteigt, für 30 sitzt, für 20 Proben gleichmäßig sinkt und für 30 niedrig sitzt. Eine erste Ordnung IIR-Filter Ndash supercat 28. August 13 um 15:31 wird eine Welle, die scharf beginnt zu steigen und allmählich aus der Nähe (aber nicht auf) der Eingabe Maximum, dann scharf beginnt zu fallen und allmählich aus der Nähe (aber nicht auf) die Eingabe Minimum. Sehr unterschiedliches Verhalten Ndash supercat Eine Frage ist, dass ein einfacher gleitender Durchschnitt kann oder nicht nützlich sein. Mit einem IIR-Filter kannst du einen schönen Filter mit relativ wenigen Berechnungen bekommen. Die FIR, die Sie beschreiben, kann Ihnen nur ein Rechteck in der Zeit geben - ein sinc in freq - und Sie können die Seitenkeulen verwalten. Es lohnt sich, ein paar ganzzahlige Multiplikatoren zu werfen, um es zu einem schönen symmetrischen, abstimmbaren FIR zu machen, wenn man die Uhrzeiger ersparen kann. Ndash Scott Seidman Aug 29 13 bei 13:50 ScottSeidman: Keine Notwendigkeit für Multiplikationen, wenn man einfach jede Stufe der FIR entweder den Mittelwert der Eingabe auf diese Stufe und ihren vorherigen gespeicherten Wert ausgibt und dann die Eingabe speichern (falls man hat Der numerische Bereich, man könnte die Summe eher als Durchschnitt verwenden). Ob das besser als ein Kastenfilter ist, hängt von der Anwendung ab (die Sprungantwort eines Kastenfilters mit einer Gesamtverzögerung von 1ms, zum Beispiel, wird eine böse d2dt Spitze haben, wenn die Eingangsänderung und wieder 1ms später, aber das Minimum haben wird Möglich ddt für einen Filter mit insgesamt 1ms Verzögerung). Ndash supercat Als mikeselectricstuff sagte, wenn Sie wirklich brauchen, um Ihren Speicherbedarf zu reduzieren, und Sie dont mind Ihre Impulsantwort ist ein exponentielles (anstelle eines rechteckigen Pulses), würde ich für einen exponentiellen gleitenden durchschnittlichen Filter gehen . Ich benutze sie ausgiebig. Bei dieser Art von Filter brauchst du keinen Puffer. Sie müssen nicht n hintere Proben speichern. Nur einer. Also, Ihre Speicheranforderungen werden durch einen Faktor von N reduziert. Auch brauchst du keine Teilung dafür. Nur Multiplikationen Wenn Sie Zugriff auf Gleitkomma-Arithmetik haben, verwenden Sie Gleitkomma-Multiplikationen. Andernfalls machen ganzzahlige Multiplikationen und verschieben nach rechts. Allerdings sind wir im Jahr 2012, und ich würde Ihnen empfehlen, Compiler (und MCUs) zu verwenden, mit denen Sie mit Gleitkommazahlen arbeiten können. Abgesehen davon, dass mehr Speicher effizienter und schneller (Sie müssen nicht Elemente in jedem kreisförmigen Puffer zu aktualisieren), würde ich sagen, es ist auch natürlicher. Denn eine exponentielle Impulsantwort passt besser der Art, wie sich die Natur verhält, in den meisten Fällen. Beantwortet Apr 20 12 at 9:59 Ein Problem mit dem IIR-Filter, der fast von Olin und Supercat berührt wird, aber anscheinend von anderen nicht beachtet wird, ist, dass die Abrundung einige Ungenauigkeiten (und potenziell Biastruncation) einführt. Unter der Annahme, dass N eine Potenz von zwei ist und nur ganzzahlige Arithmetik verwendet wird, beseitigt das Verschiebungsrecht systematisch die LSBs der neuen Probe. Das heißt, wie lange die Serie jemals sein könnte, der Durchschnitt wird diese niemals berücksichtigen. Nehmen wir z. B. eine langsam abnehmende Reihe an (8,8,8, 8,7,7,7,7,7,6,6) und nehmen an, daß der Durchschnitt in der Tat 8 am Anfang ist. Die erste 7 Probe wird den Durchschnitt auf 7 bringen, was auch immer die Filterstärke. Nur für eine Probe. Gleiche Geschichte für 6, etc. Jetzt an das Gegenteil denken. Die serie geht nach oben Der Durchschnitt wird auf 7 für immer bleiben, bis die Probe groß genug ist, um es zu ändern. Natürlich können Sie für die Vorspannung korrigieren, indem Sie 12N2 hinzufügen, aber das wird nicht wirklich das Präzisionsproblem lösen. In diesem Fall bleibt die abnehmende Reihe für immer bei 8, bis die Probe 8-12 (N2) ist. Für N4 zum Beispiel wird jede Probe über Null den Durchschnitt unverändert halten. Ich glaube, eine Lösung dafür würde bedeuten, einen Akkumulator der verlorenen LSBs zu halten. Aber ich habe es nicht weit genug gemacht, um Code bereit zu haben, und ich bin nicht sicher, dass es nicht schaden würde die IIR Macht in einigen anderen Fällen von Serien (zum Beispiel, ob 7,9,7,9 würde durchschnittlich 8 dann). Olin, deine zweistufige Kaskade braucht auch eine Erklärung. Meinst du mit zwei durchschnittlichen Werten, mit dem Ergebnis der ersten in die Sekunde in jeder Iteration eingegeben. Was ist der Vorteil davon

No comments:

Post a Comment