Hallo Leute,
Habe mir ein Programm geschrieben was meinen I2C Temperatursensor
(DS1621) auswertet und auf einer 7 - Segmentanzeige darstellt.
Das passt soweit alles. Das Problem ist jetzt. Das der Wert sehr stark
toggelt... Immer zwischen zwei Werten. Da habe ich mir gedacht, dass man
das mit hilfe einer Mittelwert ermittlung unterbinden könnte?!
Wie seht ihr das ?
Wie mache ich das am klügsten ?
Ich habe da an ca. 30 Messungen gedacht...
(Temperatur = ((Messwert_1 ... + Messwert_30) / 30);
Wie setze ich das in meinem Quellcode nun um ?...
>Das Problem ist jetzt. Das der Wert sehr stark>toggelt... Immer zwischen zwei Werten. Da habe ich mir gedacht, dass man>das mit hilfe einer Mittelwert ermittlung unterbinden könnte?!
Zwischen welchen Werten toggelt der?
>Wie seht ihr das ?>Wie mache ich das am klügsten ?>>Ich habe da an ca. 30 Messungen gedacht...
Blödsinn. Temperaturen ändern sich nur sehr langsam.
Dein Problem liegt ganz woanders.
holger schrieb:> Zwischen welchen Werten toggelt der?
Nehmen wir an, Es sind aktuell 20 Grad... Wenn es wärmer wird, Toggelt
der zwischen 20 & 21 Grad ständig hin und her...
In vielen Fällen liegt's an der Anzeige.
a) Wenn sich nichts tut, wozu dann mit high-speed messen?
b) Messwerte, vor allem Temperaturen liegen nun mal selten bei Irgendwas
Komma Null.
Also zwei Möglichkeiten fallen mir dazu ein.
1. Alle 5 Sekunden ein paar Messungen und durch die Anzahl teilen.
Dann anzeigen. Zwischenzeitlich kannst Du den µP ins Bettchen
schicken und Strom sparen.
2. Wenn Du auf volle Pulle stehst. Dauermessung aufsummieren alle paar
Sekunden durch die Anzahl teilen und die Anzeige aktualisieren.
Beides läuft darauf hinaus, dass nur gelegentlich die Anzeige
aktualisiert wird.
Ich sehe das Problem nicht. Nimmst du ein Array, schreibst da die Werte
rein - kannst ringbuffer-mässig dir immer den ältesten Index merken und
den updaten - dann entsprechend Formel mitteln.
Dass der Wert genau zwischen zwei Werten hin- und herspringt, kann Dir
mit Mittelwertbildung genauso passieren. Du brauchst eher eine
Hysterese, d.h. die Anzeige ändert sich z.B. erst, wenn die Temperatur
sich um mindestens zwei Auflösungsschritte geändert hat. Das kann man
natürlich mit einer Mittelwertbildung kombinieren.
Hans schrieb:> Dass der Wert genau zwischen zwei Werten hin- und herspringt, kann Dir> mit Mittelwertbildung genauso passieren. Du brauchst eher eine> Hysterese, d.h. die Anzeige ändert sich z.B. erst, wenn die Temperatur> sich um mindestens zwei Auflösungsschritte geändert hat. Das kann man> natürlich mit einer Mittelwertbildung kombinieren.
Hättest du einen Pseudocode für mich ?
Kann mir das gerade nicht vorstellen, wie du das meinst.
Dieter B. schrieb:> Ich habe da an ca. 30 Messungen gedacht...
Eine Zahl von "ca. 30" ist eine blöde Idee.
1. Mußt du dich für einen Wert entscheiden
2. Da du für die Mittelung durch die Zahl der Messwerte teilen mußt, ist
es grundsätzlich eine gute Idee, eine glatte 2er-Potenz von Messwerten
zu mitteln und dies auch im Programm über eine Konstante so zu coden.
Das gibt dem Compiler die Möglichkeit, diesen Rechenschritt in Bezug auf
den Rechenaufwand sehr effektiv zu implementieren.
Mike schrieb:> Das gibt dem Compiler die Möglichkeit, diesen Rechenschritt in Bezug auf> den Rechenaufwand sehr effektiv zu implementieren.
Bei einem Controller, der alle fünf Minuten die Temperatur misst, ist
das völlig egal.
Man braucht das gar nicht zu teilen. Man addiert einfach 10 Werte und
gibt diese 3-Stellige Zahl aus. Vor die rechte Ziffer setzt man den
Dezimalpunkt. Sowas nennt sich dann 10-fach Oversampling.
mfg.
Durch das Mitteln kann man das hin und her schwanken vermindern, aber
nicht ganz vermeiden. So lange die Schwankungen nicht so schnell nicht,
das man der Anzeige nicht folgen kann (also etwa schneller als etwa 2
Hz), stört das normalerweise auch nicht.
Vollständig unterdrücken des hin und her Schwankens geht per Hysterese -
dabei hat man dann aber zeitweise einen leicht falschen Angezeigten
Wert. Um den Fehler zu reduzieren, kann man erst mit erhöhter Auflösung
messen (gff. durch mitteln), und dann die Hysterese deutlich kleiner
wählen als einen Schritt der Anzeige.
Dieter B. schrieb:> Hans schrieb:>> Dass der Wert genau zwischen zwei Werten hin- und herspringt, kann Dir>> mit Mittelwertbildung genauso passieren. Du brauchst eher eine>> Hysterese, d.h. die Anzeige ändert sich z.B. erst, wenn die Temperatur>> sich um mindestens zwei Auflösungsschritte geändert hat. Das kann man>> natürlich mit einer Mittelwertbildung kombinieren.>> Hättest du einen Pseudocode für mich ?>> Kann mir das gerade nicht vorstellen, wie du das meinst.
In etwa so:
Sinnvollerweise enthält die Variable temp hier nicht die Temperatur in
°C, sonst würde sich die Anzeige ja erst nach 3°C Unterschied ändern.
Sondern eben Zehntel- oder Hunderstelgrad, die man aus mehreren
Messungen gemittelt hat. THRESHOLD kann man dann so einstellen, dass die
Anzeige ruhig genug ist.
>> Zwischen welchen Werten toggelt der?>>Nehmen wir an, Es sind aktuell 20 Grad... Wenn es wärmer wird, Toggelt>der zwischen 20 & 21 Grad ständig hin und her...
Dann miss halt nur alle 10 Minuten und gib den Wert
einmal alle 10 Minuten aus.
Dann fällt das gar nicht auf. Schneller wird sich deine
Temperatur sowieso nicht ändern.
Noch zur Mittelwertbildung: Das kann man recht einfach und
speicherschonend so machen:
1
#define AVG_FACTOR 10
2
longavg=0;
3
4
voidupdate_temp()
5
{
6
inttemp=get_temp();
7
avg=avg+temp-(avg/AVG_FACTOR);
8
print_temp(avg/AVG_FACTOR);
9
}
Die Variable avg enthält den zehnfachen (AVG_FACTOR) Mittelwert der
letzten Messungen. Mit jeder Messung wird die aktuelle Temperatur
addiert und dafür ein Zehntel des bisherigen Werts abgezogen.
Das ist nicht genau das gleiche wie der Mittelwert der letzten 10 Werte,
sondern die aktuellen Werte gehen mit höherer Gewichtung als ältere
Werte ein. Der Effekt ist der gleiche: Temperaturänderungen und
Schwankungen wirken sich langsamer auf den angezeigten Mittelwert aus.
Wenn man auf Rechenzeit beim Mitteln bedacht ist, wählt man für
AVG_FACTOR eine Zweierpotenz. Für die Anzeige als Dezimalwert sind
dagegen wie schon erwähnt 10er-Potenzen praktischer, weil man da nur das
Komma verschieben muss.
> Dass der Wert genau zwischen zwei Werten hin- und herspringt, kann Dir> mit Mittelwertbildung genauso passieren. Du brauchst eher eine> Hysterese, d.h. die Anzeige ändert sich z.B. erst, wenn die Temperatur> sich um mindestens zwei Auflösungsschritte geändert hat. Das kann man> natürlich mit einer Mittelwertbildung kombinieren.> Hättest du einen Pseudocode für mich ?
Hysterese PseudoCode...
1
if((measVal>(AdcVal+SigWindow))
2
||(measVal<(AdcVal-SigWindow))){
3
AdcVal=measVal;// Referenz für die nächste Messung
4
AdcValOut(measVal);
5
}
Du kannst einen Messwert auch "nachlaufen" lassen. Hierbei wird nicht
direkt auf jede Änderung reagiert sondern in einem kleineren Raster
nachgelaufen. Folgender Code sollte dir eine Idee geben, bezogen auf
dein Temperatur Mess Problem musst du den Code natürlich umbauen. Das
Beispiel ist hier von einer ADC Messung aber ich denke das Prinzip wird
klar.
Hysterese kombinert...
Hierdurch erfolgt eine Annäherung an den Messwert. Denk dir einfach das
+1, -1 hinter deiner Sichtbaren Stelle sitzt, erst nach 10 gleichen
Trends wird der Messwert sichtbar. Auflösung geht hierdurch keine
verloren aber die Anzeige wird träge und läuft zeitlich hinterher.
Eine kurze Studie des Datenblatts des DS1621 hat ergeben: Das Teil
liefert im zweiten Byte noch 0,5°C Schritte. Die würde ich auf jeden
Fall mit auswerten. Danach kann ja eine Mittelwertbildung, Hysterese
oder ähnliches folgen.
Bernd N schrieb:>> Dass der Wert genau zwischen zwei Werten hin- und herspringt,> kann Dir>> mit Mittelwertbildung genauso passieren. Du brauchst eher eine>> Hysterese, d.h. die Anzeige ändert sich z.B. erst, wenn die Temperatur>> sich um mindestens zwei Auflösungsschritte geändert hat. Das kann man>> natürlich mit einer Mittelwertbildung kombinieren.>>> Hättest du einen Pseudocode für mich ?>> Hysterese PseudoCode...> if ((measVal > (AdcVal + SigWindow))> || (measVal < (AdcVal - SigWindow))) {> AdcVal = measVal; // Referenz für die> nächste Messung> AdcValOut (measVal);> }> Hysterese kombinert... if (measVal > AdcVal) {> (measVal - AdcVal > AdcWindow) ? (AdcVal = measVal) : (AdcVal +=> 1);> } else if (measVal < AdcVal) {> (AdcVal - measVal > AdcWindow) ? (AdcVal = measVal) : (AdcVal -=> 1);> }>
Hallo Bernd,
Dein Tipp gefällt mir ;)
Hast du evtl. Skype ?
B e r n d W. schrieb:> Danach kann ja eine Mittelwertbildung, Hysterese> oder ähnliches folgen.
Hallo,
statt Mittelwertbildung wie vorgeschlagen über Intervalle ist eine
Tiefpassfunktion (gleitender Wittelwert, Wichtungsfunktion) oft
zweckmäßiger und auch einfacher zu programmieren.
http://de.wikipedia.org/wiki/Gleitender_Mittelwert
Ausgabewert = ((MerkWert * TPC-1) + aktueller Messwert) / TPC
TPC = Tiefpasskonstante (1.....n).
Der Ausgabewert wird sich wieder gemerkt und in der nächsten
Ausgabeschleife wieder als "MerkWert" verwendet.
Um ständiges Flackern der Anzeige zwischen 2 Zuständen zu vermeiden, ist
wie schon geschrieben eine Hysterese zweckmäßig.
Damit eine Anzeige z.B. wegen Rauschen oder Störeinstrhalungen nicht
ständig zwischen 22°C und 21,9°C hin und her flackert, weil der Messwert
gerade auf der Schaltschwelle von 21,95 herum dümmpelt, darf man bei
ansteigender Temp. erst bei z.B. 21,97°C auf 22,0°C schalten aber
umgekehrt bei ansinkender Temp. erst bei 21,93°C auf 21,9°C
zurückschalten. Die Hysterese wäre in diesem Fall +/-0,2Grad.
Programmtechnisch kann man dazu auch wieder den "MerkWert" benutzen und
je nach Richtung der Temperaturentwicklung für die Ausgabe aufs Display
einen kleinen Offset dazu gegeben oder abziehen.
In die Tiefpassfunktion darf man diesen Offset natürlich nicht geben.
Gruß Öletronika