ADC Kalibrierung

#1288448
Lesenswert?

Guten Tag,

um bei einem ATmega16 (ADC) die Messgenauigkeit zu verbessern benutze 
ich folgenden Code:

ADC_Wert = ADC_Wert*0.964; funktioniert, bläht den Code aber auf.

ADC_Wert = ADC_Wert*247/256; das funktioniert nicht (denke das liegt am 
int                               Bereich)
ADC_Wert = (ADC_Wert*247)>>8; das funktioniert nicht (kommt nur murks 
raus)

bei float Deklarierung meckert der Kompiler
Da ich im Weiteren verlauf des Programms mit ADC_Wert als integer 
arbeite darf nicht nach String wandeln.

Da muss es doch einen eleganteren Weg geben?

Danke.
#1288469
Lesenswert?

Eric S. schrieb:
> Da habe ich schon mal gelesen, wenn ich das richtig sehe wird aus dem
> Integer ein String gemacht, brauche jedoch einen Zahlenwert.

Nein. Da wird kein String daraus gemacht.
Welchen Datentyp hat den ADC_Wert?
Ich vermute mal, das das bei dir ein int ist.

So jetzt nimm einfach mal an, dass ADC_Wert gleich 1024 sei.
1024 * 247 macht 252928

Autsch. Die maximale Zahl, die mit einem int darstellbar ist ist nur 
32767. Das Ergebnis der Multiplikation mit 247 ist also für einen int 
vieeeel zu gross.

Behoben wird das, indem man den Compiler zwingt die Multiplikation im 
Zahlenraum long oder unsigned long zu machen. Dann geht sich das aus.
Gast #1288486
Lesenswert?

Die Verwendung von Kettenbrüchen ermöglicht manchmal eine Verbesserung 
der Performance indem mit kleineren Brüchen, in 8-Bit oder 16- Bit 
Darstellung bei höherer Genauigkeit der Näherung gearbeitet wird.

Beispiel mit JavaScript:
http://www.henked.de/javascript/kettenbrueche.htm

Beispielsweise wird die Skalierung für eine Grafik einmal über einen 
Kettenbruch angenähert und dann kann man alle Elemente damit auf dem 
Display anzeigen. Oder wie im vorliegenden Fall wenn es zeitkritisch 
wäre.

Das Produkt im Zähler muss natürlich zuerst berechnet werden und darf 
keinen Überlauf provozieren. Weil der Kettenbruch konvergiert kann man 
die Genauigkeit wählen - hoffentlich.

Dies ist manchmal besser als einfach mit 100 oder 1000 zu multiplizieren 
was dann zu einem Überlauf führen kann.

>>ADC_Wert = (unsigned long) ADC_Wert*247/256;
Das ist finde ich relativ geschickt /256 und >>8 sollte vom Compiler her 
optimierbar sein, es muss aber
ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine 
höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird.
#1288493
Lesenswert?

Jorge schrieb:
> es muss aber
> ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine
> höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird.

Das steht hier aber anders:
http://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t
Diese Operatoren sind afaik gleichwertig und werden daher von links nach 
rechts ausgewertet.
Gast #1289027
Lesenswert?

Hi Falk,


>Ändert a) an dem Grundproblem der Festkommaarithmetik wenig und b)
>sollte der OP beim nächsten mal besser lesen. Dort steht ziemlich am
>Anfang was von Überlauf vermeiden.

Du hast natürlich Recht. Gerade beim AVR, der Multiplikation drauf hat. 
Bei einem kleinen PIC oder wie in meinem Fall einem 386SX ohne 
Coprozessor sieht es anders aus. Mein Ding musste Mehrkanaldaten 
anzeigen (ISA).

27/28  bietet eine gute Näherung (0.9643), man kann die Multiplikation 
mit dem Bruch in Assembler auf Additionen und Subtraktionen zurückführen 
und damit einen Überlauf von vorneherein vermeiden:

- Nenner subtrahieren solange bis das Ergebnis kleiner Null und 
mitzählen
- dann solange den Messwert addieren bis grösser Null und mitzählen

Also am Ende ist der Messwert 27mal addiert worden und der Nenner wurde 
so oft es geht abgezogen, der Rest bleibt. Dabei kommt es nie zu einem 
Überlauf.


Ein 386 schafft die Multiplikation und Division nicht in einem Takt 
sodass das Vorgehen eine mehr als doppelte Geschwindigkeit für die 
Darstellung der Fieberkurven brachte. Der Flaschenhals war dann das 
Löschen des Bildschirms (300ms) was über eine Änderung der Farbpalette 
einer der 16 VGA-Farben entschärft wurde. Das Löschen des gesamten 
Schirms wurde dann in 1/16 Abschnitten "hidden" erledigt.

Es hängt natürlich von der konkreten Anwendung ab, rechts Schieben ist 
wirklich sehr effektiv vor allem mit einem Barrel Shifter.

Gruss

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren