10 #ifndef PF_implementations_H 11 #define PF_implementations_H 26 #include <type_traits> 49 template <
class PARTICLE_TYPE,
class MY
SELF,
class BINTYPE>
57 typedef std::set<BINTYPE, typename BINTYPE::lt_operator>
78 ASSERT_(robotMovement2D->poseChange);
79 me.m_movementDrawer.setPosePDF(
80 robotMovement2D->poseChange.get_ptr());
82 robotMovement2D->poseChange->getMeanVal());
91 me.m_movementDrawer.setPosePDF(
92 robotMovement3D->poseChange);
99 "Action list does not contain any " 100 "CActionRobotMovement2D or CActionRobotMovement3D " 109 const size_t M = me.m_poseParticles.m_particles.size();
114 for (
size_t i = 0; i < M; i++)
118 me.m_movementDrawer.drawSample(incrPose);
126 me.PF_SLAM_implementation_custom_update_particle_with_new_pose(
127 me.m_poseParticles.m_particles[i].d.get(),
139 TSetStateSpaceBins stateSpaceBins;
142 const double delta_1 = 1.0 - KLD_options.
KLD_delta;
143 const double epsilon_1 = 0.5 / KLD_options.
KLD_epsilon;
146 me.m_poseParticles.prepareFastDrawSample(PF_options);
149 std::vector<mrpt::math::TPose3D> newParticles;
150 std::vector<double> newParticlesWeight;
151 std::vector<size_t> newParticlesDerivedFromIdx;
159 me.m_movementDrawer.drawSample(increment_i);
162 const size_t drawn_idx =
163 me.m_poseParticles.fastDrawSample(PF_options);
168 me.getLastPose(drawn_idx, pose_is_valid)) +
173 newParticles.push_back(newPose_s);
174 newParticlesWeight.push_back(0);
175 newParticlesDerivedFromIdx.push_back(drawn_idx);
180 KLF_loadBinFromParticle<PARTICLE_TYPE, BINTYPE>(
182 me.m_poseParticles.m_particles[drawn_idx].d.get(),
185 if (stateSpaceBins.find(
p) == stateSpaceBins.end())
189 stateSpaceBins.insert(
p);
192 size_t K = stateSpaceBins.size();
203 N = newParticles.size();
214 me.PF_SLAM_implementation_replaceByNewParticleSet(
215 me.m_poseParticles.m_particles, newParticles,
216 newParticlesWeight, newParticlesDerivedFromIdx);
223 const size_t M = me.m_poseParticles.m_particles.size();
227 for (
size_t i = 0; i < M; i++)
233 const double obs_log_likelihood =
234 me.PF_SLAM_computeObservationLikelihoodForParticle(
235 PF_options, i, *sf, partPose2);
236 me.m_poseParticles.m_particles[i].log_w +=
237 obs_log_likelihood * PF_options.
powFactor;
254 template <
class BINTYPE,
class MY
SELF>
268 double indivLik, maxLik = -1e300;
279 for (
size_t q = 0;
q < N;
q++)
281 me.m_movementDrawer.drawSample(drawnSample);
285 indivLik = me.PF_SLAM_computeObservationLikelihoodForParticle(
286 PF_options,
index, *observation, x_predict);
289 vectLiks[
q] = indivLik;
290 if (indivLik > maxLik)
292 maxLikDraw = drawnSample;
303 me.m_pfAuxiliaryPFOptimal_estimatedProb[
index] =
305 me.m_pfAuxiliaryPFOptimal_maxLikelihood[
index] = maxLik;
308 me.m_pfAuxiliaryPFOptimal_maxLikDrawnMovement[
index] = maxLikDraw;
312 return me.m_poseParticles.m_particles[
index].log_w +
313 me.m_pfAuxiliaryPFOptimal_estimatedProb[
index];
328 template <
class BINTYPE,
class MY
SELF>
337 const double cur_logweight =
338 me.m_poseParticles.m_particles[
index].log_w;
352 me.m_pfAuxiliaryPFStandard_estimatedProb[
index] =
353 me.PF_SLAM_computeObservationLikelihoodForParticle(
354 PF_options,
index, *observation, x_predict);
357 return cur_logweight +
358 me.m_pfAuxiliaryPFStandard_estimatedProb[
index];
368 double indivLik, maxLik = -1e300;
376 for (
size_t q = 0;
q < N;
q++)
378 me.m_movementDrawer.drawSample(drawnSample);
382 indivLik = me.PF_SLAM_computeObservationLikelihoodForParticle(
383 PF_options,
index, *observation, x_predict);
386 vectLiks[
q] = indivLik;
387 if (indivLik > maxLik)
389 maxLikDraw = drawnSample;
400 me.m_pfAuxiliaryPFStandard_estimatedProb[
index] =
403 me.m_pfAuxiliaryPFOptimal_maxLikelihood[
index] = maxLik;
405 me.m_pfAuxiliaryPFOptimal_maxLikDrawnMovement[
index] =
410 return cur_logweight +
411 me.m_pfAuxiliaryPFOptimal_estimatedProb[
index];
420 template <
bool USE_OPTIMAL_SAMPLING>
427 class PARTICLE_TYPE,
class MYSELF,
class BINTYPE,
428 class EVALUATOR = std::conditional_t<
438 typedef std::set<BINTYPE, typename BINTYPE::lt_operator>
441 const size_t M = me.m_poseParticles.m_particles.size();
450 MYSELF, BINTYPE>(actions, sf, me))
463 me.m_pfAuxiliaryPFOptimal_maxLikelihood.assign(
465 me.m_pfAuxiliaryPFOptimal_maxLikDrawnMovement.resize(M);
466 me.m_pfAuxiliaryPFOptimal_estimatedProb.resize(M);
467 me.m_pfAuxiliaryPFStandard_estimatedProb.resize(M);
471 me.m_movementDrawer.getSamplingMean3D(meanRobotMovement);
474 func = [&](
size_t i) {
475 return EVALUATOR::template evaluate<BINTYPE, MYSELF>(
476 PF_options, i, &meanRobotMovement, sf, me);
479 me.m_poseParticles.prepareFastDrawSample(PF_options, func);
484 if (USE_OPTIMAL_SAMPLING &&
485 me.isLoggingLevelVisible(mrpt::utils::LVL_DEBUG))
488 mrpt::utils::LVL_DEBUG,
490 "[prepareFastDrawSample] max (log) = %10.06f\n",
493 mrpt::utils::LVL_DEBUG,
495 "[prepareFastDrawSample] max-mean (log) = %10.06f\n",
496 -
math::mean(me.m_pfAuxiliaryPFOptimal_estimatedProb) +
498 me.m_pfAuxiliaryPFOptimal_estimatedProb)));
500 mrpt::utils::LVL_DEBUG,
502 "[prepareFastDrawSample] max-min (log) = %10.06f\n",
505 me.m_pfAuxiliaryPFOptimal_estimatedProb)));
523 std::vector<mrpt::math::TPose3D> newParticles;
524 std::vector<double> newParticlesWeight;
525 std::vector<size_t> newParticlesDerivedFromIdx;
533 me.m_pfAuxiliaryPFOptimal_maxLikMovementDrawHasBeenUsed.assign(
537 USE_OPTIMAL_SAMPLING ? me.m_pfAuxiliaryPFOptimal_estimatedProb
538 : me.m_pfAuxiliaryPFStandard_estimatedProb);
545 newParticles.resize(M);
546 newParticlesWeight.resize(M);
547 newParticlesDerivedFromIdx.resize(M);
549 const bool doResample = me.m_poseParticles.ESS() < PF_options.
BETA;
551 for (
size_t i = 0; i < M; i++)
559 k = me.m_poseParticles.fastDrawSample(
567 double newParticleLogWeight = 0.0;
570 doResample, maxMeanLik, k, sf, PF_options, newPose,
571 newParticleLogWeight, me);
574 newParticles[i] = newPose;
575 newParticlesDerivedFromIdx[i] = k;
576 newParticlesWeight[i] = newParticleLogWeight;
589 newParticles.clear();
590 newParticlesWeight.resize(0);
591 newParticlesDerivedFromIdx.clear();
604 TSetStateSpaceBins stateSpaceBinsLastTimestep;
605 std::vector<vector_uint> stateSpaceBinsLastTimestepParticles;
607 unsigned int partIndex;
609 me.logStr(mrpt::utils::LVL_DEBUG,
"[FIXED_SAMPLING] Computing...");
610 for (partIt = me.m_poseParticles.m_particles.begin(), partIndex = 0;
611 partIt != me.m_poseParticles.m_particles.end();
612 ++partIt, ++partIndex)
616 KLF_loadBinFromParticle<PARTICLE_TYPE, BINTYPE>(
617 p, KLD_options, partIt->d.get());
621 stateSpaceBinsLastTimestep.find(
p);
622 if (posFound == stateSpaceBinsLastTimestep.end())
624 stateSpaceBinsLastTimestep.insert(
p);
625 stateSpaceBinsLastTimestepParticles.push_back(
631 stateSpaceBinsLastTimestep.begin(), posFound);
632 stateSpaceBinsLastTimestepParticles[idx].push_back(
637 mrpt::utils::LVL_DEBUG,
639 "[FIXED_SAMPLING] done (%u bins in t-1)\n",
640 (
unsigned int)stateSpaceBinsLastTimestep.size()));
645 double delta_1 = 1.0 - KLD_options.
KLD_delta;
647 bool doResample = me.m_poseParticles.ESS() < PF_options.
BETA;
654 const size_t minNumSamples_KLD = std::max(
658 stateSpaceBinsLastTimestep.size()));
659 size_t Nx = minNumSamples_KLD;
661 const size_t Np1 = me.m_poseParticles.m_particles.size();
664 for (
size_t k = 0; k < Np1; k++)
665 oldPartIdxsStillNotPropragated[k] = k;
667 const size_t Np = stateSpaceBinsLastTimestepParticles.size();
669 for (
size_t k = 0; k < Np; k++) permutationPathsAuxVector[k] = k;
675 permutationPathsAuxVector.begin(),
676 permutationPathsAuxVector.end(),
682 TSetStateSpaceBins stateSpaceBins;
696 k = me.m_poseParticles.fastDrawSample(
704 if (permutationPathsAuxVector.size())
706 const size_t idxBinSpacePath =
707 *permutationPathsAuxVector.rbegin();
708 permutationPathsAuxVector.resize(
709 permutationPathsAuxVector.size() - 1);
714 stateSpaceBinsLastTimestepParticles[idxBinSpacePath]
716 k = stateSpaceBinsLastTimestepParticles[idxBinSpacePath]
718 ASSERT_(k < me.m_poseParticles.m_particles.size());
721 oldPartIdxsStillNotPropragated.erase(
std::find(
722 oldPartIdxsStillNotPropragated.begin(),
723 oldPartIdxsStillNotPropragated.end(), k));
736 if (oldPartIdxsStillNotPropragated.size())
741 oldPartIdxsStillNotPropragated.size();
743 oldPartIdxsStillNotPropragated.begin() +
746 oldPartIdxsStillNotPropragated.erase(it);
753 me.m_poseParticles.m_particles.size();
761 double newParticleLogWeight;
764 doResample, maxMeanLik, k, sf, PF_options, newPose,
765 newParticleLogWeight, me);
768 newParticles.push_back(newPose);
769 newParticlesDerivedFromIdx.push_back(k);
770 newParticlesWeight.push_back(newParticleLogWeight);
778 KLF_loadBinFromParticle<PARTICLE_TYPE, BINTYPE>(
779 p, KLD_options, me.m_poseParticles.m_particles[k].d.get(),
789 if (stateSpaceBins.find(
p) == stateSpaceBins.end())
792 stateSpaceBins.insert(
p);
795 int K = stateSpaceBins.
size();
806 N = newParticles.size();
809 N < std::max(Nx, minNumSamples_KLD)) ||
810 (permutationPathsAuxVector.size() && !doResample));
813 mrpt::utils::LVL_DEBUG,
815 "[ADAPTIVE SAMPLE SIZE] #Bins: %u \t #Particles: %u \t " 817 static_cast<unsigned>(stateSpaceBins.size()),
818 static_cast<unsigned>(N), (unsigned)Nx));
827 me.PF_SLAM_implementation_replaceByNewParticleSet(
828 me.m_poseParticles.m_particles, newParticles, newParticlesWeight,
829 newParticlesDerivedFromIdx);
832 me.m_poseParticles.normalizeWeights();
846 template <
class MY
SELF,
class BINTYPE>
851 if (actions !=
nullptr)
857 if (me.m_accumRobotMovement3DIsValid)
860 ASSERT_(robotMovement2D->poseChange);
861 if (!me.m_accumRobotMovement2DIsValid)
863 robotMovement2D->poseChange->getMean(
864 me.m_accumRobotMovement2D.rawOdometryIncrementReading);
865 me.m_accumRobotMovement2D.motionModelConfiguration =
866 robotMovement2D->motionModelConfiguration;
869 me.m_accumRobotMovement2D.rawOdometryIncrementReading +=
870 robotMovement2D->poseChange->getMeanVal();
872 me.m_accumRobotMovement2DIsValid =
true;
881 if (me.m_accumRobotMovement2DIsValid)
883 "Mixing 2D and 3D actions is not allowed.")
885 if (!me.m_accumRobotMovement3DIsValid)
886 me.m_accumRobotMovement3D = robotMovement3D->poseChange;
888 me.m_accumRobotMovement3D +=
889 robotMovement3D->poseChange;
893 me.m_accumRobotMovement3DIsValid =
true;
900 const bool SFhasValidObservations =
903 : me.PF_SLAM_implementation_doWeHaveValidObservations(
904 me.m_poseParticles.m_particles, sf);
907 if (!((me.m_accumRobotMovement2DIsValid ||
908 me.m_accumRobotMovement3DIsValid) &&
909 SFhasValidObservations))
914 if (me.m_accumRobotMovement3DIsValid)
916 me.m_movementDrawer.setPosePDF(
917 me.m_accumRobotMovement3D);
918 me.m_accumRobotMovement3DIsValid =
925 me.m_accumRobotMovement2D.rawOdometryIncrementReading,
926 me.m_accumRobotMovement2D.motionModelConfiguration);
929 me.m_movementDrawer.setPosePDF(
932 me.m_accumRobotMovement2DIsValid =
942 template <
class MY
SELF,
class BINTYPE>
944 const bool doResample,
const double maxMeanLik,
954 while (((USE_OPTIMAL_SAMPLING
955 ? me.m_pfAuxiliaryPFOptimal_estimatedProb[k]
956 : me.m_pfAuxiliaryPFStandard_estimatedProb[k]) -
961 me.m_poseParticles.m_particles.size();
963 mrpt::utils::LVL_DEBUG,
964 "[PF_SLAM_aux_perform_one_rejection_sampling_step] Warning: " 965 "Discarding very unlikely particle.");
978 if (me.PF_SLAM_implementation_skipRobotMovement())
983 out_newPose = oldPose;
989 if (!USE_OPTIMAL_SAMPLING)
991 me.m_movementDrawer.drawSample(movementDraw);
996 poseLogLik = me.PF_SLAM_computeObservationLikelihoodForParticle(
997 PF_options, k, *sf, out_newPose);
1002 double acceptanceProb;
1004 const int maxTries = 10000;
1005 double bestTryByNow_loglik =
1006 -std::numeric_limits<double>::max();
1012 !me.m_pfAuxiliaryPFOptimal_maxLikMovementDrawHasBeenUsed
1017 me.m_pfAuxiliaryPFOptimal_maxLikMovementDrawHasBeenUsed
1020 me.m_pfAuxiliaryPFOptimal_maxLikDrawnMovement[k]);
1025 me.m_movementDrawer.drawSample(movementDraw);
1034 me.PF_SLAM_computeObservationLikelihoodForParticle(
1035 PF_options, k, *sf, out_newPose);
1037 if (poseLogLik > bestTryByNow_loglik)
1039 bestTryByNow_loglik = poseLogLik;
1040 bestTryByNow_pose = out_newPose;
1043 double ratioLikLik = std::exp(
1045 me.m_pfAuxiliaryPFOptimal_maxLikelihood[k]);
1046 acceptanceProb =
std::min(1.0, ratioLikLik);
1048 if (ratioLikLik > 1)
1050 me.m_pfAuxiliaryPFOptimal_maxLikelihood[k] =
1055 }
while (++timeout < maxTries &&
1060 if (timeout >= maxTries)
1063 poseLogLik = bestTryByNow_loglik;
1065 mrpt::utils::LVL_WARN,
1066 "[PF_implementation] Warning: timeout in rejection " 1072 if (USE_OPTIMAL_SAMPLING)
1075 out_newParticleLogWeight =
1081 const double weightFact =
1082 me.m_pfAuxiliaryPFOptimal_estimatedProb[k] *
1084 out_newParticleLogWeight =
1085 me.m_poseParticles.m_particles[k].log_w + weightFact;
1090 const double weightFact =
1091 (poseLogLik - me.m_pfAuxiliaryPFStandard_estimatedProb[k]) *
1094 out_newParticleLogWeight = weightFact;
1096 out_newParticleLogWeight =
1097 weightFact + me.m_poseParticles.m_particles[k].log_w;
uint32_t drawUniform32bit()
Generate a uniformly distributed pseudo-random number using the MT19937 algorithm, in the whole range of 32-bit integers.
mrpt::poses::CPose3DPDFGaussian poseChange
The 3D pose change probabilistic estimation.
std::vector< uint32_t > vector_uint
void getMean(CPose3D &mean_pose) const override
Returns an estimate of the pose, (the mean, or mathematical expectation of the PDF).
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
static void PF_SLAM_aux_perform_one_rejection_sampling_step(const bool doResample, const double maxMeanLik, size_t k, const mrpt::obs::CSensoryFrame *sf, const mrpt::bayes::CParticleFilter::TParticleFilterOptions &PF_options, mrpt::poses::CPose3D &out_newPose, double &out_newParticleLogWeight, MYSELF &me)
static constexpr bool DoesResampling
#define INVALID_LIKELIHOOD_VALUE
unsigned int pfAuxFilterOptimal_MaximumSearchSamples
In the algorithm "CParticleFilter::pfAuxiliaryPFOptimal" (and in "CParticleFilter::pfAuxiliaryPFStand...
#define MRPT_CHECK_NORMAL_NUMBER(val)
static constexpr bool DoesResampling
#define THROW_EXCEPTION(msg)
GLdouble GLdouble GLdouble GLdouble q
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
Option set for KLD algorithm.
void computeFromOdometry(const mrpt::poses::CPose2D &odometryIncrement, const TMotionModelOptions &options)
Computes the PDF of the pose increment from an odometry reading and according to the given motion mod...
Compute w[i]*p(z_t | mu_t^i), with mu_t^i being the mean of the new robot pose.
const_iterator find(const KEY &key) const
A generic implementation of the PF method "pfStandardProposal" (standard proposal distribution...
Declares a class for storing a collection of robot actions.
static void PF_SLAM_implementation(const mrpt::obs::CActionCollection *actions, const mrpt::obs::CSensoryFrame *sf, const mrpt::bayes::CParticleFilter::TParticleFilterOptions &PF_options, const TKLDParams &KLD_options, MYSELF &me)
CONTAINER::Scalar minimum(const CONTAINER &v)
Represents a probabilistic 3D (6D) movement.
Represents a probabilistic 2D movement of the robot mobile base.
std::function< double(size_t index)> TParticleProbabilityEvaluator
A callback function type for evaluating the probability of m_particles of being selected, used in "fastDrawSample".
unsigned int KLD_minSampleSize
Parameters for the KLD adaptive sample size algorithm (see Dieter Fox's papers), which is used only i...
static void PF_SLAM_implementation(const mrpt::obs::CActionCollection *actions, const mrpt::obs::CSensoryFrame *sf, const mrpt::bayes::CParticleFilter::TParticleFilterOptions &PF_options, const TKLDParams &KLD_options, MYSELF &me)
std::shared_ptr< CActionRobotMovement2D > Ptr
CActionRobotMovement2D::Ptr getBestMovementEstimation() const
Returns the best pose increment estimator in the collection, based on the determinant of its pose cha...
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
void composeFrom(const CPose3D &A, const CPose3D &B)
Makes "this = A (+) B"; this method is slightly more efficient than "this= A + B;" since it avoids th...
double KLD_minSamplesPerBin
(Default: KLD_minSamplesPerBin=0) The minimum number of samples will be the maximum of KLD_minSampleS...
double averageLogLikelihood(const CVectorDouble &logLikelihoods)
A numerically-stable method to compute average likelihood values with strongly different ranges (unwe...
mrpt::utils::poly_ptr_ptr< mrpt::poses::CPosePDF::Ptr > poseChange
The 2D pose change probabilistic estimation.
static bool PF_SLAM_implementation_gatherActionsCheckBothActObs(const mrpt::obs::CActionCollection *actions, const mrpt::obs::CSensoryFrame *sf, MYSELF &me)
Auxiliary method called by PF implementations: return true if we have both action & observation...
Declares a class for storing a "sensory frame", a set of "observations" taken by the robot approximat...
std::shared_ptr< CActionRobotMovement3D > Ptr
bool pfAuxFilterStandard_FirstStageWeightsMonteCarlo
Only for PF_algorithm==pfAuxiliaryPFStandard: If false, the APF will predict the first stage weights ...
CONTAINER::Scalar maximum(const CONTAINER &v)
double BETA
The resampling of particles will be performed when ESS (in range [0,1]) < BETA (default is 0...
ptrdiff_t random_generator_for_STL(ptrdiff_t i)
A random number generator for usage in STL algorithms expecting a function like this (eg...
unsigned int KLD_maxSampleSize
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
static double evaluate(const mrpt::bayes::CParticleFilter::TParticleFilterOptions &PF_options, unsigned long index, const mrpt::poses::CPose3D *action, const mrpt::obs::CSensoryFrame *observation, const MYSELF &me)
double chi2inv(double P, unsigned int dim=1)
The "quantile" of the Chi-Square distribution, for dimension "dim" and probability 0<P<1 (the inverse...
const T & get_ptr() const
double max_loglikelihood_dyn_range
Only for PF_algorithm=pfAuxiliaryPFOptimal: If a given particle has a max_likelihood (from the a-prio...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
double powFactor
An optional step to "smooth" dramatic changes in the observation model to affect the variance of the ...
The configuration of a particle filter.
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
double mean(const CONTAINER &v)
Computes the mean value of a vector.
int round(const T value)
Returns the closer integer (int) to x.
static double evaluate(const mrpt::bayes::CParticleFilter::TParticleFilterOptions &PF_options, unsigned long index, const mrpt::poses::CPose3D *action, const mrpt::obs::CSensoryFrame *observation, const MYSELF &me)
std::vector< size_t > vector_size_t
bool pfAuxFilterOptimal_MLE
(Default=false) In the algorithm "CParticleFilter::pfAuxiliaryPFOptimal", if set to true...
T::Ptr getActionByClass(const size_t &ith=0) const
Access to the i'th action of a given class, or a nullptr smart pointer if there is no action of that ...
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
double distance(const TPoint2D &p1, const TPoint2D &p2)
Gets the distance between two points in a 2D space.
bool adaptiveSampleSize
A flag that indicates whether the CParticleFilterCapable object should perform adative sample size (d...