www.mikrocontroller.net

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


Autor: Axel Rühl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Axel Rühl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Axel Rühl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Horst Piening (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael (Gast)
Datum:

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

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Axel Rühl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Inge (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand erklären was moving average eigentlich ist???

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Gleitender Mittelwert", Mittelwert der letzten x Messungen.

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mario Konegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Zombie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grabschänder ;)

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.