def _predict_bias(self, obs_set, fc_set): # Return a set of bias_ts per observation geo_point bias_set = api.TemperatureSourceVector() kf = api.KalmanFilter() kbp = api.KalmanBiasPredictor(kf) kta = api.TimeAxis(self.t0, api.deltahours(3), 8) for obs in obs_set: kbp.update_with_forecast(fc_set, obs.ts, kta) pattern = api.KalmanState.get_x(kbp.state) # a_ts = api.TimeSeries(pattern, api.deltahours(3), self.ta) # can do using ct of TimeSeries, or: b_ts = api.create_periodic_pattern_ts(pattern, api.deltahours(3), self.ta.time(0), self.ta) # function bias_set.append(api.TemperatureSource(obs.mid_point(), b_ts)) return bias_set
def test_compute_running_bias(self): """ Verify that if we feed forecast[n] and observation into the bias-predictor it will create the estimated bias offsets """ f = api.KalmanFilter() bp = api.KalmanBiasPredictor(f) self.assertIsNotNone(bp) self.assertEqual(bp.filter.parameter.n_daily_observations, 8) n_fc = 1 utc = api.Calendar() t0 = utc.time(2016, 1, 1) dt = api.deltahours(1) n_fc_steps = 24 * 10 # 10 days history fc_dt = api.deltahours(6) fc_fx = lambda time_axis: self._create_fc_values( time_axis, 2.0) # just return a constant 2.0 deg C for now n_obs = n_fc_steps obs_ta = api.TimeAxis(t0, dt, n_obs) obs_ts = api.TimeSeries(obs_ta, fill_value=0.0, point_fx=api.POINT_INSTANT_VALUE) kalman_dt = api.deltahours( 3) # suitable average for prediction temperature kalman_ta = api.TimeAxis(t0, kalman_dt, n_obs // 3) fc_ts = self._create_forecast_set(n_fc, t0, dt, n_fc_steps, fc_dt, fc_fx)[0] bias_ts = bp.compute_running_bias( fc_ts, obs_ts, kalman_ta) # also verify we can feed in a pure TsVector bias_pattern = bp.state.x # the bp.state.x is now the best estimates fo the bias between fc and observation self.assertEqual(len(bias_pattern), 8) for i in range(len(bias_pattern)): self.assertLess(abs(bias_pattern[i] - 2.0), 0.2) # bias should iterate to approx 2.0 degC now. # and...: for i in range(8): self.assertAlmostEqual(bias_ts.value(i), 0.0) # expect 0.0 for the first day for i in range(8): self.assertLess(abs(bias_ts.value(bias_ts.size() - i - 1) - 2.0), 0.2) # last part should be 2.0 deg.C
def test_filter(self): f = api.KalmanFilter() self.assertEqual(f.parameter.n_daily_observations, 8) s = f.create_initial_state() self.assertEqual(s.size(), 8) utc = api.Calendar() t0 = utc.time(2015, 1, 1) dt = api.deltahours(3) n = 8 ta = api.Timeaxis2(t0, dt, n) for i in range(ta.size()): f.update(2.0, ta.time(i), s) x = s.x self.assertEqual(len(x), 8) self.assertEqual(len(s.k), 8) self.assertEqual(s.P.shape[0], 8) self.assertEqual(s.P.shape[1], 8) self.assertEqual(s.W.shape[0], 8) self.assertEqual(s.W.shape[1], 8)
def test_bias_predictor(self): """ Verify that if we feed forecast[n] and observation into the bias-predictor it will create the estimated bias offsets """ f = api.KalmanFilter() bp = api.KalmanBiasPredictor(f) self.assertIsNotNone(bp) self.assertEqual(bp.filter.parameter.n_daily_observations, 8) n_fc = 8 utc = api.Calendar() t0 = utc.time(2016, 1, 1) dt = api.deltahours(1) n_fc_steps = 36 # e.g. like arome 36 hours fc_dt = api.deltahours(6) fc_fx = lambda time_axis: self._create_fc_values( time_axis, 2.0) # just return a constant 2.0 deg C for now fc_set = self._create_geo_forecast_set(n_fc, t0, dt, n_fc_steps, fc_dt, fc_fx) n_obs = 24 obs_ta = api.TimeAxis(t0, dt, n_obs) obs_ts = api.TimeSeries(obs_ta, fill_value=0.0, point_fx=api.POINT_INSTANT_VALUE) kalman_dt = api.deltahours( 3) # suitable average for prediction temperature kalman_ta = api.TimeAxis(t0, kalman_dt, 8) bp.update_with_forecast( fc_set, obs_ts, kalman_ta ) # here we feed in forecast-set and observation into kalman fc_setv = self._create_forecast_set(n_fc, t0, dt, n_fc_steps, fc_dt, fc_fx) bp.update_with_forecast( fc_setv, obs_ts, kalman_ta) # also verify we can feed in a pure TsVector bias_pattern = bp.state.x # the bp.state.x is now the best estimates fo the bias between fc and observation self.assertEqual(len(bias_pattern), 8) for i in range(len(bias_pattern)): self.assertLess(abs(bias_pattern[i] - 2.0), 0.2) # bias should iterate to approx 2.0 degC now.