Hallo, ich war scheinbar ausreichend geschickt, und habe bei meinem ADWandler (im ATMega128) ein Rauschen von unter einem Digit erreicht. Aber anstatt, das ich es jetzt geschafft hätte: Beim Wechsel des Eingangssignals über die Grenze zwischen zwei Digit kommt das restliche Rauschen zum Tragen. Das schaut dann z.B. so aus: _______ ___ __ __ ___ ______ Wenn man's sich anguckt, kann man prima erkennen, das es sich angenähert um eine Gerade handelt, und im Grenzbereich, das Rauschen halt zum hin und Herr springen führt. Wie kann ich das vermeiden? Was sind da die üblichen Techniken? Mein Gedanke: Eine Grenze an der dieser Effekt auftritt wird es immer geben. Ob es nun ein 1 Bit oder 100-Bit AD-Wandler ist, irgendwo ist nunmal eine Grenzen. Einen Mittelwert zu bilden führt auch nicht zum erfolgt, wenn sich das Signal längere Zeit im Grenzbereich aufhält, führt das auch am Ausgang des Mittelwertes zum springen. (Es geht um einen Temperatursensor --> alles ist langsam.) Die Lösung währe wohl eine Hysterese, per SW konstruiert, geht jedoch ein Bit des ADW dafür drauf. :-/ Das müsste ich mir dann wieder durch 2 oder 4 Wandlungen oder -ergenisse erkaufen kaufen. Jemand eine bessere Idee? evtl. Abtastrate senken? Was mir noch nicht ganz klar ist: FIR und IIR Filter. Kann man mit erträglichem Aufwand die Grenzfrequenz eines Filters bis unter 10Hz ziehen? Aber würde das tatsächlich das Problem lösen? Im Grenzfall (Eingang = exakt die Grenze zwischen 2 Digits + Rauschen) würde am Ende ja auch ein (geglättetes) Rauschen übrig bleiben. Danke für jeden Hinweis, Grüße Henning
Sauber, die unterspreichenfunktion hat meine Skizze gefressen: ich probiere es nochmal mit punkten: ....... ... .. . . .. ... .........
Das Rauschen um ein LSB kannst Du nicht vermeiden. Was Du tun kannst, ist einen Tiefpaß zu programmieren, indem Du eine größere Anzahl Messungen aufaddierst und das Ergebnis dann durch die Anzahl der Messungen teilst. Geht besonders einfach bei 256 Messungen, da dann das Ergebnis um genau eine Registerbreite von 8Bit verschoben ist und nur noch aus den höherwetigen Übergaberegistern gelesen zu werden braucht ohne noch die Division ausführen zu müssen.
Das bereits erreichte Resultat ist sehr gut. Ich wuerd's so lassen. Ausser man haette zuviel Bandbreite und koennte mitteln. Aber was bringt's ?
Du kannst das Umkippen des letzten Bits auch zeitabhängig machen. Wenn nur das letzte Bit klappert, über 5 Sekunden mitteln und dann Runden. Falls die Änderung mehr als 1 Bit ist, sofort durchgeben.
Danke schonmal für die Beiträge. Wie oben beschrieben hilft ein Filter nur bedingt: Wenn ein Mittelwert aus 5,6,5,6,5,6,5,6,5,6,5,6,5,6, gebildet wird, kommt dabei 5,5 raus --gerundet--> 6 kommt als nächstes eine 5, ist der mitterwert aber 5,47 raus --> 5 ein Rauschen bleibt also auch wenn die Messzeit länger wird, nur die Warscheinlichkeit, das sich das Eingangssignal um 5,5+Rauschen bewegt, sinkt dabei. Es ist tatsächlich nur das letzte Bit, welches sich bewegt. Und das auch nur, wenn der zu wandelnde Wert in den Bereich um eine Grenze zwischen zwei Digits bewegt. Ich denke der Tip von eProfi ist schon richtig: Ich werde wohl die Änderungsrate bestimmen müssen, und bei wenig Änderungen die Abtastrate künstlich senken.
Die Abtastrate muß nur so hoch sein, daß Du inklusive Filter noch eine effektive Messung auf 1...10 Sekunden machst. Schneller ändern sich Temperaturen meistens nicht oder es wäre nicht von Belang. Den ADC kannst Du somit alle beispielsweise 1...10 ms 1x single shot messen lassen. Die ADC-Wandelfrequenz kannst Du in dem Fall auch bis auf 50kHz senken.
Alles schön und gut... Den digitalen Restfehler kann man mit keiner Methode vermeiden. Wie ja bereits aus dem Beispiel um den Wert 5,5 gezeigt wurde ist immer, auch bei Mittelwertbildung, Rundung, geringer Abtastrate usw. bei digitaler Signalverarbeitung ein Restfehler durch Kippen des LSB vorhanden. Alle Kurvenglättungsmaßnahmen bringen sicher eine Besserung. In der Praxis wird aber der beste Weg sein, die Auflösung des AD-Umsetzers midestens ein oder zwei Digit höher zu wählen, als das gewünschte Messergebnis. Ebenso ist die Kenntnis über einen Erwartungswert manchmal hilfreich. Unerwartete Werte können dann verworfen werden. z.B. ist bei Aufheizvorgängen eine ansteigende Kurve zu vermuten. Aber gerade in Grenzbereichen, wo der Messwert relativ konstant bleibt, muss man mit dem digitalen Restfehler leben. Es gibt keinen Ausweg.
Das sauberste Verfahren: Kombination von Integration über möglichst mind. 8 Werte, dann Hysterese auf die 'Nachkommawerte' z.B. letzter an die Anwendung übertragener W. 135 solange neuer Mittelwert nicht um mehr als 0,6 ... 1,1 abweicht, wird kein neuer Wert an die Anwendung übergeben, d.h. volle Auflösung , aber stark reduziertes Pauschen. Die Hysterese bestimmt das 'Restrauschen' das natürlich nicht ganz zu vermeiden ist, zumal ja nicht alle Schritte eines Wandlers gleich sind (vgl Datenblatt)
Mein Ergebnis, mit dem ich sehr zufrieden bin: Wenn man zusätzlich die Abtastrate senkt, wird weiter die Wahrscheinlichkeit gesenkt, mit der sich der Messwert im Grenzbereich zwischen 2 Digits befindet (wie oben beschrieben). Danke an koe.
1 | #define MaxIBit 3
|
2 | //---Anzahl der Bit, mit der die Auflösung erhöht und wieder gefilter wird
|
3 | #define MaxI 1<<MaxIBit
|
4 | static uint16_t arr[MaxCh][MaxI] = { {0,0,0,0,0,0,0,0}, |
5 | {0,0,0,0,0,0,0,0}, |
6 | {0,0,0,0,0,0,0,0}, |
7 | {0,0,0,0,0,0,0,0} }; |
8 | static uint16_t arrsum[MaxCh] = {0,0,0,0}; |
9 | static uint8_t i = 0; |
10 | |
11 | uint8_t Ch; |
12 | |
13 | i = (i+1) % MaxI; |
14 | for (Ch=0; Ch<MaxCh; Ch++) |
15 | {
|
16 | arr[Ch][i] = ReadChannel(Ch) + eeprom_read_word(&eeChXOffset[Ch]); |
17 | uint16_t tmp; |
18 | tmp = 0; |
19 | uint8_t k; |
20 | for (k=0; k<(sizeof(arr[Ch])/sizeof(arr[Ch][0])); k++) |
21 | tmp += arr[Ch][k]; |
22 | if (abs(arrsum[Ch]-tmp) > MaxI) |
23 | {
|
24 | arrsum[Ch] = tmp; |
25 | TempChX[Ch] = tmp>>MaxIBit; |
26 | }
|
27 | }
|
Irgendjemand verbesserungsvorschläge?
Schau dir doch mal die Funktionsweise von Delta-Sigma-Wandlern an. Mit der entsprechenden Filterung wird die Auflösung erhöht (wenn im Eingangssignale "echtes weisses" Rauschen drinne wäre, dann hackst du die unnötigen Bits ab und das Ergebnis steht wie eine "1.000000000"...:o))) Der eogentliche Wandler hat dabei oftmals nur 1 Bit. Da hilft doch die Mathematik ein wenig weiter. Ansonsten wäre die Frage, welche Genauigkeit überhaupt nötig ist bzw. prinzipiell möglich wäre. Mit 1% Fehler im Sensor machen schon 8 Bit oftmals keinen Sinn. Und echte 12 Bit sind oftmals schon eine unüberwindliche Hürde, wenn reale Bauteile zum Einsatz kommen. Viel Spaß Thomas
Nach meinem Wissen gibt es keine Möglichkeit, das Wandlungsprinzip eines Delta-Sigma-Wandlers per Software zu erweitern, den schließlich wird in HW durch den Bitstream eine entsprechende Ladungsmenge in die Charge-Balance zurückgeführt, was man per Software nicht ersetzen kann. Mir geht es nur darum Temperaturänderungen zu erfassen (hohe Auflösung). Ob der Gemessene wert wirklich den physikalischen 22°C entspricht (Genauigkeit) ist für mich zwar wünschenswert aber nur zweitrangig. Grüße Henning
Es geht um die statistischen Methoden bei der Delta-Sigma-Wandlung, die sehr wohl in Software umgesetzt werden können. Welche Temperaturänerungen willst du denn erfassen und welche Sensoren verwendest du ? Temperaturmessung ist eine recht heikle Angelegenheit, wenn es wirklich kleine Änderungen bzw. hohe Genauigkeit betrifft. Evtl. eine passende Differenz-Vorverstärkung einsetzen. Ansonsten sieht das ganze doch schon recht ordentlich aus (+- 1 Bit)....
Mit Oversampling kann das Bitrauschen sogar zur Genauigkeitssteigerung ausgenutzt werden. TI beschreibt in einer Appnote (slaa323), wie mit dem ADC_12 der MSP430-Familie durch Oversampling mehr effektiv nutzbare Bits Auflösung gewonnen werden können. Ich nutze so etwas mit 256-fach-Oversampling, was mir vier zusätzliche Bits einbringt, die erfreulich stabil sind. Natürlich ist ein anständiges Schaltungsdesign hier erforderlich, auf einem "breadboard" wird das nicht funktionieren.
Thomas: Es geht mir eigentlich nur um den Lerneffekt. Das ganze ist eine Schaltung, mit der die Raumtemperatur gemessen wird, und darauf hin über ein Ventil der Fußbodenheizung der Regelkreis geschlossen wird. Die erreichte Auflösung ist also absolut unnötig, wenn man ehrlich ist! Alleine die Luftbewegungen im Raum haben einen erheblichen Einfluss auf den Messwert so, dass auch bei einer hohen Güte in der Signalverarbeitung eigentlich nix gescheites dabei raus kommen kann. Mir geht es eher darum möglichst viel über die Techniken und Möglichkeiten dahinter zu lernen, um für das nächsten Projekt neue Freiheitsgrade zu gewinnen. Aber zurück zum Delta-Sigma-Wandler: Das Prinzip basiert doch auf dem Vergleich des Messwertes mit einer Referenz. Das Ergebnis wird aufsummiert und dann über einen Komparator (1-Bit ADW) auf größer und kleiner entschieden. Dann entweder eine Ladungsmenge der Referenz zu- oder abgeführt. Eben dieser Informations-Stream hinter dem Komparator kann durch einen Decoder ausgewertet werden, und daraus der Messwert bestimmt werden. Am Ausgang (von HW zu SW in der MCU) ist dann aber doch eine Binärzahl, und kein Bitstream mehr. Wie meinst du, könnte man dort noch eine weiteren Dekodereinheit anschließen? Nocheinmal der Kreislauf? Mit einer Referenz2 verrechnen, aufintegrieren, Schwellwert prüfen, inc/dec(Referenz2). Man hätte wieder einen Bitstream, den man dekodieren könnte. Aber gewinnt man dadurch wirklich Auflösung? Rufus: Danke für den Hinweis auf das AppNote. Das gleitende Oversampling verwendet ich ja im Code bereits; doch im AppNote wird klar, das die 8 Samples effektiv 1.5bit bringen. Es müsste also eigentlich ausreichen, mit 4 Samples zu arbeiten. Dadurch würde eff. 1 bit gewonnen, das dann in der Hysterese wieder verbraucht werden kann.
Hier das neue Stück Code Die Geschwindigkeit bei größerem Oversampling Buffer wird erheblich Beschleunigt. Pro Kanal kostet das einen weiteren Speicherplatz (in diesem Fall uint16_t)
1 | #define MaxIbit 2
|
2 | #define MaxI (1<<MaxIbit)
|
3 | static uint16_t arr[MaxCh][MaxI] = { {0},{0},{0},{0} }; |
4 | static uint16_t arrsumA[MaxCh] = {0}; |
5 | static uint16_t arrsumB[MaxCh] = {0}; |
6 | static uint8_t i = 0; |
7 | uint8_t Ch; |
8 | |
9 | i = (i+1) % MaxI; |
10 | for (Ch=0; Ch<MaxCh; Ch++) |
11 | {
|
12 | arrsumB[Ch] -= arr[Ch][i]; |
13 | uint16_t ADCVal; |
14 | ADCVal = ReadChannel(Ch) + eeprom_read_word(&eeChXOffset[Ch]); |
15 | arrsumB[Ch] += ADCVal; |
16 | arr[Ch][i] = ADCVal; |
17 | if (abs(arrsumA[Ch]-arrsumB[Ch]) > (MaxI/2)) |
18 | {
|
19 | arrsumA[Ch] = arrsumB[Ch]; |
20 | TempChX[Ch] = arrsumB[Ch]>>MaxIbit; |
21 | }
|
22 | }
|
Eine recht gute Erklärung verschiedener Techniken ist bei Luminary in der AN01239 zu finden.
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.