blob: fb72454c4e58203888aa585e10370d9b556198f9 [file] [log] [blame]
Brian Silverman8d3816a2017-07-03 18:52:15 -07001#include "motors/math.h"
2
Brian Silverman8d3816a2017-07-03 18:52:15 -07003#include "gmock/gmock.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07004#include "gtest/gtest.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07005
6namespace frc971 {
Brian Silvermana96c1a42018-05-12 12:11:31 -07007namespace motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -07008namespace testing {
9
10class SinCosIntTest : public ::testing::Test {
11 public:
Philipp Schrader790cb542023-07-05 21:06:52 -070012 void SetUp() override { MathInit(); }
Brian Silverman8d3816a2017-07-03 18:52:15 -070013
Brian Silverman9ccec6e2018-10-21 22:06:35 -070014 template <class Rotation, int kTableSize>
Brian Silverman8d3816a2017-07-03 18:52:15 -070015 void CheckSinCos() {
16 static constexpr float kTolerance = 0.004;
Philipp Schrader790cb542023-07-05 21:06:52 -070017 SCOPED_TRACE("num=" + ::std::to_string(Rotation::num) +
18 " den=" + ::std::to_string(Rotation::den) +
19 " table_size=" + ::std::to_string(kTableSize));
Brian Silverman8d3816a2017-07-03 18:52:15 -070020 for (uint32_t theta = 0; theta < Rotation::den; ++theta) {
Brian Silverman9ccec6e2018-10-21 22:06:35 -070021 const float theta_float = ThetaToFloat<Rotation>(theta);
Philipp Schrader790cb542023-07-05 21:06:52 -070022 SCOPED_TRACE("theta=" + ::std::to_string(theta) +
23 " theta_float=" + ::std::to_string(theta_float));
Brian Silverman9ccec6e2018-10-21 22:06:35 -070024 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 Silverman8d3816a2017-07-03 18:52:15 -070028 }
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 Silverman9ccec6e2018-10-21 22:06:35 -070040TEST_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 Silverman8d3816a2017-07-03 18:52:15 -070047}
48
Brian Silverman9ccec6e2018-10-21 22:06:35 -070049TEST_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
61TEST_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
68TEST_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 Silverman8d3816a2017-07-03 18:52:15 -070074}
75
76class SinCosFloatTest : public ::testing::Test {
77 public:
Philipp Schrader790cb542023-07-05 21:06:52 -070078 void SetUp() override { MathInit(); }
Brian Silverman8d3816a2017-07-03 18:52:15 -070079
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
92TEST_F(SinCosFloatTest, Endpoints) {
93 CheckSinCos(0);
94 CheckSinCos(-0.2);
95 CheckSinCos(0.2);
96}
97
98} // namespace testing
Brian Silvermana96c1a42018-05-12 12:11:31 -070099} // namespace motors
Brian Silverman8d3816a2017-07-03 18:52:15 -0700100} // namespace frc971