如何使用 Swift 将一对字节转换为 Float
How to convert a pair of bytes into a Float using Swift
我正在使用 this article 通过 BLE 与物联网传感器通信。在文章中,提到了这句话:
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代码:
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 { [=15=].load(as: UInt32.self) }))
let yAxis = Float(bitPattern: UInt32(littleEndian: [values[4], values[5], 0x00, 0x00].withUnsafeBytes { [=15=].load(as: UInt32.self) }))
let zAxis = Float(bitPattern: UInt32(littleEndian: [values[6], values[7], 0x00, 0x00].withUnsafeBytes { [=15=].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 初始化器 and/or 使用 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: [=10=])} )
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
我正在使用 this article 通过 BLE 与物联网传感器通信。在文章中,提到了这句话:
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代码:
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 { [=15=].load(as: UInt32.self) }))
let yAxis = Float(bitPattern: UInt32(littleEndian: [values[4], values[5], 0x00, 0x00].withUnsafeBytes { [=15=].load(as: UInt32.self) }))
let zAxis = Float(bitPattern: UInt32(littleEndian: [values[6], values[7], 0x00, 0x00].withUnsafeBytes { [=15=].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 初始化器 and/or 使用 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: [=10=])} )
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