diff options
Diffstat (limited to 'test/gyro_cal.c')
-rw-r--r-- | test/gyro_cal.c | 511 |
1 files changed, 0 insertions, 511 deletions
diff --git a/test/gyro_cal.c b/test/gyro_cal.c deleted file mode 100644 index 10d48ca18e..0000000000 --- a/test/gyro_cal.c +++ /dev/null @@ -1,511 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "common.h" -#include "gyro_cal.h" -#include "gyro_still_det.h" -#include "gyro_cal_init_for_test.h" -#include "motion_sense.h" -#include "test_util.h" -#include <string.h> -#include <stdlib.h> -#include <math.h> -#include <stdio.h> - -float kToleranceGyroRps = 1e-6f; -float kDefaultGravityMps2 = 9.81f; -int kDefaultTemperatureKelvin = 298; - -#define NANOS_TO_SEC (1.0e-9f) -#define NANO_PI (3.14159265359f) -/** Unit conversion: milli-degrees to radians. */ -#define MDEG_TO_RAD (NANO_PI / 180.0e3f) - -#define MSEC_TO_NANOS(x) ((uint64_t)((x) * (uint64_t)(1000000))) -#define SEC_TO_NANOS(x) MSEC_TO_NANOS((x) * (uint64_t)(1000)) -#define HZ_TO_PERIOD_NANOS(hz) (SEC_TO_NANOS(1024) / ((uint64_t)((hz)*1024))) - -struct motion_sensor_t motion_sensors[] = { - [BASE] = {}, - [LID] = {}, -}; - -const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors); - -/** - * This function will return a uniformly distributed random value in the range - * of (0,1). This is important that 0 and 1 are excluded because of how the - * value is used in normal_random. For references: - * - rand() / RAND_MAX yields the range [0,1] - * - rand() / (RAND_MAX + 1) yields the range [0,1) - * - (rand() + 1) / (RAND_MAX + 1) yields the range (0, 1) - * - * @return A uniformly distributed random value. - */ -static double rand_gen(void) -{ - return ((double)(rand()) + 1.0) / ((double)(RAND_MAX) + 1.0); -} - -/** - * @return A normally distributed random value - */ -static float normal_random(void) -{ - double v1 = rand_gen(); - double v2 = rand_gen(); - - return (float)(cos(2 * 3.14 * v2) * sqrt(-2.0 * log(v1))); -} - -/** - * @param mean The mean to use for the normal distribution. - * @param stddev The standard deviation to use for the normal distribution. - * @return A normally distributed random value based on mean and stddev. - */ -static float normal_random2(float mean, float stddev) -{ - return normal_random() * stddev + mean; -} - -/** - * Tests that a calibration is updated after a period where the IMU device is - * stationary. Accelerometer and gyroscope measurements are simulated with data - * sheet specs for the BMI160 at their respective noise floors. A magnetometer - * sensor is also included in this test. - * - * @return EC_SUCCESS on success. - */ -static int test_gyro_cal_calibration(void) -{ - int i; - struct gyro_cal gyro_cal; - - /* - * Statistics for simulated gyroscope data. - * RMS noise = 70mDPS, offset = 150mDPS. - */ - /* [Hz] */ - const float sample_rate = 400.0f; - /* [rad/sec] */ - const float gyro_bias = MDEG_TO_RAD * 150.0f; - /* [rad/sec] */ - const float gyro_rms_noise = MDEG_TO_RAD * 70.0f; - const uint64_t sample_interval_nanos = HZ_TO_PERIOD_NANOS(sample_rate); - - /* - * Statistics for simulated accelerometer data. - * noise density = 200ug/rtHz, offset = 50mg. - */ - /* [m/sec^2] */ - const float accel_bias = 0.05f * kDefaultGravityMps2; - /* [m/sec^2] */ - const float accel_rms_noise = - 0.0002f * kDefaultGravityMps2 * fp_sqrtf(0.5f * sample_rate); - - /* - * Statistics for simulated magnetometer data. - * RMS noise = 0.4 micro Tesla (uT), offset = 0.2uT. - */ - const float mag_bias = 0.2f; /* [uT] */ - const float mag_rms_noise = 0.4f; /* [uT] */ - - float bias[3]; - float bias_residual[3]; - int temperature_kelvin; - uint32_t calibration_time_us = 0; - - bool calibration_received = false; - - gyro_cal_initialization_for_test(&gyro_cal); - - /* No calibration should be available yet. */ - TEST_EQ(gyro_cal_new_bias_available(&gyro_cal), false, "%d"); - - /* - * Simulate up to 20 seconds of sensor data (zero mean, additive white - * Gaussian noise). - */ - for (i = 0; i < (int)(20.0f * sample_rate); ++i) { - const uint32_t timestamp_us = - (i * sample_interval_nanos) / 1000; - - /* Generate and add an accelerometer sample. */ - gyro_cal_update_accel( - &gyro_cal, timestamp_us, - normal_random2(accel_bias, accel_rms_noise), - normal_random2(accel_bias, accel_rms_noise), - normal_random2(accel_bias, accel_rms_noise)); - - /* Generate and add a gyroscrope sample. */ - gyro_cal_update_gyro(&gyro_cal, timestamp_us, - normal_random2(gyro_bias, gyro_rms_noise), - normal_random2(gyro_bias, gyro_rms_noise), - normal_random2(gyro_bias, gyro_rms_noise), - kDefaultTemperatureKelvin); - - /* - * The simulated magnetometer here has a sampling rate that is - * 4x slower than the accel/gyro - */ - if (i % 4 == 0) { - gyro_cal_update_mag( - &gyro_cal, timestamp_us, - normal_random2(mag_bias, mag_rms_noise), - normal_random2(mag_bias, mag_rms_noise), - normal_random2(mag_bias, mag_rms_noise)); - } - calibration_received = gyro_cal_new_bias_available(&gyro_cal); - if (calibration_received) - break; - } - - TEST_EQ(calibration_received, true, "%d"); - - gyro_cal_get_bias(&gyro_cal, bias, &temperature_kelvin, - &calibration_time_us); - bias_residual[0] = gyro_bias - bias[0]; - bias_residual[1] = gyro_bias - bias[1]; - bias_residual[2] = gyro_bias - bias[2]; - - /* - * Make sure that the bias estimate is within 20 milli-degrees per - * second. - */ - TEST_LT(bias_residual[0], 20.f * MDEG_TO_RAD, "%f"); - TEST_LT(bias_residual[1], 20.f * MDEG_TO_RAD, "%f"); - TEST_LT(bias_residual[2], 20.f * MDEG_TO_RAD, "%f"); - - TEST_NEAR(gyro_cal.stillness_confidence, 1.0f, 0.0001f, "%f"); - - TEST_EQ(temperature_kelvin, kDefaultTemperatureKelvin, "%d"); - - return EC_SUCCESS; -} - -/** - * Tests that calibration does not falsely occur for low-level motion. - * - * @return EC_SUCCESS on success. - */ -static int test_gyro_cal_no_calibration(void) -{ - int i; - struct gyro_cal gyro_cal; - - /* Statistics for simulated gyroscope data. */ - /* RMS noise = 70mDPS, offset = 150mDPS. */ - const float sample_rate = 400.0f; /* [Hz] */ - const float gyro_bias = MDEG_TO_RAD * 150.0f; /* [rad/sec] */ - const float gyro_rms_noise = MDEG_TO_RAD * 70.0f; /* [rad/sec] */ - const uint64_t sample_interval_nanos = HZ_TO_PERIOD_NANOS(sample_rate); - - /* Statistics for simulated accelerometer data. */ - /* noise density = 200ug/rtHz, offset = 50mg. */ - /* [m/sec^2] */ - const float accel_bias = 0.05f * kDefaultGravityMps2; - /* [m/sec^2] */ - const float accel_rms_noise = - 200.0e-6f * kDefaultGravityMps2 * fp_sqrtf(0.5f * sample_rate); - - /* Define sinusoidal gyroscope motion parameters. */ - const float omega_dt = - 2.0f * NANO_PI * sample_interval_nanos * NANOS_TO_SEC; - const float amplitude = MDEG_TO_RAD * 550.0f; /* [rad/sec] */ - - bool calibration_received = false; - - gyro_cal_initialization_for_test(&gyro_cal); - - for (i = 0; i < (int)(20.0f * sample_rate); ++i) { - const uint32_t timestamp_us = - (i * sample_interval_nanos) / 1000; - - /* Generate and add an accelerometer sample. */ - gyro_cal_update_accel( - &gyro_cal, timestamp_us, - normal_random2(accel_bias, accel_rms_noise), - normal_random2(accel_bias, accel_rms_noise), - normal_random2(accel_bias, accel_rms_noise)); - - /* Generate and add a gyroscope sample. */ - gyro_cal_update_gyro( - &gyro_cal, timestamp_us, - normal_random2(gyro_bias, gyro_rms_noise) + - amplitude * sin(2.0f * omega_dt * i), - normal_random2(gyro_bias, gyro_rms_noise) - - amplitude * sin(2.1f * omega_dt * i), - normal_random2(gyro_bias, gyro_rms_noise) + - amplitude * cos(4.3f * omega_dt * i), - kDefaultTemperatureKelvin); - - /* Check for calibration update. Break after first one. */ - calibration_received = gyro_cal_new_bias_available(&gyro_cal); - if (calibration_received) - break; - } - - /* Determine that NO calibration had occurred. */ - TEST_EQ(calibration_received, false, "%d"); - - /* Make sure that the device was NOT classified as "still". */ - TEST_GT(1.0f, gyro_cal.stillness_confidence, "%f"); - - return EC_SUCCESS; -} - -/** - * Tests that a shift in a stillness window mean does not trigger a calibration. - * - * @return EC_SUCCESS on success. - */ -static int test_gyro_cal_win_mean_shift(void) -{ - struct gyro_cal gyro_cal; - int i; - - /* Statistics for simulated gyroscope data. */ - const float sample_rate = 400.0f; /* [Hz] */ - const float gyro_bias = MDEG_TO_RAD * 150.0f; /* [rad/sec] */ - const float gyro_bias_shift = MDEG_TO_RAD * 60.0f; /* [rad/sec] */ - const uint64_t sample_interval_nanos = HZ_TO_PERIOD_NANOS(sample_rate); - - /* Initialize the gyro calibration. */ - gyro_cal_initialization_for_test(&gyro_cal); - - /* - * Simulates 8 seconds of sensor data (no noise, just a gyro mean shift - * after 4 seconds). - * Assumptions: The max stillness period is 6 seconds, and the mean - * delta limit is 50mDPS. The mean shift should be detected and exceed - * the 50mDPS limit, and no calibration should be triggered. NOTE: This - * step is not large enough to trip the variance checking within the - * stillness detectors. - */ - for (i = 0; i < (int)(8.0f * sample_rate); i++) { - const uint32_t timestamp_us = - (i * sample_interval_nanos) / 1000; - - /* Generate and add a accelerometer sample. */ - gyro_cal_update_accel(&gyro_cal, timestamp_us, 0.0f, 0.0f, - 9.81f); - - /* Generate and add a gyroscope sample. */ - if (timestamp_us > 4 * SECOND) { - gyro_cal_update_gyro(&gyro_cal, timestamp_us, - gyro_bias + gyro_bias_shift, - gyro_bias + gyro_bias_shift, - gyro_bias + gyro_bias_shift, - kDefaultTemperatureKelvin); - } else { - gyro_cal_update_gyro(&gyro_cal, timestamp_us, gyro_bias, - gyro_bias, gyro_bias, - kDefaultTemperatureKelvin); - } - } - - /* Determine that NO calibration had occurred. */ - TEST_EQ(gyro_cal_new_bias_available(&gyro_cal), false, "%d"); - - return EC_SUCCESS; -} - -/** - * Tests that a temperature variation outside the acceptable range prevents a - * calibration. - * - * @return EC_SUCCESS on success. - */ -static int test_gyro_cal_temperature_shift(void) -{ - int i; - struct gyro_cal gyro_cal; - - /* Statistics for simulated gyroscope data. */ - const float sample_rate = 400.0f; /* [Hz] */ - const float gyro_bias = MDEG_TO_RAD * 150.0f; /* [rad/sec] */ - const float temperature_shift_kelvin = 2.6f; - const uint64_t sample_interval_nanos = HZ_TO_PERIOD_NANOS(sample_rate); - - gyro_cal_initialization_for_test(&gyro_cal); - - /* - * Simulates 8 seconds of sensor data (no noise, just a temperature - * shift after 4 seconds). - * Assumptions: The max stillness period is 6 seconds, and the - * temperature delta limit is 1.5C. The shift should be detected and - * exceed the limit, and no calibration should be triggered. - */ - for (i = 0; i < (int)(8.0f * sample_rate); i++) { - const uint32_t timestamp_us = - (i * sample_interval_nanos) / 1000; - float temperature_kelvin = kDefaultTemperatureKelvin; - - /* Generate and add a accelerometer sample. */ - gyro_cal_update_accel(&gyro_cal, timestamp_us, 0.0f, 0.0f, - 9.81f); - - /* Sets the temperature value. */ - if (timestamp_us > 4 * SECOND) - temperature_kelvin += temperature_shift_kelvin; - - /* Generate and add a gyroscope sample. */ - gyro_cal_update_gyro(&gyro_cal, timestamp_us, gyro_bias, - gyro_bias, gyro_bias, - (int)temperature_kelvin); - } - - /* Determine that NO calibration had occurred. */ - TEST_EQ(gyro_cal_new_bias_available(&gyro_cal), false, "%d"); - - return EC_SUCCESS; -} - -/** - * Verifies that complete sensor stillness results in the correct bias estimate - * and produces the correct timestamp. - * - * @return EC_SUCCESS on success; - */ -static int test_gyro_cal_stillness_timestamp(void) -{ - struct gyro_cal gyro_cal; - int64_t time_us; - - /* - * 10Hz update rate for 11 seconds should trigger the in-situ - * algorithms. - */ - const float gyro_bias_x = 0.09f; - const float gyro_bias_y = -0.04f; - const float gyro_bias_z = 0.05f; - - float bias[3]; - int temperature_kelvin = 273; - uint32_t calibration_time_us = 0; - - gyro_cal_initialization_for_test(&gyro_cal); - for (time_us = 0; time_us < 11 * SECOND; time_us += 100 * MSEC) { - /* Generate and add a accelerometer sample. */ - gyro_cal_update_accel(&gyro_cal, time_us, 0.0f, 0.0f, 9.81f); - - /* Generate and add a gyroscope sample. */ - gyro_cal_update_gyro(&gyro_cal, time_us, gyro_bias_x, - gyro_bias_y, gyro_bias_z, - kDefaultTemperatureKelvin); - } - - /* Determine if there is a new calibration. Get the calibration value. - */ - TEST_EQ(gyro_cal_new_bias_available(&gyro_cal), 1, "%d"); - - gyro_cal_get_bias(&gyro_cal, bias, &temperature_kelvin, - &calibration_time_us); - - /* Make sure that the bias estimate is within kToleranceGyroRps. */ - TEST_NEAR(gyro_bias_x - bias[0], 0.0f, 0.0001f, "%f"); - TEST_NEAR(gyro_bias_y - bias[1], 0.0f, 0.0001f, "%f"); - TEST_NEAR(gyro_bias_z - bias[2], 0.0f, 0.0001f, "%f"); - - /* Checks that the calibration occurred at the expected time. */ - TEST_EQ(6 * SECOND, gyro_cal.calibration_time_us, "%u"); - - /* Make sure that the device was classified as 100% "still". */ - TEST_NEAR(1.0f, gyro_cal.stillness_confidence, 0.0001f, "%f"); - - /* Make sure that the calibration temperature is correct. */ - TEST_EQ(kDefaultTemperatureKelvin, temperature_kelvin, "%d"); - - return EC_SUCCESS; -} - -/** - * Verifies that setting an initial bias works. - * - * @return EC_SUCCESS on success. - */ -static int test_gyro_cal_set_bias(void) -{ - struct gyro_cal gyro_cal; - - /* Get the initialized bias value; should be zero. */ - float bias[3] = { 0.0f, 0.0f, 0.0f }; - int temperature_kelvin = 273; - uint32_t calibration_time_us = 10; - - /* Initialize the gyro calibration. */ - gyro_cal_initialization_for_test(&gyro_cal); - gyro_cal_get_bias(&gyro_cal, bias, &temperature_kelvin, - &calibration_time_us); - TEST_NEAR(0.0f, bias[0], 0.0001f, "%f"); - TEST_NEAR(0.0f, bias[1], 0.0001f, "%f"); - TEST_NEAR(0.0f, bias[2], 0.0001f, "%f"); - TEST_EQ(0, temperature_kelvin, "%d"); - TEST_EQ(0, calibration_time_us, "%d"); - - /* Set the calibration bias estimate. */ - bias[0] = 1.0f; - bias[1] = 2.0f; - bias[2] = 3.0f; - gyro_cal_set_bias(&gyro_cal, bias, 31, 3 * 60 * SECOND); - - bias[0] = 0.0f; - bias[1] = 0.0f; - bias[2] = 0.0f; - /* Check that it was set correctly. */ - gyro_cal_get_bias(&gyro_cal, bias, &temperature_kelvin, - &calibration_time_us); - TEST_NEAR(1.0f, bias[0], 0.0001f, "%f"); - TEST_NEAR(2.0f, bias[1], 0.0001f, "%f"); - TEST_NEAR(3.0f, bias[2], 0.0001f, "%f"); - TEST_EQ(31, temperature_kelvin, "%d"); - TEST_EQ(3 * 60 * SECOND, calibration_time_us, "%u"); - - return EC_SUCCESS; -} - -/** - * Verifies that the gyroCalRemoveBias function works as intended. - * - * @return EC_SUCCESS on success - */ -static int test_gyro_cal_remove_bias(void) -{ - struct gyro_cal gyro_cal; - float bias[3] = { 1.0f, 2.0f, 3.0f }; - float bias_out[3]; - - /* Initialize the gyro calibration. */ - gyro_cal_initialization_for_test(&gyro_cal); - - /* Set an calibration bias estimate. */ - gyro_cal_set_bias(&gyro_cal, bias, kDefaultTemperatureKelvin, - 5 * 60 * SECOND); - - /* Correct the bias, and check that it has been adequately removed. */ - gyro_cal_remove_bias(&gyro_cal, bias, bias_out); - - /* Make sure that the bias estimate is within kToleranceGyroRps. */ - TEST_NEAR(0.0f, bias_out[0], 0.0001f, "%f"); - TEST_NEAR(0.0f, bias_out[1], 0.0001f, "%f"); - TEST_NEAR(0.0f, bias_out[2], 0.0001f, "%f"); - - return EC_SUCCESS; -} - -void run_test(int argc, char **argv) -{ - test_reset(); - - RUN_TEST(test_gyro_cal_calibration); - RUN_TEST(test_gyro_cal_no_calibration); - RUN_TEST(test_gyro_cal_win_mean_shift); - RUN_TEST(test_gyro_cal_temperature_shift); - RUN_TEST(test_gyro_cal_stillness_timestamp); - RUN_TEST(test_gyro_cal_set_bias); - RUN_TEST(test_gyro_cal_remove_bias); - - test_print_result(); -} |