-1

I have a function that takes in a 16 bit unsigned integer value and converts it to a double. The data comes from a temperature sensor (MCP9808) and the function converts it to degrees Celsius.

The function is defined as follows:

double convert_tempc(uint16_t data) {
    double temp = data & 0x0FFF;
    temp /=  16.0;
    if (data & 0x1000) temp -= 256;
    return temp;
} 

My question is, how can I perform the inverse of this series of operations?

I need a function to find the 16-bit value produced by this sensor that results in a given temperature in degrees Celsius.

Since the 16-bit value can only represent a finite number of values, I imagine the inverse function would need to find the nearest double that can be represented, and then perform the inverse conversion.

Is there any simple way to do this?

The function is written in C, but I will be implementing it in Python.

marco
  • 93
  • 1
  • 1
  • 7
  • "The function is written in C, but I will be implementing it in Python." Well, good luck, then do so, and ask again if you are having specific problems with that. A 16-bit integer is still just an integer, only with a limited maximum value. What's your question? – MisterMiyagi Oct 10 '16 at 04:59
  • I am not asking about converting the function to python, I am asking about finding the series of operations that would perform the functional inverse (take in a double, spit out the uint16_t). I am not worried about converting c to python. – marco Oct 10 '16 at 05:03
  • You mean reversing the operators? `-=` corresponds to `+=`, `/=` corresponds to `*=`; the bitwise operations just check ranges, but in a lossy way, so you cannot be exact anyways. Basically just apply the operators the other way around. `int(temp * 16) & 0xFFFF` should do. – MisterMiyagi Oct 10 '16 at 05:09
  • 1
    Strictly speaking, this function is not invertible because it loses the 3 most significant bits of `data`. However, if you don't care about those bits, or the sensor only returns data in the range `0 <= data <= 0x1fff` then inverting the function is straightforward. – PM 2Ring Oct 10 '16 at 05:22
  • 1
    @MisterMiyagi: That doesn't handle the sign bit correctly. But `int(temp * 16) & 0x1FFF` looks pretty good. :) – PM 2Ring Oct 10 '16 at 05:34
  • @PM2Ring You're right. Having sign bits inside of unsigned types always confuses me... – MisterMiyagi Oct 10 '16 at 05:51
  • @MisterMiyagi: Yes, handling unsigned integers can be a bit confusing in Python since it doesn't have an unsigned integer type, and (in Python 3) integers don't have a fixed bit length. – PM 2Ring Oct 10 '16 at 07:12

1 Answers1

1

Here's some code that verifies the formula proposed in the comments.

def u16_to_float(data):
    temp = data & 0x0FFF
    temp /=  16.0
    if data & 0x1000:
        temp -= 256
    return temp

def float_to_u16(temp):
    return int(temp * 16) & 0x1FFF

# test

for data in range(0x2000):
    temp = u16_to_float(data)
    u = float_to_u16(temp)
    assert u == data, (data, temp, u)

print('Ok')
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182