Forum: Mikrocontroller und Digitale Elektronik gleitender Mittelwert im Atmel


von Stefan KM (Gast)


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

von karadur (Gast)


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.

von Läubi .. (laeubi) Benutzerseite


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.

von Stefan KM (Gast)


Lesenswert?

@ karadur

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

von karadur (Gast)


Lesenswert?

@ Stefan KM.

Die Formel gilt dann immer noch.

von Stefan KM (Gast)


Lesenswert?

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

von Frank S. (Firma: HSCS) (linuxerr)


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.

von Johannes S. (johanness)


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.

von karadur (Gast)


Lesenswert?

@ Stefan KM

richtig.

von Stefan KM (Gast)


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?

von Johannes S. (johanness)


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!

von Stefan KM (Gast)


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.

von Johannes S. (johanness)


Lesenswert?

Wie gesagt, hast du die Klammern korrigiert? Also

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

von Johannes S. (johanness)


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.

von Stefan KM (Gast)


Lesenswert?

Ich habs jetzt. Es funktioniert.

Danke dir.

von Johannes S. (johanness)


Lesenswert?

Freut mich zu lesen :)

von Stefan KM (Gast)


Lesenswert?

Zu früh gefreut.....

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

von Thomas B. (yahp) Benutzerseite


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Stefan KM (Gast)


Lesenswert?

Wie komme ich denn jetzt hier voran?
Kann mir jemand weiterhelfen?

Danke

von Thomas O. (Gast)


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

von karadur (Gast)


Lesenswert?

@ Stefan KM

Die Klammer auch im "Else"-Teil korrigiert.

von Frank S. (Firma: HSCS) (linuxerr)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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  ;-)

von Stefan KM (Gast)


Lesenswert?

@ karadur

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

Danle

von Siggi (Gast)


Lesenswert?

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

von ... .. (docean) Benutzerseite


Lesenswert?

Ich verwende immer die Form:
(das spart Speicher)
1
float filter(float neuer_wert)
2
{
3
  static float gewichtung=0.5,alter_wert;
4
5
  neuer_wert = (alter_wert*gewichtung)+(neuer_wert*(1-gewichtung));
6
  alter_wert = neuer_wert;
7
8
  return neuer_wert;
9
}

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... ;) )

von Thomas B. (yahp) Benutzerseite


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.

von Frank S. (Firma: HSCS) (linuxerr)


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.

von Thomas B. (yahp) Benutzerseite


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.

von Johannes S. (johanness)


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):
1
final int n_max=0;
2
int n=0;
3
int aeltester_Wert=0;
4
int puffer[]=new int[n_max];
5
int mittel=0;
6
int mittelwert (int neuerWert) {
7
    if (n<n_max) {
8
        mittel=(n*mittel+neuerWert)/(n+1);
9
        puffer[n]=neuerWert;
10
        n++;
11
    } else {
12
        mittel+=(neuerWert-puffer[aeltester_Wert])/n_max;
13
        puffer[aeltester_Wert]=neuerWert;
14
        aeltester_Wert=(aeltester_Wert+1)%n_max;
15
    }
16
    return mittel;
17
}

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:
1
final int n_max=0;
2
int n=0;
3
int aeltester_Wert=0;
4
int puffer[]=new int[n_max];
5
int mittel=0;´// eigentlich Mittelwert*n
6
int mittelwert (int neuerWert) {
7
    if (n<n_max) {
8
        mittel+=neuerWert;
9
        puffer[n]=neuerWert;
10
        n++;
11
    } else {
12
        mittel+=neuerWert-puffer[aeltester_Wert];
13
        puffer[aeltester_Wert]=neuerWert;
14
        aeltester_Wert=(aeltester_Wert+1)%n_max;
15
    }
16
    return mittel/n;
17
}

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

von Moritz (Gast)


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.

von ajax (Gast)


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.

von Johannes S. (johanness)


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.

von Thomas O. (Gast)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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.
1
unsigned long mittelwert(unsigned long newval) 
2
{
3
   static short n = 1;
4
   static unsigned long avgsum;
5
   unsigned long avg;
6
   if (n<100) {
7
      avgsum += newval;
8
      avg = avgsum/n;
9
      n++;
10
   }
11
   else {
12
      // Konstanten kann der Compiler evtl. besser optimieren
13
      avgsum -= avgsum/100;
14
      avgsum += newval;
15
      avg = avgsum/100;
16
   }
17
   return avg;
18
}

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

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

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

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

von Frank S. (Firma: HSCS) (linuxerr)


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.

von eProfi (Gast)


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.

von ajax (Gast)


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.

von Hannes L. (hannes)


Lesenswert?


von ajax (Gast)


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

von eProfi (Gast)


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.

von ajax (Gast)


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

von Sinusgeek (Gast)


Lesenswert?

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

von rene (Gast)


Lesenswert?


von ajax (Gast)


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.

von ajax (Gast)


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

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.