commence breakage
[inav.git] / src / test / unit / maths_unittest.cc
blob77779d366e2d61d26bb7da8624c6800e2c4e0dbe
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdint.h>
19 #include <stdbool.h>
21 #include <limits.h>
23 #include <math.h>
25 #define USE_BARO
27 extern "C" {
28 #include "common/maths.h"
29 #include "common/vector.h"
32 #include "unittest_macros.h"
33 #include "gtest/gtest.h"
35 TEST(MathsUnittest, TestConstrain)
37 // Within bounds
38 EXPECT_EQ(constrain(0, 0, 0), 0);
39 EXPECT_EQ(constrain(1, 1, 1), 1);
40 EXPECT_EQ(constrain(1, 0, 2), 1);
42 // Equal to bottom bound.
43 EXPECT_EQ(constrain(1, 1, 2), 1);
44 // Equal to top bound.
45 EXPECT_EQ(constrain(1, 0, 1), 1);
47 // Equal to both bottom and top bound.
48 EXPECT_EQ(constrain(1, 1, 1), 1);
50 // Above top bound.
51 EXPECT_EQ(constrain(2, 0, 1), 1);
52 // Below bottom bound.
53 EXPECT_EQ(constrain(0, 1, 2), 1);
56 TEST(MathsUnittest, TestConstrainNegatives)
58 // Within bounds.
59 EXPECT_EQ(constrain(-1, -1, -1), -1);
60 EXPECT_EQ(constrain(-1, -2, 0), -1);
62 // Equal to bottom bound.
63 EXPECT_EQ(constrain(-1, -1, 0), -1);
64 // Equal to top bound.
65 EXPECT_EQ(constrain(-1, -2, -1), -1);
67 // Equal to both bottom and top bound.
68 EXPECT_EQ(constrain(-1, -1, -1), -1);
70 // Above top bound.
71 EXPECT_EQ(constrain(-1, -3, -2), -2);
72 // Below bottom bound.
73 EXPECT_EQ(constrain(-3, -2, -1), -2);
76 TEST(MathsUnittest, TestConstrainf)
78 // Within bounds.
79 EXPECT_FLOAT_EQ(constrainf(1.0f, 0.0f, 2.0f), 1.0f);
81 // Equal to bottom bound.
82 EXPECT_FLOAT_EQ(constrainf(1.0f, 1.0f, 2.0f), 1.0f);
83 // Equal to top bound.
84 EXPECT_FLOAT_EQ(constrainf(1.0f, 0.0f, 1.0f), 1.0f);
86 // Equal to both bottom and top bound.
87 EXPECT_FLOAT_EQ(constrainf(1.0f, 1.0f, 1.0f), 1.0f);
89 // Above top bound.
90 EXPECT_FLOAT_EQ(constrainf(2.0f, 0.0f, 1.0f), 1.0f);
91 // Below bottom bound.
92 EXPECT_FLOAT_EQ(constrainf(0, 1.0f, 2.0f), 1.0f);
94 // Above bouth bounds.
95 EXPECT_FLOAT_EQ(constrainf(2.0f, 0.0f, 1.0f), 1.0f);
96 // Below bouth bounds.
97 EXPECT_FLOAT_EQ(constrainf(0, 1.0f, 2.0f), 1.0f);
100 TEST(MathsUnittest, TestDegreesToRadians)
102 EXPECT_FLOAT_EQ(degreesToRadians(0), 0.0f);
103 EXPECT_FLOAT_EQ(degreesToRadians(90), 0.5f * M_PIf);
104 EXPECT_FLOAT_EQ(degreesToRadians(180), M_PIf);
105 EXPECT_FLOAT_EQ(degreesToRadians(-180), - M_PIf);
108 TEST(MathsUnittest, TestApplyDeadband)
110 EXPECT_EQ(applyDeadband(0, 0), 0);
111 EXPECT_EQ(applyDeadband(1, 0), 1);
112 EXPECT_EQ(applyDeadband(-1, 0), -1);
114 EXPECT_EQ(applyDeadband(0, 10), 0);
115 EXPECT_EQ(applyDeadband(1, 10), 0);
116 EXPECT_EQ(applyDeadband(10, 10), 0);
118 EXPECT_EQ(applyDeadband(11, 10), 1);
119 EXPECT_EQ(applyDeadband(-11, 10), -1);
122 void expectVectorsAreEqual(fpVector3_t *a, fpVector3_t *b)
124 EXPECT_FLOAT_EQ(a->x, b->x);
125 EXPECT_FLOAT_EQ(a->y, b->y);
126 EXPECT_FLOAT_EQ(a->z, b->z);
129 TEST(MathsUnittest, TestRotateVectorWithNoAngle)
131 fpVector3_t vector = { .x = 1.0f, .y = 0.0f, .z = 0.0f};
132 fp_angles_t euler_angles = {.raw={0.0f, 0.0f, 0.0f}};
134 fpMat3_t rmat;
135 rotationMatrixFromAngles(&rmat, &euler_angles);
136 rotationMatrixRotateVector(&vector, &vector, &rmat);
138 fpVector3_t expected_result = { .x = 1.0f, .y = 0.0f, .z = 0.0f};
139 expectVectorsAreEqual(&vector, &expected_result);
142 TEST(MathsUnittest, TestRotateVectorAroundAxis)
144 // Rotate a vector <1, 0, 0> around an each axis x y and z.
145 fpVector3_t vector = { .x = 1.0f, .y = 0.0f, .z = 0.0f};
146 fp_angles_t euler_angles = {.raw={90.0f, 0.0f, 0.0f}};
148 fpMat3_t rmat;
149 rotationMatrixFromAngles(&rmat, &euler_angles);
150 rotationMatrixRotateVector(&vector, &vector, &rmat);
152 fpVector3_t expected_result = { .x = 1.0f, .y = 0.0f, .z = 0.0f};
153 expectVectorsAreEqual(&vector, &expected_result);
156 #if defined(FAST_MATH) || defined(VERY_FAST_MATH)
157 TEST(MathsUnittest, TestFastTrigonometrySinCos)
159 EXPECT_NEAR(sin_approx(0.0f), 0.0f, 1e-6);
160 EXPECT_NEAR(sin_approx(M_PIf / 2), 1.0f, 1e-6);
161 EXPECT_NEAR(sin_approx(-M_PIf / 2), -1.0f, 1e-6);
162 EXPECT_NEAR(sin_approx(M_PIf), 0.0f, 1e-6);
163 EXPECT_NEAR(sin_approx(-M_PIf), 0.0f, 1e-6);
164 EXPECT_NEAR(sin_approx(3 * M_PIf / 2), -1.0f, 1e-6);
165 EXPECT_NEAR(sin_approx(-3 * M_PIf / 2), 1.0f, 1e-6);
166 EXPECT_NEAR(sin_approx(2 * M_PIf), 0.0f, 1e-6);
167 EXPECT_NEAR(sin_approx(-2 * M_PIf), 0.0f, 1e-6);
168 EXPECT_NEAR(sin_approx(3 * M_PIf / 4), 0.707106781f, 1e-6);
169 EXPECT_NEAR(sin_approx(-3 * M_PIf / 4), -0.707106781f, 1e-6);
170 EXPECT_NEAR(sin_approx(2 * M_PIf + 3 * M_PIf / 4), 0.707106781f, 1e-6);
171 EXPECT_NEAR(sin_approx(-2 * M_PIf - 3 * M_PIf / 4), -0.707106781f, 1e-6);
173 EXPECT_NEAR(cos_approx(0.0f), 1.0f, 1e-6);
174 EXPECT_NEAR(cos_approx(M_PIf / 2), 0.0f, 1e-6);
175 EXPECT_NEAR(cos_approx(-M_PIf / 2), 0.0f, 1e-6);
176 EXPECT_NEAR(cos_approx(M_PIf), -1.0f, 1e-6);
177 EXPECT_NEAR(cos_approx(-M_PIf), -1.0f, 1e-6);
178 EXPECT_NEAR(cos_approx(3 * M_PIf / 2), 0.0f, 1e-6);
179 EXPECT_NEAR(cos_approx(-3 * M_PIf / 2), 0.0f, 1e-6);
180 EXPECT_NEAR(cos_approx(2 * M_PIf), 1.0f, 1e-6);
181 EXPECT_NEAR(cos_approx(-2 * M_PIf), 1.0f, 1e-6);
182 EXPECT_NEAR(cos_approx(3 * M_PIf / 4), -0.707106781f, 1e-6);
183 EXPECT_NEAR(cos_approx(-3 * M_PIf / 4), -0.707106781f, 1e-6);
184 EXPECT_NEAR(cos_approx(2 * M_PIf + 3 * M_PIf / 4), -0.707106781f, 1e-6);
185 EXPECT_NEAR(cos_approx(-2 * M_PIf - 3 * M_PIf / 4), -0.707106781f, 1e-6);
188 TEST(MathsUnittest, TestFastTrigonometryATan2)
190 EXPECT_NEAR(atan2_approx(1, 1), M_PIf / 4, 1e-6);
191 EXPECT_NEAR(atan2_approx(-1, 1), -M_PIf / 4, 1e-6);
192 EXPECT_NEAR(atan2_approx(1, -1), 3 * M_PIf / 4, 1e-6);
193 EXPECT_NEAR(atan2_approx(-1, -1), -3 * M_PIf / 4, 1e-6);
194 EXPECT_NEAR(atan2_approx(0, 1), 0, 1e-6);
195 EXPECT_NEAR(atan2_approx(0, -1), M_PIf, 1e-6);
196 EXPECT_NEAR(atan2_approx(1, 0), M_PIf / 2, 1e-6);
197 EXPECT_NEAR(atan2_approx(-1, 0), -M_PIf / 2, 1e-6);
200 TEST(MathsUnittest, TestFastTrigonometryACos)
202 EXPECT_NEAR(acos_approx(0.0f), M_PIf / 2, 1e-4);
203 EXPECT_NEAR(acos_approx(1.0f), 0, 1e-4);
204 EXPECT_NEAR(acos_approx(-1.0f), M_PIf, 1e-4);
205 EXPECT_NEAR(acos_approx(0.707106781f), M_PIf / 4, 1e-4);
206 EXPECT_NEAR(acos_approx(-0.707106781f), 3 * M_PIf / 4, 1e-4);
210 TEST(MathsUnittest, TestSensorScaleUnitTest)
212 sensorCalibrationState_t calState;
213 float result[3];
215 int16_t samples[6][3] = {
216 { 2896, 2896, 0 },
217 { -2897, 2896, 0 },
218 { 0, 4096, 0 },
219 { 0, -4096, 0 },
220 { 0, 2895, -2897 },
221 { 0, 0, -4096 } };
223 // Given
224 sensorCalibrationResetState(&calState);
225 sensorCalibrationPushSampleForScaleCalculation(&calState, 0, samples[0], 4096 );
226 sensorCalibrationPushSampleForScaleCalculation(&calState, 0, samples[1], 4096 );
227 sensorCalibrationPushSampleForScaleCalculation(&calState, 1, samples[2], 4096 );
228 sensorCalibrationPushSampleForScaleCalculation(&calState, 1, samples[3], 4096 );
229 sensorCalibrationPushSampleForScaleCalculation(&calState, 2, samples[4], 4096 );
230 sensorCalibrationPushSampleForScaleCalculation(&calState, 2, samples[5], 4096 );
231 sensorCalibrationSolveForScale(&calState, result);
233 EXPECT_NEAR(result[0], 1, 1e-4);
234 EXPECT_NEAR(result[1], 1, 1e-4);
235 EXPECT_NEAR(result[2], 1, 1e-4);
238 #endif