#!/usr/bin/env python3
"``naginterface.library.tsa.kalman_unscented_state`` Python Example."
# NAG Copyright 2017-2019.
# pylint: disable=invalid-name,too-many-locals
from math import cos, pi, sin
import numpy as np
from naginterfaces.library import tsa
[docs]def main():
"""
Example for :func:`naginterfaces.library.tsa.kalman_unscented_state`.
Combined time and measurement update, one iteration of the
Unscented Kalman Filter for a nonlinear state space model,
with additive noise.
Demonstrates passing user-defined communication data to
callback functions.
>>> main()
naginterfaces.library.tsa.kalman_unscented_state Python Example Results.
Applying the UKF to a nonlinear state space model, with additive noise.
At time point 0, state estimate is:
( 0.664, -0.092, 0.104)
At time point 1, state estimate is:
( 1.598, 0.081, 0.314)
At time point 2, state estimate is:
( 2.128, 0.213, 0.378)
At time point 3, state estimate is:
( 3.134, 0.674, 0.660)
At time point 4, state estimate is:
( 3.809, 1.181, 0.906)
At time point 5, state estimate is:
( 4.730, 2.000, 1.298)
At time point 6, state estimate is:
( 4.429, 2.474, 1.762)
At time point 7, state estimate is:
( 4.357, 3.246, 2.162)
At time point 8, state estimate is:
( 3.907, 3.852, 2.246)
At time point 9, state estimate is:
( 3.360, 4.398, 2.504)
At time point 10, state estimate is:
( 2.552, 4.741, 2.750)
At time point 11, state estimate is:
( 2.191, 5.193, 3.281)
At time point 12, state estimate is:
( 1.309, 5.018, 3.610)
At time point 13, state estimate is:
( 1.071, 4.894, 4.031)
At time point 14, state estimate is:
( 0.618, 4.322, 4.124)
Estimate of the Cholesky factorization of the state
covariance matrix at the last time point:
[
1.92e-01
-3.82e-01, 2.22e-02
1.58e-06, 2.23e-07, 9.95e-03
]
"""
print(
'naginterfaces.library.tsa.kalman_unscented_state '
'Python Example Results.'
)
print(
'Applying the UKF to a nonlinear state space model, '
'with additive noise.'
)
def cb_f(xt, data):
"The (three-variable) state function."
t1 = 0.5*data['r']*(data['phi_rt'] + data['phi_lt'])
t3 = (data['r']/data['d'])*(data['phi_rt'] - data['phi_lt'])
fxt = np.empty(xt.shape)
for i in range(xt.shape[1]):
fxt[:, i] = xt[:, i] + [
cos(xt[2, i])*t1, sin(xt[2, i])*t1, t3
]
return fxt
def cb_h(my, yt, data):
"The (three-variable, two-observation) measurement function."
hyt = np.empty((my, yt.shape[1]))
for i in range(yt.shape[1]):
hyt[:, i] = [
(
data['Delta'] -
yt[0, i]*cos(data['A']) -
yt[1, i]*sin(data['A'])
),
yt[2, i] - data['A']
]
# Make sure that the theta is in the same range as the observed
# data, which in this case is [0, 2*pi)
if hyt[1, i] < 0:
hyt[1, i] = hyt[1, i] + 2*pi
return hyt
# The initial state vector:
mx = 3
x = np.zeros(mx)
# The Cholesky factorization of the covariance matrix for the
# process noise:
lx = np.diag([0.1]*mx)
# The Cholesky factorization of the initial state covariance matrix:
st = np.diag([0.1]*mx)
# Number of time points to run the system for:
ntime = 15
# Additional time-independent problem parameters
# (for communication to callback functions):
data = {'r': 3.0, 'd': 4.0, 'Delta': 5.814, 'A': 0.464}
# Additional time-dependent problem parameters:
phi_rt = [0.4]*ntime
phi_lt = [0.1]*ntime
# Observations:
y_obs = np.array([
[5.262, 5.923],
[4.347, 5.783],
[3.818, 6.181],
[2.706, 0.085],
[1.878, 0.442],
[0.684, 0.836],
[0.752, 1.300],
[0.464, 1.700],
[0.597, 1.781],
[0.842, 2.040],
[1.412, 2.286],
[1.527, 2.820],
[2.399, 3.147],
[2.661, 3.569],
[3.327, 3.659],
])
# The Cholesky factorization of the covariance matrix for the
# observation noise:
ly = np.diag([0.01]*y_obs.shape[1])
for t in range(ntime):
data['phi_rt'] = phi_rt[t]
data['phi_lt'] = phi_lt[t]
y = y_obs[t]
x, st = tsa.kalman_unscented_state(
y, lx, ly, cb_f, cb_h, x, st, data
)
print('At time point {:d}, state estimate is:'.format(t))
print('(' + ', '.join(['{:10.3f}']*len(x)).format(*x) + ')')
print('Estimate of the Cholesky factorization of the state')
print('covariance matrix at the last time point:')
print('[')
for i in range(st.shape[0]):
print(' ' + ', '.join(['{:10.2e}']*(i+1)).format(*st[i, :(i+1)]))
print(']')
if __name__ == '__main__':
import doctest
import sys
sys.exit(
doctest.testmod(
None, verbose=True, report=False,
optionflags=doctest.REPORT_NDIFF,
).failed
)