Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpUnscentedKalman.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software 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 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Display a point cloud using PCL library.
32 */
33
38
39#include <visp3/core/vpUnscentedKalman.h>
40
41#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
43vpUnscentedKalman::vpUnscentedKalman(const vpMatrix &Q, const vpMatrix &R, std::shared_ptr<vpUKSigmaDrawerAbstract> &drawer, const vpProcessFunction &f, const vpMeasurementFunction &h)
44 : m_hasUpdateBeenCalled(false)
45 , m_Q(Q)
46 , m_R(R)
47 , m_f(f)
48 , m_h(h)
49 , m_sigmaDrawer(drawer)
50 , m_b(nullptr)
51 , m_bx(nullptr)
52 , m_measMeanFunc(vpUnscentedKalman::simpleMean)
53 , m_measResFunc(vpUnscentedKalman::simpleResidual)
54 , m_stateAddFunction(vpUnscentedKalman::simpleAdd)
55 , m_stateMeanFunc(vpUnscentedKalman::simpleMean)
56 , m_stateResFunc(vpUnscentedKalman::simpleResidual)
57{ }
58
59void vpUnscentedKalman::init(const vpColVector &mu0, const vpMatrix &P0)
60{
61 if ((mu0.getRows() != P0.getCols()) || (mu0.getRows() != P0.getRows())) {
62 throw(vpException(vpException::dimensionError, "Initial state X0 and process covariance matrix P0 sizes mismatch"));
63 }
64 if ((m_Q.getCols() != P0.getCols()) || (m_Q.getRows() != P0.getRows())) {
65 throw(vpException(vpException::dimensionError, "Initial process covariance matrix P0 and Q matrix sizes mismatch"));
66 }
67 m_Xest = mu0;
68 m_Pest = P0;
69 m_mu = mu0;
70 m_Ppred = P0;
71}
72
73void vpUnscentedKalman::filter(const vpColVector &z, const double &dt, const vpColVector &u)
74{
75 predict(dt, u);
76 update(z);
77}
78
79void vpUnscentedKalman::predict(const double &dt, const vpColVector &u)
80{
82 vpMatrix P;
83
84 if (m_hasUpdateBeenCalled) {
85 // Update is the last function that has been called, starting from the filtered values.
86 x = m_Xest;
87 P = m_Pest;
88 m_hasUpdateBeenCalled = false;
89 }
90 else {
91 // Predict is the last function that has been called, starting from the predicted values.
92 x = m_mu;
93 P = m_Ppred;
94 }
95
96 // Drawing the sigma points
97 m_chi = m_sigmaDrawer->drawSigmaPoints(x, P);
98
99 // Computation of the attached weights
100 vpUKSigmaDrawerAbstract::vpSigmaPointsWeights weights = m_sigmaDrawer->computeWeights();
101 m_wm = weights.m_wm;
102 m_wc = weights.m_wc;
103
104 // Computation of the prior based on the sigma points
105 size_t nbPoints = m_chi.size();
106 if (m_Y.size() != nbPoints) {
107 m_Y.resize(nbPoints);
108 }
109 for (size_t i = 0; i < nbPoints; ++i) {
110 vpColVector prior = m_f(m_chi[i], dt);
111 if (m_b) {
112 prior = m_stateAddFunction(prior, m_b(u, dt));
113 }
114 else if (m_bx) {
115 prior = m_stateAddFunction(prior, m_bx(u, m_chi[i], dt));
116 }
117 m_Y[i] = prior;
118 }
119
120 // Computation of the mean and covariance of the prior
121 vpUnscentedTransformResult transformResults = unscentedTransform(m_Y, m_wm, m_wc, m_Q, m_stateResFunc, m_stateMeanFunc);
122 m_mu = transformResults.m_mu;
123 m_Ppred = transformResults.m_P;
124}
125
127{
128 size_t nbPoints = m_chi.size();
129 if (m_Z.size() != nbPoints) {
130 m_Z.resize(nbPoints);
131 }
132 for (size_t i = 0; i < nbPoints; ++i) {
133 m_Z[i] = (m_h(m_Y[i]));
134 }
135
136 // Computation of the mean and covariance of the prior expressed in the measurement space
137 vpUnscentedTransformResult transformResults = unscentedTransform(m_Z, m_wm, m_wc, m_R, m_measResFunc, m_measMeanFunc);
138 m_muz = transformResults.m_mu;
139 m_Pz = transformResults.m_P;
140
141 // Computation of the Kalman gain
142 vpMatrix Pxz = m_wc[0] * m_stateResFunc(m_Y[0], m_mu) * m_measResFunc(m_Z[0], m_muz).transpose();
143 size_t nbPts = m_wc.size();
144 for (size_t i = 1; i < nbPts; ++i) {
145 Pxz += m_wc[i] * m_stateResFunc(m_Y[i], m_mu) * m_measResFunc(m_Z[i], m_muz).transpose();
146 }
147 m_K = Pxz * m_Pz.inverseByCholesky();
148
149 // Updating the estimate
150 m_Xest = m_stateAddFunction(m_mu, m_K * m_measResFunc(z, m_muz));
151 m_Pest = m_Ppred - m_K * m_Pz * m_K.transpose();
152 m_hasUpdateBeenCalled = true;
153}
154
155vpUnscentedKalman::vpUnscentedTransformResult vpUnscentedKalman::unscentedTransform(const std::vector<vpColVector> &sigmaPoints,
156 const std::vector<double> &wm, const std::vector<double> &wc, const vpMatrix &cov,
157 const vpAddSubFunction &resFunc, const vpMeanFunction &meanFunc
158)
159{
160 vpUnscentedKalman::vpUnscentedTransformResult result;
161
162 // Computation of the mean
163 result.m_mu = meanFunc(sigmaPoints, wm);
164
165 // Computation of the covariance
166 result.m_P = cov;
167 size_t nbSigmaPoints = sigmaPoints.size();
168 for (size_t i = 0; i < nbSigmaPoints; ++i) {
169 vpColVector e = resFunc(sigmaPoints[i], result.m_mu);
170 result.m_P += wc[i] * e*e.transpose();
171 }
172 return result;
173}
174END_VISP_NAMESPACE
175#else
176void vpUnscentedKalman_dummy()
177{
178
179}
180#endif
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:435
unsigned int getRows() const
Definition vpArray2D.h:433
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ dimensionError
Bad dimension.
Definition vpException.h:71
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpMatrix inverseByCholesky() const
vpMatrix transpose() const
vpUnscentedKalman(const vpMatrix &Q, const vpMatrix &R, std::shared_ptr< vpUKSigmaDrawerAbstract > &drawer, const vpProcessFunction &f, const vpMeasurementFunction &h)
Construct a new vpUnscentedKalman object.
static vpColVector simpleAdd(const vpColVector &a, const vpColVector &toAdd)
Simple function to compute an addition, which just does .
static vpColVector simpleResidual(const vpColVector &a, const vpColVector &toSubtract)
Simple function to compute a residual, which just does .
static vpColVector simpleMean(const std::vector< vpColVector > &vals, const std::vector< double > &wm)
Simple function to compute a mean, which just does .
void update(const vpColVector &z)
Update the estimate of the state based on a new measurement.
void filter(const vpColVector &z, const double &dt, const vpColVector &u=vpColVector())
Perform first the prediction step and then the filtering step.
void predict(const double &dt, const vpColVector &u=vpColVector())
Predict the new state based on the last state and how far in time we want to predict.
std::function< vpColVector(const vpColVector &)> vpMeasurementFunction
Measurement function, which converts the prior points in the measurement space. The argument is a poi...
std::function< vpColVector(const vpColVector &, const double &)> vpProcessFunction
Process model function, which projects the sigma points forward in time. The first argument is a sigm...
void init(const vpColVector &mu0, const vpMatrix &P0)
Set the guess of the initial state and covariance.
The weights corresponding to the sigma points drawing.