mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik gleitender Mittelwert im Atmel


Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen.

Ich möchte gern einen gleitenden Mittelwert programmieren.
Ich haben einen festen Messzyklus meines AVR's. In jeder Runde soll nun 
der Messwert aufaddiert werden und nach z.B. 100 Messzyklen unter 100 
geteilt werden und dann der Mittelwert ausgegeben werden (an PC).

Wenn ich mit dem normalen Mittelwert arbeite, muss ich genau 
100*Messzykluszeit warten bis das Ergebis da ist. Solang kann ich aber 
nicht warten.

Ich würde lieber eine "Anschwingphase" in kaufen nehmen, wie es bei 
einem gleitenden Mittelwert der Fall ist. Dafür würde ich aber nach den 
ersten 100 Messzyklen nach jedem Messzyklus einen gemittelten Wert 
übergeben bekommen.

Kann mit jemand erklären, wie ich den gleitenden Mittelwert verstehen 
muss?
Habe ich einen Puffer für 100 Werte und fülle diesen mit einem Messwert 
pro Messzyklus und teile jedesmal durch 100?

Danke euch

Autor: karadur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Du kannst z.B. den Mittelwert gleich dem ersten Messwert nehmen. Sei n 
die Anzahl der Messungen.
Der nächste Mittelwert ist dann ((n-1)* alter Mittelwert + Messwert)/n
 Wenn du n von 2 bis 100 laufen lässt erhälst du vom ersten Messwert an 
Mittelwerte.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kanst das derart machen, das du eine Puffer hast der Größe 100

P[100];

Nach jeder messung schmeißt du den ältesten Wert raus fügst deinen neuen 
Wert ein.

Im Übrigen nimm lieber 128 Werte dann kannst du einfach durch schiften 
nach rechts teilen das geht sehr viel fixer.

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ karadur

Und wenn ich n erreicht habe? Gilt die Formel dann immer noch?

Autor: karadur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan KM.

Die Formel gilt dann immer noch.

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wenn ich n erreicht habe, darf n einfach nur nicht mehr inkremtieren 
!? Stimmt das?

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also wenn die mittelwertbildung schnell gehen soll, dann nehme ich zb 
bei 8bit werten 256 messwerte (können aber auch 128, 64, 32 etc sein). 
den mittelwert ermittle ich in einem 16-bit wert. dazu müsste man also 
256 messwerte aufsummieren und dann durch 256 teilen. das bedeutet, das 
divisionsergebnis steht um höherwertigen byte des 16-bit registers schon 
fertig da, wenn ich die messwerte aufsummiere.
der ablauf sieht nun so aus:
1. der 16bit wert wird aus 0 gesetzt (initialisierung)
2. wenn ein messwert eintrifft, wird vom 16-bit register der wert des 
höherwertigen bytes vom 16bit wert (also der aktuelle mittelwert) 
subtrahiert, sodass der 16bit wert auf den 255/256-teil absinkt und dann 
addiere ich den messwert zum 16bit wert hinzu. damit bildet sich der 
neue wert zu:
16-bit(neu)=255/256*16-bit(alt)+1/256*messwert.
im höherwertigen byte des 16-bit wertes steht damit immer der aktuelle 
mittelwert, eine zwischenspeicherung von messwerten ist nicht nötig.
wie gesagt, mit 128, 64, 32 ..messwerten funktioniert das ähnlich, sind 
evtl ein paar verschiebeoperationen nötig.

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Formel von karadur mittelt dir nicht einfach die letzten n Werte, es 
ist eher so eine Art Tiefpass, dessen Stärke durch n festgelegt wird. 
Dein Mittelwert wird von allen vorangegangenen Werten bestimmt, aber die 
aus der näheren Vergangenheit haben mehr Gewicht.

Wichtung:

letzter Punkt       1/n
vorletzter Punkt    (n-1)/n^2
vorvorletzter       (n-1)^2/n^3
usw.

Nachteil: Es ist nicht der geforderte Mittelwert.
Vorteil: Du musst nicht ein ganzes Array speichern, sondern immer nur 
den letzten Mittelwert.

Autor: karadur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan KM

richtig.

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@karadur

Es funktioniert leider nicht.

Hier mein C-Code:

average_mB = x;               // neuer Messwert
    if (n<100)
      {
       new_Average = ((n-1)*old_Average)+average_mB/n;
       old_Average = new_Average;
       n++;
      }
    else
      {
       new_Average = ((n-1)*old_Average)+average_mB/n;
       old_Average = new_Average;
      }


Was habe ich vergessen? Oder nicht beachtet?

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sieht eigentlich gut aus, ist n am Anfang auch auf 1 gesetzt?

Ach ja, die letzte Klammer zu muss direkt vor dem /n kommen!

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe n auf 2 gesetzt. Die Werte springen total auf und ab. Sieht 
irgendwie so aus, als ob etwas überläuft.

Aber ich alle verwendeten Variablen als unsignes long definiert.

Meine Messwerte liegen im Bereich von 0-4000.

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, hast du die Klammern korrigiert? Also

new_Average = ((n-1)*old_Average+average_mB)/n;

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du am Anfang n=2 setzt, wie initialisierst du deinen Mittelwert? 
Bei n=1 würde die Startbelegung rausfallen, so aber ist sie wichtig.

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habs jetzt. Es funktioniert.

Danke dir.

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Freut mich zu lesen :)

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu früh gefreut.....

Wenn die 100 erreicht sind, fangen die Werte erneut an zu springen. Muss 
ich die Werte irgendwie zwischenpuffern?

Autor: Thomas B. (yahp) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Schlaefendorf wrote:

> 2. wenn ein messwert eintrifft, wird vom 16-bit register der wert des
> höherwertigen bytes vom 16bit wert (also der aktuelle mittelwert)
> subtrahiert, sodass der 16bit wert auf den 255/256-teil absinkt und dann
> addiere ich den messwert zum 16bit wert hinzu. damit bildet sich der
> neue wert zu:

Ein interessanter Ansatz, aber schlussendlich nicht korrekt. Bei wenig 
schwankenden Werten und großem n sicher erträglich, aber für die 
Mittelung von wenigen stärker schwankenden Werten ist das nicht so das 
Wahre.

> 16-bit(neu)=255/256*16-bit(alt)+1/256*messwert.

Die Formel entspricht nicht der Beschreibung. Warum soll der neue 
Messwert erst geteilt werden?

> im höherwertigen byte des 16-bit wertes steht damit immer der aktuelle
> mittelwert, eine zwischenspeicherung von messwerten ist nicht nötig.

Nicht "immer", sondern erst, wenn n Werte aufgelaufen sind.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach das immer gern mit 2er-Potenzen, dann hats der Compiler 
leichter:
unsigned long avg_val, avgmem, new_val;
:
avgmem -= avgmem/128; // Filterbreite 128 Abtastungen, alten Wert abziehen
avgmem += new_val;    // neuen Wert aufaddieren
avg_val = avgmem/128; // Mittelwert berechnen
Und keine Unterscheidungen zwischen Startup und Betrieb.
Das macht ein "normales" analoges RC-Glied auch nicht  ;-)

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie komme ich denn jetzt hier voran?
Kann mir jemand weiterhelfen?

Danke

Autor: Thomas O. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan KM

Hier noch eine weitere Formel, die einem Tiefpass entspricht:

sample += (aktWert - mittelWert);
mittelWert = (sample >> 3);

Das Ganze kannst Du dann über die Shiftanzahl gewichten.
Wenn die Werte nicht ständig springen funktionierts auch sehr gut.

Schönes Wochenend

Autor: karadur (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan KM

Die Klammer auch im "Else"-Teil korrigiert.

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas B. wrote:
> Ein interessanter Ansatz, aber schlussendlich nicht korrekt. Bei wenig
> schwankenden Werten und großem n sicher erträglich, aber für die
> Mittelung von wenigen stärker schwankenden Werten ist das nicht so das
> Wahre.
doch, denn ein neuer messwert kann sich immer nur eine erhöhung des 
mittelwertes von maximal 1 bewirken, da er nur mit der wichtung 1/256 in 
den mittelwert eingeht
>> 16-bit(neu)=255/256*16-bit(alt)+1/256*messwert.
> Die Formel entspricht nicht der Beschreibung. Warum soll der neue
> Messwert erst geteilt werden?
der 8 bit-messwert wird mit dem 16-bitwert addiert, sodass er mit dieser 
wichtung in den neu ermittelten mittelwert (höherwertiges byte des 
16-bit wertes) eingeht. damit ist die division im prinzip mit der 
addition des 8bit wertes bereits erledigt, eine extra divisionsoperation 
ist nicht nötig.
> Nicht "immer", sondern erst, wenn n Werte aufgelaufen sind.
es wird zu beginn der mittelwert aus 255 nullen (oder einem anderen 
startwert) und dem neuen messwert ermittelt und dadurch ein einschwingen 
auf den mittelwert und  kein sprung!
würde man zu beginn wenige werte mitteln, so hätte der mittelwert (zb 
bei stark schwankenden werten) sowieso keinerlei aussagekraft.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Schlaefendorf wrote:
> würde man zu beginn wenige werte mitteln, so hätte der mittelwert (zb
> bei stark schwankenden werten) sowieso keinerlei aussagekraft.
Richtig, denn das macht ein "normales" analoges RC-Glied auch nicht  ;-)

Autor: Stefan KM (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ karadur

Natürlich NICHT....   Manchmal, aber nur manchmal...  naja ich sprech es 
lieber nicht aus.

Danle

Autor: Siggi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
avgmem -= avgmem/128; // Hier wird der alte Wert bestimmt nicht 
abgezogen

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verwende immer die Form:
(das spart Speicher)
float filter(float neuer_wert)
{
  static float gewichtung=0.5,alter_wert;

  neuer_wert = (alter_wert*gewichtung)+(neuer_wert*(1-gewichtung));
  alter_wert = neuer_wert;

  return neuer_wert;
}

Diese Fkt. realisiert einen Filter mit unendlicher Sprungantwort...über 
die gewichtung kannst du einstellen wie stark gefiltert wird...

Auf dem AVR vlt nicht unbedingt als float aber das Prinzip sollte klar 
sein...

(Ich hoffe das funzt soo... ;) )

Autor: Thomas B. (yahp) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Schlaefendorf wrote:
> doch, denn ein neuer messwert kann sich immer nur eine erhöhung des
> mittelwertes von maximal 1 bewirken, da er nur mit der wichtung 1/256 in
> den mittelwert eingeht

Korrekt wäre bei einem gleitenden Mittelwert eben genau den Messwert zu 
entfernen, der jetzt vor dem relevanten Intervall liegt. Dafür 1/256 des 
aktuellen Messwerts zu verwenden ist eine Näherung, aber eben nicht 
korrekt. Ich sag' ja nicht, dass es keine sinnvolle Näherung wäre...

> der 8 bit-messwert wird mit dem 16-bitwert addiert, sodass er mit dieser
> wichtung in den neu ermittelten mittelwert (höherwertiges byte des
> 16-bit wertes) eingeht. damit ist die division im prinzip mit der
> addition des 8bit wertes bereits erledigt, eine extra divisionsoperation
> ist nicht nötig.

Eben, so ist es und genau das sagt die Formel nicht.

>> Nicht "immer", sondern erst, wenn n Werte aufgelaufen sind.
> es wird zu beginn der mittelwert aus 255 nullen (oder einem anderen
> startwert) und dem neuen messwert ermittelt und dadurch ein einschwingen
> auf den mittelwert und  kein sprung!
> würde man zu beginn wenige werte mitteln, so hätte der mittelwert (zb
> bei stark schwankenden werten) sowieso keinerlei aussagekraft.

Freilich gibt es so keinen Sprung, aber es ist eben auch kein Mittelwert 
der Messwerte. Es wird erst dann ein Mittelwert, wenn der "Puffer" 
vollgelaufen ist. Vorher sind Werte mit drinnen, die nicht von 
Messwerten stammen.

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas B. wrote:
> Freilich gibt es so keinen Sprung, aber es ist eben auch kein Mittelwert
> der Messwerte. Es wird erst dann ein Mittelwert, wenn der "Puffer"
> vollgelaufen ist. Vorher sind Werte mit drinnen, die nicht von
> Messwerten stammen.
ja, aber wenn du zwei messwerte hast und das arithmetische mittel 
berechnest, hast du auch keinen mittelwert deines signals, ausser es sit 
konstant.

Autor: Thomas B. (yahp) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Schlaefendorf wrote:
> ja, aber wenn du zwei messwerte hast und das arithmetische mittel
> berechnest, hast du auch keinen mittelwert deines signals, ausser es sit
> konstant.

Hu? Also warum soll der Mittelwert von zwei Werten nicht der Mittelwert 
sein? Das ist er sehr wohl.

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für die korrekte Implementierung des gleitenden Mittelwertes könnte man 
einen Ringpuffer nehmen, etwa so (ist jetzt in Java, da ich aus C echt 
raus bin, aber C müsste eigentlich fast identisch sein, statt überall 
32-Bit-int sind natürlich die kleinstmöglichen Einheiten zu wählen):
final int n_max=0;
int n=0;
int aeltester_Wert=0;
int puffer[]=new int[n_max];
int mittel=0;
int mittelwert (int neuerWert) {
    if (n<n_max) {
        mittel=(n*mittel+neuerWert)/(n+1);
        puffer[n]=neuerWert;
        n++;
    } else {
        mittel+=(neuerWert-puffer[aeltester_Wert])/n_max;
        puffer[aeltester_Wert]=neuerWert;
        aeltester_Wert=(aeltester_Wert+1)%n_max;
    }
    return mittel;
}

Bei den Integer-Divisionen ist allerdings immer ein Abrunden dabei, bei 
ungünstigen Folgen könnten sich die Rundungsfehler ansammeln und der 
Mittelwert vom tatsächlichen Mittel abweichen. Alternative, falls der 
maximale Input mal der Zahl der zu mittelnden Werte noch ins int passt:
final int n_max=0;
int n=0;
int aeltester_Wert=0;
int puffer[]=new int[n_max];
int mittel=0;´// eigentlich Mittelwert*n
int mittelwert (int neuerWert) {
    if (n<n_max) {
        mittel+=neuerWert;
        puffer[n]=neuerWert;
        n++;
    } else {
        mittel+=neuerWert-puffer[aeltester_Wert];
        puffer[aeltester_Wert]=neuerWert;
        aeltester_Wert=(aeltester_Wert+1)%n_max;
    }
    return mittel/n;
}

Wegen der genannten Einschränkung und der großen Speichernutzung würde 
ich eher den RC-Glied-ähnlichen Filter von oben verwenden :)

Autor: Moritz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die einzige Möglichkeit einen gleitenden Mittelwert korrekt zu 
implementieren geht über die Speicherung aller n Werte. Dazu einen 
Ringbuffer verwenden wie Slotta schrieb. Nimm für n 2er Potenzen für 
einfache Division mit n.
Slottas erster Algorithmus ist ungünstig, weil Division durch n+1 nicht 
mehr mit shiften geht. Die zweite Variante ist besser.

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas O. (Gast)
>sample += (aktWert - mittelWert);
>mittelWert = (sample >> 3);

Ist leider nicht richtig, Im Gleichspannungsfall läuft deine Gleichung 
gegen

mittelWert=1/9 aktWert

D.h. ist um den Faktor 9 zu klein.

Autor: Johannes Slotta (johanness)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moritz wrote:
> Slottas erster Algorithmus ist ungünstig, weil Division durch n+1 nicht
> mehr mit shiften geht. Die zweite Variante ist besser.

Wie gesagt, der erste Algorithmus hat auch seine Probleme mit den 
Rundungsfehlern. Der zweite rundet nur bei der Ausgabe, geht dafür eben 
nur, wenn der Mittelwert*Zahl der zu mittelnden Werte noch in die 
Datenstruktur (wahrscheinlich meist ein 16-bit-unsigned-int) passt.

Wenn du dir den 2. Algo noch mal genau ansiehst, da kannst du auch nicht 
einfach die Division durch n durch einen Shift ersetzen, dafür müsstest 
du diesen Teil für die Einschwingphase getrennt abhandeln. Ist halt der 
Preis dafür, dass du bereits am Anfang halbwegs vernünftige Werte 
bekommst.

Alternative wäre, das Feld vorzubelegen und den Mittelwert entsprechend 
zu initialisieren und dann gleich über alles hinweg zu mitteln. Dann 
kannst du aber den ersten Mittelwerten praktisch keine Information 
entnehmen, da sie praktisch komplett von der Initialisierung abhängen. 
Wenn du die ersten Messwerte wegwerfen kannst ist das sicher die bessere 
Lösung, da du dir später die Fallunterscheidung sparst und in jedem Fall 
mit einem billigen Shiftoperator wegkommst.

Autor: Thomas O. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ajax (Gast)
Bau Dir dazu mal 'ne Excel Tabelle und Du wirst sehen wie schön das 
Ganze auch bei Gleichspannung - mit nicht wechselnden Werten - 
funktioniert.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die einzige Möglichkeit einen gleitenden Mittelwert korrekt zu
> implementieren geht über die Speicherung aller n Werte.
Das stimmt, allerdings kann man sich die Frage stellen, ob Stefan KM das 
überhaupt will/braucht. Wenn "nur" ein Tiefpass entsprechend einem 
RC-Glied nachgebildet werden soll, dann reicht die Speicherung des 
aktuellen Summenwertes aus. Ein Kondensator speichert ja auch nicht die 
letzten 100 Werte, sondern "nur" die aktuelle Summe.

Was er will, ist doch eine Art "besseres" RC-Glied, das (ohne 5*tau)
 - nach der 1. Messung direkt diesen Wert
 - nach der 2. bis zur 99. Messung den Mittelwert aus diesen Messungen
 - ab der 100. den MW aus allen vorangegangenen Messungen
ausgibt.
unsigned long mittelwert(unsigned long newval) 
{
   static short n = 1;
   static unsigned long avgsum;
   unsigned long avg;
   if (n<100) {
      avgsum += newval;
      avg = avgsum/n;
      n++;
   }
   else {
      // Konstanten kann der Compiler evtl. besser optimieren
      avgsum -= avgsum/100;
      avgsum += newval;
      avg = avgsum/100;
   }
   return avg;
}

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

Bewertung
0 lesenswert
nicht lesenswert
ajax wrote:
> Thomas O. (Gast)
>>sample += (aktWert - mittelWert);
>>mittelWert = (sample >> 3);
>
> Ist leider nicht richtig

Wahrscheinlich war so etwas gemeint:
diff = sample - avg;
avg += (diff >> n);

Ist nur eine andere Schreibweise für den exponential moving average 
filter mit Koeffizient 1-2^(-n).

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eine tiefpasssimulation bringt auf jeden fall einen sinnvoleren wert, 
als das arithmetische mittel, da länger zurück liegende werte viel 
schwächer gewichtet werden als im mittelwert, die geschichte des signals 
also viel stärker beachtet wird. der bloße mittelwert "hüpft" weiter 
sinnlos rum! der teifpass konvergiert (je nach wichtung und filtertiefe) 
evtl langsamer. die wichtung des filters (also seine grenzfrequenz) muss 
also evtl angepasst werden.

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
meine aktuelle Version des Tiefpasses schaut so aus:

Initialisieren mit
averSum = n * sample;



averSum += sample - (aver = averSum / n);

Input:  sample
Output: aver


n sinnvollerweise ein Vielfaches von 2, damit die Division mit Shifts 
ausgeführt werden kann.

Bei dieser Version gibt es keinen Rundungsfehler, da in averSum der 
n-fache Wert von sample aufsummiert wird.

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas O.

>Bau Dir dazu mal 'ne Excel Tabelle und Du wirst sehen wie schön das
>Ganze auch bei Gleichspannung

Du hattest recht, ich habe mich leider verrechnet :-(
Deine Gleichung stimmt und ist die gleiche wie die von Andreas Schwarz.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interessant ist, dass auch in dem Beitrag "Mittelwert Berechnung" jemand 
die RC-Tiefpassfunktion mit dem gleitenden Mittelwert verwechselt. Der 
RC-Tiefpass ist eben kein gleitender Mittelwert, sondern nähert sich 
exponentiel dem Eingangswert an. Während der gleitende Mittelwert als 
Mittelwert eines Teiles eines Eingangssignals berechnet wird, wobei das 
Mittelwertfenster eben über diese Eingangssignal "gleitet".

Jetzt die große Preisfrage: wie berechnet sich das äuqivalent zu TAU 
beim RC Tiefpass für den oben angegebenn IIR-Filter?

>>diff = sample - avg;
>>avg += (diff >> n);

Tau=f(Abtastfrequenz,n) ?

Durch die Kenntnis von Tau bekommt man auch ein Gefühl für die Dauer des 
Einlaufens des Ausgangswertes.

Gruß,
ajax

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Halt,
Datum: 01.12.2008 19:33
war meine vorletzte Version.

folgende hat den Vorteil, einen Sample aktueller zu sein (der aktuelle 
Sample geht noch ins Ergebnis ein):
aver = (averSum += sample - aver) / n;


Die Initialisierung schaut dann so aus:
averSum = (aver = sample) * n;


Auch das mit dem Rundungsfehler stimmt nicht ganz, man müsste
aver = ((averSum += sample - aver) + n/2) / n;
schreiben, da die Integer-Division immer abrundet und nie aufrundet.
Mit dieser Formel wird der Wert etwas schneller erreicht.


Der Vorteil meiner Formel ist, dass
 - bei konstantem Eingangswert  dieser auch erreicht wird.
 - nur eine Division auftritt.

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jetzt die große Preisfrage: wie berechnet sich das äuqivalent zu TAU
>beim RC Tiefpass für den oben angegebenn IIR-Filter?
>>diff = sample - avg;
>>avg += (diff >> n);

>Tau=f(Abtastfrequenz,n) ?

Ich habe noch mal ein wenig nachgedacht, weil mich die Frage selbst 
interessiert hat.

Angenommenn, man hat eine Gewichtungsfaktor a für einen neuen Wert,

Ausgang=Eingang*a+AlterAusgang*(1-a)

Dann erhält man für Tau

Tau=-1/(fab*ln(1-a))

für kleine a gilt

Tau~=1/(a*fab)

d.h. bei eine Abtastfrequenz von 1KHz und einer Gewichtung a von 1/100 
erhält man ein Tau von 0.1 Sekunden.

Die Grenzfrequenz für den Tiefpass ergibt sich dann mit

fg=1/(2*pi*Tau)

zu 1.6Hz

Was haltet Ihr davon?

Gruß,
ajax

Autor: Sinusgeek (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Cool....
Und wie sieht dieser Algorithmus in AVR-ASM aus?
Welche Ressourcen verbraucht er??
Lohnt sich das???

Autor: rene (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>http://www.ibrtses.com/embedded/exponential.html

Bei den Gleichungen im Link fehlt die Zeiteinheit.
Tau bei einem RC-Tiefpass hat die Einheit "Sekunde"
N hingegen ist einheitenlos. Erst in Verbindung mit der Abtastzeit 
ergibt sich ein Zeitbezug, was ja für eine Filtereigenschaft die 
wesentliche Größe ist.

Autor: ajax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>http://www.ibrtses.com/embedded/exponential.html

Die in dem Link vorgestellt Berechnungsvorschrift benötigt etwas mehr 
Rechenzeit, wohingegen diese Formel
>>diff = sample - avg;
>>avg += (diff >> n);

nur
1xSubtraktion
1xShift
1xAdition benötigt

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.