Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 1 | #include "motors/math.h" |
| 2 | |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 3 | #include "gmock/gmock.h" |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame^] | 4 | #include "gtest/gtest.h" |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 5 | |
| 6 | namespace frc971 { |
Brian Silverman | a96c1a4 | 2018-05-12 12:11:31 -0700 | [diff] [blame] | 7 | namespace motors { |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 8 | namespace testing { |
| 9 | |
| 10 | class SinCosIntTest : public ::testing::Test { |
| 11 | public: |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame^] | 12 | void SetUp() override { MathInit(); } |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 13 | |
Brian Silverman | 9ccec6e | 2018-10-21 22:06:35 -0700 | [diff] [blame] | 14 | template <class Rotation, int kTableSize> |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 15 | void CheckSinCos() { |
| 16 | static constexpr float kTolerance = 0.004; |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame^] | 17 | SCOPED_TRACE("num=" + ::std::to_string(Rotation::num) + |
| 18 | " den=" + ::std::to_string(Rotation::den) + |
| 19 | " table_size=" + ::std::to_string(kTableSize)); |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 20 | for (uint32_t theta = 0; theta < Rotation::den; ++theta) { |
Brian Silverman | 9ccec6e | 2018-10-21 22:06:35 -0700 | [diff] [blame] | 21 | const float theta_float = ThetaToFloat<Rotation>(theta); |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame^] | 22 | SCOPED_TRACE("theta=" + ::std::to_string(theta) + |
| 23 | " theta_float=" + ::std::to_string(theta_float)); |
Brian Silverman | 9ccec6e | 2018-10-21 22:06:35 -0700 | [diff] [blame] | 24 | EXPECT_THAT((FastSinInt<Rotation, kTableSize>(theta)), |
| 25 | ::testing::FloatNear(sin(theta_float), kTolerance)); |
| 26 | EXPECT_THAT((FastCosInt<Rotation, kTableSize>(theta)), |
| 27 | ::testing::FloatNear(cos(theta_float), kTolerance)); |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 28 | } |
| 29 | } |
| 30 | |
| 31 | private: |
| 32 | template <class Rotation> |
| 33 | double ThetaToFloat(uint32_t theta) { |
| 34 | const double rotation_double = |
| 35 | static_cast<double>(Rotation::num) / static_cast<double>(Rotation::den); |
| 36 | return (static_cast<double>(theta) + 0.5) * rotation_double * 2.0 * M_PI; |
| 37 | } |
| 38 | }; |
| 39 | |
Brian Silverman | 9ccec6e | 2018-10-21 22:06:35 -0700 | [diff] [blame] | 40 | TEST_F(SinCosIntTest, Numerator1DefaultTable) { |
| 41 | CheckSinCos<::std::ratio<1, 2>, 2>(); |
| 42 | CheckSinCos<::std::ratio<1, 4>, 4>(); |
| 43 | CheckSinCos<::std::ratio<1, 8>, 8>(); |
| 44 | CheckSinCos<::std::ratio<1, 128>, 128>(); |
| 45 | CheckSinCos<::std::ratio<1, 1024>, 1024>(); |
| 46 | CheckSinCos<::std::ratio<1, 4096>, 4096>(); |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 47 | } |
| 48 | |
Brian Silverman | 9ccec6e | 2018-10-21 22:06:35 -0700 | [diff] [blame] | 49 | TEST_F(SinCosIntTest, Numerator1LargerTable) { |
| 50 | // Don't include silly things like a denominator of 2 and table size of 4 |
| 51 | // here. It will fail because the slope varies so much that linearly |
| 52 | // interpolating between 0.5pi/1.5pi vs 0.25pi/0.75pi/1.25pi/1.75pi gives very |
| 53 | // different results. |
| 54 | CheckSinCos<::std::ratio<1, 2>, 4096>(); |
| 55 | CheckSinCos<::std::ratio<1, 2>, 1024>(); |
| 56 | CheckSinCos<::std::ratio<1, 8>, 4096>(); |
| 57 | CheckSinCos<::std::ratio<1, 128>, 4096>(); |
| 58 | CheckSinCos<::std::ratio<1, 1024>, 2048>(); |
| 59 | } |
| 60 | |
| 61 | TEST_F(SinCosIntTest, Numerator5DefaultTable) { |
| 62 | CheckSinCos<::std::ratio<5, 8>, 8>(); |
| 63 | CheckSinCos<::std::ratio<5, 128>, 128>(); |
| 64 | CheckSinCos<::std::ratio<5, 1024>, 1024>(); |
| 65 | CheckSinCos<::std::ratio<5, 4096>, 4096>(); |
| 66 | } |
| 67 | |
| 68 | TEST_F(SinCosIntTest, Numerator5LargerTable) { |
| 69 | CheckSinCos<::std::ratio<5, 2>, 4096>(); |
| 70 | CheckSinCos<::std::ratio<5, 2>, 1024>(); |
| 71 | CheckSinCos<::std::ratio<5, 8>, 4096>(); |
| 72 | CheckSinCos<::std::ratio<5, 128>, 4096>(); |
| 73 | CheckSinCos<::std::ratio<5, 1024>, 2048>(); |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | class SinCosFloatTest : public ::testing::Test { |
| 77 | public: |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame^] | 78 | void SetUp() override { MathInit(); } |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 79 | |
| 80 | void CheckSinCos(float theta) { |
| 81 | ASSERT_GE(theta, -0.2f); |
| 82 | ASSERT_LE(theta, 0.2f); |
| 83 | |
| 84 | static constexpr float kTolerance = 0.002; |
| 85 | EXPECT_THAT(FastSinFloat(theta), |
| 86 | ::testing::FloatNear(sin(theta), kTolerance)); |
| 87 | EXPECT_THAT(FastCosFloat(theta), |
| 88 | ::testing::FloatNear(cos(theta), kTolerance)); |
| 89 | } |
| 90 | }; |
| 91 | |
| 92 | TEST_F(SinCosFloatTest, Endpoints) { |
| 93 | CheckSinCos(0); |
| 94 | CheckSinCos(-0.2); |
| 95 | CheckSinCos(0.2); |
| 96 | } |
| 97 | |
| 98 | } // namespace testing |
Brian Silverman | a96c1a4 | 2018-05-12 12:11:31 -0700 | [diff] [blame] | 99 | } // namespace motors |
Brian Silverman | 8d3816a | 2017-07-03 18:52:15 -0700 | [diff] [blame] | 100 | } // namespace frc971 |