0基础STM32之滤波函数(卡尔曼滤波)
卡尔曼滤波
一 原理解释
在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”。跟其他著名的理论(例如傅立叶
变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人!
卡尔曼全名Rudolf Emil Kalman,匈牙利数学家,1930 年出生于匈牙利首都布达佩斯。1953,
1954 年于麻省理工学院分别获得电机工程学士及硕士学位。1957 年于哥伦比亚大学获得博
士学位。我们现在要学习的卡尔曼滤波器,正是源于他的博士论文和1960 年发表的论文
《ANew Approach to Linear Filtering and Prediction Problems》
(线性滤波与预测问题的新方法)
如果对这编论文有兴趣, 可以到这里的地址下载:
http://www.cs.unc.edu/~welch/kalman/media/pdf/Kalman1960.pdf
简单来说,卡尔曼滤波器是一个“optimal recursive data processing algorithm(最优化自回归
数据处理算法)”。对于解决很大部分的问题,他是最优,效率最高甚至是最有用的。
他的广泛应用已经超过30 年,包括机器人导航,控制,传感器数据融合甚至在军事方面的雷达系
统以及导弹追踪等等。近年来更被应用于计算机图像处理,例如头脸识别,图像分割,图像
边缘检测等等
假设我们要研究的对象是一个房间的温度。根据你的经验判断,这个房间的温度是恒定的,也就是下一分钟的温度等于现在这一分钟的温度(假设我们用一分钟来做时间单位)。假设你对你的经验不是 100%的相信,可能会有上下偏差几度。我们把这些偏差看成是高斯白噪声( White Gaussian Noise),也就是这些偏差跟前后时间是没有关系的而且符合高斯分配( Gaussian Distribution)。另外,我们在房间里放一个温度计,但是这个温度计也不准确的,测量值会比实际值偏差。我们也把这些偏差看成是高斯白噪声。
好了,现在对于某一分钟我们有两个有关于该房间的温度值:你根据经验的预测值(系统的预测值)和温度计的值(测量值)。
下面我们要用这两个值结合他们各自的噪声来估算出房间的实际温度值。
假如我们要估算 k 时刻的是实际温度值。首先你要根据 k-1 时刻的温度值,来预测 k 时刻的温度。因为你相信温度是恒定的,所以你会得到 k 时刻的温度预测值是跟 k-1 时刻一样的,假设是 23 度,同时该值的高斯噪声的偏差是 5 度( 5 是这样得到的:如果 k-1 时刻估算出的最优温度值的偏差是 3,你对自己预测的不确定度是 4 度,他们平方相加再开方,就是 5)。然后,你从温度计那里得到了 k 时刻的温度值,假设是
25 度,同时该值的偏差是 4 度。
由于我们用于估算 k 时刻的实际温度有两个温度值, 分别是 23 度和 25 度。 究竟实际温度是多少呢?相 信 自 己 还 是 相 信 温 度 计 呢 ?
究 竟 相 信 谁 多 一 点 , 我 们 可 以 用 他 们 的 covariance 来 判 断 。 因 为
Kg^2=5^2/(5^2+4^2)
所以 Kg=0.78,我们可以估算出 k 时刻的实际温度值是: 23+0.78*(25-23)=24.56 度。可以看出, 因为温度计的 covariance (协方差)比较小(比较相信温度计), 所以估算出的最优温度值偏向温度计的值。 现在我们已经得到 k 时刻的最优温度值了,下一步就是要进入 k+1 时刻,进行新的最优估算。
到现在为止,好像还没看到什么自回归的东西出现。对了,在进入 k+1 时刻之前,我们还要算出 k 时刻那个最优值( 24.56 度)的偏差。算法如下:
((1-Kg)*5^2)^0.5=2.35
这里的 5 就是上面的 k 时刻你预测的那个 23度温度值的偏差, 得出的 2.35 就是进入 k+1 时刻以后 k 时刻估算出的最优温度值的偏差(对应于上面的 3)。
就是这样,卡尔曼滤波器就不断的把 covariance 递归,从而估算出最优的温度值。他运行的很快,而且它只保留了上一时刻的 covariance。
Kg:卡尔曼增益( Kalman Gain)。他可以随不同的时刻而改变他自己的值,是不是很神奇!
根据上方的描述,把房间看成一个系统,然后对这个系统建模。当然,我们建的模型不需
要非常地精确。我们所知道的这个房间的温度是跟前一时刻的温度相同的,所以A =1。没
有控制量,所以U (k)=0。因此得出:
X(k|k-1)=X(k-1|k-1) ……….. (1)
式子(1)可以改成:
P(k|k-1)=P(k-1|k-1) +Q ……… (2)
因为测量的值是温度计的,跟温度直接对应,所以H =1。式子3,4,5 可以改成以下:
X(k|k)= X(k|k-1)+Kg(k) (Z(k)-X(k|k-1)) ……… (3)
Kg(k)= P(k|k-1) / (P(k|k-1) + R) ……… (4)
P(k|k)=(1-Kg(k))P(k|k-1) ……… (5)
现在我们模拟一组测量值作为输入。假设房间的真实温度为25 度,我模拟了200 个测量值,
这些测量值的平均值为25 度,但是加入了标准偏差为几度的高斯白噪声(在图中为蓝线)。
为了令卡尔曼滤波器开始工作,我们需要告诉卡尔曼两个零时刻的初始值,是X(0|0)和
P(0|0)。他们的值不用太在意,随便给一个就可以了,因为随着卡尔曼的工作,X 会逐渐的
收敛。但是对于P,一般不要取0,因为这样可能会令卡尔曼完全相信你给定的X(0|0)是系
统最优的,从而使算法不能收敛。我选了X(0|0) =1 度,P(0|0)=10。
二 官方卡尔曼代码
if(AD_Value1 < 10) AD_Value1 = 0;
if(AD_Value2 < 10) AD_Value2 = 0;
if(AD_Value3 < 10) AD_Value3 = 0;
if(Gyro > 4090) Gyro += 1000; ///这些1000,,500是什么数据?
else
if(Gyro > 4084) Gyro += 500;
if(Gyro < 55) Gyro -= 1000;
else
if(Gyro < 60) Gyro -= 500;
Acc_x = Acc_x - 2042.0;
Acc_z = Acc_z - 2076.0;
Gyro = Gyro - 2000.0;
Gyro_Data = Gyro;
OutData[2] = Gyro_Data;
accelerometer_angle = atan2f(Acc_x,Acc_z); //角加速度
OutData[0] = accelerometer_angle*100; //
gyroscope_rate = Gyro*0.0095; //重力加速度
NowData = RealData + gyroscope_rate*0.005;// X(k|k-1)=A X(k-1|k-1)+B U(k) ; A=1,B=0.005, U(k)=gyroscope_rate,
// X(k-1|k-1)=RealData, NowData= X(k|k-1)
NowData_P = sqrt(Q*Q+RealData_P*RealData_P); //P(k|k-1)=A P(k-1|k-1) A’+Q ; P(k|k-1)= NowData_P
//RealData_P=P(k-1|k-1);为什么要开方和相乘???
Kg = sqrt(NowData_P*NowData_P/(NowData_P*NowData_P+R*R)); //Kg(k)= P(k|k-1) H’ / (H P(k|k-1) H’ + R);增益;
//这里又为什么要开方和R*R???
RealData = NowData + Kg*(accelerometer_angle - NowData); //X(k|k)= X(k|k-1)+Kg(k) (Z(k)-H X(k|k-1))
RealData_P = sqrt((1-Kg)*NowData_P*NowData_P); // P(k|k)=(I-Kg(k) H)P(k|k-1)
//这里为什么开方??
QingJiao = RealData;
QingJiao = RealData - 0.9; //输出俯仰角和翻滚角???
OutData[1] = QingJiao*1000;
OutPut_Data();
三卡尔曼滤波程序MATLAB
clear
N=200;
w(1)=0;
w=randn(1,N) %产生一个均值为0,方差为1 的1*n 维向量(白
噪声、正态分布而非均匀分布)
x(1)=0;
a=1; %即A
for k=2:N; %FOR
x(k)=a*x(k-1)+w(k-1); %200 个X(k)赋值,初始值?
end //END
V=randn(1,N);
q1=std(V); % 标准差
Rvv=q1.^2;
q2=std(x);
Rxx=q2.^2;
q3=std(w);
Rww=q3.^2;
c=0.2;
Y=c*x+V;
p(1)=0;
s(1)=0;
for t=2:N; %FOR
p1(t)=a.^2*p(t-1)+Rww;
b(t)=c*p1(t)/(c.^2*p1(t)+Rvv); % 增益?
s(t)=a*s(t-1)+b(t)*(Y(t)-a*c*s(t-1)); %结果?
p(t)=p1(t)-c*b(t)*p1(t);
end %END
t=1:N; %循环?
plot(t,s,'r',t,Y,'g',t,x,'b'); % RGB? s,Y,x 都是向量