Example #1
0
    def test_simulate_continuous(self):
        m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
        x0 = GaussRV(5, m0, P0)
        q = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 1e-6]))
        dyn = ReentryVehicle2DTransition(x0, q, dt=0.05)
        x = dyn.simulate_continuous(200, dt=0.05)

        plt.figure()
        plt.plot(x[0, ...], x[1, ...], color='r')
        plt.show()
    def test_cho_dot_ein(self):
        # attempt to compute the transformed covariance using cholesky decomposition

        # integrand
        # input moments
        mean_in = np.array([6500.4, 349.14, 1.8093, 6.7967, 0.6932])
        cov_in = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])

        f = ReentryVehicle2DTransition(GaussRV(5, mean_in, cov_in), GaussRV(3)).dyn_eval
        dim_in, dim_out = ReentryVehicle2DTransition.dim_state, 1

        # transform
        ker_par_mo = np.hstack((np.ones((dim_out, 1)), 25 * np.ones((dim_out, dim_in))))
        tf_so = GaussianProcessTransform(dim_in, dim_out, ker_par_mo, point_str='sr')

        # Monte-Carlo for ground truth
        # tf_ut = UnscentedTransform(dim_in)
        # tf_ut.apply(f, mean_in, cov_in, np.atleast_1d(1), None)
        tf_mc = MonteCarloTransform(dim_in, 1000)
        mean_mc, cov_mc, ccov_mc = tf_mc.apply(f, mean_in, cov_in, np.atleast_1d(1))
        C_MC = cov_mc + np.outer(mean_mc, mean_mc.T)

        # evaluate integrand
        x = mean_in[:, None] + la.cholesky(cov_in).dot(tf_so.model.points)
        Y = np.apply_along_axis(f, 0, x, 1.0, None)

        # covariance via np.dot
        iK, Q = tf_so.model.iK, tf_so.model.Q
        C1 = iK.dot(Q).dot(iK)
        C1 = Y.dot(C1).dot(Y.T)

        # covariance via np.einsum
        C2 = np.einsum('ab, bc, cd', iK, Q, iK)
        C2 = np.einsum('ab,bc,cd', Y, C2, Y.T)

        # covariance via np.dot and cholesky
        K = tf_so.model.kernel.eval(tf_so.model.kernel.par, tf_so.model.points)
        L_lower = la.cholesky(K)
        Lq = la.cholesky(Q)
        phi = la.solve(L_lower, Lq)
        psi = la.solve(L_lower, Y.T)
        bet = psi.T.dot(phi)
        C3_dot = bet.dot(bet.T)
        C3_ein = np.einsum('ij, jk', bet, bet.T)

        logging.debug("MAX DIFF: {:.4e}".format(np.abs(C1 - C2).max()))
        logging.debug("MAX DIFF: {:.4e}".format(np.abs(C3_dot - C3_ein).max()))
        self.assertTrue(np.allclose(C1, C2), "MAX DIFF: {:.4e}".format(np.abs(C1 - C2).max()))
        self.assertTrue(np.allclose(C3_dot, C3_ein), "MAX DIFF: {:.4e}".format(np.abs(C3_dot - C3_ein).max()))
        self.assertTrue(np.allclose(C1, C3_dot), "MAX DIFF: {:.4e}".format(np.abs(C1 - C3_dot).max()))
Example #3
0
    def test_single_vs_multi_output(self):
        # results of the GPQ and GPQMO should be same if parameters properly chosen, GPQ is a special case of GPQMO
        m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
        x0 = GaussRV(5, m0, P0)
        dyn = ReentryVehicle2DTransition(x0, GaussRV(5))
        f = dyn.dyn_eval
        dim_in, dim_out = dyn.dim_in, dyn.dim_state

        # input mean and covariance
        mean_in, cov_in = m0, P0

        # single-output GPQ
        ker_par_so = np.hstack((np.ones((1, 1)), 25 * np.ones((1, dim_in))))
        tf_so = GaussianProcessTransform(dim_in, dim_out, ker_par_so)

        # multi-output GPQ
        ker_par_mo = np.hstack((np.ones((dim_out, 1)), 25 * np.ones(
            (dim_out, dim_in))))
        tf_mo = MultiOutputGaussianProcessTransform(dim_in, dim_out,
                                                    ker_par_mo)

        # transformed moments
        # FIXME: transformed covariances different
        mean_so, cov_so, ccov_so = tf_so.apply(f, mean_in, cov_in,
                                               np.atleast_1d(0))
        mean_mo, cov_mo, ccov_mo = tf_mo.apply(f, mean_in, cov_in,
                                               np.atleast_1d(0))

        print('mean delta: {}'.format(np.abs(mean_so - mean_mo).max()))
        print('cov delta: {}'.format(np.abs(cov_so - cov_mo).max()))
        print('ccov delta: {}'.format(np.abs(ccov_so - ccov_mo).max()))

        # results of GPQ and GPQMO should be the same
        self.assertTrue(np.array_equal(mean_so, mean_mo))
        self.assertTrue(np.array_equal(cov_so, cov_mo))
        self.assertTrue(np.array_equal(ccov_so, ccov_mo))
Example #4
0
    def setUpClass(cls):
        cls.ssm = {}
        # setup UNGM
        x0 = GaussRV(1)
        q = GaussRV(1, cov=np.array([[10.0]]))
        r = GaussRV(1)
        dyn = UNGMTransition(x0, q)
        obs = UNGMMeasurement(r, 1)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'ungm': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})

        # setup UNGM with non-additive noise
        x0 = GaussRV(1)
        q = GaussRV(1, cov=np.array([[10.0]]))
        r = GaussRV(1)
        dyn = UNGMNATransition(x0, q)
        obs = UNGMNAMeasurement(r, 1)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'ungmna': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})

        # setup 2D pendulum
        x0 = GaussRV(2, mean=np.array([1.5, 0]), cov=0.01 * np.eye(2))
        dt = 0.01
        q = GaussRV(2,
                    cov=0.01 * np.array([[(dt**3) / 3,
                                          (dt**2) / 2], [(dt**2) / 2, dt]]))
        r = GaussRV(1, cov=np.array([[0.1]]))
        dyn = Pendulum2DTransition(x0, q, dt=dt)
        obs = Pendulum2DMeasurement(r, dyn.dim_state)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'pend': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})

        # setup reentry vehicle radar tracking
        m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
        x0 = GaussRV(5, m0, P0)
        q = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 1e-6]))
        r = GaussRV(2, cov=np.diag([1e-6, 0.17e-6]))
        dyn = ReentryVehicle2DTransition(x0, q)
        obs = Radar2DMeasurement(r, 5)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'rer': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})

        # setup coordinated turn bearing only tracking
        m0 = np.array([1000, 300, 1000, 0, np.deg2rad(-3.0)])
        P0 = np.diag([100, 10, 100, 10, 0.1])
        x0 = GaussRV(5, m0, P0)
        dt = 0.1
        rho_1, rho_2 = 0.1, 1.75e-4
        A = np.array([[dt**3 / 3, dt**2 / 2], [dt**2 / 2, dt]])
        Q = np.zeros((5, 5))
        Q[:2, :2], Q[2:4, 2:4], Q[4, 4] = rho_1 * A, rho_1 * A, rho_2 * dt
        q = GaussRV(5, cov=Q)
        r = GaussRV(4, cov=10e-3 * np.eye(4))
        sen = np.vstack((1000 * np.eye(2), -1000 * np.eye(2))).astype(np.float)
        dyn = CoordinatedTurnTransition(x0, q)
        obs = BearingMeasurement(r, 5, state_index=[0, 2], sensor_pos=sen)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'ctb': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})

        # setup CTRS with radar measurements
        x0 = GaussRV(5, cov=0.1 * np.eye(5))
        q = GaussRV(2, cov=np.diag([0.1, 0.1 * np.pi]))
        r = GaussRV(2, cov=np.diag([0.3, 0.03]))
        dyn = ConstantTurnRateSpeed(x0, q)
        obs = Radar2DMeasurement(r, 5)
        x = dyn.simulate_discrete(100)
        y = obs.simulate_measurements(x)
        cls.ssm.update({'ctrs': {'dyn': dyn, 'obs': obs, 'x': x, 'y': y}})
Example #5
0
def reentry_gpq_demo():
    mc_sims = 20
    disc_tau = 0.5  # discretization period

    # ground-truth data generator (true system)
    m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 0])
    x0 = GaussRV(5, m0, P0)
    Q = np.diag([2.4064e-5, 2.4064e-5, 0])
    q = GaussRV(3, cov=Q)
    sys = ReentryVehicle2DTransition(x0, q, dt=disc_tau)

    # radar measurement model
    r = GaussRV(2, cov=np.diag([1e-6, 0.17e-6]))
    radar_x, radar_y = sys.R0, 0
    obs = Radar2DMeasurement(r, 5, radar_loc=np.array([radar_x, radar_y]))

    # Generate reference trajectory by Euler-Maruyama integration
    x = sys.simulate_continuous(duration=200, dt=disc_tau, mc_sims=mc_sims)
    x_ref = x.mean(axis=2)

    # generate radar measurements
    y = obs.simulate_measurements(x)

    # setup SSM for the filter
    m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0])
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
    x0 = GaussRV(5, m0, P0)
    q = GaussRV(3, cov=disc_tau*Q)
    dyn = ReentryVehicle2DTransition(x0, q, dt=disc_tau)

    # Initialize filters
    hdyn = np.array([[1.0, 25, 25, 25, 25, 25]])
    hobs = np.array([[1.0, 25, 25, 1e4, 1e4, 1e4]])
    alg = (
        GaussianProcessKalman(dyn, obs, hdyn, hobs, kernel='rbf', points='ut'),
        UnscentedKalman(dyn, obs),
    )

    # Are both filters using the same sigma-points?
    # assert np.array_equal(alg[0].tf_dyn.model.points, alg[1].tf_dyn.unit_sp)

    num_alg = len(alg)
    d, steps, mc_sims = x.shape
    mean, cov = np.zeros((d, steps, mc_sims, num_alg)), np.zeros((d, d, steps, mc_sims, num_alg))
    for imc in range(mc_sims):
        for ia, a in enumerate(alg):
            mean[..., imc, ia], cov[..., imc, ia] = a.forward_pass(y[..., imc])
            a.reset()

    # Plots
    plt.figure()
    g = GridSpec(2, 4)
    plt.subplot(g[:, :2])

    # Earth surface w/ radar position
    t = 0.02 * np.arange(-1, 4, 0.1)
    plt.plot(sys.R0 * np.cos(t), sys.R0 * np.sin(t), color='darkblue', lw=2)
    plt.plot(radar_x, radar_y, 'ko')

    plt.plot(x_ref[0, :], x_ref[1, :], color='r', ls='--')
    # Convert from polar to cartesian
    meas = np.stack((radar_x + y[0, ...] * np.cos(y[1, ...]), radar_y + y[0, ...] * np.sin(y[1, ...])), axis=0)
    for i in range(mc_sims):
        # Vehicle trajectory
        # plt.plot(x[0, :, i], x[1, :, i], alpha=0.35, color='r', ls='--')

        # Plot measurements
        plt.plot(meas[0, :, i], meas[1, :, i], 'k.', alpha=0.3)

        # Filtered position estimate
        plt.plot(mean[0, 1:, i, 0], mean[1, 1:, i, 0], color='g', alpha=0.3)
        plt.plot(mean[0, 1:, i, 1], mean[1, 1:, i, 1], color='orange', alpha=0.3)

    # Performance score plots
    error2 = mean.copy()
    lcr = np.zeros((steps, mc_sims, num_alg))
    for a in range(num_alg):
        for k in range(steps):
            mse = mse_matrix(x[:4, k, :], mean[:4, k, :, a])
            for imc in range(mc_sims):
                error2[:, k, imc, a] = squared_error(x[:, k, imc], mean[:, k, imc, a])
                lcr[k, imc, a] = log_cred_ratio(x[:4, k, imc], mean[:4, k, imc, a], cov[:4, :4, k, imc, a], mse)

    # Averaged RMSE and Inclination Indicator in time
    pos_rmse_vs_time = np.sqrt((error2[:2, ...]).sum(axis=0)).mean(axis=1)
    inc_ind_vs_time = lcr.mean(axis=1)

    # Plots
    plt.subplot(g[0, 2:])
    plt.title('RMSE')
    plt.plot(pos_rmse_vs_time[:, 0], label='GPQKF', color='g')
    plt.plot(pos_rmse_vs_time[:, 1], label='UKF', color='r')
    plt.legend()
    plt.subplot(g[1, 2:])
    plt.title('Inclination Indicator $I^2$')
    plt.plot(inc_ind_vs_time[:, 0], label='GPQKF', color='g')
    plt.plot(inc_ind_vs_time[:, 1], label='UKF', color='r')
    plt.legend()
    plt.show()

    print('Average RMSE: {}'.format(pos_rmse_vs_time.mean(axis=0)))
    print('Average I2: {}'.format(inc_ind_vs_time.mean(axis=0)))
Example #6
0
def reentry_demo(dur=200, mc_sims=100, outfile=None):
    # use default filename if unspecified
    if outfile is None:
        outfile = 'reentry_demo_results.dat'
    outfile = os.path.join('..', outfile)

    if not os.path.exists(outfile) or True:
        tau = 0.05
        disc_tau = 0.1

        # initial condition statistics
        m0 = np.array([6500, 350, -1.8, -6.8, 0.7])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 0])
        init_rv = GaussRV(5, m0, P0)

        # process noise statistics
        noise_rv = GaussRV(3, cov=np.diag([2.4e-5, 2.4e-5, 0]))
        sys = ReentryVehicle2DTransition(init_rv, noise_rv)

        # measurement noise statistics
        meas_noise_rv = GaussRV(2, cov=np.diag([1e-6, 0.17e-6]))
        obs = Radar2DMeasurement(meas_noise_rv,
                                 5,
                                 radar_loc=np.array([6374, 0.0]))

        np.random.seed(0)
        # Generate reference trajectory by SDE simulation
        x = sys.simulate_continuous(duration=dur, dt=tau, mc_sims=mc_sims)
        y = obs.simulate_measurements(x)

        # subsample data for the filter and performance score calculation
        x = x[:, ::2, ...]  # take every second point on the trajectory
        y = y[:, ::2, ...]  # and corresponding measurement

        # Initialize state-space model with mis-specified initial mean
        # m0 = np.array([6500.4, 349.14, -1.1093, -6.1967, 0.6932])
        m0 = np.array([6500, 350, -1.1, -6.1, 0.7])
        P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
        init_rv = GaussRV(5, m0, P0)
        noise_rv = GaussRV(3, cov=np.diag([2.4e-5, 2.4e-5, 1e-6]))
        dyn = ReentryVehicle2DTransition(init_rv, noise_rv, dt=disc_tau)
        # NOTE: higher tau causes higher spread of trajectories at the ends

        # Initialize filters
        par_dyn = np.array([[1.0, 1, 1, 1, 1, 1]])
        par_obs = np.array([[1.0, 0.9, 0.9, 1e4, 1e4,
                             1e4]])  # np.atleast_2d(np.ones(6))
        mul_ut = np.hstack((np.zeros((dyn.dim_in, 1)), np.eye(dyn.dim_in),
                            2 * np.eye(dyn.dim_in))).astype(np.int)
        alg = OrderedDict({
            # GaussianProcessKalman(ssm, par_dyn, par_obs, kernel='rbf', points='ut'),
            'bsqkf':
            BayesSardKalman(dyn,
                            obs,
                            par_dyn,
                            par_obs,
                            mul_ut,
                            mul_ut,
                            points='ut'),
            'bsqkf_2e-6':
            BayesSardKalman(dyn,
                            obs,
                            par_dyn,
                            par_obs,
                            mul_ut,
                            mul_ut,
                            points='ut'),
            'bsqkf_2e-7':
            BayesSardKalman(dyn,
                            obs,
                            par_dyn,
                            par_obs,
                            mul_ut,
                            mul_ut,
                            points='ut'),
            'ukf':
            UnscentedKalman(dyn, obs, beta=0.0),
        })

        alg['bsqkf'].tf_dyn.model.model_var = np.diag(
            [0.0002, 0.0002, 0.0002, 0.0002, 0.0002])
        alg['bsqkf'].tf_obs.model.model_var = 0 * np.eye(2)
        alg['bsqkf_2e-6'].tf_dyn.model.model_var = 2e-6 * np.eye(5)
        alg['bsqkf_2e-6'].tf_obs.model.model_var = 0 * np.eye(2)
        alg['bsqkf_2e-7'].tf_dyn.model.model_var = 2e-7 * np.eye(5)
        alg['bsqkf_2e-7'].tf_obs.model.model_var = 0 * np.eye(2)

        # print experiment setup
        print('System (reality)')
        print('{:10s}: {}'.format('x0_mean', sys.init_rv.mean))
        print('{:10s}: {}'.format('x0_cov', sys.init_rv.cov.diagonal()))
        print()
        print('State-Space Model')
        print('{:10s}: {}'.format('x0_mean', dyn.init_rv.mean))
        print('{:10s}: {}'.format('x0_cov', dyn.init_rv.cov.diagonal()))
        print()
        print('BSQ Expected Model Variance')
        print('{:10s}: {}'.format(
            'dyn_func', alg['bsqkf'].tf_dyn.model.model_var.diagonal()))
        print('{:10s}: {}'.format(
            'obs_func', alg['bsqkf'].tf_obs.model.model_var.diagonal()))
        print()

        num_alg = len(alg)
        d, steps, mc_sims = x.shape
        mean, cov = np.zeros((d, steps, mc_sims, num_alg)), np.zeros(
            (d, d, steps, mc_sims, num_alg))
        for ia, a in enumerate(alg):
            print('Running {:<5} ... '.format(a.upper()), end='', flush=True)
            t0 = time.time()
            for imc in range(mc_sims):
                mean[..., imc, ia], cov[..., imc,
                                        ia] = alg[a].forward_pass(y[..., imc])
                alg[a].reset()
            print('{:>30}'.format('Done in {:.2f} [sec]'.format(time.time() -
                                                                t0)))

        # Performance score plots
        print()
        print('Computing performance scores ...')
        error2 = mean.copy()
        lcr_x = np.zeros((steps, mc_sims, num_alg))
        lcr_pos = lcr_x.copy()
        lcr_vel = lcr_x.copy()
        lcr_theta = lcr_x.copy()
        for a in range(num_alg):
            for k in range(steps):
                mse = mse_matrix(x[:, k, :], mean[:, k, :, a])
                for imc in range(mc_sims):
                    error2[:, k, imc,
                           a] = squared_error(x[:, k, imc], mean[:, k, imc, a])
                    lcr_x[k, imc,
                          a] = log_cred_ratio(x[:, k, imc], mean[:, k, imc, a],
                                              cov[:, :, k, imc, a], mse)
                    lcr_pos[k, imc,
                            a] = log_cred_ratio(x[:2, k, imc], mean[:2, k, imc,
                                                                    a],
                                                cov[:2, :2, k, imc,
                                                    a], mse[:2, :2])
                    lcr_vel[k, imc,
                            a] = log_cred_ratio(x[2:4, k, imc], mean[2:4, k,
                                                                     imc, a],
                                                cov[2:4, 2:4, k, imc,
                                                    a], mse[2:4, 2:4])
                    lcr_theta[k, imc,
                              a] = log_cred_ratio(x[4, k, imc], mean[4, k, imc,
                                                                     a],
                                                  cov[4, 4, k, imc, a], mse[4,
                                                                            4])

        # Averaged RMSE and Inclination Indicator in time
        x_rmse_vs_time = np.sqrt(error2.sum(axis=0)).mean(axis=1)
        pos_rmse_vs_time = np.sqrt((error2[:2, ...]).sum(axis=0)).mean(axis=1)
        vel_rmse_vs_time = np.sqrt((error2[2:4, ...]).sum(axis=0)).mean(axis=1)
        theta_rmse_vs_time = np.sqrt((error2[4, ...])).mean(axis=1)
        x_inc_vs_time = lcr_x.mean(axis=1)
        pos_inc_vs_time = lcr_pos.mean(axis=1)
        vel_inc_vs_time = lcr_vel.mean(axis=1)
        theta_inc_vs_time = lcr_theta.mean(axis=1)

        print('{:10s}: {}'.format('RMSE', x_rmse_vs_time.mean(axis=0)))
        print('{:10s}: {}'.format('INC', x_inc_vs_time.mean(axis=0)))

        # Save the simulation results into outfile
        data_dict = {
            'duration': dur,
            'disc_tau': disc_tau,
            'alg_str': list(alg.keys()),
            'x': x,
            'mean': mean,
            'cov': cov,
            'state': {
                'rmse': x_rmse_vs_time,
                'inc': x_inc_vs_time
            },
            'position': {
                'rmse': pos_rmse_vs_time,
                'inc': pos_inc_vs_time
            },
            'velocity': {
                'rmse': vel_rmse_vs_time,
                'inc': vel_inc_vs_time
            },
            'parameter': {
                'rmse': theta_rmse_vs_time,
                'inc': theta_inc_vs_time
            },
        }
        joblib.dump(data_dict, outfile)

        # Visualize simulation results, plots, tables
        reentry_demo_results(data_dict)
    else:
        reentry_demo_results(joblib.load(outfile))
Example #7
0
def reentry_analysis_demo(dur=50, mc_sims=10):
    tau = 0.05
    disc_tau = 0.1

    # initial condition statistics
    m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 0])
    init_rv = GaussRV(5, m0, P0)

    # process noise statistics
    noise_rv = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 0]))
    sys = ReentryVehicle2DTransition(init_rv, noise_rv)

    # measurement noise statistics
    dim_obs = 2
    meas_noise_rv = GaussRV(dim_obs, cov=np.diag([1e-6, 0.17e-6]))
    obs = Radar2DMeasurement(meas_noise_rv, 5, radar_loc=np.array([6374, 0.0]))

    np.random.seed(0)
    # Generate reference trajectory by SDE simulation
    x = sys.simulate_continuous(duration=dur, dt=tau, mc_sims=mc_sims)
    y = obs.simulate_measurements(x)

    # subsample data for the filter and performance score calculation
    x = x[:, ::2, ...]  # take every second point on the trajectory
    y = y[:, ::2, ...]  # and corresponding measurement

    # Initialize state-space model with mis-specified initial mean
    m0 = np.array([6500.4, 349.14, -1.1093, -6.1967, 0.6932])
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
    init_rv = GaussRV(5, m0, P0)
    noise_rv = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 1e-6]))
    dyn = ReentryVehicle2DTransition(init_rv, noise_rv, dt=disc_tau)
    # NOTE: higher tau causes higher spread of trajectories at the ends

    # Initialize filters
    par_dyn = np.array([[1.0, 1, 1, 1, 1, 1]])
    par_obs = np.array([[1.0, 0.9, 0.9, 1e4, 1e4,
                         1e4]])  # np.atleast_2d(np.ones(6))
    mul_ut = np.hstack((np.zeros((dyn.dim_in, 1)), np.eye(dyn.dim_in),
                        2 * np.eye(dyn.dim_in))).astype(np.int)
    alg = OrderedDict({
        # GaussianProcessKalman(ssm, par_dyn, par_obs, kernel='rbf', points='ut'),
        'bsqkf':
        BayesSardKalman(dyn,
                        obs,
                        par_dyn,
                        par_obs,
                        mul_ut,
                        mul_ut,
                        points='ut'),
        'ukf':
        UnscentedKalman(dyn, obs, kappa=0.0, beta=2.0),
    })

    alg['bsqkf'].tf_dyn.model.model_var = np.diag([0.1, 0.1, 0.1, 0.1, 0.015])
    alg['bsqkf'].tf_obs.model.model_var = 0 * np.eye(2)
    print('BSQ EMV\ndyn: {} \nobs: {}'.format(
        alg['bsqkf'].tf_dyn.model.model_var.diagonal(),
        alg['bsqkf'].tf_obs.model.model_var.diagonal()))

    # FILTERING
    num_alg = len(alg)
    d, steps, mc_sims = x.shape
    mean, cov = np.zeros((d, steps, mc_sims, num_alg)), np.zeros(
        (d, d, steps, mc_sims, num_alg))
    mean_x, cov_x = mean.copy(), cov.copy()
    mean_y, cov_y = np.zeros((dim_obs, steps, mc_sims, num_alg)), np.zeros(
        (dim_obs, dim_obs, steps, mc_sims, num_alg))
    cov_yx = np.zeros((dim_obs, d, steps, mc_sims, num_alg))

    # y = np.hstack((np.zeros((dim_obs, 1, mc_sims)), y))
    for ia, a in enumerate(alg):
        print('Running {:<5} ... '.format(a.upper()), end='', flush=True)
        t0 = time.time()
        for imc in range(mc_sims):
            for k in range(steps):

                # TIME UPDATE
                alg[a]._time_update(k)
                # record predictive moments
                mean_x[:, k, imc,
                       ia], cov_x[..., k, imc,
                                  ia] = alg[a].x_mean_pr, alg[a].x_cov_pr
                mean_y[:, k, imc,
                       ia], cov_y[..., k, imc,
                                  ia] = alg[a].y_mean_pr, alg[a].y_cov_pr
                cov_yx[..., k, imc, ia] = alg[a].xy_cov

                # MEASUREMENT UPDATE
                alg[a]._measurement_update(y[:, k, imc])
                # record filtered moments
                mean[:, k, imc,
                     ia], cov[..., k, imc,
                              ia] = alg[a].x_mean_fi, alg[a].x_cov_fi

            # reset filter storage
            alg[a].reset()
        print('{:>30}'.format('Done in {:.2f} [sec]'.format(time.time() - t0)))
Example #8
0
def ukf_trunc_demo(mc_sims=50):
    disc_tau = 0.5  # discretization period in seconds
    duration = 200

    # define system
    m0 = np.array([6500.4, 349.14, -1.8093, -6.7967, 0.6932])
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 0])
    x0 = GaussRV(5, m0, P0)
    q = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 0]))
    sys = ReentryVehicle2DTransition(x0, q, dt=disc_tau)
    # define radar measurement model
    r = GaussRV(2, cov=np.diag([1e-6, 0.17e-6]))
    obs = Radar2DMeasurement(r, sys.dim_state)

    # simulate reference state trajectory by SDE integration
    x = sys.simulate_continuous(duration, disc_tau, mc_sims)
    x_ref = x.mean(axis=2)
    # simulate corresponding radar measurements
    y = obs.simulate_measurements(x)

    # initialize state-space model; uses cartesian2polar as measurement (not polar2cartesian)
    P0 = np.diag([1e-6, 1e-6, 1e-6, 1e-6, 1])
    x0 = GaussRV(5, m0, P0)
    q = GaussRV(3, cov=np.diag([2.4064e-5, 2.4064e-5, 1e-6]))
    dyn = ReentryVehicle2DTransition(x0, q, dt=disc_tau)

    # initialize UKF and UKF in truncated version
    alg = (
        UnscentedKalman(dyn, obs),
        TruncatedUnscentedKalman(dyn, obs),
    )
    num_alg = len(alg)

    # space for filtered mean and covariance
    steps = x.shape[1]
    x_mean = np.zeros((dyn.dim_in, steps, mc_sims, num_alg))
    x_cov = np.zeros((dyn.dim_in, dyn.dim_in, steps, mc_sims, num_alg))

    # filtering estimate of the state trajectory based on provided measurements
    from tqdm import trange
    for i_est, estimator in enumerate(alg):
        for i_mc in trange(mc_sims):
            x_mean[..., i_mc, i_est], x_cov[..., i_mc, i_est] = estimator.forward_pass(y[..., i_mc])
            estimator.reset()

    # Plots
    plt.figure()
    g = GridSpec(2, 4)
    plt.subplot(g[:, :2])

    # Earth surface w/ radar position
    radar_x, radar_y = dyn.R0, 0
    t = 0.02 * np.arange(-1, 4, 0.1)
    plt.plot(dyn.R0 * np.cos(t), dyn.R0 * np.sin(t), color='darkblue', lw=2)
    plt.plot(radar_x, radar_y, 'ko')

    plt.plot(x_ref[0, :], x_ref[1, :], color='r', ls='--')
    # Convert from polar to cartesian
    meas = np.stack(( + y[0, ...] * np.cos(y[1, ...]), radar_y + y[0, ...] * np.sin(y[1, ...])), axis=0)
    for i in range(mc_sims):
        # Vehicle trajectory
        # plt.plot(x[0, :, i], x[1, :, i], alpha=0.35, color='r', ls='--')

        # Plot measurements
        plt.plot(meas[0, :, i], meas[1, :, i], 'k.', alpha=0.3)

        # Filtered position estimate
        plt.plot(x_mean[0, 1:, i, 0], x_mean[1, 1:, i, 0], color='g', alpha=0.3)
        plt.plot(x_mean[0, 1:, i, 1], x_mean[1, 1:, i, 1], color='orange', alpha=0.3)

    # Performance score plots
    error2 = x_mean.copy()
    lcr = np.zeros((steps, mc_sims, num_alg))
    for a in range(num_alg):
        for k in range(steps):
            mse = mse_matrix(x[:4, k, :], x_mean[:4, k, :, a])
            for imc in range(mc_sims):
                error2[:, k, imc, a] = squared_error(x[:, k, imc], x_mean[:, k, imc, a])
                lcr[k, imc, a] = log_cred_ratio(x[:4, k, imc], x_mean[:4, k, imc, a], x_cov[:4, :4, k, imc, a], mse)

    # Averaged RMSE and Inclination Indicator in time
    pos_rmse_vs_time = np.sqrt((error2[:2, ...]).sum(axis=0)).mean(axis=1)
    inc_ind_vs_time = lcr.mean(axis=1)

    # Plots
    plt.subplot(g[0, 2:])
    plt.title('RMSE')
    plt.plot(pos_rmse_vs_time[:, 0], label='UKF', color='g')
    plt.plot(pos_rmse_vs_time[:, 1], label='UKF-trunc', color='r')
    plt.legend()
    plt.subplot(g[1, 2:])
    plt.title('Inclination Indicator $I^2$')
    plt.plot(inc_ind_vs_time[:, 0], label='UKF', color='g')
    plt.plot(inc_ind_vs_time[:, 1], label='UKF-trunc', color='r')
    plt.legend()
    plt.show()

    print('Average RMSE: {}'.format(pos_rmse_vs_time.mean(axis=0)))
    print('Average I2: {}'.format(inc_ind_vs_time.mean(axis=0)))