Forum: Mikrocontroller und Digitale Elektronik Mittelwert berechnung


von Michael (Gast)


Lesenswert?

Hallo,

ich muß einen Mittelwert von m/s berechnen.
Die Werte kommen 40 mal pro Sekunde und werden dann jede Sekunde aufs
LCD geschrieben.
Momentan werden die 40 Strecken und die 40 Zeiten in ein Array
geschrieben dann jeweils addiert und dann Strecke durch Zeit ergibt den
Wert.
Gibt es einere schnellere Lösung vielleicht mit einem Filter?

Gruß Michael

von Gary (Gast)


Lesenswert?

Hallo - d.h. du bildest den Mittelwert quasi immer über eine Messreihe
von 40 Messungen?
Sicher hast du ein festes Abtastraster - dann kannst du dir die Zeit
sparen.
Aber egal was du machst... auch ein Filter braucht "Altwerte".
Was du machst scheint so was wie die gleitende Mittelung >>
Tiefpass/Integrator zu sein.

von Gary (Gast)


Lesenswert?

PS - Warum brauchst du soviele Messpunkte - ist die Wegerfassung so
ungenau bzw. schwankt das Signal so stark? Evtl. kannst du was an der
Auflösung machen und damit den Rechenaufwand verringern.

von Detlev Tietjen (Gast)


Lesenswert?

Hi,
als erstes fällt mir auf, dass deine Mittelwertbildung nicht korrekt
ist wenn die Zeitabstände nicht identisch sind. Du müsstest jede
Strecke jeweils durch ihre Zeit teilen und dann diese Werte mitteln.

Meine Empfehlung:
Wenn möglich die Hardware an die Anforderung anpassen. Das heißt:

- Gleiche Zeitabstände zwischen Messungen. Dann muss man die Zeiten
nicht in die Rechnung einbringen. Stattdessen ist die Geschwindigkeit
dann Strecke mal (1/T). (1/T) stellt dabei eine Konstante dar. Optimal
wäre natürlich eine Zahl, die als Bit-Shift ausgeführt werden kann. Die
Strecken werden dann einfach aufaddiert, am Ende einmal mit (1/T)
multipliziert und dann durch die Zahl der Messungen geteilt.
- Für die Zahl der Messungen möglichst eine Potenz von 2 (z.B 32 oder
64) als Zahl der Messungen wählen, dann kann man die Division als
Bit-Shift ausführen.
- Diese Operation kann man auch mit der (1/T) Multiplikation
kombinieren. Man muss also nur die Strecken addieren und am Ende einmal
mit irgendeinem Wert multiplizieren bzw Shiften.

Mehr fällt mir nicht ein.

Gruß, Detlev

von Michael (Gast)


Lesenswert?

Danke, letzteres werde ich mal versuchen.
Gruß Michael

von karadur (Gast)


Lesenswert?

Hallo

ein gleitender Mittelwert ist hier einfacher.
Für den ersten Wert ist der Mittelwert gleich dem Messwert. Beim 2ten
die Summe aus dem letzten Mittelwert gewichtet mit der bisherigen
Anzahl der Messungen geteilt durch die neue Anzahl + dem neuen Wert
geteilt durch der neuen Anzahl der Messungen.
Für 40 Messungen also immer alter Mittelwert geteilt durch 40 mal 39 +
neuer Messwert/40. Damit spart man das Array und man hat nach jeder
Messung einen neuen Wert.

von ,-,-,-,- (Gast)


Lesenswert?

Deine Ausführungen und die Formel passen nicht zueinander.
So wies beschrieben war würde ihrgendwann der Zähler für die Messungen
überlaufen. Die Formel ansich passt dann schon eher.

Aber auch anders, ist das ganze nicht sehr brauchbar, wenn man bedenkt,
dass hier mit teilen und multipliziern gearbeitet wird. Beides sehr
unpraktisch wenn man keinen µC mit Multiplikator in Hardware hat.

Mit shift-befehlen könnte das womöglich so aussehen:

mittelwert - (mittelwert >> 5) + (messwert >> 5) (für 32 Messungen)

Dürfte dann doch erheblich schneller als der Ursprünglich code sein.
Allerdings kostet das immernoch einiges an Abarbeitungszeit für die
shifts.

Das Effizienteste dürfte es sein, ein Variable der doppelten breite der
Messwerte(16 für 8bit) aufzuaddieren und diese dann nach 2^n Messunge
mit n shifts zu teilen.

von Hannes L. (hannes)


Lesenswert?

oder so:
1
;==================================================================
2
; Routine für Mittelwert über 256 Messungen (z.B. ADC)
3
;------------------------------------------------------------------
4
; in 'wert_h' und 'wert_l' steht der Mittelwert, 
5
; in 'wert_n' sind die Nachkommastellen,
6
; wl und wh sind Temp-Register
7
; das Register 'null' enthält immer 0
8
9
;für 16-Bit-Werte:
10
 in wl,adcl             ;ADC-Wert
11
 in wh,adch             ;einlesen
12
 sub wert_n,wert_l      ;1/256 vom Wert
13
 sbc wert_l,wert_h      ;mit Übertrag
14
 sbc wert_h,null        ;subtrahieren,
15
 add wert_n,wl          ;1/256 des neuen
16
 adc wert_l,wh          ;Wertes mit Übertrag
17
 adc wert_h,null        ;addieren
18
;fertig...
19
20
;für 8-Bit-Wert:
21
 in wl,adch             ;linksbündig justierten ADC-Wert einlesen
22
 sub wert_n,wert        ;1/256 vom alten Wert
23
 sbc wert,null          ;mit Übertrag subtrahieren
24
 add wert_n,wl          ;1/256 vom neuen Wert
25
 adc wert,null          ,mit Übertrag addieren
26
;fertig...

...

von karadur (Gast)


Lesenswert?

@,-,-,-,-
Sorry die Beschreibung ist nicht vollständig. Das gilt nur bis der
40ste Wert gemessen wurde, danach wird immer durch 40 geteilt.
40 ist natürlich kein Wert der für einen uC optimal ist.
Ich habe diesen Mittelwert in der Labordatenerfassung oft eingesetzt
und er funktioniert auf einem PC hervorragend.
Für einen uC muß man das halt optimieren. Der Vorteil ist eben das nur
der letzte Mittelwert gespeichert werden muß, nachdem die Anzahl der
Werte die Sollanzahl erreicht hat.

von Profi (Gast)


Lesenswert?

Ihr müsst aber unterscheiden zwischen Mittelwertbildung über eine
definierte Anzahl von Messungen und einem gleitenden Mittelwert, der
die einfachste Variante eines IIR-Filters ist.

Um die Rechenoperationen bei hoher Genauigkeit möglichst gering zu
halten, habe ich immer den skalierten (z.B. *32) Mittelwert
gespeichert, dann davon 1/32 abgezogen und den Messwert addiert.
Der Mittelwert pendelt sich dann auf dem 32-fachen des Messwertes ein.

Mittelwert-=Mittelwert>>5-Messwert   oder
Mittelwert+=Messwert-Mittelwert>>5

Oft kann man mit dem skalierten Mittelwert einfacher weiterrechnen.

Übrigens ist ein gleitendes Filter mit 32 schon ein sehr starkes
Filter.

Die andere Möglichkeit ist ein echtes IIR-Filter. Die haben den
Vorteil, dass sie Störer gut wegfiltern und auf Änderungen schnell
reagieren. Allerdings ist die Wahl der benötigten Faktoren für die
Filtergleichung eine diffizile Angelegenheit.

Für den Digitalfilter-Anfänger ist es nämlich recht schwer,
festzustellen, ob der Filter wirklich filtert, oder eher nur
Mittelwerte berechnet (aperiodischer Fall).
Ein Problem dabei ist auch, dass in der Literatur diese Faktoren
unterschiedlich beziffert und deren Vorzeichen unterschiedlich
bezeichnet werden.

von Bernhard S. (bernhard)


Lesenswert?

@Hannes

ich habe Deine

"Routine für Mittelwert über 256 Messungen (z.B. ADC)" ausprobiert.

Mir ist aber noch etwas unklar, wenn ich 256 mal den Wert 100 (wl)

einlese, dann erhalte ich als Ergebnis bei der 8-Bit-Variante

immer "63".

Ist das korrekt und auch so beabsichtigt?

Ich dachte, dass nach 256 Messungen und wl=100 auch als Ergebnis 100
errechnet wird?

Danke

Bernhard

von Detlev (Gast)


Lesenswert?

Dein Test ist korrekt. Ein gleitender Mittelwert nähert sich nur sehr
langsam an den endgültigen Wert an, vergleiche Aufladung eines
Kondensators über einen Widerstand. Der Wert, den du erhältst ist daher
(näherungsweise) 100 * (1 - 1/e), und das ist eben 63, wenn du mit 0
startest.

von Karl heinz B. (kbucheg)


Lesenswert?

> Ist das korrekt und auch so beabsichtigt?

Wenn ich mir in Excel mal diesen 'gleitenden
Mittelwert' nachbilde, dann sehe ich: Der
Mittelwert hinkt ziemlich hinterher und steigt
nur sehr langsam an. Nach 256 Iterationen ist
tatsächlich erst ein 'Mittelwert' von 63,2
erreicht (erster 'Mittelwert' auf 0 gesetzt
und danach immer 100 hineingerechnet). Selbst
wenn ich den Startwert auf 90 setze, wird nach
256 Iterationen erst ein Wert von 96,3 erreicht.

von Arno H. (Gast)


Lesenswert?

Meiner Meinung nach sollte der Mittelwert der Geschwindigkeit aus
Gesamtstrecke / Gesamtzeit errechnet werden, oder irre ich mich da?

Arno

von karadur (Gast)


Lesenswert?

Hallo

den Nachteil des "nachhinkens" kann man umgehen wenn man zu Anfang
den Mittelwert über die wirklich schon gemessenen Werte berechnet.
Wie ich schon geschrieben habe: 1 Wert=1Mittelwert.
Bei der 2ten Messung Mittelwert = alter Mittelwert/2 + neuer Wert/2
Bei der 3ten Messung Mittelwert = alter Mittelwert/3*2 + neuer Wert/3
bei der nten Messung Mittelwert = alter Mittelwert/n*(n-1)+neuer Wert/n
mit n=Anzahl der Messung
wobei n mitläuft bis die Blockgröße erreicht ist. z.B. 32 oder 64

evtl. kann man auch statt der exakten Anzahlen Stufen in 2er Potenzen
verwenden.
Diese Routine läuft seit Jahren in Messsystemen auf PCs bei vielen
Kunden von mir.

von Bernhard S. (bernhard)


Lesenswert?

Ein kleines Beispiel für eine Mittelwertbildung eines ADC-Wertes.

Ein ADC-Wert wird 256 mal eingelesen und die Werte miteinander

addiert anschließend erfolgt eine Prüfung (wie beim kaufmannischen

Runden) der Nachkommastelle (temp4).



Diese Prüfung entscheidet, ob das Ergebnis aufgerundet werden soll

oder nicht.


Bernhard



;#############################################################
; ADC-WERT 256 mal einlesen und daraus den Mittelwert bilden
;
; OUT:   TEMP1 (low)
;  TEMP2
MESSEN:
  push temp3  ; HILFSREGISTER sichern
  push temp4
  push temp5
  push temp6
  push temp8
;-------------------------------------------------------------
  clr temp3  ; HILFSREGISTER CLEAR
  clr temp4
  clr temp5
  clr temp6
  clr temp8
;-------------------------------------------------------------

; neuen ADC-Wert lesen   Wert verwerfen,
; da meist vom vorherigem ADC-Kanal
  sbi ADCSRA, ADIF  ; logisch "1" löscht ADIF flag !
MESSEN_w:
  sbis ADCSRA, ADIF  ; warten bis ADIF flag gesetzt
  rjmp MESSEN_w

;-------------------------------------------------------------

; neuen ADC-Wert lesen  (Schleife - 256 mal)
MESSEN_SCHLEIFE:
  sbi ADCSRA, ADIF  ; logisch "1" löscht ADIF flag !
MESSEN_SCHLEIFE_w:
  sbis ADCSR, ADIF ; warten bis ADIF flag gesetzt
  rjmp MESSEN_SCHLEIFE_w

;-------------------------------------------------------------

; ADC einlesen:
  in  temp1, ADCL ; immer zuerst LOW Byte lesen
  in  temp2, ADCH ; danach das mittlerweile gesperrte High Byte

;-------------------------------------------------------------

; alle 256 ADC-Werte addieren
  add temp4,temp1         ; addieren
  adc temp5,temp2         ; addieren über Carry
  adc temp6,temp3         ; addieren über Carry
  dec temp8      ; Schleifenzähler MINUS 1
  brne MESSEN_SCHLEIFE     ; ==> SCHLEIFE


;-------------------------------------------------------------

; MITTELWERT-BERECHNUNG  (Prüfung der "Kommastelle" temp4)
  cpi temp4,128     ; "Kommastelle" kleiner als 128 ?
  brlo MESSEN_MITTELWERT_w ; ist kleiner ==> Sprung

;-------------------------------------------------------------
; Aufrunden
  ldi temp1,1     ; =1
  add temp5,temp1     ; addieren von 1
  adc temp6,temp3     ; addieren über Carry
MESSEN_MITTELWERT_w:
;   Ergebnis nach temp1 und temp2 kopieren
  mov temp1,temp5
  mov temp2,temp6


;-------------------------------------------------------------
  pop temp8  ; Hilfsregister wieder herstellen
  pop temp6
  pop temp5
  pop temp4
  pop temp3
ret
;#################################################################

von n/a (Gast)


Lesenswert?

Genausogut hättest Du temp4 mit 128 initialisieren können und die ganze
Aufrundungsgeschichte am Ende wäre überflüssig.

von Bernhard S. (bernhard)


Lesenswert?

;Genausogut hättest Du temp4 mit 128 initialisieren können

Stimmt!!!

Sehr gute Idee.

Danke

von Marko B. (Gast)


Lesenswert?

Mal was anderes: der Mittelwert (arithmetisches Mittel) ist schlecht
geeignet, um Meßwerte zu glätten. Viel besser ist der Median
(Zentralwert), weil damit Ausreißer viel weniger stark gewichtet
werden. Allerdings ist die Berechnung etwas aufwendiger (Sortieren
einer Tabelle).

von andi r. (Gast)


Lesenswert?

Ob median oder oder arithmetisches mittel ist eine frage
des zwecks des "Filters":
um die wirkung von ausreißern(=messFEHLER) zu verhindern eignet sich
der median optimal. Er "glättet" (=tiefpass) allerdings nicht, unter
ungünstigsten umständen bekommt man sogar einen sehr
"nicht-repräsentativen" Wert.
z.b. 9,8,1,9,0 :
median= 8
a.mittel =5,4 -> 5
zum reinen glätten eignet sich dann besser das a. mittel.

ich hab bei sensoren an einem roboter (die billigen sharp IR
enfernungs-teile) mit einer kombination aus median und a. mittel das
beste (=zuverlässigste) ergebnis gehabt:
32 messungen, die sortiert,
aus den mittleren 16 dann das arithmetische mittel gebildet.

zurück zum thema:
wenn der controller wenig anderes zu tun hat, als die 40 werte/s
zu mitteln, und das LCD zu bedienen; und die aktuelle lösung
zufriedenstellende ergebnisse liefert, wär ich glücklich damit.

wobei natürlich die rechenzeit in diesem fall auch für eine
exzentrische akademiker-lösung reicht ;-)

von Hannes L. (hannes)


Lesenswert?

@Bernhard:

Sorry, aus irgendeinem Grund bekam ich keine Mailbanachrichtigung mehr,
wenn hier neue Beiträge verfasst wurden. Daher fiel mir der Thread erst
jetzt zufällig wieder auf.

Aber Deine Frage wurde ja inzwischen bereits so umfassend beantwortet,
dass ich auch noch etwas daraus lernen konnte.

Danke...

Ich benutze diese Routine für sich langsam ändernde Werte, wie z.B. die
Batteriespannung. Dabei kommt es mir nicht unbedingt auf das extrem
starke Integrieren dieser Routine an, sondern auf ihre Einfachheit und
den extrem geringen Bedarf an Rechenzeit. Meist wird der erste Messwert
nach dem Reset als Startwert genommen, manchmal (wenn ein Grenzwert zum
Auslösen eines Alarms oder einer Notabschaltung überwacht wird) aber
auch auf ein Fixwert.

Die Idee zu dieser Routine kam mir, als hier jemand jemand Anderem (ich
finde den Thread jetzt leider nicht) den Algorithmus erklärt hatte.
Demnach sollte vor jeder Messung 1/10 (oder war's 1/100?) des
Mittelwertes vom Mittelwert subtrahiert werden und 1/10 (1/100) des
neuen Messwertes zum Mittelwert addiert werden. Da mir die (relativ
aufwendige) Berechnung des Zehntels bzw. Hundertstels für diesen Zweck
unangemessen erschien, stellten ich das auf 1/256 um, womit die
Division entfällt, da sie durch Byteshiften ersetzt werden kann. Und
seitdem hat sich diese Routine bei mir bestens bewährt.

...

von Tomas (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe die hervorragende Funktion von Hannes Lux genauer in Excel 
untersucht. Ändert sich das ADC Ergebnis von 0 auf 256, dann dauert es 
weitere 1030 Messungen, bis der "Mittelwert über 256 Messungen" den Wert 
255 erreicht hat.
Bei 5 Messungen je Sekunde dauert das ca. 3 Minuten 26 Sekunden.

Für viele Zwecke ist das zu langsam. Deshalb als Anlage die Auswertung 
für den gleitenden Mittelwert über 128/64/32/16/8 und 4 Werte. Hierfür 
ist lediglich ein zusätzliches Shiften erforderlich, was die Effiziens 
nur unwesentlich verschlchtert.

Ein "Mittelwert über 64 Messungen" eines 10Bit ADC passt noch in ein 16 
Bit Register und gleicht sich nach 326 Messungen aus.

von Dai (Gast)


Lesenswert?


von Dai (Gast)


Angehängte Dateien:

Lesenswert?

zum obigen Beitrag von mir.

von Tomas (Gast)


Lesenswert?

@Dai
Du sagst es, dass ist der Algorithmus von Hannes wie ich ihn in Excel 
formuliert habe. Ich hatte die erforderliche Anzahl der 
Iterationsschritte gesucht bis zum Ausgleich gesucht. Hast Du dafür eine 
geschlossene Lösung?

In meinem Fall geht es um die Auswertung eines PIR-Sensors. Ich erfasse 
die Pegeländerungen gegenüber dem gleitenden Mittelwert (Auswertung ca. 
10Hz).

Hier noch der angepasste Code für schnelle Filterung:
1
;===============================================================================
2
; Routine für gleitenden Mittelwert über 2 bis 64 Messungen eines 10Bit-ADC (AVR)
3
;-------------------------------------------------------------------------------
4
; 10 Bit ADC
5
; vereinfacht wird der 2^n-fache Mittelwert fotgeschrieben, mit n=2...64
6
; im Registerpaar R19:R18 (16Bit) steht der 2^n-fache Mittelwert des ADC
7
; R17:R16 und R20 sind Temp-Register
8
9
10
   MOV R17, R19            ;Kopieren des alten MW
11
   MOV R16, R18
12
13
   LDI R20, 6              ;2^n (6->64)
14
Div_n:
15
   LSR R17                 ;Division des MW durch 2^n
16
   ROR R16
17
   DEC R20
18
   BRNE Div_n
19
   SUB R18, R16             ;MW_neu = MW_alt*(1-1/2^n)  
20
   SBC R19, R17
21
22
   IN R16,adcl             ;ADC-Wert
23
   IN R17,adch             ;einlesen
24
25
   ADD R18,R16             ;MW_neu=MW_alt*(1-1/2^n)+ADC
26
   ADC R19,R17             ;mit Übertrag addieren
27
28
;fertig...

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.