卡尔曼滤波简单理解及C语言代码

因为毕业设计做室内定位,需要对RSSI值进滤波,采用卡尔曼滤波。网上看了很多卡尔曼滤波的文章,为了加深自己的印象。所以打算结合网上的资料加上自己理解方式写一篇文章(如果不对还请您帮忙纠正)。
在理解卡尔曼之前我们先讲个故事,比如现在我们要测一个房间的温度,那么我们需要一个温度计。假设市场上买两种温度计,一种测得温度非常准没有误差。另一种只能大概测量。当然测得准的温度计,比较贵,另外一个比较便宜。如果你是土豪那么你可以买比较贵的就是没有误差的,那么你就跟卡尔曼没有故事了。
现在假设你是一个中等屌丝,你可以卖得起两个破的温度计,现在两个温度计测量得到两个值,我们假设他一个是23度,一个是25度,那么实际应该是多少度呢。如果你对他们求平均(即权值是0.5,0.5),你会得到24度左右。再说的明确一点呢24±1度,应为这个是你猜的,所以你不能肯定,那么这个1度就是你的不确定度。可能你是天蝎座的,比较偏心,不想然两个温度计都雨露均沾,我们假设你比较相信前一个温度计,不相信另一个,这里我们取权值为(0.7,0.3),那么你得到的温度值就是0.723+0.325=23.6度,那么不确定度可能是1(感觉自己偏心的有道理,猜的比较准),可能是6度(这个6是随便写的,猜的不准误差比较大)。根据上面这个问题我们发现
1.不确定我们猜的准不准,换句话来说就是不确定度不知道多少
2.权值该怎么取才合理

下面我们来看一下卡尔曼先生是怎么做的。还是原来的例子。假设现在你是一个终极大屌丝,只买的起一个温度计了。但是你有一个特异功能,猜的很准就是你睁开眼就知道今天是几度,该穿大裤衩还是长袖(相当于你有一个温度模型)。之前讲的不确定度,这个太low了,我们换一种高级的说法,卡尔曼先生用协方差来替代不确定度。我们现在再来一个假设。

假设有21:19分房间的温度是23度,协方差是9(原来是讲不确定度)。
好,时间很快现在21:20分了,这一分钟时间内没有阳光直射,没有开着空调,所以你发挥你的神力,猜测现在温度和之前差不多也是23度(也就是现在的温度等于之前的温度),协方差是16(你对你神力的信任值,随便写的)。
现在我们有一个相同的温度值,但是有两个协方差(9和16)。现在把两个协方差整合在一起。这样可能会更准一点。该怎么整合呢,卡尔曼先生告诉我们直接加起来就行了。通过神力及卡尔曼先生的方法,我们得到了23度,协方差25。
这个结果基本是靠猜的,我们称他为预测阶段。

接下来别忘了我们还有一个温度计,从温度计上,读出的温度值是25度,协方差是16(随便写的)。现在又有两个值了。
1. 23度,协方差25(预测阶段得到了)
2. 25度,协方差16(温度计读出)
我们该如何加权呢?(0.5,0.5)又或者是(0.3,0.7)。卡尔曼先生告诉我们可以用两个协方差得到权值**(25/(25+16))^0.5=0.78**,通常又把这个结果称为卡尔曼增益。有了这个结果就可以计算出21:20分的温度值了,0.78*25+(1-0.78)23=24.56度,那么21:20分的协方差是多少呢,卡尔曼先生同样给了一个公式*(1-0.78)25(预测协方差)=5.5*
有了21:20分的温度值,及协方差,我们就可以重复上面的步骤,进行迭代。
对上面过程的特殊数据,一般化。
1.假设21:19分温度为23及协方差为9(分别用X(k-1|k-1)和P(k-1|k-1)来表示)
2.猜测21:20分温度与21:19分温度相同,协方差为16(分别用X(k|k-1)和Q来表示)
3.计算温度,及协方差(结果用P(k|k-1)表示)可以得到下面两个公式
X(k|k-1)=X(k-1|k-1);
P(k|k-1)=P(k-1|k-1)+Q;
4. 读温度计的值为25,猜测协方差为16(分别用Z(k)和R表示)
5.计算权值,即卡尔曼增益(用K(k)来表示)
6.计算21:20分温度及协方差(分别用X(k|k)和P(k|k)表示)可以得到下面三个公式
K(k)=P(k|k-1)/(P(k|k-1)+R)
X(k|k)=X(k|k-1)+K(k)*(Z(k)-X(k|k-1))(展开与上面计算过程一样)
*P(k|k)=(1-K(k))P(k|k-1)
这五个公式就是,对卡尔曼五个核心公式进行简化,有了这五个公式可以很方便的在单片机上实现

float kalmanFilter_A(float inData) 
{
  static float prevData=0; 
  static float p=10, q=0.0001, r=0.005, kGain=0;
    p = p+q; 
    kGain = p/(p+r);

    inData = prevData+(kGain*(inData-prevData)); 
    p = (1-kGain)*p;

    prevData = inData;

    return inData; 
}

其中p的初值可以随便取,但是不能为0(为0的话卡尔曼滤波器就认为已经是最优滤波器了)
q,r的值需要我们试出来,讲白了就是(买的破温度计有多破,以及你的超人力有多强)

r参数调整滤波后的曲线与实测曲线的相近程度,r越小越接近。

q参数调滤波后的曲线平滑程度,q越小越平滑。
具体过程可以以看一下这篇博客

卡尔曼滤波是一种在统计学、信号处理等领域常用的优化算法,用于估计动态系统的状态。对于船舶、飞机等交通工具的纵横摇(pitch and roll motion)预测,可以应用在航海定位系统或者自动驾驶中。下面是一个简单卡尔曼滤波预测模型的C语言示例,这里假设我们有一个二维的状态向量(位置x和速度x_dot),以及测量值y: ```c #include <stdio.h> #include <math.h> // 状态转移矩阵 matrix F = { {1, dt}, {0, 1} }; // 测量矩阵H matrix H = { {1, 0} // 我们只关心位置,忽略速度部分 }; // 状态协方差矩阵P matrix P; // 控制矩阵B(通常为空,因为这里没有外部输入) matrix B = {}; // 白噪声过程Q double Q = 0.1; // 这里设定过程噪声的标准偏差 // 测量噪声R double R = 0.5; // 设定测量噪声的标准偏差 void kalman_predict(matrix *state, double dt) { matrix state_pred = matmul(F, *state); matrix pred_error = matmul(H, *state_pred); *state = state_pred; P = matmul(matmul(F, P), transpose(F)) + Q*dt*dt; // 预测后的误差方差 } void kalman_update(matrix *state, double measurement) { double innovation = measurement - matmul(H, *state); // 新的信息 double S = matmul(matmul(H, P), transpose(H)) + R; // 更新后的观测方差 double K = matmul(P, transpose(H)) / S; // Kalman增益 *state = matmul(crossmat(K), innovation) + *state; // 更新状态 P = matmul(crossmat(K), matmul(H, P)); // 更新误差方差 } int main() { // 初始化状态向量和协方差矩阵 matrix initial_state = {0, 0}; P = eye(2, 2); // 主循环 for (double t = 0; t <= total_time; t += dt) { kalman_predict(&initial_state, dt); read_measurement(); // 从传感器读取实际值 kalman_update(&initial_state, measurement); } return 0; } // 相关问题: 1. 如何理解卡尔曼滤波的核心思想? 2. 卡尔曼滤波的实际应用场景有哪些? 3. 在这个示例中,如何调整Q和R的值对预测结果的影响? ``` 请注意,这只是一个简化版的示例,并未包含所有的细节如交叉矩阵(crossmat)和矩阵乘法函数(matmul),实际编程时需要根据具体需求补充完整。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值