70 #include <visp3/core/vpConfig.h>
71 #include <visp3/core/vpGaussRand.h>
72 #ifdef VISP_HAVE_DISPLAY
73 #include <visp3/gui/vpPlot.h>
77 #include <visp3/core/vpParticleFilter.h>
79 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
81 #ifdef ENABLE_VISP_NAMESPACE
97 point[0] = particle[1] * dt + particle[0];
98 point[1] = particle[1];
99 point[2] = particle[3] * dt + particle[2];
100 point[3] = particle[3];
113 void computeCoordinatesFromMeasurement(
const vpColVector &z,
const double &xRadar,
const double &yRadar,
double &x,
double &y)
115 double dx = z[0] * std::cos(z[1]);
116 double dy = z[0] * std::sin(z[1]);
129 double computeError(
const double &x0,
const double &y0,
const double &x1,
const double &y1)
133 double error = std::sqrt(dx * dx + dy * dy);
146 double error = computeError(state[0], state[2], gt_X[0], gt_X[1]);
159 double computeMeasurementsError(
const vpColVector &z,
const double &xRadar,
const double &yRadar,
const vpColVector >_X)
161 double xMeas = 0., yMeas = 0.;
162 computeCoordinatesFromMeasurement(z, xRadar, yRadar, xMeas, yMeas);
163 double error = computeError(xMeas, yMeas, gt_X[0], gt_X[1]);
184 vpRadarStation(
const double &x,
const double &y,
const double &range_std,
const double &elev_angle_std,
185 const double &distMaxAllowed)
188 , m_rngRange(range_std, 0., 4224)
189 , m_rngElevAngle(elev_angle_std, 0., 2112)
191 double sigmaDistance = distMaxAllowed / 3.;
192 double sigmaDistanceSquared = sigmaDistance * sigmaDistance;
193 m_constantDenominator = 1. / std::sqrt(2. * M_PI * sigmaDistanceSquared);
194 m_constantExpDenominator = -1. / (2. * sigmaDistanceSquared);
206 double dx = particle[0] - m_x;
207 double dy = particle[2] - m_y;
208 meas[0] = std::sqrt(dx * dx + dy * dy);
209 meas[1] = std::atan2(dy, dx);
223 double dx = pos[0] - m_x;
224 double dy = pos[1] - m_y;
225 double range = std::sqrt(dx * dx + dy * dy);
226 double elevAngle = std::atan2(dy, dx);
228 measurements[0] = range;
229 measurements[1] = elevAngle;
245 measurementsNoisy[0] += m_rngRange();
246 measurementsNoisy[1] += m_rngElevAngle();
247 return measurementsNoisy;
262 double xParticle = particle[0];
263 double yParticle = particle[2];
264 double xMeas = 0., yMeas = 0.;
265 computeCoordinatesFromMeasurement(meas, m_x, m_y, xMeas, yMeas);
266 double dist = computeError(xParticle, yParticle, xMeas, yMeas);
267 double likelihood = std::exp(m_constantExpDenominator * dist) * m_constantDenominator;
268 likelihood = std::min(likelihood, 1.0);
269 likelihood = std::max(likelihood, 0.);
278 double m_constantDenominator;
279 double m_constantExpDenominator;
298 , m_rngVel(vel_std, 0.)
313 dx[0] += m_rngVel() * dt;
314 dx[1] += m_rngVel() * dt;
328 static const int SOFTWARE_CONTINUE = 42;
330 unsigned int m_nbStepsWarmUp;
344 double m_maxDistanceForLikelihood;
354 , m_nbStepsWarmUp(200)
358 , m_sigmaElevAngle(
vpMath::rad(0.5))
359 , m_stdevAircraftVelocity(0.2)
367 , m_maxDistanceForLikelihood(50.)
380 std::string arg(argv[i]);
381 if ((arg ==
"--nb-steps-main") && ((i+1) < argc)) {
382 m_nbSteps = std::atoi(argv[i + 1]);
385 else if ((arg ==
"--nb-steps-warmup") && ((i+1) < argc)) {
386 m_nbStepsWarmUp = std::atoi(argv[i + 1]);
389 else if ((arg ==
"--dt") && ((i+1) < argc)) {
390 m_dt = std::atoi(argv[i + 1]);
393 else if ((arg ==
"--stdev-range") && ((i+1) < argc)) {
394 m_sigmaRange = std::atof(argv[i + 1]);
397 else if ((arg ==
"--stdev-elev-angle") && ((i+1) < argc)) {
398 m_sigmaElevAngle =
vpMath::rad(std::atof(argv[i + 1]));
401 else if ((arg ==
"--stdev-aircraft-vel") && ((i+1) < argc)) {
402 m_stdevAircraftVelocity = std::atof(argv[i + 1]);
405 else if ((arg ==
"--radar-X") && ((i+1) < argc)) {
406 m_radar_X = std::atof(argv[i + 1]);
409 else if ((arg ==
"--radar-Y") && ((i+1) < argc)) {
410 m_radar_Y = std::atof(argv[i + 1]);
413 else if ((arg ==
"--gt-X0") && ((i+1) < argc)) {
414 m_gt_X_init = std::atof(argv[i + 1]);
417 else if ((arg ==
"--gt-Y0") && ((i+1) < argc)) {
418 m_gt_Y_init = std::atof(argv[i + 1]);
421 else if ((arg ==
"--gt-vX0") && ((i+1) < argc)) {
422 m_gt_vX_init = std::atof(argv[i + 1]);
425 else if ((arg ==
"--gt-vY0") && ((i+1) < argc)) {
426 m_gt_vY_init = std::atof(argv[i + 1]);
429 else if ((arg ==
"--max-distance-likelihood") && ((i+1) < argc)) {
430 m_maxDistanceForLikelihood = std::atof(argv[i + 1]);
433 else if (((arg ==
"-N") || (arg ==
"--nb-particles")) && ((i+1) < argc)) {
434 m_N = std::atoi(argv[i + 1]);
437 else if ((arg ==
"--seed") && ((i+1) < argc)) {
438 m_seedPF = std::atoi(argv[i + 1]);
441 else if ((arg ==
"--nb-threads") && ((i+1) < argc)) {
442 m_nbThreads = std::atoi(argv[i + 1]);
445 else if ((arg ==
"--ampli-max-X") && ((i+1) < argc)) {
446 m_ampliMaxX = std::atof(argv[i + 1]);
449 else if ((arg ==
"--ampli-max-Y") && ((i+1) < argc)) {
450 m_ampliMaxY = std::atof(argv[i + 1]);
453 else if ((arg ==
"--ampli-max-vX") && ((i+1) < argc)) {
454 m_ampliMaxVx = std::atof(argv[i + 1]);
457 else if ((arg ==
"--ampli-max-vY") && ((i+1) < argc)) {
458 m_ampliMaxVy = std::atof(argv[i + 1]);
461 else if (arg ==
"-d") {
462 m_useDisplay =
false;
464 else if ((arg ==
"-h") || (arg ==
"--help")) {
465 printUsage(std::string(argv[0]));
467 defaultArgs.printDetails();
471 std::cout <<
"WARNING: unrecognised argument \"" << arg <<
"\"";
473 std::cout <<
" with associated value(s) { ";
476 bool hasToRun =
true;
477 while ((j < argc) && hasToRun) {
478 std::string nextValue(argv[j]);
479 if (nextValue.find(
"--") == std::string::npos) {
480 std::cout << nextValue <<
" ";
488 std::cout <<
"}" << std::endl;
494 return SOFTWARE_CONTINUE;
498 void printUsage(
const std::string &softName)
500 std::cout <<
"SYNOPSIS" << std::endl;
501 std::cout <<
" " << softName <<
" [--nb-steps-main <uint>] [--nb-steps-warmup <uint>]" << std::endl;
502 std::cout <<
" [--dt <double>] [--stdev-range <double>] [--stdev-elev-angle <double>] [--stdev-aircraft-vel <double>]" << std::endl;
503 std::cout <<
" [--radar-X <double>] [--radar-Y <double>]" << std::endl;
504 std::cout <<
" [--gt-X0 <double>] [--gt-Y0 <double>] [--gt-vX0 <double>] [--gt-vY0 <double>]" << std::endl;
505 std::cout <<
" [--max-distance-likelihood <double>] [-N, --nb-particles <uint>] [--seed <int>] [--nb-threads <int>]" << std::endl;
506 std::cout <<
" [--ampli-max-X <double>] [--ampli-max-Y <double>] [--ampli-max-vX <double>] [--ampli-max-vY <double>]" << std::endl;
507 std::cout <<
" [-d, --no-display] [-h]" << std::endl;
512 std::cout << std::endl << std::endl;
513 std::cout <<
"DETAILS" << std::endl;
514 std::cout <<
" --nb-steps-main" << std::endl;
515 std::cout <<
" Number of steps in the main loop." << std::endl;
516 std::cout <<
" Default: " << m_nbSteps << std::endl;
517 std::cout << std::endl;
518 std::cout <<
" --nb-steps-warmup" << std::endl;
519 std::cout <<
" Number of steps in the warmup loop." << std::endl;
520 std::cout <<
" Default: " << m_nbStepsWarmUp << std::endl;
521 std::cout << std::endl;
522 std::cout <<
" --dt" << std::endl;
523 std::cout <<
" Timestep of the simulation, in seconds." << std::endl;
524 std::cout <<
" Default: " << m_dt << std::endl;
525 std::cout << std::endl;
526 std::cout <<
" --stdev-range" << std::endl;
527 std::cout <<
" Standard deviation of the range measurements, in meters." << std::endl;
528 std::cout <<
" Default: " << m_sigmaRange << std::endl;
529 std::cout << std::endl;
530 std::cout <<
" --stdev-elev-angle" << std::endl;
531 std::cout <<
" Standard deviation of the elevation angle measurements, in degrees." << std::endl;
532 std::cout <<
" Default: " <<
vpMath::deg(m_sigmaElevAngle) << std::endl;
533 std::cout << std::endl;
534 std::cout <<
" --stdev-aircraft-vel" << std::endl;
535 std::cout <<
" Standard deviation of the aircraft velocity, in m/s." << std::endl;
536 std::cout <<
" Default: " << m_stdevAircraftVelocity << std::endl;
537 std::cout << std::endl;
538 std::cout <<
" --radar-X" << std::endl;
539 std::cout <<
" Position along the X-axis of the radar, in meters." << std::endl;
540 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
541 std::cout <<
" Default: " << m_radar_X << std::endl;
542 std::cout << std::endl;
543 std::cout <<
" --radar-Y" << std::endl;
544 std::cout <<
" Position along the Y-axis of the radar, in meters." << std::endl;
545 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
546 std::cout <<
" Default: " << m_radar_Y << std::endl;
547 std::cout << std::endl;
548 std::cout <<
" --gt-X0" << std::endl;
549 std::cout <<
" Initial position along the X-axis of the aircraft, in meters." << std::endl;
550 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
551 std::cout <<
" Default: " << m_gt_X_init << std::endl;
552 std::cout << std::endl;
553 std::cout <<
" --gt-Y0" << std::endl;
554 std::cout <<
" Initial position along the Y-axis of the aircraft, in meters." << std::endl;
555 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
556 std::cout <<
" Default: " << m_gt_Y_init << std::endl;
557 std::cout << std::endl;
558 std::cout <<
" --gt-vX0" << std::endl;
559 std::cout <<
" Initial velocity along the X-axis of the aircraft, in m/s." << std::endl;
560 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
561 std::cout <<
" Default: " << m_gt_vX_init << std::endl;
562 std::cout << std::endl;
563 std::cout <<
" --gt-vY0" << std::endl;
564 std::cout <<
" Initial velocity along the Y-axis of the aircraft, in m/s." << std::endl;
565 std::cout <<
" Be careful, because singularities happen if the aircraft flies above the radar." << std::endl;
566 std::cout <<
" Default: " << m_gt_vY_init << std::endl;
567 std::cout << std::endl;
568 std::cout <<
" --max-distance-likelihood" << std::endl;
569 std::cout <<
" Maximum tolerated distance between a particle and the measurements." << std::endl;
570 std::cout <<
" Above this value, the likelihood of the particle is 0." << std::endl;
571 std::cout <<
" Default: " << m_maxDistanceForLikelihood << std::endl;
572 std::cout << std::endl;
573 std::cout <<
" -N, --nb-particles" << std::endl;
574 std::cout <<
" Number of particles of the Particle Filter." << std::endl;
575 std::cout <<
" Default: " << m_N << std::endl;
576 std::cout << std::endl;
577 std::cout <<
" --seed" << std::endl;
578 std::cout <<
" Seed to initialize the Particle Filter." << std::endl;
579 std::cout <<
" Use a negative value makes to use the current timestamp instead." << std::endl;
580 std::cout <<
" Default: " << m_seedPF << std::endl;
581 std::cout << std::endl;
582 std::cout <<
" --nb-threads" << std::endl;
583 std::cout <<
" Set the number of threads to use in the Particle Filter (only if OpenMP is available)." << std::endl;
584 std::cout <<
" Use a negative value to use the maximum number of threads instead." << std::endl;
585 std::cout <<
" Default: " << m_nbThreads << std::endl;
586 std::cout << std::endl;
587 std::cout <<
" --ampli-max-X" << std::endl;
588 std::cout <<
" Maximum amplitude of the noise added to a particle along the X-axis." << std::endl;
589 std::cout <<
" Default: " << m_ampliMaxX << std::endl;
590 std::cout << std::endl;
591 std::cout <<
" --ampli-max-Y" << std::endl;
592 std::cout <<
" Maximum amplitude of the noise added to a particle along the Y-axis." << std::endl;
593 std::cout <<
" Default: " << m_ampliMaxY << std::endl;
594 std::cout << std::endl;
595 std::cout <<
" --ampli-max-vX" << std::endl;
596 std::cout <<
" Maximum amplitude of the noise added to a particle to the velocity along the X-axis component." << std::endl;
597 std::cout <<
" Default: " << m_ampliMaxVx << std::endl;
598 std::cout << std::endl;
599 std::cout <<
" --ampli-max-vY" << std::endl;
600 std::cout <<
" Maximum amplitude of the noise added to a particle to the velocity along the Y-axis component." << std::endl;
601 std::cout <<
" Default: " << m_ampliMaxVy << std::endl;
602 std::cout << std::endl;
603 std::cout <<
" -d, --no-display" << std::endl;
604 std::cout <<
" Deactivate display." << std::endl;
605 std::cout <<
" Default: display is ";
606 #ifdef VISP_HAVE_DISPLAY
607 std::cout <<
"ON" << std::endl;
609 std::cout <<
"OFF" << std::endl;
611 std::cout << std::endl;
612 std::cout <<
" -h, --help" << std::endl;
613 std::cout <<
" Display this help." << std::endl;
614 std::cout << std::endl;
618 int main(
const int argc,
const char *argv[])
621 int returnCode = args.
parseArgs(argc, argv);
629 unsigned int nbParticles = args.
m_N;
640 using std::placeholders::_1;
641 using std::placeholders::_2;
648 filter.init(X0, f, likelihoodFunc, checkResamplingFunc, resamplingFunc);
650 #ifdef VISP_HAVE_DISPLAY
656 plot->
setTitle(0,
"Position along X-axis");
667 plot->
setTitle(1,
"Velocity along X-axis");
669 plot->
setUnitY(1,
"Velocity (m/s)");
678 plot->
setTitle(2,
"Position along Y-axis");
689 plot->
setTitle(3,
"Velocity along Y-axis");
691 plot->
setUnitY(3,
"Velocity (m/s)");
711 double averageFilteringTime = 0.;
712 double meanErrorFilter = 0., meanErrorNoise = 0.;
713 double xNoise_prec = 0., yNoise_prec = 0.;
717 for (
unsigned int i = 0; i < nbStepsWarmUp; ++i) {
726 filter.filter(z, args.
m_dt);
731 computeCoordinatesFromMeasurement(z, args.
m_radar_X, args.
m_radar_Y, xNoise_prec, yNoise_prec);
734 for (
unsigned int i = 0; i < args.
m_nbSteps; ++i) {
742 filter.filter(z, args.
m_dt);
748 double normErrorFilter = computeStateError(Xest, gt_X);
749 meanErrorFilter += normErrorFilter;
752 double xNoise = 0., yNoise = 0.;
754 double normErrorNoise = computeMeasurementsError(z, args.
m_radar_X, args.
m_radar_Y, gt_X);
755 meanErrorNoise += normErrorNoise;
757 #ifdef VISP_HAVE_DISPLAY
760 plot->
plot(0, 0, i, gt_X[0]);
761 plot->
plot(0, 1, i, Xest[0]);
762 plot->
plot(0, 2, i, xNoise);
764 double vxNoise = (xNoise - xNoise_prec) / args.
m_dt;
765 plot->
plot(1, 0, i, gt_V[0]);
766 plot->
plot(1, 1, i, Xest[1]);
767 plot->
plot(1, 2, i, vxNoise);
769 plot->
plot(2, 0, i, gt_X[1]);
770 plot->
plot(2, 1, i, Xest[2]);
771 plot->
plot(2, 2, i, yNoise);
773 double vyNoise = (yNoise - yNoise_prec) / args.
m_dt;
774 plot->
plot(3, 0, i, gt_V[1]);
775 plot->
plot(3, 1, i, Xest[3]);
776 plot->
plot(3, 2, i, vyNoise);
782 xNoise_prec = xNoise;
783 yNoise_prec = yNoise;
787 meanErrorFilter /=
static_cast<double>(args.
m_nbSteps);
788 meanErrorNoise /=
static_cast<double>(args.
m_nbSteps);
789 averageFilteringTime = averageFilteringTime / (
static_cast<double>(args.
m_nbSteps) +
static_cast<double>(nbStepsWarmUp));
790 std::cout <<
"Mean error filter = " << meanErrorFilter <<
"m" << std::endl;
791 std::cout <<
"Mean error noise = " << meanErrorNoise <<
"m" << std::endl;
792 std::cout <<
"Mean filtering time = " << averageFilteringTime <<
"us" << std::endl;
795 std::cout <<
"Press Enter to quit..." << std::endl;
799 #ifdef VISP_HAVE_DISPLAY
806 const double maxError = 150.;
807 if (meanErrorFilter > maxError) {
808 std::cerr <<
"Error: max tolerated error = " << maxError <<
", mean error = " << meanErrorFilter << std::endl;
811 else if (meanErrorFilter >= meanErrorNoise) {
812 std::cerr <<
"Error: mean error without filter = " << meanErrorNoise <<
", mean error with filter = " << meanErrorFilter << std::endl;
821 std::cout <<
"This example is only available if you compile ViSP in C++11 standard or higher." << std::endl;
Class to simulate a flying aircraft.
vpColVector update(const double &dt)
Compute the new position of the aircraft after dt seconds have passed since the last update.
vpACSimulator(const vpColVector &X0, const vpColVector &vel, const double &vel_std)
Construct a new vpACSimulator object.
Implementation of column vector and the associated operations.
static const vpColor blue
static const vpColor black
Class for generating random number with normal probability density.
Provides simple mathematics computation tools that are not available in the C mathematics library (ma...
static double rad(double deg)
static double deg(double rad)
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....
std::function< vpColVector(const vpColVector &, const double &)> vpProcessFunction
Process model function, which projects a particle forward in time. The first argument is a particle,...
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 ...
std::function< double(const vpColVector &, const MeasurementsType &)> vpLikelihoodFunction
Likelihood function, which evaluates the likelihood of a particle with regard to the measurements....
This class enables real time drawing of 2D or 3D graphics. An instance of the class open a window whi...
void initGraph(unsigned int graphNum, unsigned int curveNbr)
void setUnitY(unsigned int graphNum, const std::string &unity)
void setLegend(unsigned int graphNum, unsigned int curveNum, const std::string &legend)
void plot(unsigned int graphNum, unsigned int curveNum, double x, double y)
void setUnitX(unsigned int graphNum, const std::string &unitx)
void setColor(unsigned int graphNum, unsigned int curveNum, vpColor color)
void setTitle(unsigned int graphNum, const std::string &title)
Class that permits to convert the position of the aircraft into range and elevation angle measurement...
vpRadarStation(const double &x, const double &y, const double &range_std, const double &elev_angle_std, const double &distMaxAllowed)
Construct a new vpRadarStation object.
double likelihood(const vpColVector &particle, const vpColVector &meas)
Compute the likelihood of a particle (value between 0. and 1.) knowing the measurements....
vpColVector measureWithNoise(const vpColVector &pos)
Noisy measurement of the range and elevation angle that correspond to pos.
vpColVector state_to_measurement(const vpColVector &particle)
Convert a particle of the Particle Filter into the measurement space.
vpColVector measureGT(const vpColVector &pos)
Perfect measurement of the range and elevation angle that correspond to pos.
VISP_EXPORT double measureTimeMicros()
bool m_useDisplay
If true, activate the plot and the renderer if VISP_HAVE_DISPLAY is defined.
int m_nbThreads
Number of thread to use in the Particle Filter.
unsigned int m_nbSteps
Number of steps for the main loop.
static const int SOFTWARE_CONTINUE
double m_stdevAircraftVelocity
double m_ampliMaxVx
Amplitude max of the noise for the state component corresponding to the velocity along the X-axis.
double m_ampliMaxY
Amplitude max of the noise for the state component corresponding to the Y coordinate.
unsigned int m_N
The number of particles.
double m_ampliMaxVy
Amplitude max of the noise for the state component corresponding to the velocity along the Y-axis.
double m_maxDistanceForLikelihood
The maximum allowed distance between a particle and the measurement, leading to a likelihood equal to...
int parseArgs(const int argc, const char *argv[])
unsigned int m_nbStepsWarmUp
Number of steps for the warmup phase.
double m_ampliMaxX
Amplitude max of the noise for the state component corresponding to the X coordinate.
long m_seedPF
Seed for the random generators of the PF.