예제 #1
0
class TestKalmanContinuousDiscrete(OrnsteinUhlenbeckCDTestCase):
    """
    Try Kalman filtering on a continuous-discrete setting.

    Try OU process.
    """
    def setUp(self):
        super().setup_ornsteinuhlenbeck()
        self.method = Kalman(self.dynmod, self.measmod, self.initrv)

    def test_dynamicmodel(self):
        self.assertEqual(self.dynmod, self.method.dynamicmodel)

    def test_measurementmodel(self):
        self.assertEqual(self.measmod, self.method.measurementmodel)

    def test_initialdistribution(self):
        self.assertEqual(self.initrv, self.method.initialrandomvariable)

    def test_predict_shape(self):
        pred, _ = self.method.predict(0.0, self.delta_t, self.initrv)
        self.assertEqual(pred.mean.shape, (1, ))
        self.assertEqual(pred.cov.shape, (1, 1))

    def test_predict_value(self):
        pred, _ = self.method.predict(0.0, self.delta_t, self.initrv)
        ah = scipy.linalg.expm(self.delta_t * self.drift)
        qh = (self.q / (2 * self.lam) *
              (1 - scipy.linalg.expm(2 * self.drift * self.delta_t)))
        expectedmean = np.squeeze(ah @ (self.initrv.mean * np.ones(1)))
        expectedcov = np.squeeze(ah @ (self.initrv.cov * np.eye(1)) @ ah.T +
                                 qh)
        self.assertApproxEqual(expectedmean, pred.mean)
        self.assertApproxEqual(expectedcov, pred.cov)

    def test_update(self):
        data = self.measmod.transition_realization(
            self.initrv.mean * np.ones(1), 0.0)[0].sample()
        upd, __, __, __ = self.method.update(0.0, self.initrv, data)
        self.assertEqual(upd.mean.shape, (1, ))
        self.assertEqual(upd.cov.shape, (1, 1))

    def test_smoother(self):
        """
        RMSE of filter smaller than rmse of measurements?
        """
        filter_posterior = self.method.filter(self.obs, self.tms)
        filtms = filter_posterior.state_rvs.mean
        smooth_posterior = self.method.filtsmooth(self.obs, self.tms)
        smooms = smooth_posterior.state_rvs.mean

        self.assertEqual(filtms[1:].shape, self.states[1:].shape)
        self.assertEqual(smooms[1:].shape, self.states[1:].shape)
        self.assertEqual(self.obs.shape, self.states[1:].shape)

        normaliser = np.sqrt(self.states[1:].size)
        filtrmse = np.linalg.norm(filtms[1:] - self.states[1:]) / normaliser
        smoormse = np.linalg.norm(smooms[1:] - self.states[1:]) / normaliser
        obs_rmse = np.linalg.norm(self.obs - self.states[1:]) / normaliser

        if VISUALISE is True:
            plt.title("Ornstein Uhlenbeck (%.2f < " % smoormse +
                      "%.2f < %.2f?)" % (filtrmse, obs_rmse))
            plt.plot(self.tms[1:],
                     self.obs[:, 0],
                     ".",
                     label="Observations",
                     alpha=0.5)
            plt.plot(self.tms, filtms, "-", label="Filter guess")
            plt.plot(self.tms, smooms, "-", label="Smoother guess")
            plt.plot(self.tms,
                     self.states,
                     "-",
                     linewidth=6,
                     alpha=0.25,
                     label="Truth")
            plt.legend()
            plt.show()
        self.assertLess(smoormse, filtrmse)
        self.assertLess(filtrmse, obs_rmse)
예제 #2
0
 def setUp(self):
     super().setup_ornsteinuhlenbeck()
     self.method = Kalman(self.dynmod, self.measmod, self.initrv)
예제 #3
0
 def setUp(self):
     super().setup_cartracking()
     self.method = Kalman(self.dynmod, self.measmod, self.initrv)
예제 #4
0
class TestKalmanDiscreteDiscrete(CarTrackingDDTestCase):
    """
    Try Kalman filtering and smoothing on a discrete setting.
    """
    def setUp(self):
        super().setup_cartracking()
        self.method = Kalman(self.dynmod, self.measmod, self.initrv)

    def test_dynamicmodel(self):
        self.assertEqual(self.dynmod, self.method.dynamicmodel)

    def test_measurementmodel(self):
        self.assertEqual(self.measmod, self.method.measurementmodel)

    def test_initialdistribution(self):
        self.assertEqual(self.initrv, self.method.initialrandomvariable)

    def test_predict(self):
        pred, _ = self.method.predict(0.0, self.delta_t, self.initrv)
        self.assertEqual(pred.mean.ndim, 1)
        self.assertEqual(pred.mean.shape[0], 4)
        self.assertEqual(pred.cov.ndim, 2)
        self.assertEqual(pred.cov.shape[0], 4)
        self.assertEqual(pred.cov.shape[1], 4)

    def test_update(self):
        data = self.measmod.transition_realization(self.initrv.mean,
                                                   0.0)[0].sample()
        upd, __, __, __ = self.method.update(0.0, self.initrv, data)
        self.assertEqual(upd.mean.ndim, 1)
        self.assertEqual(upd.mean.shape[0], 4)
        self.assertEqual(upd.cov.ndim, 2)
        self.assertEqual(upd.cov.shape[0], 4)
        self.assertEqual(upd.cov.shape[1], 4)

    def test_filtsmooth(self):
        """
        RMSE of smoother smaller than rmse of filter smaller
        than of measurements?
        """
        filter_posterior = self.method.filter(self.obs, self.tms)
        filtms = filter_posterior.state_rvs.mean
        smooth_posterior = self.method.filtsmooth(self.obs, self.tms)
        smooms = smooth_posterior.state_rvs.mean

        normaliser = np.sqrt(self.states[1:, :2].size)
        filtrmse = np.linalg.norm(filtms[1:, :2] -
                                  self.states[1:, :2]) / normaliser
        smoormse = np.linalg.norm(smooms[1:, :2] -
                                  self.states[1:, :2]) / normaliser
        obs_rmse = np.linalg.norm(self.obs - self.states[1:, :2]) / normaliser

        if VISUALISE is True:
            plt.title("Car tracking trajectory (%.2f " % smoormse +
                      "< %.2f < %.2f?)" % (filtrmse, obs_rmse))
            plt.plot(self.obs[:, 0],
                     self.obs[:, 1],
                     ".",
                     label="Observations",
                     alpha=0.5)
            plt.plot(filtms[:, 0], filtms[:, 1], "-", label="Filter guess")
            plt.plot(smooms[:, 0], smooms[:, 1], "-", label="Smoother guess")
            plt.plot(
                self.states[:, 0],
                self.states[:, 1],
                "-",
                linewidth=6,
                alpha=0.25,
                label="Truth",
            )
            plt.legend()
            plt.show()
        self.assertLess(smoormse, filtrmse)
        self.assertLess(filtrmse, obs_rmse)
예제 #5
0
class TestKalmanPosterior(CarTrackingDDTestCase, NumpyAssertions):
    def setUp(self):
        super().setup_cartracking()
        self.method = Kalman(self.dynmod, self.measmod, self.initrv)
        self.posterior = self.method.filter(self.obs, self.tms)

    def test_len(self):
        self.assertTrue(len(self.posterior) > 0)
        self.assertEqual(len(self.posterior.locations), len(self.posterior))
        self.assertEqual(len(self.posterior.state_rvs), len(self.posterior))

    def test_locations(self):
        self.assertArrayEqual(self.posterior.locations,
                              np.sort(self.posterior.locations))

        self.assertApproxEqual(self.posterior.locations[0], self.tms[0])
        self.assertApproxEqual(self.posterior.locations[-1], self.tms[-1])

    def test_getitem(self):
        self.assertArrayEqual(self.posterior[0].mean,
                              self.posterior.state_rvs[0].mean)
        self.assertArrayEqual(self.posterior[0].cov,
                              self.posterior.state_rvs[0].cov)

        self.assertArrayEqual(self.posterior[-1].mean,
                              self.posterior.state_rvs[-1].mean)
        self.assertArrayEqual(self.posterior[-1].cov,
                              self.posterior.state_rvs[-1].cov)

        self.assertArrayEqual(self.posterior[:].mean,
                              self.posterior.state_rvs[:].mean)
        self.assertArrayEqual(self.posterior[:].cov,
                              self.posterior.state_rvs[:].cov)

    def test_state_rvs(self):
        self.assertTrue(
            isinstance(self.posterior.state_rvs, _RandomVariableList))

        self.assertEqual(len(self.posterior.state_rvs[0].shape), 1)
        self.assertEqual(self.posterior.state_rvs[-1].shape, self.initrv.shape)

    def test_call_error_if_small(self):
        self.assertLess(-0.5, self.tms[0])
        with self.assertRaises(ValueError):
            self.posterior(-0.5)

    def test_call_vectorisation(self):
        locs = np.arange(0, 1, 20)
        evals = self.posterior(locs)
        self.assertEqual(len(evals), len(locs))

    def test_call_interpolation(self):
        self.assertLess(self.tms[0], 9.88)
        self.assertGreater(self.tms[-1], 9.88)
        self.assertTrue(9.88 not in self.tms)
        self.posterior(9.88)

    def test_call_to_discrete(self):
        self.assertEqual(self.tms[0], 0)
        self.assertArrayEqual(self.posterior(0.0).mean, self.posterior[0].mean)
        self.assertArrayEqual(self.posterior(0.0).cov, self.posterior[0].cov)

        self.assertEqual(self.tms[-1], 19.8)
        self.assertArrayEqual(
            self.posterior(19.8).mean, self.posterior[-1].mean)
        self.assertArrayEqual(self.posterior(19.8).cov, self.posterior[-1].cov)

        self.assertArrayEqual(
            self.posterior(self.tms[2]).mean, self.posterior[2].mean)
        self.assertArrayEqual(
            self.posterior(self.tms[5]).mean, self.posterior[5].mean)
        self.assertArrayEqual(
            self.posterior(self.tms[10]).mean, self.posterior[10].mean)

    def test_call_extrapolation(self):
        self.assertGreater(30, self.tms[-1])
        self.posterior(30)
예제 #6
0
 def setUp(self):
     super().setup_cartracking()
     self.method = Kalman(self.dynmod, self.measmod, self.initrv)
     self.posterior = self.method.filter(self.obs, self.tms)
예제 #7
0
class TestKalmanPosteriorSampling(CarTrackingDDTestCase, NumpyAssertions):
    def setUp(self):
        super().setup_cartracking()
        self.method = Kalman(self.dynmod, self.measmod, self.initrv)
        self.posterior = self.method.filter(self.obs, self.tms)

    def test_output_shape(self):
        loc_inputs = [
            None,
            self.posterior.locations[[2, 3]],
            np.arange(0.0, 0.5, 0.025),
        ]
        dim = (self.method.dynamod.dimension, )
        single_sample_shapes = [
            (len(self.posterior), self.method.dynamod.dimension),
            (2, self.method.dynamod.dimension),
            (len(loc_inputs[-1]), self.method.dynamod.dimension),
        ]

        for size in [(), (5, ), (2, 3, 4)]:
            for loc, loc_shape in zip(loc_inputs, single_sample_shapes):
                with self.subTest(size=size, loc=loc):
                    sample = self.posterior.sample(locations=loc, size=size)
                    if size == ():
                        self.assertEqual(sample.shape, loc_shape)
                    else:
                        self.assertEqual(sample.shape, size + loc_shape)

    def test_sampling_all_locations_multiple_samples(self):
        five_samples = self.posterior.sample(size=5)

        chi_squared = np.array([
            chi_squared_statistic(sample, self.posterior[:].mean,
                                  self.posterior[:].cov)
            for sample in five_samples
        ]).mean()
        self.assertLess(chi_squared, 10.0)
        self.assertLess(0.1, chi_squared)

    def test_sampling_two_locations_multiple_samples(self):
        locs = self.posterior.locations[[2, 3]]
        five_samples = self.posterior.sample(locations=locs, size=5)

        chi_squared = np.array([
            chi_squared_statistic(
                sample,
                self.posterior[:].mean[[2, 3]],
                self.posterior[:].cov[[2, 3]],
            ) for sample in five_samples
        ]).mean()
        self.assertLess(chi_squared, 10.0)
        self.assertLess(0.1, chi_squared)

    def test_sampling_many_locations_multiple_samples(self):
        locs = np.arange(0.0, 0.5, 0.025)
        five_samples = self.posterior.sample(locations=locs, size=5)

        chi_squared = np.array([
            chi_squared_statistic(sample,
                                  self.posterior(locs).mean,
                                  self.posterior(locs).cov)
            for sample in five_samples
        ]).mean()
        self.assertLess(chi_squared, 10.0)
        self.assertLess(0.1, chi_squared)