KalmanFilter
model.h
1 #ifndef MODEL_H
2 #define MODEL_H
3 
4 #include <assert.h>
5 #include <stdexcept>
6 
7 /*
8  * Empty class designed for representing a model. Inherited types
9  * include discrete and continuos version. K represents time unit.
10  * The reason for various sub classes is for more user to clearly
11  * understand what models they are working with.
12  */
13 template <class K>
14 class model{};
15 
32 template <typename T> class continuousModel: public model<double>{
33  public:
42  virtual T function(const T & val, const double time) const = 0;
43 };
44 
57 template <typename T> class discreteModel: public model<int>{
58  public:
68  virtual T function(const T& val, const int index) const = 0;
69 };
70 
71 /*
72  * Abstract jacobian that defines a general Jacobian class. Class declares
73  * a single method `function` that returns the jacobian of a variable val
74  * evaluated at time T. The function with which the Jacobian is associated
75  * here is not defined here and it is the users responsibility that the Jacobian
76  * is correct.
77  * This is akin to the model<K> type class from which continuousModel<G> and
78  * discreteModel<G> inherit from.
79  * The reason for various sub classes is for more user to clearly
80  * understand what jacobians they are working with.
81  */
82 template<class VECTOR, class MATRIX, class T>
83 class jacobian{
84  public:
86  virtual MATRIX function(const VECTOR& val, const T t) = 0;
87 };
88 
89 
90 /*
91  * Abstract jacobianContinuous. Class declares
92  * a single method `function` that returns the jacobian of a variable val
93  * evaluated at time T. The function with which the Jacobian is associated
94  * here is not defined here and it is the users responsibility that the Jacobian
95  * is correct. The jacobianContinuous in other classes is associated with a continuousModel.
96  * See continuousModel<K> for an example of what the jacobianContinuous<K> implementation
97  * would look like.
98  */
99 template <class VECTOR, class MATRIX>
100 class jacobianContinuous: public jacobian<VECTOR,MATRIX,double>{
101  public:
103  virtual MATRIX function(const VECTOR & val, double t) = 0;
104 };
105 
106 
107 
108 /*
109  * Abstract jacobianDiscrete. Class declares
110  * a single method `function` that returns the jacobian of a variable val
111  * evaluated at time T. The function with which the Jacobian is associated
112  * here is not defined here and it is the users responsibility that the Jacobian
113  * is correct. The jacobianDiscrete in other classes is associated with a discreteModel.
114  * See continuousModel<K> for an example of what the jacobianContinuous<K> implementation
115  * would look like.
116  */
117 template <class VECTOR, class MATRIX>
118 class jacobianDiscrete: public jacobian<VECTOR,MATRIX,int>{
119  public:
121  virtual MATRIX function(const VECTOR & val, int t) = 0;
122 };
123 
124 
125 /*
126  * Abstract class akin to continuousModel<K> and discreteModel<K>
127  * where 'function' only takes time T argument and returns type M
128  * argument.
129  */
130 template <class M, class T1>
132  public:
133  //Pure virtual method.
134  virtual M const function(T1 t) = 0;
135 };
136 
137 
138 template<class VECTOR, class MATRIX, class T>
140  public:
142  virtual MATRIX function(const VECTOR& val, const T t) = 0;
143  virtual MATRIX sqrt(const VECTOR & val, int t) = 0;
144 };
145 
146 
147 template <class VECTOR, class MATRIX>
148 class discreteNoiseCovariance: public noiseCovariance<VECTOR,MATRIX,int>{
149  public:
151  virtual MATRIX function(const VECTOR & val, int t) = 0;
152  virtual MATRIX sqrt(const VECTOR & val, int t) = 0;
153 };
154 
155 
156 /*
157  * Non abstract solver for solving discrete models.
158  * Unlike continuousSolver<T> there is no abstract base class
159  * for the discrete case as there is no variance for
160  * discrete solvers since all the hard work is encoded in the
161  * discreteModel. Despite this, both discreteSolver<T>
162  * and continuousSolver<T> have very similar methods and variables
163  * raising the question as to why they do not inherit from the same method.
164  * This was an initial 'mistake' and is now the way the code is.
165  */
166 template<class T> class discreteSolver{
167  private:
169  const discreteModel<T> *M;
170 
172  int currentIndex;
173 
175  T currentState;
176 
177  public:
178  /*
179  * \param startIndex initial time
180  * \param startState initial state of model at startIndex
181  * Constructor.
182  */
183  discreteSolver(const discreteModel<T> *M, const int startIndex, const T& startState)
184  :M(M),currentIndex(startIndex),currentState(startState){}
185 
186  /*
187  * Constructor for when no model provided. No check is conducted to
188  * see if user ran setInitialConditions before running solve - in the
189  * case when user does that the behaviour is undefined.
190  */
192 
194  void solve(int stepsForward){
195  if(stepsForward < 0){
196  throw std::out_of_range("");
197  }
198  for(int i = 0; i < stepsForward; i++){
199  currentState = M->function(currentState,currentIndex);
200  currentIndex++;
201  }
202  }
203 
204  /*
205  * Setter of time and current model state included in order for easier solver reuse.
206  */
207  void setInitialConditions(const T & newState, int newIndex){
208  currentState = newState;
209  currentIndex = newIndex;
210  }
211 
214  return currentState;
215  }
216 
218  double getCurrentIndex(){
219  return currentIndex;
220  }
221 
222  /*
223  * Interface for interacting with model. Does not affect
224  * the solver's stored current time and current state.
225  */
226  T evaluateModel(const T & t,const double time){
227  return M->function(t,time);
228  }
229 };
230 
231 /*
232  * Abstract numerical solver of ODEs represented by continuousModel<T>
233  */
234 template<class T>class continuousSolver{
235  private:
237  const continuousModel<T> *M;
238 
240  double currentTime;
241 
243  T currentState;
244 
245  //TODO:destructor/constructor?
246  public:
247  /*
248  * \param startTime initial time
249  * \param startState initial state of model at initial time
250  * \param continuousModel encoding ODE
251  * Constructor.
252  */
253  continuousSolver(const continuousModel<T> *M, const double startTime, const T& startState)
254  :M(M),currentTime(startTime),currentState(startState){};
255 
256  /*
257  * Solve timeForward time units forward from currentTime.
258  * This pure virtual method leaves the detail of solving the
259  * continuousModel up to the inheriting class - be it Eulers, RK4
260  * or whatever.
261  */
262  virtual void solve(double timeForward) = 0;
263 
264  /*
265  * Setter of time and current model state included in order for easier solver reuse.
266  */
267  void setInitialConditions(const T & newState, double newTime){
268  currentState = newState;
269  currentTime = newTime;
270  }
271 
274  return currentState;
275  }
276 
278  double getCurrentTime(){
279  return currentTime;
280  }
281 
282  /*
283  * Interface for interacting with model. Does not affect
284  * the solver's stored current time and current state.
285  */
286  T evaluateModel(const T & t,const double time) const{
287  return M->function(t,time);
288  }
289 };
290 
291 
292 /*
293  * Non abstract RK4 solver inheriting from continuousSolver<T>
294  */
295 template <typename T> class continuousSolverRK4: public continuousSolver<T>{
296 
297  private:
299  double timeStep;
300  public:
301  /*
302  * \param startTime initial time
303  * \param startState initial state of model at initial time
304  * \param continuousModel encoding ODE
305  * \param timeStep the timestep RK4 will use
306  * Constructor.
307  */
308  continuousSolverRK4( continuousModel<T>* M,const double startTime,const T& startState, double timeStep):
309  continuousSolver<T>(M,startTime,startState),timeStep(timeStep){
310  }
311 
312  /*
313  * Implementation of solve method that is pure virtual in superclass continuousSolver.
314  * Propagate the current state and current time according to the ODE described in continuousModel
315  * provided in the constructor.
316  */
317  void solve(double timeForward){
318 
319  if(timeForward < 0){
320  throw std::out_of_range("");
321  }
322 
323  double localTime = continuousSolver<T>::getCurrentTime();
325 
326  double startTime = localTime;
327  double localTimeStep = timeStep;
328  double finalTime = startTime + timeForward;
329 
330  while(localTime < finalTime){
331  //deal with unequal timestep not dividing evently into timeForward
332  if(localTime + localTimeStep > finalTime){
333  localTimeStep = finalTime - localTime;
334  }
335 
336  T k1 = localTimeStep*continuousSolver<T>::evaluateModel(tmp , localTime );
337  T k2 = localTimeStep*continuousSolver<T>::evaluateModel(tmp + 0.5*k1, localTime + 0.5*localTimeStep);
338  T k3 = localTimeStep*continuousSolver<T>::evaluateModel(tmp + 0.5*k2, localTime + 0.5*localTimeStep);
339  T k4 = localTimeStep*continuousSolver<T>::evaluateModel(tmp + k3, localTime + localTimeStep);
340 
341  tmp = tmp + (1.0/6.0)*(k1 + 2.0*k2 + 2.0*k3 + k4);
342  localTime+=localTimeStep;
343  }
345  }
346 };
347 #endif
Definition: model.h:295
Definition: model.h:57
Definition: model.h:118
double getCurrentIndex()
Getter for current time.
Definition: model.h:218
Definition: model.h:148
double getCurrentTime()
Getter for current time.
Definition: model.h:278
virtual T function(const T &val, const int index) const =0
Definition: model.h:131
void solve(int stepsForward)
solve timeForward time units forward from currentTime
Definition: model.h:194
Definition: model.h:234
T getCurrentState()
Getter for current state.
Definition: model.h:213
Definition: model.h:100
T getCurrentState()
Getter for state.
Definition: model.h:273
Definition: model.h:32
Definition: model.h:14
Definition: model.h:139
Definition: model.h:166
Definition: model.h:83
virtual T function(const T &val, const double time) const =0