来自 iOS 加速度计的高通滤波器方程未返回良好结果
High Pass Filter Equation from iOS accelerometer not returning good results
我正在尝试基于 Accelerometer Graph project 为 iOS 加速度计实施高通滤波器。代码写在Swift这里是完整的class:
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
}
}
class 是涉及 SpriteKit 和 CoreLocation 的项目的一部分,因此我从 class 中删除了一些部分,因为它们不相关。此代码的问题在于它不能像 Apple 给出的示例那样工作。在加速度计图中,当 phone 静止并且对运动非常敏感时,所有值都等于 0,这是高通滤波器所期望的,但是在我的例子中,当 phone 时,值并不总是 0 =22=] 不动,它们需要时间来改变(即使是非常强烈的摇动),最后通常需要几秒钟才能稳定下来。简而言之,它的行为更像是低通或卡尔曼滤波器,而不是高通滤波器。因为它是一个 SpriteKit 项目,所以我也尝试从 GameScene.swift 文件调用加速度计更新,但结果是一样的。我还对 startDeviceMotionUpdatesToQueue 和 startDeviceMotionUpdatesToQueue 函数进行了重力实验,但没有成功。
问题是您使用应用程序的主队列进行加速度计更新。主队列用于对 UI 执行更改。使用主队列进行加速度计更新会使主队列超载,因此并非每个操作都在提交到 NSOperationQueue 后立即执行。
解决方案是创建一个新的 NSOperationQueue
let queue = NSOperationQueue()
并将其传递给 motionManager.startAccelerometerUpdatesToQueue 而不是 NSOperationQueue.mainQueue()
。
如果你想在 motionHandler 中对你的 UI 进行更改,你必须使用 gcd's
dispatch_async(dispatch_get_main_queue() {
//perform UI changes here
}
我正在尝试基于 Accelerometer Graph project 为 iOS 加速度计实施高通滤波器。代码写在Swift这里是完整的class:
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
}
}
class 是涉及 SpriteKit 和 CoreLocation 的项目的一部分,因此我从 class 中删除了一些部分,因为它们不相关。此代码的问题在于它不能像 Apple 给出的示例那样工作。在加速度计图中,当 phone 静止并且对运动非常敏感时,所有值都等于 0,这是高通滤波器所期望的,但是在我的例子中,当 phone 时,值并不总是 0 =22=] 不动,它们需要时间来改变(即使是非常强烈的摇动),最后通常需要几秒钟才能稳定下来。简而言之,它的行为更像是低通或卡尔曼滤波器,而不是高通滤波器。因为它是一个 SpriteKit 项目,所以我也尝试从 GameScene.swift 文件调用加速度计更新,但结果是一样的。我还对 startDeviceMotionUpdatesToQueue 和 startDeviceMotionUpdatesToQueue 函数进行了重力实验,但没有成功。
问题是您使用应用程序的主队列进行加速度计更新。主队列用于对 UI 执行更改。使用主队列进行加速度计更新会使主队列超载,因此并非每个操作都在提交到 NSOperationQueue 后立即执行。 解决方案是创建一个新的 NSOperationQueue
let queue = NSOperationQueue()
并将其传递给 motionManager.startAccelerometerUpdatesToQueue 而不是 NSOperationQueue.mainQueue()
。
如果你想在 motionHandler 中对你的 UI 进行更改,你必须使用 gcd's
dispatch_async(dispatch_get_main_queue() {
//perform UI changes here
}