Forum: Digitale Signalverarbeitung / DSP / Machine Learning MOVING AVERAGE FILTER in FastAVR?


von Axel Rühl (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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ß

von Chris (Gast)


Lesenswert?

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.

von Axel Rühl (Gast)


Lesenswert?

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

von Axel Rühl (Gast)


Lesenswert?

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

von Hagen (Gast)


Lesenswert?

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

von Horst Piening (Gast)


Lesenswert?

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.

von Hagen (Gast)


Lesenswert?

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

von Michael (Gast)


Lesenswert?

Schon etwas älter, könnte aber noch funktionieren :-)
http://www.mikrocontroller.net/forum/read-1-8170.html#8727

von Norbert (Gast)


Lesenswert?

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

von Axel Rühl (Gast)


Lesenswert?

@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

von Norbert (Gast)


Lesenswert?

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

von Hagen (Gast)


Lesenswert?

@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

von Inge (Gast)


Lesenswert?

Kann mir jemand erklären was moving average eigentlich ist???

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

"Gleitender Mittelwert", Mittelwert der letzten x Messungen.

von Alex (Gast)


Lesenswert?

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.

von Mario Konegger (Gast)


Lesenswert?

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.

von Martin (Gast)


Lesenswert?

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

von Zombie (Gast)


Lesenswert?

Grabschänder ;)

von Hagen R. (hagen)


Lesenswert?

>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
Noch kein Account? Hier anmelden.