Forum: Compiler & IDEs NTC - Steinhart-Hart -> -15605°C (Weltrekord?)


von Taucher (Gast)


Lesenswert?

Hallo Forum,

neulich habe ich eine wirklich saubere Funktionssammlung für NTCs von 
Davide Gironi gefunden welche Funktionen für Beta und auch 
Steinhart-Hart beinhaltet.
http://davidegironi.blogspot.co.at/2012/12/reading-temperature-on-avr-atmega-using.html

Ich wollte ausprobieren wieviel der Unterschied bei der Verwendung von 
Beta-Values und der Steinhart-Hart Methode ist.
Das Auslesen des ADCs liefert einen NTC-Widerstand von 9100Ohm (Was für 
einen 10k-Typen recht plausibel klingt.)

SH:
Mit den Koeffizienten von meinem 10k NTC-Sensor erhalte ich für 
gemessene 9100Ohm als Resultat 17434°C. Das ist ziemlich warm, ja fast 
Rekordverdächtig.

Beta:
Dann habe ich die Funktion für Beta probiert.
Diese liefert -15605°C!!!
Als Physiker würde ich jetzt den Nobelpreis beantragen.

Ich habe daraufhin mein Datenblatt verifiziert und das Beta-Value dort 
eingegeben: 
http://www.daycounter.com/Calculators/Steinhart-Hart-Thermistor-Calculator.phtml
Die Website berechnet mir 27°C für meinen Widerstand.

Offenbar rufe ich die Funktionen falsch auf.

Könnt ihr den Fehler erkennen?

Beta:
1
// Call
2
long l;
3
double d;
4
l = adc_getresistence(adc, 10000);
5
d = ntctemp_getB(9100.0, 3970, 25.0, 10000);
6
7
// Function
8
/*
9
 * get temperature using Beta Model Equation
10
 *
11
 * "adcresistance" adc resistence read
12
 * "beta" beta value
13
 * "adctref" temperature reference for the measuread value
14
 * "adcrref" resistance reference for the measured value
15
 */
16
float ntctemp_getB(long adcresistence, int beta, float adctref, int adcrref) {
17
  // use the Beta Model Equation
18
  // temperature (kelvin) = beta / ( beta / tref + ln ( R / rref ) )
19
  float t;
20
  t = beta / ( beta / (float)(adctref + 273.15) + log ( adcresistence / (float)adcrref ) );
21
  t = t - 273.15; // convert Kelvin to Celcius
22
  //t = (t * 9.0) / 5.0 + 32.0; // convert Celcius to Fahrenheit
23
  return t;
24
}

Steinhart:
1
// Call
2
long l;
3
double d;
4
l = adc_getresistence(adc, 10000);
5
d = ntctemp_getSH(adc_getresistence(adc, 10000), (double)1.123219e-3, (double)2.35988061e-8, (double)7.3295648e-10);
6
7
//Funktion:
8
/*
9
 * get temperature using the Steinhart-Hart Thermistor Equation
10
 *
11
 * "adcresistance" adc resistence read
12
 * "A", "B", "C" equation parameters
13
 */
14
float ntctemp_getSH(long adcresistence, float A, float B, float C) {
15
  // use the Steinhart-Hart Thermistor Equation
16
  // temperature (Kelvin) = 1 / (A + B*ln(R) + C*(ln(R)^3))
17
  float t;
18
  t = log( adcresistence );
19
  t = 1 / (A + (B * t) + (C * t * t * t));
20
  t = t - 273.15; // convert Kelvin to Celcius
21
  //t = (t * 9.0) / 5.0 + 32.0; // convert Celcius to Fahrenheit
22
  return t;
23
}

Freue mich schon auf euer Feedback.
Ein wirkliches Rätsel für mich...

Lg,
Tom

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Nur so nach dem Überfliegen: ist das Wandlungsergebnis vielleicht 'left 
justified'?

von STK500-Besitzer (Gast)


Lesenswert?

Welchen Wert liefert denn die "adc_getresistence()"?

von Helmut S. (helmuts)


Lesenswert?

Deine Berechnung ist übrigens falsch und deine Koeffizienten vermutlich 
auch.
Zeig mal bitte einen Link auf das Datenblatt.

von Oliver (Gast)


Lesenswert?

Solche Fragen beantwortet man mit Taschenrechner und Debugger. Genau für 
solche Probleme wurden die erfunden.

Am besten die Berechnungen in Einzelschritte zerlegen, duchsteppen, und 
schauen, was wo schief geht.

Das ist seit Menschengedenken Programmieralltag. Da musst du durch.

Oliver

von Taucher (Gast)


Lesenswert?

Von der Funktion adc_getresistence() bekomme ich folgenden Wert: 9320
Das klingt bei einem 10k NTC ganz normal.
Diesen Wert gebe ich an ntctemp_getB() oder ntctemp_getSH() weiter.

Das mit dem 'left justified' werde ich mir jetzt noch genauer ansehen.

Das Datenblatt hat Shibaura 
http://www.shibauraelectronics.com/html/products/p_sensor_pre_a.html 
leider nicht online. Ich müsste den Ausdruck einscannen...

@ Oliver, ja genau so debugge ich im Visual Studio auf dem PC. Mit einem 
µC ohne Debugschnittstelle, ohne Display ist das nicht so einfach, werde 
ich natürlich trotzdem bewerkstelligen wenn herauskommt, dass kein 
offensichtlicher Anfängerfehler vorliegt.

Danke so weit...
Lg,
Tom

von Peter II (Gast)


Lesenswert?

Taucher schrieb:
> @ Oliver, ja genau so debugge ich im Visual Studio auf dem PC. Mit einem
> µC ohne Debugschnittstelle, ohne Display ist das nicht so einfach, werde
> ich natürlich trotzdem bewerkstelligen wenn herauskommt, dass kein
> offensichtlicher Anfängerfehler vorliegt.

dann nimmt den code doch mal auf den PC und schau was dort rauskommt.

von Helmut S. (helmuts)


Lesenswert?

http://www.shibauraelectronics.com/html/pdf/products/thermistor.pdf

Da stehen aber nirgends die Faktoren A, B und C.
Woher haast du die?
Etwa selbst berechnet?

von Helmut S. (helmuts)


Lesenswert?

Hab jetzt meine Glaskugel augepackt.

Beachte die Skalierungsfaktoren in dem PDF.
http://assets.newport.com/webDocuments-EN/images/AN04_Thermistor_Calibration_IX.PDF

-->R=9100;A=1.123219e-3;B=2.35988061e-4;C=7.3295648e-8;

-->T=1/(A+B*log(R)+C*(log(R))^3)
 T  =

    300.29858

-->T1=T-273.15
 T1  =

    27.148583



Die Nagelprobe:

-->R=10000
 R  =

    10000.

-->T=1/(A+B*log(R)+C*(log(R))^3)
 T  =

    298.15

Das entspricht exakt 25°C.



Beachte, dass in Matheprogrammen und allgemein in englischsprachigen 
Ländern "log" zur Basis e ist, also dem deutschen "ln" entspricht. 
Vielleicht ist "ln" sogar nur in deutschsprachigen Ländern gebräuchlich.

von Helmut S. (helmuts)


Lesenswert?

Nachtrag zum Programm

Falsch:

  float t;
  t = log( adcresistence );
  t = 1 / (A + (B*t) + (C*t*t*t));
  t = t - 273.15; // convert Kelvin to Celcius


Richtig:

  float r, t;
  r = log( adcresistence );
  t = 1 / (A + B*r + C*r*r*r);
  t = t - 273.15; // convert Kelvin to Celcius

von Anette Schavan (Gast)


Lesenswert?

>Falsch:
>  float t;
>  t = log( adcresistence );
>  t = 1 / (A + (B*t) + (C*t*t*t));
>  t = t - 273.15; // convert Kelvin to Celcius


>Richtig:
>  float r, t;
>  r = log( adcresistence );
>  t = 1 / (A + B*r + C*r*r*r);
>  t = t - 273.15; // convert Kelvin to Celcius


Und warum? Wo ist der Unterschied? Ich kann keinen Fehler entdecken.

von Patrick C. (pcrom)


Lesenswert?

1
d = ntctemp_getB(9100.0, 3970, 25.0, 10000);
Warum gibs du 9100.0 - das musz doch einen LONG sein oder ???

von Karl H. (kbuchegg)


Lesenswert?

Patrick C. schrieb:
>
1
d = ntctemp_getB(9100.0, 3970, 25.0, 10000);
> Warum gibs du 9100.0 - das musz doch einen LONG sein oder ???

Wenn ein ordentlicher Funktionsprototyp vorhanden ist, dann weiß der 
Compiler schon, wie man aus einem double einen long macht.

von Karl H. (kbuchegg)


Lesenswert?

Im Ausgabecode könnte auch noch ein Fehler stecken.
Wenn man die Bytes eines double einer int-verarbeitenden Funktion auf 
Byteebene unterjubelt, dann werden da auch die schrägsten 'Ergebnisse' 
auftauchen.

-> kompletter, kombilierbarer Code

wenn sich da nichts findet, dann eben auf die Taschenrechnermethode. Mit 
einem bekannten Eingangswert am Taschenrechner die Sache durchrechnen, 
alle Zwischenergebnisse notieren (und checken ob das Endergebnis stimmt 
:-) und dann das ganze nochmal mit dem µC, wobei man dann eben auch die 
Zwischenergebnisse vergleicht. Zwischenergebnisse ansehen ist eine 
Technik, die sich seit 60 Jahren bewährt hat.

von Helmut S. (helmuts)


Lesenswert?

> Und warum? Wo ist der Unterschied? Ich kann keinen Fehler entdecken.
>

Weil du die Variable t falsch verwendet hast. Schau meinen Code an. Der 
stimmt. Deiner nicht.

t = log( adcresistence );

Das ist doch einfach nur falsch.

von Karl H. (kbuchegg)


Lesenswert?

Helmut S. schrieb:
>> Und warum? Wo ist der Unterschied? Ich kann keinen Fehler entdecken.
>>
>
> Weil du die Variable t falsch verwendet hast.


Na ja.
Falsch ist jetzt übertrieben.
t hat zwischendurch mal einen Wert, der nicht die Temperatur ist. Aber 
falsch ist es deswegen nicht. Die 'Gültigkeitsbereiche' von r und t 
überlappen sich nicht. Von daher ist es verzeihlich, die Variable in 
diesem kurzen Code mal kurz zu zweckentfremden um darin den log zu 
speichern.
Nachdem dann
1
   .... 1 / (A + (B * t) + (C * t * t * t))
berechnet wurde (mit t in der Funktion 'hält den Logarithmus'), kriegt t 
dann seine endgültige Bedeutung einer Temperatur.
1
   t = 1 / .....
und ab da wird dann der Logarithmus nicht mehr gebraucht.

Codemässig würde ich mal schätzen macht es keinen Unterschied, weil der 
Compiler beide Variablen aufgrund der Einfachheit des Codes nicht 
unbedingt anlegen muss, wenn er genügend Register frei hat.

von J.-u. G. (juwe)


Lesenswert?

Taucher schrieb:
1
(double)1.123219e-3, (double)2.35988061e-8, (double)7.3295648e-10);

Wie bereits Helmut S. halte auch ich die von Dir verwendeten 
Koeffizienten für falsch. Insbesondere die Zehnerpotenzen von B und C 
sind sehr ungewöhnlich.
Hier:
Beitrag "Re: NTC - Steinhart-Hart -> -15605°C (Weltrekord?)"
hat Helmut ja bereits plausiblere Werte aufgeführt.

Aber es muss noch ein anderer Fehler in Deinem Programm stecken, denn 
selbst mit den falschen Koeffizienten kommt ein anderer Wert raus, als 
von Deinem Programm berechnet.

von Helmut S. (helmuts)


Lesenswert?

Mit meinen Werten ist das Ergebnis richtig.

A=1.123219e-3
B=2.35988061e-4
C=7.3295648e-8

Ich verstehe gar nicht wo da jetzt noch ein Problem sein soll.

von J.-u. G. (juwe)


Lesenswert?

Helmut S. schrieb:
> Mit meinen Werten ist das Ergebnis richtig.
Ja eben, das sehe ich ja auch so.

> Ich verstehe gar nicht wo da jetzt noch ein Problem sein soll.

Das Problem ist, dass selbst mit seinen falschen Koeffizienten nach der 
Steinhart-Hart-Formel nie und nimmer 17434°C raus kommt. Hier teile ich 
die Meinung von Karl Heinz, dass die Ausgabefunktion fehlerhaft ist.

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
Noch kein Account? Hier anmelden.