Фильтр Калмана. Первый взгляд

ss13hyxhav_hfn8edalwf1s3qms.gif


Введение


Эта публикация дает простое и интуитивно понятное введение к вопросу об использовании фильтра Калмана. Публикация рассчитана на тех, кто слышал о фильтре Калмана, но не знает, как он работает, а также на тех, кто знает уравнения фильтра Калмана, но не знает, откуда они берутся.

Требуемые знания: знакомство с матричной алгеброй, нормальным многомерным распределением, ковариацией матриц и т. д.

Постановка задачи


Фильтр Калмана имеет множество применений в технике и экономике. Выберем не тривиальную задачу — отслеживание местоположения ракеты запущенyой из страны Y. Обозначим текущее местоположение ракеты m8enoeoau9wxm8zyxyq4vov8ylu.png как пару координат широты — a и долготы — b, на контурной карте это fw5zu1jd2eepdg0orybaa1dz7v0.png.

На данный момент времени, точные координаты х неизвестны, но мы можем определить вероятность нахождения ракеты в данной точке f6rnt1u82bo7fic0td9pxcobjl8.png исходя из двумерной плотности вероятности 2d2_vmw2uq72vdozff44cfpjeta.png. Предполагая гауссовским закон распределения, значение плотности вероятности в точке можно записать в виде:

n_xwcbdpnucwcxqxzhzgzfqit8w.png (1)

где: bxgseropunqwsg6udgf5by1pr78.png — распределение вероятности местоположения ракеты;
Σ — ковариационная матрица 2×2.

В рассматриваемой модели:

hzzzhlp4zus4y0wkpybxewpb8qu.png (2)

Используем следующий листинг для построения на плоскости эллиптической области распределения вероятности с центром красного цвета.

Листинг решения
from scipy import linalg
import numpy as np
import matplotlib.cm as cm
from matplotlib.mlab import bivariate_normal
import matplotlib.pyplot as plt
# == Настройка гостовской плотности р == #
Σ = [[0.4, 0.3], [0.3, 0.45]]
Σ = np.matrix(Σ)
x_hat = np.matrix([0.2, -0.2]).T
# ==Определим матрицы G и R из уравнения y = G x + N(0, R) == #
G = [[1, 0], [0, 1]]
G = np.matrix(G)
R = 0.5 * Σ
# == Матрицы A и Q== #
A = [[1.2, 0], [0, -0.2]]
A = np.matrix(A)
Q = 0.3 * Σ
# == Матрицы A и Q == #
y = np.matrix([2.3, -1.9]).T
# == Настройка сетки для построения графика== #
x_grid = np.linspace(-1.5, 2.9, 100)
y_grid = np.linspace(-3.1, 1.7, 100)
X, Y = np.meshgrid(x_grid, y_grid)
def gen_gaussian_plot_vals(μ, C):
"µTorrent.lnk "
m_x, m_y = float(μ[0]), float(μ[1])
s_x, s_y = np.sqrt(C[0, 0]), np.sqrt(C[1, 1])
s_xy = C[0, 1]
return bivariate_normal(X, Y, s_x, s_y, m_x, m_y, s_xy)
#Построить график
fig, ax = plt.subplots(figsize=(8,6))
ax.grid()
Z = gen_gaussian_plot_vals(x_hat, Σ)
ax.contourf(X, Y, Z, 6, alpha=0.6, cmap=cm.jet)
cs = ax.contour(X, Y, Z, 6, colors="black")
ax.clabel(cs, inline=1, fontsize=10)
plt.show()


Получим:

2_cu-d9fimup2haimafqj9mikla.png

Определение шага фильтрации


Датчики, установленные на ракете, сообщают координаты её текущего положения qokcu9lcuj_zbztngozk8ok86fm.png. Поместим эту точку на график с помощью следующего листинга.

Листинг решения
fig, ax = plt.subplots(figsize=(8, 6))
ax.grid()
Z = gen_gaussian_plot_vals(x_hat, Σ)
ax.contourf(X, Y, Z, 6, alpha=0.6, cmap=cm.jet)
cs = ax.contour(X, Y, Z, 6, colors="black")
ax.clabel(cs, inline=1, fontsize=10)
ax.text(float(y[0]), float(y[1]), "$y$", fontsize=20, color="black")
plt.show()


Получим:
9jrustabgwdtzc16sg5wln9rkek.png
Датчики неточны поэтому мы должны интерпретировать выход нашего датчика не как l0xeplcp9n4ipl_qqdqfwudloii.png, а следующим образом:
maqaegky_lho4n3wyfhpthkshma.png (3)
Здесь матрицы G и R имеют размерность 2×2, а матрица R содержит только положительные элементы. Помеха в виде шумов — yhg0w-u7htnq2fyzjxyc6bqniec.png, не зависит от измеряемых координат — crsvdfokb15h0yfgkkfoabosvya.png.
Для объединения плотности вероятности axonncftnt-43nkpm4qa7cbkcj8.png и полученного соотношения для y воспользуемся уравнением Байеса используя безусловную 2d2_vmw2uq72vdozff44cfpjeta.png и условную kr8cwenqtuznfu-ikzmsurkg_aw.png вероятности:
w6kgaec5v823xrifbjvc6fpavhm.png
где: ahb9ikoiwympnijxiwoflm6mioa.png

Для определения kr8cwenqtuznfu-ikzmsurkg_aw.png воспользуемся следующими соотношениями и условиями:


Поскольку мы находимся в линейной и гауссовой структуре, обновленная плотность может быть вычислена путем вычисления линейных регрессий; в частности, известно решение [1]:
bm_-vsohwjasxbaywuyutntf45e.png
где:
lbwuyzp7wg1huyuvfewu5g4mwjy.png
p8idr9mmot4cstkpbgwqhhfzqag.png (4)
где: 9lwta_x4mhir69qoluffufcyww0.png — матрица коэффициентов регрессии.

Эта новая плотность s7cwesxdpsjnqxki3t8olyswujo.png показана на следующем рисунке через контурные линии и цветовую карту. Первоначальная плотность оставлена в виде контурных линий для сравнения.

Листинг решения
fig, ax = plt.subplots(figsize=(8, 6))
ax.grid()
Z = gen_gaussian_plot_vals(x_hat, Σ)
cs1 = ax.contour(X, Y, Z, 6, colors="black")
ax.clabel(cs1, inline=1, fontsize=10)
M = Σ * G.T * linalg.inv(G * Σ * G.T + R)
x_hat_F = x_hat + M * (y - G * x_hat)
Σ_F = Σ - M * G * Σ
new_Z = gen_gaussian_plot_vals(x_hat_F, Σ_F)
cs2 = ax.contour(X, Y, new_Z, 6, colors="black")
ax.clabel(cs2, inline=1, fontsize=10)
ax.contourf(X, Y, new_Z, 6, alpha=0.6, cmap=cm.jet)
ax.text(float(y[0]), float(y[1]), "$y$", fontsize=20, color="black")
plt.show()


Получим:

qpud2wwefrnpz0fttrj0jvls4lo.png
Наша новая плотность «закручивает» предыдущую 2d2_vmw2uq72vdozff44cfpjeta.png в направлении, определяемом новой информацией sapb-4k-ln97mhzhbdoh4qjcof8.png.
При генерации фигуры мы устанавливаем G как единичную матрицу и 7vcd0lbc_k8ysrvzwcx0nalubp0.png
, матрица для j2sfu6z712chhopusl38uqndhq0.png согласно соотношению (2).

Прогноз на шаг вперёд


Подведём промежуточные итоги. Нами получено вероятное текущее положение ракеты с использованием информации о начальном и текущем её положении. Это имеет название фильтрация, но не прогнозирование, поскольку фильтруем от шума, но не можем предсказать местоположение ракеты в следующий момент времени.

Давайте предположим, что нам поставлена другая задача: предсказать местоположение ракеты после истечения единицы времени, не имея никакой информации о новом её местоположении.

Для решения этой задачи используем линейную гауссовою модель вида:

1vkivujkw19ap_fb7hhw-niipzq.png (5)

Наша цель — объединить этот закон движения и наше текущее распределение bm_-vsohwjasxbaywuyutntf45e.png, чтобы придумать новое предсказательное распределение для местоположения ракеты за одну единицу времени.

Ввиду (5) все, что нам нужно сделать, — ввести случайный вектор woe8d44mnyeiuy5hthx8bjbu5ag.png и выработать распределение gged0-tycfcbg7trjk1tcd3_rli.png, где w не зависит от rbanjy9uc5etzjsliodar3wxyhs.png и имеет распределение xixb0eh75d8umjbj4p3pbwaevty.png

Поскольку в (5) используются линейные комбинации случайных переменных с гауссовыми распределениями, то и gged0-tycfcbg7trjk1tcd3_rli.png также является гауссовой переменной.

После преобразований соотношений (4) с учётом введенных переменных получим:

eekymja7wfxwlfkmqhqhapinzis.png

ddmdbyyuc1sfzqeakkozto0lnge.png

ft4xy2fhdrhk6iyr8q8rmc6e130.png

Матрица 3lq4qvpbhxkpb_tpahxqjwsiaak.png часто записывается как 1mttmhge1jm9_mr9qlcsxzmc9y0.png и называется усилением Кальмана. Добавлен индекс j2sfu6z712chhopusl38uqndhq0.png, напоминающий нам, что 1mttmhge1jm9_mr9qlcsxzmc9y0.png зависит от j2sfu6z712chhopusl38uqndhq0.png, но не зависит от yfozso7uyb8mflcilnetg-iabie.png или bxgseropunqwsg6udgf5by1pr78.png

Используя эти обозначения, мы можем суммировать наши результаты следующим образом. Наше обновленное предсказание — имеет плотность вероятности rdatck7xdfmla1blbpibnvbtwmw.png, где:

q5xlguhrnjxbj2gfvipbc9hzct0.png
iahbmx2eugupwtj_fkfojw3xrz0.png (6)

Плотность rxfg6jkwqm6lsdshakcdyn1mdhm.png называется прогностическим распределением. Прогностическое распределение — это новая плотность, показанная на следующем рисунке, где использованы обновлённые параметры:

bmeapl4fcpzqzo3uyp7keex0l1o.png

Листинг решения
fig, ax = plt.subplots(figsize=(8,6))
ax.grid()
# Плотность 1
Z = gen_gaussian_plot_vals(x_hat, Σ)
cs1 = ax.contour(X, Y, Z, 6, colors="black")
ax.clabel(cs1, inline=1, fontsize=10)
# Плотность 2
M = Σ * G.T * linalg.inv(G * Σ * G.T + R)
x_hat_F = x_hat + M * (y - G * x_hat)
Σ_F = Σ - M * G * Σ
Z_F = gen_gaussian_plot_vals(x_hat_F, Σ_F)
cs2 = ax.contour(X, Y, Z_F, 6, colors="black")
ax.clabel(cs2, inline=1, fontsize=10)
# Плотность 3
new_x_hat = A * x_hat_F
new_Σ = A * Σ_F * A.T + Q
new_Z = gen_gaussian_plot_vals(new_x_hat, new_Σ)
cs3 = ax.contour(X, Y, new_Z, 6, colors="black")
ax.clabel(cs3, inline=1, fontsize=10)
ax.contourf(X, Y, new_Z, 6, alpha=0.6, cmap=cm.jet)
ax.text(float(y[0]), float(y[1]), "$y$", fontsize=20, color="black")
plt.show()


Получим:

j9ujg0gmappumzx8bkwe7xgxty0.png

Рекурсивная процедура


Давайте посмотрим на то, что мы сделали. Мы начали текущий период с 2d2_vmw2uq72vdozff44cfpjeta.png для размещения координат crsvdfokb15h0yfgkkfoabosvya.png ракеты. Затем мы использовали текущее измерение для обновления вероятности до. Наконец, мы использовали закон движения (5) для 3c8tej1m4f9pdk4cfrns3gjkthw.png обновить до f_glcq166fsyevebrgvgcqgnhiq.png.

Если мы сейчас переходим к следующему периоду, мы снова готовы взять f_glcq166fsyevebrgvgcqgnhiq.png в качестве предшествующего периода. Обозначая wivk5jugakofd9h1lhpo8oxq5k8.png для 2d2_vmw2uq72vdozff44cfpjeta.png и vxy9qu2fuhkvddahbpsyxkkujri.png для f_glcq166fsyevebrgvgcqgnhiq.png, полная рекурсивная процедура состоит:

  1. Начинаем текущий период с предшествующего wyfwr9hft8pr2u69hgrqsfmu4g0.png
  2. Получаем текущее измерение fhbhorfxymbmitp64uodouujp4e.png
  3. Вычислить распределение фильтрации hkch7305qmgvxl-aeco5_spqnfo.png изa5ymlgprwc0nxpgdp3w7p0vuxdi.png иfhbhorfxymbmitp64uodouujp4e.png, применяя правило Байеса и условное распределение (3) ;
  4. Вычислить прогностическое распределение 3ydwnhq9kjg_peimrkggswv6hh0.png из фильтрационного распределения (5);
  5. Приращение t на единицу и переход к шагу 1.

Повторяя (6), динамика для vda9ob7k4em1i-htn4pqqr57yvs.png и c4dtgozda4izy9ln070xcdm7ui4.png выглядит следующим образом:

73shrbkryoyvy-xqygvkypx9q-s.png
ldyoejzagz-4bl2fkjxbx5n1y7s.png (7)

Это стандартные динамические уравнения для фильтра Калмана (см., например, [2], с. 58)

Конвергенция


Матрицa c4dtgozda4izy9ln070xcdm7ui4.png является мерой неопределенности нашего предсказания vda9ob7k4em1i-htn4pqqr57yvs.png из -y-srvbglyuv7toxngtik6bwt9k.png. Помимо особых случаев, эта неопределенность никогда не будет полностью решена, независимо от того, сколько времени истекает.

Одна из причин заключается в том, что наше предсказание vda9ob7k4em1i-htn4pqqr57yvs.png составлено на основе информации, доступной в t-1, а не t. Даже если мы знаем точное значение 6vtzg9wubxc7u4x_qf0drdbkcpu.png (чего мы не делаем), из уравнения перехода (5) следует, что:

ygvfip68rl4hqudfu6gmskwt2ou.png

Поскольку 7rkwxbysibnifdpfmcvt72wnhsa.png не наблюдается при t-1, в любое время предсказание -y-srvbglyuv7toxngtik6bwt9k.png повлечет за собой некоторую ошибку (если 7rkwxbysibnifdpfmcvt72wnhsa.png не вырождается).

Однако, конечно, возможно, что c4dtgozda4izy9ln070xcdm7ui4.png сходится к постоянной матрице при tpz-umc_gx3bromy6raiwzj5odq.png. Чтобы изучить эту тему, давайте разберем второе уравнение в (7):

yna0murmnxpvzkqql9l4scjbeka.png (8)

Это нелинейное разностное уравнение для c4dtgozda4izy9ln070xcdm7ui4.png. Фиксированная точка (8) является постоянной матрицей Σ такой, что:

3dqp07ac4ijlnvnyiawwhijxydg.png

Уравнение (8) известно, как разностное уравнение Риккати дискретного времени. Уравнение (9) называется дискретным временным алгебраическим уравнением Риккати.

Условия, при которых существует неподвижная точка и сходящаяся к ней последовательность xc8h6n7_cjpfymjfysgkcfphwf8.png, обсуждаются в [3] и [4], глава 4.

Достаточным (но не необходимым) условием является то, что все собственные значения 5jsabmksdizwp1yf3sa2wjsmkc0.png матрицы A удовлетворяют rkxgtjlco4k5kjc3n2qar3qxlny.png (см., например, [4], стр. 77). Это сильное условие гарантирует, что безусловное распределение -y-srvbglyuv7toxngtik6bwt9k.png сходится при zb7f9y9qufoyvqypw3tgwfxoj_s.png.

В этом случае для любого начального выбора nwzoxvyskty1bdhjefohfbqeqfs.png, неотрицательного и симметричного, последовательность xc8h6n7_cjpfymjfysgkcfphwf8.png в (8) сходится к неотрицательной симметрической матрице nq16ggz7jnvyvs0uerw8jd7lv2k.png, которая является решением (9).

Реализация


Класс Kalman из пакета QuantEcon.py реализует фильтр Kalman на основе линейной модели пространства состояний следующего вида:

cdce5bx3c858ibkud6gfnleplqs.png
fcbotnitjigxi53n8jxihy9uira.png

Приведём переход переменных к принятым в публикации обозначениям:

tiuxejctw6xrznmqntttyoux2fc.png

Класс Kalman из пакета QuantEcon.py [5] имеет ряд методов, приведём те, которые относятся к данной публикации:

  • before_to_filtered, метод обновляет tiedszgyqlt1p33xivtd_plw4f8.png до tkghi_dq2rnyimsgo0wxi0isay8.png;
  • filter_to_forecast, метод обновляет распределение фильтрации до прогнозирующего распределения — которое становится новым ранее ysvbctsk8j99ssuryhkqkzn-m4k.png;
  • update, обновление, которое сочетает в себе последние два метода;
  • stationary_values, метод вычисляет решение уравнения (9) и соответствующее (стационарное) усиление Кальмана.

Примеры использования класса Kalman из пакета QuantEcon.py


Пример 1


Рассмотрим следующее простое применение фильтра Калмана взятое из [2], раздел 2.9.2. Предположим, что все переменные являются скалярами, скрытое состояние 3c8tej1m4f9pdk4cfrns3gjkthw.png фактически является постоянным, равным некоторому значению 0ponrhtzz9dzwdzpoanfzrxnuuo.png. Динамика состояний отражена в выражении (5) сn3z1kevrw2dlryehcvldr7ttdcu.png, nttgv2oqrpqfmvpfbej0_n_hpag.png и hmvb3qajni9n_nqwkxevsitq2to.png. Уравнение измерения: j4bi-xdhn7xalbtx1ktr7n10cea.png, где wgyyc4blpopx-vprt_0laqms5bc.png равно yun4oqigdbam1lxzarzorazkfia.png.

Задача этого примера с использованием kalman.py построить первые пять предсказательных плотностей 05gm78zd8rqyrktpv9jbc8miusc.png. При моделировании использовать следующие значения переменных lyu5ihpptly6yw17qlp2flgo1-w.png.

Листинг решения
from quantecon import Kalman
import numpy as np
from quantecon import LinearStateSpace
import matplotlib.pyplot as plt
from scipy.stats import norm
# == параметры == #
θ = 10 # Постоянное значение состояния x_t
A, C, G, H = 1, 0, 1, 1
ss = LinearStateSpace(A, C, G, H, mu_0=θ)
# ==задание до инициализации фильтра Калмана == #
x_hat_0, Σ_0 = 8, 1
kalman = Kalman(ss, x_hat_0, Σ_0)
# == наблюдение за измерением в модели пространства состояний== #
N = 5
x, y = ss.simulate(N)
y = y.flatten()
# == настроить график == #
fig, ax = plt.subplots(figsize=(8,6))
xgrid = np.linspace(θ - 5, θ + 2, 200)
for i in range(N):
# == записать текущее прогнозируемое среднее и дисперсию== #
m, v = [float(z) for z in (kalman.x_hat, kalman.Sigma)]
# =обновление фильтра == #
ax.plot(xgrid, norm.pdf(xgrid, loc=m, scale=np.sqrt(v)), label=f'$t={i}$')
kalman.update(y[i])
ax.set_title(f'Первые {N} распределений плотности вероятности \n при $\\theta = {θ:.1f}$')
ax.legend(loc='upper left')
plt.show()


Получим:

zumuqpllzsaloox7-e3gbgm32pm.png

Как показано в [2], в разделах 2.9.1–2.9.2, эти распределения асимптотически приближаются к неизвестному значению m5vqlmtzymjyhc_drvdldurxsms.png.

Пример 2


На предыдущем графике приведена некоторая поддержка идеи о том, что интеграл плотности вероятности сходится к m5vqlmtzymjyhc_drvdldurxsms.png.
Чтобы проверить идею, нужно выбрать небольшое 7p8cnh2dxyg9662ig4nkr1vjghg.png и вычислить интеграл:
ufsal93nwv3zezidasfh4jj7fxq.png
для ygh28olzlrltgyw5oftjx624jfk.png.

Листинг решения
from quantecon import Kalman
from numpy import*
from quantecon import LinearStateSpace
from scipy.stats import norm
import matplotlib.pyplot as plt
from scipy.integrate import quad
ϵ = 0.1
θ = 10  # Постоянное значение состояния x_t
A, C, G, H = 1, 0, 1, 1
ss = LinearStateSpace(A, C, G, H, mu_0=θ)
x_hat_0, Σ_0 = 8, 1
kalman = Kalman(ss, x_hat_0, Σ_0)
T = 600
z = empty(T)
x, y = ss.simulate(T)
y = y.flatten()
for t in range(T):
# Запись текущего предсказанного среднего, дисперсии  их плотности распределения
m, v = [float(temp) for temp in (kalman.x_hat, kalman.Sigma)]
f = lambda x: norm.pdf(x, loc=m, scale=sqrt(v))
integral, error = quad(f, θ - ϵ, θ + ϵ)
z[t] = 1 - integral
kalman.update(y[t])
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_ylim(0, 1)
ax.set_xlim(0, T)
ax.plot(range(T), z)
ax.fill_between(range(T), zeros(T), z, color="blue", alpha=0.2)
plt.show()


Получим:

ho7agdueej2x997kzjgtadmjutu.png

Пример 3


Как обсуждалось выше, последовательность saikgcboetgdku_qagogi3zhzao.png не вырождена, то в общем случае невозможно предсказать -y-srvbglyuv7toxngtik6bwt9k.png без ошибок в момент времени t-1 (и это было бы так, даже если бы мы могли наблюдать 6vtzg9wubxc7u4x_qf0drdbkcpu.png). Давайте теперь сравним предсказание vda9ob7k4em1i-htn4pqqr57yvs.png, сделанное фильтром Калмана, против конкурента, которому разрешено наблюдать 6vtzg9wubxc7u4x_qf0drdbkcpu.png.

Этот конкурент будет использовать условное ожидание a1ru4qqo9axyaav5c0xqqxybsms.png, которое в этом случае является vzvkcojb5e0afbmo_jd54vkgk0o.png… Известно, что условное ожидание является оптимальным методом прогнозирования с точки зрения минимизации среднеквадратической ошибки. (Точнее, минимизатор 5ne1hfuna3d_wy94ffeaor7nxt8.png по g равен gtdqle_93ngbvd4l9hz9vsvxi0g.png).

Таким образом, мы сравниваем фильтр Калмана с конкурентом, который имеет больше информации (в смысле возможности наблюдать скрытое состояние) и ведет себя оптимально с точки зрения минимизации квадратичной ошибки. Наши переходы будут оцениваться по квадрату ошибки.

В частности, ваша задача состоит в том, чтобы генерировать график, отображающий наблюдения как ihl_z4dhvoqp6hzpjlb4gbfe1ta.png, так и chxebuwtdjnqtpfqwso9aengzre.png против t при t=1,…,50.

Для параметров задайте gtyjph6qrbi4zr9wd3lakti2cu4.png, -1um6g5t0k855wvhzvak65c1sv8.png и wwskrukf9awkmw5t43ivwjh1-4w.png, где I — тождество 2 × 2.

Задать

o8nzjoybl55yfupeojs6s8juzv0.png.

Чтобы инициализировать предыдущую плотность, следует установить:

jchcnvjcxtbgjh8jxhxxiolxezw.png.

и flzn_eqb3cp-urne1dkrktxcnp4.png.

Наконец, установите fyvtigv07qchkrrjxfhr7m0p9zs.png.

Листинг решения
from scipy.linalg import eigvals
from quantecon import Kalman
import numpy as np
from quantecon import LinearStateSpace
import matplotlib.pyplot as plt
# === Определение A, C, G, H === #
G = np.identity(2)
H = np.sqrt(0.5) * np.identity(2)
A = [[0.5, 0.4],
      [0.6, 0.3]]
C = np.sqrt(0.3) * np.identity(2)
# === Настроить модель пространства состояний, начальное значение x_0 установить на ноль=== #
ss = LinearStateSpace(A, C, G, H, mu_0 = np.zeros(2))
# === Определить предыдущую плотность=== #
Σ = [[0.9, 0.3],
      [0.3, 0.9]]
Σ = np.array(Σ)
x_hat = np.array([8, 8])
# === Инициализировать фильтр Калмана === #
kn = Kalman(ss, x_hat, Σ)
# == Печатать собственные значения A == #
print("Собственные значения A:")
print(eigvals(A))
# == Печать стационарная Σ== #
S, K = kn.stationary_values()
print("Дисперсия ошибки стационарного прогноза:")
print(S)
# === Создать сюжет=== #
T = 50
x, y = ss.simulate(T)
e1 = np.empty(T-1)
e2 = np.empty(T-1)
for t in range(1, T):
kn.update(y[:,t])
e1[t-1] = np.sum((x[:, t] - kn.x_hat.flatten())**2)
e2[t-1] = np.sum((x[:, t] - A @ x[:, t-1])**2)
fig, ax = plt.subplots(figsize=(9,6))
ax.plot(range(1, T), e1, 'k-', lw=2, alpha=0.6, label='Ошибка фильтра Калмана')
ax.plot(range(1, T), e2, 'g-', lw=2, alpha=0.6, label='Условная математическая ошибка')
ax.legend()
plt.show()


Получим:

Собственные значения A:
[ 0.9+0.j -0.1+0.j]
Дисперсия ошибки стационарного прогноза:
[[0.40329108 0.1050718 ]
[0.1050718 0.41061709]]

clwt-pjvsecyyvtqm1ipqvxeecs.png

Пример 4


Попробуйте изменить коэффициент 0.3 в Q=0.3I вверх и вниз. Для Q=0.5I получим:

Собственные значения A:

[ 0.9+0.j -0.1+0.j]

Дисперсия ошибки стационарного прогноза:
[[0.62286148 0.12527948]
[0.12527948 0.63270989]]

bb0grbfi8kiortcfdsivnj5rfbc.png

Для Q=0.1I получим:

Собственные значения A:
[ 0.9+0.j -0.1+0.j]
Дисперсия ошибки стационарного прогноза:
[[0.16433113 0.06508848]
[0.06508848 0.16752408]]

ur8jnpi6rynqqhi-wwwk5hwbt2u.png

Заметим, как диагональные значения в стационарном решении nq16ggz7jnvyvs0uerw8jd7lv2k.png (см. (9)) возрастают и убывают в соответствии с этим коэффициентом.

Интерпретация заключается в том, что большая случайность в законе движения для приводит к большей (постоянной) неопределенности в прогнозировании.

  1. C.M. Bishop. Pattern Recognition and Machine Learning. Springer, 2006.
  2. L Ljungqvist and T J Sargent. Recursive Macroeconomic Theory. MIT Press, 4 edition, 2018.
  3. E.W. Anderson, L.P. Hansen, E.R. McGrattan, and T.J. Sargent. Mechanics of Forming and Estimating Dynamic Linear Economies. In Handbook of Computational Economics. Elsevier, vol 1 edition, 1996.
  4. D.B. O. Anderson and J.B. Moore. Optimal Filtering. Dover Publications, 2005.
  5. kalman.py.https://github.com/QuantEcon/QuantEcon.py/blob/master/quantecon/kalman.py

© Habrahabr.ru