swift - 如何使用 Swift 将一对字节转换为浮点数
问题描述
我正在使用本文通过 BLE 与 IoT 传感器进行通信。在文章中,提到了这句话:
前两个字节似乎不属于数据(可能是表示它是数据包的前缀),但其余的更有趣。对于加速度计,我们得到三个有符号的 16 位整数(小端序),可以简单地缩放到我们设置的范围以获得我们的设置序列。因此,带符号的 16 位整数的 +/-2^15 范围对应于 +/-16g,从而得到因子 1/2048。为了获得以 m/s² 为单位的加速度,我们应用了 9.81/2048 的系数。因此,相应的蓝牙部分显示为:
<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 代码:
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。我现在要做的是将对转换为双打。
例如:
values[2], values[3] = [250 255] (accXRaw)
values[4], values[5] = [199 249] (accYRaw)
values[6], values[7] = [91 191] (accZRaw)
在文章中,作者通过一个 int16 little endian 来做到这一点。我想对 swift 5 做同样的事情,但不确定我是否做得正确。这是我的代码:
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
这些数字看起来很奇怪,我怀疑我做错了什么。我是否正确阅读了字节对(至少与文章一致)?如果不是,我犯了什么错误?
解决方案
您的问题是您不应该使用 bitPattern 初始化程序和/或使用 UInt32(littleEndian:) 初始化程序来初始化 Float。您需要将这 2 个字节转换为 Int16,将其强制转换为 Float,然后乘以 9.81/2048 的因子以获得其加速度。
对此进行扩展,您可以创建一个数值初始化程序,该初始化程序采用符合 DataProtocol(数据或字节 [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 对象。
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
推荐阅读
- android - 如何在 Calllback 上切换 Kivy 布局?
- java - ReentrantLock - lock.unlock() 不释放锁
- python-3.x - 无法使用 XPATH python 从脚本标签中抓取 JSON
- java - Java - 如何编写遍历 Map 中 HashSet 值的迭代器
- numpy - 了解 numpy 中的分层抽样
- c++ - 无法运行简单的 std::async 和 std::future 测试程序。错误:“具有初始化程序但类型不完整。” 这是怎么回事?
- r - mlr 中的警告“NA 用作学习器参数缺失的默认值”是什么意思?
- python-3.x - Xgboost GPU predict 不断崩溃 Jupyter notebook Python 内核
- php - 值不等于折扣代码的文本框条目
- c# - 使用 C# 将原始数据发送到 USB 点阵打印机