【问题标题】:Converting 4 uint_8 values to float in python在 python 中将 4 个 uint_8 值转换为浮点数
【发布时间】:2019-07-19 21:03:04
【问题描述】:

我正在开发一个通过蓝牙将传感器数据帧发送到主机的系统。主机运行一个处理传感器数据的 python 程序。传感器数据包含来自开发套件板上的 c 代码的 float(32) 值。这些值被分成 4 个字节(uint_8)。我想将这些值转换回 float32。我尝试了各种解决方案,但似乎都没有。有任何想法吗?

我尝试使用 struct.pack/struct.unpack 函数,但我要么误解了用法,要么有其他问题。 输入示例: [22, 132, 0, 0, 0, 0, 199, 230, 254, 255, 255....

def int2bytes(i):
    hex_value = '{0:x}'.format(i)
    # make length of hex_value a multiple of two
    hex_value = '0' * (len(hex_value) % 2) + hex_value
    return codecs.decode(hex_value, 'hex_codec')

def convert_from_byte(data):
    byte_array = [0]*4
    byte_count = 0
    float_count = 0
    data_size = len(data)
    data_float = [] * 247
    for i in range(data_size):
        byte_array[byte_count] = int2bytes(data[i])
        if(byte_count==3):
            byte_array = ''.join(byte_array)
            data_float[float_count] =struct.unpack('<f', byte_array)
            float_count += 1
            byte_count = 0
        byte_count += 1
    return data_float

我预计值在 0.005 左右,但可能会有很大差异。

【问题讨论】:

  • 明确一点,[22,132,0,0] 是第一个浮点数,[0,0,199,230] 是第二个浮点数,等等?
  • struct.unpack('&lt;f', bytes([22, 132, 0, 0])) 怎么样?它不需要int2bytes,你可以使用data[:4] - struct.unpack('&lt;f', bytes(data[:4])) - 然后得到data = data[4:]

标签: python python-2.7


【解决方案1】:

我认为您的输入不正确。直观地说,[22,132,0,0] 和 [0,0,199,230] 是完全不同的数字,第一个字节的高位为零,第二个字节为低位。

您可以使用以下方法轻松地将 4 个无符号字节转换为浮点数。在本例中,我将使用大端格式的 4 个字节来匹配 Wikipedia 中的第一个示例(参见 single-precision examples)。所以只是在[0, 0, 0, 1]中设置的低位位

import struct
>>>struct.unpack('>f', struct.pack('4B', *[0,0,0,1]))
(1.401298464324817e-45,)

所以打包 4 个字节,然后解包为大端浮点数。你可以用同样的方式做小端浮点数,只需颠倒输入和浮点字节序说明符。

>>> struct.unpack('<f', struct.pack('4B', *[1,0,0,0]))
(1.401298464324817e-45,)

当我尝试您的数据时,它与您所期望的完全不同,因此我怀疑您得到的输入是错误的。

data = [22, 132, 0, 0, 0, 0, 199, 230,]
>>> struct.unpack('<f',struct.pack('4B', *data[:4]))
(4.738350627267936e-41,)
>>> struct.unpack('<f',struct.pack('4B', *data[4:8]))
(-4.698754650455297e+23,)

所以一个结果是 38 个数量级太小,另一个是 26 个数量级太高。在任何情况下,一旦你弄清楚为什么输入被弄乱了,你就可以使用上述方法将字节转换为浮点数。

最后用同样的过程为列表中的所有字节创建一个浮点列表。

[struct.unpack('<f',struct.pack('4B', *data[i:i+4]))[0] for i in range(0, len(data), 4)]

【讨论】:

  • 非常感谢您回答我的问题。
  • 我的预测错了。我在考虑处理过的传感器数据。 [ 6.07065530e-03 2.17261743e-02 -2.90762056e-02 ..., -1.52583336e-04 7.74722648e-05 2.58271320e-05] 这更像是我所期待的。不过还差得很远。
  • 因此,如果列表中的值错误,我可以看到两种可能性。一个,现在似乎不太可能,是任何为您提供数据的浮点格式与最常用的格式不同。更有可能的是,在向您的应用程序传递数据的过程中发生了一些未知的事情。我希望是后者,尤其是因为第一个和第二个例子有很大的不同。
【解决方案2】:

你可以使用data[:4]得到四个数字,bytes()转换成字节,然后你就可以用struct。之后你可以把这四个数字剪掉-data = data[4:]

import struct

def convert_from_byte(data):

    results = []

    while data:
        part = data[:4]
        value = struct.unpack('<f', bytes(part))
        results.append(value[0])
        data = data[4:]

    return results

data = [22, 132, 0, 0, 0, 0, 199, 230, 254, 255, 255, 0]
convert_from_byte(data)

# [4.738350627267936e-41, -4.698754650455297e+23, 2.3509884213848822e-38]

您也可以使用range(len())data[i:i+4] 来使用可能更少的内存

def convert_from_byte(data):

    results = []

    for i in range(0, len(data), 4):
        part = data[i:i+4]
        value = struct.unpack('<f', bytes(part))
        results.append(value[0])

    return results

data = [22, 132, 0, 0, 0, 0, 199, 230, 254, 255, 255, 0]
convert_from_byte(data)

# [4.738350627267936e-41, -4.698754650455297e+23, 2.3509884213848822e-38]

这甚至可以写成列表推导式

def convert_from_byte(data):
    return [struct.unpack('<f', bytes(data[i:i+4]))[0] for i in range(0, len(data), 4)]

data = [22, 132, 0, 0, 0, 0, 199, 230, 254, 255, 255, 0]
convert_from_byte(data)

# [4.738350627267936e-41, -4.698754650455297e+23, 2.3509884213848822e-38]

【讨论】:

  • 是的,输入端的bytesstruct 干净。它得到了相同的答案,但这与他所期望的完全不同。
  • @Deepstop 值与预期的 0.005 有很大不同,即使我们使用 '&gt;f' 而不是 '&lt;f' 但也许预期是错误的 ;)
【解决方案3】:

为什么不用位运算符将 8 位推入 32 位浮点数

data_float += (byte_array[0] << 24)
data_float += (byte_array[1] << 16)
data_float += (byte_array[2] << 8)
data_float += (byte_array[3])
float_array[i] = data_float

【讨论】:

  • 这行不通。您只是将移位数字的整数值相加,这将产生错误的结果。
  • 这不是他要求的吗?传感器有一些 32 位浮点数,它转换为 4 个 8 位值以通过空中发送,并且需要重新加在一起以再次获得原始的 32 位数字。我并没有真正尝试修复原始代码,这与我用于 arduino 2.4ghz RF 传感器的功能相同
  • 如果浮点数是与字节数组联合的一部分,则该概念将在 C 中起作用。在你的回答中data_float 将是一个整数,就像byte_array 中的元素一样,但结果需要是一个浮点数。可能有一个库(通常有)可以在整数表示和内部浮点表示之间创建union,就像在 C 中一样,但它不会自动发生。
  • 关于 C 的更正。我稍微掩盖了 Python 语法/样式,但 Python 中的按位函数似乎与 C 中的相同/相似。我使用的一个传感器从一个返回浮点数带小数点后 2 位的温度读取器,它被转换为 32 位整数,切成 uint8 数组并使用无线电堆栈传输,我用按位函数重新组合它,但采用这样的模式。在有一个真正简单地将 int 返回到小数点后两位(例如:5515 变为 55.15)的函数调用之后,我想这里的关键是准确地知道小数位
  • 在这种情况下,字节是浮点表示。浮点的 32 位标准是 1 个符号位、8 个指数位和 23 位有效数(又名尾数),隐含前导 1 位。所以它不是从浮点转换,而是机器架构存储的浮点值。因此,仅仅重新组装这些位是不够的,还要说服 Python 将这些位视为浮点值。在您的示例中,您先将其转换为 32 位整数,然后再将其转换为 uint8
猜你喜欢
  • 1970-01-01
  • 2021-05-01
  • 2020-03-21
  • 2016-01-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2019-01-21
  • 2020-04-27
相关资源
最近更新 更多