【kalman filter】卡尔曼滤波器与python实现

时间:2022-07-22
本文章向大家介绍【kalman filter】卡尔曼滤波器与python实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

“学习的同时记录,记录的同时分享,分享的同时交流,交流的同时学习。”

先上一个卡尔曼的照片,以表敬意:

卡尔曼滤波器

  • 英文kalman filter
  • 这里介绍简单的,只有一个状态的滤波器
  • 卡尔曼滤波器经常用在控制系统中、机器人系统中,但是这里主要讲解如何用在AI的大数据分析预测中
  • 为什么考虑到用这个处理时间序列?因为有一个队员提出,在处理电信号、语音、位置信息的时候,使用kalman滤波器可以更有效的过滤更多的噪音。
  • 在尝试特征工程的时候,我是把这个方法当成一个玄学,看看是否可以提高效果,因为我目前还理解不了这其中的统计学的奥秘。

为什么要用kalman filter

假设我们有100个时间点的数据,这个数据就是分别在100个点观测出来的结果。

对于每一个时间点的数据,获取的方法有两个:

  • 第一个就是观测,但是测量的结果不一定准确,可能受限于测量仪器的精度?
  • 第二个就是用这个时间点之前的所有数据,预测这个时间点的数据,当然,这个预测值也是不准的。
  • 可否利用这两种方法,相互促进,预测的值更准,或者说让观测到的值更接近本质?Kalman Filter卡尔曼滤波器就这样做的。

这里肯定会有人不理解,观测到的值都不一定准,你怎么还能依赖于预测的值呢?(其实这个是阿里的面试官反驳我的话,当时我确实蒙了,因为这个方法只是拿来用在特征构建中,其实滤波器是用在控制系统专业中的,下面是朋友给我讲的一个例子。)

破解概念上的认知枷锁:卡尔曼滤波究竟做了什么事情

卡尔曼滤波做的事就是:举个例子,已知上个时刻飞机的位置,知道现在这个时刻收到的雷达测量的飞机的位置。用前面两个数据来估计此时飞机的位置。精简的说就是知道上个时刻状态,又知道测量数据,融合这两个数据来求当前状态。

你一定会问现在知道当前时刻的测量数据那么我认为当前状态就是测量数据不就好了么?换句话说:“你一定会觉得雷达测量到的飞机位置不就是当前飞机的位置嘛?为何要用卡尔曼滤波来估计飞机当前的位置?”。

:现在这个时刻收到的雷达信号测量的飞机的位置还真不一定是飞机当前的真实位置。首先雷达信号测量有误差。其次你想想我现在收到雷达信号,那是之前发射过去然后返回的信号。这个过程是不是要时间?这段时间飞机说不定以超2倍音速飞行,说不定直接坠机,这些都有可能。也就是说即使收到测量数据但是还是不确飞机位置在哪。于是我得需要根据前一个时刻的位置估计出当前时刻的飞机位置 结合 测量数据 综合考虑来 估计当前飞机位置。这就是卡尔曼滤波的作用。

那么你一定会问:根据前一个时刻估计的飞机位置怎么就可以估计现在这个时刻的飞机位置了?

:卡尔曼认为所有的状态变化(位置变化)都是线性的。什么叫做线性?上个时刻位置是0.3,速度是0.2。那么我估计下个时刻的位置就是0.5。这就叫做线性。

接下来你一定会问:那并不是所有的状态变化都是线性的怎么办?你像风速变化它就不是线性的。

:恭喜你发明了新的算法。事实上别人已经为这个算法命名了叫做扩展卡尔曼滤波。现在我们要学习的是卡尔曼滤波。你只需要记住卡尔曼滤波就是认为所有变化都是线性的。

那么现在我知道了怎么用上个时刻飞机的位置估计当前时刻的飞机位置,也知道了还得借助当前时刻收到的测量数据来综合考虑来估计当前飞机的位置。那么怎么综合考虑呢?这就涉及到一个比例。到底这两个数据占比多少?这就是卡尔曼滤波的核心精髓。卡尔曼滤波算法要动态的调这个比例。(有种中庸之道的调调,既不只信测量数据,也不只信上个时刻的位置所估算的当前时刻位置。)

简单讲讲kalman filter的过程

每一个观测数据,严谨的说都应该会有一个偏差值。比方说,现在温度计测量是26度,偏差值是0.5度,那么真实的问题应该是在(25.5,26.5)之间,或者写成

26pm0.5

这样我们预测的值,和观测的值,再加上这两个各自的偏差,总共四个已知信息,来推测真实的、更本质的数据。

  • 预测的值:可以通过事先设定的公式,上一个时刻的真实的值算出来;
  • 观测的值:直接读取测量仪器的值。
  • 观测的值的偏差:这个也是可以直接得到的;
  • 预测的值的偏差:这个是从上一个时间点的预测的值的偏差经过给定公式计算出来的。

下面的公式中,脚标k表示时间点,k-1是上一个时间点。大写字母A,B,C表示常数,事先设定的;大写字母H,是一个需要计算的。

  • 预测的值:
x^{预测}_k=A*x_{k-1}^{真实}+B*u_{k-1}
  • 观测的值:
x^{观测}_k
  • 观测的值的偏差:
p^{观测}_k
  • 预测的值的偏差:预测()预测
  • kalman增益H: 预测预测观测
  • 真实的值: 真实观测()预测

可以看出,这个kalman增益就是一个加权平均的权重,是观测值更重要还是预测值更重要;两者的重要性就由两者的偏差大小决定,偏差小的更重要。

其中

u_{k-1}

表示上一个时间点的控制信号,比方说一个机器人,机器人的状态去觉得机器人自身的行为,但是很多情况这个控制信号是不用考虑的。比方对股市的时间序列做kalman滤波,那么并没有什么控制信号去控制,只是任由其自由发展。


举一个例子,房间的温度的例子:

总共有三个时刻,上午、下午和晚上(实际的话,时间点间隔应该会很短,这里只是举例),上午温度是观测值是23度,偏差是0.5,因为上午是第一个时间点,所以没有预测值;

下午,假设A=1,B=0,所以下午的预测值是23度,然后假设初始偏差是1;下午的观测值是25度,观测值的偏差是0.5,所以可以计算得到kalman增益

H=frac{1^2}{1^2+0.5^2}=0.8

,所以下午的真实值是:

0.8*25+(1-0.8)*23=24.6

晚上,晚上的预测值就是上一时刻的真实值,所以是24.6,偏差是

sqrt{(1-0.8)*1}=0.4472

;晚上的观测值是20度,然后偏差是0.5,所以kalman增益增益,所以这个时刻的真实值是:

最后总结一下,其实我们只需要什么呢?需要知道观测的误差是0.5,然后三个时间点的观测数据:[23,25,20],然后用kalman滤波器之后,就变成[23,24.6,22.56]。类似于一个平滑的作用。

python怎么实现呢?

from pykalman import KalmanFilter

def Kalman1D(observations,damping=1):
    # To return the smoothed time series data
    observation_covariance = damping
    initial_value_guess = observations[0]
    transition_matrix = 1
    transition_covariance = 0.1
    initial_value_guess
    kf = KalmanFilter(
            initial_state_mean=initial_value_guess,
            initial_state_covariance=observation_covariance,
            observation_covariance=observation_covariance,
            transition_covariance=transition_covariance,
            transition_matrices=transition_matrix
        )
    pred_state, state_cov = kf.smooth(observations)
    return pred_state

这里面使用的是pykalman库中的KalmanFilter,因为上面讲解的Kalman Filter是简化的,绕开了正统的解释的正态分布的知识,所以这里的卡尔曼滤波器的参数可能无法与上面给出的卡尔曼公式中一一对应,会产生一定的脱节,但是本质相同。(说白了就是我学的不够透彻2333)

这里讲一下参数:

  • initial_state_mean和initial_state_covariance:在上面的公式中,一开始的初始值,就是第一个观测值,但是在这个方法中,初始值并不是第一个观测值,而是由一个正态分布中随机采样出来的一个值,这个正态分布就是以initial_state_mean为均值,以initial_state_covariance为方差的;
  • observation_covariance这个可以相当于观测偏差;
  • transition_covariance这个就是预测偏差;
  • transition_matrices就是上面公式中的大写字母A,为1。

运行结果

从上面的那个函数中,可以看到transition_covariance是0.1,也就是预测偏差时0.1,所以假设观测偏差很小,那么可以想象,滤波器后的结果应该与观测值非常接近,这里选取观测偏差为0.001:

然后假设观测误差很大,那么可以想想,平滑的力度会很大,结果就是:

最后看一下在某次比赛中的利用kalman滤波器来平滑数据的前后对比图: