diff src/Tests/compass_test.cpp @ 282:7d9edd3b8c86

Make a more compact COMPASS calibration code (<7KB), and add more tests.
author jDG
date Fri, 22 May 2015 14:50:40 +0200
parents
children cd2320cd6f9a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Tests/compass_test.cpp	Fri May 22 14:50:40 2015 +0200
@@ -0,0 +1,132 @@
+//////////////////////////////////////////////////////////////////////////////
+/// compass_test.cpp
+/// Unit test for compass calibration.
+/// Copyright (c) 2012-2015, JD Gascuel, HeinrichsWeikamp, all right reserved.
+//////////////////////////////////////////////////////////////////////////////
+//  HISTORY
+// 2015-05-23 jDG: Rewrite compass testing, to allow reducing code size.
+
+extern "C" {
+#   include "compass.h"
+}
+
+#include <gtest/gtest.h>
+
+#include <math.h>
+#include <iostream>
+
+//////////////////////////////////////////////////////////////////////////////
+
+inline float uniform() {
+    return (rand() & 0xFFFF) / 65536.0f;
+}
+inline float sqr(float x) {
+    return x*x;
+}
+
+static float radius = 0.21f;
+static float cx = 0, cy = 0, cz = 0;
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void check_calib()
+{
+    compass_reset_calibration();
+
+    //---- Generates random points on a sphere -------------------------------
+    // of radius,center (cx, cy, cz):
+    for(int i=0; i<100; ++i)
+    {
+        float theta = uniform()*360.0f;
+        float phi   = uniform()*180.0f - 90.0f;
+
+        float x = cx + radius * cosf(phi)*cosf(theta);
+        float y = cy + radius * cosf(phi)*sinf(theta);
+        float z = cz + radius * sinf(phi);
+
+        compass_DX_f = short(32768 * x);
+        compass_DY_f = short(32768 * y);
+        compass_DZ_f = short(32768 * z);
+        compass_add_calibration();
+    }
+
+    compass_solve_calibration();
+    float r2 = sqr(compass_CX_f/32768.0f - cx)
+             + sqr(compass_CY_f/32768.0f - cy)
+             + sqr(compass_CZ_f/32768.0f - cz);
+
+    // Calibration error less than 2 bits:
+    EXPECT_NEAR(0, sqrtf(r2), 3.0f/32768.0f)
+        << "Center at (" << compass_CX_f/32768.0f << ", "
+                         << compass_CY_f/32768.0f << ", "
+                         << compass_CZ_f/32768.0f << ")."
+        << " Error = " << sqrtf(r2);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST(compass, calibration_centered)
+{
+    compass_CX_f = compass_CY_f = compass_CZ_f = 0;
+
+    // Half-unit, centered, sphere:
+    radius = 0.5f;
+
+    // Try 10 recalibration passes:
+    for(int p=0; p<10; ++p)
+        check_calib();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST(compass, calibration_near_centered)
+{
+    // Put magnetic center elsewhere, but keep position+radius < 1.0, to
+    // avoid Q15 overflow...
+    radius = 0.21f;
+    cx = 0.019f, cy = -0.026f, cz = 0.004f;
+
+    // Try 10 recalibration passes:
+    for(int p=0; p<10; ++p)
+        check_calib();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST(compass, calibration_far_centered)
+{
+    // Put magnetic center elsewhere, but keep position+radius < 1.0, to
+    // avoid Q15 overflow...
+    radius = 0.21f;
+    cx = -0.79f, cy = 0.79f, cz = 0.79f;
+
+    // Try 10 recalibration passes:
+    for(int p=0; p<10; ++p)
+        check_calib();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST(compass, calibration_small_centered_signal)
+{
+    // use a very very small magnetic signal, centered:
+    radius = 0.001f;
+    cx = 0.000f, cy = 0.000f, cz = 0.000f;
+
+    // Try 10 recalibration passes:
+    for(int p=0; p<10; ++p)
+        check_calib();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST(compass, calibration_small_off_centered_signal)
+{
+    // Have a rather small sphere radius (20%), off-centered buy 80%
+    radius = 0.200f;
+    cx = 0.800f, cy = -0.800f, cz = 0.800f;
+
+    // Try 10 recalibration passes:
+    for(int p=0; p<10; ++p)
+        check_calib();
+}