Python 鼠标位置的卡尔曼滤波器未按预期工作
Python Kalman filter for mouse position isn't working as expected
我开始在 Jupyter notebook 上使用 python,因此出于学习目的,我在 YouTube tutorial 之后实现了卡尔曼滤波器。我首先将我的卡尔曼滤波器与静态数据一起使用,我猜它正在工作,所以我尝试扩展该代码以在鼠标坐标上应用滤波器,但它的行为确实很奇怪。谁能帮我解决一下?
我希望有 this kind of result 但我得到了类似于屏幕截图的内容。
这是代码-
import numpy as np
import pandas as pd
from tkinter import *
### True Value: What should be the actual value if there was no error in measurements
### Estimates : It is the predicted value.
#### Error in Estimate: Error in the predicted value
### Measurements : It is the actual value measured with sensor
#### Error in Measurements: Error in the measured value
#### initializing variables
true_x,true_y = 0,0 # True Mouse location
Est_x,Est_y = 0,0 # Initial Estimate
Err_est_x,Err_est_y = 5,5 # Error in Initial Estimate
M_x,M_y = 0,0 # Initial Measurements
Err_msr_x,Err_msr_y = 5,5 # Error in Initial Measurements
kg_x,kg_y = 0,0 # Kalman Gain
def getKG(Err_est, Err_msr):
return Err_est/(Err_est+Err_msr)
def getEst(EST_prev, kg, Msr):
return EST_prev+kg*(Msr-EST_prev)
def getE_est(kg, Err_est):
return (1-kg)*Err_est
def updateKal(val, kg, Est, Err_est, Err_msr):
kg = getKG(Err_est, Err_msr)
Est = getEst(Est, kg, val)
Err_est = getE_est(kg, Err_est)
return kg, Est, Err_est
kg_x,Est_x,Err_est_x = updateKal(true_x,kg_x,Est_x,Err_est_x,Err_msr_x)
kg_y,Est_y,Err_est_y = updateKal(true_y,kg_y,Est_y,Err_est_y,Err_msr_y)
def activate_paint(e):
global lastx, lasty
global true_x, true_y
cv.bind('<B1-Motion>', paint)
lastx, lasty = e.x, e.y
true_x, true_y = e.x, e.y
Est_x, Est_y = e.x, e.y
def paint(e):
global lastx, lasty
global true_x, true_y
global kg_x, Est_x, Err_est_x
global kg_y, Est_y, Err_est_y
global firstval
x, y = e.x, e.y
kg_x, Est_x, Err_est_x = updateKal(x, kg_x, Est_x, Err_est_x, 0.5)
kg_y, Est_y, Err_est_y = updateKal(y, kg_y, Est_y, Err_est_y, 0.5)
cv.create_line((lastx, lasty, x, y), fill='blue',width=1)
cv.create_line((true_x,true_y, Est_x, Est_y), fill='green',width=2)
lastx, lasty = x, y
true_x, true_y = Est_x, Est_y
root = Tk()
lastx, lasty = None, None
cv = Canvas(root, width=640, height=480, bg='white')
cv.bind('<1>', activate_paint)
cv.pack(expand=YES, fill=BOTH)
root.mainloop()
红色的是卡尔曼,蓝色的是实际的
编辑: 使用@Lho 建议的代码更新
我认为您缺少的是流程模型。如果您正在测量一个静态参数,那么像这样的策略是可行的,但是如果您正在跟踪的状态本身正在发生变化,就像这里一样,您需要一个将这些变化考虑在内的过程模型。您将在每个更新步骤之前执行流程模型估计步骤。
本例中的过程模型将涉及一些基本的牛顿物理学。我建议扩展您正在跟踪的状态(x 和 y)以包括速度(vx、vy)和加速度(ax、ay)。因此,您的状态向量不是 [x y]T,而是 X = [x y vx vy ax ay]T。 (您可以根据每个时间步长的移动量推导出速度,您可以尝试从几个时间步长的移动推导出真实加速度,或者假设一个合理的加速度可能就足够了,因为真实加速度在这种情况可能会不稳定并且不容易建模。)您还需要一个过程矩阵 F 将 X 转换为测量值向量 Z(即,[x y]T,您正在进行的模糊测量)。在这种情况下,F 将是一个 2x6 矩阵。
我没有 运行 你的代码,但你的变量 Err_est_x
和 Err_est_y
只会越来越小?您必须在每次调用 updateCall
后增加这些变量,如下所示:
# in method paint()
#
kg_x, Est_x, Err_est_x = updateKal(x, kg_x, Est_x, Err_est_x, 0.5)
kg_y, Est_y, Err_est_y = updateKal(y, kg_y, Est_y, Err_est_y, 0.5)
Err_est_x = 1.1 * Err_est_x + 0.1 # new code
Err_est_y = 1.1 * Err_est_y + 0.1 # new code
解释:如果你的估计误差很低,那么新的噪声测量的信息也很低[1]。
这在您的可视化中也可见:最初,红色卡尔曼估计是 'very fast' 因为您的估计误差很高。但是当你的估计误差越来越小的时候,你的红卡尔曼估计就是'slowing done'.
请注意,我没有 运行 您的代码,因此选择的值(1.1 和 0.1)可能太高或太小。 Increase/reduce 两个数字到 increase/reduce 你的红色卡尔曼估计的 'speed'。
[1]例如,如果你的估计误差为0,那么新测量的信息增益也为0。
我开始在 Jupyter notebook 上使用 python,因此出于学习目的,我在 YouTube tutorial 之后实现了卡尔曼滤波器。我首先将我的卡尔曼滤波器与静态数据一起使用,我猜它正在工作,所以我尝试扩展该代码以在鼠标坐标上应用滤波器,但它的行为确实很奇怪。谁能帮我解决一下?
我希望有 this kind of result 但我得到了类似于屏幕截图的内容。
这是代码-
import numpy as np
import pandas as pd
from tkinter import *
### True Value: What should be the actual value if there was no error in measurements
### Estimates : It is the predicted value.
#### Error in Estimate: Error in the predicted value
### Measurements : It is the actual value measured with sensor
#### Error in Measurements: Error in the measured value
#### initializing variables
true_x,true_y = 0,0 # True Mouse location
Est_x,Est_y = 0,0 # Initial Estimate
Err_est_x,Err_est_y = 5,5 # Error in Initial Estimate
M_x,M_y = 0,0 # Initial Measurements
Err_msr_x,Err_msr_y = 5,5 # Error in Initial Measurements
kg_x,kg_y = 0,0 # Kalman Gain
def getKG(Err_est, Err_msr):
return Err_est/(Err_est+Err_msr)
def getEst(EST_prev, kg, Msr):
return EST_prev+kg*(Msr-EST_prev)
def getE_est(kg, Err_est):
return (1-kg)*Err_est
def updateKal(val, kg, Est, Err_est, Err_msr):
kg = getKG(Err_est, Err_msr)
Est = getEst(Est, kg, val)
Err_est = getE_est(kg, Err_est)
return kg, Est, Err_est
kg_x,Est_x,Err_est_x = updateKal(true_x,kg_x,Est_x,Err_est_x,Err_msr_x)
kg_y,Est_y,Err_est_y = updateKal(true_y,kg_y,Est_y,Err_est_y,Err_msr_y)
def activate_paint(e):
global lastx, lasty
global true_x, true_y
cv.bind('<B1-Motion>', paint)
lastx, lasty = e.x, e.y
true_x, true_y = e.x, e.y
Est_x, Est_y = e.x, e.y
def paint(e):
global lastx, lasty
global true_x, true_y
global kg_x, Est_x, Err_est_x
global kg_y, Est_y, Err_est_y
global firstval
x, y = e.x, e.y
kg_x, Est_x, Err_est_x = updateKal(x, kg_x, Est_x, Err_est_x, 0.5)
kg_y, Est_y, Err_est_y = updateKal(y, kg_y, Est_y, Err_est_y, 0.5)
cv.create_line((lastx, lasty, x, y), fill='blue',width=1)
cv.create_line((true_x,true_y, Est_x, Est_y), fill='green',width=2)
lastx, lasty = x, y
true_x, true_y = Est_x, Est_y
root = Tk()
lastx, lasty = None, None
cv = Canvas(root, width=640, height=480, bg='white')
cv.bind('<1>', activate_paint)
cv.pack(expand=YES, fill=BOTH)
root.mainloop()
红色的是卡尔曼,蓝色的是实际的
编辑: 使用@Lho 建议的代码更新
我认为您缺少的是流程模型。如果您正在测量一个静态参数,那么像这样的策略是可行的,但是如果您正在跟踪的状态本身正在发生变化,就像这里一样,您需要一个将这些变化考虑在内的过程模型。您将在每个更新步骤之前执行流程模型估计步骤。
本例中的过程模型将涉及一些基本的牛顿物理学。我建议扩展您正在跟踪的状态(x 和 y)以包括速度(vx、vy)和加速度(ax、ay)。因此,您的状态向量不是 [x y]T,而是 X = [x y vx vy ax ay]T。 (您可以根据每个时间步长的移动量推导出速度,您可以尝试从几个时间步长的移动推导出真实加速度,或者假设一个合理的加速度可能就足够了,因为真实加速度在这种情况可能会不稳定并且不容易建模。)您还需要一个过程矩阵 F 将 X 转换为测量值向量 Z(即,[x y]T,您正在进行的模糊测量)。在这种情况下,F 将是一个 2x6 矩阵。
我没有 运行 你的代码,但你的变量 Err_est_x
和 Err_est_y
只会越来越小?您必须在每次调用 updateCall
后增加这些变量,如下所示:
# in method paint()
#
kg_x, Est_x, Err_est_x = updateKal(x, kg_x, Est_x, Err_est_x, 0.5)
kg_y, Est_y, Err_est_y = updateKal(y, kg_y, Est_y, Err_est_y, 0.5)
Err_est_x = 1.1 * Err_est_x + 0.1 # new code
Err_est_y = 1.1 * Err_est_y + 0.1 # new code
解释:如果你的估计误差很低,那么新的噪声测量的信息也很低[1]。 这在您的可视化中也可见:最初,红色卡尔曼估计是 'very fast' 因为您的估计误差很高。但是当你的估计误差越来越小的时候,你的红卡尔曼估计就是'slowing done'.
请注意,我没有 运行 您的代码,因此选择的值(1.1 和 0.1)可能太高或太小。 Increase/reduce 两个数字到 increase/reduce 你的红色卡尔曼估计的 'speed'。
[1]例如,如果你的估计误差为0,那么新测量的信息增益也为0。