ich habe einige Sampels (Fahrregler) und will einen gleitenden mittelwert bilden, jetzt mache ich 4 Messungen, nach der 4ten addiere ich alles zusammen, teile ich durch 4 und gebe den Mittelwert aus. Soweit so grün, Ich möchte aber den gleitenden Mittelwert der letzten vergangenen Werte ausgeben, und nicht immer eine Pause von vier Messungen haben, bevor ich die Daten ausgegeben habe. Bin ich aber zu blöd zu, muss irgentwie mit einem Ringpuffer gemacht werden, oder? Do If running < 4 Then temp=temp+messwert Incr running Else mittelwert= temp / 4 temp = 0 running = 0 Mittelwert_ausgeben() End If Loop Danke, Leute Axel Rühl Potsdam
Hallo, zum Moving average-Filter gibt es doch in den Atmel Application notes ein Beispiel mit Code in diesen Zip-Datein. Müßte nur die Nummer der App-note nachschauen. Gruß
AVR222: 8-Point Moving Average Filter (5 pages, updated 5/02) This Application Note gives an demonstration of how the addressing modes in the AVR architecture can be utlized.
ja, danke Appnote 222, ich weiß. Ich werde den Flowchart in mein FastAVR-Basic übersetzen, beim Hardware TWI habe ich es ja auch geschafft... Danke, ich dachte, jemand hätte was in Hochsprache, was er mir überließe. Gruß Axel
bin nochmal über mein posting geflogen... mir gehts einfach nur drum, das Prinzip zu verstehen! ich habe alle 20mSec einen Messwert. den speicher ich zwischen und warte auf den nächsten. wenn -sagen wir- drei eingetroffen sind, nimm ich die, bilde den Mittelwert und schreibe diesen an die mittelste Stelle des zurück ins Array. jetzt verschiebe ich elemente des Arrays um einen nach links, das "rechte" Array-element wird mit dem neuen Wert beschrieben. ganz "links" steht mein mittelwert, welcher nun in die Berechnung mit den vorletzten und dem aktuellen Wert eingeht.So eine Erklärung hatte ich mir erhofft, habe ich aber nicht gesagt. Selbst Schulz. Danke trotzdem Gruß Axel
Du definierst ein Array mit zB. 4 Werten. Dann benötigst du eine Index Variable. Am Anfang wird das Array mit Nullen gefüllt und die Indexvariable auf 0 gesetzt. Der nächste Input wird nun ins Array gespeichert an Position 0 = Index. Danach wird der Index um +1 erhöht und falls er 4 ist auf 0 zurückgesetzt. Fertig ist der Ringpuffer für die letzten 4 Samples. Nun brauchst du nur eine Funktion die die 4 Werte im Array addiert und durch 4 teilt, schon haste dein AVG über die 4 letzten Samples. Gruß Hagen
Hallo Axel, probier mal folgendes: #include <stdio.h> main() { int ar[4], *p=ar, i, mid; *(ar+0)= *(ar+1)= *(ar+2)= *(ar+3)= 0; for( i=0; i<100; i++ ) { *p= i; if( p == ar+3 ) p= ar; else p++; mid= ( *(ar+0)+ *(ar+1)+ *(ar+2)+ *(ar+3) ) / 4; printf(" %4d %5d %4d %4d \t %4d %4d \n", *(ar+0), *(ar+1), *(ar+2), *(ar+3), i, mid); } } das waere dann ein gleitender Durchschitt ueber die jeweils letzten 4 Werte. gruss horst.
int samples[4] = {0,0,0,0}; int index=0; while (1) { samples[index++] = input; index %= 4; int average = 0; for (int i = 0; i < 4; i++) { average += samples[i]; } average /= 4; } wäre mein Vorschlag der in fakt identisch zu Horst seinem arbeitet. Gruß Hagen
Schon etwas älter, könnte aber noch funktionieren :-) http://www.mikrocontroller.net/forum/read-1-8170.html#8727
Hi, In Bascom: Dim index as byte dim value(4) as byte dim average as word dim count as byte index = 1 'arrays in bascom beginnen mit 1 :-( do value(index) =getadc(x) 'messen incr index if index = 5 then index = 1 for count = 1 to 4 average = average + value(count) next shift average, right, 2 'geht schneller als /4 loop Fastavr wird ja nicht sooo viel anders sein. Anstatt do-loop kannst Du das was dazwischen steht natürlich auch als sub aufrufen oder wie auch immer. Gruß, Norbert
@Norbert ja, sowas hab' ich ja jetzt auch schon, nur dass ich erst nach rechts schiebe, wenn das array voll ist mit vier neuen werten. jetzt werde ich das so machen, das ich immer aufaddiere und ausgebe. Ich werde dann den errechneten Mittelwert, wie oben super erklärt, mit ins array zurückschreiben, um diesen in die Messung einfließen zu lassen. ich habe mir auch die AVR222 im Simlator angesehen, war mir dann aber doch ein ziemlich wildes hinundhergespringe, wobei die indizierte Adressierung schon eine witzige Sache ist. @Horst ist das nicht der arithmetische Mittelwert? ich dachte beim gleitenden wird der aktuelle Mittelwert bei der berechnung der neuen Daten mit einbezogen.. Hmmm Gruß Axel
Hi, Dann mach es doch so wie mein Beispiel (nur ohne den Fehler average bis ins unendliche hochzuaddieren ;-)), nur daß der letzte Mittelwert den ältesten Wert des arrays ersetzt: do incr index value(index) = getadc(x) 'messen value(index-1) = average if index = 5 then index = 1 average = 0 for count = 1 to 4 average = average + value(count) next shift average, right, 2 'geht schneller als /4 loop Noch ne Idee zum glätten, ev. etwas träge: -Wert messen als Anfang Dann immer: -neuen Wert messen Wert = (3*Wert + neuer Wert)/4 Gruß, Norbert
@Axel, jetzt bin ich aber verwirrt. Das Arithmetische Mittel ist der Mittelwert über alle Daten, der gleitende Mittelwert der Mittelwert über einen Ausschnitt der Daten. In unserem Beispiel hier eben der Auschnitt über die letzten 4 Datenwerten. Würde man beim gleitenden Mittelwert den letzten berechneten Mittelwert mit einbeziehen so bekäme man einen angepassten arithmetischen Mittelwert über alle Daten. Dies hätte zur Folge das der aktuell berechnete Mittelwert, je länger man sampelt, immer stärker an das arith. Mittel angenährt wird. Sehe ich das jetzt falsch herum ? @Norbert: die meisten Hochsprachen optimieren Divisionen oder Multiplikationen von Ganzzahlen mit einer 2'er Potenz-Zahl immer als Links/Rechtsshift. Also auch wenn man X / 4, oder X mod 4, oder X * 4 schreibt so sollte der Compiler smart genug sein diese in X >> 2, X and 3, X << 2 zu übersetzen, WENN die Hardware keine schnellen Divisionen, Multiplikationen unterstützt. Gruß Hagen
Wie ein Rechteckfenster welches über die Messwerte gezogen wird. Die Wichtung jedes Wertes ist 1/N wenn N die Anzahl der Werte ist. Als Tiefpass o.ä. absolut ungeeignet, es versaut dir nur das Spektrum.
Hallo zusammen, nur falls es noch einen interessiert. Soweit ich die bisherigen Varianten hier überblickt habe, wird immer die Summe für den Mittelwert ausgewertet. Das macht diese Methoden aber langsamer mit steigernder Fensterlänge. Nachdem der Mittelwert linear ist, kann ich die Summe auch einfach zerlegen und spare mir so jedesmal die Summe auszuwerten. Also: #define WindowSize 4 int samples[WindowSize] = {0,0,0,0}; int index = 0; int average = 0; while (1) { /* Alten Wert abziehen. */ average -= samples[index]; /* Neuen Wert zufügen. */ samples[index] = input / WindowSize; /* Neuen Mittelwert bilden. */ average += samples[index] /* Im Ringbuffer weiterstellen */ index++; index %= WindowSize; } Der Code ist keinesfalls "optimal", sondern sollte nur die Funktionsweise demonstrieren. Desweiteren muss man bei diesem Verfahren die Rundungsfehler beachten, d.h. bei Benutzung von Integer-Arithmetik ist der gewonnene Mittelwert etwas ungenauer.
Hallo zusammen, mal ein ganz anderer Ansatz: Warum erhöhst Du nicht einfach die Sampling-Zeit am AD-Wandler. Somit hast Du ein Hardware-Moving-Average-Filter! Nimm einfach ne viermal so hohe Samplingrate, ist das gleiche, wie wenn Dein AD-Wandler vier Werte aufnimmt und Du Sie dann wieder mittelst (Okay...gesame Sampling- und Convert- Zeit betrachten!))! Die vier Einzelwerte interessieren Dich ja eh nicht und die Werte die der AD-Wandler liefert werden auch besser (Im Datenblatt des AD-Wandlers dürfte auch ne Formel für die Mindest-Sample-Zeit angegeben sein). Nur so ein Gedanke. Gruß Martin
>mal ein ganz anderer Ansatz: Warum erhöhst Du nicht einfach die >Sampling-Zeit am AD-Wandler. Somit hast Du ein >Hardware-Moving-Average-Filter! Nöö so hat man im besten Falle eine Unterabtastung. Wenn man vor dem ADC Eingang noch einen RC-Tiefpass mit passender Grenzfrequenz setzt dann wird ein Schuh draus. Ohne diesen schlägt die Sample&Holdstufe des ADCs zu, wir reden ja vom AVR, und die benötigt nur 1.5 ADC Takte um das Eingangssignal zu sampeln. Gruß Hagen
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.