Verschieben Durchschnitt Pic18f


Wie andere schon erwähnt haben, sollten Sie einen IIR (Endlosimpulsantwort) - Filter anstelle des FIR (Finite Impulse Response) Filter, den Sie jetzt verwenden. Es gibt mehr dazu, aber auf den ersten Blick werden FIR-Filter als explizite Windungen und IIR-Filter mit Gleichungen implementiert. Das besondere IIR-Filter, das ich viel in Mikrocontrollern verwende, ist ein einpoliges Tiefpaßfilter. Dies ist das digitale Äquivalent eines einfachen R-C-Analogfilters. Für die meisten Anwendungen haben diese bessere Eigenschaften als der Kastenfilter, den Sie verwenden. Die meisten Verwendungen eines Box-Filter, die ich begegnet bin, sind ein Ergebnis von jemand nicht Aufmerksamkeit in der digitalen Signalverarbeitung Klasse, nicht als Ergebnis der Notwendigkeit ihrer besonderen Eigenschaften. Wenn Sie nur wollen, um hohe Frequenzen zu dämpfen, dass Sie wissen, Rauschen sind, ist ein einpoliges Tiefpassfilter besser. Der beste Weg, um ein digitales in einem Mikrocontroller zu implementieren, ist in der Regel: FILT lt - FILT FF (NEW - 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 einstellt. Betrachten Sie diesen Algorithmus und sehen Sie, dass für FF 0 der Filter unendlich schwer ist, da sich der Ausgang nie ändert. Für FF 1 ist das eigentlich gar kein Filter, da der Ausgang nur dem Eingang folgt. Nützliche Werte sind dazwischen. Bei kleinen Systemen wählen Sie FF auf 1/2 N, so dass die Multiplikation mit FF als Rechtsverschiebung um N Bits erreicht werden kann. Beispielsweise kann FF 1/16 betragen und das Multiplizieren mit FF daher eine Rechtsverschiebung von 4 Bits. Andernfalls benötigt dieses Filter nur eine Subtraktion und eine Addition, obwohl die Zahlen in der Regel größer als der Eingangswert sein müssen (mehr über die numerische Genauigkeit in einem separaten Abschnitt weiter unten). Ich normalerweise nehmen A / D-Messwerte 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 dB / Oktave über der Rolloff-Frequenz. Für A / D-Messungen ist es jedoch gewöhnlich relevanter, den Filter im Zeitbereich zu betrachten, indem er seine Sprungantwort betrachtet. Dies zeigt Ihnen, wie schnell Ihr System eine Änderung sehen wird, wenn die Sache, die Sie messen, ändert. Zur Erleichterung der Gestaltung dieser Filter (was nur bedeutet Kommissionierung FF und entscheiden, wie viele von ihnen zu kaskadieren), benutze ich mein Programm FILTBITS. Sie legen die Anzahl der Schaltbits für jede FF in der kaskadierten Filterreihe fest und berechnen die Schrittantwort und andere Werte. Eigentlich habe ich in der Regel laufen diese über mein Wrapper-Skript PLOTFILT. Dies führt FILTBITS, die eine CSV-Datei macht, dann die CSV-Datei. Beispielsweise ist hier das Ergebnis von PLOTFILT 4 4: Die beiden Parameter zu PLOTFILT bedeuten, dass es zwei Filter gibt, die von dem oben beschriebenen Typ kaskadiert sind. Die Werte von 4 geben die Anzahl der Schaltbits an, um die Multiplikation mit FF zu realisieren. Die beiden FF-Werte sind in diesem Fall 1/16. Die rote Spur ist die Einheit Schritt Antwort, und ist die Hauptsache zu betrachten. Dies bedeutet beispielsweise, dass sich der Ausgang des kombinierten Filters auf 90 des neuen Wertes in 60 Iterationen niederschlägt, falls sich der Eingang sofort ändert. Wenn Sie ca. 95 Einschwingzeit kümmern, dann müssen Sie etwa 73 Iterationen warten, und für 50 Einschwingzeit nur 26 Iterationen. Die grüne Kurve zeigt Ihnen den Ausgang einer einzelnen Amplitude. Dies gibt Ihnen eine Vorstellung von der zufälligen Rauschunterdrückung. Es sieht aus wie keine einzelne Probe wird mehr als eine 2,5 Änderung in der Ausgabe verursachen. Die blaue Spur soll ein subjektives Gefühl geben, was dieser Filter mit weißem Rauschen macht. Dies ist kein strenger Test, da es keine Garantie gibt, was genau der Inhalt der Zufallszahlen war, die als der weiße Rauscheneingang für diesen Durchlauf von PLOTFILT ausgewählt wurden. Seine nur, um Ihnen ein grobes Gefühl, wie viel es gequetscht werden und wie glatt es ist. PLOTFILT, vielleicht FILTBITS, und viele andere nützliche Dinge, vor allem für PIC-Firmware-Entwicklung ist verfügbar in der PIC Development Tools-Software-Release auf meiner Software-Downloads-Seite. Hinzugefügt über numerische Genauigkeit Ich sehe aus den Kommentaren und nun eine neue Antwort, dass es Interesse an der Diskussion der Anzahl der Bits benötigt, um diesen Filter zu implementieren. Beachten Sie, dass das Multiplizieren mit FF Log 2 (FF) neue Bits unterhalb des Binärpunkts erzeugt. Bei kleinen Systemen wird FF gewöhnlich mit 1/2 N gewählt, so daß diese Multiplikation tatsächlich durch eine Rechtsverschiebung von N Bits realisiert wird. FILT ist daher meist eine feste Ganzzahl. Beachten Sie, dass dies ändert keine der Mathematik aus der Prozessoren Sicht. Wenn Sie beispielsweise 10-Bit A / D-Messwerte und N 4 (FF 1/16) filtern, benötigen Sie 4 Fraktionsbits unter den 10-Bit-Integer-A / D-Messwerten. Einer der meisten Prozessoren, youd tun 16-Bit-Integer-Operationen aufgrund der 10-Bit-A / D-Lesungen. In diesem Fall können Sie immer noch genau die gleichen 16-Bit-Integer-Opertions, aber beginnen mit der A / D-Lesungen um 4 Bits verschoben verschoben. Der Prozessor kennt den Unterschied nicht und muss nicht. Das Durchführen der Mathematik auf ganzen 16-Bit-Ganzzahlen funktioniert, ob Sie sie als 12,4 feste oder wahre 16-Bit-Ganzzahlen (16,0 Fixpunkt) betrachten. Im Allgemeinen müssen Sie jedem Filterpole N Bits hinzufügen, wenn Sie aufgrund der numerischen Darstellung kein Rauschen hinzufügen möchten. Im obigen Beispiel müsste das zweite Filter von zwei 1044 18 Bits haben, um keine Informationen zu verlieren. In der Praxis auf einer 8-Bit-Maschine bedeutet, dass youd 24-Bit-Werte verwenden. Technisch nur den zweiten Pol von zwei würde den größeren Wert benötigen, aber für Firmware Einfachheit ich in der Regel die gleiche Darstellung, und damit der gleiche Code, für alle Pole eines Filters. Normalerweise schreibe ich eine Unterroutine oder Makro, um eine Filterpol-Operation durchzuführen, dann gelten, dass für jeden Pol. Ob eine Unterroutine oder ein Makro davon abhängt, ob Zyklen oder Programmspeicher in diesem Projekt wichtiger sind. So oder so, ich benutze einige Scratch-Zustand, um NEU in die Subroutine / Makro, die FILT Updates, sondern auch lädt, dass in den gleichen Kratzer NEU war in. Dies macht es einfach, mehrere Pole anzuwenden, da die aktualisierte FILT von einem Pol ist Die NEUE der nächsten. Wenn ein Unterprogramm, ist es sinnvoll, einen Zeiger auf FILT auf dem Weg in, die auf nur nach FILT auf dem Weg nach draußen aktualisiert wird. Auf diese Weise arbeitet das Unterprogramm automatisch auf aufeinanderfolgenden Filtern im Speicher, wenn es mehrmals aufgerufen wird. Mit einem Makro benötigen Sie nicht einen Zeiger, da Sie in der Adresse passieren, um auf jeder Iteration zu arbeiten. Code-Beispiele Hier ist ein Beispiel für ein Makro wie oben für eine PIC 18 beschrieben: Und hier ist ein ähnliches Makro für eine PIC 24 oder dsPIC 30 oder 33: Beide Beispiele sind als Makros mit meinem PIC-Assembler-Präprozessor implementiert. Die mehr fähig ist als eine der eingebauten Makroanlagen. Clabacchio: Ein weiteres Thema, das ich erwähnen sollte, ist die Firmware-Implementierung. Sie können eine einpolige Tiefpassfilter-Subroutine einmal schreiben und dann mehrmals anwenden. Tatsächlich schreibe ich normalerweise solch ein Unterprogramm, um einen Zeiger im Gedächtnis in den Filterzustand zu nehmen, dann ihn voranbringen den Zeiger, so daß er nacheinander leicht aufgerufen werden kann, um mehrpolige Filter zu verwirklichen. Ndash Olin Lathrop Apr 20 12 at 15:03 1. Dank sehr viel für Ihre Antworten - alle von ihnen. Ich beschloss, dieses IIR-Filter zu verwenden, aber dieser Filter wird nicht als Standard-Tiefpaßfilter verwendet, da ich die Zählerwerte berechnen und sie vergleichen muss, um Änderungen in einem bestimmten Bereich zu erkennen. Da diese Werte von sehr unterschiedlichen Dimensionen abhängig von Hardware Ich wollte einen Durchschnitt nehmen, um in der Lage sein, auf diese Hardware spezifischen Änderungen automatisch reagieren. Wenn Sie mit der Beschränkung einer Macht von zwei Anzahl von Elementen zu durchschnittlich leben können (dh 2,4,8,16,32 etc), dann kann die Teilung einfach und effizient auf einem getan werden Low-Performance-Mikro ohne dedizierte Division, weil es als Bit-Shift durchgeführt werden kann. Jede Schicht rechts ist eine Macht von zwei zB: Der OP dachte, er hatte zwei Probleme, die Teilung in einem PIC16 und Speicher für seinen Ringpuffer. Diese Antwort zeigt, dass die Teilung nicht schwierig ist. Zwar adressiert es nicht das Gedächtnisproblem, aber das SE-System erlaubt Teilantworten, und Benutzer können etwas von jeder Antwort für selbst nehmen, oder sogar redigieren und kombinieren andere39s Antworten. Da einige der anderen Antworten eine Divisionsoperation erfordern, sind sie ähnlich unvollständig, da sie nicht zeigen, wie dies auf einem PIC16 effizient erreicht werden kann. Ndash Martin Apr 20 12 at 13:01 Es gibt eine Antwort für einen echten gleitenden Durchschnitt Filter (auch bekannt als Boxcar-Filter) mit weniger Speicher Anforderungen, wenn Sie dont mind Downsampling. Es heißt ein kaskadiertes Integrator-Kamm-Filter (CIC). Die Idee ist, dass Sie einen Integrator, die Sie nehmen Differenzen über einen Zeitraum, und die wichtigsten Speicher-sparende 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 um Stateize Proben zu halten. Offensichtlich können Sie bessere Leistung erzielen, wenn Ihr stateize und decimationFactor Potenzen von 2 sind, so dass die Divisions - und Restoperatoren durch Shifts und Masken ersetzt werden. Postscript: Ich stimme mit Olin, dass Sie immer sollten einfache IIR-Filter vor einem gleitenden durchschnittlichen Filter. Wenn Sie die Frequenz-Nullen eines Boxcar-Filters nicht 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 (mit einer hohen Sample-Rate-Eingang und Mittelung es für die Verwendung durch einen Low-Rate-Prozess), dann kann ein CIC-Filter genau das, was Sie suchen. (Vor allem, wenn Sie stateize1 verwenden und den Ringbuffer insgesamt mit nur einem einzigen vorherigen Integrator-Wert zu vermeiden) Theres einige eingehende Analyse der Mathematik hinter der Verwendung der ersten Ordnung IIR-Filter, Olin Lathrop bereits beschrieben hat auf der Digital Signal Processing Stack-Austausch (Enthält viele schöne Bilder.) Die Gleichung für diese IIR-Filter ist: Dies kann mit nur Ganzzahlen und keine Division mit dem folgenden Code implementiert werden (möglicherweise benötigen einige Debugging, wie ich aus dem Speicher wurde.) Dieser Filter approximiert einen gleitenden Durchschnitt von Die letzten K Proben durch Einstellen des Wertes von alpha auf 1 / K. Führen Sie dies im vorherigen Code durch die Definition von BITS auf LOG2 (K), dh für K 16 gesetzt BITS auf 4, für K 4 gesetzt BITS auf 2, etc. (Ill Überprüfung der Code hier aufgelistet, sobald ich eine Änderung und Bearbeiten Sie diese Antwort, wenn nötig.) Antwort # 1 am: Juni 23, 2010, um 4:04 Uhr Heres ein einpoliges Tiefpassfilter (gleitender Durchschnitt, mit Cutoff-Frequenz CutoffFrequency). Sehr einfach, sehr schnell, funktioniert super, und fast kein Speicher Overhead. Hinweis: Alle Variablen haben einen Bereich über die Filterfunktion hinaus, mit Ausnahme des übergebenen newInput Hinweis: Dies ist ein einstufiger Filter. Mehrere Stufen können zusammen kaskadiert werden, um die Schärfe des Filters zu erhöhen. Wenn Sie mehr als eine Stufe verwenden, müssen Sie DecayFactor anpassen (was die Cutoff-Frequenz betrifft), um sie zu kompensieren. Und natürlich alles, was Sie brauchen, ist die beiden Zeilen überall platziert, brauchen sie nicht ihre eigene Funktion. Dieser Filter hat eine Rampenzeit, bevor der gleitende Durchschnitt diejenige des Eingangssignals darstellt. 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. (CutoffFrequency / SampleRate) einen Bereich zwischen 0 und 0,5 aufweist. DecayFactor ist ein Wert zwischen 0 und 1, in der Regel in der Nähe von 1. Single-precision Schwimmer sind gut genug für die meisten Dinge, ich bevorzuge nur Doppel. Wenn Sie mit ganzen Zahlen bleiben müssen, können Sie DecayFactor und Amplitude Factor in Fractional Integers umwandeln, in denen der Zähler als Integer gespeichert wird und der Nenner eine Ganzzahl von 2 ist (so können Sie Bit-Shift nach rechts als die Nenner, anstatt sich während der Filterschleife teilen zu müssen). Zum Beispiel, wenn DecayFactor 0.99, und Sie Ganzzahlen verwenden möchten, können Sie DecayFactor 0.99 65536 64881. Und dann immer wenn Sie multiplizieren mit DecayFactor in Ihrer Filterschleife, nur verschieben Sie das Ergebnis 16. Für weitere Informationen über dieses, ein ausgezeichnetes Buch thats Online, Kapitel 19 auf rekursive Filter: dspguide / ch19.htm PS Für das Moving Average-Paradigma, einen anderen Ansatz für die Einstellung DecayFactor und AmplitudeFactor, die möglicherweise mehr relevant für Ihre Bedürfnisse, können Sie sagen, Sie wollen die vorherigen, etwa 6 Artikeln gemittelt, diskret tun es, fügen Sie 6 Elemente und teilen durch 6, so Können Sie den AmplitudeFactor auf 1/6 und DecayFactor auf (1.0 - AmplitudeFactor) einstellen. Antwortete May 14 12 at 22:55 Jeder andere hat kommentiert gründlich über den Nutzen der IIR vs FIR, und auf Power-of-two-Division. Id nur, um einige Implementierungsdetails zu geben. Das unten genannte funktioniert gut auf kleinen Mikrocontrollern ohne FPU. Es gibt keine Multiplikation, und wenn Sie N eine Potenz von zwei halten, ist die gesamte Division ein-Zyklus-Bit-Verschiebung. Basic FIR-Ringpuffer: Halten Sie einen laufenden Puffer der letzten N-Werte und einen laufenden SUM aller Werte im Puffer. Jedes Mal, wenn eine neue Probe kommt, subtrahieren Sie den ältesten Wert im Puffer von SUM, ersetzen Sie ihn durch das neue Sample, fügen Sie das neue SUM zu SUM hinzu und geben Sie SUM / N aus. Modifizierter IIR-Ringpuffer: Halten Sie einen laufenden SUM der letzten N-Werte. Jedes Mal, wenn ein neues Sample eingeht, SUM - SUM / N, fügen Sie das neue Sample hinzu und geben SUM / N aus. Antwort # 1 am: August 28, 2008, um 13:45 Uhr Wenn Sie 399m lesen Sie Recht, you39re beschreiben ein erster Ordnung IIR-Filter der Wert you39re subtrahieren isn39t der älteste Wert, der herausfällt, sondern ist stattdessen der Durchschnitt der vorherigen Werte. Erstklassige IIR-Filter können sicherlich nützlich sein, aber I39m nicht sicher, was du meinst, wenn Sie vorschlagen, dass der Ausgang ist der gleiche für alle periodischen Signale. Bei einer Abtastrate von 10 kHz liefert das Einspeisen einer 100 Hz-Rechteckwelle in ein 20-stufiges Kastenfilter ein Signal, das für 20 Abtastungen gleichmäßig ansteigt, für 30 sitzt, für 20 Abtastungen gleichmäßig sinkt und für 30 sitzt. Ein erster Ordnung IIR-Filter. Ndash Supercat Aug 28 13 am 15:31 wird eine Welle, die scharf anfängt zu steigen und allmählich Niveaus in der Nähe (aber nicht auf) das Eingabe-Maximum, dann scharf beginnt zu fallen und allmählich in der Nähe (aber nicht auf) der Eingabe Minimum. Sehr unterschiedliches Verhalten. Ndash Supercat Ein Problem ist, dass ein einfacher gleitender Durchschnitt kann oder auch nicht nützlich sein. Mit einem IIR-Filter können Sie einen schönen Filter mit relativ wenigen Calcs erhalten. Die FIR Sie beschreiben kann Ihnen nur ein Rechteck in der Zeit - ein sinc in freq - und Sie können nicht die Seitenkeulen zu verwalten. Es kann lohnt sich, in ein paar ganzzahlige Multiplikatoren zu werfen, um es eine schöne symmetrische abstimmbare FIR, wenn Sie die Zeitschaltuhren ersparen können. Ndash ScottSeidman: Keine Notwendigkeit für Multiplikatoren, wenn man einfach jede Stufe der FIR entweder den Durchschnitt der Eingabe auf diese Stufe und ihre vorherigen gespeicherten Wert, und dann speichern Sie die Eingabe (wenn man hat Der numerische Bereich, man könnte die Summe anstatt den Durchschnitt verwenden). Ob das besser ist als ein Box-Filter, hängt von der Anwendung ab (die Sprungantwort eines Boxfilters mit einer Gesamtverzögerung von 1ms wird zum Beispiel eine böse d2 / dt-Spitze aufweisen, wenn der Eingang geändert wird, und wieder 1ms später, wird aber haben Die minimal mögliche d / dt für einen Filter mit einer Gesamtverzögerung von 1ms). Ndash supercat Wie mikeselectricstuff sagte, wenn Sie wirklich brauchen, um Ihren Speicherbedarf zu reduzieren, und Sie dont dagegen Ihre Impulsantwort ist eine exponentielle (anstelle eines rechteckigen Puls), würde ich für einen exponentiellen gleitenden durchschnittlichen Filter gehen . Ich nutze sie ausgiebig. Mit dieser Art von Filter, brauchen Sie nicht jeden Puffer. Sie brauchen nicht zu speichern N Vergangenheit Proben. Nur einer. So werden Ihre Speicheranforderungen um einen Faktor von N reduziert. Auch brauchen Sie keine Division für das. Nur Multiplikationen. Wenn Sie Zugriff auf Gleitpunktarithmetik haben, verwenden Sie Fließkomma-Multiplikationen. Andernfalls können ganzzahlige Multiplikationen und Verschiebungen nach rechts erfolgen. Allerdings sind wir im Jahr 2012, und ich würde Ihnen empfehlen, Compiler (und MCUs), mit denen Sie mit Gleitkommazahlen arbeiten können. Abgesehen davon, dass mehr Speicher effizienter und schneller (Sie dont haben, um Elemente in jedem kreisförmigen Puffer zu aktualisieren), würde ich sagen, es ist auch natürlich. Weil eine exponentielle Impulsantwort besser auf die Art und Weise reagiert, wie sich die Natur verhält, in den meisten Fällen. Ein Problem mit dem IIR-Filter fast berührt von Olin und Supercat, aber anscheinend von anderen ignoriert ist, dass die Rundung nach unten führt einige Ungenauigkeiten (und möglicherweise Bias / Trunkierung). Unter der Annahme, dass N eine Potenz von zwei ist und nur ganzzahlige Arithmetik verwendet wird, beseitigt das Shift-Recht systematisch die LSBs des neuen Samples. Das bedeutet, dass, wie lange die Serie jemals sein könnte, wird der Durchschnitt nie berücksichtigen. Nehmen wir z. B. eine langsam abnehmende Reihe (8,8,8,8,7,7,7,7,6,6) an und nehmen an, daß der Durchschnitt tatsächlich 8 ist. Die Faust 7 Probe bringt den Durchschnitt auf 7, unabhängig von der Filterstärke. Nur für eine Probe. Gleiche Geschichte für 6, usw. Jetzt denke an das Gegenteil. Die serie geht auf. Der Durchschnitt bleibt auf 7 für immer, bis die Probe groß genug ist, um es zu ändern. Natürlich können Sie für die Bias korrigieren, indem Sie 1 / 2N / 2, aber das nicht wirklich lösen, die Präzision Problem. In diesem Fall wird die abnehmende Reihe für immer bei 8 bleiben, bis die Probe 8-1 / 2 (N / 2) ist. Für N4 zum Beispiel, wird jede Probe über Null halten den Durchschnitt unverändert. Ich glaube, eine Lösung für das implizieren würde, um einen Akkumulator der verlorenen LSBs halten. Aber ich habe es nicht weit genug, um Code bereit, und Im nicht sicher, es würde nicht schaden, die IIR Macht in einigen anderen Fällen der Serie (zum Beispiel, ob 7,9,7,9 würde durchschnittlich 8 dann). Olin, Ihre zweistufige Kaskade würde auch eine Erklärung brauchen. Halten Sie zwei durchschnittliche Werte mit dem Ergebnis der ersten in die zweite in jeder Iteration eingezogen halten. Was ist der Nutzen von diesem wie dieses Im Gegensatz zu ppulle 06 Aug 2009 Hallo, I39m auf der Suche nach ein wenig Hilfe, um einige Zeit zu retten das Rad neu zu erfinden. I39m Probenahme eine Anzahl von Sensoren, drei Beschleunigungsmesser, drei Magnetometer und zwei ADC-Kanäle. Die ADC - und Accelerometer-Kanäle geben mir unsigned int Daten und das Magnetometer gibt mir signierte Ints. Ich habe eine PIC18F4550 I39d wie diese in einer Tabelle zu speichern, und einen gleitenden Durchschnitt Filter auf sie. ZB: int aMagXArray8 // Arrays von jeweils 8 Werten // zuordnen. // Probieren Sie die Samples aus und setzen Sie sie in Variablen wie SensorMagX, SensorMagY usw. einMagXArraynPos SensorMagX aMagYArraynPos SensorMagY usw. nPos nPos nPos amp 0x07 // dh nPos von 0..7 halten und dann den gleitenden Durchschnitt z. B. nTot 0 für (i0ilt8i) nTot melden NTot aMagXArrayi nMagXAveragedValue nTot / 8 usw. Wiederholen Sie für die anderen sieben Sensoren einen ziemlich normalen gleitenden Durchschnitt Alogorithmus, speichern Sie die Proben in einer Tabelle mit einem rotierenden Zeiger und durchschnittlich die Tabelle, wenn Sie einen Wert möchten Leider ist alle diese Array-Referenzierung nimmt ein großes Stück Code-Raum, die ich don39t haben, weil alle anderen Code in meinem PIC. Verwendung von Zeigern isn39t viel Hilfe entweder. So I39d wie neu zu schreiben diese in Montage. Es ist schon eine Weile her, seit ich mit indirekter Adressierung gespielt habe, daher dieser Beitrag. Gibt es einen 18F4550-Assembler-Algorithmus, der ganze Zahlen (unsigned oder signed) summiert, die in einem Array sitzen Die Summe kann dann geteilt werden, um den gleitenden Durchschnitt zu geben. Vermutlich müssen I39d die Arrays auf einer einzigen Seite zuordnen, um die Dinge zu vereinfachen. Stellt der Sourceboost-Compiler automatisch sicher, dass Arrays in einer Seite zugewiesen werden Danke für jede Hilfe. Phil wie dieses im Gegensatz zu Reynard 06 Aug 2009 Arrays werden, wo der Linker denkt, es ist Platz. Wenn Sie Ihren Arrays eine feste Adresse zuweisen, können Sie sie auf derselben Seite platzieren. Alle Variablen, die Sie verwenden, um diese Arrays zu manipulieren, reparieren sie auf der gleichen Seite wie die Arrays, um einige Seitenschalt-Code zu reduzieren. Anstatt Ihre Arrays als kreisförmige Puffer zu behandeln und auf Zeigerumbruch zu testen, sollten Sie die Arrays als Stack verwenden. Verwenden Sie etwas wie Memmove oder Memcpy (oder Assembler Äquivalente), um alles verschieben, bis ein int dann fügen Sie Ihre neue Probe in die erste Array-Position nur. Deklarieren Sie unsignierte int-Arrays, in denen Sie unsigned ints speichern, um ein bisschen schneller für diese Datentypen hinzuzufügen. Wenn Sie mit 8 teilen, stellen Sie sicher, dass der Compiler keine 16-Bit-Teilungsroutine aufruft, sondern lediglich 3 Verschiebungen nach rechts macht. Wenn es dann tun Sie die Verschiebung sich. Das gleiche gilt für die signierten Ints. Holen Sie sich diese Assembler-Handbuch und sehen, was Sie tun können. Gefällt mir Im Gegensatz zu ppulle 07 Aug 2009 Hallo Reynard, Vielen Dank für die Antwort. Ich habe gebetet um immer meine Headspace wieder in Assembler-Modus. Erstens, I39m nicht sicher, es gibt einen memmove Opcode für die PIC18F4450. Ich würde mich darüber irren, inzwischen bleibe ich mit der runden Puffertechnik. Die Shift rechts für Divisoren von Vielfachen von 2 I39m schon auf. In der Tat, wenn man sich die Opcode von Sourceboost erstellt it39ll optimieren Divisionen, indem sie mehrere Schichten auf jeden Fall. Nicht sicher, über die richtige Verschiebung signierte Ints. Ich denke, Sie müssen die hohe Ordnung zu bewahren. In jedem Fall für 2-Byte-Ints mit 18F4450 müssen Sie zwei Byte-Verschiebungen zu tun, so dass auf dem High-Byte Sie klar, die zu tragen, drehen nach rechts durch tragen, so dass die niedrige Ordnung wird im Trager gespeichert dann drehen nach rechts durch tragen auf dem niedrigen (Mit dem gespeicherten Übertrag). Die indirekte Adressierung vs paging isn39t ein Problem I39ve herausgefunden, indem Sie das Datenblatt. I39ll die Adresse des Arrays einem der FSRx-Zeiger zuordnen und das POSTINCx-Register verwenden, um auf die Elemente zuzugreifen. Aus dem Datenblatt die INDFx, POSTINCx, PREINCx. Etc Register alle verwenden 12-Bit-Adressierung. So dass Paging isn39t ein Problem. Hier ist ein Trick, den ich gefunden habe, als ich versuchte, meinen Code effizienter zu gestalten. Ich hatte ursprünglich Code simliar zu: nSensorX readsensoradc (SENSORNUMBER) //, die einen ADC auf dem angegebenen Sensor ausliest und ein unsigned int zurückgibt. ASensorXcircularbufferpointer nSensorX oder aSensorXcircularbufferpointer readsensoradc (SENSORNUMBER) /// wo aSensorX ein Array ist alles gut und gut. Aber mit vielen Sensoren Sie am Ende mit viel Code generiert wird das Array Handling. Bloating-Code aus, da jeder Array-Zugriff separat behandelt wird. Ich fand es effizienter (wenn auch weniger lesbar), um meine Sensor-Lesefunktion neu zu schreiben, um einen Zeiger void readsensoradc (unsigned char nSensorNum, unsigned int dest) zu verwenden. Readsensoradc (SENSORNUMBER, aSensorXcircularbufferpointer) wird dieser Code nur für den Array / Pointer-Zugriff in der Funktion generiert und muss nicht für jeden Sensor wiederholt werden. Nur nützlich, wenn Sie Ihre Werte in ein Array einfügen möchten. Wie dies im Gegensatz zu Reynard 07 Aug 2009 Sie scheinen auf dem richtigen Weg für immer, dass Code Effizienz. Memmove und Memcpy sind Standard-Bibliotheksfunktionen und keine Op-Codes. Schreiben Sie Ihre eigene Version für Ihre Anwendung wäre wahrscheinlich effizienter und schneller. Um signierte Ints zu verschieben, benutzen Sie einfach eine C-Anweisung. Der Code produziert wird wahrscheinlich so gut wie Sie schreiben können und kümmert sich um die signd und trägt. Der Compiler kann gelegentlich FSR0 im Inneren installieren und Bibliotheksfunktionen so ein Auge auf, dass als Funktionen kann es nicht bewahren. Der Interrupt bewahrt FSR0. Bei Verwendung von FOR-Schleifen ist es manchmal schneller, einen dekrementierenden Iterationszähler zu verwenden. Testen auf Null kann schneller als ein Vergleich mit einer Konstanten oder Variablen sein. Viel Glück ausquetschen, dass letzte Byte und Mikrosekunde. Wie dieses im Gegensatz zu Orin 07 Aug 2009 Hi, I39m auf der Suche nach ein bisschen Hilfe, um einige Zeit zu retten neu erfinden das Rad. I39m Probenahme eine Anzahl von Sensoren, drei Beschleunigungsmesser, drei Magnetometer und zwei ADC-Kanäle. Die ADC - und Accelerometer-Kanäle geben mir unsigned int Daten und das Magnetometer gibt mir signierte Ints. Ich habe eine PIC18F4550 I39d wie diese in einer Tabelle zu speichern, und einen gleitenden Durchschnitt Filter auf sie. ZB: int aMagXArray8 // Arrays von jeweils 8 Werten // zuordnen. // Probieren Sie die Samples aus und setzen Sie sie in Variablen wie SensorMagX, SensorMagY usw. einMagXArraynPos SensorMagX aMagYArraynPos SensorMagY usw. nPos nPos nPos amp 0x07 // dh nPos von 0..7 halten und dann den gleitenden Durchschnitt z. B. nTot 0 für (i0ilt8i) nTot melden NTot aMagXArrayi nMagXAveragedValue nTot / 8 usw. Wiederholung für die anderen sieben Sensoren Ich wouldn39t die Summe jedes Mal neu berechnen. I39d folgendes tun: / Null nTotMagX und xMagArray bei Programminitialisierung / nTotMagX - aMagXArraynPos / entfernen älteste Wert von sum / aMagXArraynPos SensorMagX / Speichern neuer Wert / nTotMagX SensorMagX / add neuen Wert zu summieren / nPos (nPos 1) amp 7 nMagXAveragedValue nTotMagX / 8 Dies setzt voraus, dass Sie genügend Arbeitsspeicher für die zusätzlichen globalen Variablen nTotMagX (und nTotMagY) haben. Wenn Sie einen Zeiger anstelle von nPos zu Schritt durch das Array verwenden wollte: / Programme Initialisierung / int pOldestMagX ampaMagXArray0 nTotMagX - pOldestMagX / entfernen älteste Wert von sum / pOldestMagX SensorMagX / Speichern neuer Wert / nTotMagX SensorMagX / add neuen Wert zu summieren / if (POldestMagX ampaMagXArray8) pOldestMagX ampaMagXArray0 Ich weiß nicht, was besser wäre. You39d müssen nur sehen, was der Compiler in jedem Fall produziert. Wie dies im Gegensatz zu Pavel 08 Aug 2009 Was ist mit diesem Code Es generiert Code (fast) so klein wie Montage: Wie diese im Gegensatz zu ppulle 08 Aug 2009 Danke für die Antworten. Die Idee, eine laufende Spur der Gesamtsumme zu halten und sie zu entfernen, bevor sie den neuen Wert hinzufügen, ist groß. Speichert Code, um über das Array zu summieren, und spart Zeit. (Bekam viel RAM links, sehr eng auf ROM). Führt die Neueinführung und Summation auch in einem Schritt durch. Danke für den Eingang Pavel, das ist ein interessanter Ansatz. Aber ich frage mich, wie zukünftige Beweis es sein wird. Es geht davon aus, dass das FSR-Register nach dem Arrayzugriff beibehalten wird. Auch Sie don39t spezifizieren, welches indf Register zu verwenden, indf0, indf1 oder indf2 (für PIC18F4550). Kein Biggie, könnte nur einige zusätzliche Code explizit laden die FSR. zB unsigned int ptrSamplesEnd unsigned int aSamples8 unsigned int ptrSamplePos unsigned int nTotalSamples ptrSamplesEnd ampaSamples8 // Punkt auf einen Wert über dem Ende der Proben Array nTotalSamples - ptrSamplePos // Entfernen Sie die alte Probe ptrSamplePos nSample // fügen Sie die neue, wenn (ptrSamplePos ptrSampleEnd) ptrSamplePos aSamples oder in asm (man beachte ich haven39t diese geprüft. nur hier meinen Kopf Codierung aus, hoffe ich habe meine hoch / niedrig, um die Bytes rechts) void addsample (unsigned int nSample) movf ptrSamplePos1, W movwf fsr0h movf ptrSamplePos, W movwf fsr0l Set bis der FSR movf postinc0, W SUBWF nTotalSamples movf postdec0, W subwfb nTotalSamples1 tun int Subtraktion, subtrahieren erste Low-Byte, dann High-Byte mit borrow. Verwenden Sie postinc / postdev FSR zurück in die Array-Element Position zu bekommen wir movf nSample wollen, W movwf postinc0 movf nSample1, W movwf indf0 konnten wir den Vergleich zu tun unten auf fsr0h und fsr0l andere postinc verwenden. aber we39d es sowieso wieder auf ptrSamplePos zu laden, könnte genauso gut ptrSamplePos direkt infsnz ptrSamplePos erhöhen, F Schritt Low-Byte von ptrSamplePos incf ptrSamplePos1 und das High-Byte erhöhen, wenn das Low-Byte 0xff-gt0x00 movf ptrSamplePos1 ging, W jetzt sehen, ob we39ve spitz über das Ende des cpfseq finishadd ptrSamplesEnd1 BH nicht gleich so ptrSamplePos1ltgtptrSamplesEnd1 movf ptrSamplesPos, W, wenn hier we39re, waren hohe Bytes gleich. So überprüfen wir niedrige Bytes cpfseq ptrSamplesEnd BH finishadd no, also beenden wir movf aSamples1, W ptrSamplePos hoch und niedrig waren gleich ptrSamplesEnd (hoch und niedrig). So dass wir es zum Start des Arrays zurückgesetzt. Movwf ptrSamplesPos1 movf aSamples1, W movwf ptrSamplesPos // Jetzt nTotalSamples ist die Summe aller Ints im Array aSamples und wir können unseren Durchschnitt richtig durchführen. Frage hätten wir den movff Opcode an einigen Stellen über zB movff aSamples1, ptrSamplesPos1 movff aSamples verwendet, ptrSamplesPos noch vier Zyklen dauern würde, aber vielleicht klarer sein als das Hantieren mit dem W-Register. Wie dieses im Gegensatz zu Pavel 08 Aug 2009 Danke für die Eingabe Pavel, that39s ein interessanter Ansatz. Aber ich frage mich, wie zukünftige Beweis es sein wird. Es geht davon aus, dass das FSR-Register nach dem Arrayzugriff beibehalten wird. Auch Sie don39t spezifizieren, welches indf Register zu verwenden, indf0, indf1 oder indf2 (für PIC18F4550). Kein Biggie, könnte nur einige zusätzliche Code explizit laden die FSR. Compiler sollte erkennen, dass Zeigerregister (wie FSR) mit demselben Zeiger initialisiert und Code in der zweiten Anweisung optimieren. AltboostC bereits dies tut, aber aus einigen Gründen tut es doesn39t es für diesen besonderen Fall. Wird untersuchen und zu beheben. Also die Antwort auf Ihre Frage ist, dass in Zukunft BoostC Releases gibt es keine Notwendigkeit zu ersetzen 39samplescount val39 mit Assembly. Compiler generiert optimierten Code. Wie dieses im Gegensatz zu ppulle 10 Aug 2009 Danke für das Betrachten dieser Pavel, I39ve bekam genug, um mit zu gehen. Jetzt habe ich zu incoorporate dies in einer einzigen Routine, die einen Satz von acht Proben nehmen wird, so dass ein acht klopfen endlichen Impulsantwort-Filter mit zwei Byte Präzision. Wie dies im Gegensatz zu ppulle 11 Aug 2009 I39ve bekam einen netten kleinen Asm-Code Hinzufügen von Sensoren, Durchführen Array Summen usw. und tun alles bis zur Teilung von 8, um den Durchschnitt zu nehmen. Anstatt es für mich selbst herauszufinden, dachte ich, I39d nur wieder verwenden Sie den Code, den sourceboost generiert, um eine Divide von 8 auf einem signierten int zu tun. Die Ergebnisse waren jedoch nicht wie erwartet. ZB kompilieren und diesen Schritt im Debugger durchführen Bin ich hier etwas fehlt. Es sieht aus wie die Optimierung zu tun, ein Divisor, die ein Vielfaches von 2 isn39t Handhabung signierten Ints sehr gut. Ich würde für k-1 annehmen. -7 - gt k / 80. K-8. -15 - gt k / 8-1, k-16. -24 - gtk / 8-2 etc Wer weiß, asm Code-Sequenz, die eine signierte int division von acht richtig tun wird Es funktioniert für kgt0. Ich don39t wollen zusätzliche Code hinzufügen, um das Schild zu überprüfen und künstlich ein, um die Teilung zu korrigieren. Wie dies im Gegensatz zu Reynard 11 Aug 2009 Dividing unterzeichneten ints durch Befugnisse von 2 erfordert besondere Behandlung und Fudge-Faktoren wegen Rundung Probleme. Ich schlage vor, die Umwandlung der negativen int auf einen positiven Wert dann dividiert durch 8 dann wieder negativ. BoostC ist nicht der einzige Compiler, der diese eine falsche für signierte Variablen bekommt. Wie dies im Gegensatz zu ppulle 12 Aug 2009 Danke für die Köpfe auf, wie Compiler mit signierten Ints befassen. Es ist sicher eine Falle für das Ungewisse zu sein. Ich hoffte there39d ein generischer Bitfiddling-Algorithmus that39d Griff, dass Art der Sache. Jedenfalls habe ich alle genommenen Ratschläge, die Subtraktion der alten Geschichte Wert, bevor Sie die neue, um schnell berechnen die Summen sowie die Umwandlung von negativen Ints positiv (und wieder zurück), bevor Sie die Teilung. Vielen Dank an alle who39ve geholfen. Unten ist mein Beitrag zur Sourceboost Welt. Ein 12-Bit-Präzision, unterzeichnet, acht Kanal, acht Klopfen finite Impulsantwort-Filter. Aka gleitenden Durchschnitt auf acht Eingänge. Alle Kommentare zu mehr Bytes aus dem Code-Stripping würde geschätzt, I39m sicher, es gibt effizientere Möglichkeiten, einige Dinge zu tun, wie die Umwandlung der negativen zur positiven Zahlen, Dividieren und das Hinzufügen von 16bit Ints usw. Auf jeden Fall ist es zu 164 Bytes kompiliert, das ist in Ordnung Für meine Anwendung, und viel weniger als ich dachte, es wäre. Wie dieses im Gegensatz zu Reynard 12 Aug 2009 Gut zu sehen, dass Sie eine Lösung gefunden haben. Ich mache eine ähnliche Sache mit einem X / Y-Beschleunigungsmesser auf seiner Seite als Inklinometer für meine Feld Bogenschießen. Ich benutze die Stack-Methode, die ich bereits erwähnt habe. Zeit und Code Raum ist kein Problem für mich. Ich benutze eine Nachschlagtabelle, um den durchschnittlichen X-Kanal in Grad umzuwandeln und dann auf eine kleine 2-stellige LED-Anzeige zu stellen. Es ist alles in eine lange Kunststoff-Box (120x30x30mm) mit einem Loch an jedem Ende zu schauen durch und wählen Sie mein Ziel. Die Anzeige ist innerhalb des Kastens unter dem vorderen Loch, also kann ich eine sofortige Lektüre erhalten, während noch das Ziel betrachtend. Ich bekomme / -63 Grad, die alle Kurse, die ich schießen deckt. Es kann eine Idee sein, wenn der Compiler / Präprozessor die Datentypen, mit denen es zu tun hat, betrachtet und eine real signierte Divisionsroutine aufruft, anstatt sie in Verschiebungen für Divisoren von Kräften von 2 zu optimieren. Wie diese Im Gegensatz zu russhensel 13 Aug 2009 Hallo, Auf der Suche nach ein bisschen Hilfe, um einige Zeit neu erfinden das Rad sparen. I39m Probenahme eine Anzahl von Sensoren, drei Beschleunigungsmesser, drei Magnetometer und zwei ADC-Kanäle. Die ADC - und Accelerometer-Kanäle geben mir unsigned int Daten und das Magnetometer gibt mir signierte Ints. Ich habe eine PIC18F4550 I39d wie diese in einer Tabelle zu speichern, und einen gleitenden Durchschnitt Filter auf sie. ZB: int aMagXArray8 // Arrays von jeweils 8 Werten // zuordnen. // Probieren Sie die Samples aus und setzen Sie sie in Variablen wie SensorMagX, SensorMagY usw. einMagXArraynPos SensorMagX aMagYArraynPos SensorMagY usw. nPos nPos nPos amp 0x07 // dh nPos von 0..7 halten und dann den gleitenden Durchschnitt z. B. nTot 0 für (i0ilt8i) nTot melden NTot aMagXArrayi nMagXAveragedValue nTot / 8 usw. Wiederholen Sie für die anderen sieben Sensoren einen ziemlich normalen gleitenden Durchschnitt Alogorithmus, speichern Sie die Proben in einer Tabelle mit einem rotierenden Zeiger und durchschnittlich die Tabelle, wenn Sie einen Wert möchten Leider ist alle diese Array-Referenzierung nimmt ein großes Stück Code-Raum, die ich don39t haben, weil alle anderen Code in meinem PIC. Verwendung von Zeigern isn39t viel Hilfe entweder. So I39d wie neu zu schreiben diese in Montage. Es ist schon eine Weile her, seit ich mit indirekter Adressierung gespielt habe, daher dieser Beitrag. Gibt es einen 18F4550-Assembler-Algorithmus, der ganze Zahlen (unsigned oder signed) summiert, die in einem Array sitzen Die Summe kann dann geteilt werden, um den gleitenden Durchschnitt zu geben. Vermutlich müssen I39d die Arrays auf einer einzigen Seite zuordnen, um die Dinge zu vereinfachen. Stellt der Sourceboost-Compiler automatisch sicher, dass Arrays in einer Seite zugewiesen werden Danke für jede Hilfe. Phil Ich habe eine andere Methode und frage mich, was alle denken. Nehmen Sie den alten Durchschnitt und multipliziert mit 7. Fügen Sie den neuen Wert hinzu und teilen Sie durch 8. Dies ist Ihr neuer Durchschnitt. Alle Lesen jemals genommen, um den neuen Durchschnitt beitragen, hat die letzte ein Gewicht von 1/8 oder 0,13, die achte ein Gewicht von 0,04 der 16. zurück ein Gewicht von 0,01 .01. Für die Mittelung über eine engere Periode multiplizieren mit 3 und dividieren durch 4. Sie können herausfinden, andere Werte. Verwenden Sie eine Leistung von 2 für die Division, so wird es mit (hoffentlich) eine Schicht durchgeführt werden. Um mit 7 zu multiplizieren, können Sie kombinieren Verschiebungen und fügt (Blick auf die kompilierte Ausgabe zu sehen, wie effizient), wenn es schneller als das, was der Compiler kommt mit. Jetzt haben Sie keine Array oder Zeiger zu bewältigen. Was denken Sie, Sollten wir Modell mit einem Tafelblatt und im Vergleich zu anderen Methoden. Ich habe eine andere Methode und frage mich, was alle von euch denken. Nehmen Sie den alten Durchschnitt und multipliziert mit 7. Fügen Sie den neuen Wert hinzu und teilen Sie durch 8. Dies ist Ihr neuer Durchschnitt. Alle Lesen jemals genommen, um den neuen Durchschnitt beitragen, hat die letzte ein Gewicht von 1/8 oder 0,13, die achte ein Gewicht von 0,04 der 16. zurück ein Gewicht von 0,01 .01. Für die Mittelung über eine engere Periode multiplizieren mit 3 und dividieren durch 4. Sie können herausfinden, andere Werte. Verwenden Sie eine Leistung von 2 für die Division, so wird es mit (hoffentlich) eine Schicht durchgeführt werden. Um mit 7 zu multiplizieren, können Sie kombinieren Verschiebungen und fügt (Blick auf die kompilierte Ausgabe zu sehen, wie effizient), wenn es schneller als das, was der Compiler kommt mit. Jetzt haben Sie keine Array oder Zeiger zu bewältigen. Was denken Sie, Sollten wir Modell mit einem Tafelblatt und im Vergleich zu anderen Methoden. Russ das ist eine interessante Idee. Mein erster Gedanke (ohne jede Prüfung) ist, dass Sie den Rundungsfehler mit jedem neuen laufenden Durchschnitt akkumulieren. 8 mal der alte Durchschnitt wird Ihnen nicht die Summe der 8 Proben, die verwendet wurden, um den alten Durchschnitt zu berechnen. Folglich haben 7 mal won39t Ihnen die alte Summe weniger eine durchschnittliche Probe, entweder. Darüber hinaus, wie Sie darauf hingewiesen haben, ist es nicht der gleiche laufende Durchschnitt auch ohne die akkumulierten Rundungsverlust. Eine Probe 16 Zyklen zurück (oder 9 oder 50) wird noch einige Gewicht mit diesem Modell. Unabhängig von seiner Geschwindigkeit und Speicher Anforderungen, es hängt wirklich von der Anwendung, ob diese Methode besser oder schlechter ist (auch wenn Sie den Rundungsverlust zu ignorieren). That39s meine .02 ohne wirklich darüber nachzudenken, zu viel. Gefällt mir Im Gegensatz zu russhensel 14 Aug 2009 Ich habe eine andere Methode und frage mich, was alle denken. Nehmen Sie den alten Durchschnitt und multipliziert mit 7. Fügen Sie den neuen Wert hinzu und teilen Sie durch 8. Dies ist Ihr neuer Durchschnitt. Alle Lesen jemals genommen, um den neuen Durchschnitt beitragen, hat die letzte ein Gewicht von 1/8 oder 0,13, die achte ein Gewicht von 0,04 der 16. zurück ein Gewicht von 0,01 .01. Für die Mittelung über eine engere Periode multiplizieren mit 3 und dividieren durch 4. Sie können herausfinden, andere Werte. Verwenden Sie eine Leistung von 2 für die Division, so wird es mit (hoffentlich) eine Schicht durchgeführt werden. Um mit 7 zu multiplizieren, können Sie kombinieren Verschiebungen und fügt (Blick auf die kompilierte Ausgabe zu sehen, wie effizient), wenn es schneller als das, was der Compiler kommt mit. Jetzt haben Sie keine Array oder Zeiger zu bewältigen. Was denken Sie, Sollten wir Modell mit einem Tafelblatt und im Vergleich zu anderen Methoden. Russ das ist eine interessante Idee. Mein erster Gedanke (ohne jede Prüfung) ist, dass Sie den Rundungsfehler mit jedem neuen laufenden Durchschnitt akkumulieren. 8 mal der alte Durchschnitt wird Ihnen nicht die Summe der 8 Proben, die verwendet wurden, um den alten Durchschnitt zu berechnen. Folglich haben 7 mal won39t Ihnen die alte Summe weniger eine durchschnittliche Probe, entweder. Darüber hinaus, wie Sie darauf hingewiesen haben, ist es nicht der gleiche laufende Durchschnitt auch ohne die akkumulierten Rundungsverlust. Eine Probe 16 Zyklen zurück (oder 9 oder 50) wird noch einige Gewicht mit diesem Modell. Unabhängig von seiner Geschwindigkeit und Speicher Anforderungen, es hängt wirklich von der Anwendung, ob diese Methode besser oder schlechter ist (auch wenn Sie den Rundungsverlust zu ignorieren). That39s meine .02 ohne wirklich darüber nachzudenken, zu viel. Ich dachte nicht über das Rudern, aber ich sollte darauf hingewiesen haben, dass zumindest die Mathematik in genug Genauigkeit durchgeführt werden sollte, so dass es keine Überlaufprobleme. Vielleicht könnte einige der Mathematik auf einen Faktor von 2 bis zu einem gewissen Maß an Präzision um zu halten. Das ist natürlich, wenn wir denken, dass die Methode wert ist, zu verbessern. Wie dies im Gegensatz zu ppulle 15 Aug 2009 Ich lasse es an andere zu überprüfen, die Methode, die russ hat kommen mit (I39ve bekam meine Lösung und zog auf andere Sachen). Es sieht aber interessant aus. Ich denke nicht, dass Rundung (in Bezug auf die Multiplikation) ein Problem sein wird, wenn die Zahlen auf die Genauigkeit des Akkumulators beschränkt sind (dh für 16bit unterschrieben die zusätzlichen Samples auf 4096, dh 16-Bit-Bit-Divisor-Bits). Aber die Teilung gibt mir ein bisschen Sorgen, da es fast immer einen Rest geben wird. Dass39s wahrscheinlich der Hauptbereich, wo Verlust der Genauigkeit auftreten wird. Beachten Sie, dass wir39re tun einen durchschnittlichen und effektiv wegwerfen Bits, um Dinge zu glätten sowieso. So vielleicht sein ein Fall von Versuch es und sehen. Mein Hauptanliegen ist, dass eine Teilung durch sieben Operationen (oder durch eine weniger als die Multiplikation für andere Selektionen) durch sie die Natur niemals ein sauberer Schaltvorgang sein wird, daher benötigen Sie eine progressive Subtraktionsroutine (dh Teilung), die dem Code hinzugefügt wird. Wodurch die Codelänge und die Verarbeitungszeit erhöht werden. Alternativ, wenn Sie die Division ein Vielfaches von 2 (z. B. 8) behalten, benötigen Sie eine progressive Addition (dh Multiplikation), um die 1 zu tun. So oder so ist es nicht einmal multiplizieren oder teilen. Wenn der 8x8bit-Multiplikations-Opcode auf dem 18F4450 verwendet wird, kann es sein, dass du mit dem Opcode um 9 multiplizierst und durch Schichten verschiebst und keine separate Routine aufrufst. In diesem Fall haben Sie39d einen 9-Tap-Filter. Das geht natürlich nur mit 8 bit Zahlen. Wie dies im Gegensatz zu russhensel 17 Aug 2009 Ich lasse es an andere zu überprüfen, die Methode, die russ hat kommen mit (I39ve bekam meine Lösung und zog auf andere Sachen). Es sieht aber interessant aus. Ich denke nicht, dass Rundung (in Bezug auf die Multiplikation) ein Problem sein wird, wenn die Zahlen auf die Genauigkeit des Akkumulators beschränkt sind (dh für 16bit unterschrieben die zusätzlichen Samples auf 4096, dh 16-Bit-Bit-Divisor-Bits). Aber die Teilung gibt mir ein bisschen Sorgen, da es fast immer einen Rest geben wird. Dass39s wahrscheinlich der Hauptbereich, wo Verlust der Genauigkeit auftreten wird. Beachten Sie, dass wir39re tun einen durchschnittlichen und effektiv wegwerfen Bits, um Dinge zu glätten sowieso. So vielleicht sein ein Fall von Versuch es und sehen. Mein Hauptanliegen ist, dass eine Teilung durch sieben Operationen (oder durch eine weniger als die Multiplikation für andere Selektionen) durch sie die Natur niemals ein sauberer Schaltvorgang sein wird, daher benötigen Sie eine progressive Subtraktionsroutine (dh Teilung), die dem Code hinzugefügt wird. Wodurch die Codelänge und die Verarbeitungszeit erhöht werden. Alternativ, wenn Sie die Division ein Vielfaches von 2 (z. B. 8) behalten, benötigen Sie eine progressive Addition (dh Multiplikation), um die 1 zu tun. So oder so ist es nicht einmal multiplizieren oder teilen. Wenn der 8x8bit-Multiplikations-Opcode auf dem 18F4450 verwendet wird, kann es sein, dass du mit dem Opcode um 9 multiplizierst und durch Schichten verschiebst und keine separate Routine aufrufst. In diesem Fall haben Sie39d einen 9-Tap-Filter. Das geht natürlich nur mit 8 bit Zahlen. Ich habe einige Tests mit einer Tabelle durchgeführt. Round-off-Fehler ist in der Tat ein Problem. Das Skalieren der Werte um ein paar Potenzen von 2 kann dieses Problem lösen. Die meisten der Mathematik ist 16 Bit und ich möchte, dass es gut für 10 Bit a bis d. Mehr Infos wenn ich noch mehr hinschaue. Die Division ist um 8 nicht 7 so die Verschiebung ist gut, aber für den Verlust von Bits aus dem rechten Ende. Wie dies im Gegensatz zu Orin 17 Aug 2009 Ich lasse es an andere zu überprüfen, die Methode, die russ hat kommen mit (I39ve bekam meine Lösung und zog auf andere Sachen). Es sieht aber interessant aus. Ich denke nicht, dass Rundung (in Bezug auf die Multiplikation) ein Problem sein wird, wenn die Zahlen auf die Genauigkeit des Akkumulators beschränkt sind (dh für 16bit unterschrieben die zusätzlichen Samples auf 4096, dh 16-Bit-Bit-Divisor-Bits). Aber die Teilung gibt mir ein bisschen Sorgen, da es fast immer einen Rest geben wird. Dass39s wahrscheinlich der Hauptbereich, wo Verlust der Genauigkeit auftreten wird. Beachten Sie, dass wir39re tun einen durchschnittlichen und effektiv wegwerfen Bits, um Dinge zu glätten sowieso. So vielleicht sein ein Fall von Versuch es und sehen. Mein Hauptanliegen ist, dass eine Teilung durch sieben Operationen (oder durch eine weniger als die Multiplikation für andere Selektionen) durch sie die Natur niemals ein sauberer Schaltvorgang sein wird, daher benötigen Sie eine progressive Subtraktionsroutine (dh Teilung), die dem Code hinzugefügt wird. Wodurch die Codelänge und die Verarbeitungszeit erhöht werden. Alternativ, wenn Sie die Division ein Vielfaches von 2 (z. B. 8) behalten, benötigen Sie eine progressive Addition (dh Multiplikation), um die 1 zu tun. So oder so ist es nicht einmal multiplizieren oder teilen. Wenn der 8x8bit-Multiplikations-Opcode auf dem 18F4450 verwendet wird, kann es sein, dass du mit dem Opcode um 9 multiplizierst und durch Schichten verschiebst und keine separate Routine aufrufst. In diesem Fall haben Sie39d einen 9-Tap-Filter. Das geht natürlich nur mit 8 bit Zahlen. Ich habe einige Tests mit einer Tabelle durchgeführt. Round-off-Fehler ist in der Tat ein Problem. Das Skalieren der Werte um ein paar Potenzen von 2 kann dieses Problem lösen. Die meisten der Mathematik ist 16 Bit und ich möchte, dass es gut für 10 Bit a bis d. Mehr Infos wenn ich noch mehr hinschaue. Die Division ist um 8 nicht 7 so die Verschiebung ist gut, aber für den Verlust von Bits aus dem rechten Ende. Ich fast vorgeschlagen, diese Methode in meiner ursprünglichen Antwort. Es ist ein Filter des Formulars: Filterwert (neuer Wert p) ((1-p) gefilterter Wert) wobei 0 lt p lt 1. Der vorgeschlagene Filter hat p 1/8. Er schätzt die rechte Seite um 8, um zu erhalten: gefilterter Wert 8 Neuer Wert (7 gefilterter Wert) Wie bei Rundungsfehlern, aren39t sprechen wir über einen Trunkierungsfehler, wenn die Division durch eine einfache Verschiebung I39d erfolgt Anstatt das Ergebnis zu kürzen. Beachten Sie, dass 7 gefilterter Wert besser als ((gefilterter Wert ltlt 3) - gefilterter Wert) berechnet werden kann. Es könnte weniger Code als ((gefilterter Wert ltlt2) (gefilterter Wert ltlt1) gefilterter Wert) für eine Multiplikation mit 7 erzeugen. Ja, dieses Filter hat noch einen signifikanten Beitrag von der 8. vorherigen Probe, als würde p 1/4 platzieren. I39d versucht sein, p 1/2 zu verwenden, wodurch der Filter: Filterwert (gefilterter Wert Neuer Wert 1) / 2, der viel einfacher zu berechnen ist.

Comments