def sample(self, n_timesteps, initial_state=None, random_state=None): '''Sample from model defined by the Unscented Kalman Filter Parameters ---------- n_timesteps : int number of time steps initial_state : optional, [n_dim_state] array initial state. If unspecified, will be sampled from initial state distribution. random_state : optional, int or Random random number generator ''' (transition_functions, observation_functions, transition_covariance, observation_covariance, initial_state_mean, initial_state_covariance) = (self._initialize_parameters()) n_dim_state = transition_covariance.shape[-1] n_dim_obs = observation_covariance.shape[-1] # logic for instantiating rng if random_state is None: rng = check_random_state(self.random_state) else: rng = check_random_state(random_state) # logic for selecting initial state if initial_state is None: initial_state = rng.multivariate_normal(initial_state_mean, initial_state_covariance) # logic for generating samples x = np.zeros((n_timesteps, n_dim_state)) z = np.zeros((n_timesteps, n_dim_obs)) for t in range(n_timesteps): if t == 0: x[0] = initial_state else: transition_function = (_last_dims(transition_functions, t - 1, ndims=1)[0]) transition_noise = (rng.multivariate_normal( np.zeros(n_dim_state), transition_covariance.newbyteorder('='))) x[t] = transition_function(x[t - 1], transition_noise) observation_function = (_last_dims(observation_functions, t, ndims=1)[0]) observation_noise = (rng.multivariate_normal( np.zeros(n_dim_obs), observation_covariance.newbyteorder('='))) z[t] = observation_function(x[t], observation_noise) return (x, ma.asarray(z))
def augmented_unscented_filter(mu_0, sigma_0, f, g, Q, R, Z): '''Apply the Unscented Kalman Filter with arbitrary noise Parameters ---------- mu_0 : [n_dim_state] array mean of initial state distribution sigma_0 : [n_dim_state, n_dim_state] array covariance of initial state distribution f : function or [T-1] array of functions state transition function(s). Takes in an the current state and the process noise and outputs the next state. g : function or [T] array of functions observation function(s). Takes in the current state and outputs the current observation. Q : [n_dim_state, n_dim_state] array transition covariance matrix R : [n_dim_state, n_dim_state] array observation covariance matrix Returns ------- mu_filt : [T, n_dim_state] array mu_filt[t] = mean of state at time t given observations from times [0, t] sigma_filt : [T, n_dim_state, n_dim_state] array sigma_filt[t] = covariance of state at time t given observations from times [0, t] ''' # extract size of key components T = Z.shape[0] n_dim_state = Q.shape[-1] n_dim_obs = R.shape[-1] # construct container for results mu_filt = np.zeros((T, n_dim_state)) sigma_filt = np.zeros((T, n_dim_state, n_dim_state)) for t in range(T): # Calculate sigma points for augmented state: # [actual state, transition noise, observation noise] if t == 0: mu, sigma = mu_0, sigma_0 else: mu, sigma = mu_filt[t - 1], sigma_filt[t - 1] # extract sigma points using augmented representation (points_state, points_transition, points_observation) = (augmented_unscented_filter_points( mu, sigma, Q, R)) # Calculate E[x_t | z_{0:t-1}], Var(x_t | z_{0:t-1}) and sigma points # for P(x_t | z_{0:t-1}) if t == 0: points_pred = points_state moments_pred = points2moments(points_pred) else: transition_function = _last_dims(f, t - 1, ndims=1)[0] (points_pred, moments_pred) = (unscented_filter_predict( transition_function, points_state, points_transition=points_transition)) # Calculate E[z_t | z_{0:t-1}], Var(z_t | z_{0:t-1}) observation_function = _last_dims(g, t, ndims=1)[0] mu_filt[t], sigma_filt[t] = (unscented_filter_correct( observation_function, moments_pred, points_pred, Z[t], points_observation=points_observation)) return (mu_filt, sigma_filt)
def augmented_unscented_smoother(mu_filt, sigma_filt, f, Q): '''Apply the Unscented Kalman Smoother with arbitrary noise Parameters ---------- mu_filt : [T, n_dim_state] array mu_filt[t] = mean of state at time t given observations from times [0, t] sigma_filt : [T, n_dim_state, n_dim_state] array sigma_filt[t] = covariance of state at time t given observations from times [0, t] f : function or [T-1] array of functions state transition function(s). Takes in an the current state and the process noise and outputs the next state. Q : [n_dim_state, n_dim_state] array transition covariance matrix Returns ------- mu_smooth : [T, n_dim_state] array mu_smooth[t] = mean of state at time t given observations from times [0, T-1] sigma_smooth : [T, n_dim_state, n_dim_state] array sigma_smooth[t] = covariance of state at time t given observations from times [0, T-1] ''' # extract size of key parts of problem T, n_dim_state = mu_filt.shape # instantiate containers for results mu_smooth = np.zeros(mu_filt.shape) sigma_smooth = np.zeros(sigma_filt.shape) mu_smooth[-1], sigma_smooth[-1] = mu_filt[-1], sigma_filt[-1] for t in reversed(range(T - 1)): # get sigma points for [state, transition noise] mu = mu_filt[t] sigma = sigma_filt[t] moments_state = Moments(mu, sigma) moments_transition_noise = Moments(np.zeros(n_dim_state), Q) (points_state, points_transition) = (augmented_points( [moments_state, moments_transition_noise])) # compute E[x_{t+1} | z_{0:t}], Var(x_{t+1} | z_{0:t}) f_t = _last_dims(f, t, ndims=1)[0] (points_pred, moments_pred) = unscented_transform(points_state, f_t, points_noise=points_transition) # Calculate Cov(x_{t+1}, x_t | z_{0:t-1}) sigma_pair = ((points_pred.points - moments_pred.mean).T.dot( np.diag(points_pred.weights_covariance)).dot(points_state.points - moments_state.mean).T) # compute smoothed mean, covariance smoother_gain = sigma_pair.dot(linalg.pinv(moments_pred.covariance)) mu_smooth[t] = ( mu_filt[t] + smoother_gain.dot(mu_smooth[t + 1] - moments_pred.mean)) sigma_smooth[t] = ( sigma_filt[t] + smoother_gain.dot(sigma_smooth[t + 1] - moments_pred.covariance).dot(smoother_gain.T)) return (mu_smooth, sigma_smooth)