Reputation: 6325
Working with Core Motion the acceleration appears to always be returned with respect to the device. Meaning if you shake the device screen up it will be in the +/-Z (depending on initial reference) if you then turn the device to the side and shake up and down, the same as before, the acceleration will be in the +/-X or Y.
I want to convert this device specific acceleration back to a "global" frame. Meaning that the same physical movements of the device result in the acceleration data coming back in the same axis regardless of the devices orientation when shook.
For example, if we shake the device up and down, with the screen up, it comes in the z, and if you then rotate the device so the screen is facing forward and do the same shakes the z axis still shows acceleration even though with respect to the device it is the Y axis.
I've been trying to rotate the acceleration back to the initial attitude and it looks like it sometimes works and sometimes doesn't. I'm not convinced that rotation is the correct approach. I'm not sure if it is sound math or just randomly looks right sometimes.
extension CMQuaternion {
var toSIMD: simd_quatd {
return simd_quatd(ix: x, iy: y, iz: z, r: w)
}
}
extension CMAcceleration {
var toSIMD: SIMD3<Double> {
return SIMD3<Double>(x,y,z)
}
}
Then to do the calculation like so:
var reference: simd_quatd?
motionManager.startDeviceMotionUpdates(using: .xArbitraryZVertical, to: .main) { deviceMotion, error in
guard let deviceMotion = deviceMotion else { return }
let userAcceleration = deviceMotion.userAcceleration.toSIMD
let adjusted: SIMD3<Double>
if let ref = reference {
// rotate the userAccel by the inverse of the reference times the current attitude.
adjusted = simd_act(simd_mul( simd_inverse(ref.quaternion.toSIMD),deviceMotion.attitude.quaternion.toSIMD), userAcceleration)
} else {
reference = deviceMotion.attitude.quaternion.toSIMD
adjusted = userAcceleration
}
...
}
The end goal is to put the "up/down" component into a FFT to try and find the frequency of the movements.
Is rotating the acceleration vector the right approach? Is there a better way to achieve a attitude independent acceleration? Or better yet, find frequency of device motion regardless of orientation!
Upvotes: 3
Views: 556
Reputation: 6325
I was able to verify that this indeed is a way to "rotate" the acceleration data.
As a note instead of using the first frame as the reference I simplified it and use the quaternion
let referenceFrame = simd_inverse(simd_quatd(ix: 0,iy: 0,iz: 0,r: 1))
then for processing the adjusted acceleration I do:
let userAcceleration = motion.userAcceleration.toSIMD
let adjusted = simd_act(simd_mul(referenceFrame, motion.attitude.quaternion.toSIMD), userAcceleration)
adjusted
's Z component will then be up/down in the global frame.
I've been doing this in realtime without any issues.
Upvotes: 2