Arduino Thermistor Program: subtraction gives wrong number.

Discussion in 'Embedded Systems and Microcontrollers' started by NathanielZhu, Nov 27, 2015.

  1. NathanielZhu

    Thread Starter Member

    Dec 5, 2011
    39
    2
    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.

    Code (C):
    1.  
    2. int thermPin = A0;
    3. 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};
    4. 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};
    5. int temperature = 0;
    6. int finalIndex = 0;
    7. void setup()
    8. {
    9.   pinMode(thermPin, INPUT);
    10.   Serial.begin(9600);
    11. }
    12. void loop()
    13. {
    14.   double x = analogRead(thermPin);
    15.   double y = ((5.0/1023.0)*x);
    16.   double z = ((y*100000.0)/(5.0*(1-((y/5.0))))); //Get the Resistence of the Thermistor
    17.   //Estimate temperature based on temperature-resistance table
    18.   int indexA;
    19.   int indexB;
    20.   int difference1;
    21.   int difference2;
    22.   boolean first;
    23.   double cat = 0;
    24.   for(int i = 0; i<40; i++)
    25.   {
    26.     //Calculate resistence difference
    27.     int indexAValue = tOutputTableO[I];
    28.     int indexBValue = tOutputTableO[i+1];
    29.  
    30.     difference1 = (z - indexAValue); // Subtraction values are ALL WRONG by a huge magnitude.
    31.     difference2 = (z - indexBValue); //all wrong
    32.  
    33.     double d1 = abs(difference1);
    34.     double d2 = abs(difference2);
    35.  
    36.     Serial.println(i);
    37.     Serial.println(z);
    38.     Serial.println(difference1);
    39.     Serial.println(difference2);
    40.     if(d2<d1)
    41.     {
    42.       finalIndex = i+1;
    43.       //Serial.println(finalIndex);
    44.       //cat = d2;
    45.     }
    46.   }
    47.   temperature = tOutputTableF[finalIndex];
    48.   delay (1000);
    49. }
    50.  
    Used code tags for c
     
    Last edited by a moderator: Nov 28, 2015
  2. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    your Overflowing an integer.
     
  3. KeepItSimpleStupid

    Well-Known Member

    Mar 4, 2014
    1,146
    204
    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.
     
  4. NathanielZhu

    Thread Starter Member

    Dec 5, 2011
    39
    2
    Are you sure? I've already tried changing everything to doubles and floats so that my code only has doubles or floats.
     
  5. NathanielZhu

    Thread Starter Member

    Dec 5, 2011
    39
    2
    Yeah good idea, I'll try that next, but I'm still wondering why my linear search is messing up.
     
  6. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    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 (Text):
    1.  
    2. Double difference1 = 0;
    3.  
    4. difference1 = (z - double(indexAValue));
    5.  
     
  7. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    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: Nov 28, 2015
  8. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    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.
     
  9. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    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.
     
  10. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    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
    Code (C):
    1. void setup ()
    2.   {
    3.   Serial.begin (115200);
    4.   Serial.println ();
    5.  
    6.   Serial.println (30000 + 30000); // twice 30000
    7.   Serial.println (60 * 60 * 24);  // seconds in a day
    8.   Serial.println (50 / 100 * 1000); // half of 1000
    9.   }  // end of setup
    10.  
    11. 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: Nov 28, 2015
  11. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    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.
     
Loading...