def test_kalman_filter_without_prior_predict(self): t0 = dt.datetime(2017, 5, 12, 16, 18, 25, 204000) process = proc.WienerProcess.create_from_cov(mean=3., cov=25.) kf = kalman.KalmanFilter(t0, state_distr=N(mean=100., cov=250.), process=process) observable = kf.create_observable( kalman.KalmanFilterObsModel.create(1.), process) t1 = t0 + dt.timedelta(hours=1) observable.observe(time=t1, obs=N(mean=100.35, cov=100.0)) posterior_predicted_obs1 = observable.predict(t1) npt.assert_almost_equal(posterior_predicted_obs1.distr.mean, 100.28590504) npt.assert_almost_equal(posterior_predicted_obs1.distr.cov, 71.513353115) npt.assert_almost_equal(posterior_predicted_obs1.cross_cov, posterior_predicted_obs1.distr.cov) t2 = t1 + dt.timedelta(hours=2) observable.observe(time=t2, obs=N(mean=100.35, cov=100.0)) posterior_predicted_obs2 = observable.predict(t2) npt.assert_almost_equal(posterior_predicted_obs2.distr.mean, 100.45709020) npt.assert_almost_equal(posterior_predicted_obs2.distr.cov, 42.395213845) npt.assert_almost_equal(posterior_predicted_obs2.cross_cov, posterior_predicted_obs2.distr.cov)
def predict(self, time, true_value=None): if time < self._time: raise ValueError( 'Predicting the past (current time=%s, prediction time=%s)' % (self._time, time)) if true_value is not None and filtering.FilterPypeOptions.TRUE_VALUE in self._pype_options: self._pype.send(filtering.TrueValue(self, self._time, true_value)) if time == self._time: return state_distrs = [] row = 0 for p in self._processes: process_dim = p.process_dim m = self._state_distr.mean[row:row + process_dim, 0:1] c = self._state_distr.cov[row:row + process_dim, row:row + process_dim] state_distrs.append( p.propagate_distr(time, self._time, N(mean=m, cov=c))) row += process_dim state_mean = np.vstack([d.mean for d in state_distrs]) state_cov = block_diag(*[d.cov for d in state_distrs]) self._state_distr = N(mean=state_mean, cov=state_cov, copy=False) self._is_posterior = False self._time = time if filtering.FilterPypeOptions.PRIOR_STATE in self._pype_options: self._pype.send(self.state)
def process_run_df(self, df): auto_refresh = self._auto_refresh self._auto_refresh = False try: for i in range(len(df)): time = df.iloc[i]['time'] observable_name = df.iloc[i]['observable_name'] accepted = df.iloc[i]['accepted'] obs_mean = df.iloc[i]['obs_mean'] obs_cov = df.iloc[i]['obs_cov'] predicted_obs_mean = df.iloc[i]['predicted_obs_mean'] predicted_obs_cov = df.iloc[i]['predicted_obs_cov'] cross_cov = df.iloc[i]['cross_cov'] innov_mean = df.iloc[i]['innov_mean'] innov_cov = df.iloc[i]['innov_cov'] prior_state_mean = df.iloc[i]['prior_state_mean'] prior_state_cov = df.iloc[i]['prior_state_cov'] posterior_state_mean = df.iloc[i]['posterior_state_mean'] posterior_state_cov = df.iloc[i]['posterior_state_cov'] true_value = df.iloc[i]['true_value'] log_likelihood = df.iloc[i]['log_likelihood'] gain = df.iloc[i]['gain'] # TODO Use an appropriate FilterState, it doesn't have to be KalmanFilterState prior_filter_state_object = kalman.KalmanFilterState( None, time, False, N(prior_state_mean, prior_state_cov), self._filter_name) # TODO Use an appropriate FilterState, it doesn't have to be KalmanFilterState posterior_filter_state_object = kalman.KalmanFilterState( None, time, True, N(posterior_state_mean, posterior_state_cov), self._filter_name) self.process_filter_object(prior_filter_state_object) self.process_filter_object(posterior_filter_state_object) # Need the following check to skip the initial state row, which # may be present in the DataFrame: if not (i == 0 and observable_name is None): true_value_object = filtering.TrueValue( None, time, true_value, self._filter_name) obs = filtering.Obs(None, time, N(obs_mean, obs_cov), observable_name) predicted_obs = filtering.PredictedObs( None, time, N(predicted_obs_mean, predicted_obs_cov), cross_cov, observable_name) innov_distr = N(innov_mean, innov_cov) # TODO Use an appropriate ObsResult, it doesn't have to be KalmanObsResult obs_result_object = kalman.KalmanObsResult( accepted, obs, predicted_obs, innov_distr, log_likelihood, gain) if true_value is not None: self.process_filter_object(true_value_object) if obs_mean is not None: self.process_filter_object(obs_result_object) finally: self.refresh() self._auto_refresh = auto_refresh
def observe(self, obs_distr, predicted_obs, true_value): if true_value is not None and filtering.FilterPypeOptions.TRUE_VALUE in self._pype_options: self._pype.send(filtering.TrueValue(self, self._time, true_value)) innov = obs_distr.mean - predicted_obs.distr.mean innov_cov = predicted_obs.distr.cov + obs_distr.cov innov_cov_inv = np.linalg.inv(innov_cov) gain = np.dot(predicted_obs.cross_cov.T, innov_cov_inv) m = self._state_distr.mean + np.dot(gain, innov) c = self._state_distr.cov - np.dot(gain, predicted_obs.cross_cov) self._state_distr = N(mean=m, cov=c, copy=False) self._is_posterior = True if filtering.FilterPypeOptions.POSTERIOR_STATE in self._pype_options: self._pype.send(self.state) log_likelihood = -.5 * (obs_distr.dim * KalmanFilter.LN_2PI + np.log(np.linalg.det(innov_cov)) + \ np.dot(np.dot(innov.T, innov_cov_inv), innov)) obs = filtering.Obs(predicted_obs.observable, self._time, obs_distr) obs_result = KalmanObsResult(True, obs, predicted_obs, N(mean=innov, cov=innov_cov, copy=False), log_likelihood, gain) if filtering.FilterPypeOptions.OBS_RESULT in self._pype_options: self._pype.send(obs_result) return obs_result
def testkalmanfilterwithlowvarianceobs(self): t0 = dt.datetime(2017, 5, 12, 16, 18, 25, 204000) process = proc.WienerProcess.create_from_cov(mean=3., cov=25.) kf = kalman.KalmanFilter(t0, state_distr=N(mean=100., cov=250.), process=process) observable = kf.create_observable( kalman.KalmanFilterObsModel.create(1.), process) t1 = t0 + dt.timedelta(hours=1) observable.observe(time=t1, obs=N(mean=200., cov=0.0)) posterior_predicted_obs1 = observable.predict(t1) npt.assert_almost_equal(posterior_predicted_obs1.distr.mean, 200.0) npt.assert_almost_equal(posterior_predicted_obs1.distr.cov, 2.8421709430404007E-14) npt.assert_almost_equal(posterior_predicted_obs1.cross_cov, posterior_predicted_obs1.distr.cov)
def predict(self, time, true_value=None): if time < self._time: raise ValueError( 'Predicting the past (current time=%s, prediction time=%s)' % (self._time, time)) if true_value is not None and filtering.FilterPypeOptions.TRUE_VALUE in self._pype_options: self._pype.send(filtering.TrueValue(self, self._time, true_value)) if time == self._time: return state_distrs = [] row = 0 for p in self._processes: process_dim = p.process_dim m = self._state_distr.mean[row:row + process_dim, 0:1] c = self._state_distr.cov[row:row + process_dim, row:row + process_dim] state_distr = p.propagate_distr( self._time, N(mean=m, cov=c), time, assume_distr=self._approximate_distr) if not isinstance(state_distr, N): if self._approximate_distr: state_distr = N.approximate(state_distr, copy=False) else: raise ValueError( 'The propagated state distribution is not Normal; to approximate with a Normal distribution, set the approximate_distr parameter to True (currently False)' ) state_distrs.append(state_distr) row += process_dim state_mean = np.vstack([d.mean for d in state_distrs]) state_cov = block_diag(*[d.cov for d in state_distrs]) self._state_distr = N(mean=state_mean, cov=state_cov, copy=False) self._is_posterior = False self._time = time if filtering.FilterPypeOptions.PRIOR_STATE in self._pype_options: self._pype.send(self.state)
def predict_obs(self, time, state_distr, observable=None): obs_mean = np.dot(self._obs_matrix, state_distr.mean) cross_cov = np.dot(self._obs_matrix, state_distr.cov) obs_cov = np.dot(cross_cov, self._obs_matrix.T) return filtering.PredictedObs(observable, time, N(mean=obs_mean, cov=obs_cov), cross_cov)
def _sub_state_distr(self, state_distr): return N(mean=self._sub_state_mean(state_distr.mean), cov=self._sub_state_cov(state_distr.cov), copy=False)
def _sub_state_distr(self, state_distr): # TODO Does this even make sense? return N(mean=self._sub_state_mean(state_distr.mean), cov=self._sub_state_cov(state_distr.cov), copy=False)
def testkalmanfiltermultid(self): t0 = dt.datetime(2017, 5, 12, 16, 18, 25, 204000) process1 = proc.WienerProcess.create_from_cov(mean=3., cov=25.) process2 = proc.WienerProcess.create_from_cov(mean=[1., 4.], cov=[[36.0, -9.0], [-9.0, 25.0]]) kf = kalman.KalmanFilter(t0, state_distr=N(mean=[100.0, 120.0, 130.0], cov=[[250.0, 0.0, 0.0], [0.0, 360.0, 0.0], [0.0, 0.0, 250.0]]), process=(process1, process2)) state_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(1.0, np.eye(2)), process1, process2) coord0_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(1.), process1) coord1_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(npu.row(1., 0.)), process2) coord2_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(npu.row(0., 1.)), process2) sum_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(npu.row(1., 1., 1.)), process1, process2) lin_comb_observable = kf.create_observable( kalman.KalmanFilterObsModel.create(npu.row(2., 0., -3.)), process1, process2) t1 = t0 + dt.timedelta(hours=1) predicted_obs1_prior = state_observable.predict(t1) npt.assert_almost_equal( predicted_obs1_prior.distr.mean, npu.col(100.0 + 3.0 / 24.0, 120.0 + 1.0 / 24.0, 130.0 + 4.0 / 24.0)) npt.assert_almost_equal(predicted_obs1_prior.distr.cov, [[250.0 + 25.0 / 24.0, 0.0, 0.0], [0.0, 360.0 + 36.0 / 24.0, -9.0 / 24.0], [0.0, -9.0 / 24.0, 250 + 25.0 / 24.0]]) npt.assert_almost_equal(predicted_obs1_prior.cross_cov, predicted_obs1_prior.distr.cov) state_observable.observe(time=t1, obs=N(mean=[100.35, 121.0, 135.0], cov=[[100.0, 0.0, 0.0], [0.0, 400.0, 0.0], [0.0, 0.0, 100.0]])) predicted_obs1_posterior = state_observable.predict(t1) npt.assert_almost_equal( predicted_obs1_posterior.distr.mean, npu.col(100.285905044, 120.493895183, 133.623010239)) npt.assert_almost_equal( predicted_obs1_posterior.distr.cov, [[71.513353115, 0.0, 0.0], [0.0, 189.888267669, -0.056112925], [0.0, -0.056112925, 71.513338130]]) npt.assert_almost_equal(predicted_obs1_posterior.cross_cov, predicted_obs1_posterior.distr.cov) predicted_obs1_0 = coord0_observable.predict(t1) npt.assert_almost_equal(predicted_obs1_0.distr.mean, 100.285905044) npt.assert_almost_equal(predicted_obs1_0.distr.cov, 71.513353115) npt.assert_almost_equal(predicted_obs1_0.cross_cov, npu.row(71.513353115, 0.0, 0.0)) predicted_obs1_1 = coord1_observable.predict(t1) npt.assert_almost_equal(predicted_obs1_1.distr.mean, 120.493895183) npt.assert_almost_equal(predicted_obs1_1.distr.cov, 189.888267669) npt.assert_almost_equal(predicted_obs1_1.cross_cov, npu.row(0.0, 189.888267669, -0.056112925)) predicted_obs1_2 = coord2_observable.predict(t1) npt.assert_almost_equal(predicted_obs1_2.distr.mean, 133.623010239) npt.assert_almost_equal(predicted_obs1_2.distr.cov, 71.513338130) npt.assert_almost_equal(predicted_obs1_2.cross_cov, npu.row(0.0, -0.056112925, 71.513338130)) predicted_obs1_sum = sum_observable.predict(t1) npt.assert_almost_equal(predicted_obs1_sum.distr.mean, 354.402810466) npt.assert_almost_equal(predicted_obs1_sum.distr.cov, 332.802733064) npt.assert_almost_equal( predicted_obs1_sum.cross_cov, npu.row(71.513353115, 189.832154744, 71.457225204)) predicted_obs1_lin_comb = lin_comb_observable.predict(t1) npt.assert_almost_equal(predicted_obs1_lin_comb.distr.mean, -200.297220628) npt.assert_almost_equal(predicted_obs1_lin_comb.distr.cov, 929.673455633) npt.assert_almost_equal( predicted_obs1_lin_comb.cross_cov, npu.row(143.026706231, 0.168338776, -214.540014390)) t2 = t1 + dt.timedelta(minutes=30) coord1_observable.observe(time=t2, obs=N(mean=125.25, cov=4.)) predicted_obs2_1 = coord1_observable.predict(t2) npt.assert_almost_equal(predicted_obs2_1.distr.mean, 125.152685704) npt.assert_almost_equal(predicted_obs2_1.distr.cov, 3.917796226) npt.assert_almost_equal(predicted_obs2_1.cross_cov, npu.row(0.0, 3.917796226, -0.005006475)) t3 = t2 + dt.timedelta(minutes=30) predicted_obs3_prior_sum = sum_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_prior_sum.distr.mean, 359.368174232) npt.assert_almost_equal(predicted_obs3_prior_sum.distr.cov, 149.392502944) npt.assert_almost_equal( predicted_obs3_prior_sum.cross_cov, npu.row(72.555019782, 4.475289751, 72.36219341)) predicted_obs3_prior0 = coord0_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_prior0.distr.mean, 100.410905044) npt.assert_almost_equal(predicted_obs3_prior0.distr.cov, 72.555019782) npt.assert_almost_equal(predicted_obs3_prior0.cross_cov, npu.row(72.555019782, 0.0, 0.0)) predicted_obs3_prior1 = coord1_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_prior1.distr.mean, 125.173519037) npt.assert_almost_equal(predicted_obs3_prior1.distr.cov, 4.667796226) npt.assert_almost_equal(predicted_obs3_prior1.cross_cov, npu.row(0.0, 4.667796226, -0.192506475)) predicted_obs3_prior2 = coord2_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_prior2.distr.mean, 133.783750150) npt.assert_almost_equal(predicted_obs3_prior2.distr.cov, 72.554699886) npt.assert_almost_equal(predicted_obs3_prior2.cross_cov, npu.row(0.0, -0.192506475, 72.554699886)) sum_observable.observe(time=t3, obs=N(mean=365.00, cov=9.)) predicted_obs3_posterior_sum = sum_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_posterior_sum.distr.mean, 364.679994753) npt.assert_almost_equal(predicted_obs3_posterior_sum.distr.cov, 8.488612159) npt.assert_almost_equal(predicted_obs3_posterior_sum.cross_cov, npu.row(4.122639429, 0.254289862, 4.111682867)) predicted_obs3_posterior0 = coord0_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_posterior0.distr.mean, 102.990681374) npt.assert_almost_equal(predicted_obs3_posterior0.distr.cov, 39.319665849) npt.assert_almost_equal(predicted_obs3_posterior0.cross_cov, npu.row(39.319665849, 0.0, 0.0)) predicted_obs3_posterior1 = coord1_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_posterior1.distr.mean, 125.332643059) npt.assert_almost_equal(predicted_obs3_posterior1.distr.cov, 4.541349469) npt.assert_almost_equal(predicted_obs3_posterior1.cross_cov, npu.row(0.0, 4.541349469, -2.237058941)) predicted_obs3_posterior2 = coord2_observable.predict(t3) npt.assert_almost_equal(predicted_obs3_posterior2.distr.mean, 136.356670319) npt.assert_almost_equal(predicted_obs3_posterior2.distr.cov, 39.495767563) npt.assert_almost_equal(predicted_obs3_posterior2.cross_cov, npu.row(0.0, -2.237058941, 39.495767563))