Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 72edc63

Browse files
takayuki5168HansRobo
authored andcommittedDec 16, 2022
fix(interpolation): query key is out of range due to double calculation error (autowarefoundation#2204)
* fix issue sligtly out of range due to double's calculation error Signed-off-by: Takayuki Murooka <[email protected]> * update test Signed-off-by: Takayuki Murooka <[email protected]> Signed-off-by: Takayuki Murooka <[email protected]> Signed-off-by: Kotaro Yoshimoto <[email protected]>
1 parent c468cc5 commit 72edc63

File tree

6 files changed

+44
-15
lines changed

6 files changed

+44
-15
lines changed
 

‎common/interpolation/include/interpolation/interpolation_utils.hpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef INTERPOLATION__INTERPOLATION_UTILS_HPP_
1616
#define INTERPOLATION__INTERPOLATION_UTILS_HPP_
1717

18+
#include <algorithm>
1819
#include <array>
1920
#include <stdexcept>
2021
#include <vector>
@@ -51,7 +52,7 @@ inline bool isNotDecreasing(const std::vector<double> & x)
5152
return true;
5253
}
5354

54-
inline void validateKeys(
55+
inline std::vector<double> validateKeys(
5556
const std::vector<double> & base_keys, const std::vector<double> & query_keys)
5657
{
5758
// when vectors are empty
@@ -71,9 +72,20 @@ inline void validateKeys(
7172
}
7273

7374
// when query_keys is out of base_keys (This function does not allow exterior division.)
74-
if (query_keys.front() < base_keys.front() || base_keys.back() < query_keys.back()) {
75+
constexpr double epsilon = 1e-3;
76+
if (
77+
query_keys.front() < base_keys.front() - epsilon ||
78+
base_keys.back() + epsilon < query_keys.back()) {
7579
throw std::invalid_argument("query_keys is out of base_keys");
7680
}
81+
82+
// NOTE: Due to calculation error of double, a query key may be slightly out of base keys.
83+
// Therefore, query keys are cropped here.
84+
auto validated_query_keys = query_keys;
85+
validated_query_keys.front() = std::max(validated_query_keys.front(), base_keys.front());
86+
validated_query_keys.back() = std::min(validated_query_keys.back(), base_keys.back());
87+
88+
return validated_query_keys;
7789
}
7890

7991
template <class T>

‎common/interpolation/include/interpolation/zero_order_hold.hpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ std::vector<T> zero_order_hold(
2727
const std::vector<double> & query_keys, const double overlap_threshold = 1e-3)
2828
{
2929
// throw exception for invalid arguments
30-
interpolation_utils::validateKeys(base_keys, query_keys);
30+
const auto validated_query_keys = interpolation_utils::validateKeys(base_keys, query_keys);
3131
interpolation_utils::validateKeysAndValues(base_keys, base_values);
3232

3333
std::vector<T> query_values;
3434
size_t closest_segment_idx = 0;
35-
for (size_t i = 0; i < query_keys.size(); ++i) {
35+
for (size_t i = 0; i < validated_query_keys.size(); ++i) {
3636
// Check if query_key is closes to the terminal point of the base keys
37-
if (base_keys.back() - overlap_threshold < query_keys.at(i)) {
37+
if (base_keys.back() - overlap_threshold < validated_query_keys.at(i)) {
3838
closest_segment_idx = base_keys.size() - 1;
3939
} else {
4040
for (size_t j = closest_segment_idx; j < base_keys.size() - 1; ++j) {
4141
if (
42-
base_keys.at(j) - overlap_threshold < query_keys.at(i) &&
43-
query_keys.at(i) < base_keys.at(j + 1)) {
42+
base_keys.at(j) - overlap_threshold < validated_query_keys.at(i) &&
43+
validated_query_keys.at(i) < base_keys.at(j + 1)) {
4444
// find closest segment in base keys
4545
closest_segment_idx = j;
4646
}

‎common/interpolation/src/linear_interpolation.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ std::vector<double> lerp(
2828
const std::vector<double> & query_keys)
2929
{
3030
// throw exception for invalid arguments
31-
interpolation_utils::validateKeys(base_keys, query_keys);
31+
const auto validated_query_keys = interpolation_utils::validateKeys(base_keys, query_keys);
3232
interpolation_utils::validateKeysAndValues(base_keys, base_values);
3333

3434
// calculate linear interpolation
3535
std::vector<double> query_values;
3636
size_t key_index = 0;
37-
for (const auto query_key : query_keys) {
37+
for (const auto query_key : validated_query_keys) {
3838
while (base_keys.at(key_index + 1) < query_key) {
3939
++key_index;
4040
}

‎common/interpolation/src/spherical_linear_interpolation.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ std::vector<geometry_msgs::msg::Quaternion> slerp(
3434
const std::vector<double> & query_keys)
3535
{
3636
// throw exception for invalid arguments
37-
interpolation_utils::validateKeys(base_keys, query_keys);
37+
const auto validated_query_keys = interpolation_utils::validateKeys(base_keys, query_keys);
3838
interpolation_utils::validateKeysAndValues(base_keys, base_values);
3939

4040
// calculate linear interpolation
4141
std::vector<geometry_msgs::msg::Quaternion> query_values;
4242
size_t key_index = 0;
43-
for (const auto query_key : query_keys) {
43+
for (const auto query_key : validated_query_keys) {
4444
while (base_keys.at(key_index + 1) < query_key) {
4545
++key_index;
4646
}

‎common/interpolation/src/spline_interpolation.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ std::vector<double> SplineInterpolation::getSplineInterpolatedValues(
222222
const std::vector<double> & query_keys) const
223223
{
224224
// throw exceptions for invalid arguments
225-
interpolation_utils::validateKeys(base_keys_, query_keys);
225+
const auto validated_query_keys = interpolation_utils::validateKeys(base_keys_, query_keys);
226226

227227
const auto & a = multi_spline_coef_.a;
228228
const auto & b = multi_spline_coef_.b;
@@ -231,7 +231,7 @@ std::vector<double> SplineInterpolation::getSplineInterpolatedValues(
231231

232232
std::vector<double> res;
233233
size_t j = 0;
234-
for (const auto & query_key : query_keys) {
234+
for (const auto & query_key : validated_query_keys) {
235235
while (base_keys_.at(j + 1) < query_key) {
236236
++j;
237237
}
@@ -247,15 +247,15 @@ std::vector<double> SplineInterpolation::getSplineInterpolatedDiffValues(
247247
const std::vector<double> & query_keys) const
248248
{
249249
// throw exceptions for invalid arguments
250-
interpolation_utils::validateKeys(base_keys_, query_keys);
250+
const auto validated_query_keys = interpolation_utils::validateKeys(base_keys_, query_keys);
251251

252252
const auto & a = multi_spline_coef_.a;
253253
const auto & b = multi_spline_coef_.b;
254254
const auto & c = multi_spline_coef_.c;
255255

256256
std::vector<double> res;
257257
size_t j = 0;
258-
for (const auto & query_key : query_keys) {
258+
for (const auto & query_key : validated_query_keys) {
259259
while (base_keys_.at(j + 1) < query_key) {
260260
++j;
261261
}

‎common/interpolation/test/src/test_interpolation_utils.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,23 @@ TEST(interpolation_utils, validateKeys)
9595

9696
const std::vector<double> back_out_query_keys{0.0, 1.0, 2.0, 4.0};
9797
EXPECT_THROW(validateKeys(base_keys, back_out_query_keys), std::invalid_argument);
98+
99+
{ // validated key check in normal case
100+
const std::vector<double> normal_query_keys{0.5, 1.5, 3.0};
101+
const auto validated_query_keys = validateKeys(base_keys, normal_query_keys);
102+
for (size_t i = 0; i < normal_query_keys.size(); ++i) {
103+
EXPECT_EQ(normal_query_keys.at(i), validated_query_keys.at(i));
104+
}
105+
}
106+
107+
{ // validated key check in case slightly out of range
108+
constexpr double slightly_out_of_range_epsilon = 1e-6;
109+
const std::vector<double> slightly_out_of_range__query_keys{
110+
0.0 - slightly_out_of_range_epsilon, 3.0 + slightly_out_of_range_epsilon};
111+
const auto validated_query_keys = validateKeys(base_keys, slightly_out_of_range__query_keys);
112+
EXPECT_NEAR(validated_query_keys.at(0), 0.0, 1e-10);
113+
EXPECT_NEAR(validated_query_keys.at(1), 3.0, 1e-10);
114+
}
98115
}
99116

100117
TEST(interpolation_utils, validateKeysAndValues)

0 commit comments

Comments
 (0)
Please sign in to comment.