34 #ifndef VP_PARTICLE_FILTER_H
35 #define VP_PARTICLE_FILTER_H
37 #include <visp3/core/vpConfig.h>
39 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
40 #include <visp3/core/vpColVector.h>
41 #include <visp3/core/vpGaussRand.h>
42 #include <visp3/core/vpMatrix.h>
46 #ifdef VISP_HAVE_OPENMP
95 template <
typename MeasurementsType>
173 VP_EXPLICIT
vpParticleFilter(
const unsigned int &N,
const std::vector<double> &stdev,
const long &seed = -1,
const int &nbThreads = -1);
253 void update(
const MeasurementsType &z);
272 m_useCommandStateFunction =
false;
273 m_useProcessFunction =
true;
286 m_useCommandStateFunction =
true;
287 m_useProcessFunction =
false;
298 m_likelihood = likelihood;
309 m_stateFilterFunc = filterFunc;
320 m_checkIfResample = resamplingCondFunc;
331 m_resampling = resamplingFunc;
381 #ifdef VISP_HAVE_OPENMP
382 void predictMultithread(
const double &dt,
const vpColVector &u);
383 void updateMultithread(
const MeasurementsType &z);
386 void predictMonothread(
const double &dt,
const vpColVector &u);
387 void updateMonothread(
const MeasurementsType &z);
393 unsigned int m_nbMaxThreads;
394 std::vector<std::vector<vpGaussRand>> m_noiseGenerators;
395 std::vector<vpColVector> m_particles;
396 std::vector<double> m_w;
408 bool m_useProcessFunction;
409 bool m_useCommandStateFunction;
412 template <
typename MeasurementsType>
415 template <
typename MeasurementsType>
418 template <
typename MeasurementsType>
422 , m_w(N, 1./static_cast<double>(N))
423 , m_useProcessFunction(false)
424 , m_useCommandStateFunction(false)
426 #ifndef VISP_HAVE_OPENMP
429 std::cout <<
"[vpParticleFilter::vpParticleFilter] WARNING: OpenMP is not available, maximum number of threads to use clamped to 1" << std::endl;
432 int maxThreads = omp_get_max_threads();
433 if (nbThreads <= 0) {
434 m_nbMaxThreads = maxThreads;
436 else if (nbThreads > maxThreads) {
437 m_nbMaxThreads = maxThreads;
438 std::cout <<
"[vpParticleFilter::vpParticleFilter] WARNING: maximum number of threads to use clamped to "
439 << maxThreads <<
" instead of " << nbThreads <<
" due to OpenMP restrictions." << std::endl;
440 std::cout <<
"[vpParticleFilter::vpParticleFilter] If you want more, consider to use omp_set_num_threads before." << std::endl;
443 m_nbMaxThreads = nbThreads;
445 omp_set_num_threads(m_nbMaxThreads);
448 unsigned int sizeState =
static_cast<unsigned int>(stdev.size());
449 m_noiseGenerators.resize(m_nbMaxThreads);
450 unsigned long long seedForGenerator;
452 seedForGenerator = seed;
459 sampler.
setSeed(seed, 0x123465789ULL);
460 samplerRandomIdx.
setSeed(seed + 4224, 0x123465789ULL);
462 vpUniRand seedGenerator(seedForGenerator);
463 for (
unsigned int threadId = 0; threadId < m_nbMaxThreads; ++threadId) {
464 for (
unsigned int stateId = 0; stateId < sizeState; ++stateId) {
465 m_noiseGenerators[threadId].push_back(
vpGaussRand(stdev[stateId], 0.,
static_cast<long>(seedGenerator.
uniform(0., 1e9))));
470 template <
typename MeasurementsType>
476 if (x0.
size() != m_noiseGenerators[0].size()) {
480 m_stateFilterFunc = filterFunc;
482 m_checkIfResample = checkResamplingFunc;
483 m_resampling = resamplingFunc;
484 m_stateAdd = addFunc;
485 m_useProcessFunction =
true;
486 m_useCommandStateFunction =
false;
492 template <
typename MeasurementsType>
498 if (x0.
size() != m_noiseGenerators[0].size()) {
502 m_stateFilterFunc = filterFunc;
504 m_checkIfResample = checkResamplingFunc;
505 m_resampling = resamplingFunc;
506 m_stateAdd = addFunc;
507 m_useProcessFunction =
false;
508 m_useCommandStateFunction =
true;
514 template <
typename MeasurementsType>
521 template <
typename MeasurementsType>
524 if (m_nbMaxThreads == 1) {
525 predictMonothread(dt, u);
527 #ifdef VISP_HAVE_OPENMP
529 predictMultithread(dt, u);
534 template <
typename MeasurementsType>
537 if (m_nbMaxThreads == 1) {
540 #ifdef VISP_HAVE_OPENMP
542 updateMultithread(z);
545 bool shouldResample = m_checkIfResample(m_N, m_w);
546 if (shouldResample) {
548 m_particles = std::move(particles_weights.
m_particles);
549 m_w = std::move(particles_weights.
m_weights);
553 template <
typename MeasurementsType>
556 return m_stateFilterFunc(m_particles, m_w, m_stateAdd);
559 template <
typename MeasurementsType>
562 size_t nbParticles = particles.
size();
563 if (nbParticles == 0) {
567 for (
size_t i = 1; i < nbParticles; ++i) {
568 res = addFunc(res, particles[i] * weights[i]);
573 template <
typename MeasurementsType>
576 double sumSquare = 0.;
577 for (
unsigned int i = 0; i < N; ++i) {
578 sumSquare += weights[i] * weights[i];
580 if (sumSquare < std::numeric_limits<double>::epsilon()) {
584 double N_eff = 1.0 / sumSquare;
585 return (N_eff < (N / 2.0));
588 template <
typename MeasurementsType>
591 unsigned int nbParticles =
static_cast<unsigned int>(particles.size());
593 double sumWeights = 0.;
594 std::vector<int> idx(nbParticles);
597 for (
unsigned int i = 0; i < nbParticles; ++i) {
600 int index = samplerRandomIdx.uniform(0, nbParticles);
601 for (
unsigned int j = 0; j < nbParticles; ++j) {
602 if (x < sumWeights + weights[j]) {
606 sumWeights += weights[j];
613 newParticlesWeights.
m_particles.resize(nbParticles);
614 for (
unsigned int i = 0; i < nbParticles; ++i) {
615 newParticlesWeights.
m_particles[i] = particles[idx[i]];
619 newParticlesWeights.
m_weights.resize(nbParticles, 1.0/
static_cast<double>(nbParticles));
620 return newParticlesWeights;
623 template <
typename MeasurementsType>
626 unsigned int sizeState = x0.
size();
627 unsigned int chunkSize = m_N / m_nbMaxThreads;
628 double uniformWeight = 1. /
static_cast<double>(m_N);
629 for (
unsigned int i = 0; i < m_nbMaxThreads; ++i) {
630 unsigned int idStart = chunkSize * i;
631 unsigned int idStop = chunkSize * (i + 1);
633 if (i == m_nbMaxThreads - 1) {
636 for (
unsigned int id = idStart;
id < idStop; ++id) {
639 for (
unsigned int idState = 0; idState < sizeState; ++idState) {
640 noise[idState] = m_noiseGenerators[i][idState]();
643 m_particles[id] = m_stateAdd(x0, noise);
646 m_w[id] = uniformWeight;
651 #ifdef VISP_HAVE_OPENMP
652 template <
typename MeasurementsType>
655 int iam, nt, ipoints, istart, npoints(m_N);
656 unsigned int sizeState = m_particles[0].size();
657 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
659 iam = omp_get_thread_num();
660 nt = omp_get_num_threads();
661 ipoints = npoints / nt;
663 istart = iam * ipoints;
666 ipoints = npoints - istart;
669 for (
int i = istart; i< istart + ipoints; ++i) {
671 if (m_useCommandStateFunction) {
672 m_particles[i] = m_bx(u, m_particles[i], dt);
674 else if (m_useProcessFunction) {
675 m_particles[i] = m_f(m_particles[i], dt);
680 for (
unsigned int j = 0; j < sizeState; ++j) {
681 noise[j] = m_noiseGenerators[iam][j]();
685 m_particles[i] = m_stateAdd(m_particles[i], noise);
690 template <
typename MeasurementsType>
692 const MeasurementsType &z, std::vector<double> &w,
const int &istart,
const int &ipoints)
695 for (
int i = istart; i< istart + ipoints; ++i) {
696 w[i] = w[i] * likelihood(v_particles[i], z);
702 template <
typename MeasurementsType>
705 double sumWeights = 0.0;
706 int iam, nt, ipoints, istart, npoints(m_N);
709 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
711 iam = omp_get_thread_num();
712 nt = omp_get_num_threads();
713 ipoints = npoints / nt;
715 istart = iam * ipoints;
718 ipoints = npoints - istart;
720 tempSums[iam] = threadLikelihood<MeasurementsType>(m_likelihood, m_particles, z, m_w, istart, ipoints);
722 sumWeights = tempSums.sum();
724 if (sumWeights > std::numeric_limits<double>::epsilon()) {
725 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
727 iam = omp_get_thread_num();
728 nt = omp_get_num_threads();
729 ipoints = npoints / nt;
731 istart = iam * ipoints;
734 ipoints = npoints - istart;
738 for (
int i = istart; i < istart + ipoints; ++i) {
739 m_w[i] = m_w[i] / sumWeights;
746 template <
typename MeasurementsType>
749 unsigned int sizeState = m_particles[0].size();
750 for (
unsigned int i = 0; i < m_N; ++i) {
752 if (m_useCommandStateFunction) {
753 m_particles[i] = m_bx(u, m_particles[i], dt);
755 else if (m_useProcessFunction) {
756 m_particles[i] = m_f(m_particles[i], dt);
764 for (
unsigned int j = 0; j < sizeState; ++j) {
765 noise[j] = m_noiseGenerators[0][j]();
769 m_particles[i] = m_stateAdd(m_particles[i], noise);
773 template <
typename MeasurementsType>
776 double sumWeights = 0.;
778 for (
unsigned int i = 0; i < m_N; ++i) {
779 m_w[i] = m_w[i] * m_likelihood(m_particles[i], z);
780 sumWeights += m_w[i];
784 if (sumWeights > std::numeric_limits<double>::epsilon()) {
785 for (
unsigned int i = 0; i < m_N; ++i) {
786 m_w[i] = m_w[i] / sumWeights;
unsigned int size() const
Return the number of elements of the 2D array.
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
@ notInitialized
Used to indicate that a parameter is not initialized.
@ dimensionError
Bad dimension.
Class for generating random number with normal probability density.
The class permits to use a Particle Filter.
std::function< vpParticlesWithWeights(const std::vector< vpColVector > &, const std::vector< double > &)> vpResamplingFunction
Function that takes as argument the vector of particles and the vector of associated weights....
virtual ~vpParticleFilter()
void setResamplingFunction(const vpResamplingFunction &resamplingFunc)
Set the resampling function that generate new particles and associated weights when the filter starts...
void setLikelihoodFunction(const vpLikelihoodFunction &likelihood)
Set the likelihood function that updates the weights of the particles based on the new measurements.
std::function< vpColVector(const std::vector< vpColVector > &, const std::vector< double > &, const vpStateAddFunction &)> vpFilterFunction
Filter function, which computes the filtered state of the particle filter. The first argument is the ...
void filter(const MeasurementsType &z, const double &dt, const vpColVector &u=vpColVector())
Perform first the prediction step and then the update step. If needed, resampling will also be perfor...
static bool simpleResamplingCheck(const unsigned int &N, const std::vector< double > &weights)
Returns true if the following condition is fulfilled, or if all the particles diverged: .
static vpColVector weightedMean(const std::vector< vpColVector > &particles, const std::vector< double > &weights, const vpStateAddFunction &addFunc)
Simple function to compute a weighted mean, which just does .
std::function< vpColVector(const vpColVector &, const double &)> vpProcessFunction
Process model function, which projects a particle forward in time. The first argument is a particle,...
struct vpParticleFilter::vpParticlesWithWeights vpParticlesWithWeights
Structure of vectors for which the i^th element of the weights vector is associated to the i^th eleme...
void init(const vpColVector &x0, const vpProcessFunction &f, const vpLikelihoodFunction &l, const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc, const vpFilterFunction &filterFunc=weightedMean, const vpStateAddFunction &addFunc=simpleAdd)
Set the guess of the initial state.
std::function< vpColVector(const vpColVector &, const vpColVector &, const double &)> vpCommandStateFunction
Command model function, which projects a particle forward in time according to the command and its pr...
static vpParticlesWithWeights simpleImportanceResampling(const std::vector< vpColVector > &particles, const std::vector< double > &weights)
Function implementing the resampling of a Simple Importance Resampling Particle Filter.
std::function< bool(const unsigned int &, const std::vector< double > &)> vpResamplingConditionFunction
Function that takes as argument the number of particles and the vector of weights associated to each ...
static vpColVector simpleAdd(const vpColVector &a, const vpColVector &toAdd)
Simple function to compute an addition, which just does .
void setCheckResamplingFunction(const vpResamplingConditionFunction &resamplingCondFunc)
Set the function that returns true when the filter starts to degenerate and false otherwise.
void setFilterFunction(const vpFilterFunction &filterFunc)
Set the filter function that compute the filtered state from the particles and their associated weigh...
VP_EXPLICIT vpParticleFilter(const unsigned int &N, const std::vector< double > &stdev, const long &seed=-1, const int &nbThreads=-1)
Construct a new vpParticleFilter object.
std::function< double(const vpColVector &, const MeasurementsType &)> vpLikelihoodFunction
Likelihood function, which evaluates the likelihood of a particle with regard to the measurements....
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.
void setCommandStateFunction(const vpCommandStateFunction &bx)
Set the command function to use when projecting the particles in the future.
void setProcessFunction(const vpProcessFunction &f)
Set the process function to use when projecting the particles in the future.
void update(const MeasurementsType &z)
Update the weights of the particles based on a new measurement. The weights will be normalized (i....
std::function< vpColVector(const vpColVector &, const vpColVector &)> vpStateAddFunction
Function that computes either the equivalent of an addition in the state space. The first argument is...
vpColVector computeFilteredState()
Compute the filtered state from the particles and their associated weights.
Class for generating random numbers with uniform probability density.
int uniform(int a, int b)
void setSeed(uint64_t initstate, uint64_t initseq)
VISP_EXPORT double measureTimeMicros()
Structure of vectors for which the i^th element of the weights vector is associated to the i^th eleme...
std::vector< double > m_weights
std::vector< vpColVector > m_particles