Arduino Thermistor Program: subtraction gives wrong number.

Thread Starter

NathanielZhu

Joined Dec 5, 2011
50
I'm writing my own thermistor program that obtains the resistence of the thermistor in a voltage divider using E = Ei (R1/R1+R2) and solving for R1.
I think the code for obtaining the resistence works fine.

Then, I found a comparable resistence/temperature table and I am storing the table into two arrays. One to hold the resistence and the other to hold the temperature.

Ok.

Here's where it messes up. I want to iterate through the length of the array take the difference between my thermistor resistence and the resistences of the table. I take the absolute value of the difference. The smallest difference means that it is closest to the true value of the thermistor. So, I take the index of the resistence closest t the thermistor resistence and plug that index into another array which contains the equivalent temperature that corresponds to the index.

PROBLEM IS: When I subtract the resistence of the thermistor with the resistence in the array, I get absolutely BRAIN DEAD STUPID numbers like Arduino failed kindergarden.
ex: 120000 - 320000 = +16000 or 120000 - 285000 = -32000.
WTF.

I tried using various data types: int, double, and float and I get the same weird result.

Here's my code using doubles:
I have taken a picture of the Serial Monitor Output.

C:
int thermPin = A0;
int tOutputTableF[] = {37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113};
int tOutputTableO[] = {302466,285206,269035,253877,239664,226331,213819,201971,190946,180588,170853,161700,153092,144992,137367,130189,123368,117000,110998,105338,100000,94963,90208,85719,81479,77438,73654,70076,66692,63491,60461,57594,54878,52306,49847,47538,45349,43273,41303};
int temperature = 0;
int finalIndex = 0;
void setup()
{
  pinMode(thermPin, INPUT);
  Serial.begin(9600);
}
void loop()
{
  double x = analogRead(thermPin);
  double y = ((5.0/1023.0)*x);
  double z = ((y*100000.0)/(5.0*(1-((y/5.0))))); //Get the Resistence of the Thermistor
  //Estimate temperature based on temperature-resistance table
  int indexA;
  int indexB;
  int difference1;
  int difference2;
  boolean first;
  double cat = 0;
  for(int i = 0; i<40; i++)
  {
    //Calculate resistence difference
    int indexAValue = tOutputTableO[I];
    int indexBValue = tOutputTableO[i+1];

    difference1 = (z - indexAValue); // Subtraction values are ALL WRONG by a huge magnitude.
    difference2 = (z - indexBValue); //all wrong

    double d1 = abs(difference1);
    double d2 = abs(difference2);
  
    Serial.println(i);
    Serial.println(z);
    Serial.println(difference1);
    Serial.println(difference2); 
    if(d2<d1)
    {
      finalIndex = i+1;
      //Serial.println(finalIndex);
      //cat = d2;
    }
  }
  temperature = tOutputTableF[finalIndex];
  delay (1000);
}
Used code tags for c
 

Attachments

Last edited by a moderator:
If you have an ordered list (increasing or decreasing) then you should just do a binary search.

Say you had 100 numbers. I sometimes bump it up to 128 ( a power of 2)
So, 1-64 amd 65-100
Whach half is it in?
Say 1-64
Divide by 2
1-32 and 33 to 64
Which half is it in
Say 33-64
div by 2
33+32 or 33 to 64?
Which half is it in?
Etc

The padding to a power of 2 initially makes the splitting easier even if it's not splitting in half.
 

Thread Starter

NathanielZhu

Joined Dec 5, 2011
50
If you have an ordered list (increasing or decreasing) then you should just do a binary search.

Say you had 100 numbers. I sometimes bump it up to 128 ( a power of 2)
So, 1-64 amd 65-100
Whach half is it in?
Say 1-64
Divide by 2
1-32 and 33 to 64
Which half is it in
Say 33-64
div by 2
33+32 or 33 to 64?
Which half is it in?
Etc

The padding to a power of 2 initially makes the splitting easier even if it's not splitting in half.
Yeah good idea, I'll try that next, but I'm still wondering why my linear search is messing up.
 

djsfantasi

Joined Apr 11, 2010
9,163
Your subtraction is mixing types. You are subtracting an integer from a double. Sometimes this works; sometimes it produces crap. And then assigning it to an integer.

First, what is the range of numbers in your table? For z? An integer maxes out at 32767.

You can try casting indexAValue to a double. And then making the difference variables double also.
Code:
Double difference1 = 0;

difference1 = (z - double(indexAValue));
 

djsfantasi

Joined Apr 11, 2010
9,163
Just noticed a typo in your posted code in your search logic. One member of the array is indexed by 'I' and the other by 'i'. Two different variables? Depends on the compiler.

Ok, one more thing. tOutputTableO is defined as int, but it's values are out of range for int. It should be defined as long and references to it should be long, too.

In general, your data types are randomly assigned. AnalogRead returns an int( you are assigning it to a double. I don't trust implied casting...
 
Last edited by a moderator:

be80be

Joined Jul 5, 2008
2,072
I've read about this two time on the arduino forum and your code looks like its doing the same thing I tried to find where they show how it messing up I'll look some more but it's something to do with overflow if you do you end up with crazy numbers.
I just can remember how it was fixed .
Something to do with it using the first number size and not the foat size to hold the answer.
 

djsfantasi

Joined Apr 11, 2010
9,163
Exactly. If you don't explicitly cast the type that you want the calculation done with, the compiler may use the wrong type. It's just easier to cast variables when performing mixed arithmetic.

Casting means converting a variable to the desired type. That's what I did to indexAValue in my example.

Also don't forget that tOutputTableO is defined as an int and initialized with values that are too large.
 

be80be

Joined Jul 5, 2008
2,072
I found the link to Nick Gammons site maybe it will help you http://www.gammon.com.au/forum/?id=12146
It shows stuff that happens and why
C:
void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  Serial.println (30000 + 30000); // twice 30000
  Serial.println (60 * 60 * 24);  // seconds in a day
  Serial.println (50 / 100 * 1000); // half of 1000
  }  // end of setup

void loop () { }
You'd think you would get this
60000
86400
500
But you don't it prints this out
-5536
20864
0
I played with it a bit and tried it with a calculator and it did the same thing using programmer mode

Changed code tags to C
 
Last edited by a moderator:

djsfantasi

Joined Apr 11, 2010
9,163
I would have guessed the second set of results.
Can't prove the first one, but since int overflows at 32767 and 30000 is less, it will try to use integer as operands. The negative comes from the high bit being set and the remaining bits must form the ones complement of 5536.
The second example is a little easier to explain. The result of the operations are 86400. An unsigned int maxes out at 65,536. Due to overflow, subtract the two numbers and voila, you get your number.
The third is easiest. Without parentheses, the order of operations is not what you expect. You are dividing 50 by 100,000, which as an integer is 0. Note this holds true in algebra as well. PEMDAS. Multiplication is performed before division!

So basically, always use parentheses to code what you mean. In a mixed type calculation, cast all variables in the calculation to a common type and then cast the final value to the desired result.
 
Top