Float vermeiden, ADC-Ergebnis umrechnen?

Gast #2113727
Lesenswert?

Hallo,

mein 24 bit DAC liefert 0,5  VREF  2^23 -1 als "Vollausschlag". Mein 
Drucksensor liefert eine bestimmte Spannung unterhalb von 0,5 * VREF als 
Vollausschlag.

Jetzt würde ich gerne das Ergebnis (steht in einem int32_t) zur 
Displayausgabe in die physikalische Einheit umrechen (hier Druck, 
Pascal). Dabei würde ich gerne auch zwei Kommastellen ausgeben!

Wie mache ich das am besten, ohne float benutzen zu müssen? Den Artikel 
über Festkommaarithmetik habe ich mir durchgelesen, aber nicht ganz 
verstanden.

Der direkte Zusammenhang zwischen physikalischer Größe und DAC 
Datenregister
wäre:

druck = dac / 56,1486412316

Danke schonmal für Tips in die richtige Richtung.
#2113736
Lesenswert?

Als Tip, wo du noch etwas selber rechnen musst:

Den Wert teilen durch 56 ist ja zu ungenau, durch de exakten
Wert teilen geht nicht ohne Gleitkommarechnung.
Also ein kleiner Umweg: durch 56.1486412316 teilen ist
dasselbe wie mit 0.01780987 multiplizieren. Das sieht zwar
auch nach Gleitkomma aus, aber man kann ja auch mit
0.1780987 multiplizieren und sich mekren, daß das Ergebnis
um 10 zu groß ist, oder mit 1.780987 und sich den Faktor 100
merken, oder mit 17.80987 multiplizieren und 1000 merken...

Dein AD-Wert nutzt die 32 Bit ja nicht aus. Also kannst
du sehen, wie weit du das obige Spiel treiben kannst, bevor
die 32 Bit nicht mehr reichen.
Mit der größtmöglichen Zahl multiplizierst du jetzt (ganzzahlig),
konvertierst z.B. mit ultoa() in einen String und gibst den aus,
allerdings mit einem eingefügten Dezimalpunkt oder Komma an der
Stelle, die sich aus dem gemerkten Korrektutfaktor ergibt (z.B.
4. Stelle von hinten bei 10000).
Gast #2114231
Lesenswert?

Danke für den Tip. Aber von 24 bit bis 32 bit sind ja nur 8 bit 
Unterschied, der maximale Faktor also 256. Oder vertue ich mich da? Dann 
könnte ich maximal mit 178 multiplizieren und dann durch 100 teilen. 
Wenn ich das richtig sehe, hätte ich dann meine zwei Dezimalstellen, 
oder? Wenn auch mit einem leichten Rechenfehler.
Gast #2114257
Lesenswert?

Ruben schrieb:
> Danke für den Tip. Aber von 24 bit bis 32 bit sind ja nur 8 bit
> Unterschied, der maximale Faktor also 256. Oder vertue ich mich da? Dann
> könnte ich maximal mit 178 multiplizieren und dann durch 100 teilen.

Rechnerisch sind das nur 8 Bit, praktisch wette ich, daß du mindestens 
16 bit Unterschied nutzen kannst.

Die Hardware, die an einem 24-Bit-AD-Wandler auch noch das letzte Bit 
sinnvoll nutzbar macht, möchte ich sehen. Vermutlich enthalten die 
unteren 8 bit nur reines Rauschen.

Oliver
Gast #2114515
Lesenswert?

Ich habe das so verstanden:

(2^23-1) / 56,1486412316 Pa

 = 8388607 / 56,1486412316 Pa
 = 149400,00 Pa
 = 1494,0000 hPa

Das ist zwar für Luftdruck ein bisschen hoch, aber man braucht ja noch 
Reserven :-)

@Ruben
Überleg dir aber mal:
- wieviel Volt diese Nachkommstellen haben?
- welche Genauigkeit hat der ADC?
- wie ist der ADC kalibriert?
- wie hoch ist das Rauschen?
- welche Genauigkeit hat der Sensor?

Die Unsicherheit bei (Spitzen-)Kalibrierlaboratorien liegt bei ca. 0,02 
hPa im atmosphärischen Bereich.

Du wirst die Nachkommstellen nicht wirklich brauchen.
Gast #2114658
Lesenswert?

Moin DAC hat einen Bereich von -2,5V bis 2,5V. Mein Sensor liefert aber 
nur +/- 200mV bei Vollausschlag. Wenn ich den Ausgangswert durch 56 
teile, gehen Informationen verloren. Die Nachkommastellen würden schon 
noch ziemlich stabil bleiben. Mir geht es nicht um absolute Genauigkeit, 
sondern hauptsächlich um Auflösung. Ich muss den Zeitpunkt und die 
ungefähre Amplitude von kleinen Drucksprüngen auswerten.
Gast #2114690
Lesenswert?

Naja, es ist ganz einfach. Mache ein Beispiel mit 16bit 
Festkomma-Aritmetik,
sollte der Compiler long long beherrschen (multiplication) dann kannst 
du auch 32.32bit Festkomma-Aritmetik machen.

Beispiel dac/adc result = 100
wird dividiert durch 56,1486412316
Hier ist es vereinfacht, man muß auch gegenrechnen,
z.B. macht (float)(0xffff)/(unsigned int)(0xffff/56.1486412316)
56.1576692373607540702656389032 und nicht 56.1486412316
hier würde man den Fehler ausbessern, indem man
value=value*1167+value>>7 macht, als Beispiel um den Fehler von
0.009028... bei der Division auszubessern. Diese Sachen sind meist
Handoptimiert, oder man nimmt einen generelle fixnum lib.

Zuerst mal wird die division in eine Multiplication umgewandelt.
Hier da 16 bit Fixmath wird 0xffff verwendet.
Wegen mycast sowie high/low bin ich mir unsicher ob das so funktioniert,
kann mittels union, ... gemacht werden, prinzipiell ist es so aber 
einfacher
zu verstehen. high(value) => (value>>16) -- low(value) ==(value&0xffff)

int32_t value;
#define mycast(x,type,offset) ((uint[])(unsigned int)&x)[offset]
#define high(x) mycast(x,uint16_t,0)
#define low(x) mycast(x,uint16_t,1)
#define DIV(x) (unsigned int)(0xffff/(x))
value=100;
value *= DIV(56.1486412316);
printf("%d",high(value)); high(value)=0;
if(value)
for(printf(",");value;high(value)=0)value*=10,printf("%01d",high(value)) 
;
Gast #2115218
Lesenswert?

Ruben schrieb:
> Moin DAC hat einen Bereich von -2,5V bis 2,5V. Mein Sensor liefert aber
> nur +/- 200mV bei Vollausschlag. Wenn ich den Ausgangswert durch 56
> teile, gehen Informationen verloren. Die Nachkommastellen würden schon
> noch ziemlich stabil bleiben. Mir geht es nicht um absolute Genauigkeit,
> sondern hauptsächlich um Auflösung. Ich muss den Zeitpunkt und die
> ungefähre Amplitude von kleinen Drucksprüngen auswerten.

Du willst 2 Stellen hinter dem Komma, also (Pseudocode):

result = ADCvalue * 100

Da dein ADC-Ergebniss weniger als 20 Bit hat (0,2V von 2,5V), gibts 
keinen Überlauf.

result = result/56

alle anderen digits in deinem Faktor machen weniger aus, als die 2 
Stellen hinter dem Komma anzeigen können.

dann

print result/100
print ','          // oder '.'
print result^100   // Modulo

MfG Klaus

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