classdef BaseDiscreteSystemModel < BaseSystemModel
%BASEDISCRETESYSTEMMODEL Abstract base class for discrete system models
% BaseDiscreteSystemModel is a base class that encapsulates the
% evolution of a discrete noisy system. It is abstract, and cannot
% be directly instantiated.
%
% It models the system with time evolution
% x(t+1) = f(x(t), t) + v
% where v is gaussian noise with mean 0 and covariance Q, or more
% generally, the system
% x(t+1) = f(x(t), t, v)
%
% BaseDiscreteSystemModel methods:
% simulate - simulate a noisy measurement.
% predict - given probability distribution of current
% state, predict next state
%
properties
f;
Q;
isLinearNoise = true;
J_x; % Jacobian of f with respect to x, if known
J_v; % Jacobian of f with respect to v, if known
end
properties (Access = protected)
cholQ;
end
methods
function sysModel = BaseDiscreteSystemModel(f, Q, varargin)
if nargin == 0
return;
end
if isa(f, 'BaseDiscreteSystemModel')
assert(nargin == 1, 'Too many arguments');
sysModel.f = f.f;
sysModel.Q = f.Q;
sysModel.isLinearNoise = f.isLinearNoise;
sysModel.J_x = f.J_x;
sysModel.J_v = f.J_v;
sysModel.cholQ = f.cholQ;
else
sysModel.f = f;
sysModel.Q = Q;
sysModel.cholQ = sdchol(sysModel.Q);
if ~isempty(varargin)
% now parse option/value pairs
for k = 1:2:length(varargin)
sysModel.(varargin{k}) = varargin{k+1};
end
end
end
end
function x = simulate(this, x, dt, t)
if nargin == 3
t = 0; % if current time not specified, assume irrelevent. Should we
% warn instead?
elseif nargin == 2
t = 0;
dt = 1;
end
assert(abs(dt - round(dt)) < eps, 'dt must be an integer.');
dt = round(dt);
cholQ = this.cholQ;
for k=1:dt
v = (randn(1, size(cholQ, 1)) * cholQ)';
if this.isLinearNoise
x = this.f(x, t) + v;
else
x = this.f(x, t, v);
end
end
end
end
% inherit the abstract method
% [x, P] = predict(this, x, P, dt, curTime)
% from BaseSystemModel
end