如何使用Swift将一对字节转换为Float [英] How to convert a pair of bytes into a Float using Swift

查看:234
本文介绍了如何使用Swift将一对字节转换为Float的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用本文通过IoT传感器与IoT传感器进行通信BLE.在文章中,引用了此报价:

I am using this article to communicate with an IoT sensor via BLE. In the article, this quote is mentioned:

前两个字节似乎不属于数据(可能是一个前缀,表示它是一个数据包),但其余字节更有趣.对于加速度计,我们得到三个带符号的16位整数(小端),可以将其简单地缩放到我们为获得设置序列而设置的范围.因此,带符号的16位整数的+/- 2 ^ 15范围对应于+/- 16g,从而导致系数为1/2048.为了获得以m/s²为单位的加速度,我们应用9.81/2048的因数.因此,相应的蓝牙部分显示为:

The first two bytes do not seem to belong to the data (probably a prefix to denote that it is a data packet), but the remaining ones are more interesting. For the accelerometer, we get three signed 16 bit integers (little endian), which can simply be scaled to the range we set up to get our setup sequence. So the +/-2^15 range of the signed 16bit integer corresponds to the +/-16g, resulting in a factor 1/2048. To get the acceleration in m/s², we apply a factor of 9.81/2048. So, the corresponding bluetooth part reads:

<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="2" length="2">accXRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="4" length="2">accYRaw</output>
<output char="326a9006-85cb-9195-d9dd-464cfbbae75a" conversion="int16LittleEndian" offset="6" length="2">accZRaw</output>

要阅读此代码,我正在运行以下Swift代码:

To read this code, I am running this Swift code:

private func sensor(from characteristic: CBCharacteristic) {
    guard let characteristicData = characteristic.value,
    let _ = characteristicData.first else { return }
    let data = characteristic.value!
    var values = [UInt8](repeating: 0, count: data.count)
    data.copyBytes(to: &values, count: data.count)
    print("values = \(values)")
}

打印后的结果是:

values = [3, 4, 250, 255, 199, 249, 91, 191]

与文章提到的一样,我可以确认前两个字节不属于任何数据,并且始终在重复.字节值[2-7]不断变化,这使我更加有信心,这两个对代表accXRaw,accYRaw和accZRaw.我现在想做的就是将两双转换为双打.

Alike the article mentions, I can confirm that the first two bytes do not belong to any data, and are consistently repeating. Bytes values[2-7] are constantly changing, which makes me more confident that the pairs represent accXRaw, accYRaw, and accZRaw. What I want to do now is convert the pairs to doubles.

例如:

values[2], values[3] = [250 255] (accXRaw)

values[4], values[5] = [199 249] (accYRaw)

values[6], values[7] = [91 191]  (accZRaw)

在本文中,作者通过int16小尾数来完成此操作.我想对swift 5做同样的事情,但是不确定我是否做对了.这是我的代码:

In the article, the author does this via a int16 little endian. I want to do the same with swift 5, but not sure if I am doing it correctly. Here is my code:

let xAxis = Float(bitPattern: UInt32(littleEndian: [values[2], values[3], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let yAxis = Float(bitPattern: UInt32(littleEndian: [values[4], values[5], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
let zAxis = Float(bitPattern: UInt32(littleEndian: [values[6], values[7], 0x00, 0x00].withUnsafeBytes { $0.load(as: UInt32.self) }))
    
print("x=\(xAxis), y=\(yAxis), z=\(zAxis)");

结果是:

values = [3, 4, 250, 255, 199, 249, 91, 191]

x=9.1827e-41, y=8.9603e-41, z=6.8645e-41

这些数字看起来很奇怪,我怀疑我做错了什么.我是否正确读取了字节对(至少与文章一致)?如果没有,我犯了什么错误?

These numbers just look weird, and I suspect I am doing something wrong. Am I reading the byte pairs correctly ( at least in line with the article ) ? If not, what mistakes did I make?

推荐答案

您的问题是您不应该使用bitPattern初始化程序和/或使用UInt32(littleEndian :)初始化程序来初始化Float.您需要将这2个字节转换为Int16,将其强制转换为Float,然后乘以9.81/2048的系数来获得其加速度.

Your issue there is that you are not suppose to initialize your Float using the bitPattern initializer and/or use the UInt32(littleEndian:) initializer. What you need is to convert those 2 bytes to Int16, coerce it to Float and then multiply by the factor of 9.81/2048 to get its acceleration.

对此进行扩展,您可以创建一个数值初始化器,该初始化器采用符合DataProtocol(数据或字节[UInt8])的对象:

Expanding on that, you can create a Numeric initializer that takes an object that conforms to DataProtocol (Data or Bytes [UInt8]):

extension Numeric {
    init<D: DataProtocol>(_ data: D) {
        var value: Self = .zero
        let size = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0)} )
        assert(size == MemoryLayout.size(ofValue: value))
        self = value
    }
}

然后,您可以使用子数据(两个字节)初始化Int16对象.

Then you can initialize your Int16 object with the subdata (two bytes).

let bytes: [UInt8] = [3, 4, 250, 255, 199, 249, 91, 191]
let xData = bytes[2..<4]
let yData = bytes[4..<6]
let zData = bytes[6..<8]

let factor: Float = 9.81/2048

let xAxis = Float(Int16(xData)) * factor
let yAxis = Float(Int16(yData)) * factor
let zAxis = Float(Int16(zData)) * factor

print("x:", xAxis, "y:", yAxis, "z:", zAxis)  // x: -0.028740235 y: -7.6305327 z: -79.27036

这篇关于如何使用Swift将一对字节转换为Float的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆