Main MRPT website > C++ reference for MRPT 1.5.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 = dynamic_cast<const CPosePDFParticles*>( &o );
61  ASSERT_(pdf);
62 
63  // Both are m_particles:
64  m_particles = pdf->m_particles;
65  }
66  else
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();itDest!=m_particles.end();++itDest,++partsIt )
80  {
81  itDest->log_w = 0;
82  itDest->d.reset(new CPose2D(
83  (pdf->mean.x() + (*partsIt)[0]),
84  (pdf->mean.y() + (*partsIt)[1]),
85  (pdf->mean.phi() + (*partsIt)[2]))
86  );
87  itDest->d->normalizePhi();
88  }
89 
90  }
91 
92  MRPT_END
93 }
94 
96 {
97  clearParticles();
98 }
99 
100 /*---------------------------------------------------------------
101  getMean
102  Returns an estimate of the pose, (the mean, or mathematical expectation of the PDF), computed
103  as a weighted average over all m_particles.
104  ---------------------------------------------------------------*/
105 void CPosePDFParticles::getMean(CPose2D &est_) const
106 {
107  // Calc average on SE(2)
108  const size_t n = m_particles.size();
109  if (n)
110  {
111  mrpt::poses::SE_average<2> se_averager;
112  for (size_t i=0;i<n;i++)
113  {
114  const CPose2D &p = *m_particles[i].d;
115  double w = exp(m_particles[i].log_w);
116  se_averager.append(p,w);
117  }
118  se_averager.get_average(est_);
119  }
120  else
121  {
122  est_ = CPose2D();
123  }
124 }
125 
126 /*---------------------------------------------------------------
127  getEstimatedCovariance
128  ---------------------------------------------------------------*/
129 void CPosePDFParticles::getCovarianceAndMean(CMatrixDouble33 &cov, CPose2D &mean) const
130 {
131  cov.zeros();
132  getMean(mean);
133 
134  size_t i,n = m_particles.size();
135  double var_x=0,var_y=0,var_p=0,var_xy=0,var_xp=0,var_yp=0;
136  double mean_phi = mean.phi();
137 
138  if (mean_phi<0) mean_phi = M_2PI + mean_phi;
139 
140  double lin_w_sum = 0;
141 
142  for (i=0;i<n;i++) lin_w_sum+= exp( m_particles[i].log_w );
143  if (lin_w_sum==0) lin_w_sum=1;
144 
145  for (i=0;i<n;i++)
146  {
147  double w = exp( m_particles[i].log_w ) / lin_w_sum;
148 
149  // Manage 1 PI range:
150  double err_x = m_particles[i].d->x() - mean.x();
151  double err_y = m_particles[i].d->y() - mean.y();
152  double err_phi = math::wrapToPi( fabs(m_particles[i].d->phi() - mean_phi) );
153 
154  var_x+= square(err_x)*w;
155  var_y+= square(err_y)*w;
156  var_p+= square(err_phi)*w;
157  var_xy+= err_x*err_y*w;
158  var_xp+= err_x*err_phi*w;
159  var_yp+= err_y*err_phi*w;
160  }
161 
162  if (n<2)
163  {
164  // Not enought information to estimate the variance:
165  }
166  else
167  {
168  // Unbiased estimation of variance:
169  cov(0,0) = var_x;
170  cov(1,1) = var_y;
171  cov(2,2) = var_p;
172 
173  cov(1,0) = cov(0,1) = var_xy;
174  cov(2,0) = cov(0,2) = var_xp;
175  cov(1,2) = cov(2,1) = var_yp;
176 
177  }
178 }
179 
180 
181 /*---------------------------------------------------------------
182  writeToStream
183  ---------------------------------------------------------------*/
184 void CPosePDFParticles::writeToStream(mrpt::utils::CStream &out,int *version) const
185 {
186  if (version)
187  *version = 0;
188  else
189  {
190  writeParticlesToStream( out );
191  }
192 }
193 
194 /*---------------------------------------------------------------
195  readFromStream
196  ---------------------------------------------------------------*/
197 void CPosePDFParticles::readFromStream(mrpt::utils::CStream &in, int version)
198 {
199  switch(version)
200  {
201  case 0:
202  {
203  readParticlesFromStream( in );
204  } break;
205  // fordward-compatible with mrpt2:
206  case 1:
207  {
209  newparts.readParticlesFromStream(in);
210  resetDeterministic(CPose2D(),newparts.m_particles.size());
211  for (size_t i=0;i<newparts.m_particles.size();i++)
212  {
213  *m_particles[i].d = CPose2D(*newparts.m_particles[i].d);
214  m_particles[i].log_w = newparts.m_particles[i].log_w;
215  }
216  }
217  break;
218  default:
220 
221  };
222 }
223 
224 
225 /*---------------------------------------------------------------
226  resetDeterministic
227  Reset PDF to a single point and set the number of m_particles
228  ---------------------------------------------------------------*/
229 void CPosePDFParticles::resetDeterministic( const CPose2D &location,
230  size_t particlesCount)
231 {
232  if (particlesCount>0)
233  {
234  clear();
235  m_particles.resize(particlesCount);
236  for (auto &p: m_particles)
237  p.d.resetDefaultCtor();
238  }
239 
240  for (auto &p: m_particles)
241  {
242  *p.d = location;
243  p.log_w = .0;
244  }
245 }
246 
247 /*---------------------------------------------------------------
248  resetUniform
249  ---------------------------------------------------------------*/
250 void CPosePDFParticles::resetUniform(
251  const double & x_min,
252  const double & x_max,
253  const double & y_min,
254  const double & y_max,
255  const double & phi_min,
256  const double & phi_max,
257  const int &particlesCount)
258 {
259  MRPT_START
260 
261  if (particlesCount>0)
262  {
263  clear();
264  m_particles.resize(particlesCount);
265  for (int i = 0; i < particlesCount; i++)
266  m_particles[i].d.reset(new CPose2D());
267  }
268 
269  size_t i,M = m_particles.size();
270  for (i=0;i<M;i++)
271  {
272  m_particles[i].d->x( randomGenerator.drawUniform( x_min, x_max ) );
273  m_particles[i].d->y( randomGenerator.drawUniform( y_min, y_max ) );
274  m_particles[i].d->phi( randomGenerator.drawUniform( phi_min, phi_max ) );
275  m_particles[i].log_w=0;
276  }
277 
278  MRPT_END
279 }
280 
281 void CPosePDFParticles::resetAroundSetOfPoses(
282  const std::vector<mrpt::math::TPose2D> & list_poses,
283  const size_t num_particles_per_pose,
284  const double spread_x,
285  const double spread_y,
286  const double spread_phi_rad)
287 {
288  MRPT_START
289  ASSERT_(!list_poses.empty());
290  ASSERT_(num_particles_per_pose>=1);
291 
292  const size_t N = list_poses.size() * num_particles_per_pose;
293 
294  clear();
295  m_particles.resize(N);
296  size_t i,nSpot;
297  for (i=0,nSpot=0;nSpot<list_poses.size();nSpot++)
298  {
299  const mrpt::math::TPose2D & p = list_poses[nSpot];
300  for (size_t k=0;k<num_particles_per_pose;k++,i++)
301  {
302  m_particles[i].d.reset(new CPose2D());
303  m_particles[i].d->x( randomGenerator.drawUniform( p.x - spread_x*0.5, p.x + spread_x*0.5 ) );
304  m_particles[i].d->y( randomGenerator.drawUniform( p.y - spread_y*0.5, p.y + spread_y*0.5 ) );
305  m_particles[i].d->phi( randomGenerator.drawUniform( p.phi - spread_phi_rad*0.5, p.phi + spread_phi_rad*0.5 ) );
306  m_particles[i].log_w=0;
307  }
308  }
309 
310  ASSERT_EQUAL_(i,N);
311 
312  MRPT_END
313 }
314 
315 /*---------------------------------------------------------------
316  saveToTextFile
317  Save PDF's m_particles to a text file. In each line it
318  will go: "x y phi weight"
319  ---------------------------------------------------------------*/
321 {
322  FILE *f=os::fopen(file.c_str(),"wt");
323  if (!f) return;
324  os::fprintf(f,"%% x y yaw[rad] log_weight\n");
325 
326  for (unsigned int i=0;i<m_particles.size();i++)
327  os::fprintf(f,"%f %f %f %e\n",
328  m_particles[i].d->x(),
329  m_particles[i].d->y(),
330  m_particles[i].d->phi(),
331  m_particles[i].log_w );
332 
333  os::fclose(f);
334 }
335 
336 /*---------------------------------------------------------------
337  getParticlePose
338  ---------------------------------------------------------------*/
339 CPose2D CPosePDFParticles::getParticlePose(size_t i) const
340 {
341  return *m_particles[i].d;
342 }
343 
344 /*---------------------------------------------------------------
345  changeCoordinatesReference
346  ---------------------------------------------------------------*/
347 void CPosePDFParticles::changeCoordinatesReference(const CPose3D &newReferenceBase_ )
348 {
349  const CPose2D newReferenceBase = CPose2D(newReferenceBase_);
350 
351  for (CParticleList::iterator it=m_particles.begin();it!=m_particles.end();++it)
352  it->d->composeFrom(newReferenceBase, *it->d);
353 }
354 
355 /*---------------------------------------------------------------
356  drawSingleSample
357  ---------------------------------------------------------------*/
358 void CPosePDFParticles::drawSingleSample( CPose2D &outPart ) const
359 {
360  const double uni = randomGenerator.drawUniform(0.0,0.9999);
361  double cum = 0;
362 
363  for (CParticleList::const_iterator it=m_particles.begin();it!=m_particles.end();++it)
364  {
365  cum+= exp(it->log_w);
366  if ( uni<= cum )
367  {
368  outPart= (*it->d);
369  return;
370  }
371  }
372 
373  // Might not come here normally:
374  outPart = *(m_particles.rbegin())->d;
375 }
376 
377 /*---------------------------------------------------------------
378  +=
379  ---------------------------------------------------------------*/
381 {
382  for (CParticleList::iterator it=m_particles.begin();it!=m_particles.end();++it)
383  it->d->composeFrom(*it->d, Ap);
384 }
385 
386 /*---------------------------------------------------------------
387  append
388  ---------------------------------------------------------------*/
389 void CPosePDFParticles::append( CPosePDFParticles &o )
390 {
391  for (unsigned int i=0;i<o.m_particles.size();i++)
392  {
393  CParticleData part;
394  part.d.reset(new CPose2D(*o.m_particles[i].d));
395  part.log_w = o.m_particles[i].log_w;
396  m_particles.push_back( part );
397  }
398 
399  normalizeWeights();
400 }
401 
402 /*---------------------------------------------------------------
403  inverse
404  ---------------------------------------------------------------*/
406 {
407  MRPT_START
409  CPosePDFParticles *out = static_cast<CPosePDFParticles*>( &o );
410 
411 
412  out->copyFrom( *this );
413  static CPose2D nullPose(0,0,0);
414 
415  for (unsigned int i=0;i<out->m_particles.size();i++)
416  (*out->m_particles[i].d) = nullPose - (*out->m_particles[i].d);
417 
418  MRPT_END
419 }
420 
421 /*---------------------------------------------------------------
422  getMostLikelyParticle
423  ---------------------------------------------------------------*/
424 CPose2D CPosePDFParticles::getMostLikelyParticle() const
425 {
426  CParticleList::const_iterator it, itMax=m_particles.begin();
427  double max_w = -1e300;
428 
429 
430  for (it=m_particles.begin();it!=m_particles.end();++it)
431  {
432  if (it->log_w > max_w)
433  {
434  itMax = it;
435  max_w = it->log_w;
436  }
437  }
438 
439  return *itMax->d;
440 }
441 
442 /*---------------------------------------------------------------
443  bayesianFusion
444  ---------------------------------------------------------------*/
445 void CPosePDFParticles::bayesianFusion(const CPosePDF &p1,const CPosePDF &p2, const double &minMahalanobisDistToDrop )
446 {
447  MRPT_UNUSED_PARAM(p1);MRPT_UNUSED_PARAM(p2);MRPT_UNUSED_PARAM(minMahalanobisDistToDrop);
448 
449  THROW_EXCEPTION("Not implemented yet!");
450 }
451 
452 /*---------------------------------------------------------------
453  evaluatePDF_parzen
454  ---------------------------------------------------------------*/
455 double CPosePDFParticles::evaluatePDF_parzen(
456  const double & x,
457  const double & y,
458  const double & phi,
459  const double & stdXY,
460  const double & stdPhi ) const
461 {
462  double ret = 0;
463 
464  for (CParticleList::const_iterator it=m_particles.begin();it!=m_particles.end();++it)
465  {
466  double difPhi = math::wrapToPi( phi - it->d->phi() );
467 
468  ret += exp(it->log_w) *
469  math::normalPDF( it->d->distance2DTo(x,y), 0, stdXY ) *
470  math::normalPDF( fabs( difPhi ), 0, stdPhi );
471  }
472 
473  return ret;
474 }
475 
476 /*---------------------------------------------------------------
477  saveParzenPDFToTextFile
478  ---------------------------------------------------------------*/
479 void CPosePDFParticles::saveParzenPDFToTextFile(
480  const char *fileName,
481  const double & x_min,
482  const double & x_max,
483  const double & y_min,
484  const double & y_max,
485  const double & phi,
486  const double & stepSizeXY,
487  const double & stdXY,
488  const double & stdPhi ) const
489 {
490  FILE *f=os::fopen(fileName,"wt");
491  if (!f) return;
492 
493  for (double y=y_min; y<y_max; y+=stepSizeXY)
494  {
495  for (double x=x_min; x<x_max; x+=stepSizeXY)
496  {
497  os::fprintf(f,"%f ",
498  evaluatePDF_parzen(x,y,phi,stdXY,stdPhi) );
499  } // y
500  os::fprintf(f,"\n");
501  } // x
502 
503  os::fclose(f);
504 }
#define ASSERT_EQUAL_(__A, __B)
Computes weighted and un-weighted averages of SE(2) poses.
Definition: SO_SE_average.h:88
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:113
FILE BASE_IMPEXP * fopen(const char *fileName, const char *mode) MRPT_NO_THROWS
An OS-independent version of fopen.
Definition: os.cpp:255
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
Definition: zip.h:16
CPose2D mean
The mean value.
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
Definition: math_frwds.h:29
int BASE_IMPEXP void BASE_IMPEXP fclose(FILE *f)
An OS-independent version of fclose.
Definition: os.cpp:272
GLint location
Definition: glext.h:3910
The namespace for Bayesian filtering algorithm: different particle filters and Kalman filter algorith...
#define THROW_EXCEPTION(msg)
BASE_IMPEXP CRandomGenerator randomGenerator
A static instance of a CRandomGenerator class, for use in single-thread applications.
GLenum GLsizei n
Definition: glext.h:4618
Scalar * iterator
Definition: eigen_plugins.h:23
int BASE_IMPEXP fprintf(FILE *fil, const char *format,...) MRPT_NO_THROWS MRPT_printf_format_check(2
An OS-independent version of fprintf.
Definition: os.cpp:412
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:24
void append(const mrpt::poses::CPose2D &p)
Adds a new pose to the computation.
IMPLEMENTS_SERIALIZABLE(CLogFileRecord_FullEval, CHolonomicLogFileRecord, mrpt::nav) IMPLEMENTS_SERIALIZABLE(CHolonomicFullEval
mrpt::math::CMatrixDouble33 cov
The 3x3 covariance matrix.
void clear()
Clear the contents of this container.
Definition: ts_hash_map.h:113
void drawGaussianMultivariateMany(VECTOR_OF_VECTORS &ret, size_t desiredSamples, const COVMATRIX &cov, const typename VECTOR_OF_VECTORS::value_type *mean=NULL)
Generate a given number of multidimensional random samples according to a given covariance matrix...
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3962
#define M_2PI
Definition: mrpt_macros.h:380
void copyFrom(const CPosePDF &o) MRPT_OVERRIDE
Copy operator, translating if necesary (for example, between m_particles and gaussian representations...
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:52
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:38
CParticleList m_particles
The array of particles.
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
virtual const mrpt::utils::TRuntimeClassId * GetRuntimeClass() const
Returns information about the class of an object in runtime.
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.
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:135
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
std::vector< T1 > & operator+=(std::vector< T1 > &a, const std::vector< T2 > &b)
a+=b (element-wise sum)
Definition: ops_vectors.h:70
Eigen::Matrix< dataType, 4, 4 > inverse(Eigen::Matrix< dataType, 4, 4 > &pose)
Definition: Miscellaneous.h:74
int version
Definition: mrpt_jpeglib.h:898
Declares a class that represents a Probability Density Function (PDF) over a 2D pose (x...
GLsizei const GLchar ** string
Definition: glext.h:3919
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:51
This template class declares the array of particles and its internal data, managing some memory-relat...
Declares a class that represents a probability density function (pdf) of a 2D pose (x...
Definition: CPosePDF.h:39
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
#define CLASS_ID(class_name)
Access to runtime class ID for a defined class name.
Definition: CObject.h:82
#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:36
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:72
void readParticlesFromStream(STREAM &in)
Reads the sequence of particles and their weights from a stream (requires T implementing CSerializabl...
const double & phi() const
Get the phi angle of the 2D pose (in radians)
Definition: CPose2D.h:84
double log_w
The (logarithmic) weight value for this particle.
GLuint in
Definition: glext.h:6301
Lightweight 2D pose.
mrpt::utils::copy_ptr< T > d
The data associated with this particle. The use of copy_ptr<> allows relying on compiler-generated co...
#define ASSERT_(f)
GLenum GLint GLint y
Definition: glext.h:3516
GLenum GLint x
Definition: glext.h:3516
double BASE_IMPEXP normalPDF(double x, double mu, double std)
Evaluates the univariate normal (Gaussian) distribution at a given point "x".
Definition: math.cpp:908
GLfloat GLfloat p
Definition: glext.h:5587
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.5.9 Git: 690a4699f Wed Apr 15 19:29:53 2020 +0200 at miƩ abr 15 19:30:12 CEST 2020