Hi zusammen, folgende Sitiation: ich bekomme von meiner heizung jede Sekunde Daten auf den PC angeliefert, und diese "rauschen" z.B. 04.02.2013 04:09:18 X_T_AUL -792 04.02.2013 04:09:27 X_T_AUL -904 04.02.2013 04:10:02 X_T_AUL -792 04.02.2013 04:10:11 X_T_AUL -904 04.02.2013 04:10:37 X_T_AUL -792 (T_AUL steht für Temperatur Außenluft) oder 03.02.2013 22:31:42 X_T_RAUM 22251 03.02.2013 22:33:28 X_T_RAUM 22225 03.02.2013 22:35:03 X_T_RAUM 22251 03.02.2013 22:36:49 X_T_RAUM 22225 (Raumtemperatur) die Werte sind integers, skaliert mit 1000, d.h. 22251 steht für 22.251°C wie man sieht ist die Differenz bei Außenluft immer 112, bei Raumtemperatur immer 26, ich vermute also dass das niederwertigste Bit genau diese Wertigkeit hat. Dass diese Wertigkeit unterschiedlich ist, macht die Sache nicht einfacher Die Daten werden momentan geloggt, und eh schon nur bei Änderungen (deshalb gibts auch nicht jede Sekunde einen Wert) ich möchte diese Daten nun "glätten" im Sinne von Rauschen eliminieren und Anzahl der Log-Einträge reduzieren. Erste Idee: simples Runden: schlechte Idee, weil 22251 wäre 22.3, 22225 wäre 22.2, also nicht wirklich was gewonnen zweite Idee: Mittelwert-Bildung, dann runden. Schon besser, aber: wohin runden? Auf wieviele Stellen? idealerweise sollte das System "selbstlernend" sein, da wie oben zu sehen die "Genauigkeit" je nach Parameter unterschiedlich ist (und ich hab doch einige Parameter, wo ich nicht jeden getrennt behandeln will) dritte Idee: digitales Filter: Bessel oder Butterworth? welche ordnung? vierte idee: Dithering http://www.mikrocontroller.net/articles/Dithering Da blick ich aber nicht wirklich durch... Gibts da sowas wie "best practices"? Danke, Michi
PT1-Filter: #define filterStaerke 6 int32_t tmpSum; tmpSum += (tmpSum >> filterStaerke) + tmpInput; tmpSum steigt dann auf das 2**filterStaerke-fache von tmpInput an, deshalb auch 32bit.
Gleitender mittelwert über n Werte. Warum wir die Raumtemperatur auf 3 Nachkommastellen ausgegeben? Genauer als 0,3 Grad dürfte die eh nicht sein... Ingo
PT1-Glied klingt schon mal sehr gut... die Art der "Mittelwert-Bildung" kannte ich zwar, aber der Name PT1 ist mir neu. Man lernt ja jeden tag was neues... Aber: Diese Art der Glättung wird mein eigentliches problem, nämlich die Anzahl der Log-Einträge, eher verschlimmern: Ich krieg viele Zwischenwerte, wo sich jeder vom vorherigen unterscheidet, und damit noch mehr Einträge... @ingo: die Daten werden per Modbus abgefragt, alle Daten als 32-bit-Integer codiert, und bei Temperaturen wird einfach mit 1000 multipliziert. Das ist vom Gerät her so vorgegeben. Die vielen Kommastellen dürften von der Umrechnung Widerstand=>Temperatur herrühren (PT100 und so...) Vielleicht denk ich aber auch zu kompliziert: mein Problem ist, dass ich bei jeder Änderung einen neuen Datensatz speichere. Und hier löst reines Runden mein Problem nicht: springt ein Wert zwischen 20.24 und 20.25, und ich runde, dann springt er halt zwischen 20.2 und 20.3,also nix gewonnen... Ich könnte ja aber nicht stur auf Änderung prüfen, sondern auf Delta: Erst wenn die Abweichung zum zuletzt gespeicherten Wert größer als ein Schwellwert ist, wird gespeichert! Damit ließe sich die Glättung per PT1 und ein speicherplatz-sparendes Logging ideal kombinieren... Was hält ihr davon?
Michael Reinelt schrieb: > Was hält ihr davon? Ich würde zusätzlich noch die Bedingung setzen daß der neue Wert für eine Mindestanzahl Meßwerte stabil ist bzw. der Abstand zu einem parallel geführten PT1-Filter unter einer Schwelle liegt. Gruß Anja
Michael Reinelt schrieb: > wie man sieht ist die Differenz bei Außenluft immer 112, bei > Raumtemperatur immer 26, ich vermute also dass das niederwertigste Bit > genau diese Wertigkeit hat. Dass diese Wertigkeit unterschiedlich ist, > macht die Sache nicht einfacher Dann maskiere das letzte oder die beiden letzten Bits aus und teste was passiert. Und, nein dabei verschenkst Du keine Genauigkeit, die Bits sind sowieso nur geraten. fonsana
Ich sehe ein Probem darin, daß Deine Werte eine Genauigkeit suggerieren, die gar nicht vorhanden ist. Angenommen, Deine Vermutung ist richtig und der Unterschied von -0.904°C zu -0.792°C wäre genau ein LSB. Dann entspricht Deine Auflösung an dieser Stelle der Temperaturkurve ca. 0.1K Du gibst aber 3 Nachkommastellen an. Mein Tip: Begrenze die Genauigkeit der Werte auf einen sinnvollen Bereich , z.B. 0.2K. Noch ein Tip: http://www.dspguide.com/ch15.htm beschreibt sehr schön, wie und warum man Rauschen per MovingAverage-Filter wegbekommt.
Ganz praktisch ohne die ganze hochtrabende Theorie: Mit PT1-Filter glätten (Ausreißer beseitigen), dann per Hysterese auf "grobe" (0,2K?) Änderungen prüfen, danach die nichtssagenden Hundertstel und Tausendstel wegwerfen. ...
Eine -zugegeben etwas provokante- Frage: Streichst du dein Nutellabrot morgens mit dem Mikrometer? In etwa so sinnvoll ist der Versuch die Messwerte zu glätten, die sich um max. 1/10° unterscheiden, nur weil hinten noch 2 Zufallszahlen dranhängen, die aus der Binär zu Dezimal Konvertierung stammen. Schmeiss die hinteren 2 Stellen ZUERST weg, und runde: Bei Aussentemperatur auf höchstens 1°, selbst das braucht für die Heizungssteuerung keine Sau, und für die Innentemp. von mir aus auf 0,2°. Die Sensoren haben wahrscheinlich sowiso eine Genauigleit von +- 1 oder gar 2°.
Michael Reinelt schrieb: > und ein speicherplatz-sparendes Logging Genau deswegen: schmeiss die letzten 2 Stellen weg!
Ein Tiefpass benutzt genau eine Speicherzelle der jeweiligen Wortbreite. siehe http://www.ibrtses.com/embedded/exponential.html
Das ist kein Rauschen, sondern 1LSB des AD-Wandlers. Das kriegst Du nicht genauer gemacht. Daß es bei verschiedenen Werten unterschiedlich ist, liegt wohl daran, daß der Sensor nichtlinear ist und eine Korrekturrechnung erfolgt.
Peter Dannegger schrieb: > Das ist kein Rauschen, sondern 1LSB des AD-Wandlers. Das kriegst Du > nicht genauer gemacht. > Daß es bei verschiedenen Werten unterschiedlich ist, liegt wohl daran, > daß der Sensor nichtlinear ist und eine Korrekturrechnung erfolgt. Danke, Peter! Du hast es erfasst... Genauer will ich's eh nicht kriegen, nur das "Zittern" des LSB eliminieren. Einfach "die letzten zwei Stellen streichen" ist da eher die Holzhammer-Methode... bei der gelegenheit gleich noch eine Frage zum PT1-Filter: ich hab gelesen das PT1 entspricht einem Teifpass 1. ordnung, also ein RC-Glied. Dort ist die grenzfrequenz 1/(2*Pi*R*C). Gibts was "vergleichbares" für das PT1-Glied? Hängt dort natürlich von der Abtast-Frequenz ab...
Michael Reinelt schrieb: > Einfach "die letzten zwei Stellen > streichen" ist da eher die Holzhammer-Methode... Nö, das ist die ehrliche Methode. Das andere ist dem Anwender etwas vorlügen.
Peter Dannegger schrieb: > Michael Reinelt schrieb: >> Einfach "die letzten zwei Stellen >> streichen" ist da eher die Holzhammer-Methode... > > Nö, das ist die ehrliche Methode. > Das andere ist dem Anwender etwas vorlügen. Ich würde die Stellen nicht streichen, sondern sinnvoll runden. Gruss Harald
Michael Reinelt schrieb: > Einfach "die letzten zwei Stellen > streichen" ist da eher die Holzhammer-Methode... Die LSB ist bei den ersten Werten in der 3! Stelle, die beiden letzten Ziffern ergeben sich nur weil sich binäre Zahlen nicht glatt in dezimale umrechnen können. Ein Zappeln des LSB kann man nie ganz verhindern, höchstens seine Frequenz heruntersetzen. Dein Holzhammer hat gerade mal 50g und du willst damit einen 180 Nagel in den Balken schlagen. Aber nimm ruhig weiter die Schieblehre um die Brotdicke beim Frühstück zu kontrollieren.
Harald Wilhelms schrieb: > Ich würde die Stellen nicht streichen, sondern sinnvoll runden. Richtig, hatte mich hier schlecht ausgedrückt. Obwohl auch ein Streichen nur ein Fehler von max 0,05° wären, was mehr als eine ganze Größenordnung besser als der wahrscheinliche Fehler der Messung wäre. Wahrscheinlich sitzt jetzt der Aussentemperatursensor so, daß die Sonne draufscheinen kann :-)
Udo Schmitt schrieb: > Aber nimm ruhig weiter die Schieblehre um die Brotdicke beim Frühstück > zu kontrollieren. Bei meinem AG habe ich ein Interferrometer, das eine solche Dicke auf einige Zehntel Nanometer genau messen kann. Das wäre für diesen Zweck doch sicher noch besser geeignet. :-) Gruss Harald
Ich esse kein Nutellabrot! Die letzten Stellen kommen meiner Meinung nach nicht von der binär->dezimal-umrechnung, sondern vom Umrechenfaktor Widerstand=> Temperatur (die berühmten 0.00385), schlimmstenfalls wird sogar nichtlinear umgerechnet. trotzdem bin ich bei euch: sinnvoll runden. nur - wo ist sinnvoll? Wie ich schon geschrieben habe - springt ein Wert zwischen 20.241 und 20.253, und ich runde, dann springt er halt zwischen 20.2 und 20.3, also nix gewonnen... Und bevor ihr euch am Begriff "Temperatur" aufhängt - ich krieg auch noch andere Werte (Drehzahlen, CO2-Gehalt, ...) die zwar dasselbe grundlegende Problem haben (schwanken des LSB) aber in ganz anderen Wertebereichen. ich müsste irgendwie auf "signifikante bits" runden, bzw. eben genau das LSB wegwerfen (und vielleicht gleich noch eins dazu) nur müsst ich das erstmal finden.... außerdem behindert eine zu starke Rundung noch eine andere Auswertung: Das Erkennen von Tendenzen. Auch wenn der absolute Fehler bei der Raumtemperatur bei +/- 2K läge, so lassen sich doch auch leichte temperaturänderungen gut erkennen.
Also, Du hast ein Logging-Problem, es sind Dir zu viele Daten? Einfache Lösung: Nur alle 5 Sekunden oder alle 10 Sekunden oder nur jede Minute speichern. Andere Lösung, Du willst entscheidenden, wann sich eine signifikante Änderung eines Wertes ergeben hat, die es sich lohnt zu speichern. Dazu musst Du erstmal entscheiden, wann eine solche signifikante Änderung vorliegt. Momentan ist jede Änderung signifikant. Ein möglicher Ansatz wäre z.B., immer die letzten 5 Messwerte anzusehen: Wenn drei der letzten fünf Messwerte (egal welche) gleich dem letzten gespeichertem sind, dann wird kein neuer Messwert gespeichert. Solche Verfahren kannst Du beliebig "intelligent" machen. Z.B. könnte es eine Schwelle für ein Fehlerquadratsumme geben. Wenn diese überschritten ist, wird ein neuer Messwert gespeichert.
Michael Reinelt schrieb: > Wie ich schon geschrieben habe - springt ein Wert zwischen 20.241 und > 20.253, > und ich runde, dann springt er halt zwischen 20.2 und 20.3, also nix > gewonnen... Das Rauschen des letzten Bits kannst Du bei digitaler Verarbeitung nun mal nicht verhindern. Bei Temperaturen macht es aber nur selten Sinn, eine höhere Genauigkeit als 0,1 Grad anzuzeigen. Ob man eine solche Genauigkeit überhaupt erreicht, ist dann noch eine andere Frage. Gruss Harald
Michael Reinelt schrieb: > Danke, Peter! Du hast es erfasst... Genauer will ich's eh nicht kriegen, > nur das "Zittern" des LSB eliminieren. Einfach "die letzten zwei Stellen > streichen" ist da eher die Holzhammer-Methode... Wie wärs mit einer Hysterese?
1 | #define ABS(x) (((x)<0)?-(x):(x))
|
2 | #define RESOLUTION 250
|
3 | |
4 | void temp_log_task(void) |
5 | {
|
6 | static int logged = 0; |
7 | int now = get_temp(); |
8 | int diff = ABS(now - logged); |
9 | if (diff >= RESOLUTION / 2) { |
10 | // Wert runden (optional)
|
11 | logged = ((now + RESOLUTION / 2) / RESOLUTION) * RESOLUTION; |
12 | log_temp(logged); |
13 | }
|
14 | }
|
Statt den Wert zu runden, könnte man ihn auch in der Bitbreite reduzieren, falls der Speicherplatz in der Logdatei relevant ist.
Mein Senf dazu: 1. Ich setze mal voraus, daß sowohl bei 0°C als auch bei 20°C das Rauschen im ADC-Rohwert gleich ist (1 bis 2 LSBs). Dann macht es Sinn, den ADC-Rohwert zu tiefpaßfiltern, mit PT1 oder MovingAverage, um das statistische Rauschen zu entfernen. PT1 z.B. so:
1 | gefiltert = gefiltert * (1.0 - faktor) + rohwert * (faktor); |
mit faktor = 0.0 bis 1.0 Die Filterfrequenz ergibt sich aus dem "faktor" und dem Zeitraster, wie oft Du den Filter rechnest. 2. Lege beim Loggen eine Hysterese fest, also der aktuelle Werte muß sich um x zum Vorgänger verändert haben, damit Du ihn loggst. Wenn Du die Hysterese relativ zum Meßwert nimmst (als Prozentwert), löst sich auch Dein Problem, daß Du über den Meßbereich unterschiedliche Stabilität der Stellen hast. Z.B. so:
1 | if ( (aktuell > (alt * 1.05)) || (aktuell < (alt * 0.95)) ) |
ergibt 5% "Hysterese". PS: Ich hab zur Verständlichkeit einfach mal Fließkomma hingeschrieben, aber das ganze läßt sich natürlich auch einfach als Fixkomma implementieren.
Mir ist gerade aufgefallen, dass mein Code oben gar keine Hysterese ist, sondern im Prinzip nur rundet. Negative Zahlen sogar falsch ... Richtig wäre es so:
1 | #define RESOLUTION 250
|
2 | |
3 | void temp_log_task(void) |
4 | {
|
5 | static int logged = 0; |
6 | int now = get_temp(); |
7 | int diff = now - logged; |
8 | if (diff >= RESOLUTION || diff <= -RESOLUTION) { |
9 | logged = now; |
10 | // Wert runden (optional)
|
11 | int offset = RESOLUTION / 2; |
12 | offset = (logged < 0) ? -offset : offset; |
13 | logged = ((logged + offset) / RESOLUTION) * RESOLUTION; |
14 | // Wert speichern
|
15 | log_temp(logged); |
16 | }
|
17 | }
|
Michael Reinelt schrieb: > Dort ist die grenzfrequenz 1/(2*Pi*R*C). > > Gibts was "vergleichbares" für das PT1-Glied? Hängt dort natürlich von > der Abtast-Frequenz ab... Klar gibt es das: Im einfachsten Fall ist die Abtastfrequenz viel größer als die Zeitkonstante R*C. Beim PT1-Glied ist die Anfangssteigung gleich der Zeitkonstante. -> Beim digitalen Regler ist der Anteil neu zu alt gleich dem Verhältnis Abtastzeit zu Zeitkonstante. Beispiel: Die Zeitkonstante R*C = 160 ms die Abtastrate = 10 ms. PT1,neu = PT1,alt + 10ms/160ms*(Messwert,neu - PT1,alt) Wobei sich der Wert 1/16 einfach durch 4*Rechtsshift ergibt. Die Grenzfrequenz wird genauso wie beim analogen Beispiel aus der Zeitkonstante berechnet. Gruß Anja
Bronco schrieb: > Wenn Du die Hysterese relativ zum Meßwert nimmst (als Prozentwert), > löst sich auch Dein Problem, daß Du über den Meßbereich unterschiedliche > Stabilität der Stellen hast. Wenn du das bei der Temperatur machst, erübrigt sich die relative Hystere von selbst, weil der Messwert allermeist im Bereich 250 .. 300 K liegt, d.h. sich nur über einen überschaubaren Bereich von knapp 20% ändert. Oder welcher Temperaturbezugspunkt schwebte dir vor? Und wieso gerade der?
Michael Reinelt schrieb: > 04.02.2013 04:09:18 X_T_AUL -792 > 04.02.2013 04:09:27 X_T_AUL -904 > 04.02.2013 04:10:02 X_T_AUL -792 > 04.02.2013 04:10:11 X_T_AUL -904 > 04.02.2013 04:10:37 X_T_AUL -792 Das sieht mir doch sehr periodisch aus, als ob da irgendetwas mit der Datenerfassung nicht stimmt. So gleichmäßig schwankt die Sonne selten. Ist das auch über längere Zeiträume so?
Wie wär's mit einem Median-Filter. Dann bleiben alle Stellen erhalten aber das Zittern verschwindet (vielleicht bei geeignetert Länge). Obwohl der Median eigentlich besser gegen Außreißer geeignet ist.
genau Laura! hier endet die Diskussion, wo sie gerade anfängt interessant zu werden. (Deshalb mein Kommentar auch ein halbes Jahr später) Selbst wenn man davon ausgeht, daß in jeder Schwingung (gezappel) Info steckt, sollte man nach meiner langjährigen Erfahrung grundsätzlich einen Mittenwertfilter einsetzen bevor man die Ergebnisse mit o.g. Verfahren weiterverarbeitet. Über eine Eliminierung der Störeinflüsse reden wir hier nat. nicht. Ungewollte, unperiodische Spitzen lassen sich nicht immer vermeiden. Ich benutze gerne einen 1 aus 3 Spike(?)-Filter. Mit den Begriffen kenne ich mich nicht so gut aus, aber am besten ich hänge mal eine C-Funktion zum Verständnis an. Ich würde gerne lesen, daß jemand das effektiver schreiben kann. Von der Funktion bin ich allerdings mehrfach überzeugt worden. Gerade, wenn man auf fast jedes Sampeln angewiesen ist, kenne ich gar keine andere vernünftige Filterung als Alternative. Aber auch mit mehr Verarbeitungszeit zur Verfügung und nur einen Durchlauf (i=1)der Funktion kann man das Ergebnis rekursiv wieder zur "Vorqualifizierung" benutzen. Wie gesagt, was hier Standardbegriffe angeht, bin ich ungebildet. Deshalb nenne ich es mal einen rukursiven Mittenwertfilter: Man "füttert" die Funktion "Mitte" dann nur noch mit Werten, die dem vorherigen Ergebnis angenähert wurden. einfaches Bsp.: Messergebnis = Mitte(Messplatz_1, ((Messergebnis+ADC_Wert)/2), 1); schön schnell, wenn auch nicht gerade Data Memory-sparend, selbst wenn man int32_t entsprechend anpasst. Und dann kann das eigentliche Filtern losgehen. Viel Spaß und nicht ärgern lassen P.
Wolfgang schrieb: > Michael Reinelt schrieb: >> 04.02.2013 04:09:18 X_T_AUL -792 >> 04.02.2013 04:09:27 X_T_AUL -904 >> 04.02.2013 04:10:02 X_T_AUL -792 >> 04.02.2013 04:10:11 X_T_AUL -904 >> 04.02.2013 04:10:37 X_T_AUL -792 > > Das sieht mir doch sehr periodisch aus, als ob da irgendetwas mit der > Datenerfassung nicht stimmt. So gleichmäßig schwankt die Sonne selten. > Ist das auch über längere Zeiträume so? Es kann auch schlicht durch die Umrechnung kommen: X_T_AUL=k1*T+k2 wobei T der physikalische Meßwert ist. Wenn man die Koeffizienten ausrechnet (X_T_AUL einfacherhalber positiv benutzt), ergibt sich ja: k1=112 k2=8 und T dann in Einzelschritten Wenn du die Daten reduzieren willst, speichere also den Wert T und nicht X_T_AUL ! Hm. Stoff der 7.Klasse "Lineare Gleichung"
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.