简体   繁体   中英

16 bit hex into 14 bit signed int python?

I get a 16 bit Hex number (so 4 digits) from a sensor and want to convert it into a signed integer so I can actually use it. There are plenty of codes on the internet that get the job done, but with this sensor it is a bit more arkward.

In fact, the number has only 14 bit, the first two (from the left) are irrelevant. I tried to do it (in Python 3) but failed pretty hard. Any suggestions how to "cut" the first two digits of the number and then make the rest a signed integer? The Datasheet says, that E002 should be -8190 ane 1FFE should be +8190.

Thanks a lot!

Let's define a conversion function:

>>> def f(x):
...    r = int(x, 16)
...    return r if r < 2**15 else r - 2**16
... 

Now, let's test the function against the values that the datahsheet provided:

>>> f('1FFE')
8190
>>> f('E002')
-8190

The usual convention for signed numbers is that a number is negative if the high bit is set and positive if it isn't. Following this convention, '0000' is zero and 'FFFF' is -1. The issue is that int assumes that a number is positive and we have to correct for that:

  • For any number equal to or less than 0x7FFF , then high bit is unset and the number is positive. Thus we return r=int(x,16) if r<2**15.

  • For any number r-int(x,16) that is equal to or greater than 0x8000 , we return r - 2**16 .

  • While your sensor may only produce 14-bin data, the manufacturer is following the standard convention for 16-bit integers.

Alternative

Instead of converting x to r and testing the value of r , we can directly test whether the high bit in x is set:

>>> def g(x):
...    return int(x, 16) if x[0] in '01234567' else int(x, 16) - 2**16
... 
>>> g('1FFE')
8190
>>> g('E002')
-8190

Ignoring the upper bits

Let's suppose that the manufacturer is not following standard conventions and that the upper 2-bits are unreliable. In this case, we can use modulo, % , to remove them and, after adjusting the other constants as appropriate for 14-bit integers, we have:

>>> def h(x):
...    r = int(x, 16) % 2**14
...    return r if r < 2**13 else r - 2**14
... 
>>> h('1FFE')
8190
>>> h('E002')
-8190

There is a general algorithm for sign-extending a two's-complement integer value val whose number of bits is nbits (so that the top-most of those bits is the sign bit).

That algorithm is:

  1. treat the value as a non-negative number, and if needed, mask off additional bits
  2. invert the sign bit, still treating the result as a non-negative number
  3. subtract the numeric value of the sign bit considered as a non-negative number, producing as a result, a signed number.

Expressing this algorithm in Python produces:

from __future__ import print_function

def sext(val, nbits):
    assert nbits > 0
    signbit = 1 << (nbits - 1)
    mask = (1 << nbits) - 1
    return ((val & mask) ^ signbit) - signbit

if __name__ == '__main__':
    print('sext(0xe002, 14) =', sext(0xe002, 14))
    print('sext(0x1ffe, 14) =', sext(0x1ffe, 14))

which when run shows the desired results:

sext(0xe002, 14) = -8190
sext(0x1ffe, 14) = 8190

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM