PX4 Firmware
PX4 Autopilot Software http://px4.io
test_matrix.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (C) 2013-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file test_matrix.cpp
36  * Tests for the PX4 matrix math library.
37  */
38 
39 #include <unit_test.h>
40 
41 #include <matrix/math.hpp>
42 #include <matrix/filter.hpp>
43 #include <matrix/integration.hpp>
44 #include <matrix/Quaternion.hpp>
45 
46 using namespace matrix;
47 
48 class MatrixTest : public UnitTest
49 {
50 public:
51  virtual bool run_tests();
52 
53 private:
54  bool attitudeTests();
55  bool filterTests();
56  bool helperTests();
57  bool integrationTests();
58  bool inverseTests();
59  bool matrixAssignmentTests();
60  bool matrixMultTests();
61  bool matrixScalarMultTests();
62  bool setIdentityTests();
63  bool sliceTests();
64  bool squareMatrixTests();
65  bool transposeTests();
66  bool vectorTests();
67  bool vector2Tests();
68  bool vector3Tests();
69  bool vectorAssignmentTests();
70  bool dcmRenormTests();
71  bool pseudoInverseTests();
72 };
73 
75 {
76  ut_run_test(attitudeTests);
77  ut_run_test(filterTests);
78  ut_run_test(helperTests);
79  ut_run_test(integrationTests);
80  ut_run_test(inverseTests);
81  ut_run_test(matrixAssignmentTests);
82  ut_run_test(matrixMultTests);
83  ut_run_test(matrixScalarMultTests);
84  ut_run_test(setIdentityTests);
85  ut_run_test(sliceTests);
86  ut_run_test(squareMatrixTests);
87  ut_run_test(transposeTests);
88  ut_run_test(vectorTests);
89  ut_run_test(vector2Tests);
90  ut_run_test(vector3Tests);
91  ut_run_test(vectorAssignmentTests);
92  ut_run_test(dcmRenormTests);
93  ut_run_test(pseudoInverseTests);
94 
95  return (_tests_failed == 0);
96 }
97 
98 
100 
101 using std::fabs;
102 
104 {
105  float eps = 1e-6;
106 
107  // check data
108  Eulerf euler_check(0.1f, 0.2f, 0.3f);
109  Quatf q_check(0.98334744f, 0.0342708f, 0.10602051f, .14357218f);
110  float dcm_data[] = {
111  0.93629336f, -0.27509585f, 0.21835066f,
112  0.28962948f, 0.95642509f, -0.03695701f,
113  -0.19866933f, 0.0978434f, 0.97517033f
114  };
115  Dcmf dcm_check(dcm_data);
116 
117  // euler ctor
118  ut_test(isEqual(euler_check, Vector3f(0.1f, 0.2f, 0.3f)));
119 
120 
121  // euler default ctor
122  Eulerf e;
123  Eulerf e_zero = zeros<float, 3, 1>();
124  ut_test(isEqual(e, e_zero));
125  ut_test(isEqual(e, e));
126 
127  // euler vector ctor
129  v(0) = 0.1f;
130  v(1) = 0.2f;
131  v(2) = 0.3f;
132  Eulerf euler_copy(v);
133  ut_test(isEqual(euler_copy, euler_check));
134 
135  // quaternion ctor
136  Quatf q0(1, 2, 3, 4);
137  Quatf q(q0);
138  ut_test(fabs(q(0) - 1) < eps);
139  ut_test(fabs(q(1) - 2) < eps);
140  ut_test(fabs(q(2) - 3) < eps);
141  ut_test(fabs(q(3) - 4) < eps);
142 
143  // quat normalization
144  q.normalize();
145  ut_test(isEqual(q, Quatf(0.18257419f, 0.36514837f,
146  0.54772256f, 0.73029674f)));
147  ut_test(isEqual(q0.unit(), q));
148 
149  // quat default ctor
150  q = Quatf();
151  ut_test(isEqual(q, Quatf(1, 0, 0, 0)));
152 
153  // euler to quaternion
154  q = Quatf(euler_check);
155  ut_test(isEqual(q, q_check));
156 
157  // euler to dcm
158  Dcmf dcm(euler_check);
159  ut_test(isEqual(dcm, dcm_check));
160 
161  // quaternion to euler
162  Eulerf e1(q_check);
163  ut_test(isEqual(e1, euler_check));
164 
165  // quaternion to dcm
166  Dcmf dcm1(q_check);
167  ut_test(isEqual(dcm1, dcm_check));
168 
169  // dcm default ctor
170  Dcmf dcm2;
171  SquareMatrix<float, 3> I = eye<float, 3>();
172  ut_test(isEqual(dcm2, I));
173 
174  // dcm to euler
175  Eulerf e2(dcm_check);
176  ut_test(isEqual(e2, euler_check));
177 
178  // dcm to quaterion
179  Quatf q2(dcm_check);
180  ut_test(isEqual(q2, q_check));
181 
182  // constants
183  double deg2rad = M_PI / 180.0;
184  double rad2deg = 180.0 / M_PI;
185 
186  // euler dcm round trip check
187  for (int roll = -90; roll <= 90; roll += 90) {
188  for (int pitch = -90; pitch <= 90; pitch += 90) {
189  for (int yaw = -179; yaw <= 180; yaw += 90) {
190  // note if theta = pi/2, then roll is set to zero
191  int roll_expected = roll;
192  int yaw_expected = yaw;
193 
194  if (pitch == 90) {
195  roll_expected = 0;
196  yaw_expected = yaw - roll;
197 
198  } else if (pitch == -90) {
199  roll_expected = 0;
200  yaw_expected = yaw + roll;
201  }
202 
203  if (yaw_expected < -180) { yaw_expected += 360; }
204 
205  if (yaw_expected > 180) { yaw_expected -= 360; }
206 
207  //printf("roll:%d pitch:%d yaw:%d\n", roll, pitch, yaw);
208  Euler<double> euler_expected(
209  deg2rad * double(roll_expected),
210  deg2rad * double(pitch),
211  deg2rad * double(yaw_expected));
212  Euler<double> euler(
213  deg2rad * double(roll),
214  deg2rad * double(pitch),
215  deg2rad * double(yaw));
216  Dcm<double> dcm_from_euler(euler);
217  //dcm_from_euler.print();
218  Euler<double> euler_out(dcm_from_euler);
219  ut_test(isEqual(rad2deg * euler_expected, rad2deg * euler_out));
220 
221  Eulerf eulerf_expected(
222  float(deg2rad)*float(roll_expected),
223  float(deg2rad)*float(pitch),
224  float(deg2rad)*float(yaw_expected));
225  Eulerf eulerf(float(deg2rad)*float(roll),
226  float(deg2rad)*float(pitch),
227  float(deg2rad)*float(yaw));
228  Dcm<float> dcm_from_eulerf(eulerf);
229  Euler<float> euler_outf(dcm_from_eulerf);
230  ut_test(isEqual(float(rad2deg)*eulerf_expected,
231  float(rad2deg)*euler_outf));
232  }
233  }
234  }
235 
236  // quaterion copy ctors
237  float data_v4[] = {1, 2, 3, 4};
238  Vector<float, 4> v4(data_v4);
239  Quatf q_from_v(v4);
240  ut_test(isEqual(q_from_v, v4));
241 
242  Matrix<float, 4, 1> m4(data_v4);
243  Quatf q_from_m(m4);
244  ut_test(isEqual(q_from_m, m4));
245 
246  // quaternion derivative
247  Vector<float, 4> q_dot = q.derivative1(Vector3f(1, 2, 3));
248  (void)q_dot;
249 
250  // quaternion product
251  Quatf q_prod_check(0.93394439f, 0.0674002f, 0.20851f, 0.28236266f);
252  ut_test(isEqual(q_prod_check, q_check * q_check));
253  q_check *= q_check;
254  ut_test(isEqual(q_prod_check, q_check));
255 
256  // Quaternion scalar multiplication
257  float scalar = 0.5;
258  Quatf q_scalar_mul(1.0f, 2.0f, 3.0f, 4.0f);
259  Quatf q_scalar_mul_check(1.0f * scalar, 2.0f * scalar,
260  3.0f * scalar, 4.0f * scalar);
261  Quatf q_scalar_mul_res = scalar * q_scalar_mul;
262  ut_test(isEqual(q_scalar_mul_check, q_scalar_mul_res));
263  Quatf q_scalar_mul_res2 = q_scalar_mul * scalar;
264  ut_test(isEqual(q_scalar_mul_check, q_scalar_mul_res2));
265  Quatf q_scalar_mul_res3(q_scalar_mul);
266  q_scalar_mul_res3 *= scalar;
267  ut_test(isEqual(q_scalar_mul_check, q_scalar_mul_res3));
268 
269  // quaternion inverse
270  q = q_check.inversed();
271  ut_test(fabs(q_check(0) - q(0)) < eps);
272  ut_test(fabs(q_check(1) + q(1)) < eps);
273  ut_test(fabs(q_check(2) + q(2)) < eps);
274  ut_test(fabs(q_check(3) + q(3)) < eps);
275 
276  q = q_check;
277  q.invert();
278  ut_test(fabs(q_check(0) - q(0)) < eps);
279  ut_test(fabs(q_check(1) + q(1)) < eps);
280  ut_test(fabs(q_check(2) + q(2)) < eps);
281  ut_test(fabs(q_check(3) + q(3)) < eps);
282 
283  // rotate quaternion (nonzero rotation)
284  Quatf qI(1.0f, 0.0f, 0.0f, 0.0f);
285  Vector<float, 3> rot;
286  rot(0) = 1.0f;
287  rot(1) = rot(2) = 0.0f;
288  qI.rotate(rot);
289  Quatf q_true(cosf(1.0f / 2), sinf(1.0f / 2), 0.0f, 0.0f);
290  ut_test(fabs(qI(0) - q_true(0)) < eps);
291  ut_test(fabs(qI(1) - q_true(1)) < eps);
292  ut_test(fabs(qI(2) - q_true(2)) < eps);
293  ut_test(fabs(qI(3) - q_true(3)) < eps);
294 
295  // rotate quaternion (zero rotation)
296  qI = Quatf(1.0f, 0.0f, 0.0f, 0.0f);
297  rot(0) = 0.0f;
298  rot(1) = rot(2) = 0.0f;
299  qI.rotate(rot);
300  q_true = Quatf(cosf(0.0f), sinf(0.0f), 0.0f, 0.0f);
301  ut_test(fabs(qI(0) - q_true(0)) < eps);
302  ut_test(fabs(qI(1) - q_true(1)) < eps);
303  ut_test(fabs(qI(2) - q_true(2)) < eps);
304  ut_test(fabs(qI(3) - q_true(3)) < eps);
305 
306  // get rotation axis from quaternion (nonzero rotation)
307  q = Quatf(cosf(1.0f / 2), 0.0f, sinf(1.0f / 2), 0.0f);
308  rot = q.to_axis_angle();
309  ut_test(fabs(rot(0)) < eps);
310  ut_test(fabs(rot(1) - 1.0f) < eps);
311  ut_test(fabs(rot(2)) < eps);
312 
313  // get rotation axis from quaternion (zero rotation)
314  q = Quatf(1.0f, 0.0f, 0.0f, 0.0f);
315  rot = q.to_axis_angle();
316  ut_test(fabs(rot(0)) < eps);
317  ut_test(fabs(rot(1)) < eps);
318  ut_test(fabs(rot(2)) < eps);
319 
320  // from axis angle (zero rotation)
321  rot(0) = rot(1) = rot(2) = 0.0f;
322  q.from_axis_angle(rot, 0.0f);
323  q_true = Quatf(1.0f, 0.0f, 0.0f, 0.0f);
324  ut_test(fabs(q(0) - q_true(0)) < eps);
325  ut_test(fabs(q(1) - q_true(1)) < eps);
326  ut_test(fabs(q(2) - q_true(2)) < eps);
327  ut_test(fabs(q(3) - q_true(3)) < eps);
328 
329  return true;
330 }
331 
333 {
334  const size_t n_x = 6;
335  const size_t n_y = 5;
336  SquareMatrix<float, n_x> P = eye<float, n_x>();
337  SquareMatrix<float, n_y> R = eye<float, n_y>();
339  C.setIdentity();
340  float data[] = {1, 2, 3, 4, 5};
341  Vector<float, n_y> r(data);
342 
345  float beta = 0;
346  kalman_correct<float, 6, 5>(P, C, R, r, dx, dP, beta);
347 
348  float data_check[] = {0.5, 1, 1.5, 2, 2.5, 0};
349  Vector<float, n_x> dx_check(data_check);
350  ut_test(isEqual(dx, dx_check));
351 
352  return true;
353 }
354 
356 {
357  ut_test(::fabs(wrap_pi(4.0) - (4.0 - 2 * M_PI)) < 1e-5);
358  ut_test(::fabs(wrap_pi(-4.0) - (-4.0 + 2 * M_PI)) < 1e-5);
359  ut_test(::fabs(wrap_pi(3.0) - (3.0)) < 1e-3);
360  wrap_pi(NAN);
361 
362  Vector3f a(1, 2, 3);
363  Vector3f b(4, 5, 6);
364  ut_test(isEqual(a, a));
365 
366  return true;
367 }
368 
369 
370 Vector<float, 6> f(float t, const Matrix<float, 6, 1> &y, const Matrix<float, 3, 1> &u);
371 
373 {
374  float v = -sinf(t);
375  return v * ones<float, 6, 1>();
376 }
377 
379 {
380  Vector<float, 6> y = ones<float, 6, 1>();
381  Vector<float, 3> u = ones<float, 3, 1>();
382  float t0 = 0;
383  float tf = 2;
384  float h = 0.001f;
385  integrate_rk4(f, y, u, t0, tf, h, y);
386  float v = 1 + cosf(tf) - cosf(t0);
387  ut_test(isEqual(y, (ones<float, 6, 1>()*v)));
388 
389  return true;
390 }
391 
393 {
394  float data[9] = {0, 2, 3,
395  4, 5, 6,
396  7, 8, 10
397  };
398  float data_check[9] = {-0.4f, -0.8f, 0.6f,
399  -0.4f, 4.2f, -2.4f,
400  0.6f, -2.8f, 1.6f
401  };
402 
403  SquareMatrix<float, 3> A(data);
404  SquareMatrix<float, 3> A_I = inv(A);
405  SquareMatrix<float, 3> A_I_check(data_check);
406 
407  float eps = 1e-5;
408 
409  ut_test((A_I - A_I_check).abs().max() < eps);
410 
411  SquareMatrix<float, 3> zero_test = zeros<float, 3, 3>();
412  inv(zero_test);
413 
414  return true;
415 }
416 
418 {
419  Matrix3f m;
420  m.setZero();
421  m(0, 0) = 1;
422  m(0, 1) = 2;
423  m(0, 2) = 3;
424  m(1, 0) = 4;
425  m(1, 1) = 5;
426  m(1, 2) = 6;
427  m(2, 0) = 7;
428  m(2, 1) = 8;
429  m(2, 2) = 9;
430 
431  float data[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
432  Matrix3f m2(data);
433 
434  double eps = 1e-6f;
435 
436  for (size_t i = 0; i < 3; i++) {
437  for (size_t j = 0; j < 3; j++) {
438  ut_test(fabs(data[i * 3 + j] - m2(i, j)) < eps);
439  }
440  }
441 
442  float data_times_2[9] = {2, 4, 6, 8, 10, 12, 14, 16, 18};
443  Matrix3f m3(data_times_2);
444 
445  ut_test(isEqual(m, m2));
446  ut_test(!isEqual(m, m3));
447 
448  m2 *= 2;
449  ut_test(isEqual(m2, m3));
450 
451  m2 /= 2;
452  m2 -= 1;
453  float data_minus_1[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
454  ut_test(isEqual(Matrix3f(data_minus_1), m2));
455 
456  m2 += 1;
457  ut_test(isEqual(Matrix3f(data), m2));
458 
459  m3 -= m2;
460 
461  ut_test(isEqual(m3, m2));
462 
463  float data_row_02_swap[9] = {
464  7, 8, 9,
465  4, 5, 6,
466  1, 2, 3,
467  };
468 
469  float data_col_02_swap[9] = {
470  3, 2, 1,
471  6, 5, 4,
472  9, 8, 7
473  };
474 
475  Matrix3f m4(data);
476 
477  ut_test(isEqual(-m4, m4 * (-1)));
478 
479  m4.swapCols(0, 2);
480  ut_test(isEqual(m4, Matrix3f(data_col_02_swap)));
481  m4.swapCols(0, 2);
482  m4.swapRows(0, 2);
483  ut_test(isEqual(m4, Matrix3f(data_row_02_swap)));
484  ut_test(fabs(m4.min() - 1) < 1e-5);
485 
486  Scalar<float> s = 1;
487  ut_test(fabs(s - 1) < 1e-5);
488 
489  Matrix<float, 1, 1> m5 = s;
490  ut_test(fabs(m5(0, 0) - s) < 1e-5);
491 
493  m6.row(0) = Vector2f(1, 1);
494  m6.col(0) = Vector2f(1, 1);
495 
496  return true;
497 }
498 
500 {
501  float data[9] = {1, 0, 0, 0, 1, 0, 1, 0, 1};
502  Matrix3f A(data);
503  float data_check[9] = {1, 0, 0, 0, 1, 0, -1, 0, 1};
504  Matrix3f A_I(data_check);
505  Matrix3f I;
506  I.setIdentity();
507  Matrix3f R = A * A_I;
508  ut_test(isEqual(R, I));
509 
510  Matrix3f R2 = A;
511  R2 *= A_I;
512  ut_test(isEqual(R2, I));
513 
514 
515  Matrix3f A2 = eye<float, 3>() * 2;
516  Matrix3f B = A2.emult(A2);
517  Matrix3f B_check = eye<float, 3>() * 4;
518  ut_test(isEqual(B, B_check));
519 
520  return true;
521 }
522 
524 {
525  float data[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
526  Matrix3f A(data);
527  A = A * 2;
528  float data_check[9] = {2, 4, 6, 8, 10, 12, 14, 16, 18};
529  Matrix3f A_check(data_check);
530  ut_test(isEqual(A, A_check));
531 
532  return true;
533 }
534 
535 
536 template class matrix::Matrix<float, 3, 3>;
537 
539 {
540  Matrix3f A;
541  A.setIdentity();
542 
543  for (int i = 0; i < 3; i++) {
544  for (int j = 0; j < 3; j++) {
545  if (i == j) {
546  ut_test(fabs(A(i, j) - 1) < 1e-7);
547 
548  } else {
549  ut_test(fabs(A(i, j) - 0) < 1e-7);
550  }
551  }
552  }
553 
554  return true;
555 }
556 
558 {
559  float data[9] = {0, 2, 3,
560  4, 5, 6,
561  7, 8, 10
562  };
563  float data_check[6] = {
564  4, 5, 6,
565  7, 8, 10
566  };
567  SquareMatrix<float, 3> A(data);
568  Matrix<float, 2, 3> B_check(data_check);
569  Matrix<float, 2, 3> B(A.slice<2, 3>(1, 0));
570  ut_test(isEqual(B, B_check));
571 
572  float data_2[4] = {
573  11, 12,
574  13, 14
575  };
576 
577  Matrix<float, 2, 2> C(data_2);
578  A.slice<2, 2>(1, 1) = C;
579 
580  float data_2_check[9] = {
581  0, 2, 3,
582  4, 11, 12,
583  7, 13, 14
584  };
585  Matrix<float, 3, 3> D(data_2_check);
586  ut_test(isEqual(A, D));
587 
588  return true;
589 }
590 
591 
593 {
594  float data[9] = {1, 2, 3,
595  4, 5, 6,
596  7, 8, 10
597  };
598  SquareMatrix<float, 3> A(data);
599  Vector3<float> diag_check(1, 5, 10);
600 
601  ut_test(isEqual(A.diag(), diag_check));
602 
603  float data_check[9] = {
604  1.01158503f, 0.02190432f, 0.03238144f,
605  0.04349195f, 1.05428524f, 0.06539627f,
606  0.07576783f, 0.08708946f, 1.10894048f
607  };
608 
609  float dt = 0.01f;
611  SquareMatrix<float, 3> eA_check(data_check);
612 
613  float eps = 1e-3;
614  ut_test((eA - eA_check).abs().max() < eps);
615 
616  return true;
617 }
618 
620 {
621  float data[6] = {1, 2, 3, 4, 5, 6};
622  Matrix<float, 2, 3> A(data);
623  Matrix<float, 3, 2> A_T = A.transpose();
624  float data_check[6] = {1, 4, 2, 5, 3, 6};
625  Matrix<float, 3, 2> A_T_check(data_check);
626  ut_test(isEqual(A_T, A_T_check));
627 
628  return true;
629 }
630 
632 {
633  float data1[] = {1, 2, 3, 4, 5};
634  float data2[] = {6, 7, 8, 9, 10};
635  Vector<float, 5> v1(data1);
636  ut_test(fabs(v1.norm() - 7.416198487095663f) < 1e-5);
637  Vector<float, 5> v2(data2);
638  ut_test(fabs(v1.dot(v2) - 130.0f) < 1e-5);
639  v2.normalize();
640  Vector<float, 5> v3(v2);
641  ut_test(isEqual(v2, v3));
642  float data1_sq[] = {1, 4, 9, 16, 25};
643  Vector<float, 5> v4(data1_sq);
644  ut_test(isEqual(v1, v4.sqrt()));
645 
646  return true;
647 }
648 
650 {
651  Vector2f a(1, 0);
652  Vector2f b(0, 1);
653  ut_test(fabs(a % b - 1.0f) < 1e-5);
654 
655  Vector2f c;
656  ut_test(fabs(c(0) - 0) < 1e-5);
657  ut_test(fabs(c(1) - 0) < 1e-5);
658 
659  static Matrix<float, 2, 1> d(a);
660  // the static keywork is a workaround for an internal bug of GCC
661  // "internal compiler error: in trunc_int_for_mode, at explow.c:55"
662  ut_test(fabs(d(0, 0) - 1) < 1e-5);
663  ut_test(fabs(d(1, 0) - 0) < 1e-5);
664 
665  Vector2f e(d);
666  ut_test(fabs(e(0) - 1) < 1e-5);
667  ut_test(fabs(e(1) - 0) < 1e-5);
668 
669  float data[] = {4, 5};
670  Vector2f f(data);
671  ut_test(fabs(f(0) - 4) < 1e-5);
672  ut_test(fabs(f(1) - 5) < 1e-5);
673  return true;
674 }
675 
677 {
678  Vector3f a(1, 0, 0);
679  Vector3f b(0, 1, 0);
680  Vector3f c = a.cross(b);
681  ut_test(isEqual(c, Vector3f(0, 0, 1)));
682  c = a % b;
683  ut_test(isEqual(c, Vector3f(0, 0, 1)));
684  Matrix<float, 3, 1> d(c);
685  Vector3f e(d);
686  ut_test(isEqual(e, d));
687  float data[] = {4, 5, 6};
688  Vector3f f(data);
689  ut_test(isEqual(f, Vector3f(4, 5, 6)));
690  return true;
691 }
692 
694 {
695  Vector3f v;
696  v(0) = 1;
697  v(1) = 2;
698  v(2) = 3;
699 
700  static const float eps = 1e-7f;
701 
702  ut_test(fabsf(v(0) - 1) < eps);
703  ut_test(fabsf(v(1) - 2) < eps);
704  ut_test(fabsf(v(2) - 3) < eps);
705 
706  Vector3f v2(4, 5, 6);
707 
708  ut_test(fabsf(v2(0) - 4) < eps);
709  ut_test(fabsf(v2(1) - 5) < eps);
710  ut_test(fabsf(v2(2) - 6) < eps);
711 
712  SquareMatrix<float, 3> m = diag(Vector3f(1, 2, 3));
713  ut_test(fabsf(m(0, 0) - 1) < eps);
714  ut_test(fabsf(m(1, 1) - 2) < eps);
715  ut_test(fabsf(m(2, 2) - 3) < eps);
716 
717  return true;
718 }
719 
721 {
722  bool verbose = true;
723 
724  Dcm<float> A = eye<float, 3>();
725  Euler<float> euler(0.1f, 0.2f, 0.3f);
726  Dcm<float> R(euler);
727 
728  // demonstrate need for renormalization
729  for (int i = 0; i < 1000; i++) {
730  A = R * A;
731  }
732 
733  float err = 0.0f;
734 
735  if (verbose) {
736  for (int row = 0; row < 3; row++) {
737  Vector3f rvec(Matrix<float, 1, 3>(A.row(row)).transpose());
738  err += fabsf(1.0f - rvec.length());
739  }
740 
741  printf("error: %e\n", (double)err);
742  }
743 
744  A.renormalize();
745 
746  err = 0.0f;
747 
748  for (int row = 0; row < 3; row++) {
749  Vector3f rvec(Matrix<float, 1, 3>(A.row(row)).transpose());
750  err += fabsf(1.0f - rvec.length());
751  }
752 
753  if (verbose) {
754  printf("renorm error: %e\n", (double)err);
755  }
756 
757  static const float eps = 1e-6f;
758  ut_test(err < eps);
759 
760  return true;
761 }
762 
764 {
765  // 3x4 Matrix test
766  float data0[12] = {
767  0.f, 1.f, 2.f, 3.f,
768  4.f, 5.f, 6.f, 7.f,
769  8.f, 9.f, 10.f, 11.f
770  };
771 
772  float data0_check[12] = {
773  -0.3375f, -0.1f, 0.1375f,
774  -0.13333333f, -0.03333333f, 0.06666667f,
775  0.07083333f, 0.03333333f, -0.00416667f,
776  0.275f, 0.1f, -0.075f
777  };
778 
779  Matrix<float, 3, 4> A0(data0);
780  Matrix<float, 4, 3> A0_I = geninv(A0);
781  Matrix<float, 4, 3> A0_I_check(data0_check);
782 
783  ut_test((A0_I - A0_I_check).abs().max() < 1e-5);
784 
785  // 4x3 Matrix test
786  float data1[12] = {
787  0.f, 4.f, 8.f,
788  1.f, 5.f, 9.f,
789  2.f, 6.f, 10.f,
790  3.f, 7.f, 11.f
791  };
792 
793  float data1_check[12] = {
794  -0.3375f, -0.13333333f, 0.07083333f, 0.275f,
795  -0.1f, -0.03333333f, 0.03333333f, 0.1f,
796  0.1375f, 0.06666667f, -0.00416667f, -0.075f
797  };
798 
799  Matrix<float, 4, 3> A1(data1);
800  Matrix<float, 3, 4> A1_I = geninv(A1);
801  Matrix<float, 3, 4> A1_I_check(data1_check);
802 
803  ut_test((A1_I - A1_I_check).abs().max() < 1e-5);
804 
805  // Square matrix test
806  float data2[9] = {
807  0, 2, 3,
808  4, 5, 6,
809  7, 8, 10
810  };
811  float data2_check[9] = {
812  -0.4f, -0.8f, 0.6f,
813  -0.4f, 4.2f, -2.4f,
814  0.6f, -2.8f, 1.6f
815  };
816 
817  SquareMatrix<float, 3> A2(data2);
818  SquareMatrix<float, 3> A2_I = inv(A2);
819  SquareMatrix<float, 3> A2_I_check(data2_check);
820  ut_test((A2_I - A2_I_check).abs().max() < 1e-5);
821 
822  // Mock-up effectiveness matrix
823  const float B_quad_w[6][16] = {
824  {-0.5717536f, 0.43756646f, 0.5717536f, -0.43756646f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
825  { 0.35355328f, -0.35355328f, 0.35355328f, -0.35355328f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
826  { 0.28323701f, 0.28323701f, -0.28323701f, -0.28323701f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
827  { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
828  { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
829  {-0.25f, -0.25f, -0.25f, -0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
830  };
831  Matrix<float, 6, 16> B(B_quad_w);
832  const float A_quad_w[16][6] = {
833  { -0.495383f, 0.707107f, 0.765306f, 0.0f, 0.0f, -1.000000f },
834  { 0.495383f, -0.707107f, 1.000000f, 0.0f, 0.0f, -1.000000f },
835  { 0.495383f, 0.707107f, -0.765306f, 0.0f, 0.0f, -1.000000f },
836  { -0.495383f, -0.707107f, -1.000000f, 0.0f, 0.0f, -1.000000f },
837  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
838  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
839  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
840  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
841  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
842  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
843  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
844  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
845  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
846  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
847  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
848  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}
849  };
850  Matrix<float, 16, 6> A_check(A_quad_w);
852  ut_test((A - A_check).abs().max() < 1e-5);
853 
854  return true;
855 
856 }
Vector3 cross(const Matrix31 &b) const
Definition: Vector3.hpp:59
bool vector2Tests()
#define ut_declare_test_c(test_function, test_class)
Definition: unit_test.h:40
bool vector3Tests()
bool integrationTests()
SquareMatrix< float, 3 > Matrix3f
void invert()
Invert quaternion in place.
Definition: Quaternion.hpp:333
bool filterTests()
void normalize()
Definition: Vector.hpp:87
bool sliceTests()
Base class to be used for unit tests.
Definition: unit_test.h:54
bool vectorTests()
Quaternion class.
Definition: Dcm.hpp:24
bool attitudeTests()
Matrix< Type, N, M > transpose() const
Definition: Matrix.hpp:353
bool squareMatrixTests()
bool helperTests()
bool pseudoInverseTests()
bool setIdentityTests()
int test_matrix(int argc, char *argv[])
#define ut_test(test)
Used to assert a value within a unit test.
Definition: unit_test.h:124
bool matrixScalarMultTests()
void swapRows(size_t a, size_t b)
Definition: Matrix.hpp:462
int integrate_rk4(Vector< Type, M >(*f)(Type, const Matrix< Type, M, 1 > &x, const Matrix< Type, N, 1 > &u), const Matrix< Type, M, 1 > &y0, const Matrix< Type, N, 1 > &u, Type t0, Type tf, Type h0, Matrix< Type, M, 1 > &y1)
Definition: integration.hpp:8
const Slice< Type, M, 1, M, N > col(size_t j) const
Definition: Matrix.hpp:395
Vector< Type, 3 > to_axis_angle() const
Rotation vector from quaternion XXX DEPRECATED, use AxisAngle class.
Definition: Quaternion.hpp:481
void rotate(const AxisAngle< Type > &vec)
Rotate quaternion from rotation vector.
Definition: Quaternion.hpp:383
void setIdentity()
Definition: Matrix.hpp:447
const Slice< Type, P, Q, M, N > slice(size_t x0, size_t y0) const
Definition: Matrix.hpp:374
void from_axis_angle(Vector< Type, 3 > vec)
Rotation quaternion from vector.
Definition: Quaternion.hpp:431
void renormalize()
Definition: Dcm.hpp:175
Matrix41 derivative1(const Matrix31 &w) const
Computes the derivative of q_21 when rotated with angular velocity expressed in frame 1 v_2 = q_21 * ...
Definition: Quaternion.hpp:308
bool isEqual(const Matrix< Type, M, N > &x, const Matrix< Type, M, N > &y, const Type eps=1e-4f)
Definition: Matrix.hpp:571
Type dot(const MatrixM1 &b) const
Definition: Vector.hpp:55
uint8_t * data
Definition: dataman.cpp:149
Vector unit() const
Definition: Vector.hpp:91
Vector2< float > Vector2f
Definition: Vector2.hpp:69
bool inv(const SquareMatrix< Type, M > &A, SquareMatrix< Type, M > &inv)
inverse based on LU factorization with partial pivotting
Type length() const
Definition: Vector.hpp:83
Euler angles class.
Definition: AxisAngle.hpp:18
Vector< Type, M > diag() const
A0[0][0]
Definition: calcH_YAW312.c:14
#define err(eval,...)
Definition: err.h:83
Type wrap_pi(Type x)
Wrap value in range [-π, π)
SquareMatrix< Type, M > diag(Vector< Type, M > d)
bool transposeTests()
Vector3< float > Vector3f
Definition: Vector3.hpp:136
Quaternion inversed() const
Invert quaternion.
Definition: Quaternion.hpp:343
Type min() const
Definition: Matrix.hpp:517
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
float dt
Definition: px4io.c:73
#define M_PI
Definition: gps_helper.cpp:38
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &y, const Matrix< float, 3, 1 > &u)
const Slice< Type, 1, N, M, N > row(size_t i) const
Definition: Matrix.hpp:385
bool matrixAssignmentTests()
Dual< Scalar, N > max(const Dual< Scalar, N > &a, const Dual< Scalar, N > &b)
Definition: Dual.hpp:224
bool matrixMultTests()
bool vectorAssignmentTests()
#define ut_run_test(test)
Runs a single unit test.
Definition: unit_test.h:96
bool dcmRenormTests()
virtual bool run_tests()
Override to run your unit tests.
Definition: test_matrix.cpp:74
SquareMatrix< Type, M > expm(const Matrix< Type, M, M > &A, size_t order=5)
Type norm() const
Definition: Vector.hpp:73
P[0][0]
Definition: quatCovMat.c:44
void setZero()
Definition: Matrix.hpp:416
Dual< Scalar, N > abs(const Dual< Scalar, N > &a)
Definition: Dual.hpp:196
All rotations and axis systems follow the right-hand rule.
Vector sqrt() const
Definition: Vector.hpp:111
void swapCols(size_t a, size_t b)
Definition: Matrix.hpp:477
Matrix< Type, M, N > emult(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:157
Matrix< Type, N, M > geninv(const Matrix< Type, M, N > &G)
Geninv Fast pseudoinverse based on full rank cholesky factorisation.
bool inverseTests()