filtro Kalman 2d en Python
Mi entrada es una serie de tiempo 2d (x,y) de un punto que se mueve en una pantalla para un software de seguimiento. Tiene algo de ruido que quiero eliminar usando el filtro Kalman. ¿Alguien puede indicarme un código Python para el filtro Kalman 2d? En el libro de cocina scipy encontré solo un ejemplo 1d: http://www.scipy.org/Cookbook/KalmanFiltering Vi que hay una implementación para el filtro Kalman en OpenCV, pero no pude encontrar ejemplos de código. ¡Gracias!
Aquí está mi implementación del filtro de Kalman basada en las ecuaciones dadas en Wikipedia . Tenga en cuenta que mi comprensión de los filtros de Kalman es muy rudimentaria, por lo que es muy probable que existan formas de mejorar este código. (Por ejemplo, sufre el problema de inestabilidad numérica discutido aquí . Según tengo entendido, esto solo afecta la estabilidad numérica cuando Q
el ruido de movimiento es muy pequeño. En la vida real, el ruido generalmente no es pequeño, así que afortunadamente (en al menos para mi implementación) en la práctica la inestabilidad numérica no aparece.)
En el siguiente ejemplo, kalman_xy
se supone que el vector de estado es una tupla de 4: 2 números para la ubicación y 2 números para la velocidad. Las matrices F
y H
se han definido específicamente para este vector de estado: Si x
es un estado de 4 tuplas, entonces
new_x = F * x
position = H * x
Luego llama a kalman
, que es el filtro de Kalman generalizado. Es general en el sentido de que sigue siendo útil si desea definir un vector de estado diferente, tal vez una tupla de 6 que represente la ubicación, la velocidad y la aceleración. Sólo tienes que definir las ecuaciones de movimiento proporcionando las apropiadas F
y H
.
import numpy as np
import matplotlib.pyplot as plt
def kalman_xy(x, P, measurement, R,
motion = np.matrix('0. 0. 0. 0.').T,
Q = np.matrix(np.eye(4))):
"""
Parameters:
x: initial state 4-tuple of location and velocity: (x0, x1, x0_dot, x1_dot)
P: initial uncertainty convariance matrix
measurement: observed position
R: measurement noise
motion: external motion added to state vector x
Q: motion noise (same shape as P)
"""
return kalman(x, P, measurement, R, motion, Q,
F = np.matrix('''
1. 0. 1. 0.;
0. 1. 0. 1.;
0. 0. 1. 0.;
0. 0. 0. 1.
'''),
H = np.matrix('''
1. 0. 0. 0.;
0. 1. 0. 0.'''))
def kalman(x, P, measurement, R, motion, Q, F, H):
'''
Parameters:
x: initial state
P: initial uncertainty convariance matrix
measurement: observed position (same shape as H*x)
R: measurement noise (same shape as H)
motion: external motion added to state vector x
Q: motion noise (same shape as P)
F: next state function: x_prime = F*x
H: measurement function: position = H*x
Return: the updated and predicted new values for (x, P)
See also http://en.wikipedia.org/wiki/Kalman_filter
This version of kalman can be applied to many different situations by
appropriately defining F and H
'''
# UPDATE x, P based on measurement m
# distance between measured and current position-belief
y = np.matrix(measurement).T - H * x
S = H * P * H.T + R # residual convariance
K = P * H.T * S.I # Kalman gain
x = x + K*y
I = np.matrix(np.eye(F.shape[0])) # identity matrix
P = (I - K*H)*P
# PREDICT x, P based on motion
x = F*x + motion
P = F*P*F.T + Q
return x, P
def demo_kalman_xy():
x = np.matrix('0. 0. 0. 0.').T
P = np.matrix(np.eye(4))*1000 # initial uncertainty
N = 20
true_x = np.linspace(0.0, 10.0, N)
true_y = true_x**2
observed_x = true_x + 0.05*np.random.random(N)*true_x
observed_y = true_y + 0.05*np.random.random(N)*true_y
plt.plot(observed_x, observed_y, 'ro')
result = []
R = 0.01**2
for meas in zip(observed_x, observed_y):
x, P = kalman_xy(x, P, meas, R)
result.append((x[:2]).tolist())
kalman_x, kalman_y = zip(*result)
plt.plot(kalman_x, kalman_y, 'g-')
plt.show()
demo_kalman_xy()
Los puntos rojos muestran las mediciones de posición ruidosas, la línea verde muestra las posiciones predichas por Kalman.
Para un proyecto mío, necesitaba crear intervalos para el modelado de series de tiempo y, para hacer el procedimiento más eficiente, creé tsmoothie : una biblioteca de Python para el suavizado de series de tiempo y la detección de valores atípicos de forma vectorizada.
Proporciona diferentes algoritmos de suavizado junto con la posibilidad de calcular intervalos.
En el caso de KalmanSmoother
, se puede operar un suavizado de una curva juntando diferentes componentes: nivel, tendencia, estacionalidad, estacionalidad larga.
import numpy as np
import matplotlib.pyplot as plt
from tsmoothie.smoother import *
from tsmoothie.utils_func import sim_randomwalk
# generate 3 randomwalks timeseries of lenght 100
np.random.seed(123)
data = sim_randomwalk(n_series=3, timesteps=100,
process_noise=10, measure_noise=30)
# operate smoothing
smoother = KalmanSmoother(component='level_trend',
component_noise={'level':0.1, 'trend':0.1})
smoother.smooth(data)
# generate intervals
low, up = smoother.get_intervals('kalman_interval', confidence=0.05)
# plot the first smoothed timeseries with intervals
plt.figure(figsize=(11,6))
plt.plot(smoother.smooth_data[0], linewidth=3, color='blue')
plt.plot(smoother.data[0], '.k')
plt.fill_between(range(len(smoother.data[0])), low[0], up[0], alpha=0.3)
Señalo también que tsmoothie puede realizar el suavizado de múltiples series temporales de forma vectorizada.