*kf
by An Uncommon Lab

Tips

This page covers techniques to make it easier to take advantage of *kf.

Writing Common Interfaces

In order to make it easy to switch between using an engine-generated filter, a framework function, or a basic filter, all functions that the user provides in *kf are expected to have a similar interface, but using only the inputs that matter for the filter architecture at hand. For instance, for an extended Kalman filter, the propagation function interface might be:

x_k = f(t_km1, t_k, x_km1, u_km1);

This will work for the linear and extended filters generated by the engine, for kff, and for an appropriate basic filter, like eif. However, for an unscented filter, it might be:

x_k = f(t_km1, t_k, x_km1, u_km1, q_km1);

That is, they're the same but for that extra noise input that the UKF uses.

When testing between different architectures or just testing different options, we probably don't want to write a bunch of different functions that all do just about the same thing. In cases like this, we can use MATLAB's nargin feature to write a single interface that can handle multiple types of interfaces. For this case:

function x_k = f(t_km1, t_k, x_km1, u_km1, q_km1)

  % If there's no q_km1 input, set a default.
  if nargin < 5
    q_km1 = [0; 0; 0];
  end
  
  x_k = ... % Some general function of x_km1, u_km1, and q_km1.;

end

In general, propagation-related interfaces will look like:

fcn(t_km1, ...      % Time at sample k-1
    t_k, ...        % Current time, sample k
    x_km1, ...      % State at sample k-1
    u_km1, ...      % Input vector (when requested)
    q_km1, ...      % Process noise (UKFs and PFs)
    c_km1, ...      % Consider parameters (UKFs with consider covariance)
    user_var_1, ... % User-provided variables
    user_var_2);

Similarly, observation-related interfaces will look like:

fcn(t_k, ...        % Current time, sample k
    x_k, ...        % State (or predicted state) at sample k
    u_km1, ...      % Input vector (when requested)
    r_k, ...        % Measurement noise (UKFs)
    c_k, ...        % Consider parameters (UKFs with consider covariance)
    user_var_1, ... % User-provided variables
    user_var_2);

Building functions that user varargin is easy, and this works fine with code generation too.

Using the Engine Programmatically

The *kf engine represents the user's configuration of a filter as a struct, allowing a user to create a filter programmatically, without the use of the graphical interface. To start with the right structure, use skfoptions.

options = skfoptions();

One can then set whatever is necessary:

% Select an unscented filter; no need to use full name.
options.filter_type = 'Uns';

To learn which option to set, open the *kf engine graphical user interface with skfengine. The option identifier for each input will be shown in the Info box on the bottom left.

To generate the code for the filter, example, etc.:

skfgen(options);

This options structure is exactly the same thing that the engine loads and saves, so if you've saved a configuration that you like, you can just load it as a .mat file to explore it:

saved = load('my_saved_configuration.mat');
saved.options

To load the current options structure into the graphical user interface:

skfengine(saved.options);

Now you can see what you've changed to make sure you're doing the right thing.

Simulations with Multi-Rate Sensors

In real applications, data sources are often not updated at the same rate. This can be handled with the updates input in the *kf engine and the framework functions. However, writing simulations for these multi-rate problems can be difficult. Our open-source odehybrid library makes it easy to quickly piece-together hybrid continuous-discrete simulations with multiple discrete rates.

Table of Contents

  1. Writing Common Interfaces
  2. Using the Engine Programmatically
  3. Simulations with Multi-Rate Sensors