Bayes Filters Library
The best from particle and Kalman filtering: the Unscented Particle Filter

The following snippet code shows how to run an Unscented Particle Filter (UPF) using the implementation provided by the library.

1 /*
2  * Copyright (C) 2016-2019 Istituto Italiano di Tecnologia (IIT)
3  *
4  * This software may be modified and distributed under the terms of the
5  * BSD 3-Clause license. See the accompanying LICENSE file for details.
6  */
7 
17 #include <BayesFilters/SIS.h>
20 #include <BayesFilters/utils.h>
22 
23 #include <iostream>
24 #include <memory>
25 #include <string>
26 
27 #include <Eigen/Dense>
28 
29 using namespace bfl;
30 using namespace Eigen;
31 
32 
33 class UPFSimulation : public SIS
34 {
35 public:
36  UPFSimulation
37  (
38  std::size_t num_particle,
39  std::size_t state_size,
40  std::size_t simulation_steps,
41  /* Initial covariance of the Gaussian belief associated to each particle. */
42  Ref<MatrixXd> initial_covariance,
43  std::unique_ptr<ParticleSetInitialization> initialization,
44  std::unique_ptr<PFPrediction> prediction,
45  std::unique_ptr<PFCorrection> correction,
46  std::unique_ptr<Resampling> resampling
47  ) noexcept :
48  SIS(num_particle, state_size, std::move(initialization), std::move(prediction), std::move(correction), std::move(resampling)),
49  simulation_steps_(simulation_steps),
50  initial_covariance_(initial_covariance),
51  estimates_extraction_(state_size)
52  { }
53 
54 protected:
55  bool run_condition() override
56  {
57  if (step_number() < simulation_steps_)
58  return true;
59  else
60  return false;
61  }
62 
63  std::vector<std::string> log_file_names(const std::string& folder_path, const std::string& file_name_prefix) override
64  {
65  std::vector<std::string> sis_filenames = SIS::log_file_names(folder_path, file_name_prefix);
66 
67  /* Add file names for logging of the conditional expected value. */
68  sis_filenames.push_back(folder_path + "/" + file_name_prefix + "_mean");
69 
70  return sis_filenames;
71  }
72 
73  bool initialization_step() override
74  {
75  estimates_extraction_.setMethod(EstimatesExtraction::ExtractionMethod::mean);
76 
78  return false;
79 
80  /* Initialize initial mean and covariance for each particle. */
81  for (std::size_t i = 0; i < pred_particle_.components; i++)
82  {
83  /* Set mean equal to the particle position. */
84  pred_particle_.mean(i) = pred_particle_.state(i);
85 
86  /* Set the covariance obtained within the ctor. */
87  pred_particle_.covariance(i) = initial_covariance_;
88  }
89 
90  return true;
91  }
92 
93  void log() override
94  {
95  VectorXd mean;
96  std::tie(std::ignore, mean) = estimates_extraction_.extract(cor_particle_.state(), cor_particle_.weight());
97 
98  logger(pred_particle_.state().transpose(), pred_particle_.weight().transpose(),
99  cor_particle_.state().transpose(), cor_particle_.weight().transpose(),
100  mean.transpose());
101  }
102 
103 private:
104  std::size_t simulation_steps_;
105 
106  Eigen::MatrixXd initial_covariance_;
107 
108  EstimatesExtraction estimates_extraction_;
109 };
110 
111 
112 int main(int argc, char* argv[])
113 {
114  std::cout << "Running an unscented particle filter on a simulated target." << std::endl;
115 
116  const bool write_to_file = (argc > 1 ? std::string(argv[1]) == "ON" : false);
117  if (write_to_file)
118  std::cout << "Data is logged in the test folder with prefix testUPF." << std::endl;
119 
120 
121  /* A set of parameters needed to run an unscented particle filter in a simulated environment. */
122  double surv_x = 1000.0;
123  double surv_y = 1000.0;
124  std::size_t num_particle_x = 7;
125  std::size_t num_particle_y = 7;
126  std::size_t num_particle = num_particle_x * num_particle_y;
127  Vector4d initial_state(10.0f, 0.0f, 10.0f, 0.0f);
128  std::size_t simulation_time = 100;
129  std::size_t state_size = 4;
130 
131  /* Unscented transform parameters.*/
132  double alpha = 1.0;
133  double beta = 2.0;
134  double kappa = 0.0;
135 
136  /* Step 1 - Initialization */
137 
138  Matrix4d initial_covariance;
139  initial_covariance << pow(0.05, 2), 0, 0, 0,
140  0, pow(0.05, 2), 0, 0,
141  0, 0, pow(0.01, 2), 0,
142  0, 0, 0, pow(0.01, 2);
143 
144  /* Initialize particle initialization class. */
145  std::unique_ptr<ParticleSetInitialization> grid_initialization = utils::make_unique<InitSurveillanceAreaGrid>(surv_x, surv_y, num_particle_x, num_particle_y);
146 
147 
148  /* Step 2 - Prediction */
149 
150  /* Step 2.1 - Define the state model. */
151 
152  /* Initialize a white noise acceleration state model. */
153  double T = 1.0f;
154  double tilde_q = 10.0f;
155 
156  std::unique_ptr<AdditiveStateModel> wna = utils::make_unique<WhiteNoiseAcceleration>(WhiteNoiseAcceleration::Dim::TwoD, T, tilde_q);
157 
158  /* Step 2.2 - Define the prediction step */
159 
160  /* Initialize the kalman particle filter prediction step that wraps a Gaussian prediction step,
161  in this case an unscented kalman filter prediction step. */
162  std::unique_ptr<GaussianPrediction> upf_prediction = utils::make_unique<UKFPrediction>(std::move(wna), alpha, beta, kappa);
163  std::unique_ptr<PFPrediction> gpf_prediction = utils::make_unique<GPFPrediction>(std::move(upf_prediction));
164 
165 
166  /* Step 3 - Correction */
167 
168  /* Step 3.1 - Define where the measurement are originated from (simulated in this case). */
169 
170  /* Initialize simulated target model with a white noise acceleration. */
171  std::unique_ptr<StateModel> target_model = utils::make_unique<WhiteNoiseAcceleration>(WhiteNoiseAcceleration::Dim::TwoD, T, tilde_q);
172  std::unique_ptr<SimulatedStateModel> simulated_state_model = utils::make_unique<SimulatedStateModel>(std::move(target_model), initial_state, simulation_time);
173 
174  if (write_to_file)
175  simulated_state_model->enable_log("./", "testUPF");
176 
177  /* Initialize a measurement model (a linear sensor reading x and y coordinates). */
178  double sigma_x = 10.0;
179  double sigma_y = 10.0;
180  Eigen::MatrixXd R(2, 2);
181  R << std::pow(sigma_x, 2.0), 0.0,
182  0.0, std::pow(sigma_y, 2.0);
183 
184  std::unique_ptr<AdditiveMeasurementModel> simulated_linear_sensor = utils::make_unique<SimulatedLinearSensor>(std::move(simulated_state_model), SimulatedLinearSensor::LinearMatrixComponent{ 4, std::vector<std::size_t>{ 0, 2 } }, R);
185 
186  if (write_to_file)
187  simulated_linear_sensor->enable_log("./", "testUPF");
188 
189 
190  /* Step 3.2 - Define the likelihood model. */
191 
192  /* Initialize an exponential likelihood as measurement likelihood. */
193  std::unique_ptr<LikelihoodModel> exp_likelihood = utils::make_unique<GaussianLikelihood>();
194 
195  /* Step 3.3 - Define the correction step. */
196 
197  /* An additional state model is required to make the transitionProbability of the state model available
198  to the particle filter correction step. */
199  std::unique_ptr<StateModel> transition_probability_model = utils::make_unique<WhiteNoiseAcceleration>(WhiteNoiseAcceleration::Dim::TwoD, T, tilde_q);
200 
201  /* Initialize the particle filter correction step that wraps a Guassian correction step,
202  in this case an unscented kalman filter correction step. */
203  std::unique_ptr<GaussianCorrection> upf_correction = utils::make_unique<UKFCorrection>(std::move(simulated_linear_sensor), alpha, beta, kappa);
204  std::unique_ptr<PFCorrection> gpf_correction = utils::make_unique<GPFCorrection>(std::move(exp_likelihood), std::move(upf_correction), std::move(transition_probability_model));
205 
206 
207  /* Step 4 - Resampling */
208 
209  /* Initialize a resampling algorithm. */
210  std::unique_ptr<Resampling> resampling = utils::make_unique<Resampling>();
211 
212 
213  /* Step 5 - Assemble the particle filter. */
214  std::cout << "Constructing unscented particle filter..." << std::flush;
215 
216  UPFSimulation upf(num_particle, state_size, simulation_time, initial_covariance, std::move(grid_initialization), std::move(gpf_prediction), std::move(gpf_correction), std::move(resampling));
217 
218  if (write_to_file)
219  upf.enable_log("./", "testUPF");
220 
221  std::cout << "done!" << std::endl;
222 
223 
224  /* Step 6 - Prepare the filter to be run */
225  std::cout << "Booting unscented particle filter..." << std::flush;
226 
227  upf.boot();
228 
229  std::cout << "completed!" << std::endl;
230 
231 
232  /* Step 7 - Run the filter and wait until it is closed */
233  /* Note that since this is a simulation, the filter will end upon simulation termination */
234  std::cout << "Running unscented particle filter..." << std::flush;
235 
236  upf.run();
237 
238  std::cout << "waiting..." << std::flush;
239 
240  if (!upf.wait())
241  return EXIT_FAILURE;
242 
243  std::cout << "completed!" << std::endl;
244 
245  return EXIT_SUCCESS;
246 }
bfl::LinearModel::LinearMatrixComponent
std::pair< std::size_t, std::vector< std::size_t > > LinearMatrixComponent
Pair of data representing.
Definition: LinearModel.h:37
GaussianLikelihood.h
EstimatesExtraction.h
bfl::SIS
Definition: SIS.h:25
SimulatedLinearSensor.h
bfl
Port of boost::any for C++11 compilers.
Definition: AdditiveMeasurementModel.h:13
AdditiveStateModel.h
Resampling.h
bfl::WhiteNoiseAcceleration::Dim::TwoD
@ TwoD
bfl::SIS::initialization_step
bool initialization_step() override
Definition: SIS.cpp:52
bfl::SIS::log_file_names
std::vector< std::string > log_file_names(const std::string &folder_path, const std::string &file_name_prefix) override
Definition: SIS.cpp:93
InitSurveillanceAreaGrid.h
SIS.h
utils.h
bfl::EstimatesExtraction::ExtractionMethod::mean
@ mean
GPFPrediction.h
SimulatedStateModel.h
UKFCorrection.h
UKFPrediction.h
WhiteNoiseAcceleration.h
GPFCorrection.h
bfl::EstimatesExtraction
Definition: EstimatesExtraction.h:23