2

I have a function in Python that reads a ds18b20 temp sensor. The sensor gives me a faulty value (-0.062) about 5% of the time that I read it. This is not a problem but I do not want to log the value since it looks ugly in my graphs.

I can't manage to "catch" the value in an if-statement to replace it with "#error". The code below runs nicely but it appears that the if-statement is faulty and does not work - it just runs everything under the else.

I have tried everything, even "catching" all values between 1000 and 1500 (present temperature reading before dividing by 1000) to check if it would work with any temperature, but it does not.

Does anyone have any idea why my if-statement does not work?

 def readtwo():
    tfile = open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave")
    text = tfile.read()
    tfile.close()
    secondline = text.split("\n")[1]
    temperaturedata = secondline.split(" ")[9]
    temperature = float(temperaturedata[2:])
    temperature = temperature / 1000
    if temperature  == -0.062:
            return("#error")
    else:
            return(temperature)
4
  • 3
    float comparisons are inaccurate. You're better off comparing the integer value you get back before you convert it to a float (e.g. if temperaturedata[2:] == '-62': ...) Commented Jan 29, 2013 at 0:47
  • Have you seen the decimal module? Commented Jan 29, 2013 at 0:47
  • @nneonneo why don't you just make that an answer? Commented Jan 29, 2013 at 0:55
  • Do you have an example of the text variable that has the error you mention? I think then people can help you better. Commented Jan 18, 2014 at 7:12

3 Answers 3

3

Testing base 10 floats for (in)equality is almost always the wrong thing to do, because they almost always cannot be exactly represented in a binary system.

From what I see of your snippet, you should compare against the string, then convert to float if it is not the dreaded -0.062:

def readtwo():
    tfile = open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave")
    text = tfile.read()
    tfile.close()
    secondline = text.split("\n")[1]
    temperaturedata = secondline.split(" ")[9]
    temperature = temperaturedata[2:]
    if temperature == '-0062':
            return("#error")
    else:
        temperature = float(temperature) / 1000
        return(temperature)
Sign up to request clarification or add additional context in comments.

5 Comments

Your division is in the wrong spot, or you need to compare against a different string
+1. But it's probably worth mentioning the more general solution of picking an epsilon: if abs(temperature - -0.062) < 0.0001: or if abs(temperature - 0.062)/0.062 < 0.0001:. The problem is knowing what's appropriate for your use case, and anyone who has even the faintest idea how to pick right already knows how to deal with floating point, so this isn't great advice without a link to What Every Computer Scientist Should Know About Floating-Point Arithmetic and the famous article about error analysis I forget the name of…
@wim: float("-0062")/1000 == -0.062 which is the value the OP doesn't want -- what am I missing?
@wim: ah, right -- probably no leading zero's in the text file; on the other hand, the OP didn't specify that portion, so maybe there are.
Yeah actually I just realised it's not really well-defined to look at that in the string space. Because the line could be like "-0062" or "-62" or " -62" etc., we don't really know and they would all parse to the same float value.
0

You might also be able to clean up the rest of the code a little:

def readtwo():

    with open("/sys/bus/w1/devices/28-0000040de8fc/w1_slave", 'r') as f:
        secondline = f.readlines()[1]
    temp = secondline.split(' ')[9][2:]

    if '-62' in temp:
        return '#error'
    else:
        return float(temp)/1000

Comments

-1

Regardless to my comment about the decimal module, floating point arithemitc has it's problems (in python as well). The foremost of which is that due to representation errors, two numbers that are equal on paper, will not be equal when compared by the program.

The way around it, is to look at the relative error between two numbers, rather than simply compare them.

in pseudo:

if abs(num1 - num2)/ abs(num2) < epsilon:
    print "They are close enough"

And in your case:

if abs(temparture + 0.062)/0.062 < 10**-3:
    return("#error")

Basically, we check that the numbers are "close enough" to be considered the same.

6 Comments

Why checking the relative difference instead of the absolute difference? Depending on the magnitude of num1, and the range of numbers we're dealing with, this could be massively sensitive.
@wim, I learned that checking the relative difference is usually a magnitude agnostic measure of closeness, because it also removes unit of measurement dependancies. An absolute error of 10^2 may seem bad, but not when you calculate the distance to the sun, and the relative error will indeed be small despite the "large" absolute error in that case.
I think you are misguided - for some applications, that can make sense. But for this case (temperatures) it is going to depend strongly on the range of values and the units of measurement. Consider for example the behaviour of your equation as num1 goes near to zero. Are we talking about 0 fahrenheit or 0 celsius here? The question changes results wildly.
@wim, the unit of measurement gets canceled out (i.e. the delta is in celsius, as is the denominator). Going to zero is a problem, but than I made an implicit assumption from the question that the range of values is not problematic. The inequality is quite correct, my mistake was in the first code block.
Yes, the unit gets cancelled out in the numerator/denominator, but the point is that the units changes the position of zero, which can be a problem here. That's why physicists like to use Kelvin, to avoid all this complications :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.