Formula Student Autonomous Systems
The code for the main driverless system
Loading...
Searching...
No Matches
ekf_state_est_performance_test.cpp
Go to the documentation of this file.
1#include <time.h>
2
3#include <chrono>
4#include <ctime>
5#include <filesystem>
6#include <fstream>
7#include <memory>
8#include <random>
9#include <rclcpp/rclcpp.hpp>
10#include <string>
11
13#include "gtest/gtest.h"
14#include "kalman_filter/ekf.hpp"
15#include "rclcpp/rclcpp.hpp"
16
22class PerformanceTest : public ::testing::Test {
23public:
24 std::shared_ptr<ExtendedKalmanFilter>
26 std::shared_ptr<MotionUpdate> motion_update_test;
27 std::chrono::_V2::system_clock::time_point
30 std::chrono::_V2::system_clock::time_point
34 std::chrono::_V2::system_clock::time_point end_time;
37 std::chrono::microseconds prediction_step_duration;
39 std::chrono::microseconds correction_step_duration;
41 std::string workload;
43 Eigen::Matrix2f q_test;
44 Eigen::MatrixXf r_test;
45 std::shared_ptr<MotionModel> motion_model_;
47 std::shared_ptr<DataAssociationModel> data_association_model_;
50 std::shared_ptr<ObservationModel> observation_model_;
52 std::string file_name;
59 auto now = std::chrono::system_clock::now();
60 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
61 std::tm now_tm;
62 localtime_r(&now_time, &now_tm);
63
64 std::stringstream ss;
65 ss << std::put_time(&now_tm, "%Y-%m-%d-%H:%M");
66 return ss.str();
67 }
68
73 bool file_exists =
74 std::filesystem::exists("../../performance/exec_time/ekf_state_est/" + file_name);
75 std::ofstream file("../../performance/exec_time/ekf_state_est/" + file_name,
76 std::ios::app);
78 // Check if the file exists
79 if (!file_exists) {
80 // If the file doesn't exist, add header
81 file << "Number of Cones in the Map, Prediction Step Execution Time, "
82 "Number of Cones coming "
83 "from perception, Correction Step Execution Time (ms), Total "
84 "time (ms)\n";
85 }
86
87 // Convert the duration from microseconds to milliseconds
88 double prediction_step_duration_milliseconds =
89 static_cast<double>(
90 std::chrono::duration_cast<std::chrono::microseconds>(prediction_step_duration)
91 .count()) /
92 1000.0;
93
94 double correction_step_duration_milliseconds =
95 static_cast<double>(
96 std::chrono::duration_cast<std::chrono::microseconds>(correction_step_duration)
97 .count()) /
98 1000.0;
99
100 double milliseconds =
101 prediction_step_duration_milliseconds + correction_step_duration_milliseconds;
102
103 printf("The Test Duration Was: %f ms\n", milliseconds);
104
105 // Append performance data
106
107 file << prediction_step_input_size << "," << prediction_step_duration_milliseconds << ","
108 << correction_step_input_size << "," << correction_step_duration_milliseconds << ","
109 << milliseconds << std::endl;
110
111 file.close();
112 }
113
118 void fill_x(int size) {
119 ekf_test = std::make_shared<ExtendedKalmanFilter>(observation_model_, data_association_model_);
120 ekf_test->add_motion_model("wheel_speed_sensor", motion_model_);
121 std::ifstream file("../../src/ekf_state_est/test/data/map_test.txt");
122
123 if (!file.is_open()) {
124 return;
125 }
126
127 int i = 0;
128 double value1;
129 double value2;
130
131 ekf_test->_x_vector_ = Eigen::VectorXf::Zero(size * 2 + 6);
132 ekf_test->_p_matrix_ = Eigen::SparseMatrix<float>(size * 2 + 6, size * 2 + 6);
133 ekf_test->_p_matrix_.coeffRef(0, 0) = static_cast<float>(1.1);
134 ekf_test->_p_matrix_.coeffRef(1, 1) = static_cast<float>(1.1);
135 ekf_test->_p_matrix_.coeffRef(2, 2) = static_cast<float>(1.1);
136 ekf_test->_p_matrix_.coeffRef(3, 3) = static_cast<float>(1.1);
137 ekf_test->_p_matrix_.coeffRef(4, 4) = static_cast<float>(1.1);
138 ekf_test->_p_matrix_.coeffRef(5, 5) = static_cast<float>(1.1);
139
140 while ((file >> value1 >> value2) && i < (size * 2 + 6)) {
141 ekf_test->_x_vector_(i) = static_cast<float>(value1);
142 i++;
143 ekf_test->_x_vector_(i) = static_cast<float>(value2);
144 i++;
145 }
146
147 file.close();
148 }
149
150 void SetUp() override {
151 file_name = "ekf_state_est_" + get_current_date_time_as_string() + ".csv";
152 start_time = std::chrono::high_resolution_clock::now();
153 prediction_step_duration = std::chrono::microseconds(0);
154 correction_step_duration = std::chrono::microseconds(0);
155 motion_update_test = std::make_shared<MotionUpdate>();
156 motion_update_test->translational_velocity = 1.58113883;
157 motion_update_test->rotational_velocity = 6.0;
158 motion_update_test->steering_angle = 2.0;
159 motion_update_test->last_update = rclcpp::Clock().now();
160
161 q_test = Eigen::Matrix2f::Zero();
162 q_test(0, 0) = static_cast<float>(0.3);
163 q_test(1, 1) = static_cast<float>(0.3);
164 r_test = Eigen::MatrixXf::Zero(5, 5);
165 r_test(0, 0) = static_cast<float>(0.8);
166 r_test(1, 1) = static_cast<float>(0.8);
167 r_test(2, 2) = static_cast<float>(0.8);
168 r_test(3, 3) = static_cast<float>(0.8);
169 r_test(4, 4) = static_cast<float>(0.8);
170 motion_model_ = std::make_shared<NormalVelocityModel>(r_test);
171 data_association_model_ = std::make_shared<MaxLikelihood>(71.0);
172 observation_model_ = std::make_shared<ObservationModel>(q_test);
173 ekf_test = std::make_shared<ExtendedKalmanFilter>(observation_model_, data_association_model_);
174 ekf_test->add_motion_model("wheel_speed_sensor", motion_model_);
175 }
176
182 void run_execution(const std::vector<common_lib::structures::Cone>& cone_map) {
183 prediction_step_duration = std::chrono::microseconds::zero();
184 correction_step_duration = std::chrono::microseconds::zero();
185
186 for (int i = 0; i < 10; i++) {
187 auto ekf_for_predict = *ekf_test;
188 auto ekf_for_correction = *ekf_test;
189
190 start_time = std::chrono::high_resolution_clock::now();
191 ekf_for_predict.prediction_step(*motion_update_test, "wheel_speed_sensor");
192 prediction_step_time = std::chrono::high_resolution_clock::now();
193 ekf_for_correction.correction_step(cone_map);
194 end_time = std::chrono::high_resolution_clock::now();
195
197 std::chrono::duration_cast<std::chrono::microseconds>(prediction_step_time - start_time);
199 std::chrono::duration_cast<std::chrono::microseconds>(end_time - prediction_step_time);
200 }
201
204 }
205
213 std::vector<common_lib::structures::Cone> create_cone_map(int n_cones) {
214 std::vector<common_lib::structures::Cone> cone_map;
215
217
218 std::ifstream file("../../src/ekf_state_est/test/data/perception_output.csv");
219 std::string line;
220
221 if (!file.is_open()) {
222 return cone_map;
223 }
224
225 while (std::getline(file, line) && correction_step_input_size < n_cones) {
226 std::istringstream iss(line);
227 std::string color;
228 std::vector<std::string> tokens;
229 std::string token;
230
231 while (std::getline(iss, token, ',')) {
232 tokens.push_back(token);
233 }
234
235 common_lib::structures::Cone cone(std::stof(tokens[0]), std::stof(tokens[1]), tokens[2], 1.0);
236
237 cone_map.push_back(cone);
239 }
240
241 file.close();
242
243 return cone_map;
244 }
245};
246
251TEST_F(PerformanceTest, TEST_EKF_PERFORMANCE) {
252 std::vector<int> cones_detected_cases = {1, 2, 5, 10};
253 std::vector<int> map_size_cases = {10, 20, 50, 100, 200};
254 for (auto i : cones_detected_cases) {
255 std::vector<common_lib::structures::Cone> cone_map = create_cone_map(i);
256 for (auto j : map_size_cases) {
257 prediction_step_input_size = j;
258 fill_x(j);
259 run_execution(cone_map);
260 print_to_file();
261 }
262 }
263}
std::string workload
Description of the workload.
Eigen::MatrixXf r_test
Test Eigen Matrix for R.
std::shared_ptr< ExtendedKalmanFilter > ekf_test
shared pointer to ExtendedKalmanFilter object
std::shared_ptr< MotionModel > motion_model_
Pointer to the MotionModel object for testing.
std::shared_ptr< MotionUpdate > motion_update_test
shared pointer to MotionUpdate object
std::string get_current_date_time_as_string()
Get current date and time as a string.
std::string file_name
File Name for Output.
std::vector< common_lib::structures::Cone > create_cone_map(int n_cones)
Read and pares a file containing containing perception's output.
std::chrono::_V2::system_clock::time_point prediction_step_time
Prediction Step Execution Time for performance measurement.
void fill_x(int size)
Fills the state vector with values from a file.
Eigen::Matrix2f q_test
Test Eigen Matrix for Q.
std::chrono::microseconds correction_step_duration
Duration of correction step execution.
std::chrono::_V2::system_clock::time_point end_time
End time for performance measurement.
void print_to_file()
Writes performance data to a CSV file.
std::shared_ptr< DataAssociationModel > data_association_model_
std::chrono::_V2::system_clock::time_point start_time
Start time for performance measurement.
std::chrono::microseconds prediction_step_duration
Duration of prediction step execution.
void run_execution(const std::vector< common_lib::structures::Cone > &cone_map)
Runes the Execution 10 times and outputs the average execution time.
std::shared_ptr< ObservationModel > observation_model_
ObservationModel object for testing.
TEST_F(PerformanceTest, TEST_EKF_PERFORMANCE)
EKF Performance Test.