Main MRPT website > C++ reference for MRPT 1.9.9
CPosePDFParticles.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "base-precomp.h" // Precompiled headers
11 
14 #include <mrpt/system/os.h>
15 #include <mrpt/random.h>
16 #include <mrpt/math/wrap2pi.h>
18 #include <mrpt/utils/CStream.h>
20 
21 using namespace mrpt;
22 using namespace mrpt::bayes;
23 using namespace mrpt::poses;
24 using namespace mrpt::math;
25 using namespace mrpt::random;
26 using namespace mrpt::utils;
27 using namespace mrpt::system;
28 using namespace std;
29 
31 
32 /*---------------------------------------------------------------
33  Constructor
34  ---------------------------------------------------------------*/
36 {
37  m_particles.resize(M);
38 
39  for (auto& p : m_particles)
40  {
41  p.log_w = .0;
42  p.d.reset(new CPose2D());
43  }
44 
45  CPose2D nullPose(0, 0, 0);
46  resetDeterministic(nullPose);
47 }
48 
49 void CPosePDFParticles::copyFrom(const CPosePDF& o)
50 {
52 
55 
56  if (this == &o) return; // It may be used sometimes
57 
59  {
60  const CPosePDFParticles* pdf =
61  dynamic_cast<const CPosePDFParticles*>(&o);
62  ASSERT_(pdf);
63 
64  // Both are m_particles:
65  m_particles = pdf->m_particles;
66  }
67  else if (o.GetRuntimeClass() == CLASS_ID(CPosePDFGaussian))
68  {
69  const CPosePDFGaussian* pdf = static_cast<const CPosePDFGaussian*>(&o);
70  size_t M = m_particles.size();
71  std::vector<CVectorDouble> parts;
73 
75 
76  clearParticles();
77  m_particles.resize(M);
78 
79  for (itDest = m_particles.begin(), partsIt = parts.begin();
80  itDest != m_particles.end(); ++itDest, ++partsIt)
81  {
82  itDest->log_w = 0;
83  itDest->d.reset(
84  new CPose2D(
85  (pdf->mean.x() + (*partsIt)[0]),
86  (pdf->mean.y() + (*partsIt)[1]),
87  (pdf->mean.phi() + (*partsIt)[2])));
88  itDest->d->normalizePhi();
89  }
90  }
91 
92  MRPT_END
93 }
94 
95 void CPosePDFParticles::clear() { clearParticles(); }
96 /*---------------------------------------------------------------
97  getMean
98  Returns an estimate of the pose, (the mean, or mathematical expectation of the
99  PDF), computed
100  as a weighted average over all m_particles.
101  ---------------------------------------------------------------*/
102 void CPosePDFParticles::getMean(CPose2D& est_) const
103 {
104  // Calc average on SE(2)
105  const size_t n = m_particles.size();
106  if (n)
107  {
108  mrpt::poses::SE_average<2> se_averager;
109  for (size_t i = 0; i < n; i++)
110  {
111  const CPose2D& p = *m_particles[i].d;
112  double w = exp(m_particles[i].log_w);
113  se_averager.append(p, w);
114  }
115  se_averager.get_average(est_);
116  }
117  else
118  {
119  est_ = CPose2D();
120  }
121 }
122 
123 /*---------------------------------------------------------------
124  getEstimatedCovariance
125  ---------------------------------------------------------------*/
126 void CPosePDFParticles::getCovarianceAndMean(
127  CMatrixDouble33& cov, CPose2D& mean) const
128 {
129  cov.zeros();
130  getMean(mean);
131 
132  size_t i, n = m_particles.size();
133  double var_x = 0, var_y = 0, var_p = 0, var_xy = 0, var_xp = 0, var_yp = 0;
134  double mean_phi = mean.phi();
135 
136  if (mean_phi < 0) mean_phi = M_2PI + mean_phi;
137 
138  double lin_w_sum = 0;
139 
140  for (i = 0; i < n; i++) lin_w_sum += exp(m_particles[i].log_w);
141  if (lin_w_sum == 0) lin_w_sum = 1;
142 
143  for (i = 0; i < n; i++)
144  {
145  double w = exp(m_particles[i].log_w) / lin_w_sum;
146 
147  // Manage 1 PI range:
148  double err_x = m_particles[i].d->x() - mean.x();
149  double err_y = m_particles[i].d->y() - mean.y();
150  double err_phi =
151  math::wrapToPi(fabs(m_particles[i].d->phi() - mean_phi));
152 
153  var_x += square(err_x) * w;
154  var_y += square(err_y) * w;
155  var_p += square(err_phi) * w;
156  var_xy += err_x * err_y * w;
157  var_xp += err_x * err_phi * w;
158  var_yp += err_y * err_phi * w;
159  }
160 
161  if (n < 2)
162  {
163  // Not enought information to estimate the variance:
164  }
165  else
166  {
167  // Unbiased estimation of variance:
168  cov(0, 0) = var_x;
169  cov(1, 1) = var_y;
170  cov(2, 2) = var_p;
171 
172  cov(1, 0) = cov(0, 1) = var_xy;
173  cov(2, 0) = cov(0, 2) = var_xp;
174  cov(1, 2) = cov(2, 1) = var_yp;
175  }
176 }
177 
178 /*---------------------------------------------------------------
179  writeToStream
180  ---------------------------------------------------------------*/
181 void CPosePDFParticles::writeToStream(
182  mrpt::utils::CStream& out, int* version) const
183 {
184  if (version)
185  *version = 0;
186  else
187  {
188  writeParticlesToStream(out);
189  }
190 }
191 
192 /*---------------------------------------------------------------
193  readFromStream
194  ---------------------------------------------------------------*/
195 void CPosePDFParticles::readFromStream(mrpt::utils::CStream& in, int version)
196 {
197  switch (version)
198  {
199  case 0:
200  {
201  readParticlesFromStream(in);
202  }
203  break;
204  default:
206  };
207 }
208 
209 /*---------------------------------------------------------------
210  resetDeterministic
211  Reset PDF to a single point and set the number of m_particles
212  ---------------------------------------------------------------*/
213 void CPosePDFParticles::resetDeterministic(
214  const CPose2D& location, size_t particlesCount)
215 {
216  if (particlesCount > 0)
217  {
218  clear();
219  m_particles.resize(particlesCount);
220  for (auto& p : m_particles) p.d.resetDefaultCtor();
221  }
222 
223  for (auto& p : m_particles)
224  {
225  *p.d = location;
226  p.log_w = .0;
227  }
228 }
229 
230 /*---------------------------------------------------------------
231  resetUniform
232  ---------------------------------------------------------------*/
233 void CPosePDFParticles::resetUniform(
234  const double& x_min, const double& x_max, const double& y_min,
235  const double& y_max, const double& phi_min, const double& phi_max,
236  const int& particlesCount)
237 {
238  MRPT_START
239 
240  if (particlesCount > 0)
241  {
242  clear();
243  m_particles.resize(particlesCount);
244  for (int i = 0; i < particlesCount; i++)
245  m_particles[i].d.reset(new CPose2D());
246  }
247 
248  size_t i, M = m_particles.size();
249  for (i = 0; i < M; i++)
250  {
251  m_particles[i].d->x(getRandomGenerator().drawUniform(x_min, x_max));
252  m_particles[i].d->y(getRandomGenerator().drawUniform(y_min, y_max));
253  m_particles[i].d->phi(getRandomGenerator().drawUniform(phi_min, phi_max));
254  m_particles[i].log_w = 0;
255  }
256 
257  MRPT_END
258 }
259 
260 void CPosePDFParticles::resetAroundSetOfPoses(
261  const std::vector<mrpt::math::TPose2D>& list_poses,
262  const size_t num_particles_per_pose, const double spread_x,
263  const double spread_y, const double spread_phi_rad)
264 {
265  MRPT_START
266  ASSERT_(!list_poses.empty());
267  ASSERT_(num_particles_per_pose >= 1);
268 
269  const size_t N = list_poses.size() * num_particles_per_pose;
270 
271  clear();
272  m_particles.resize(N);
273  size_t i, nSpot;
274  for (i = 0, nSpot = 0; nSpot < list_poses.size(); nSpot++)
275  {
276  const mrpt::math::TPose2D& p = list_poses[nSpot];
277  for (size_t k = 0; k < num_particles_per_pose; k++, i++)
278  {
279  m_particles[i].d.reset(new CPose2D());
280  m_particles[i].d->x(
281  getRandomGenerator().drawUniform(
282  p.x - spread_x * 0.5, p.x + spread_x * 0.5));
283  m_particles[i].d->y(
284  getRandomGenerator().drawUniform(
285  p.y - spread_y * 0.5, p.y + spread_y * 0.5));
286  m_particles[i].d->phi(
287  getRandomGenerator().drawUniform(
288  p.phi - spread_phi_rad * 0.5,
289  p.phi + spread_phi_rad * 0.5));
290  m_particles[i].log_w = 0;
291  }
292  }
293 
294  ASSERT_EQUAL_(i, N);
295 
296  MRPT_END
297 }
298 
299 /*---------------------------------------------------------------
300  saveToTextFile
301  Save PDF's m_particles to a text file. In each line it
302  will go: "x y phi weight"
303  ---------------------------------------------------------------*/
305 {
306  FILE* f = os::fopen(file.c_str(), "wt");
307  if (!f) return;
308  os::fprintf(f, "%% x y yaw[rad] log_weight\n");
309 
310  for (unsigned int i = 0; i < m_particles.size(); i++)
311  os::fprintf(
312  f, "%f %f %f %e\n", m_particles[i].d->x(), m_particles[i].d->y(),
313  m_particles[i].d->phi(), m_particles[i].log_w);
314 
315  os::fclose(f);
316 }
317 
318 /*---------------------------------------------------------------
319  getParticlePose
320  ---------------------------------------------------------------*/
321 CPose2D CPosePDFParticles::getParticlePose(size_t i) const
322 {
323  return *m_particles[i].d;
324 }
325 
326 /*---------------------------------------------------------------
327  changeCoordinatesReference
328  ---------------------------------------------------------------*/
329 void CPosePDFParticles::changeCoordinatesReference(
330  const CPose3D& newReferenceBase_)
331 {
332  const CPose2D newReferenceBase = CPose2D(newReferenceBase_);
333 
334  for (CParticleList::iterator it = m_particles.begin();
335  it != m_particles.end(); ++it)
336  it->d->composeFrom(newReferenceBase, *it->d);
337 }
338 
339 /*---------------------------------------------------------------
340  drawSingleSample
341  ---------------------------------------------------------------*/
342 void CPosePDFParticles::drawSingleSample(CPose2D& outPart) const
343 {
344  const double uni = getRandomGenerator().drawUniform(0.0, 0.9999);
345  double cum = 0;
346 
347  for (CParticleList::const_iterator it = m_particles.begin();
348  it != m_particles.end(); ++it)
349  {
350  cum += exp(it->log_w);
351  if (uni <= cum)
352  {
353  outPart = (*it->d);
354  return;
355  }
356  }
357 
358  // Might not come here normally:
359  outPart = *(m_particles.rbegin())->d;
360 }
361 
362 /*---------------------------------------------------------------
363  +=
364  ---------------------------------------------------------------*/
366 {
367  for (CParticleList::iterator it = m_particles.begin();
368  it != m_particles.end(); ++it)
369  it->d->composeFrom(*it->d, Ap);
370 }
371 
372 /*---------------------------------------------------------------
373  append
374  ---------------------------------------------------------------*/
375 void CPosePDFParticles::append(CPosePDFParticles& o)
376 {
377  for (unsigned int i = 0; i < o.m_particles.size(); i++)
378  {
379  CParticleData part;
380  part.d.reset(new CPose2D(*o.m_particles[i].d));
381  part.log_w = o.m_particles[i].log_w;
382  m_particles.push_back(part);
383  }
384 
385  normalizeWeights();
386 }
387 
388 /*---------------------------------------------------------------
389  inverse
390  ---------------------------------------------------------------*/
392 {
393  MRPT_START
395  CPosePDFParticles* out = static_cast<CPosePDFParticles*>(&o);
396 
397  out->copyFrom(*this);
398  static CPose2D nullPose(0, 0, 0);
399 
400  for (unsigned int i = 0; i < out->m_particles.size(); i++)
401  (*out->m_particles[i].d) = nullPose - (*out->m_particles[i].d);
402 
403  MRPT_END
404 }
405 
406 /*---------------------------------------------------------------
407  getMostLikelyParticle
408  ---------------------------------------------------------------*/
409 CPose2D CPosePDFParticles::getMostLikelyParticle() const
410 {
411  CParticleList::const_iterator it, itMax = m_particles.begin();
412  double max_w = -1e300;
413 
414  for (it = m_particles.begin(); it != m_particles.end(); ++it)
415  {
416  if (it->log_w > max_w)
417  {
418  itMax = it;
419  max_w = it->log_w;
420  }
421  }
422 
423  return *itMax->d;
424 }
425 
426 /*---------------------------------------------------------------
427  bayesianFusion
428  ---------------------------------------------------------------*/
429 void CPosePDFParticles::bayesianFusion(
430  const CPosePDF& p1, const CPosePDF& p2,
431  const double& minMahalanobisDistToDrop)
432 {
433  MRPT_UNUSED_PARAM(p1);
434  MRPT_UNUSED_PARAM(p2);
435  MRPT_UNUSED_PARAM(minMahalanobisDistToDrop);
436 
437  THROW_EXCEPTION("Not implemented yet!");
438 }
439 
440 /*---------------------------------------------------------------
441  evaluatePDF_parzen
442  ---------------------------------------------------------------*/
443 double CPosePDFParticles::evaluatePDF_parzen(
444  const double& x, const double& y, const double& phi, const double& stdXY,
445  const double& stdPhi) const
446 {
447  double ret = 0;
448 
449  for (CParticleList::const_iterator it = m_particles.begin();
450  it != m_particles.end(); ++it)
451  {
452  double difPhi = math::wrapToPi(phi - it->d->phi());
453 
454  ret += exp(it->log_w) *
455  math::normalPDF(it->d->distance2DTo(x, y), 0, stdXY) *
456  math::normalPDF(fabs(difPhi), 0, stdPhi);
457  }
458 
459  return ret;
460 }
461 
462 /*---------------------------------------------------------------
463  saveParzenPDFToTextFile
464  ---------------------------------------------------------------*/
465 void CPosePDFParticles::saveParzenPDFToTextFile(
466  const char* fileName, const double& x_min, const double& x_max,
467  const double& y_min, const double& y_max, const double& phi,
468  const double& stepSizeXY, const double& stdXY, const double& stdPhi) const
469 {
470  FILE* f = os::fopen(fileName, "wt");
471  if (!f) return;
472 
473  for (double y = y_min; y < y_max; y += stepSizeXY)
474  {
475  for (double x = x_min; x < x_max; x += stepSizeXY)
476  {
477  os::fprintf(f, "%f ", evaluatePDF_parzen(x, y, phi, stdXY, stdPhi));
478  } // y
479  os::fprintf(f, "\n");
480  } // x
481 
482  os::fclose(f);
483 }
#define ASSERT_EQUAL_(__A, __B)
Computes weighted and un-weighted averages of SE(2) poses.
A namespace of pseudo-random numbers genrators of diferent distributions.
double drawUniform(const double Min, const double Max)
Generate a uniformly distributed pseudo-random number using the MT19937 algorithm, scaled to the selected range.
double x() const
Common members of all points & poses classes.
Definition: CPoseOrPoint.h:135
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
CPose2D mean
The mean value.
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:30
int void fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:272
GLint location
Definition: glext.h:4086
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
The namespace for Bayesian filtering algorithm: different particle filters and Kalman filter algorith...
#define THROW_EXCEPTION(msg)
GLenum GLsizei n
Definition: glext.h:5074
Scalar * iterator
Definition: eigen_plugins.h:26
void saveToTextFile(const std::string &file, mrpt::math::TMatrixTextFileFormat fileFormat=mrpt::math::MATRIX_FORMAT_ENG, bool appendMRPTHeader=false, const std::string &userHeader=std::string()) const
Save matrix to a text file, compatible with MATLAB text format (see also the methods of matrix classe...
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
void append(const mrpt::poses::CPose2D &p)
Adds a new pose to the computation.
mrpt::math::CMatrixDouble33 cov
The 3x3 covariance matrix.
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:189
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
#define M_2PI
Definition: mrpt_macros.h:437
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
CParticleList m_particles
The array of particles.
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
#define CLASS_ID(T)
Access to runtime class ID for a defined class name.
Definition: CObject.h:85
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
#define MRPT_END
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
void copyFrom(const CPosePDF &o) override
Copy operator, translating if necesary (for example, between m_particles and gaussian representations...
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
void drawGaussianMultivariateMany(VECTOR_OF_VECTORS &ret, size_t desiredSamples, const COVMATRIX &cov, const typename VECTOR_OF_VECTORS::value_type *mean=nullptr)
Generate a given number of multidimensional random samples according to a given covariance matrix...
std::vector< T1 > & operator+=(std::vector< T1 > &a, const std::vector< T2 > &b)
a+=b (element-wise sum)
Definition: ops_vectors.h:74
Eigen::Matrix< dataType, 4, 4 > inverse(Eigen::Matrix< dataType, 4, 4 > &pose)
Definition: Miscellaneous.h:82
Declares a class that represents a Probability Density Function (PDF) over a 2D pose (x...
GLsizei const GLchar ** string
Definition: glext.h:4101
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:53
Declares a class that represents a probability density function (pdf) of a 2D pose (x...
Definition: CPosePDF.h:41
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
int fprintf(FILE *fil, const char *format,...) noexcept MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:405
virtual const mrpt::utils::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A template class for holding a the data and the weight of a particle.
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
Definition: CPose2D.h:40
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
const double & phi() const
Get the phi angle of the 2D pose (in radians)
Definition: CPose2D.h:91
double log_w
The (logarithmic) weight value for this particle.
GLuint in
Definition: glext.h:7274
Lightweight 2D pose.
mrpt::utils::copy_ptr< T > d
The data associated with this particle.
#define ASSERT_(f)
GLenum GLint GLint y
Definition: glext.h:3538
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
Definition: os.cpp:254
Eigen::Matrix< typename MATRIX::Scalar, MATRIX::ColsAtCompileTime, MATRIX::ColsAtCompileTime > cov(const MATRIX &v)
Computes the covariance matrix from a list of samples in an NxM matrix, where each row is a sample...
Definition: ops_matrices.h:148
GLenum GLint x
Definition: glext.h:3538
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
double normalPDF(double x, double mu, double std)
Evaluates the univariate normal (Gaussian) distribution at a given point "x".
Definition: math.cpp:989
GLfloat GLfloat p
Definition: glext.h:6305
EIGEN_STRONG_INLINE double mean() const
Computes the mean of the entire matrix.
void get_average(mrpt::poses::CPose2D &out_mean) const
Returns the average pose.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019