easykf-2.04
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Macros Pages
ukf_parameter_scalar.h
Go to the documentation of this file.
1 /* ukf_parameter_scalar.h
2  *
3  * Copyright (C) 2011-2014 Jeremy Fix
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or (at
8  * your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #ifndef UKF_PARAMETER_SCALAR_H
21 #define UKF_PARAMETER_SCALAR_H
22 
23 #include <gsl/gsl_linalg.h> // For the Cholesky decomposition
24 #include <gsl/gsl_math.h>
25 #include <gsl/gsl_blas.h>
26 
27 #include "ukf_types.h"
28 #include "ukf_math.h"
29 
30 namespace ukf
31 {
36  namespace parameter
37  {
43  {
44  // Init the lambda
45  p.lambda = p.alpha * p.alpha * (p.n + p.kpa) - p.n;
46  p.gamma = sqrt(p.n + p.lambda);
47  p.nbSamples = 2 * p.n + 1;
48 
49  // Init the matrices used to iterate
50  s.Kk = gsl_vector_alloc(p.n); // Kalman gain
51  gsl_vector_set_zero(s.Kk);
52 
53  s.Kk_mat = gsl_matrix_alloc(p.n,1);
54  gsl_matrix_set_zero(s.Kk_mat);
55 
56  s.Kk_mat_T = gsl_matrix_alloc(1,p.n);
57  gsl_matrix_set_zero(s.Kk_mat_T);
58 
59  s.Pwdk = gsl_vector_alloc(p.n); // Covariance of the parameters and output
60  gsl_vector_set_zero(s.Pwdk);
61 
62  // Whatever the type of evolution noise, its covariance is set to evolution_noise
63  s.Prrk = gsl_matrix_alloc(p.n,p.n);
64  p.evolution_noise->init(p,s);
65 
66  s.Peek = p.observation_noise; // Covariance of the observation noise
67 
68  s.Pddk = 0.0; // Covariance of the output
69 
70  s.w = gsl_vector_alloc(p.n); // Parameter vector
71  gsl_vector_set_zero(s.w);
72 
73  s.wk = gsl_vector_alloc(p.n); // Vector holding one sigma point
74  gsl_vector_set_zero(s.wk);
75 
76  s.Pk = gsl_matrix_alloc(p.n,p.n); // Covariance matrix
77  gsl_matrix_set_identity(s.Pk);
78  gsl_matrix_scale(s.Pk,p.prior_pi);
79 
80  s.Sk = gsl_matrix_alloc(p.n,p.n); // Matrix holding the cholesky decomposition of Pk
81  // Initialize Sk to the cholesky decomposition of Pk
82  gsl_matrix_memcpy(s.Sk, s.Pk);
83  gsl_linalg_cholesky_decomp(s.Sk);
84  // Set all the elements of Lpi strictly above the diagonal to zero
85  for(int k = 0 ; k < p.n ; k++)
86  for(int j = 0 ; j < k ; j++)
87  gsl_matrix_set(s.Sk,j,k,0.0);
88 
89  s.cSk = gsl_vector_alloc(p.n); // Vector holding one column of Lpi
90  gsl_vector_set_zero(s.cSk);
91 
92  s.wm = gsl_vector_alloc(p.nbSamples); // Weights used to compute the mean of the sigma points images
93  s.wc = gsl_vector_alloc(p.nbSamples); // Weights used to update the covariance matrices
94 
95  // Set the weights
96  gsl_vector_set(s.wm, 0, p.lambda / (p.n + p.lambda));
97  gsl_vector_set(s.wc, 0, p.lambda / (p.n + p.lambda) + (1.0 - p.alpha*p.alpha + p.beta));
98  for(int j = 1 ; j < p.nbSamples; j ++)
99  {
100  gsl_vector_set(s.wm, j, 1.0 / (2.0 * (p.n + p.lambda)));
101  gsl_vector_set(s.wc, j, 1.0 / (2.0 * (p.n + p.lambda)));
102  }
103 
104  s.dk = gsl_vector_alloc(p.nbSamples); // Holds the image of the sigma points
105  gsl_vector_set_zero(s.dk);
106 
107  s.d_mean = 0; // Holds the mean of the sigma points images
108 
109  s.sigmaPoints = gsl_matrix_alloc(p.n,p.nbSamples); // Holds the sigma points in the columns
110  gsl_matrix_set_zero(s.sigmaPoints);
111 
112  s.temp_n = gsl_vector_alloc(p.n);
113  gsl_vector_set_zero(s.temp_n);
114 
115  s.temp_n_n = gsl_matrix_alloc(p.n,p.n);
116  gsl_matrix_set_zero(s.temp_n_n);
117  }
118 
124  {
125  gsl_vector_free(s.Kk);
126  gsl_matrix_free(s.Kk_mat);
127  gsl_matrix_free(s.Kk_mat_T);
128  gsl_vector_free(s.Pwdk);
129  gsl_matrix_free(s.Prrk);
130 
131  gsl_vector_free(s.w);
132  gsl_vector_free(s.wk);
133 
134  gsl_matrix_free(s.Pk);
135  gsl_matrix_free(s.Sk);
136  gsl_vector_free(s.cSk);
137 
138  gsl_vector_free(s.wm);
139  gsl_vector_free(s.wc);
140 
141  gsl_vector_free(s.dk);
142 
143  gsl_matrix_free(s.sigmaPoints);
144 
145  gsl_vector_free(s.temp_n);
146  gsl_matrix_free(s.temp_n_n);
147  }
148 
153  template <typename FunctObj>
154  inline void ukf_scalar_iterate(ukf_param &p, ukf_scalar_state &s, FunctObj g, gsl_vector * xk, double dk)
155  {
156  // Here, we implement the UKF for parameter estimation in the scalar case
157  // The notations follow p93 of the PhD thesis of Van Der Merwe, "Sigma-Point Kalman Filters for Probabilistic Inference in Dynamic State-Space Models"
158 
159  // ************************************************** //
160  // ************ Time update equations ************ //
161  // ************************************************** //
162  // Add the evolution noise to the parameter covariance Eq 3.137
163  gsl_matrix_add(s.Pk, s.Prrk);
164 
165  // ************************************************** //
166  // ************ Compute the sigma points ************ //
167  // ************************************************** //
168  // Equations 3.138
169  // w_k^j = w_(k-1) <-- this is here denoted s.w
170  // w_k^j = w_(k-1) + gamma Sk_j for 1 <= j <= n
171  // w_k^j = w_(k-1) - gamma Sk_j for n+1 <= j <= 2n
172 
173  // Perform a cholesky decomposition of Pk
174  gsl_matrix_memcpy(s.Sk, s.Pk);
175  gsl_linalg_cholesky_decomp(s.Sk);
176  // Set all the elements of Lpi strictly above the diagonal to zero
177  for(int k = 0 ; k < p.n ; k++)
178  for(int j = 0 ; j < k ; j++)
179  gsl_matrix_set(s.Sk,j,k,0.0);
180 
181  gsl_matrix_set_col(s.sigmaPoints,0, s.w);
182  for(int j = 1 ; j < p.n+1 ; ++j)
183  for(int i = 0 ; i < p.n ; ++i)
184  gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) + p.gamma * gsl_matrix_get(s.Sk,i,j-1));
185 
186  for(int j = p.n+1 ; j < p.nbSamples ; ++j)
187  for(int i = 0 ; i < p.n ; ++i)
188  gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) - p.gamma * gsl_matrix_get(s.Sk,i,j-(p.n+1)));
189 
190  // ************************************************** //
191  // ***** Compute the images of the sigma points ***** //
192  // ************************************************** //
193 
194  // Compute the images of the sigma points
195  // and the mean of the yj
196  s.d_mean = 0.0;
197  gsl_vector_set_zero(s.dk);
198  for(int j = 0 ; j < p.nbSamples ; j++)
199  {
200  // Equation 3.139
201  gsl_matrix_get_col(s.wk, s.sigmaPoints,j);
202  s.dk->data[j] = g(s.wk,xk);
203 
204  // Update the mean : y_mean = sum_[j=0..2n] wm_j y_j
205  // Equation 3.140
206  s.d_mean += s.wm->data[j] * s.dk->data[j];
207  }
208 
209  // ************************************************** //
210  // ************** Update the statistics ************* //
211  // ************************************************** //
212 
213  gsl_vector_set_zero(s.Pwdk);
214  // The covariance of the output is initialized with the observation noise covariance
215  // Eq 3.142
216  s.Pddk = s.Peek;
217  for(int j = 0 ; j < p.nbSamples ; j++)
218  {
219  // Eq 3.142
220  s.Pddk += s.wc->data[j] * gsl_pow_2(s.dk->data[j] - s.d_mean);
221  // Eq 3.143
222  for(int i = 0 ; i < p.n ; ++i)
223  {
224  s.Pwdk->data[i] = s.Pwdk->data[i] + s.wc->data[j] * (gsl_matrix_get(s.sigmaPoints,i,j) - s.w->data[i]) * (s.dk->data[j] - s.d_mean) ;
225  }
226  }
227 
228  // ************************************************** //
229  // ******* Kalman gain and parameters update ******** //
230  // ************************************************** //
231 
232  //if(s.Pddk == 0.0)
233  // printf("[Error] Output covariance is null !");
234  // May not occur as soon as the observation noise covariance is set != 0.0
235 
236  // Eq. 3.144
237  for(int i = 0 ; i < p.n ; ++i)
238  s.Kk->data[i] = s.Pwdk->data[i] / s.Pddk;
239 
240  // Eq 3.145
241  // wk = w_(k-1) + Kk * (dk - d_mean)
242  s.ino_dk = dk - s.d_mean;
243  for(int i = 0 ; i < p.n ; ++i)
244  s.w->data[i] = s.w->data[i] + s.Kk->data[i] * s.ino_dk;
245 
246  // Eq. 3.146
247  // Pk = P_(k-1) - Pddk . Kk Kk^T
248  for(int i = 0 ; i < p.n ; ++i)
249  {
250  gsl_matrix_set(s.Kk_mat, i, 0, s.Kk->data[i]);
251  gsl_matrix_set(s.Kk_mat_T, 0, i, s.Kk->data[i]);
252  }
253  gsl_blas_dgemm(CblasNoTrans,CblasNoTrans,-s.Pddk, s.Kk_mat, s.Kk_mat_T,1.0,s.Pk);
254 
255  // Update of the evolution noise
257  }
258 
263  template <typename FunctObj>
264  inline void ukf_scalar_evaluate(ukf_param &p, ukf_scalar_state &s, FunctObj g, gsl_vector * xk, double &dk)
265  {
266  // ************************************************** //
267  // ************ Compute the sigma points ************ //
268  // ************************************************** //
269 
270  // 1- Compute the cholesky decomposition of Pk
271  gsl_matrix_memcpy(s.temp_n_n, s.Pk);
272  gsl_linalg_cholesky_decomp(s.temp_n_n);
273 
274  // 2 - Set all the elements of Sk_temp strictly above the diagonal to zero
275  for(int k = 0 ; k < p.n ; k++)
276  for(int j = 0 ; j < k ; j++)
277  gsl_matrix_set(s.temp_n_n,j,k,0.0);
278  // Now Sk_temp is a lower triangular matrix containing the cholesky decomposition of Pk
279 
280  // 3- Compute the sigma points
281  // Equations 3.138
282  // w_k^j = w_(k-1) <-- this is here denoted s.w
283  // w_k^j = w_(k-1) + gamma Sk_j for 1 <= j <= n
284  // w_k^j = w_(k-1) - gamma Sk_j for n+1 <= j <= 2n
285  gsl_matrix_set_col(s.sigmaPoints,0, s.w);
286  for(int j = 1 ; j < p.n+1 ; j++)
287  for(int i = 0 ; i < p.n ; ++i)
288  gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) + p.gamma * gsl_matrix_get(s.temp_n_n,i,j-1));
289 
290  for(int j = p.n+1 ; j < p.nbSamples ; j++)
291  for(int i = 0 ; i < p.n ; ++i)
292  gsl_matrix_set(s.sigmaPoints, i, j, gsl_vector_get(s.w, i) - p.gamma * gsl_matrix_get(s.temp_n_n,i,j-(p.n+1)));
293 
294  // ************************************************** //
295  // ***** Compute the images of the sigma points ***** //
296  // ************************************************** //
297 
298  // Compute the images of the sigma points
299  // and their mean
300  dk = 0.0;
301  for(int j = 0 ; j < p.nbSamples ; j++)
302  {
303  gsl_matrix_get_col(s.wk, s.sigmaPoints,j);
304  // Update the mean : d_mean = sum_[j=0..2n] w_j y_j
305  dk += gsl_vector_get(s.wm,j) * g(s.wk,xk);
306  }
307  }
308 
309  } // parameter
310 } // ukf
311 
312 #endif // UKF_PARAMETER_SCALAR_H
void ukf_scalar_init(ukf_param &p, ukf_scalar_state &s)
Allocation of the vectors/matrices and initialization.
Definition: ukf_parameter_scalar.h:42
EvolutionNoise * evolution_noise
Parameter used for the evolution noise.
Definition: ukf_types.h:96
gsl_vector * cSk
Vector holding one column of Sk, of size .
Definition: ukf_types.h:196
gsl_vector * w
Parameter vector, of size .
Definition: ukf_types.h:176
gsl_vector * Pwdk
Covariance of : , of size .
Definition: ukf_types.h:156
gsl_vector * dk
Temporary vector holding the image of the sigma points, of size .
Definition: ukf_types.h:215
double Peek
Covariance of the observation noise.
Definition: ukf_types.h:166
Pointer to the function to approximate in the scalar case.
Definition: ukf_types.h:136
double kpa
, is a good choice. According to van der Merwe, its value is not critical
Definition: ukf_types.h:60
gsl_vector * wk
Temporary vector, holding a sigma-point.
Definition: ukf_types.h:181
gsl_matrix * Sk
Matrix holding the Cholesky decomposition of , of size .
Definition: ukf_types.h:191
gsl_matrix * Pk
Covariance matrix of the parameters, of size .
Definition: ukf_types.h:186
double d_mean
Variable holding the mean of the sigma points image.
Definition: ukf_types.h:225
double observation_noise
Covariance of the observation noise.
Definition: ukf_types.h:101
Structure holding the parameters of the Unscented Kalman Filter.
Definition: ukf_types.h:55
double beta
Non negative weights used to introduce knowledge about the higher order moments of the distribution...
Definition: ukf_types.h:70
gsl_matrix * temp_n_n
Temporary matrix.
Definition: ukf_types.h:240
int n
Number of parameters to estimate.
Definition: ukf_types.h:111
void init(ukf_param &p, ukf_state &s)
Definition: ukf_types.h:395
gsl_vector * wm
Weights used to compute the mean of the sigma points' images.
Definition: ukf_types.h:203
double ino_dk
Innovation.
Definition: ukf_types.h:220
double alpha
: "Size" of sigma-point distribution. Should be small if the function is strongly non-linear ...
Definition: ukf_types.h:65
void ukf_scalar_iterate(ukf_param &p, ukf_scalar_state &s, FunctObj g, gsl_vector *xk, double dk)
Iteration for UKF for parameter estimation, in case of a scalar output.
Definition: ukf_parameter_scalar.h:154
gsl_matrix * Prrk
Covariance of the evolution noise.
Definition: ukf_types.h:161
void ukf_scalar_free(ukf_param &p, ukf_scalar_state &s)
Free of memory allocation.
Definition: ukf_parameter_scalar.h:123
gsl_matrix * Kk_mat
Temporary matrix for the kalman gain, a matrix of size .
Definition: ukf_types.h:146
double lambda
Definition: ukf_types.h:75
virtual void updateEvolutionNoise(ukf_param &p, ukf_state &s)=0
gsl_matrix * Kk_mat_T
Temporary matrix for the transpose of the kalman gain, a matrix of size .
Definition: ukf_types.h:151
gsl_vector * wc
Weights used to update the covariance matrices.
Definition: ukf_types.h:210
void ukf_scalar_evaluate(ukf_param &p, ukf_scalar_state &s, FunctObj g, gsl_vector *xk, double &dk)
Evaluation of the output from the sigma points.
Definition: ukf_parameter_scalar.h:264
gsl_vector * Kk
Kalman gain, a vector of size .
Definition: ukf_types.h:141
gsl_vector * temp_n
Temporary vector.
Definition: ukf_types.h:235
double prior_pi
Prior estimate of the covariance matrix.
Definition: ukf_types.h:106
double Pddk
Covariance of the output.
Definition: ukf_types.h:171
double gamma
Definition: ukf_types.h:80
gsl_matrix * sigmaPoints
Matrix holding the sigma points in the columns, of size .
Definition: ukf_types.h:230
int nbSamples
Number of sigma-points
Definition: ukf_types.h:116