# Kalman Filter State Covariance Matrix for Non Constant Process Noise Matrix in PyKalman

I'm experimenting with the pykalman Python library to learn about Kalman Filters. In the code below, I'm generating a random walk where each step is the last step multiplied by 1 plus some noise: 1 + std_dev. In the first block, the covariance matrix of the KF (using a 1D signal/state, so it's really just one variance) appears to converge to about 0.62. Even if I set grow_std_dev=True, causing the noise to grow significantly over time, the covariance matrix still converges to this value.

import numpy as np
import matplotlib.pyplot as plt
from pykalman import KalmanFilter

def generate_random_walk(seed=1, n_steps=100, grow_std_dev=False):
np.random.seed(seed)
rand_walk = [1]
std_devs = []

for n in range(n_steps):
if grow_std_dev:
std_dev = np.random.normal(0,0.01 * (1 + n))
else:
std_dev = np.random.normal(0,0.01)
val = rand_walk[-1] * (1 + std_dev)
std_devs.append(std_dev)
rand_walk.append(val)

return np.array(rand_walk), np.array(std_devs)

kf = KalmanFilter(transition_matrices = [1],
observation_matrices = [1],
initial_state_mean = 1,
initial_state_covariance = 1,
observation_covariance=1,
transition_covariance=1)

rand_walk, std_devs = generate_random_walk(0)
state_means, state_cov = kf.filter(rand_walk)

plt.plot(std_devs)
plt.show()
plt.plot(rand_walk_1)
plt.show()
plt.plot(state_cov.flatten())


The plots produced by the above code:

I read elsewhere that KFs can be used to perform recursive linear regression (I believe this is the correct term) between two variables by passing one variable for the observation_matrices argument and the other as the value to filter. So in the block below, I'm generating a second random walk with a different seed and passing that for observation_matrices rather than the fixed matrix of [1] as in the first block. Unlike the first example, this results in a covariance matrix that does not converge.

rand_walk_2, _ = generate_random_walk(1)

kf = KalmanFilter(transition_matrices = [1],
observation_matrices = rand_walk_2[:,None,None],
initial_state_mean = 1,
initial_state_covariance = 1,
observation_covariance=1,
transition_covariance=1)

state_means, state_cov = kf.filter(rand_walk_1)

plt.plot(rand_walk_2)
plt.show()
plt.plot(state_cov.flatten())


I'm really not as concerned with the second example other than to show that it's possible for the covariance matrix to not converge. In learning about Kalman Filters, my understanding was that part of the value is that the uncertainty of the estimate is quantified at each time step, i.e., that the covariance matrix is evolving with the state estimate. Again, by setting grow_std_dev=True, I would expect that the covariance matrix would need to change for the filter to make optimal predictions.

With that said, I'm wondering if I'm missing something about how KFs are supposed to work, missing an argument, or otherwise.

Any help is appreciated.

• Most KFs don’t have time varying noise covariance, and so the state covariance converges. Sometimes people forgo the full Kalyan filter and just use the converged filter. I’ll have to dig a bit further into your case to see what is happening, but that will be tomorrow.
– Peter K.
Dec 13, 2021 at 3:59

For classic Kalman Filter, where $${Q}_{k} = Q$$ and $${R}_{k} = R$$, namely the process noise covariance and the measurement noise covariance (I'm using Wikipedia - Kalman Filter notations) the Posterior Covariance $${P}_{k}$$ is a deterministic matrix independent of the measurements themselves.
In PyKalman, the initialization of the Kalman Filter with KalmanFilter() doesn't allow time changing matrices. But you have the filter_update() method which allows you to set the transition_covariance and observation_covariance per iteration which is what you need to do.
• Thanks for your answer. I replicated something like this using randomly generated numbers: stackoverflow.com/questions/49885025/… and it seems to work just to test the concept, but I assume this means that the values of transition_covariance or observation_covariance will always be unique to the problem? And varying these at each time step would qualify as an "adaptive" filter? Dec 13, 2021 at 6:15