Настройте данные об ускорении на глобальную систему отсчета

При работе с Core Motion ускорение всегда возвращается по отношению к устройству. Это означает, что если вы встряхнете экран устройства вверх, он будет находиться в +/-Z (в зависимости от исходного значения), если вы затем повернете устройство в сторону и встряхнете вверх и вниз, как и раньше, ускорение будет в + /-X или Y.

Я хочу преобразовать конкретное ускорение этого устройства обратно в «глобальный» кадр. Это означает, что одни и те же физические движения устройства приводят к тому, что данные об ускорении возвращаются по одной и той же оси независимо от ориентации устройства при встряхивании.

Например, если мы встряхиваем устройство вверх и вниз с поднятым экраном, оно приходит в z, и если вы затем повернете устройство так, чтобы экран был обращен вперед, и сделаете то же самое, ось z по-прежнему показывает ускорение, даже если с по отношению к устройству это ось Y.

Я пытался повернуть ускорение обратно в исходное положение, и похоже, что иногда это работает, а иногда нет. Я не уверен, что ротация - правильный подход. Я не уверен, что это здравая математика или просто иногда выглядит правильно.

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)
    }
}

Затем сделать расчет следующим образом:

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
    }
...
}

Конечная цель состоит в том, чтобы поместить компонент «вверх/вниз» в БПФ, чтобы попытаться найти частоту движений.

Является ли вращение вектора ускорения правильным подходом? Есть ли лучший способ добиться независимого от отношения ускорения? Или еще лучше, найдите частоту движения устройства независимо от ориентации!


person utahwithak    schedule 16.04.2020    source источник


Ответы (1)


Я смог убедиться, что это действительно способ «повернуть» данные ускорения.

В качестве примечания, вместо того, чтобы использовать первый кадр в качестве эталона, я упростил его и использовал кватернион.

let referenceFrame = simd_inverse(simd_quatd(ix: 0,iy: 0,iz: 0,r: 1))

затем для обработки скорректированного ускорения я делаю:

let userAcceleration = motion.userAcceleration.toSIMD

let adjusted = simd_act(simd_mul(referenceFrame, motion.attitude.quaternion.toSIMD), userAcceleration)

Затем компонент Z adjusted будет вверх/вниз в глобальном фрейме.

Я делал это в реальном времени без каких-либо проблем.

person utahwithak    schedule 17.04.2020
comment
Хорошая работа по разделению z-компонента. Я использовал CMRotationMatrix, но не смог повернуться к глобальному фрейму. Ваше решение работает. - person William Grand; 11.02.2021