33 #include "gtest/gtest.h"
44 #define PSEUDOINV_CONVERGE_LIMIT 19
155 EXPECT_EQ(-range,
bound_sym(-range - 1.0
f, range));
157 EXPECT_EQ(-range,
bound_sym(-range, range));
161 EXPECT_EQ(range,
bound_sym(range, range));
163 EXPECT_EQ(range,
bound_sym(range + 1.0
f, range));
170 EXPECT_EQ(-range,
bound_sym(-range - 1.0
f, range));
172 EXPECT_EQ(-range,
bound_sym(-range, range));
176 EXPECT_EQ(range,
bound_sym(range, range));
178 EXPECT_EQ(range,
bound_sym(range + 1.0
f, range));
255 float eps = 0.000001f;
258 for (
int i=0;
i<3;
i++) {
262 float test_vec_null[2] = {0, 0};
263 float test_vec_within[2] = {limit/2, limit/2};
264 float test_vec_edge_numerically_stable[2] = {limit, 0};
265 float test_vec_edge_numerically_unstable[2] =
266 {(float) (sqrt(2)/2*limit), (
float) (sqrt(2)/2*limit)};
267 float test_vec_outside[2] = {limit, limit};
271 ASSERT_NEAR(test_vec_null[0], 0, eps);
272 ASSERT_NEAR(test_vec_null[1], 0, eps);
276 EXPECT_EQ(test_vec_within[0], limit/2);
277 EXPECT_EQ(test_vec_within[1], limit/2);
281 EXPECT_EQ(test_vec_edge_numerically_stable[0], limit);
282 EXPECT_EQ(test_vec_edge_numerically_stable[1], 0.0
f);
285 vector2_clip(test_vec_edge_numerically_unstable, limit);
286 ASSERT_NEAR(test_vec_edge_numerically_unstable[0], sqrt(2)/2*limit, eps);
287 ASSERT_NEAR(test_vec_edge_numerically_unstable[1], sqrt(2)/2*limit, eps);
291 ASSERT_NEAR(test_vec_outside[0], sqrt(2)/2*limit, eps);
292 ASSERT_NEAR(test_vec_outside[1], sqrt(2)/2*limit, eps);
307 float const range_min = 0.0f;
308 float const range_max = 1.0f;
309 uint8_t
const curve_numpts = 5;
310 float const curve[5] = { 0.0f, 0.25f, 0.5f, 0.75f, 1.0f };
311 float eps = 0.000001f;
314 for (
size_t i = 0;
i <= 20; ++
i) {
315 float const input =
i * 0.05f;
316 EXPECT_NEAR(input,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
320 for (
size_t i = 1;
i <= 10; ++
i) {
321 float const input = range_min -
i * 0.1f;
322 EXPECT_NEAR(range_min,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
326 for (
size_t i = 1;
i <= 10; ++
i) {
327 float const input = range_max +
i * 0.1f;
328 EXPECT_NEAR(range_max,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
333 float const range_min = -1.0f;
334 float const range_max = 1.0f;
335 uint8_t
const curve_numpts = 5;
336 float const curve[5] = { -1.0f, -0.5f, 0.0f, 0.5f, 1.0f };
337 float eps = 0.000001f;
340 for (
size_t i = 0;
i <= 20; ++
i) {
341 float const input =
i * 0.1f - 1.0f;
342 EXPECT_NEAR(input,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
346 for (
size_t i = 1;
i <= 10; ++
i) {
347 float const input = range_min -
i * 0.1f;
348 EXPECT_NEAR(range_min,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
352 for (
size_t i = 1;
i <= 10; ++
i) {
353 float const input = range_max +
i * 0.1f;
354 EXPECT_NEAR(range_max,
linear_interpolate(input, curve, curve_numpts, range_min, range_max), eps);
369 const float eps = 0.00001f;
370 const float bigeps = 0.001f;
371 const float hugeeps = 0.005f;
372 const float trivial[] = {
376 const float row_vector[] = {
380 const float col_vector[] = {
386 const float identity_3x3[] = {
392 const float simple_3x4[] = {
393 1.0f, 2.0f, 3.0f, 4.0f,
394 2.0f, 3.0f, 4.0f, 5.0f,
395 3.0f, 4.0f, 5.0f, 6.0f
398 const float pseudo_4x3[] = {
399 -0.75f , -0.1f , 0.55f,
400 -0.333333f, -0.033333f, 0.266667f,
401 0.083333f, 0.033333f, -0.016667f,
405 const float simple_4x4[] = {
406 1.0f, 1.0f, 1.0f, 1.0f,
407 -1.0f, -1.0f, 1.0f, 1.0f,
408 1.0f, -1.0f, -1.0f, 1.0f,
409 -1.0f, 1.0f, -1.0f, 1.0f,
412 const float degen_5x3[] = {
424 float matrb_4x4[4*4];
431 EXPECT_NEAR(4.0
f, single[0], eps);
435 for (
int i = 0;
i < 3;
i++) {
436 EXPECT_NEAR(row_vector[
i] * 2, vect3[i], eps);
441 for (
int i = 0;
i < 3;
i++) {
442 EXPECT_NEAR(col_vector[
i] * 2, vect3[i], eps);
447 EXPECT_NEAR(40, single[0], eps);
451 for (
int i = 0;
i < 9;
i++) {
452 EXPECT_NEAR(identity_3x3[
i], matr_3x3[i], eps);
457 for (
int i = 0;
i < 9;
i++) {
458 EXPECT_NEAR(simple_3x4[
i], matr_3x4[i], eps);
463 EXPECT_NEAR(-2, matr_3x4[0], eps);
464 for (
int i = 0;
i < 12;
i += 4) {
465 EXPECT_NEAR(-2, matr_3x4[
i], eps);
466 EXPECT_NEAR(0, matr_3x4[i+1], eps);
467 EXPECT_NEAR(-4, matr_3x4[i+2], eps);
470 EXPECT_NEAR(10, matr_3x4[3], eps);
471 EXPECT_NEAR(14, matr_3x4[7], eps);
472 EXPECT_NEAR(18, matr_3x4[11], eps);
476 EXPECT_NEAR(1.0
f / trivial[0], single[0], bigeps);
480 for (
int i = 0;
i < 9;
i++) {
481 EXPECT_NEAR(identity_3x3[
i], matr_3x3[i], bigeps);
487 for (
int i = 0;
i < 16;
i++) {
488 EXPECT_NEAR(0.25
f, fabsf(matr_4x4[
i]), bigeps);
493 for (
int i = 0;
i < 4;
i++) {
494 for (
int j = 0;
j < 4;
j++) {
496 EXPECT_NEAR(1, matrb_4x4[
i*4 +
j], bigeps);
498 EXPECT_NEAR(0, matrb_4x4[
i*4 +
j], bigeps);
505 for (
int i = 0;
i < 16;
i++) {
506 EXPECT_NEAR(matrb_4x4[
i], simple_4x4[i], bigeps);
511 for (
int i = 0;
i < 12;
i++) {
512 EXPECT_NEAR(matr_4x3[
i], pseudo_4x3[i], bigeps);
517 for (
int i = 0;
i < 12;
i++) {
518 EXPECT_NEAR(matr_3x4[
i], simple_3x4[i], hugeeps);
523 for (
int i = 0;
i < 12;
i++) {
524 EXPECT_NEAR(matr_4x3[
i], pseudo_4x3[i], bigeps);
530 for (
int i = 0;
i < 15;
i++) {
531 EXPECT_NEAR(matr_5x3[
i], degen_5x3[i], hugeeps);
536 const float eps = 0.0005f;
538 float quad_mixer[10 * 8] = {
539 0.5f, 0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
540 -0.5f, -0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
541 0.49f, -0.5f, -0.5f, 1.0f, 0, 0 ,0, 0,
543 0, 0, 0, 0, 1, 0, 0, 0,
544 0, 0, 0, 0, 1, 0, 0, 0,
545 0, 0, 0, 0, 0, 1, 1, 0,
546 0, 0, 0, 0, 0, -2, -2, 0,
547 -0.5f, 0.5f, -0.5f, 1.0f, 0, 0, 0, 0,
548 -0.5f, 0.5f, -0.5f, 1.0f, 0, 0, 0, 0,
551 float hexacoax_mixer[10 * 8] = {
552 1.0f, 0.25f, 0.742f, 1.0f, 0, 0, 0, 0,
553 1.0f, 0.25f, -0.75f, 1.0f, 0, 0, 0, 0,
554 -1.0f, 0.25f, 0.742f, 1.0f, 0, 0, 0, 0,
555 -1.0f, 0.25f, -0.75f, 1.0f, 0, 0, 0, 0,
556 0.0f, -0.492f, 0.742f, 1.0f, 0, 0, 0, 0,
557 0.0f, -0.492f, -0.75f, 1.0f, 0, 0, 0, 0,
559 0.0f, -0.492f, -0.75f, 1.0f, 0, 0, 0, 0,
561 0, 0, 0, 0, 0, 1, 1, 0,
562 0, 0, 0, 0, 0, -2, -2, 0,
565 float lotsquad_mixer[10 * 8] = {
566 0.5f, 0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
567 -0.5f, -0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
568 0.5f, -0.5f, -0.5f, 1.0f, 0, 0 ,0, 0,
569 -0.5f, 0.5f, -0.5f, 1.0f, 0, 0, 0, 0,
570 0.5f, 0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
571 -0.5f, -0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
572 0.5f, -0.5f, -0.5f, 1.0f, 0, 0 ,0, 0,
573 -0.5f, 0.5f, -0.5f, 1.0f, 0, 0, 0, 0,
574 0.5f, 0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
575 -0.5f, -0.5f, 0.5f, 1.0f, 0, 0, 0, 0,
578 float octo_mixer[10 * 8] = {
579 0.707f, 0.707f, 0.5f, 1.0f, 0, 0, 0, 0,
580 -0.707f, -0.707f, 0.5f, 1.0f, 0, 0, 0, 0,
581 0.707f, -0.707f, -0.5f, 1.0f, 0, 0 ,0, 0,
582 -0.707f, 0.707f, -0.5f, 1.0f, 0, 0, 0, 0,
583 1.0f, 0.0f, 0.5f, 1.0f, 0, 0, 0, 0,
584 -1.0f, 0.0f, -0.5f, 1.0f, 0, 0 ,0, 0,
585 0.0f, -1.0f, 0.5f, 1.0f, 0, 0, 0, 0,
586 0.0f, 1.0f, -0.5f, 1.0f, 0, 0, 0, 0,
587 0, 0, 0, 1, 0, 0, 0, 0,
588 0, 0, 0, 0, 0, -2, -2, 0,
591 float elevon_mixer[10 * 8] = {
592 0.5f, 0.5f, 0.0f, 0.0f, 0, 0, 0, 0,
593 -0.492f, 0.5f, 0.0f, 0.0f, 0, 0, 0, 0,
594 0.0f, 0.0f, 0.0f, 1.0f, 0, 0, 0, 0,
595 0.0f, 0.0f, 1.0f, 0.0f, 0, 0, 0, 0,
596 0.0f, 0.0f, 0.0f, 0.0f, 1, 1, 0, 0,
597 0.0f, 0.0f, 0.0f, 0.0f, -1, 1, 0, 0,
598 0.0f, 0.0f, 0.0f, 0.0f, 1, 1, 0, 0,
599 0.0f, 0.0f, 0.0f, 0.0f, -1, 1, 0, 0,
602 float inv_motor_mixer[8 * 10];
603 float temporary[10 * 10];
604 float should_be_motor_mixer[10 * 8];
612 for (
int i = 0;
i < 10*8;
i++) {
613 EXPECT_NEAR(quad_mixer[
i], should_be_motor_mixer[i], eps);
620 matrix_mul_check(temporary, hexacoax_mixer, should_be_motor_mixer, 10, 10, 8);
622 for (
int i = 0;
i< 10*8;
i++) {
623 EXPECT_NEAR(hexacoax_mixer[
i], should_be_motor_mixer[i], eps);
626 for (
int j = 0;
j < 500;
j++) {
629 EXPECT_TRUE(
matrix_pseudoinv(should_be_motor_mixer, inv_motor_mixer, 10, 8));
630 matrix_mul_check(should_be_motor_mixer, inv_motor_mixer, temporary, 10, 8, 10);
632 matrix_mul_check(temporary, hexacoax_mixer, should_be_motor_mixer, 10, 10, 8);
634 for (
int i = 0;
i < 10*8;
i++) {
635 EXPECT_NEAR(hexacoax_mixer[
i], should_be_motor_mixer[i], eps);
643 matrix_mul_check(temporary, lotsquad_mixer, should_be_motor_mixer, 10, 10, 8);
645 for (
int i = 0;
i < 10*8;
i++) {
646 EXPECT_NEAR(lotsquad_mixer[
i], should_be_motor_mixer[i], eps);
655 for (
int i = 0;
i < 10*8;
i++) {
656 EXPECT_NEAR(octo_mixer[
i], should_be_motor_mixer[i], eps);
663 matrix_mul_check(temporary, elevon_mixer, should_be_motor_mixer, 10, 10, 8);
665 for (
int i = 0;
i < 10*8;
i++) {
666 EXPECT_NEAR(elevon_mixer[
i], should_be_motor_mixer[i], eps);
670 for (
int j = 9;
j > 0;
j--) {
673 matrix_mul(lotsquad_mixer, inv_motor_mixer, temporary,
j, 8,
j);
675 matrix_mul(temporary, lotsquad_mixer, should_be_motor_mixer,
j,
j, 8);
677 for (
int i = 0;
i <
j*8;
i++) {
678 EXPECT_NEAR(lotsquad_mixer[
i], should_be_motor_mixer[i], eps);
682 for (
int j = 9;
j > 0;
j--) {
685 matrix_mul(hexacoax_mixer, inv_motor_mixer, temporary,
j, 8,
j);
687 matrix_mul(temporary, hexacoax_mixer, should_be_motor_mixer,
j,
j, 8);
689 for (
int i=0;
i <
j*8;
i++) {
690 EXPECT_NEAR(hexacoax_mixer[
i], should_be_motor_mixer[i], eps);
694 for (
int j = 9;
j > 0;
j--) {
697 matrix_mul(octo_mixer, inv_motor_mixer, temporary,
j, 8,
j);
699 matrix_mul(temporary, octo_mixer, should_be_motor_mixer,
j,
j, 8);
701 for (
int i = 0;
i <
j*8;
i++) {
702 EXPECT_NEAR(octo_mixer[
i], should_be_motor_mixer[i], eps);
706 for (
int j = 9;
j > 0;
j--) {
709 matrix_mul(elevon_mixer, inv_motor_mixer, temporary,
j, 8,
j);
711 matrix_mul(temporary, elevon_mixer, should_be_motor_mixer,
j,
j, 8);
713 for (
int i = 0;
i <
j*8;
i++) {
714 EXPECT_NEAR(elevon_mixer[
i], should_be_motor_mixer[i], eps);
721 for (
int j = 7;
j > 0;
j--) {
722 for (
int i = 0;
i < 10;
i++) {
723 memcpy(tempb +
i *
j, octo_mixer +
i * 8, j *
sizeof(
float));
728 matrix_mul(tempb, inv_motor_mixer, temporary, 10,
j, 10);
730 matrix_mul(temporary, tempb, should_be_motor_mixer, 10, 10,
j);
732 for (
int i = 0;
i <
j*10;
i++) {
733 EXPECT_NEAR(tempb[
i], should_be_motor_mixer[i], eps);
#define matrix_mul_check(a, b, out, arows, acolsbrows, bcols)
TEST_F(RneFromLLATest, Equator)
static bool matrix_pseudoinv(const float *a, float *out, int arows, int acols)
Finds a pseudo-inverse of a matrix.
float circular_modulus_deg(float err)
Circular modulus.
void vector2_clip(float *vels, float limit)
float bound_min_max(float val, float min, float max)
Bound input value between min and max.
float bound_sym(float val, float range)
Bound input value within range (plus or minus)
static void matrix_mul(const float *a, const float *b, float *out, int arows, int acolsbrows, int bcols)
Multiplies out = a b.
float linear_interpolate(float const input, float const *curve, uint8_t num_points, const float input_min, const float input_max)