来自iOS加速计的高通滤波方程没有返回好的结果



我正在尝试实现基于加速度计图形项目的iOS加速度计高通滤波器。代码是用Swift编写的,下面是完整的类:

import Foundation
import CoreMotion
import SpriteKit
class Accelerometer {
     let motionManager: CMMotionManager
     var x: Double
     var y: Double
     var z: Double
     var lastX: Double
     var lastY: Double
     var lastZ: Double
     let kUpdateFrequency: Double
     let cutOffFrequency: Double
     let dt: Double
     let RC: Double
     let alpha: Double
     let kFilteringFactor = 0.6

init(manager: CMMotionManager){
    motionManager = manager
    motionManager.accelerometerUpdateInterval = 1.0 / 60
    motionManager.startDeviceMotionUpdates()
    x = 0.0
    y = 0.0
    z = 0.0
    lastX = 0.0
    lastY = 0.0
    lastZ = 0.00
    kUpdateFrequency = 60.0
    cutOffFrequency = 5.0
    dt = 1.0 / kUpdateFrequency
    RC = 1.0 / cutOffFrequency
    alpha = RC / (dt+RC)
    getAccelerometerUpdates()
}
func getAccelerometerUpdates() {
    motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { (data, error) -> Void in
        // Filter the raw measurments with high pass filter
        self.highPassFilter(data!)
    })
}

// High pass filter function for accelerometer measurments
func highPassFilter(data: CMAccelerometerData){
    self.x = self.alpha * (self.x + data.acceleration.x - self.lastX)
    self.y = self.alpha * (self.y + data.acceleration.y - self.lastY)
    self.z = self.alpha * (self.z + data.acceleration.z - self.lastZ)
    self.lastX = data.acceleration.x
    self.lastY = data.acceleration.y
    self.lastZ = data.acceleration.z
}
}

类是涉及SpriteKit和CoreLocation项目的一部分,所以我从类中删除了一些部分,因为它们不相关。这段代码的问题是,它不像苹果给出的例子那样工作。在加速度计图中,当手机静止并且对移动非常敏感时,所有值都等于0,这是高通滤波器所期望的,然而在我的情况下,当手机不移动时,值并不总是0,它们需要时间来改变(即使是非常强烈的震动),最后通常需要几秒钟才能稳定下来。简而言之,它的行为更像一个低通或卡尔曼滤波器,而不是高通滤波器。因为这是一个SpriteKit项目,我也尝试着从GameScene.swift文件中调用加速计更新,但结果是一样的。我还尝试了重力,尝试startDeviceMotionUpdatesToQueue和startDeviceMotionUpdatesToQueue函数,但没有运气。

问题是你使用了应用程序的主队列来更新加速度计。主队列用于执行对UI的更改。使用你的主队列进行加速计更新会使你的主队列超载,所以不是每个操作在提交给NSOperationQueue后都会立即执行。解决方案是创建一个新的NSOperationQueue

let queue = NSOperationQueue()

并传递给motionManager。startAccelerometerUpdatesToQueue代替NSOperationQueue.mainQueue() .

如果你想在motionHandler中执行UI更改,你必须使用gcd的

dispatch_async(dispatch_get_main_queue() {
    //perform UI changes here
}

最新更新