协方差的卡尔曼滤波器 EM 估计

信息处理 过滤器 Python 卡尔曼滤波器 平滑 状态空间
2022-01-28 12:34:25

这个问题可能很简单,但我从卡尔曼滤波器得到了一个奇怪的结果。让我们考虑最简单的状态空间模型,即随机游走加噪声:

yt=xt+εtxt=xt1+μt1
让我们生成Ndata=3000数据点和参数:Var(μt)=1(这是过渡方差)和Var(εt)=1(这是观察方差)。

在 Python 中使用 Kalman EM,我尝试估计转换和观察方差。

首先,我想估计“observation_covariance”并假设“transition_covariance”是已知的:

kf = KalmanFilter(
    transition_matrices=[1.], observation_matrices=Data['x'],
    transition_covariance=[1.], initial_state_mean=3,
    initial_state_covariance=[1.],
    em_vars=['observation_covariance']
)

kf = kf.em(Data['y'])

结果是0.79.

其次,我做相反的事情,即我估计“transition_covariance”并假设“observation_covariance”是已知的:

kf = KalmanFilter(
    transition_matrices=[1.], observation_matrices=Data['x'],
    observation_covariance=[1.], initial_state_mean=3,
    initial_state_covariance=[1.],
    em_vars=['transition_covariance']
)

kf = kf.em(Data['y'])

结果是0.001,这远非1

接下来,我假设“transition_covariance”和“observation_covariance”都是未知的:

kf = KalmanFilter(
    transition_matrices=[1.], observation_matrices=Data['x'],
    initial_state_mean=3, initial_state_covariance=[1.],
    em_vars=['transition_covariance', 'observation_covariance']
)

kf = kf.em(Data['y'])

结果是“observation_covariance”= 0.77 和“transition_covariance”= 0.0002。

我做错了什么?那些估计的方差不应该接近吗1?

我使用的所有代码如下:

#%%
import pandas as pd
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
import pylab as pl
from pykalman import KalmanFilter

N_data = 3000
Data = pd.DataFrame(columns=['NoiseTrs', 'NoiseObs', 'x', 'y'], index=range(N_data))
Data['NoiseTrs'] = np.random.normal(loc=0.0, scale=1.0, size=N_data)
Data['NoiseObs'] = np.random.normal(loc=0.0, scale=1.0, size=N_data)

# random walk

x_f_v = 3 # first value for the simulation
for i in range(N_data):
    if i == 0:
        Data.loc[i, 'x'] = x_f_v
    else:
        Data.loc[i, 'x'] = Data.loc[i - 1, 'x'] + Data.loc[i, 'NoiseTrs']

# plt.plot(Data['x'])
# plt.show()

Data['y'] = Data['x'] + Data['NoiseObs']

# plt.plot(Data[['x', 'y']])
# plt.show()

F = [1.]                                               # transition matrix
H = Data['x'].values.reshape(N_data,1,1).astype(float) # observation matrix
Q = [1.]                                               # transition noise
R = [1.]                                               # observation noise

#%%
init_state_mean = [3.]
init_state_cov = [1.]

kf = KalmanFilter(
    transition_matrices=F,
    observation_matrices=H,
    # transition_covariance=Q,
    # observation_covariance=R,
    initial_state_mean=init_state_mean,
    initial_state_covariance=init_state_cov,
    em_vars=['transition_covariance', 'observation_covariance']
    # em_vars=['observation_covariance']
    # em_vars=['transition_covariance']
)

kf = kf.em(Data['y'].values.astype(float))

print("observation_covariance R :", kf.observation_covariance)
print("transition_covariance Q :", kf.transition_covariance)



```
1个回答

其实,我发现了一些东西。事实上,估计转移和观察协方差是一个复杂的问题。

在维基百科中它说:

https://en.wikipedia.org/wiki/Kalman_filter#Estimation_of_the_noise_covariances_Qk_and_Rk

由于难以获得噪声协方差矩阵的良好估计,卡尔曼滤波器的实际实现通常很困难QkRk. 在该领域已经进行了广泛的研究,以从数据中估计这些协方差。一种实用的方法是自协方差最小二乘 (ALS) 技术,该技术使用常规操作数据的时间滞后自协方差来估计协方差。用于使用 ALS 技术计算噪声协方差矩阵的 GNU Octave 和 Matlab 代码可在 GNU 通用公共许可证下在线获得。

此外,这里讨论了类似的事情:

卡尔曼滤波器协方差

和这里

https://quant.stackexchange.com/questions/8501/how-to-tune-kalman-filters-parameter