23 #include <range/v3/action.hpp>
24 #include <range/v3/algorithm/any_of.hpp>
25 #include <range/v3/algorithm/min_element.hpp>
26 #include <range/v3/numeric/accumulate.hpp>
27 #include <range/v3/range/conversion.hpp>
28 #include <range/v3/view/generate.hpp>
29 #include <range/v3/view/take_exactly.hpp>
31 #include <yaml-cpp/yaml.h>
84 std::vector<double>
landmark_map{5, 12, 25, 37, 52, 55, 65, 74, 75, 87, 97};
93 using Particle = std::tuple<double, beluga::Weight>;
108 struct convert<
beluga::tutorial::Parameters> {
110 parameters.
map_size = node[
"map_size"].as<std::size_t>();
115 parameters.
dt = node[
"dt"].as<
double>();
116 parameters.
velocity = node[
"velocity"].as<
double>();
118 parameters.
sensor_range = node[
"sensor_range"].as<
double>();
121 parameters.
record_path = node[
"record_path"].as<std::string>();
122 parameters.
landmark_map = node[
"landmark_map"].as<std::vector<double>>();
128 struct convert<
std::vector<beluga::tutorial::Particle>> {
129 static Node
encode(
const std::vector<beluga::tutorial::Particle>& particles) {
138 struct convert<
std::vector<beluga::tutorial::RobotRecord>> {
139 static Node
encode(
const std::vector<beluga::tutorial::RobotRecord>& records) {
141 for (
auto&& [cycle, record] : ranges::views::enumerate(records)) {
142 node[cycle][
"ground_truth"] = record.ground_truth;
144 auto particles = node[cycle][
"particles"];
145 particles[
"current"] = record.current;
146 particles[
"prediction"] = record.prediction;
147 particles[
"update"] = record.update;
149 auto estimation = node[cycle][
"estimation"];
150 estimation[
"mean"] = std::get<0>(record.estimation);
151 estimation[
"sd"] = std::sqrt(std::get<1>(record.estimation));
157 void DumpFile(
const std::filesystem::path& path,
const Node& node) {
158 std::ofstream fout(path, std::ios::trunc);
166 int run(
const std::filesystem::path& path) {
169 std::normal_distribution<double> initial_position_distribution(
170 parameters.initial_position, parameters.initial_position_sigma);
172 ranges::views::transform(beluga::make_from_state<Particle>) |
173 ranges::views::take_exactly(parameters.number_of_particles) |
174 ranges::to<std::vector>;
176 std::vector<RobotRecord> records;
177 records.reserve(parameters.number_of_cycles);
179 double current_position{parameters.initial_position};
180 for (std::size_t n = 0; n < parameters.number_of_cycles; ++n) {
183 current_position += parameters.velocity * parameters.dt;
186 if (current_position >
static_cast<double>(parameters.map_size)) {
190 const auto motion_model = [&](
double position,
auto& random_engine) {
191 std::normal_distribution<double> motion_distribution(
192 parameters.velocity * parameters.dt, parameters.motion_model_sigma * parameters.dt);
193 return position + motion_distribution(random_engine);
196 const auto range_measurements =
197 parameters.landmark_map |
198 ranges::views::transform([&](
double landmark_position) {
return landmark_position - current_position; }) |
199 ranges::views::remove_if([&](
double range) {
return std::abs(range) > parameters.sensor_range; }) |
200 ranges::to<std::vector>;
202 const auto sensor_model = [&](
double position) {
204 parameters.landmark_map |
205 ranges::views::transform([&](
double landmark_position) {
return landmark_position - position; }) |
206 ranges::to<std::vector>;
208 return parameters.min_particle_weight +
209 std::transform_reduce(
210 range_measurements.begin(), range_measurements.end(), 1.0, std::multiplies<>{},
211 [&](
double range_measurement) {
212 const auto distances = range_map | ranges::views::transform([&](double range) {
213 return std::abs(range - range_measurement);
215 const auto min_distance = ranges::min(distances);
216 return std::exp((-1 * std::pow(min_distance, 2)) / (2 * parameters.sensor_model_sigma));
220 record.current = particles;
223 record.prediction = particles;
228 ranges::views::take_exactly(parameters.number_of_particles) |
230 record.update = particles;
233 record.estimation = estimation;
235 records.push_back(std::move(record));
239 output[
"landmark_map"] = parameters.landmark_map;
240 output[
"simulation_records"] = std::move(records);
248 int main(
int argc,
char* argv[]) {
250 std::cerr <<
"Usage: " << argv[0] <<
" <parameters_path>\n";