summaryrefslogtreecommitdiff
path: root/firmware/os/algos/calibration
diff options
context:
space:
mode:
authorMeng-hsuan Chung <menghsuan@google.com>2016-12-15 01:04:41 +0000
committerMeng-hsuan Chung <menghsuan@google.com>2016-12-15 01:04:41 +0000
commit73de7fb55e60497a2a189d82cb1d9e1b8549da5d (patch)
treeaf9cdd571dd42c097972abcf9da666d0b2ff6266 /firmware/os/algos/calibration
parentbad8af6cd1fadca604ed8af6f41e1dae9972ee35 (diff)
downloadcontexthub-73de7fb55e60497a2a189d82cb1d9e1b8549da5d.tar.gz
Revert "Syncs google3 Calibration Code to Android."
This reverts commit bad8af6cd1fadca604ed8af6f41e1dae9972ee35. Change-Id: I678435108782ae36b5b4ef0fa3e01664f282fb56
Diffstat (limited to 'firmware/os/algos/calibration')
-rw-r--r--firmware/os/algos/calibration/accelerometer/accel_cal.c111
-rw-r--r--firmware/os/algos/calibration/accelerometer/accel_cal.h8
-rw-r--r--firmware/os/algos/calibration/common/calibration_data.c36
-rw-r--r--firmware/os/algos/calibration/common/calibration_data.h72
-rw-r--r--firmware/os/algos/calibration/common/diversity_checker.c165
-rw-r--r--firmware/os/algos/calibration/common/diversity_checker.h133
-rw-r--r--firmware/os/algos/calibration/common/sphere_fit_calibration.c247
-rw-r--r--firmware/os/algos/calibration/common/sphere_fit_calibration.h143
-rw-r--r--firmware/os/algos/calibration/gyroscope/gyro_cal.c1168
-rw-r--r--firmware/os/algos/calibration/gyroscope/gyro_cal.h119
-rw-r--r--firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.c2
-rw-r--r--firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.h5
-rw-r--r--firmware/os/algos/calibration/magnetometer/mag_cal.c180
-rw-r--r--firmware/os/algos/calibration/magnetometer/mag_cal.h36
-rw-r--r--firmware/os/algos/calibration/over_temp/over_temp_cal.c940
-rw-r--r--firmware/os/algos/calibration/over_temp/over_temp_cal.h327
-rw-r--r--firmware/os/algos/calibration/util/cal_log.h28
17 files changed, 620 insertions, 3100 deletions
diff --git a/firmware/os/algos/calibration/accelerometer/accel_cal.c b/firmware/os/algos/calibration/accelerometer/accel_cal.c
index a789ce9d..eea4493a 100644
--- a/firmware/os/algos/calibration/accelerometer/accel_cal.c
+++ b/firmware/os/algos/calibration/accelerometer/accel_cal.c
@@ -156,7 +156,12 @@ static void accelCalAlgoInit(struct AccelCalAlgo *acc, uint32_t fx,
uint32_t fxb, uint32_t fy, uint32_t fyb,
uint32_t fz, uint32_t fzb, uint32_t fle) {
accelGoodDataInit(&acc->agd, fx, fxb, fy, fyb, fz, fzb, fle);
- initKasa(&acc->akf);
+
+ initMagCal(&acc->amoc, // mag_cal_t struct need for accel cal
+ 0.0f, 0.0f, 0.0f, // bias x, y, z
+ 1.0f, 0.0f, 0.0f, // c00, c01, c02
+ 0.0f, 1.0f, 0.0f, // c10, c11, c12
+ 0.0f, 0.0f, 1.0f); // c20, c21, c22
}
// Accel cal init.
@@ -260,28 +265,28 @@ static int accelStillnessDetection(struct AccelStillDet *asd,
}
// Accumulate data for KASA fit.
-static void accelCalUpdate(struct KasaFit *akf, struct AccelStillDet *asd) {
+static void accelCalUpdate(struct MagCal *amoc, struct AccelStillDet *asd) {
// Run accumulators.
float w = asd->mean_x * asd->mean_x + asd->mean_y * asd->mean_y +
asd->mean_z * asd->mean_z;
- akf->acc_x += asd->mean_x;
- akf->acc_y += asd->mean_y;
- akf->acc_z += asd->mean_z;
- akf->acc_w += w;
+ amoc->acc_x += asd->mean_x;
+ amoc->acc_y += asd->mean_y;
+ amoc->acc_z += asd->mean_z;
+ amoc->acc_w += w;
- akf->acc_xx += asd->mean_x * asd->mean_x;
- akf->acc_xy += asd->mean_x * asd->mean_y;
- akf->acc_xz += asd->mean_x * asd->mean_z;
- akf->acc_xw += asd->mean_x * w;
+ amoc->acc_xx += asd->mean_x * asd->mean_x;
+ amoc->acc_xy += asd->mean_x * asd->mean_y;
+ amoc->acc_xz += asd->mean_x * asd->mean_z;
+ amoc->acc_xw += asd->mean_x * w;
- akf->acc_yy += asd->mean_y * asd->mean_y;
- akf->acc_yz += asd->mean_y * asd->mean_z;
- akf->acc_yw += asd->mean_y * w;
+ amoc->acc_yy += asd->mean_y * asd->mean_y;
+ amoc->acc_yz += asd->mean_y * asd->mean_z;
+ amoc->acc_yw += asd->mean_y * w;
- akf->acc_zz += asd->mean_z * asd->mean_z;
- akf->acc_zw += asd->mean_z * w;
- akf->nsamples += 1;
+ amoc->acc_zz += asd->mean_z * asd->mean_z;
+ amoc->acc_zw += asd->mean_z * w;
+ amoc->nsamples += 1;
}
// Good data detection, sorting and accumulate the data for Kasa.
@@ -296,42 +301,42 @@ static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
ac1->agd.nx += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Negative x bucket nxb.
if (PHIb > asd->mean_x && ac1->agd.nxb < ac1->agd.nfxb) {
ac1->agd.nxb += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Y bucket ny.
if (PHI < asd->mean_y && ac1->agd.ny < ac1->agd.nfy) {
ac1->agd.ny += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Negative y bucket nyb.
if (PHIb > asd->mean_y && ac1->agd.nyb < ac1->agd.nfyb) {
ac1->agd.nyb += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Z bucket nz.
if (PHIZ < asd->mean_z && ac1->agd.nz < ac1->agd.nfz) {
ac1->agd.nz += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Negative z bucket nzb.
if (PHIZb > asd->mean_z && ac1->agd.nzb < ac1->agd.nfzb) {
ac1->agd.nzb += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// The leftover bucket nle.
if (PHI > asd->mean_x && PHIb < asd->mean_x && PHI > asd->mean_y &&
@@ -340,39 +345,39 @@ static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
ac1->agd.nle += 1;
ac1->agd.acc_t += temp;
ac1->agd.acc_tt += temp * temp;
- accelCalUpdate(&ac1->akf, asd);
+ accelCalUpdate(&ac1->amoc, asd);
}
// Checking if all buckets are full.
if (ac1->agd.nx == ac1->agd.nfx && ac1->agd.nxb == ac1->agd.nfxb &&
ac1->agd.ny == ac1->agd.nfy && ac1->agd.nyb == ac1->agd.nfyb &&
ac1->agd.nz == ac1->agd.nfz && ac1->agd.nzb == ac1->agd.nfzb) {
- // Check if akf->nsamples is zero.
- if (ac1->akf.nsamples == 0) {
+ // Check if amoc->nsamples is zero.
+ if (ac1->amoc.nsamples == 0) {
agdReset(&ac1->agd);
- magKasaReset(&ac1->akf);
+ magCalReset(&ac1->amoc);
complete = 0;
return complete;
} else {
// Normalize the data to the sample numbers.
- inv = 1.0f / ac1->akf.nsamples;
+ inv = 1.0f / ac1->amoc.nsamples;
}
- ac1->akf.acc_x *= inv;
- ac1->akf.acc_y *= inv;
- ac1->akf.acc_z *= inv;
- ac1->akf.acc_w *= inv;
+ ac1->amoc.acc_x *= inv;
+ ac1->amoc.acc_y *= inv;
+ ac1->amoc.acc_z *= inv;
+ ac1->amoc.acc_w *= inv;
- ac1->akf.acc_xx *= inv;
- ac1->akf.acc_xy *= inv;
- ac1->akf.acc_xz *= inv;
- ac1->akf.acc_xw *= inv;
+ ac1->amoc.acc_xx *= inv;
+ ac1->amoc.acc_xy *= inv;
+ ac1->amoc.acc_xz *= inv;
+ ac1->amoc.acc_xw *= inv;
- ac1->akf.acc_yy *= inv;
- ac1->akf.acc_yz *= inv;
- ac1->akf.acc_yw *= inv;
+ ac1->amoc.acc_yy *= inv;
+ ac1->amoc.acc_yz *= inv;
+ ac1->amoc.acc_yw *= inv;
- ac1->akf.acc_zz *= inv;
- ac1->akf.acc_zw *= inv;
+ ac1->amoc.acc_zz *= inv;
+ ac1->amoc.acc_zw *= inv;
// Calculate the temp VAR and MEA.N
ac1->agd.var_t =
@@ -387,7 +392,7 @@ static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
ac1->agd.ny > ac1->agd.nfy || ac1->agd.nyb > ac1->agd.nfyb ||
ac1->agd.nz > ac1->agd.nfz || ac1->agd.nzb > ac1->agd.nfzb) {
agdReset(&ac1->agd);
- magKasaReset(&ac1->akf);
+ magCalReset(&ac1->amoc);
complete = 0;
return complete;
}
@@ -395,15 +400,15 @@ static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
}
// Eigen value magnitude and ratio test.
-static int accEigenTest(struct KasaFit *akf, struct AccelGoodData *agd) {
+static int mocEigenTest(struct MagCal *moc, struct AccelGoodData *agd) {
// covariance matrix.
struct Mat33 S;
- S.elem[0][0] = akf->acc_xx - akf->acc_x * akf->acc_x;
- S.elem[0][1] = S.elem[1][0] = akf->acc_xy - akf->acc_x * akf->acc_y;
- S.elem[0][2] = S.elem[2][0] = akf->acc_xz - akf->acc_x * akf->acc_z;
- S.elem[1][1] = akf->acc_yy - akf->acc_y * akf->acc_y;
- S.elem[1][2] = S.elem[2][1] = akf->acc_yz - akf->acc_y * akf->acc_z;
- S.elem[2][2] = akf->acc_zz - akf->acc_z * akf->acc_z;
+ S.elem[0][0] = moc->acc_xx - moc->acc_x * moc->acc_x;
+ S.elem[0][1] = S.elem[1][0] = moc->acc_xy - moc->acc_x * moc->acc_y;
+ S.elem[0][2] = S.elem[2][0] = moc->acc_xz - moc->acc_x * moc->acc_z;
+ S.elem[1][1] = moc->acc_yy - moc->acc_y * moc->acc_y;
+ S.elem[1][2] = S.elem[2][1] = moc->acc_yz - moc->acc_y * moc->acc_z;
+ S.elem[2][2] = moc->acc_zz - moc->acc_z * moc->acc_z;
struct Vec3 eigenvals;
struct Mat33 eigenvecs;
@@ -497,13 +502,13 @@ void accelCalRun(struct AccelCal *acc, uint64_t sample_time_nsec, float x,
float radius;
// Grabbing the fit from the MAG cal.
- magKasaFit(&acc->ac1[temp_gate].akf, &bias, &radius);
+ magCalFit(&acc->ac1[temp_gate].amoc, &bias, &radius);
// If offset is too large don't take.
if (fabsf(bias.x) < MAX_OFF && fabsf(bias.y) < MAX_OFF &&
fabsf(bias.z) < MAX_OFF) {
// Eigen Ratio Test.
- if (accEigenTest(&acc->ac1[temp_gate].akf,
+ if (mocEigenTest(&acc->ac1[temp_gate].amoc,
&acc->ac1[temp_gate].agd)) {
// Storing the new offsets.
acc->x_bias_new = bias.x * KSCALE2;
@@ -540,7 +545,7 @@ void accelCalRun(struct AccelCal *acc, uint64_t sample_time_nsec, float x,
// Resetting the structs for a new accel cal run.
agdReset(&acc->ac1[temp_gate].agd);
- magKasaReset(&acc->ac1[temp_gate].akf);
+ magCalReset(&acc->ac1[temp_gate].amoc);
}
}
}
@@ -725,7 +730,7 @@ void accelCalDebPrint(struct AccelCal *acc, float temp) {
(unsigned)acc->ac1[0].agd.nx, (unsigned)acc->ac1[0].agd.nxb,
(unsigned)acc->ac1[0].agd.ny, (unsigned)acc->ac1[0].agd.nyb,
(unsigned)acc->ac1[0].agd.nz, (unsigned)acc->ac1[0].agd.nzb,
- (unsigned)acc->ac1[0].agd.nle, (unsigned)acc->ac1[0].akf.nsamples);
+ (unsigned)acc->ac1[0].agd.nle, (unsigned)acc->ac1[0].amoc.nsamples);
// Live bucket count hogher.
CAL_DEBUG_LOG(
"[BMI160]",
@@ -734,7 +739,7 @@ void accelCalDebPrint(struct AccelCal *acc, float temp) {
(unsigned)acc->ac1[1].agd.nx, (unsigned)acc->ac1[1].agd.nxb,
(unsigned)acc->ac1[1].agd.ny, (unsigned)acc->ac1[1].agd.nyb,
(unsigned)acc->ac1[1].agd.nz, (unsigned)acc->ac1[1].agd.nzb,
- (unsigned)acc->ac1[1].agd.nle, (unsigned)acc->ac1[1].akf.nsamples);
+ (unsigned)acc->ac1[1].agd.nle, (unsigned)acc->ac1[1].amoc.nsamples);
// Offset used.
CAL_DEBUG_LOG(
"[BMI160]",
diff --git a/firmware/os/algos/calibration/accelerometer/accel_cal.h b/firmware/os/algos/calibration/accelerometer/accel_cal.h
index 03c65e92..83a45070 100644
--- a/firmware/os/algos/calibration/accelerometer/accel_cal.h
+++ b/firmware/os/algos/calibration/accelerometer/accel_cal.h
@@ -1,3 +1,6 @@
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_ACCELEROMETER_ACCEL_CAL_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_ACCELEROMETER_ACCEL_CAL_H_
+
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -22,8 +25,6 @@
* the vectors should end onto a sphere. Furthermore the offset values are
* subtracted from the accelerometer data calibrating the sensor.
*/
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_ACCELEROMETER_ACCEL_CAL_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_ACCELEROMETER_ACCEL_CAL_H_
#include <stdint.h>
#include <sys/types.h>
@@ -123,8 +124,7 @@ struct AccelStatsMem {
// Struct for an accel calibration for a single temperature window.
struct AccelCalAlgo {
struct AccelGoodData agd;
- // TODO(mkramerm): Replace all abbreviations.
- struct KasaFit akf;
+ struct MagCal amoc;
};
// Complete accel calibration struct.
diff --git a/firmware/os/algos/calibration/common/calibration_data.c b/firmware/os/algos/calibration/common/calibration_data.c
deleted file mode 100644
index 9ae72d27..00000000
--- a/firmware/os/algos/calibration/common/calibration_data.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "calibration/common/calibration_data.h"
-
-#include <string.h>
-
-#include "common/math/vec.h"
-
-// FUNCTION IMPLEMENTATIONS
-//////////////////////////////////////////////////////////////////////////////
-
-// Set calibration data to identity scale factors, zero skew and
-// zero bias.
-void calDataReset(struct ThreeAxisCalData *calstruct) {
- memset(calstruct, 0, sizeof(struct ThreeAxisCalData));
- calstruct->scale_factor_x = 1.0f;
- calstruct->scale_factor_y = 1.0f;
- calstruct->scale_factor_z = 1.0f;
-}
-
-void calDataCorrectData(const struct ThreeAxisCalData* calstruct,
- const float x_impaired[THREE_AXIS_DIM],
- float* x_corrected) {
- // x_temp = (x_impaired - bias).
- float x_temp[THREE_AXIS_DIM];
- vecSub(x_temp, x_impaired, calstruct->bias, THREE_AXIS_DIM);
-
- // x_corrected = scale_skew_mat * x_temp, where:
- // scale_skew_mat = [scale_factor_x 0 0
- // skew_yx scale_factor_y 0
- // skew_zx skew_zy scale_factor_z].
- x_corrected[0] = calstruct->scale_factor_x * x_temp[0];
- x_corrected[1] = calstruct->skew_yx * x_temp[0] +
- calstruct->scale_factor_y * x_temp[1];
- x_corrected[2] = calstruct->skew_zx * x_temp[0] +
- calstruct->skew_zy * x_temp[1] +
- calstruct->scale_factor_z * x_temp[2];
-}
diff --git a/firmware/os/algos/calibration/common/calibration_data.h b/firmware/os/algos/calibration/common/calibration_data.h
deleted file mode 100644
index b0e6809b..00000000
--- a/firmware/os/algos/calibration/common/calibration_data.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/////////////////////////////////////////////////////////////////////////////
-/*
- * This module contains a data structure and corresponding helper functions for
- * a three-axis sensor calibration. The calibration consists of a bias vector,
- * bias, and a lower-diagonal scaling and skew matrix, scale_skew_mat.
- *
- * The calibration is applied to impaired sensor data as follows:
- *
- * corrected_data = scale_skew_mat * (impaired_data - bias).
- */
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_CALIBRATION_DATA_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_CALIBRATION_DATA_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define THREE_AXIS_DIM (3)
-
-// Calibration data structure.
-struct ThreeAxisCalData {
- // Scale factor and skew terms. Used to construct the following lower
- // diagonal scale_skew_mat:
- // scale_skew_mat = [scale_factor_x 0 0
- // skew_yx scale_factor_y 0
- // skew_zx skew_zy scale_factor_z].
- float scale_factor_x;
- float scale_factor_y;
- float scale_factor_z;
- float skew_yx;
- float skew_zx;
- float skew_zy;
-
- // Sensor bias offset.
- float bias[THREE_AXIS_DIM];
-
- // Calibration time.
- uint64_t calibration_time_nanos;
-};
-
-// Set calibration data to identity scale factors, zero skew and
-// zero bias.
-void calDataReset(struct ThreeAxisCalData *calstruct);
-
-// Apply a stored calibration to correct a single sample of impaired sensor
-// data.
-void calDataCorrectData(const struct ThreeAxisCalData* calstruct,
- const float x_impaired[THREE_AXIS_DIM],
- float* x_corrected);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_CALIBRATION_DATA_H_
diff --git a/firmware/os/algos/calibration/common/diversity_checker.c b/firmware/os/algos/calibration/common/diversity_checker.c
deleted file mode 100644
index 8e5c3e28..00000000
--- a/firmware/os/algos/calibration/common/diversity_checker.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "calibration/common/diversity_checker.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include "common/math/vec.h"
-
-// Struct initialization.
-void diversityCheckerInit(
- struct DiversityChecker* diverse_data,
- float threshold,
- float max_distance,
- size_t min_num_diverse_vectors,
- size_t max_num_max_distance,
- float var_threshold,
- float max_min_threshold) {
- ASSERT_NOT_NULL(diverse_data);
- // Initialize parameters.
- diverse_data->threshold = threshold;
- diverse_data->max_distance = max_distance;
- diverse_data->min_num_diverse_vectors = min_num_diverse_vectors;
- // checking for min_num_diverse_vectors = 0
- if (min_num_diverse_vectors < 1) {
- diverse_data->min_num_diverse_vectors = 1;
- }
- diverse_data->max_num_max_distance = max_num_max_distance;
- diverse_data->var_threshold = var_threshold;
- diverse_data->max_min_threshold = max_min_threshold;
- // Setting the rest to zero.
- diversityCheckerReset(diverse_data);
-}
-
-// Reset
-void diversityCheckerReset(struct DiversityChecker* diverse_data) {
- ASSERT_NOT_NULL(diverse_data);
- // Clear data memory.
- memset(&diverse_data->diverse_data, 0,
- sizeof(diverse_data->diverse_data));
- // Resetting counters and data full bit.
- diverse_data->num_points = 0;
- diverse_data->num_max_dist_violations = 0;
- diverse_data->data_full = false;
-}
-
-void diversityCheckerUpdate(
- struct DiversityChecker* diverse_data, float x, float y, float z) {
- ASSERT_NOT_NULL(diverse_data);
- // Converting three single inputs to a vector.
- const float vec[3] = {x, y, z};
- // Result vector for vector difference.
- float vec_diff[3];
- // normSquared result (k)
- float norm_squared_result;
-
- // If memory is full, no need to run through the data.
- if (!diverse_data->data_full) {
- size_t i;
- // Running over all existing data points
- for (i = 0; i < diverse_data->num_points; ++i) {
- // v = v1 - v2;
- vecSub(vec_diff,
- &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
- vec,
- THREE_AXIS_DATA_DIM);
- // k = |v|^2
- norm_squared_result = vecNormSquared(vec_diff, THREE_AXIS_DATA_DIM);
- // if k < Threshold then leave the function.
- if (norm_squared_result < diverse_data->threshold) {
- return;
- }
- // if k > max_distance, count and leave the function.
- if (norm_squared_result > diverse_data->max_distance) {
- diverse_data->num_max_dist_violations++;
- return;
- }
- }
- // If none of the above caused to leave the function, data is diverse.
- // Notice that the first data vector will be stored no matter what.
- memcpy(&diverse_data->
- diverse_data[diverse_data->num_points * THREE_AXIS_DATA_DIM],
- vec,
- sizeof(float) * THREE_AXIS_DATA_DIM);
- // Count new data point.
- diverse_data->num_points++;
- // Setting data_full to 1, if memory is full.
- if (diverse_data->num_points == NUM_DIVERSE_VECTORS) {
- diverse_data->data_full = true;
- }
- }
-}
-
-bool diversityCheckerNormQuality(struct DiversityChecker* diverse_data,
- float x_bias,
- float y_bias,
- float z_bias) {
- ASSERT_NOT_NULL(diverse_data);
- // If not enough diverse data points or max distance violations return false.
- if (diverse_data->num_points <= diverse_data->min_num_diverse_vectors ||
- diverse_data->num_max_dist_violations >=
- diverse_data->max_num_max_distance) {
- return false;
- }
- float vec_bias[3] = {x_bias, y_bias, z_bias};
- float vec_bias_removed[3];
- float norm_results;
- float acc_norm = 0.0f;
- float acc_norm_square = 0.0f;
- float max;
- float min;
- size_t i;
- for (i = 0; i < diverse_data->num_points; ++i) {
- // v = v1 - v_bias;
- vecSub(vec_bias_removed,
- &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
- vec_bias,
- THREE_AXIS_DATA_DIM);
-
- // norm = ||v||
- norm_results = vecNorm(vec_bias_removed, THREE_AXIS_DATA_DIM);
-
- // Accumulate for mean and VAR.
- acc_norm += norm_results;
- acc_norm_square += norm_results * norm_results ;
-
- if (i == 0) {
- min = norm_results;
- max = norm_results;
- }
- // Finding min
- if (norm_results < min) {
- min = norm_results;
- }
-
- // Finding max.
- if (norm_results > max) {
- max = norm_results;
- }
- // can leave the function if max-min is violated
- // no need to continue.
- if ((max - min) > diverse_data->max_min_threshold) {
- return false;
- }
- }
-
- float inv = 1.0f / diverse_data->num_points;
- float var = (acc_norm_square - (acc_norm * acc_norm) * inv) * inv;
- return (var < diverse_data->var_threshold);
-}
diff --git a/firmware/os/algos/calibration/common/diversity_checker.h b/firmware/os/algos/calibration/common/diversity_checker.h
deleted file mode 100644
index 30f53dba..00000000
--- a/firmware/os/algos/calibration/common/diversity_checker.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//////////////////////////////////////////////////////////////////////////////
-/*
- * This function implements a diversity checker and stores diverse vectors into
- * a memory. We assume that the data is located on a sphere, and we use the
- * norm of the difference of two vectors to decide if the vectors are diverse
- * enough:
- *
- * k = norm( v1 - v2 )^2 < Threshold
- *
- * Hence when k < Threshold the data is not stored, because the vectors are too
- * similar. We store diverse vectors in memory and all new incoming vectors
- * are checked against the already stored data points.
- *
- * Furthermore we also check if k > max_distance, since that data is most likely
- * not located on a sphere anymore and indicates a disturbance. Finally we give
- * a "data is full" flag to indicate once the memory is full.
- * The diverse data can be used to improve sphere fit calibrations, ensuring
- * that the sphere is populated enough resulting in better fits.
- *
- * Memory is stored in an array initialized to length of
- * [THREE_AXIS_DATA_DIM * NUM_DIVERSE_VECTORS], this has been done to be
- * compatible with the full sphere fit algorithm.
- *
- * Notice, this function stops to check if data is diverse, once the memory is
- * full. This has been done in order to save processing power.
- */
-
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_DIVERSITY_CHECKER_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_DIVERSITY_CHECKER_H_
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define THREE_AXIS_DATA_DIM (3) // data is three-dimensional.
-#define NUM_DIVERSE_VECTORS (10) // Storing 10 data points.
-
-// Main data struct.
-struct DiversityChecker {
- // Data memory.
- float diverse_data[THREE_AXIS_DATA_DIM * NUM_DIVERSE_VECTORS];
-
- // Number of data points in the memory.
- size_t num_points;
-
- // Number of data points that violated the max_distance condition.
- size_t num_max_dist_violations;
-
- // Threshold value that is used to check k against.
- float threshold;
-
- // Maximum distance value.
- float max_distance;
-
- // Data full bit.
- bool data_full;
-
- // Setup variables for NormQuality check.
-
- size_t min_num_diverse_vectors;
- size_t max_num_max_distance;
- float var_threshold;
- float max_min_threshold;
-};
-
-// Initialization of the function/struct, input:
-// threshold -> sets the threshold value, only distances k that are equal
-// or higher than that will be stored.
-// max_distance -> sets the maximum allowed distance of k.
-// min_num_diverse_vectors -> sets the gate for a minimum number of data points
-// in the memory
-// max_num_max_distance -> sets the value for a max distance violation number
-// gate.
-// var_threshold -> is a threshold value for a Norm variance gate.
-// max_min_threshold -> is a value for a gate that rejects Norm variations
-// that are larger than this number.
-void diversityCheckerInit(struct DiversityChecker* diverse_data,
- float threshold,
- float max_distance,
- size_t min_num_diverse_vectors,
- size_t max_num_max_distance,
- float var_threshold,
- float max_min_threshold);
-
-// Resetting the memory and the counters, leaves threshold and max_distance
-// as well as the setup variables for NormQuality check untouched.
-void diversityCheckerReset(struct DiversityChecker* diverse_data);
-
-// Main function. Tests the data (x,y,z) against the memory if diverse and
-// stores it, if so.
-void diversityCheckerUpdate(struct DiversityChecker* diverse_data, float x,
- float y, float z);
-
-// Removing a constant bias from the diverse_data and check if the norm is
-// within a defined bound:
-// implemented 4 gates
-// -> needs a minimum number of data points in the memory
-// (controlled by min_num_divers_vectors).
-// -> will return false if maximum number of max_distance is reached
-// (controlled by max_num_max_distance).
-// -> norm must be within a var window.
-// -> norm must be within a MAX/MIN window.
-// Returned value will only be true if all 4 gates are passed.
-bool diversityCheckerNormQuality(struct DiversityChecker* diverse_data,
- float x_bias,
- float y_bias,
- float z_bias);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_DIVERSITY_CHECKER_H_
diff --git a/firmware/os/algos/calibration/common/sphere_fit_calibration.c b/firmware/os/algos/calibration/common/sphere_fit_calibration.c
deleted file mode 100644
index 2c26af55..00000000
--- a/firmware/os/algos/calibration/common/sphere_fit_calibration.c
+++ /dev/null
@@ -1,247 +0,0 @@
-#include "calibration/common/sphere_fit_calibration.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "calibration/util/cal_log.h"
-#include "common/math/mat.h"
-#include "common/math/vec.h"
-
-// FORWARD DECLARATIONS
-///////////////////////////////////////////////////////////////////////////////
-// Utility for converting solver state to a calibration data structure.
-static void convertStateToCalStruct(const float x[SF_STATE_DIM],
- struct ThreeAxisCalData *calstruct);
-
-static bool runCalibration(struct SphereFitCal *sphere_cal,
- const struct SphereFitData *data,
- uint64_t timestamp_nanos);
-
-#define MIN_VALID_DATA_NORM (1e-4)
-
-// FUNCTION IMPLEMENTATIONS
-//////////////////////////////////////////////////////////////////////////////
-void sphereFitInit(struct SphereFitCal *sphere_cal,
- const struct LmParams *lm_params,
- const size_t min_num_points_for_cal) {
- ASSERT_NOT_NULL(sphere_cal);
- ASSERT_NOT_NULL(lm_params);
-
- // Initialize LM solver.
- lmSolverInit(&sphere_cal->lm_solver, lm_params,
- &sphereFitResidAndJacobianFunc);
-
- // Reset other parameters.
- sphereFitReset(sphere_cal);
-
- // Set num points for calibration, checking that it is above min.
- if (min_num_points_for_cal < MIN_NUM_SPHERE_FIT_POINTS) {
- sphere_cal->min_points_for_cal = MIN_NUM_SPHERE_FIT_POINTS;
- } else {
- sphere_cal->min_points_for_cal = min_num_points_for_cal;
- }
-}
-
-void sphereFitReset(struct SphereFitCal *sphere_cal) {
- ASSERT_NOT_NULL(sphere_cal);
-
- // Set state to default (diagonal scale matrix and zero offset).
- memset(&sphere_cal->x0[0], 0, sizeof(float) * SF_STATE_DIM);
- sphere_cal->x0[eParamScaleMatrix11] = 1.f;
- sphere_cal->x0[eParamScaleMatrix22] = 1.f;
- sphere_cal->x0[eParamScaleMatrix33] = 1.f;
- memcpy(sphere_cal->x, sphere_cal->x0, sizeof(sphere_cal->x));
-
- // Reset time.
- sphere_cal->estimate_time_nanos = 0;
-}
-
-void sphereFitSetSolverData(struct SphereFitCal *sphere_cal,
- struct LmData *lm_data) {
- ASSERT_NOT_NULL(sphere_cal);
- ASSERT_NOT_NULL(lm_data);
-
- // Set solver data.
- lmSolverSetData(&sphere_cal->lm_solver, lm_data);
-}
-
-bool sphereFitRunCal(struct SphereFitCal *sphere_cal,
- const struct SphereFitData *data,
- uint64_t timestamp_nanos) {
- ASSERT_NOT_NULL(sphere_cal);
- ASSERT_NOT_NULL(data);
-
- // Run calibration if have enough points.
- if (data->num_fit_points >= sphere_cal->min_points_for_cal) {
- return runCalibration(sphere_cal, data, timestamp_nanos);
- }
-
- return false;
-}
-
-void sphereFitSetInitialBias(struct SphereFitCal *sphere_cal,
- const float initial_bias[THREE_AXIS_DIM]) {
- ASSERT_NOT_NULL(sphere_cal);
- sphere_cal->x0[eParamOffset1] = initial_bias[0];
- sphere_cal->x0[eParamOffset2] = initial_bias[1];
- sphere_cal->x0[eParamOffset3] = initial_bias[2];
-}
-
-void sphereFitGetLatestCal(const struct SphereFitCal *sphere_cal,
- struct ThreeAxisCalData *cal_data) {
- ASSERT_NOT_NULL(sphere_cal);
- ASSERT_NOT_NULL(cal_data);
- convertStateToCalStruct(sphere_cal->x, cal_data);
- cal_data->calibration_time_nanos = sphere_cal->estimate_time_nanos;
-}
-
-void sphereFitResidAndJacobianFunc(const float *state, const void *f_data,
- float *residual, float *jacobian) {
- ASSERT_NOT_NULL(state);
- ASSERT_NOT_NULL(f_data);
- ASSERT_NOT_NULL(residual);
-
- const struct SphereFitData *data = (const struct SphereFitData*)f_data;
-
- // Verify that expected norm is non-zero, else use default of 1.0.
- float expected_norm = 1.0;
- ASSERT(data->expected_norm > MIN_VALID_DATA_NORM);
- if (data->expected_norm > MIN_VALID_DATA_NORM) {
- expected_norm = data->expected_norm;
- }
-
- // Convert parameters to calibration structure.
- struct ThreeAxisCalData calstruct;
- convertStateToCalStruct(state, &calstruct);
-
- // Compute Jacobian helper matrix if Jacobian requested.
- //
- // J = d(||M(x_data - bias)|| - expected_norm)/dstate
- // = (M(x_data - bias) / ||M(x_data - bias)||) * d(M(x_data - bias))/dstate
- // = x_corr / ||x_corr|| * A
- // A = d(M(x_data - bias))/dstate
- // = [dy/dM11, dy/dM21, dy/dM22, dy/dM31, dy/dM32, dy/dM3,...
- // dy/db1, dy/db2, dy/db3]'
- // where:
- // dy/dM11 = [x_data[0] - bias[0], 0, 0]
- // dy/dM21 = [0, x_data[0] - bias[0], 0]
- // dy/dM22 = [0, x_data[1] - bias[1], 0]
- // dy/dM31 = [0, 0, x_data[0] - bias[0]]
- // dy/dM32 = [0, 0, x_data[1] - bias[1]]
- // dy/dM33 = [0, 0, x_data[2] - bias[2]]
- // dy/db1 = [-scale_factor_x, 0, 0]
- // dy/db2 = [0, -scale_factor_y, 0]
- // dy/db3 = [0, 0, -scale_factor_z]
- float A[SF_STATE_DIM * THREE_AXIS_DIM];
- if (jacobian) {
- memset(jacobian, 0, sizeof(float) * SF_STATE_DIM * data->num_fit_points);
- memset(A, 0, sizeof(A));
- A[0 * SF_STATE_DIM + eParamOffset1] = -calstruct.scale_factor_x;
- A[1 * SF_STATE_DIM + eParamOffset2] = -calstruct.scale_factor_y;
- A[2 * SF_STATE_DIM + eParamOffset3] = -calstruct.scale_factor_z;
- }
-
- // Loop over all data points to compute residual and Jacobian.
- // TODO(dvitus): Use fit_data_std when available to weight residuals.
- float x_corr[THREE_AXIS_DIM];
- float x_bias_corr[THREE_AXIS_DIM];
- size_t i;
- for (i = 0; i < data->num_fit_points; ++i) {
- const float *x_data = &data->fit_data[i * THREE_AXIS_DIM];
-
- // Compute corrected sensor data
- calDataCorrectData(&calstruct, x_data, x_corr);
-
- // Compute norm of x_corr.
- const float norm = vecNorm(x_corr, THREE_AXIS_DIM);
-
- // Compute residual error: f_x = norm - exp_norm
- residual[i] = norm - data->expected_norm;
-
- // Compute Jacobian if valid pointer.
- if (jacobian) {
- if (norm < MIN_VALID_DATA_NORM) {
- return;
- }
- const float scale = 1.f / norm;
-
- // Compute bias corrected data.
- vecSub(x_bias_corr, x_data, calstruct.bias, THREE_AXIS_DIM);
-
- // Populate non-bias terms for A
- A[0 + eParamScaleMatrix11] = x_bias_corr[0];
- A[1 * SF_STATE_DIM + eParamScaleMatrix21] = x_bias_corr[0];
- A[1 * SF_STATE_DIM + eParamScaleMatrix22] = x_bias_corr[1];
- A[2 * SF_STATE_DIM + eParamScaleMatrix31] = x_bias_corr[0];
- A[2 * SF_STATE_DIM + eParamScaleMatrix32] = x_bias_corr[1];
- A[2 * SF_STATE_DIM + eParamScaleMatrix33] = x_bias_corr[2];
-
- // Compute J = x_corr / ||x_corr|| * A
- matTransposeMultiplyVec(&jacobian[i * SF_STATE_DIM], A, x_corr,
- THREE_AXIS_DIM, SF_STATE_DIM);
- vecScalarMulInPlace(&jacobian[i * SF_STATE_DIM], scale, SF_STATE_DIM);
- }
- }
-}
-
-void convertStateToCalStruct(const float x[SF_STATE_DIM],
- struct ThreeAxisCalData *calstruct) {
- memcpy(&calstruct->bias[0], &x[eParamOffset1],
- sizeof(float) * THREE_AXIS_DIM);
- calstruct->scale_factor_x = x[eParamScaleMatrix11];
- calstruct->skew_yx = x[eParamScaleMatrix21];
- calstruct->scale_factor_y = x[eParamScaleMatrix22];
- calstruct->skew_zx = x[eParamScaleMatrix31];
- calstruct->skew_zy = x[eParamScaleMatrix32];
- calstruct->scale_factor_z = x[eParamScaleMatrix33];
-}
-
-bool runCalibration(struct SphereFitCal *sphere_cal,
- const struct SphereFitData *data,
- uint64_t timestamp_nanos) {
- float x_sol[SF_STATE_DIM];
-
- // Run calibration
- const enum LmStatus status = lmSolverSolve(&sphere_cal->lm_solver,
- sphere_cal->x0, (void *)data,
- SF_STATE_DIM, data->num_fit_points,
- x_sol);
-
- // Check if solver was successful
- if (status == RELATIVE_STEP_SUFFICIENTLY_SMALL ||
- status == GRADIENT_SUFFICIENTLY_SMALL) {
- // TODO(dvitus): Check quality of new fit before using.
- // Store new fit.
-#ifdef SPHERE_FIT_DBG_ENABLED
- CAL_DEBUG_LOG(
- "[SPHERE CAL]",
- "Solution found in %d iterations with status %d.\n",
- sphere_cal->lm_solver.num_iter, status);
- CAL_DEBUG_LOG(
- "[SPHERE CAL]",
- "Solution:\n {%s%d.%06d [M(1,1)], %s%d.%06d [M(2,1)], "
- "%s%d.%06d [M(2,2)], \n"
- "%s%d.%06d [M(3,1)], %s%d.%06d [M(3,2)], %s%d.%06d [M(3,3)], \n"
- "%s%d.%06d [b(1)], %s%d.%06d [b(2)], %s%d.%06d [b(3)]}.",
- CAL_ENCODE_FLOAT(x_sol[0], 6), CAL_ENCODE_FLOAT(x_sol[1], 6),
- CAL_ENCODE_FLOAT(x_sol[2], 6), CAL_ENCODE_FLOAT(x_sol[3], 6),
- CAL_ENCODE_FLOAT(x_sol[4], 6), CAL_ENCODE_FLOAT(x_sol[5], 6),
- CAL_ENCODE_FLOAT(x_sol[6], 6), CAL_ENCODE_FLOAT(x_sol[7], 6),
- CAL_ENCODE_FLOAT(x_sol[8], 6));
-#endif
- memcpy(sphere_cal->x, x_sol, sizeof(x_sol));
- sphere_cal->estimate_time_nanos = timestamp_nanos;
- return true;
- } else {
-#ifdef SPHERE_FIT_DBG_ENABLED
- CAL_DEBUG_LOG(
- "[SPHERE CAL]",
- "Solution failed in %d iterations with status %d.\n",
- sphere_cal->lm_solver.num_iter, status);
-#endif
- }
-
- return false;
-}
diff --git a/firmware/os/algos/calibration/common/sphere_fit_calibration.h b/firmware/os/algos/calibration/common/sphere_fit_calibration.h
deleted file mode 100644
index e49f225a..00000000
--- a/firmware/os/algos/calibration/common/sphere_fit_calibration.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/////////////////////////////////////////////////////////////////////////////
-/*
- * This module contains an algorithm for performing a sphere fit calibration.
- * A sphere fit calibration solves the following non-linear least squares
- * problem:
- *
- * arg min || ||M(x - b)|| - exp_norm ||
- * M,b
- *
- * where:
- * x is a 3xN matrix containing N 3-dimensional uncalibrated data points,
- * M is a 3x3 lower diagonal scaling matrix
- * b is a 3x1 offset vector.
- * exp_norm is the expected norm of an individual calibration data point.
- * M and b are solved such that the norm of the calibrated data (M(x - b)) is
- * near exp_norm.
- *
- * This module uses a Levenberg-Marquardt nonlinear least squares solver to find
- * M and b. M is assumed to be a lower diagonal, consisting of 6 parameters.
- *
- */
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_SPHERE_FIT_CALIBRATION_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_SPHERE_FIT_CALIBRATION_H_
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "calibration/common/calibration_data.h"
-#include "common/math/levenberg_marquardt.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define MIN_NUM_SPHERE_FIT_POINTS (14)
-
-// Enum defining the meaning of the state parameters. The 9-parameter
-// sphere fit calibration computes a lower-diagonal scaling matrix (M) and
-// an offset such that:
-// x_corrected = M * (x_impaired - offset)
-enum SphereFitParams {
- eParamScaleMatrix11 = 0,
- eParamScaleMatrix21,
- eParamScaleMatrix22,
- eParamScaleMatrix31,
- eParamScaleMatrix32,
- eParamScaleMatrix33,
- eParamOffset1,
- eParamOffset2,
- eParamOffset3,
- SF_STATE_DIM
-};
-
-// Structure containing the data to be used for the sphere fit calibration.
-struct SphereFitData {
- // Data for fit (assumed to be a matrix of size num_fit_points x SF_DATA_DIM)
- const float *fit_data;
-
- // Pointer to standard deviations of the fit data, used to weight individual
- // data points. Assumed to point to a matrix of dimensions
- // num_fit_points x THREE_AXIS_DIM.
- // If NULL, data will all be used with equal weighting in the fit.
- const float *fit_data_std;
-
- // Number of fit points.
- size_t num_fit_points;
-
- // Expected data norm.
- float expected_norm;
-};
-
-// Structure for a sphere fit calibration, including a non-linear least squares
-// solver and the latest state estimate.
-struct SphereFitCal {
- // Levenberg-Marquardt solver.
- struct LmSolver lm_solver;
-
- // Minimum number of points for computing a calibration.
- size_t min_points_for_cal;
-
- // State estimate.
- float x[SF_STATE_DIM];
- uint64_t estimate_time_nanos;
-
- // Initial state for solver.
- float x0[SF_STATE_DIM];
-};
-
-// Initialize sphere fit calibration structure with solver and fit params.
-void sphereFitInit(struct SphereFitCal *sphere_cal,
- const struct LmParams *lm_params,
- const size_t min_num_points_for_cal);
-
-// Clears state estimate and initial state.
-void sphereFitReset(struct SphereFitCal *sphere_cal);
-
-// Sets data pointer for single solve of the Levenberg-Marquardt solver.
-// Must be called before calling sphereFitRunCal().
-void sphereFitSetSolverData(struct SphereFitCal *sphere_cal,
- struct LmData *lm_data);
-
-// Sends in a set of calibration data and attempts to run calibration.
-// Returns true if a calibration was successfully triggered with this data.
-bool sphereFitRunCal(struct SphereFitCal *sphere_cal,
- const struct SphereFitData *data,
- uint64_t timestamp_nanos);
-
-// Set an initial condition for the bias state.
-void sphereFitSetInitialBias(struct SphereFitCal *sphere_cal,
- const float initial_bias[THREE_AXIS_DIM]);
-
-// Returns the latest calibration data in a ThreeAxisCalData structure.
-void sphereFitGetLatestCal(const struct SphereFitCal *sphere_cal,
- struct ThreeAxisCalData *cal_data);
-
-///////////////// TEST UTILITIES ///////////////////////////////////////////
-// The following functions are exposed in the header for testing only.
-
-// The ResidualAndJacobianFunction for sphere calibration in the
-// Levenberg-Marquardt solver.
-void sphereFitResidAndJacobianFunc(const float *state, const void *f_data,
- float *residual, float *jacobian);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_COMMON_SPHERE_FIT_CALIBRATION_H_
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_cal.c b/firmware/os/algos/calibration/gyroscope/gyro_cal.c
index 1c609551..4e87dc9c 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_cal.c
+++ b/firmware/os/algos/calibration/gyroscope/gyro_cal.c
@@ -15,126 +15,44 @@
*/
#include "calibration/gyroscope/gyro_cal.h"
-
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
#include "calibration/util/cal_log.h"
-#include "common/math/vec.h"
/////// DEFINITIONS AND MACROS ///////////////////////////////////////
// Maximum gyro bias correction (should be set based on expected max bias
// of the given sensor).
-#define MAX_GYRO_BIAS (0.096f) // [rad/sec]
-
-// The time value used to throttle debug messaging.
-#define OVERTEMPCAL_WAIT_TIME_NANOS (250000000)
-
-// Converts units of radians to milli-degrees.
-#define RAD_TO_MILLI_DEGREES (float)(1e3f * 180.0f / M_PI)
-
-// Unit conversion: m/sec^2 to g's.
-#define GRAVITY_TO_G (float)(1e3f * 180.0f / M_PI)
+#define MAX_GYRO_BIAS 0.096f // [rad/sec]
-// Unit conversion: nanoseconds to seconds.
-#define NANOS_TO_SEC (1.0e-9f)
+// Helper constants for converting units.
+#define RAD_TO_MDEG (float)(1e3 * 180.0 / M_PI)
+#define GRAVITY_TO_G (float)(1.0 / 9.80665)
/////// FORWARD DECLARATIONS /////////////////////////////////////////
static void deviceStillnessCheck(struct GyroCal* gyro_cal,
- uint64_t sample_time_nanos);
+ uint64_t sample_time);
-static void computeGyroCal(struct GyroCal* gyro_cal,
- uint64_t calibration_time_nanos);
+static void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time);
-static void checkWatchdog(struct GyroCal* gyro_cal, uint64_t sample_time_nanos);
+static void checkWatchdog(struct GyroCal* gyro_cal, uint64_t sample_time);
#ifdef GYRO_CAL_DBG_ENABLED
-static void gyroCalUpdateDebug(struct GyroCal* gyro_cal);
-
-/*
- * Updates running calculation of the temperature statistics.
- *
- * Behavior:
- * 1) If 'debug_temperature' pointer is not NULL then the local calculation
- * of the temperature statistics are copied, and the function returns.
- * 2) Else, if 'reset_stats' is 'true' then the local statistics are reset
- * and the function returns.
- * 3) Otherwise, the local temperature statistics are updated according to
- * the input value 'temperature'.
- *
- * INPUTS:
- * debug_temperature: Pointer to the temperature stats sturcture to update.
- * temperature: Temperature value (Celsius).
- * reset_stats: Flag that determines if the local running stats are reset.
- */
-static void gyroTempUpdateStats(struct DebugTemperature* debug_temperature,
- float temperature, bool reset_stats);
+static void gyroCalUpdateDebug(struct GyroCal* gyro_cal,
+ struct DebugGyroCal* debug_gyro_cal);
-/*
- * Updates running calculation of the gyro's mean sampling rate.
- *
- * Behavior:
- * 1) If 'debug_mean_sampling_rate_hz' pointer is not NULL then the local
- * calculation of the sampling rate is copied, and the function returns.
- * 2) Else, if 'reset_stats' is 'true' then the local estimate is reset and
- * the function returns.
- * 3) Otherwise, the local estimate of the mean sampling rates is updated.
- *
- * INPUTS:
- * debug_mean_sampling_rate_hz: Pointer to the mean sampling rate to update.
- * timestamp_nanos: Time stamp (nanoseconds).
- * reset_stats: Flag that signals a reset of the sampling rate estimate.
- */
-static void gyroSamplingRateUpdate(float* debug_mean_sampling_rate_hz,
- uint64_t timestamp_nanos, bool reset_stats);
-
-// Defines the type of debug data to print.
-enum DebugPrintData {
- BIAS_CAL = 0,
- CAL_TIME,
- ACCEL_STATS,
- GYRO_STATS,
- MAG_STATS,
- TEMP_STATS,
- STILLNESS_DATA,
- SAMPLING_RATE
-};
-
-// Helper function for printing out common debug data.
-static void gyroCalDebugPrintData(const struct DebugGyroCal* debug_data,
- enum DebugPrintData print_data);
-
-// This conversion function is necessary for Nanohub firmware compilation (i.e.,
-// can't cast a uint64_t to a float directly). This conversion function was
-// copied from: /third_party/contexthub/firmware/src/floatRt.c
-static float floatFromUint64(uint64_t v)
-{
- uint32_t hi = v >> 32, lo = v;
-
- if (!hi) //this is very fast for cases where we fit into a uint32_t
- return(float)lo;
- else {
- return ((float)hi) * 4294967296.0f + (float)lo;
- }
-}
+static void gyroCalTuneDebugPrint(struct GyroCal* gyro_cal,
+ uint64_t sample_time);
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
-// Prints debug information useful for tuning the GyroCal parameters.
-static void gyroCalTuneDebugPrint(const struct GyroCal* gyro_cal,
- uint64_t timestamp_nanos);
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
-#endif // GYRO_CAL_DBG_ENABLED
+static void gyroCalDebugPrintData(int count, struct DebugGyroCal* debug_data);
+#endif
/////// FUNCTION DEFINITIONS /////////////////////////////////////////
// Initialize the gyro calibration data structure.
-void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration_nanos,
- uint64_t max_still_duration_nanos, float bias_x, float bias_y,
- float bias_z, uint64_t calibration_time_nanos,
- uint64_t window_time_duration_nanos, float gyro_var_threshold,
+void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration,
+ uint64_t max_still_duration, float bias_x, float bias_y,
+ float bias_z, uint64_t calibration_time,
+ uint64_t window_time_duration, float gyro_var_threshold,
float gyro_confidence_delta, float accel_var_threshold,
float accel_confidence_delta, float mag_var_threshold,
float mag_confidence_delta, float stillness_threshold,
@@ -143,9 +61,9 @@ void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration_nanos,
memset(gyro_cal, 0, sizeof(struct GyroCal));
// Initialize the stillness detectors.
- // Gyro parameter input units are [rad/sec].
- // Accel parameter input units are [m/sec^2].
- // Magnetometer parameter input units are [uT].
+ // Gyro parameter input units are [rad/sec]
+ // Accel parameter input units are [m/sec^2]
+ // Magnetometer parameter input units are [uT]
gyroStillDetInit(&gyro_cal->gyro_stillness_detect, gyro_var_threshold,
gyro_confidence_delta);
gyroStillDetInit(&gyro_cal->accel_stillness_detect, accel_var_threshold,
@@ -155,24 +73,23 @@ void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration_nanos,
// Reset stillness flag and start timestamp.
gyro_cal->prev_still = false;
- gyro_cal->start_still_time_nanos = 0;
+ gyro_cal->start_still_time = 0;
// Set the min and max window stillness duration.
- gyro_cal->min_still_duration_nanos = min_still_duration_nanos;
- gyro_cal->max_still_duration_nanos = max_still_duration_nanos;
+ gyro_cal->min_still_duration = min_still_duration;
+ gyro_cal->max_still_duration = max_still_duration;
// Sets the duration of the stillness processing windows.
- gyro_cal->window_time_duration_nanos = window_time_duration_nanos;
+ gyro_cal->window_time_duration = window_time_duration;
// Set the watchdog timeout duration.
- gyro_cal->gyro_watchdog_timeout_duration_nanos =
- 2 * window_time_duration_nanos;
+ gyro_cal->gyro_watchdog_timeout_duration = 2 * window_time_duration;
// Load the last valid cal from system memory.
gyro_cal->bias_x = bias_x; // [rad/sec]
gyro_cal->bias_y = bias_y; // [rad/sec]
gyro_cal->bias_z = bias_z; // [rad/sec]
- gyro_cal->calibration_time_nanos = calibration_time_nanos;
+ gyro_cal->calibration_time = calibration_time;
// Set the stillness threshold required for gyro bias calibration.
gyro_cal->stillness_threshold = stillness_threshold;
@@ -181,36 +98,26 @@ void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration_nanos,
// collection in sync. Setting this to zero signals that sensor data
// will be dropped until a valid end time is set from the first gyro
// timestamp received.
- gyro_cal->stillness_win_endtime_nanos = 0;
+ gyro_cal->stillness_win_endtime = 0;
// Gyro calibrations will be applied (see, gyroCalRemoveBias()).
gyro_cal->gyro_calibration_enable = (remove_bias_enable > 0);
#ifdef GYRO_CAL_DBG_ENABLED
- CAL_DEBUG_LOG("[GYRO_CAL:MEMORY]", "sizeof(struct GyroCal): %lu",
- (unsigned long int)sizeof(struct GyroCal));
-
- CAL_DEBUG_LOG("[GYRO_CAL:INIT]",
- "Gyro Bias Calibration [mdps]: %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 6));
-
- if (gyro_cal->gyro_calibration_enable) {
- CAL_DEBUG_LOG("[GYRO_CAL:INIT]", "Online gyroscope calibration ENABLED.");
- } else {
- CAL_DEBUG_LOG("[GYRO_CAL:INIT]", "Online gyroscope calibration DISABLED.");
- }
-
- // Ensures that the running temperature statistics and gyro sampling rate
- // estimate are reset.
- gyroTempUpdateStats(NULL, 0, /*reset_stats=*/true);
- gyroSamplingRateUpdate(NULL, 0, /*reset_stats=*/true);
-#endif // GYRO_CAL_DBG_ENABLED
+ CAL_DEBUG_LOG("[GYRO_CAL]", "Gyro Cal: Initialized.");
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "GyroCalInit = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [mdps]\n",
+ CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MDEG, 6));
+
+ // Initialize the debug report state machine.
+ gyro_cal->gyro_debug_state = -1;
+#endif
}
-// Void all pointers in the gyro calibration data structure (doesn't do anything
-// except prevent compiler warnings).
+// Void all pointers in the gyro calibration data structure
+// (prevents compiler warnings).
void gyroCalDestroy(struct GyroCal* gyro_cal) { (void)gyro_cal; }
// Get the most recent bias calibration value.
@@ -220,32 +127,23 @@ void gyroCalGetBias(struct GyroCal* gyro_cal, float* bias_x, float* bias_y,
*bias_x = gyro_cal->bias_x;
*bias_y = gyro_cal->bias_y;
*bias_z = gyro_cal->bias_z;
-
-#ifdef GYRO_CAL_DBG_ENABLED
- CAL_DEBUG_LOG(
- "[GYRO_CAL:STORED]",
- "Gyro Bias Calibration [mdps]: %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 6));
-#endif
}
}
// Set an initial bias calibration value.
void gyroCalSetBias(struct GyroCal* gyro_cal, float bias_x, float bias_y,
- float bias_z, uint64_t calibration_time_nanos) {
+ float bias_z, uint64_t calibration_time) {
gyro_cal->bias_x = bias_x;
gyro_cal->bias_y = bias_y;
gyro_cal->bias_z = bias_z;
- gyro_cal->calibration_time_nanos = calibration_time_nanos;
+ gyro_cal->calibration_time = calibration_time;
#ifdef GYRO_CAL_DBG_ENABLED
- CAL_DEBUG_LOG("[GYRO_CAL:RECALL]",
- "Gyro Bias Calibration [mdps]: %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 6));
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "GyroCalSetBias = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [mdps]\n",
+ CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MDEG, 6));
#endif
}
@@ -271,74 +169,60 @@ bool gyroCalNewBiasAvailable(struct GyroCal* gyro_cal) {
}
// Update the gyro calibration with gyro data [rad/sec].
-void gyroCalUpdateGyro(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
- float x, float y, float z, float temperature) {
+void gyroCalUpdateGyro(struct GyroCal* gyro_cal, uint64_t sample_time, float x,
+ float y, float z, float temperature) {
// Make sure that a valid window end time is set,
// and start the watchdog timer.
- if (gyro_cal->stillness_win_endtime_nanos <= 0) {
- gyro_cal->stillness_win_endtime_nanos =
- sample_time_nanos + gyro_cal->window_time_duration_nanos;
+ if (gyro_cal->stillness_win_endtime <= 0) {
+ gyro_cal->stillness_win_endtime =
+ sample_time + gyro_cal->window_time_duration;
// Start the watchdog timer.
- gyro_cal->gyro_watchdog_start_nanos = sample_time_nanos;
+ gyro_cal->gyro_watchdog_start = sample_time;
}
-#ifdef GYRO_CAL_DBG_ENABLED
- // Update the temperature statistics (on temperature change only).
- if (NANO_ABS(gyro_cal->latest_temperature_celcius - temperature) > FLT_MIN) {
- gyroTempUpdateStats(NULL, temperature, /*reset_stats=*/false);
- }
-
- // Update the gyro sampling rate estimate.
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/false);
-#endif // GYRO_CAL_DBG_ENABLED
-
// Record the latest temperture sample.
gyro_cal->latest_temperature_celcius = temperature;
// Pass gyro data to stillness detector
gyroStillDetUpdate(&gyro_cal->gyro_stillness_detect,
- gyro_cal->stillness_win_endtime_nanos, sample_time_nanos,
- x, y, z);
+ gyro_cal->stillness_win_endtime, sample_time, x, y, z);
// Perform a device stillness check, set next window end time, and
// possibly do a gyro bias calibration and stillness detector reset.
- deviceStillnessCheck(gyro_cal, sample_time_nanos);
+ deviceStillnessCheck(gyro_cal, sample_time);
}
// Update the gyro calibration with mag data [micro Tesla].
-void gyroCalUpdateMag(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
- float x, float y, float z) {
+void gyroCalUpdateMag(struct GyroCal* gyro_cal, uint64_t sample_time, float x,
+ float y, float z) {
// Pass magnetometer data to stillness detector.
gyroStillDetUpdate(&gyro_cal->mag_stillness_detect,
- gyro_cal->stillness_win_endtime_nanos, sample_time_nanos,
- x, y, z);
+ gyro_cal->stillness_win_endtime, sample_time, x, y, z);
// Received a magnetometer sample; incorporate it into detection.
gyro_cal->using_mag_sensor = true;
// Perform a device stillness check, set next window end time, and
// possibly do a gyro bias calibration and stillness detector reset.
- deviceStillnessCheck(gyro_cal, sample_time_nanos);
+ deviceStillnessCheck(gyro_cal, sample_time);
}
// Update the gyro calibration with accel data [m/sec^2].
-void gyroCalUpdateAccel(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
- float x, float y, float z) {
+void gyroCalUpdateAccel(struct GyroCal* gyro_cal, uint64_t sample_time, float x,
+ float y, float z) {
// Pass accelerometer data to stillnesss detector.
gyroStillDetUpdate(&gyro_cal->accel_stillness_detect,
- gyro_cal->stillness_win_endtime_nanos, sample_time_nanos,
- x, y, z);
+ gyro_cal->stillness_win_endtime, sample_time, x, y, z);
// Perform a device stillness check, set next window end time, and
// possibly do a gyro bias calibration and stillness detector reset.
- deviceStillnessCheck(gyro_cal, sample_time_nanos);
+ deviceStillnessCheck(gyro_cal, sample_time);
}
// Checks the state of all stillness detectors to determine
// whether the device is "still".
-void deviceStillnessCheck(struct GyroCal* gyro_cal,
- uint64_t sample_time_nanos) {
+void deviceStillnessCheck(struct GyroCal* gyro_cal, uint64_t sample_time) {
bool stillness_duration_exceeded = false;
bool stillness_duration_too_short = false;
bool device_is_still = false;
@@ -347,7 +231,7 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
float conf_still = 0;
// Check the watchdog timer.
- checkWatchdog(gyro_cal, sample_time_nanos);
+ checkWatchdog(gyro_cal, sample_time);
// Is there enough data to do a stillness calculation?
if ((!gyro_cal->mag_stillness_detect.stillness_window_ready &&
@@ -358,8 +242,8 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
}
// Set the next window end time for the stillness detectors.
- gyro_cal->stillness_win_endtime_nanos =
- sample_time_nanos + gyro_cal->window_time_duration_nanos;
+ gyro_cal->stillness_win_endtime =
+ sample_time + gyro_cal->window_time_duration;
// Update the confidence scores for all sensors.
gyroStillDetCompute(&gyro_cal->accel_stillness_detect);
@@ -390,15 +274,15 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
if (!gyro_cal->prev_still) {
// Record the starting timestamp of the current stillness window.
// This enables the calculation of total duration of the stillness period.
- gyro_cal->start_still_time_nanos =
+ gyro_cal->start_still_time =
gyro_cal->gyro_stillness_detect.window_start_time;
}
- // Check to see if current stillness period exceeds the desired limit.
+ // Check to see if current stillness period exceeds the desired limit
+ // to avoid corrupting the .
stillness_duration_exceeded =
((gyro_cal->gyro_stillness_detect.last_sample_time -
- gyro_cal->start_still_time_nanos) >
- gyro_cal->max_still_duration_nanos);
+ gyro_cal->start_still_time) > gyro_cal->max_still_duration);
if (stillness_duration_exceeded) {
// The current stillness has gone too long. Do a calibration with the
@@ -406,32 +290,23 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
// Update the gyro bias estimate with the current window data and
// reset the stats.
- gyroStillDetReset(&gyro_cal->accel_stillness_detect,
- /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->gyro_stillness_detect, /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->mag_stillness_detect, /*reset_stats=*/true);
+ gyroStillDetReset(&gyro_cal->accel_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->gyro_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->mag_stillness_detect, true);
// Perform calibration.
computeGyroCal(gyro_cal,
gyro_cal->gyro_stillness_detect.last_sample_time);
-#ifdef GYRO_CAL_DBG_ENABLED
- // Reset the temperature statistics and sampling rate estimate.
- gyroTempUpdateStats(NULL, 0, /*reset_stats=*/true);
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
-#endif // GYRO_CAL_DBG_ENABLED
-
// Update stillness flag. Force the start of a new stillness period.
gyro_cal->prev_still = false;
} else {
// Continue collecting stillness data.
// Reset stillness detectors, and extend stillness period.
- gyroStillDetReset(&gyro_cal->accel_stillness_detect,
- /*reset_stats=*/false);
- gyroStillDetReset(&gyro_cal->gyro_stillness_detect,
- /*reset_stats=*/false);
- gyroStillDetReset(&gyro_cal->mag_stillness_detect, /*reset_stats=*/false);
+ gyroStillDetReset(&gyro_cal->accel_stillness_detect, false);
+ gyroStillDetReset(&gyro_cal->gyro_stillness_detect, false);
+ gyroStillDetReset(&gyro_cal->mag_stillness_detect, false);
// Update stillness flag.
gyro_cal->prev_still = true;
@@ -443,8 +318,7 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
// "too short", then do a calibration with the data accumulated thus far.
stillness_duration_too_short =
((gyro_cal->gyro_stillness_detect.window_start_time -
- gyro_cal->start_still_time_nanos) <
- gyro_cal->min_still_duration_nanos);
+ gyro_cal->start_still_time) < gyro_cal->min_still_duration);
if (gyro_cal->prev_still && !stillness_duration_too_short) {
computeGyroCal(gyro_cal,
@@ -452,29 +326,28 @@ void deviceStillnessCheck(struct GyroCal* gyro_cal,
}
// Reset stillness detectors and the stats.
- gyroStillDetReset(&gyro_cal->accel_stillness_detect, /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->gyro_stillness_detect, /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->mag_stillness_detect, /*reset_stats=*/true);
-
-#ifdef GYRO_CAL_DBG_ENABLED
- // Reset the temperature statistics and sampling rate estimate.
- gyroTempUpdateStats(NULL, 0, /*reset_stats=*/true);
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
-#endif // GYRO_CAL_DBG_ENABLED
+ gyroStillDetReset(&gyro_cal->accel_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->gyro_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->mag_stillness_detect, true);
// Update stillness flag.
gyro_cal->prev_still = false;
}
// Reset the watchdog timer after we have processed data.
- gyro_cal->gyro_watchdog_start_nanos = sample_time_nanos;
+ gyro_cal->gyro_watchdog_start = sample_time;
+
+#ifdef GYRO_CAL_DBG_ENABLED
+ // Debug information available.
+ gyro_cal->debug_processed_data_available = true;
+ gyro_cal->debug_processed_data_time = sample_time;
+#endif
}
// Calculates a new gyro bias offset calibration value.
-void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time_nanos) {
+void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time) {
// Current calibration duration.
- uint64_t cur_cal_dur_nanos =
- calibration_time_nanos - gyro_cal->start_still_time_nanos;
+ uint64_t cur_cal_dur = calibration_time - gyro_cal->start_still_time;
// Check to see if new calibration values is within acceptable range.
if (!(gyro_cal->gyro_stillness_detect.prev_mean_x < MAX_GYRO_BIAS &&
@@ -483,15 +356,6 @@ void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time_nanos) {
gyro_cal->gyro_stillness_detect.prev_mean_y > -MAX_GYRO_BIAS &&
gyro_cal->gyro_stillness_detect.prev_mean_z < MAX_GYRO_BIAS &&
gyro_cal->gyro_stillness_detect.prev_mean_z > -MAX_GYRO_BIAS)) {
-#ifdef GYRO_CAL_DBG_ENABLED
- CAL_DEBUG_LOG(
- "[GYRO_CAL:WARNING]",
- "Rejected Bias Update [mdps]: %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 6));
-#endif // GYRO_CAL_DBG_ENABLED
-
// Outside of range. Ignore, reset, and continue.
return;
}
@@ -508,10 +372,10 @@ void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time_nanos) {
gyro_cal->mag_stillness_detect.prev_stillness_confidence;
// Store calibration stillness duration.
- gyro_cal->calibration_time_duration_nanos = cur_cal_dur_nanos;
+ gyro_cal->calibration_time_duration = cur_cal_dur;
// Store calibration time stamp.
- gyro_cal->calibration_time_nanos = calibration_time_nanos;
+ gyro_cal->calibration_time = calibration_time;
// Set flag to indicate a new gyro calibration value is available.
gyro_cal->new_gyro_cal_available = true;
@@ -520,42 +384,62 @@ void computeGyroCal(struct GyroCal* gyro_cal, uint64_t calibration_time_nanos) {
// Increment the total count of calibration updates.
gyro_cal->debug_calibration_count++;
+ // Store the last 'DEBUG_GYRO_SHORTTERM_NUM_CAL' calibration debug data
+ // in a circular buffer, 'debug_cal_data[]'. 'debug_head' is the index
+ // of the last valid calibration.
+ gyro_cal->debug_head++;
+ if (gyro_cal->debug_head >= DEBUG_GYRO_SHORTTERM_NUM_CAL) {
+ gyro_cal->debug_head = 0;
+ }
+ if (gyro_cal->debug_num_cals < DEBUG_GYRO_SHORTTERM_NUM_CAL) {
+ gyro_cal->debug_num_cals++;
+ }
+
// Update the calibration debug information.
- gyroCalUpdateDebug(gyro_cal);
+ gyroCalUpdateDebug(gyro_cal, &gyro_cal->debug_cal_data[gyro_cal->debug_head]);
+
+ // Improve the collection of historic calibrations. Limit frequency to
+ // every N hours.
+ if ((gyro_cal->debug_num_cals_hist <= 0) ||
+ (calibration_time -
+ gyro_cal->debug_cal_data_hist[gyro_cal->debug_head_hist]
+ .calibration_time) >= DEBUG_GYRO_CAL_LIMIT) {
+ gyro_cal->debug_head_hist++;
+ if (gyro_cal->debug_head_hist >= DEBUG_GYRO_LONGTERM_NUM_CAL) {
+ gyro_cal->debug_head_hist = 0;
+ }
+ if (gyro_cal->debug_num_cals_hist < DEBUG_GYRO_LONGTERM_NUM_CAL) {
+ gyro_cal->debug_num_cals_hist++;
+ }
- // Trigger a printout of the debug information.
- gyro_cal->debug_print_trigger = true;
+ // Update the calibration debug information.
+ gyroCalUpdateDebug(
+ gyro_cal, &gyro_cal->debug_cal_data_hist[gyro_cal->debug_head_hist]);
+ }
#endif
}
// Check for a watchdog timeout condition.
-void checkWatchdog(struct GyroCal* gyro_cal, uint64_t sample_time_nanos) {
+void checkWatchdog(struct GyroCal* gyro_cal, uint64_t sample_time) {
bool watchdog_timeout;
// Check for initialization of the watchdog time (=0).
- if (gyro_cal->gyro_watchdog_start_nanos <= 0) {
+ if (gyro_cal->gyro_watchdog_start <= 0) {
return;
}
// Check for timeout condition of watchdog.
- watchdog_timeout =
- ((sample_time_nanos - gyro_cal->gyro_watchdog_start_nanos) >
- gyro_cal->gyro_watchdog_timeout_duration_nanos);
+ watchdog_timeout = ((sample_time - gyro_cal->gyro_watchdog_start) >
+ gyro_cal->gyro_watchdog_timeout_duration);
// If a timeout occurred then reset to known good state.
if (watchdog_timeout) {
// Reset stillness detectors and restart data capture.
- gyroStillDetReset(&gyro_cal->accel_stillness_detect, /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->gyro_stillness_detect, /*reset_stats=*/true);
- gyroStillDetReset(&gyro_cal->mag_stillness_detect, /*reset_stats=*/true);
+ gyroStillDetReset(&gyro_cal->accel_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->gyro_stillness_detect, true);
+ gyroStillDetReset(&gyro_cal->mag_stillness_detect, true);
gyro_cal->mag_stillness_detect.stillness_confidence = 0;
- gyro_cal->stillness_win_endtime_nanos = 0;
-
-#ifdef GYRO_CAL_DBG_ENABLED
- // Reset the temperature statistics and sampling rate estimate.
- gyroTempUpdateStats(NULL, 0, /*reset_stats=*/true);
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
-#endif // GYRO_CAL_DBG_ENABLED
+ gyro_cal->stillness_win_endtime = 0;
// Force stillness confidence to zero.
gyro_cal->accel_stillness_detect.prev_stillness_confidence = 0;
@@ -573,596 +457,340 @@ void checkWatchdog(struct GyroCal* gyro_cal, uint64_t sample_time_nanos) {
// Assert watchdog timeout flags.
gyro_cal->gyro_watchdog_timeout |= watchdog_timeout;
- gyro_cal->gyro_watchdog_start_nanos = 0;
+ gyro_cal->gyro_watchdog_start = 0;
#ifdef GYRO_CAL_DBG_ENABLED
gyro_cal->debug_watchdog_count++;
- CAL_DEBUG_LOG("[GYRO_CAL:WATCHDOG]", "Total#, Timestamp [nsec]: %lu, %llu",
- (unsigned long int)gyro_cal->debug_watchdog_count,
- (unsigned long long int)sample_time_nanos);
#endif
}
}
#ifdef GYRO_CAL_DBG_ENABLED
-void gyroCalUpdateDebug(struct GyroCal* gyro_cal) {
+// Update the calibration debug information.
+void gyroCalUpdateDebug(struct GyroCal* gyro_cal,
+ struct DebugGyroCal* debug_gyro_cal) {
// Probability of stillness (acc, rot, still), duration, timestamp.
- gyro_cal->debug_gyro_cal.accel_stillness_conf =
+ debug_gyro_cal->accel_stillness_conf =
gyro_cal->accel_stillness_detect.prev_stillness_confidence;
- gyro_cal->debug_gyro_cal.gyro_stillness_conf =
+ debug_gyro_cal->gyro_stillness_conf =
gyro_cal->gyro_stillness_detect.prev_stillness_confidence;
- gyro_cal->debug_gyro_cal.mag_stillness_conf =
+ debug_gyro_cal->mag_stillness_conf =
gyro_cal->mag_stillness_detect.prev_stillness_confidence;
// Magnetometer usage.
- gyro_cal->debug_gyro_cal.using_mag_sensor = gyro_cal->using_mag_sensor;
+ debug_gyro_cal->used_mag_sensor = gyro_cal->using_mag_sensor;
// Temperature at calibration time.
- gyro_cal->debug_gyro_cal.temperature_celcius =
- gyro_cal->latest_temperature_celcius;
-
- // Stillness start, stop, and duration times.
- gyro_cal->debug_gyro_cal.start_still_time_nanos =
- gyro_cal->start_still_time_nanos;
- gyro_cal->debug_gyro_cal.end_still_time_nanos =
- gyro_cal->calibration_time_nanos;
- gyro_cal->debug_gyro_cal.stillness_duration_nanos =
- gyro_cal->calibration_time_duration_nanos;
-
- // Records the current calibration values.
- gyro_cal->debug_gyro_cal.calibration[0] = gyro_cal->bias_x;
- gyro_cal->debug_gyro_cal.calibration[1] = gyro_cal->bias_y;
- gyro_cal->debug_gyro_cal.calibration[2] = gyro_cal->bias_z;
-
- // Records the complete temperature statistics.
- gyroTempUpdateStats(&gyro_cal->debug_gyro_cal.debug_temperature, 0,
- /*reset_stats=*/true);
- gyroSamplingRateUpdate(&gyro_cal->debug_gyro_cal.mean_sampling_rate_hz, 0,
- /*reset_stats=*/true);
-
- // Records the previous window means.
- gyro_cal->debug_gyro_cal.accel_mean[0] =
- gyro_cal->accel_stillness_detect.prev_mean_x;
- gyro_cal->debug_gyro_cal.accel_mean[1] =
- gyro_cal->accel_stillness_detect.prev_mean_y;
- gyro_cal->debug_gyro_cal.accel_mean[2] =
- gyro_cal->accel_stillness_detect.prev_mean_z;
-
- gyro_cal->debug_gyro_cal.gyro_mean[0] =
- gyro_cal->gyro_stillness_detect.prev_mean_x;
- gyro_cal->debug_gyro_cal.gyro_mean[1] =
- gyro_cal->gyro_stillness_detect.prev_mean_y;
- gyro_cal->debug_gyro_cal.gyro_mean[2] =
- gyro_cal->gyro_stillness_detect.prev_mean_z;
-
- gyro_cal->debug_gyro_cal.mag_mean[0] =
- gyro_cal->mag_stillness_detect.prev_mean_x;
- gyro_cal->debug_gyro_cal.mag_mean[1] =
- gyro_cal->mag_stillness_detect.prev_mean_y;
- gyro_cal->debug_gyro_cal.mag_mean[2] =
- gyro_cal->mag_stillness_detect.prev_mean_z;
-
- // Records the variance data.
- gyro_cal->debug_gyro_cal.accel_var[0] =
- gyro_cal->accel_stillness_detect.win_var_x;
- gyro_cal->debug_gyro_cal.accel_var[1] =
- gyro_cal->accel_stillness_detect.win_var_y;
- gyro_cal->debug_gyro_cal.accel_var[2] =
- gyro_cal->accel_stillness_detect.win_var_z;
-
- gyro_cal->debug_gyro_cal.gyro_var[0] =
- gyro_cal->gyro_stillness_detect.win_var_x;
- gyro_cal->debug_gyro_cal.gyro_var[1] =
- gyro_cal->gyro_stillness_detect.win_var_y;
- gyro_cal->debug_gyro_cal.gyro_var[2] =
- gyro_cal->gyro_stillness_detect.win_var_z;
-
- gyro_cal->debug_gyro_cal.mag_var[0] =
- gyro_cal->mag_stillness_detect.win_var_x;
- gyro_cal->debug_gyro_cal.mag_var[1] =
- gyro_cal->mag_stillness_detect.win_var_y;
- gyro_cal->debug_gyro_cal.mag_var[2] =
- gyro_cal->mag_stillness_detect.win_var_z;
+ debug_gyro_cal->temperature_celcius = gyro_cal->latest_temperature_celcius;
+
+ // Calibration time and stillness duration.
+ debug_gyro_cal->calibration_time_duration =
+ gyro_cal->calibration_time_duration;
+ debug_gyro_cal->calibration_time = gyro_cal->calibration_time;
+
+ // Record the current calibration values
+ debug_gyro_cal->calibration[0] = gyro_cal->bias_x;
+ debug_gyro_cal->calibration[1] = gyro_cal->bias_y;
+ debug_gyro_cal->calibration[2] = gyro_cal->bias_z;
+
+ // Record the previous window means
+ debug_gyro_cal->accel_mean[0] = gyro_cal->accel_stillness_detect.prev_mean_x;
+ debug_gyro_cal->accel_mean[1] = gyro_cal->accel_stillness_detect.prev_mean_y;
+ debug_gyro_cal->accel_mean[2] = gyro_cal->accel_stillness_detect.prev_mean_z;
+
+ debug_gyro_cal->gyro_mean[0] = gyro_cal->gyro_stillness_detect.prev_mean_x;
+ debug_gyro_cal->gyro_mean[1] = gyro_cal->gyro_stillness_detect.prev_mean_y;
+ debug_gyro_cal->gyro_mean[2] = gyro_cal->gyro_stillness_detect.prev_mean_z;
+
+ debug_gyro_cal->mag_mean[0] = gyro_cal->mag_stillness_detect.prev_mean_x;
+ debug_gyro_cal->mag_mean[1] = gyro_cal->mag_stillness_detect.prev_mean_y;
+ debug_gyro_cal->mag_mean[2] = gyro_cal->mag_stillness_detect.prev_mean_z;
+
+ // Record the variance data.
+ debug_gyro_cal->accel_var[0] = gyro_cal->accel_stillness_detect.win_var_x;
+ debug_gyro_cal->accel_var[1] = gyro_cal->accel_stillness_detect.win_var_y;
+ debug_gyro_cal->accel_var[2] = gyro_cal->accel_stillness_detect.win_var_z;
+
+ debug_gyro_cal->gyro_var[0] = gyro_cal->gyro_stillness_detect.win_var_x;
+ debug_gyro_cal->gyro_var[1] = gyro_cal->gyro_stillness_detect.win_var_y;
+ debug_gyro_cal->gyro_var[2] = gyro_cal->gyro_stillness_detect.win_var_z;
+
+ debug_gyro_cal->mag_var[0] = gyro_cal->mag_stillness_detect.win_var_x;
+ debug_gyro_cal->mag_var[1] = gyro_cal->mag_stillness_detect.win_var_y;
+ debug_gyro_cal->mag_var[2] = gyro_cal->mag_stillness_detect.win_var_z;
}
-void gyroTempUpdateStats(struct DebugTemperature* debug_temperature,
- float temperature, bool reset_stats) {
- // Using the method of the assumed mean to preserve some numerical stability
- // while avoiding per-sample divisions that the more numerically stable
- // Welford method would afford.
-
- // Reference for the numerical method used below to compute the online mean
- // and variance statistics:
- // 1). en.wikipedia.org/wiki/assumed_mean
-
- // This is used for local calculations of temperature statistics.
- static struct DebugTemperature local_temperature_stats = {0};
- static bool set_assumed_mean = true;
-
- // If 'debug_temperature' is not NULL then this function just reads out the
- // current statistics, resets, and returns.
- if (debug_temperature) {
- if (local_temperature_stats.num_temperature_samples > 1) {
- // Computes the final calculation of temperature sensor mean and variance.
- float tmp = local_temperature_stats.temperature_mean_celsius;
- local_temperature_stats.temperature_mean_celsius /=
- local_temperature_stats.num_temperature_samples;
- local_temperature_stats.temperature_var_celsius =
- (local_temperature_stats.temperature_var_celsius -
- local_temperature_stats.temperature_mean_celsius * tmp) /
- (local_temperature_stats.num_temperature_samples - 1);
-
- // Adds the assumed mean value back to the total mean calculation.
- local_temperature_stats.temperature_mean_celsius +=
- local_temperature_stats.assumed_mean;
- } else {
- // Not enough samples to compute a valid variance. Indicate this with a -1
- // value.
- local_temperature_stats.temperature_var_celsius = -1.0f;
- }
-
- memcpy(debug_temperature, &local_temperature_stats,
- sizeof(struct DebugTemperature));
- reset_stats = true;
+// Helper function to print debug statements.
+void gyroCalDebugPrintData(int count, struct DebugGyroCal* debug_data) {
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL]",
+ "#%d Gyro Bias Calibration = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [mdps]\n",
+ count, CAL_ENCODE_FLOAT(debug_data->calibration[0] * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(debug_data->calibration[1] * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(debug_data->calibration[2] * RAD_TO_MDEG, 6));
+
+ if (debug_data->used_mag_sensor) {
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Using Magnetometer.\n");
+ } else {
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Not Using Magnetometer.\n");
}
- // Resets the temperature statistics and returns.
- if (reset_stats) {
- local_temperature_stats.num_temperature_samples = 0;
- local_temperature_stats.temperature_mean_celsius = 0.0f;
- local_temperature_stats.temperature_var_celsius = 0.0f;
- set_assumed_mean = true; // Sets flag.
-
- // Initialize the min/max temperatures values.
- local_temperature_stats.temperature_min_max_celsius[0] = FLT_MAX;
- local_temperature_stats.temperature_min_max_celsius[1] =
- -1.0f * (FLT_MAX - 1.0f);
- return;
- }
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Temperature = %s%d.%06d [C]\n",
+ CAL_ENCODE_FLOAT(debug_data->temperature_celcius, 6));
- // The first sample received is taken as the "assumed mean".
- if (set_assumed_mean) {
- local_temperature_stats.assumed_mean = temperature;
- set_assumed_mean = false; // Resets flag.
- }
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Calibration Timestamp = %llu [nsec]\n",
+ debug_data->calibration_time);
- // Increments the number of samples.
- local_temperature_stats.num_temperature_samples++;
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Stillness Duration = %llu [nsec]\n",
+ debug_data->calibration_time_duration);
- // Online computation of mean and variance for the running stillness period.
- float delta = (temperature - local_temperature_stats.assumed_mean);
- local_temperature_stats.temperature_var_celsius += delta * delta;
- local_temperature_stats.temperature_mean_celsius += delta;
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ " Accel Mean = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [g]\n",
+ CAL_ENCODE_FLOAT(debug_data->accel_mean[0] * GRAVITY_TO_G, 6),
+ CAL_ENCODE_FLOAT(debug_data->accel_mean[1] * GRAVITY_TO_G, 6),
+ CAL_ENCODE_FLOAT(debug_data->accel_mean[2] * GRAVITY_TO_G, 6));
- // Track the min and max temperature values.
- if (local_temperature_stats.temperature_min_max_celsius[0] > temperature) {
- local_temperature_stats.temperature_min_max_celsius[0] = temperature;
- }
- if (local_temperature_stats.temperature_min_max_celsius[1] < temperature) {
- local_temperature_stats.temperature_min_max_celsius[1] = temperature;
- }
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ " Mag Mean = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [uT]\n",
+ CAL_ENCODE_FLOAT(debug_data->mag_mean[0], 6),
+ CAL_ENCODE_FLOAT(debug_data->mag_mean[1], 6),
+ CAL_ENCODE_FLOAT(debug_data->mag_mean[2], 6));
}
-void gyroSamplingRateUpdate(float* debug_mean_sampling_rate_hz,
- uint64_t timestamp_nanos, bool reset_stats) {
- // This is used for local calculations of average sampling rate.
- static uint64_t last_timestamp_nanos = 0;
- static uint64_t time_delta_accumulator = 0;
- static size_t num_samples = 0;
-
- // If 'debug_mean_sampling_rate_hz' is not NULL then this function just reads
- // out the estimate of the sampling rate.
- if (debug_mean_sampling_rate_hz) {
- if (num_samples > 1 && time_delta_accumulator > 0) {
- // Computes the final mean calculation.
- *debug_mean_sampling_rate_hz =
- num_samples /
- (floatFromUint64(time_delta_accumulator) * NANOS_TO_SEC);
- } else {
- // Not enough samples to compute a valid sample rate estimate. Indicate
- // this with a -1 value.
- *debug_mean_sampling_rate_hz = -1.0f;
- }
- reset_stats = true;
- }
-
- // Resets the sampling rate mean estimator data if:
- // 1. The 'reset_stats' flag is set.
- // 2. A bad timestamp was received (i.e., time not monotonic).
- // 3. 'last_timestamp_nanos' is zero.
- if (reset_stats || (timestamp_nanos <= last_timestamp_nanos) ||
- last_timestamp_nanos == 0) {
- last_timestamp_nanos = timestamp_nanos;
- time_delta_accumulator = 0;
- num_samples = 0;
- return;
- }
-
- // Increments the number of samples.
- num_samples++;
+// Print Debug data useful for tuning the stillness detectors.
+void gyroCalTuneDebugPrint(struct GyroCal* gyro_cal, uint64_t sample_time) {
+ static uint64_t start_time = 0;
- // Accumulate the time steps.
- time_delta_accumulator += timestamp_nanos - last_timestamp_nanos;
- last_timestamp_nanos = timestamp_nanos;
-}
-
-void gyroCalDebugPrintData(const struct DebugGyroCal* debug_data,
- enum DebugPrintData print_data) {
- // Prints out the desired debug data.
- float mag_data;
- switch (print_data) {
- case BIAS_CAL:
- CAL_DEBUG_LOG(
- "[GYRO_CAL:BIAS]",
- "Gyro Bias Calibration [mdps]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->calibration[0] * RAD_TO_MILLI_DEGREES,
- 8),
- CAL_ENCODE_FLOAT(debug_data->calibration[1] * RAD_TO_MILLI_DEGREES,
- 8),
- CAL_ENCODE_FLOAT(debug_data->calibration[2] * RAD_TO_MILLI_DEGREES,
- 8));
- break;
-
- case CAL_TIME:
- CAL_DEBUG_LOG("[GYRO_CAL:TIME]", "Stillness Start Time [nsec]: %llu",
- (unsigned long long int)debug_data->start_still_time_nanos);
-
- CAL_DEBUG_LOG("[GYRO_CAL:TIME]", "Stillness End Time [nsec]: %llu",
- (unsigned long long int)debug_data->end_still_time_nanos);
-
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TIME]", "Stillness Duration [nsec]: %llu",
- (unsigned long long int)debug_data->stillness_duration_nanos);
- break;
-
- case ACCEL_STATS:
- CAL_DEBUG_LOG("[GYRO_CAL:ACCEL_STATS]",
- "Accel Mean [m/sec^2]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->accel_mean[0], 8),
- CAL_ENCODE_FLOAT(debug_data->accel_mean[1], 8),
- CAL_ENCODE_FLOAT(debug_data->accel_mean[2], 8));
- CAL_DEBUG_LOG(
- "[GYRO_CAL:ACCEL_STATS]",
- "Accel Variance [(m/sec^2)^2]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->accel_var[0], 8),
- CAL_ENCODE_FLOAT(debug_data->accel_var[1], 8),
- CAL_ENCODE_FLOAT(debug_data->accel_var[2], 8));
- break;
-
- case GYRO_STATS:
- CAL_DEBUG_LOG(
- "[GYRO_CAL:GYRO_STATS]",
- "Gyro Mean [mdps]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->gyro_mean[0] * RAD_TO_MILLI_DEGREES, 8),
- CAL_ENCODE_FLOAT(debug_data->gyro_mean[1] * RAD_TO_MILLI_DEGREES, 8),
- CAL_ENCODE_FLOAT(debug_data->gyro_mean[2] * RAD_TO_MILLI_DEGREES, 8));
+ // Output sensor variance levels to assist with tuning thresholds.
+ // i. Within the first 60 seconds of boot: output interval = 5 seconds.
+ // ii. Thereafter: output interval is set by DEBUG_GYRO_TUNE_UPDATES.
+ bool condition_i = ((sample_time <= 60000000000) &&
+ ((sample_time - start_time) > 5000000000)); // nsec
+ bool condition_ii = ((sample_time > 60000000000) &&
+ ((sample_time - start_time) > DEBUG_GYRO_TUNE_UPDATES));
+
+ if (condition_i || condition_ii) {
+ CAL_DEBUG_LOG("[GYRO_CAL]", "");
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL]",
+ "#%lu Gyro Bias Calibration = {%s%d.%06d, %s%d.%06d, %s%d.%06d} "
+ "[mdps]\n",
+ gyro_cal->debug_calibration_count,
+ CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MDEG, 6));
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL]",
+ " Gyro Variance = {%s%d.%08d, %s%d.%08d, %s%d.%08d} [rad/sec]^2\n",
+ CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_x, 8),
+ CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_y, 8),
+ CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_z, 8));
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL]",
+ " Accel Variance = {%s%d.%08d, %s%d.%08d, %s%d.%08d} [m/sec^2]^2\n",
+ CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_x, 8),
+ CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_y, 8),
+ CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_z, 8));
+ if (gyro_cal->using_mag_sensor) {
CAL_DEBUG_LOG(
- "[GYRO_CAL:GYRO_STATS]",
- "Gyro Variance [(rad/sec)^2]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->gyro_var[0], 8),
- CAL_ENCODE_FLOAT(debug_data->gyro_var[1], 8),
- CAL_ENCODE_FLOAT(debug_data->gyro_var[2], 8));
- break;
-
- case MAG_STATS:
- if (debug_data->using_mag_sensor) {
- CAL_DEBUG_LOG("[GYRO_CAL:MAG_STATS]",
- "Mag Mean [uT]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->mag_mean[0], 8),
- CAL_ENCODE_FLOAT(debug_data->mag_mean[1], 8),
- CAL_ENCODE_FLOAT(debug_data->mag_mean[2], 8));
- CAL_DEBUG_LOG("[GYRO_CAL:MAG_STATS]",
- "Mag Variance [uT^2]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->mag_var[0], 8),
- CAL_ENCODE_FLOAT(debug_data->mag_var[1], 8),
- CAL_ENCODE_FLOAT(debug_data->mag_var[2], 8));
- } else {
- CAL_DEBUG_LOG("[GYRO_CAL:MAG_STATS]", "Mag Mean [uT]: 0, 0, 0");
- // The -1's indicate that the magnetometer sensor was not used.
- CAL_DEBUG_LOG("[GYRO_CAL:MAG_STATS]",
- "Mag Variance [uT^2]: -1.0, -1.0, -1.0");
- }
- break;
-
- case TEMP_STATS:
- CAL_DEBUG_LOG("[GYRO_CAL:TEMP_STATS]",
- "Latest Temperature [C]: %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->temperature_celcius, 8));
+ "[GYRO_CAL]",
+ " Mag Variance = {%s%d.%06d, %s%d.%06d, %s%d.%06d} [uT]^2\n",
+ CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_x, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_y, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_z, 6));
CAL_DEBUG_LOG(
- "[GYRO_CAL:TEMP_STATS]",
- "Min/Max Temperature [C]: %s%d.%08d, %s%d.%08d",
+ "[GYRO_CAL]", " Stillness = {G%s%d.%06d, A%s%d.%06d, M%s%d.%06d}\n",
CAL_ENCODE_FLOAT(
- debug_data->debug_temperature.temperature_min_max_celsius[0], 8),
+ gyro_cal->gyro_stillness_detect.stillness_confidence, 6),
CAL_ENCODE_FLOAT(
- debug_data->debug_temperature.temperature_min_max_celsius[1], 8));
+ gyro_cal->accel_stillness_detect.stillness_confidence, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.stillness_confidence,
+ 6));
+ } else {
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Mag Variance = {---, ---, ---} [uT]^2\n");
CAL_DEBUG_LOG(
- "[GYRO_CAL:TEMP_STATS]", "Temperature Mean [C]: %s%d.%08d",
+ "[GYRO_CAL]", " Stillness = {G%s%d.%06d, A%s%d.%06d, M---}\n",
CAL_ENCODE_FLOAT(
- debug_data->debug_temperature.temperature_mean_celsius, 8));
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TEMP_STATS]", "Temperature Variance [C^2]: %s%d.%08d",
+ gyro_cal->gyro_stillness_detect.stillness_confidence, 6),
CAL_ENCODE_FLOAT(
- debug_data->debug_temperature.temperature_var_celsius, 8));
- break;
-
- case STILLNESS_DATA:
- mag_data = (debug_data->using_mag_sensor)
- ? debug_data->mag_stillness_conf
- : -1.0f; // Signals that magnetometer was not used.
- CAL_DEBUG_LOG("[GYRO_CAL:STILLNESS]",
- "Stillness [G/A/M]: %s%d.%08d, %s%d.%08d, %s%d.%08d",
- CAL_ENCODE_FLOAT(debug_data->gyro_stillness_conf, 8),
- CAL_ENCODE_FLOAT(debug_data->accel_stillness_conf, 8),
- CAL_ENCODE_FLOAT(mag_data, 8));
- break;
+ gyro_cal->accel_stillness_detect.stillness_confidence, 6));
+ }
- case SAMPLING_RATE:
- CAL_DEBUG_LOG("[GYRO_CAL:SAMPLING_RATE]",
- "Gyro Sampling Rate [Hz]: %s%d.%06d",
- CAL_ENCODE_FLOAT(
- debug_data->mean_sampling_rate_hz, 6));
- break;
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Temperature = %s%d.%06d [C]\n",
+ CAL_ENCODE_FLOAT(gyro_cal->latest_temperature_celcius, 6));
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Timestamp = %llu [nsec]\n", sample_time);
+ CAL_DEBUG_LOG("[GYRO_CAL]", " Total Gyro Calibrations: %lu\n",
+ gyro_cal->debug_calibration_count);
+ start_time = sample_time; // reset
+ }
+}
- default:
- break;
+// Start the debug data report state machine.
+void gyroCalDebugPrintStart(struct GyroCal* gyro_cal) {
+ if (gyro_cal->gyro_debug_state < 0) { // if currently in idle state.
+ gyro_cal->gyro_debug_state = 0; // start printing.
}
}
-// Debug printout state enumeration.
-enum GyroCalDebugState {
- IDLE = 0,
- WAIT_STATE,
- PRINT_BIAS,
- PRINT_TIME,
- PRINT_TEMP,
- PRINT_ACCEL,
- PRINT_GYRO,
- PRINT_MAG,
- PRINT_STILLNESS,
- PRINT_SAMPLING_RATE
-};
-
-void gyroCalDebugPrint(struct GyroCal* gyro_cal, uint64_t timestamp_nanos) {
- static enum GyroCalDebugState debug_state = IDLE;
- static enum GyroCalDebugState next_state = IDLE;
- static uint64_t wait_timer_nanos = 0;
-
- // This is a state machine that controls the reporting out of debug data.
- switch (debug_state) {
- case IDLE:
- // Wait for a trigger and start the debug printout sequence.
- if (gyro_cal->debug_print_trigger) {
- debug_state = PRINT_BIAS;
+// Print Debug data report.
+void gyroCalDebugPrint(struct GyroCal* gyro_cal, uint64_t sample_time) {
+ static int head_index = 0;
+ static uint64_t wait_timer = 0;
+ static int i = 0;
+ static int next_state = 0;
+
+ // State machine to control reporting out debug print data.
+ switch (gyro_cal->gyro_debug_state) {
+ case 0:
+ // STATE 0 : Print out header
+ if (gyro_cal->debug_num_cals == 0) {
CAL_DEBUG_LOG("[GYRO_CAL]", "");
- gyro_cal->debug_print_trigger = false; // Resets trigger.
+ CAL_DEBUG_LOG("[GYRO_CAL]", "No Gyro Calibrations To Report.\n");
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL]",
+ "#0 Gyro Bias Calibration = {%s%d.%06d, %s%d.%06d, %s%d.%06d} "
+ "[mdps]\n",
+ CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MDEG, 6),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MDEG, 6));
+ wait_timer = sample_time; // start the wait timer.
+ gyro_cal->gyro_debug_state = 7; // go to next state.
} else {
- debug_state = IDLE;
+ CAL_DEBUG_LOG("[GYRO_CAL]", "");
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "---DEBUG REPORT-------------------------------------\n");
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "Gyro Calibrations To Report (newest to oldest): %d\n",
+ gyro_cal->debug_num_cals);
+ head_index = gyro_cal->debug_head;
+ i = 1; // initialize report count
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 1; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
}
break;
- case WAIT_STATE:
- // This helps throttle the print statements.
- if ((timestamp_nanos - wait_timer_nanos) >= OVERTEMPCAL_WAIT_TIME_NANOS) {
- debug_state = next_state;
+ case 1:
+ // STATE 1: Print out past N recent calibrations.
+ if (i <= gyro_cal->debug_num_cals) {
+ // Print the data.
+ gyroCalDebugPrintData(i, &gyro_cal->debug_cal_data[head_index]);
+
+ // Move to the previous calibration data set.
+ head_index--;
+ if (head_index < 0) {
+ head_index = DEBUG_GYRO_SHORTTERM_NUM_CAL - 1;
+ }
+
+ // Increment the report count.
+ i++;
+
+ // Go to wait state.
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 1; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
+ } else {
+ // Go to wait state.
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 3; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
}
break;
- case PRINT_BIAS:
- CAL_DEBUG_LOG("[GYRO_CAL:BIAS]", "Total # Calibrations: %lu",
- (unsigned long int)gyro_cal->debug_calibration_count);
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, BIAS_CAL);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_TIME; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_TIME:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, CAL_TIME);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_TEMP; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_TEMP:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, TEMP_STATS);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_ACCEL; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_ACCEL:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, ACCEL_STATS);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_GYRO; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_GYRO:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, GYRO_STATS);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_MAG; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
+ case 2:
+ // STATE 2 : Wait state.
+ // Wait for 500msec.
+ // This helps throttle the print statements.
+ if ((sample_time - wait_timer) >= 500000000) {
+ gyro_cal->gyro_debug_state = next_state;
+ }
break;
- case PRINT_MAG:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, MAG_STATS);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_STILLNESS; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
+ case 3:
+ // STATE 3 : Print the end of the debug report.
+ CAL_DEBUG_LOG("[GYRO_CAL]", "Total Gyro Calibrations: %lu\n",
+ gyro_cal->debug_calibration_count);
- case PRINT_STILLNESS:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, STILLNESS_DATA);
+ CAL_DEBUG_LOG("[GYRO_CAL]", "Total Watchdog Timeouts: %lu\n",
+ gyro_cal->debug_watchdog_count);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_SAMPLING_RATE; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "---END DEBUG REPORT---------------------------------\n");
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 4; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
break;
- case PRINT_SAMPLING_RATE:
- gyroCalDebugPrintData(&gyro_cal->debug_gyro_cal, SAMPLING_RATE);
- debug_state = IDLE;
+ case 4:
+ // STATE 4 : Print out header (historic data)
+ CAL_DEBUG_LOG("[GYRO_CAL]", "");
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "---DEBUG REPORT (HISTORY)---------------------------\n");
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "Gyro Calibrations To Report (newest to oldest): %d\n",
+ gyro_cal->debug_num_cals_hist);
+ head_index = gyro_cal->debug_head_hist;
+ i = 1; // initialize report count
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 5; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
break;
- default:
- // Sends this state machine to its idle state.
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = IDLE; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- }
-
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
- if (debug_state == IDLE) {
- // This check keeps the tuning printout from interleaving with the above
- // debug print data.
- gyroCalTuneDebugPrint(gyro_cal, timestamp_nanos);
- }
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
-}
-
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
-void gyroCalTuneDebugPrint(const struct GyroCal* gyro_cal,
- uint64_t timestamp_nanos) {
- static enum GyroCalDebugState debug_state = IDLE;
- static enum GyroCalDebugState next_state = IDLE;
- static uint64_t wait_timer_nanos = 0;
-
- // Output sensor variance levels to assist with tuning thresholds.
- // i. Within the first 180 seconds of boot: output interval = 5
- // seconds.
- // ii. Thereafter: output interval is 60 seconds.
- bool condition_i =
- ((timestamp_nanos <= 180000000000) &&
- ((timestamp_nanos - wait_timer_nanos) > 5000000000)); // nsec
- bool condition_ii = ((timestamp_nanos > 60000000000) &&
- ((timestamp_nanos - wait_timer_nanos) > 60000000000));
-
- // This is a state machine that controls the reporting out of debug data.
- switch (debug_state) {
- case IDLE:
- // Wait for a trigger and start the debug printout sequence.
- if (condition_i || condition_ii) {
- debug_state = PRINT_BIAS;
+ case 5:
+ // STATE 5: Print out past N historic calibrations.
+ if (i <= gyro_cal->debug_num_cals_hist) {
+ // Print the data.
+ gyroCalDebugPrintData(i, &gyro_cal->debug_cal_data_hist[head_index]);
+
+ // Move to the previous calibration data set.
+ head_index--;
+ if (head_index < 0) {
+ head_index = DEBUG_GYRO_LONGTERM_NUM_CAL - 1;
+ }
+
+ // Increment the report count.
+ i++;
+
+ // Go to wait state.
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 5; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
} else {
- debug_state = IDLE;
+ // Go to wait state.
+ wait_timer = sample_time; // start the wait timer.
+ next_state = 6; // set the next state.
+ gyro_cal->gyro_debug_state = 2; // but first, go to wait state.
}
break;
- case WAIT_STATE:
- // This helps throttle the print statements.
- if ((timestamp_nanos - wait_timer_nanos) >= OVERTEMPCAL_WAIT_TIME_NANOS) {
- debug_state = next_state;
- }
- break;
-
- case PRINT_BIAS:
- CAL_DEBUG_LOG("[GYRO_CAL]", "");
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- "#%lu Gyro Bias Calibration = {%s%d.%06d, %s%d.%06d, %s%d.%06d} "
- "[mdps]\n",
- (unsigned long int)gyro_cal->debug_calibration_count,
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 6));
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_TIME; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_TIME:
- CAL_DEBUG_LOG("[GYRO_CAL:TUNE]", " Timestamp = %llu [nsec]\n",
- (unsigned long long int)timestamp_nanos);
- CAL_DEBUG_LOG("[GYRO_CAL:TUNE]", " Total Gyro Calibrations: %lu\n",
- (unsigned long int)gyro_cal->debug_calibration_count);
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_TEMP; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_TEMP:
- CAL_DEBUG_LOG("[GYRO_CAL:TUNE]", " Temperature = %s%d.%06d [C]\n",
- CAL_ENCODE_FLOAT(gyro_cal->latest_temperature_celcius, 6));
+ case 6:
+ // STATE 6 : Print the end of the debug report.
+ CAL_DEBUG_LOG("[GYRO_CAL]", "Total Gyro Calibrations: %lu\n",
+ gyro_cal->debug_calibration_count);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_ACCEL; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
+ CAL_DEBUG_LOG("[GYRO_CAL]", "Total Watchdog Timeouts: %lu\n",
+ gyro_cal->debug_watchdog_count);
- case PRINT_ACCEL:
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- " Accel Variance = {%s%d.%08d, %s%d.%08d, %s%d.%08d} "
- "[m/sec^2]^2\n",
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_x, 8),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_y, 8),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_z, 8));
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_GYRO; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
+ CAL_DEBUG_LOG("[GYRO_CAL]",
+ "---END DEBUG REPORT---------------------------------\n");
+ wait_timer = sample_time; // start the wait timer.
+ gyro_cal->gyro_debug_state = 7; // go to next state.
break;
- case PRINT_GYRO:
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- " Gyro Variance = {%s%d.%08d, %s%d.%08d, %s%d.%08d} [rad/sec]^2\n",
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_x, 8),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_y, 8),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_z, 8));
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_MAG; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_MAG:
- if (gyro_cal->using_mag_sensor) {
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- " Mag Variance = {%s%d.%08d, %s%d.%08d, %s%d.%08d} [uT]^2\n",
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_x, 8),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_y, 8),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_z, 8));
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- " Stillness = {G%s%d.%03d, A%s%d.%03d, M%s%d.%03d}\n",
- CAL_ENCODE_FLOAT(
- gyro_cal->gyro_stillness_detect.stillness_confidence, 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->accel_stillness_detect.stillness_confidence, 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->mag_stillness_detect.stillness_confidence, 3));
- } else {
- CAL_DEBUG_LOG("[GYRO_CAL:TUNE]",
- " Mag Variance = {---, ---, ---} [uT]^2\n");
- CAL_DEBUG_LOG(
- "[GYRO_CAL:TUNE]",
- " Stillness = {G%s%d.%03d, A%s%d.%03d, M---}\n",
- CAL_ENCODE_FLOAT(
- gyro_cal->gyro_stillness_detect.stillness_confidence, 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->accel_stillness_detect.stillness_confidence, 3));
+ case 7:
+ // STATE 7 : Final wait state.
+ // Wait for 10 seconds.
+ // This helps throttle the print statements.
+ if ((sample_time - wait_timer) >= 10000000000) {
+ gyro_cal->gyro_debug_state = -1;
}
-
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = IDLE; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
break;
default:
- // Sends this state machine to its idle state.
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = IDLE; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
+ // Idle state.
+ gyro_cal->gyro_debug_state = -1;
+
+ // Report periodic data useful for tuning the stillness detectors.
+ gyroCalTuneDebugPrint(gyro_cal, sample_time);
}
}
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
-#endif // GYRO_CAL_DBG_ENABLED
+#endif
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_cal.h b/firmware/os/algos/calibration/gyroscope/gyro_cal.h
index 4b5a9c44..f5a9109b 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_cal.h
+++ b/firmware/os/algos/calibration/gyroscope/gyro_cal.h
@@ -1,3 +1,6 @@
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_CAL_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_CAL_H_
+
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -14,6 +17,7 @@
* limitations under the License.
*/
+///////////////////////////////////////////////////////////////
/*
* This module contains the algorithms for producing a
* gyroscope offset calibration. The algorithm looks
@@ -37,14 +41,8 @@
* Optional Sensors and Units:
* - Magnetometer [micro-Tesla, uT]
* - Temperature [Celcius]
- *
- * #define GYRO_CAL_DBG_ENABLED to enable debug printout statements.
- * #define GYRO_CAL_DBG_TUNE_ENABLED to periodically printout sensor variance
- * data to assist in tuning the GyroCal parameters.
*/
-
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_CAL_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_CAL_H_
+///////////////////////////////////////////////////////////////
#include "calibration/gyroscope/gyro_stillness_detect.h"
@@ -53,26 +51,21 @@ extern "C" {
#endif
#ifdef GYRO_CAL_DBG_ENABLED
-// Temperature debug statistics.
-struct DebugTemperature {
- size_t num_temperature_samples;
- float temperature_min_max_celsius[2];
- float temperature_mean_celsius;
- float temperature_var_celsius;
- float assumed_mean;
-};
+// Debug: Number of past calibrations to store.
+#define DEBUG_GYRO_SHORTTERM_NUM_CAL 30
+#define DEBUG_GYRO_LONGTERM_NUM_CAL 30
+#define DEBUG_GYRO_CAL_LIMIT 7200000000000 // 2hours [nsec]
+#define DEBUG_GYRO_TUNE_UPDATES 120000000000 // 120sec [nsec]
// Gyro Cal debug information/data tracking structure.
struct DebugGyroCal {
- struct DebugTemperature debug_temperature;
- uint64_t start_still_time_nanos;
- uint64_t end_still_time_nanos;
- uint64_t stillness_duration_nanos;
- float mean_sampling_rate_hz;
float temperature_celcius;
float accel_stillness_conf;
float gyro_stillness_conf;
float mag_stillness_conf;
+ uint64_t calibration_time;
+ uint64_t calibration_time_duration;
+ bool used_mag_sensor;
float calibration[3];
float accel_mean[3];
float gyro_mean[3];
@@ -80,7 +73,6 @@ struct DebugGyroCal {
float accel_var[3];
float gyro_var[3];
float mag_var[3];
- bool using_mag_sensor;
};
#endif
@@ -90,6 +82,13 @@ struct GyroCal {
struct GyroStillDet mag_stillness_detect;
struct GyroStillDet gyro_stillness_detect;
+ // Flag is "true" when the magnetometer is used.
+ bool using_mag_sensor;
+
+ // Flag set by user to control whether calibrations are used
+ // (default: "true").
+ bool gyro_calibration_enable;
+
// Latest temperature measurement.
float latest_temperature_celcius;
@@ -97,63 +96,65 @@ struct GyroCal {
float stillness_threshold;
// Min and max durations for gyro bias calibration.
- uint64_t min_still_duration_nanos;
- uint64_t max_still_duration_nanos;
+ uint64_t min_still_duration;
+ uint64_t max_still_duration;
// Duration of the stillness processing windows.
- uint64_t window_time_duration_nanos;
+ uint64_t window_time_duration;
+
+ // Flag to indicate if device was previously still.
+ bool prev_still;
// Timestamp when device started a still period.
- uint64_t start_still_time_nanos;
+ uint64_t start_still_time;
// gyro bias estimates and last calibration timestamp.
float bias_x, bias_y, bias_z; // [rad/sec]
- uint64_t calibration_time_nanos;
- uint64_t calibration_time_duration_nanos;
+ uint64_t calibration_time;
+ uint64_t calibration_time_duration;
float stillness_confidence;
+ bool new_gyro_cal_available; // true when a new cal is ready.
// Current window end time for all sensors. Used to assist in keeping
// sensor data collection in sync. On initialization this will be set to
// zero indicating that sensor data will be dropped until a valid end time
// is set from the first gyro timestamp received.
- uint64_t stillness_win_endtime_nanos;
+ uint64_t stillness_win_endtime;
// Watchdog timer to reset to a known good state when data capture stalls.
- uint64_t gyro_watchdog_start_nanos;
- uint64_t gyro_watchdog_timeout_duration_nanos;
+ uint64_t gyro_watchdog_start;
+ uint64_t gyro_watchdog_timeout_duration;
bool gyro_watchdog_timeout;
- // Flag is "true" when the magnetometer is used.
- bool using_mag_sensor;
-
- // Flag set by user to control whether calibrations are used (default:
- // "true").
- bool gyro_calibration_enable;
-
- // Flag is 'true' when a new calibration update is ready.
- bool new_gyro_cal_available;
-
- // Flag to indicate if device was previously still.
- bool prev_still;
-
//----------------------------------------------------------------
#ifdef GYRO_CAL_DBG_ENABLED
// Debug info.
- struct DebugGyroCal debug_gyro_cal; // Debug data structure.
- size_t debug_calibration_count; // Total number of cals performed.
- size_t debug_watchdog_count; // Total number of watchdog timeouts.
- bool debug_print_trigger; // Flag used to trigger data printout.
-#endif // GYRO_CAL_DBG_ENABLED
+ bool debug_processed_data_available; // flag on a per window basis.
+ uint64_t debug_processed_data_time; // flag time stamp.
+ uint32_t debug_calibration_count; // total number of cals performed.
+ uint32_t debug_watchdog_count; // total number of watchdog timeouts.
+ int8_t gyro_debug_state; // debug report state machine.
+
+ // Debug short-term history data.
+ struct DebugGyroCal debug_cal_data[DEBUG_GYRO_SHORTTERM_NUM_CAL];
+ uint8_t debug_num_cals; // number of calibrations collected.
+ uint8_t debug_head; // index of last valid calibration.
+
+ // Debug long-term history data (limited collection frequency).
+ struct DebugGyroCal debug_cal_data_hist[DEBUG_GYRO_LONGTERM_NUM_CAL];
+ uint8_t debug_num_cals_hist; // number of calibrations collected.
+ uint8_t debug_head_hist; // index of last valid calibration.
+#endif
};
/////// FUNCTION PROTOTYPES //////////////////////////////////////////
// Initialize the gyro calibration data structure.
void gyroCalInit(struct GyroCal* gyro_cal, uint64_t min_still_duration,
- uint64_t max_still_duration_nanos, float bias_x, float bias_y,
- float bias_z, uint64_t calibration_time_nanos,
- uint64_t window_time_duration_nanos, float gyro_var_threshold,
+ uint64_t max_still_duration, float bias_x, float bias_y,
+ float bias_z, uint64_t calibration_time,
+ uint64_t window_time_duration, float gyro_var_threshold,
float gyro_confidence_delta, float accel_var_threshold,
float accel_confidence_delta, float mag_var_threshold,
float mag_confidence_delta, float stillness_threshold,
@@ -168,7 +169,7 @@ void gyroCalGetBias(struct GyroCal* gyro_cal, float* bias_x, float* bias_y,
// Set an initial bias calibration value.
void gyroCalSetBias(struct GyroCal* gyro_cal, float bias_x, float bias_y,
- float bias_z, uint64_t calibration_time_nanos);
+ float bias_z, uint64_t calibration_time);
// Remove gyro bias from the calibration [rad/sec].
void gyroCalRemoveBias(struct GyroCal* gyro_cal, float xi, float yi, float zi,
@@ -178,21 +179,23 @@ void gyroCalRemoveBias(struct GyroCal* gyro_cal, float xi, float yi, float zi,
bool gyroCalNewBiasAvailable(struct GyroCal* gyro_cal);
// Update the gyro calibration with gyro data [rad/sec].
-void gyroCalUpdateGyro(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
+void gyroCalUpdateGyro(struct GyroCal* gyro_cal, uint64_t sample_time,
float x, float y, float z, float temperature);
// Update the gyro calibration with mag data [micro Tesla].
-void gyroCalUpdateMag(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
- float x, float y, float z);
+void gyroCalUpdateMag(struct GyroCal* gyro_cal, uint64_t sample_time, float x,
+ float y, float z);
// Update the gyro calibration with accel data [m/sec^2].
-void gyroCalUpdateAccel(struct GyroCal* gyro_cal, uint64_t sample_time_nanos,
+void gyroCalUpdateAccel(struct GyroCal* gyro_cal, uint64_t sample_time,
float x, float y, float z);
#ifdef GYRO_CAL_DBG_ENABLED
+// Start the debug data report state machine.
+void gyroCalDebugPrintStart(struct GyroCal* gyro_cal);
+
// Print debug data report.
-void gyroCalDebugPrint(struct GyroCal* gyro_cal,
- uint64_t timestamp_nanos_nanos);
+void gyroCalDebugPrint(struct GyroCal* gyro_cal, uint64_t sample_time);
#endif
#ifdef __cplusplus
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.c b/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.c
index afddb481..12763b08 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.c
+++ b/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.c
@@ -52,7 +52,7 @@ void gyroStillDetUpdate(struct GyroStillDet* gyro_still_det,
float x, float y, float z) {
// Using the method of the assumed mean to preserve some numerical
// stability while avoiding per-sample divisions that the more
- // numerically stable Welford method would afford.
+ // numerically stabe Welford method would afford.
// Reference for the numerical method used below to compute the
// online mean and variance statistics:
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.h b/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.h
index 9a1d876c..9ddc9075 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.h
+++ b/firmware/os/algos/calibration/gyroscope/gyro_stillness_detect.h
@@ -1,3 +1,6 @@
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_STILLNESS_DETECT_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_STILLNESS_DETECT_H_
+
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -30,8 +33,6 @@
* are nanoseconds.
*/
///////////////////////////////////////////////////////////////
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_STILLNESS_DETECT_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_GYROSCOPE_GYRO_STILLNESS_DETECT_H_
#include <math.h>
#include <stdbool.h>
diff --git a/firmware/os/algos/calibration/magnetometer/mag_cal.c b/firmware/os/algos/calibration/magnetometer/mag_cal.c
index bd4876ca..340d021e 100644
--- a/firmware/os/algos/calibration/magnetometer/mag_cal.c
+++ b/firmware/os/algos/calibration/magnetometer/mag_cal.c
@@ -30,18 +30,16 @@
#define MAX_BATCH_WINDOW 15000000UL // 15 sec
#define MIN_BATCH_SIZE 25 // samples
-#define MAX_DISTANCE_VIOLATIONS 2
-
// eigen value magnitude and ratio test
-static int moc_eigen_test(struct KasaFit *kasa) {
+static int moc_eigen_test(struct MagCal *moc) {
// covariance matrix
struct Mat33 S;
- S.elem[0][0] = kasa->acc_xx - kasa->acc_x * kasa->acc_x;
- S.elem[0][1] = S.elem[1][0] = kasa->acc_xy - kasa->acc_x * kasa->acc_y;
- S.elem[0][2] = S.elem[2][0] = kasa->acc_xz - kasa->acc_x * kasa->acc_z;
- S.elem[1][1] = kasa->acc_yy - kasa->acc_y * kasa->acc_y;
- S.elem[1][2] = S.elem[2][1] = kasa->acc_yz - kasa->acc_y * kasa->acc_z;
- S.elem[2][2] = kasa->acc_zz - kasa->acc_z * kasa->acc_z;
+ S.elem[0][0] = moc->acc_xx - moc->acc_x * moc->acc_x;
+ S.elem[0][1] = S.elem[1][0] = moc->acc_xy - moc->acc_x * moc->acc_y;
+ S.elem[0][2] = S.elem[2][0] = moc->acc_xz - moc->acc_x * moc->acc_z;
+ S.elem[1][1] = moc->acc_yy - moc->acc_y * moc->acc_y;
+ S.elem[1][2] = S.elem[2][1] = moc->acc_yz - moc->acc_y * moc->acc_z;
+ S.elem[2][2] = moc->acc_zz - moc->acc_z * moc->acc_z;
struct Vec3 eigenvals;
struct Mat33 eigenvecs;
@@ -62,29 +60,29 @@ static int moc_eigen_test(struct KasaFit *kasa) {
}
// Kasa sphere fitting with normal equation
-int magKasaFit(struct KasaFit *kasa, struct Vec3 *bias, float *radius) {
+int magCalFit(struct MagCal *moc, struct Vec3 *bias, float *radius) {
// A * out = b
// (4 x 4) (4 x 1) (4 x 1)
struct Mat44 A;
- A.elem[0][0] = kasa->acc_xx;
- A.elem[0][1] = kasa->acc_xy;
- A.elem[0][2] = kasa->acc_xz;
- A.elem[0][3] = kasa->acc_x;
- A.elem[1][0] = kasa->acc_xy;
- A.elem[1][1] = kasa->acc_yy;
- A.elem[1][2] = kasa->acc_yz;
- A.elem[1][3] = kasa->acc_y;
- A.elem[2][0] = kasa->acc_xz;
- A.elem[2][1] = kasa->acc_yz;
- A.elem[2][2] = kasa->acc_zz;
- A.elem[2][3] = kasa->acc_z;
- A.elem[3][0] = kasa->acc_x;
- A.elem[3][1] = kasa->acc_y;
- A.elem[3][2] = kasa->acc_z;
+ A.elem[0][0] = moc->acc_xx;
+ A.elem[0][1] = moc->acc_xy;
+ A.elem[0][2] = moc->acc_xz;
+ A.elem[0][3] = moc->acc_x;
+ A.elem[1][0] = moc->acc_xy;
+ A.elem[1][1] = moc->acc_yy;
+ A.elem[1][2] = moc->acc_yz;
+ A.elem[1][3] = moc->acc_y;
+ A.elem[2][0] = moc->acc_xz;
+ A.elem[2][1] = moc->acc_yz;
+ A.elem[2][2] = moc->acc_zz;
+ A.elem[2][3] = moc->acc_z;
+ A.elem[3][0] = moc->acc_x;
+ A.elem[3][1] = moc->acc_y;
+ A.elem[3][2] = moc->acc_z;
A.elem[3][3] = 1.0f;
struct Vec4 b;
- initVec4(&b, -kasa->acc_xw, -kasa->acc_yw, -kasa->acc_zw, -kasa->acc_w);
+ initVec4(&b, -moc->acc_xw, -moc->acc_yw, -moc->acc_zw, -moc->acc_w);
struct Size4 pivot;
mat44DecomposeLup(&A, &pivot);
@@ -114,18 +112,13 @@ int magKasaFit(struct KasaFit *kasa, struct Vec3 *bias, float *radius) {
return success;
}
-void magKasaReset(struct KasaFit *kasa) {
- kasa->acc_x = kasa->acc_y = kasa->acc_z = kasa->acc_w = 0.0f;
- kasa->acc_xx = kasa->acc_xy = kasa->acc_xz = kasa->acc_xw = 0.0f;
- kasa->acc_yy = kasa->acc_yz = kasa->acc_yw = 0.0f;
- kasa->acc_zz = kasa->acc_zw = 0.0f;
-
- kasa->nsamples = 0;
-}
-
void magCalReset(struct MagCal *moc) {
- magKasaReset(&moc->kasa);
- diversityCheckerReset(&moc->diversity_checker);
+ moc->acc_x = moc->acc_y = moc->acc_z = moc->acc_w = 0.0f;
+ moc->acc_xx = moc->acc_xy = moc->acc_xz = moc->acc_xw = 0.0f;
+ moc->acc_yy = moc->acc_yz = moc->acc_yw = 0.0f;
+ moc->acc_zz = moc->acc_zw = 0.0f;
+
+ moc->nsamples = 0;
moc->start_time = 0;
}
@@ -133,32 +126,20 @@ static int moc_batch_complete(struct MagCal *moc, uint64_t sample_time_us) {
int complete = 0;
if ((sample_time_us - moc->start_time > MIN_BATCH_WINDOW) &&
- (moc->kasa.nsamples > MIN_BATCH_SIZE)) {
+ (moc->nsamples > MIN_BATCH_SIZE)) {
complete = 1;
- } else if (sample_time_us - moc->start_time > MAX_BATCH_WINDOW ||
- moc->diversity_checker.num_max_dist_violations
- >= MAX_DISTANCE_VIOLATIONS) {
- // not enough samples collected in MAX_BATCH_WINDOW or too many
- // maximum distance violations detected.
+ } else if (sample_time_us - moc->start_time > MAX_BATCH_WINDOW) {
+ // not enough samples collected in MAX_BATCH_WINDOW
magCalReset(moc);
}
return complete;
}
-void initKasa(struct KasaFit *kasa) {
- magKasaReset(kasa);
-}
-
void initMagCal(struct MagCal *moc, float x_bias, float y_bias, float z_bias,
float c00, float c01, float c02, float c10, float c11,
- float c12, float c20, float c21, float c22,
- float threshold, float max_distance,
- size_t min_num_diverse_vectors,
- size_t max_num_max_distance,
- float var_threshold,
- float max_min_threshold) {
+ float c12, float c20, float c21, float c22) {
magCalReset(moc);
moc->update_time = 0;
moc->radius = 0.0f;
@@ -176,15 +157,6 @@ void initMagCal(struct MagCal *moc, float x_bias, float y_bias, float z_bias,
moc->c20 = c20;
moc->c21 = c21;
moc->c22 = c22;
-
- // Diversity Checker Init
- diversityCheckerInit(&moc->diversity_checker,
- threshold,
- max_distance,
- min_num_diverse_vectors,
- max_num_max_distance,
- var_threshold,
- max_min_threshold);
}
void magCalDestroy(struct MagCal *moc) { (void)moc; }
@@ -193,74 +165,66 @@ bool magCalUpdate(struct MagCal *moc, uint64_t sample_time_us, float x, float y,
float z) {
bool new_bias = false;
- // Diversity Checker Update.
- diversityCheckerUpdate(&moc->diversity_checker, x, y, z);
-
// 1. run accumulators
float w = x * x + y * y + z * z;
- moc->kasa.acc_x += x;
- moc->kasa.acc_y += y;
- moc->kasa.acc_z += z;
- moc->kasa.acc_w += w;
+ moc->acc_x += x;
+ moc->acc_y += y;
+ moc->acc_z += z;
+ moc->acc_w += w;
- moc->kasa.acc_xx += x * x;
- moc->kasa.acc_xy += x * y;
- moc->kasa.acc_xz += x * z;
- moc->kasa.acc_xw += x * w;
+ moc->acc_xx += x * x;
+ moc->acc_xy += x * y;
+ moc->acc_xz += x * z;
+ moc->acc_xw += x * w;
- moc->kasa.acc_yy += y * y;
- moc->kasa.acc_yz += y * z;
- moc->kasa.acc_yw += y * w;
+ moc->acc_yy += y * y;
+ moc->acc_yz += y * z;
+ moc->acc_yw += y * w;
- moc->kasa.acc_zz += z * z;
- moc->kasa.acc_zw += z * w;
+ moc->acc_zz += z * z;
+ moc->acc_zw += z * w;
- if (++moc->kasa.nsamples == 1) {
+ if (++moc->nsamples == 1) {
moc->start_time = sample_time_us;
}
// 2. batch has enough samples?
if (moc_batch_complete(moc, sample_time_us)) {
- float inv = 1.0f / moc->kasa.nsamples;
+ float inv = 1.0f / moc->nsamples;
- moc->kasa.acc_x *= inv;
- moc->kasa.acc_y *= inv;
- moc->kasa.acc_z *= inv;
- moc->kasa.acc_w *= inv;
+ moc->acc_x *= inv;
+ moc->acc_y *= inv;
+ moc->acc_z *= inv;
+ moc->acc_w *= inv;
- moc->kasa.acc_xx *= inv;
- moc->kasa.acc_xy *= inv;
- moc->kasa.acc_xz *= inv;
- moc->kasa.acc_xw *= inv;
+ moc->acc_xx *= inv;
+ moc->acc_xy *= inv;
+ moc->acc_xz *= inv;
+ moc->acc_xw *= inv;
- moc->kasa.acc_yy *= inv;
- moc->kasa.acc_yz *= inv;
- moc->kasa.acc_yw *= inv;
+ moc->acc_yy *= inv;
+ moc->acc_yz *= inv;
+ moc->acc_yw *= inv;
- moc->kasa.acc_zz *= inv;
- moc->kasa.acc_zw *= inv;
+ moc->acc_zz *= inv;
+ moc->acc_zw *= inv;
// 3. eigen test
- if (moc_eigen_test(&moc->kasa)) {
+ if (moc_eigen_test(moc)) {
struct Vec3 bias;
float radius;
// 4. Kasa sphere fitting
- if (magKasaFit(&moc->kasa, &bias, &radius)) {
- if (diversityCheckerNormQuality(&moc->diversity_checker,
- bias.x,
- bias.y,
- bias.z)) {
- moc->x_bias = bias.x;
- moc->y_bias = bias.y;
- moc->z_bias = bias.z;
-
- moc->radius = radius;
- moc->update_time = sample_time_us;
-
- new_bias = true;
- }
+ if (magCalFit(moc, &bias, &radius)) {
+ moc->x_bias = bias.x;
+ moc->y_bias = bias.y;
+ moc->z_bias = bias.z;
+
+ moc->radius = radius;
+ moc->update_time = sample_time_us;
+
+ new_bias = true;
}
}
diff --git a/firmware/os/algos/calibration/magnetometer/mag_cal.h b/firmware/os/algos/calibration/magnetometer/mag_cal.h
index eccf35ce..a73aa22a 100644
--- a/firmware/os/algos/calibration/magnetometer/mag_cal.h
+++ b/firmware/os/algos/calibration/magnetometer/mag_cal.h
@@ -1,3 +1,6 @@
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_MAGNETOMETER_MAG_CAL_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_MAGNETOMETER_MAG_CAL_H_
+
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -13,50 +16,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_MAGNETOMETER_MAG_CAL_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_MAGNETOMETER_MAG_CAL_H_
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
-#include "calibration/common/diversity_checker.h"
#include "common/math/mat.h"
-#include "common/math/vec.h"
#ifdef __cplusplus
extern "C" {
#endif
-struct KasaFit {
- float acc_x, acc_y, acc_z, acc_w;
- float acc_xx, acc_xy, acc_xz, acc_xw;
- float acc_yy, acc_yz, acc_yw, acc_zz, acc_zw;
- size_t nsamples;
-};
-
struct MagCal {
- struct DiversityChecker diversity_checker;
- struct KasaFit kasa;
-
uint64_t start_time;
uint64_t update_time;
+ float acc_x, acc_y, acc_z, acc_w;
+ float acc_xx, acc_xy, acc_xz, acc_xw;
+ float acc_yy, acc_yz, acc_yw, acc_zz, acc_zw;
+
float x_bias, y_bias, z_bias;
float radius;
float c00, c01, c02, c10, c11, c12, c20, c21, c22;
-};
-void initKasa(struct KasaFit *kasa);
+ size_t nsamples;
+};
void initMagCal(struct MagCal *moc, float x_bias, float y_bias, float z_bias,
float c00, float c01, float c02, float c10, float c11,
- float c12, float c20, float c21, float c22,
- float threshold, float max_distance,
- size_t min_num_diverse_vectors,
- size_t max_num_max_distance,
- float var_threshold,
- float max_min_threshold);
+ float c12, float c20, float c21, float c22);
void magCalDestroy(struct MagCal *moc);
@@ -77,11 +65,9 @@ void magCalSetSoftiron(struct MagCal *moc, float c00, float c01, float c02,
void magCalRemoveSoftiron(struct MagCal *moc, float xi, float yi, float zi,
float *xo, float *yo, float *zo);
-void magKasaReset(struct KasaFit *kasa);
-
void magCalReset(struct MagCal *moc);
-int magKasaFit(struct KasaFit *kasa, struct Vec3 *bias, float *radius);
+int magCalFit(struct MagCal *moc, struct Vec3 *bias, float *radius);
#ifdef __cplusplus
}
diff --git a/firmware/os/algos/calibration/over_temp/over_temp_cal.c b/firmware/os/algos/calibration/over_temp/over_temp_cal.c
deleted file mode 100644
index 0b8b6c73..00000000
--- a/firmware/os/algos/calibration/over_temp/over_temp_cal.c
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "calibration/over_temp/over_temp_cal.h"
-
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "calibration/util/cal_log.h"
-#include "common/math/vec.h"
-#include "util/nano_assert.h"
-
-/////// DEFINITIONS AND MACROS ////////////////////////////////////////////////
-
-// The 'temp_sensitivity' parameters are set to this value to indicate that the
-// model is in its initial state.
-#define MODEL_INITIAL_STATE (1e6f)
-
-// Rate-limits the search for the nearest offset estimate to every 10 seconds
-// when no model has been updated yet.
-#define OVERTEMPCAL_NEAREST_NANOS (10000000000)
-
-// Rate-limits the check of old data to every 2 hours.
-#define OVERTEMPCAL_STALE_CHECK_TIME_NANOS (7200000000000)
-
-// A common sensor operating temperature at which to start producing the model
-// jump-start data.
-#define JUMPSTART_START_TEMP_CELSIUS (30.0f)
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
-// A debug version label to help with tracking results.
-#define OVERTEMPCAL_DEBUG_VERSION_STRING "[Dec 12, 2016]"
-
-// The time value used to throttle debug messaging.
-#define OVERTEMPCAL_WAIT_TIME_NANOS (250000000)
-
-// Debug log tag string used to identify debug report output data.
-#define OVERTEMPCAL_REPORT_TAG "[OVER_TEMP_CAL:REPORT]"
-
-// Converts units of radians to milli-degrees.
-#define RAD_TO_MILLI_DEGREES (float)(1e3f * 180.0f / M_PI)
-
-// Sensor axis label definition with index correspondence: 0=X, 1=Y, 2=Z.
-static const char kDebugAxisLabel[3] = "XYZ";
-#endif // OVERTEMPCAL_DBG_ENABLED
-
-/////// FORWARD DECLARATIONS //////////////////////////////////////////////////
-
-// Updates the most recent model estimate data.
-static void setLatestEstimate(struct OverTempCal *over_temp_cal,
- const float *offset, float offset_temp,
- uint64_t timestamp_nanos);
-
-/*
- * Determines if a new over-temperature model fit should be performed, and then
- * updates the model as needed.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * timestamp_nanos: Current timestamp for the model update.
- */
-static void computeModelUpdate(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos);
-
-/*
- * Searches 'model_data' for the sensor offset estimate closest to the current
- * temperature. Sets the 'latest_offset' pointer to the result.
- */
-static void setNearestEstimate(struct OverTempCal *over_temp_cal);
-
-/*
- * Removes the "old" offset estimates from 'model_data' (i.e., eliminates the
- * drift-compromised data). Returns 'true' if any data was removed.
- */
-static bool removeStaleModelData(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos);
-
-/*
- * Removes the offset estimates from 'model_data' at index, 'model_index'.
- * Returns 'true' if data was removed.
- */
-static bool removeModelDataByIndex(struct OverTempCal *over_temp_cal,
- size_t model_index);
-
-/*
- * Since it may take a while for an empty model to build up enough data to start
- * producing new model parameter updates, the model collection can be
- * jump-started by using the new model parameters to insert fake data in place
- * of actual sensor offset data.
- */
-static bool jumpStartModelData(struct OverTempCal *over_temp_cal);
-
-/*
- * Provides updated model parameters for the over-temperature model data.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * OUTPUTS:
- * temp_sensitivity: Updated modeled temperature sensitivity (array).
- * sensor_intercept: Updated model intercept (array).
- *
- * NOTE: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- *
- * Reference: "Comparing two ways to fit a line to data", John D. Cook.
- * http://www.johndcook.com/blog/2008/10/20/comparing-two-ways-to-fit-a-line-to-data/
- */
-static void updateModel(const struct OverTempCal *over_temp_cal,
- float *temp_sensitivity, float *sensor_intercept);
-
-/*
- * Removes the over-temp compensated offset from the input sensor data.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * vi: Single axis sensor data to be compensated.
- * index: Index for model parameter compensation (0=x, 1=y, 2=z).
- * OUTPUTS:
- * vo: Single axis sensor data that has been compensated.
- */
-static void removeSensorOffset(const struct OverTempCal *over_temp_cal,
- float vi, size_t index, float *vo);
-
-/*
- * Computes the over-temperature compensated sensor offset estimate based on the
- * input model parameters. Note, this is a single axis calculation.
- * comp_offset = (temp_sensitivity * temperature + sensor_intercept)
- *
- * INPUTS:
- * temperature: Temperature value at which to compute the estimate.
- * temp_sensitivity: Temperature sensitivity model parameter.
- * sensor_intercept: Sensor intercept model parameter.
- * RETURNS:
- * comp_offset: Over-temperature compensated sensor offset estimate.
- */
-static float getCompensatedOffset(float temperature, float temp_sensitivity,
- float sensor_intercept);
-
-/////// FUNCTION DEFINITIONS //////////////////////////////////////////////////
-
-void overTempCalInit(struct OverTempCal *over_temp_cal,
- size_t min_num_model_pts,
- uint64_t min_update_interval_nanos,
- float delta_temp_per_bin, float max_error_limit,
- uint64_t age_limit_nanos, float temp_sensitivity_limit,
- float sensor_intercept_limit, bool over_temp_enable) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- // Clears OverTempCal memory.
- memset(over_temp_cal, 0, sizeof(struct OverTempCal));
-
- // Initializes the pointer to the most recent sensor offset estimate. Sets it
- // as the first element in 'model_data'.
- over_temp_cal->latest_offset = &over_temp_cal->model_data[0];
-
- // Sets the temperature sensitivity model parameters to MODEL_INITIAL_STATE to
- // indicate that the model is in an "initial" state.
- over_temp_cal->temp_sensitivity[0] = MODEL_INITIAL_STATE;
- over_temp_cal->temp_sensitivity[1] = MODEL_INITIAL_STATE;
- over_temp_cal->temp_sensitivity[2] = MODEL_INITIAL_STATE;
-
- // Initializes the model identification parameters.
- over_temp_cal->new_overtemp_model_available = false;
- over_temp_cal->min_num_model_pts = min_num_model_pts;
- over_temp_cal->min_update_interval_nanos = min_update_interval_nanos;
- over_temp_cal->delta_temp_per_bin = delta_temp_per_bin;
- over_temp_cal->max_error_limit = max_error_limit;
- over_temp_cal->age_limit_nanos = age_limit_nanos;
- over_temp_cal->temp_sensitivity_limit = temp_sensitivity_limit;
- over_temp_cal->sensor_intercept_limit = sensor_intercept_limit;
- over_temp_cal->over_temp_enable = over_temp_enable;
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- CAL_DEBUG_LOG("[OVER_TEMP_CAL:MEMORY]", "sizeof(struct OverTempCal): %lu",
- (unsigned long int)sizeof(struct OverTempCal));
- CAL_DEBUG_LOG("[OVER_TEMP_CAL:INIT]", "Over-Temp Cal: Initialized.");
-
-#endif // OVERTEMPCAL_DBG_ENABLED
-}
-
-void overTempCalSetModel(struct OverTempCal *over_temp_cal, const float *offset,
- float offset_temp, uint64_t timestamp_nanos,
- const float *temp_sensitivity,
- const float *sensor_intercept, bool jump_start_model) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(offset);
- ASSERT_NOT_NULL(temp_sensitivity);
- ASSERT_NOT_NULL(sensor_intercept);
-
- // Sets the model parameters if they are within the acceptable limits.
- size_t i;
- for (i = 0; i < 3; i++) {
- if (NANO_ABS(temp_sensitivity[i]) < over_temp_cal->temp_sensitivity_limit &&
- NANO_ABS(sensor_intercept[i]) < over_temp_cal->sensor_intercept_limit) {
- over_temp_cal->temp_sensitivity[i] = temp_sensitivity[i];
- over_temp_cal->sensor_intercept[i] = sensor_intercept[i];
- }
- }
-
- // Sets the model update time to the current timestamp.
- over_temp_cal->modelupdate_timestamp_nanos = timestamp_nanos;
-
- // Model "Jump-Start".
- const bool model_jump_started =
- (jump_start_model) ? jumpStartModelData(over_temp_cal) : false;
-
- if (!model_jump_started) {
- // Sets the initial over-temp calibration estimate and model data.
- setLatestEstimate(over_temp_cal, offset, offset_temp, timestamp_nanos);
-
- // Now there is one offset estimate in the model.
- over_temp_cal->num_model_pts = 1;
- }
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- // Prints the updated model data.
- CAL_DEBUG_LOG("[OVER_TEMP_CAL:RECALL]",
- "Model parameters recalled from memory.");
-
- // Trigger a debug print out to view the new model parameters.
- over_temp_cal->debug_print_trigger = true;
-#endif // OVERTEMPCAL_DBG_ENABLED
-}
-
-void overTempCalGetModel(struct OverTempCal *over_temp_cal, float *offset,
- float *offset_temp, uint64_t *timestamp_nanos,
- float *temp_sensitivity, float *sensor_intercept) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
- ASSERT_NOT_NULL(offset);
- ASSERT_NOT_NULL(offset_temp);
- ASSERT_NOT_NULL(timestamp_nanos);
- ASSERT_NOT_NULL(temp_sensitivity);
- ASSERT_NOT_NULL(sensor_intercept);
-
- // Updates the latest offset so that it is the one nearest to the current
- // temperature.
- setNearestEstimate(over_temp_cal);
-
- // Gets the over-temp calibration estimate and model data.
- memcpy(offset, over_temp_cal->latest_offset->offset, 3 * sizeof(float));
- memcpy(temp_sensitivity, over_temp_cal->temp_sensitivity, 3 * sizeof(float));
- memcpy(sensor_intercept, over_temp_cal->sensor_intercept, 3 * sizeof(float));
- *offset_temp = over_temp_cal->latest_offset->offset_temp;
- *timestamp_nanos = over_temp_cal->latest_offset->timestamp_nanos;
-}
-
-void overTempCalRemoveOffset(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos, float xi, float yi,
- float zi, float *xo, float *yo, float *zo) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
- ASSERT_NOT_NULL(xo);
- ASSERT_NOT_NULL(yo);
- ASSERT_NOT_NULL(zo);
-
- // Determines whether over-temp compensation will be applied.
- if (!over_temp_cal->over_temp_enable) {
- return;
- }
-
- // Removes very old data from the collected model estimates (eliminates
- // drift-compromised data). Only does this when there is more than one
- // estimate in the model (i.e., don't want to remove all data, even if it is
- // very old [something is likely better than nothing]).
- if ((timestamp_nanos - over_temp_cal->stale_data_timer) >=
- OVERTEMPCAL_STALE_CHECK_TIME_NANOS &&
- over_temp_cal->num_model_pts > 1) {
- over_temp_cal->stale_data_timer = timestamp_nanos; // Resets timer.
-
- if (removeStaleModelData(over_temp_cal, timestamp_nanos)) {
- // If anything was removed, then this attempts to recompute the model.
- computeModelUpdate(over_temp_cal, timestamp_nanos);
- }
- }
-
- // Removes the over-temperature compensated offset from the input sensor data.
- removeSensorOffset(over_temp_cal, xi, 0, xo);
- removeSensorOffset(over_temp_cal, yi, 1, yo);
- removeSensorOffset(over_temp_cal, zi, 2, zo);
-}
-
-bool overTempCalNewModelUpdateAvailable(struct OverTempCal *over_temp_cal) {
- ASSERT_NOT_NULL(over_temp_cal);
- const bool update_available = over_temp_cal->new_overtemp_model_available &&
- over_temp_cal->over_temp_enable;
-
- // The 'new_overtemp_model_available' flag is reset when it is read here.
- over_temp_cal->new_overtemp_model_available = false;
-
- return update_available;
-}
-
-void overTempCalUpdateSensorEstimate(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos,
- const float *offset,
- float temperature_celsius) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
- ASSERT_NOT_NULL(offset);
- ASSERT(over_temp_cal->delta_temp_per_bin > 0);
-
- // Prevent a divide by zero below.
- if (over_temp_cal->delta_temp_per_bin <= 0) {
- return;
- }
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- // Updates the total count of offset estimates.
- over_temp_cal->debug_num_estimates++;
-
- // If there are fewer than the minimum number of points to produce a model,
- // then trigger a debug printout to view the model building process.
- over_temp_cal->debug_print_trigger |=
- (over_temp_cal->num_model_pts <= over_temp_cal->min_num_model_pts);
-#endif // OVERTEMPCAL_DBG_ENABLED
-
- // Provides an early escape if this is the first model estimate.
- if (over_temp_cal->num_model_pts == 0) {
- setLatestEstimate(over_temp_cal, offset, temperature_celsius,
- timestamp_nanos);
- over_temp_cal->num_model_pts = 1; // one estimate was added above.
- return;
- }
-
- // Computes the temperature bin range data.
- const int32_t bin_num =
- CAL_FLOOR(temperature_celsius / over_temp_cal->delta_temp_per_bin);
- const float temp_lo_check = bin_num * over_temp_cal->delta_temp_per_bin;
- const float temp_hi_check = (bin_num + 1) * over_temp_cal->delta_temp_per_bin;
-
- // The rules for accepting new offset estimates into the 'model_data'
- // collection:
- // 1) The temperature domain is divided into bins each spanning
- // 'delta_temp_per_bin'.
- // 2) Find and replace the i'th 'model_data' estimate data if:
- // Let, bin_num = floor(temperature_celsius / delta_temp_per_bin)
- // temp_lo_check = bin_num * delta_temp_per_bin
- // temp_hi_check = (bin_num + 1) * delta_temp_per_bin
- // Check condition:
- // temp_lo_check <= model_data[i].offset_temp < temp_hi_check
- bool replaced_one = false;
- size_t i = 0;
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
- if (over_temp_cal->model_data[i].offset_temp < temp_hi_check &&
- over_temp_cal->model_data[i].offset_temp >= temp_lo_check) {
- // NOTE - the pointer to the estimate that is getting replaced is set
- // here; the offset values are set below in the call to
- // 'setLatestEstimate'.
- over_temp_cal->latest_offset = &over_temp_cal->model_data[i];
- replaced_one = true;
- break;
- }
- }
-
- // 3) If nothing was replaced, and the 'model_data' buffer is not full
- // then add the estimate data to the array.
- // 4) Otherwise (nothing was replaced and buffer is full), replace the
- // 'latest_offset' with the incoming one. This is done below.
- if (!replaced_one && over_temp_cal->num_model_pts < OVERTEMPCAL_MODEL_SIZE) {
- // NOTE - the pointer to the next available array location is set here;
- // the offset values are set below in the call to 'setLatestEstimate'.
- over_temp_cal->latest_offset =
- &over_temp_cal->model_data[over_temp_cal->num_model_pts];
- over_temp_cal->num_model_pts++;
- }
-
- // Updates the latest model estimate data.
- setLatestEstimate(over_temp_cal, offset, temperature_celsius,
- timestamp_nanos);
-
- // Conditionally updates the over-temp model. See 'computeModelUpdate' for
- // update conditions.
- computeModelUpdate(over_temp_cal, timestamp_nanos);
-
-}
-
-void overTempCalSetTemperature(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos,
- float temperature_celsius) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
-#ifdef OVERTEMPCAL_DBG_LOG_TEMP
- static uint64_t wait_timer = 0;
- // Prints the sensor temperature trajectory for debugging purposes.
- // This throttles the print statements.
- if ((timestamp_nanos - wait_timer) >= 1000000000) {
- wait_timer = timestamp_nanos; // Starts the wait timer.
-
- // Prints out temperature and the current timestamp.
- CAL_DEBUG_LOG("[OVER_TEMP_CAL:TEMP]",
- "Temperature|Time [C|nsec] = %s%d.%06d, %llu",
- CAL_ENCODE_FLOAT(temperature_celsius, 6),
- (unsigned long long int)timestamp_nanos);
- }
-#endif // OVERTEMPCAL_DBG_LOG_TEMP
-#endif // OVERTEMPCAL_DBG_ENABLED
-
- // Updates the sensor temperature.
- over_temp_cal->temperature_celsius = temperature_celsius;
-
- // If any of the models for the sensor axes are in an initial state, then
- // this searches for the sensor offset estimate closest to the current
- // temperature. A timer is used to limit the rate at which this search is
- // performed.
- if (over_temp_cal->num_model_pts > 1 &&
- (over_temp_cal->temp_sensitivity[0] >= MODEL_INITIAL_STATE ||
- over_temp_cal->temp_sensitivity[1] >= MODEL_INITIAL_STATE ||
- over_temp_cal->temp_sensitivity[2] >= MODEL_INITIAL_STATE) &&
- (timestamp_nanos - over_temp_cal->nearest_search_timer) >=
- OVERTEMPCAL_NEAREST_NANOS) {
- setNearestEstimate(over_temp_cal);
- over_temp_cal->nearest_search_timer = timestamp_nanos; // Reset timer.
- }
-}
-
-void getModelError(const struct OverTempCal *over_temp_cal,
- const float *temp_sensitivity, const float *sensor_intercept,
- float *max_error) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(temp_sensitivity);
- ASSERT_NOT_NULL(sensor_intercept);
- ASSERT_NOT_NULL(max_error);
-
- size_t i;
- size_t j;
- float max_error_test;
- memset(max_error, 0, 3 * sizeof(float));
-
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
- for (j = 0; j < 3; j++) {
- max_error_test =
- NANO_ABS(over_temp_cal->model_data[i].offset[j] -
- getCompensatedOffset(over_temp_cal->model_data[i].offset_temp,
- temp_sensitivity[j], sensor_intercept[j]));
- if (max_error_test > max_error[j]) {
- max_error[j] = max_error_test;
- }
- }
- }
-}
-
-/////// LOCAL HELPER FUNCTION DEFINITIONS /////////////////////////////////////
-
-void setLatestEstimate(struct OverTempCal *over_temp_cal, const float *offset,
- float offset_temp, uint64_t timestamp_nanos) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(offset);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
-
- // Sets the latest over-temp calibration estimate.
- over_temp_cal->latest_offset->offset[0] = offset[0];
- over_temp_cal->latest_offset->offset[1] = offset[1];
- over_temp_cal->latest_offset->offset[2] = offset[2];
- over_temp_cal->latest_offset->offset_temp = offset_temp;
- over_temp_cal->latest_offset->timestamp_nanos = timestamp_nanos;
-}
-
-void computeModelUpdate(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- // The rules for determining whether a new model fit is computed are:
- // 1) A minimum number of data points must have been collected:
- // num_model_pts >= min_num_model_pts
- // NOTE: Collecting 'num_model_pts' and given that only one point is
- // kept per temperature bin (spanning a thermal range specified by
- // 'delta_temp_per_bin'), implies that model data covers at least,
- // model_temp_span >= 'num_model_pts' * delta_temp_per_bin
- // 2) New model updates will not occur for intervals less than:
- // (current_timestamp_nanos - modelupdate_timestamp_nanos) <
- // min_update_interval_nanos
- if (over_temp_cal->num_model_pts < over_temp_cal->min_num_model_pts ||
- (timestamp_nanos - over_temp_cal->modelupdate_timestamp_nanos) <
- over_temp_cal->min_update_interval_nanos) {
- return;
- }
-
- // Updates the linear model fit.
- float temp_sensitivity[3];
- float sensor_intercept[3];
- updateModel(over_temp_cal, temp_sensitivity, sensor_intercept);
-
- // Computes the maximum error over all of the model data.
- float max_error[3];
- getModelError(over_temp_cal, temp_sensitivity, sensor_intercept, max_error);
-
- // 3) A new set of model parameters are accepted if:
- // i. The model fit error is less than, 'max_error_limit'. See
- // getModelError() for error metric description.
- // ii. The model fit parameters must be within certain absolute
- // bounds:
- // a. NANO_ABS(temp_sensitivity) < temp_sensitivity_limit
- // b. NANO_ABS(sensor_intercept) < sensor_intercept_limit
- size_t i;
- for (i = 0; i < 3; i++) {
- if (max_error[i] < over_temp_cal->max_error_limit &&
- NANO_ABS(temp_sensitivity[i]) < over_temp_cal->temp_sensitivity_limit &&
- NANO_ABS(sensor_intercept[i]) < over_temp_cal->sensor_intercept_limit) {
- over_temp_cal->temp_sensitivity[i] = temp_sensitivity[i];
- over_temp_cal->sensor_intercept[i] = sensor_intercept[i];
- } else {
-#ifdef OVERTEMPCAL_DBG_ENABLED
- CAL_DEBUG_LOG(
- "[OVER_TEMP_CAL:REJECT]",
- "Rejected %c-Axis Parameters|Max Error [mdps/C|mdps|mdps] = "
- "%s%d.%06d, %s%d.%06d, %s%d.%06d",
- kDebugAxisLabel[i],
- CAL_ENCODE_FLOAT(temp_sensitivity[i] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(sensor_intercept[i] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(max_error[i] * RAD_TO_MILLI_DEGREES, 6));
-#endif // OVERTEMPCAL_DBG_ENABLED
- }
- }
-
- // Resets the timer and sets the update flag.
- over_temp_cal->modelupdate_timestamp_nanos = timestamp_nanos;
- over_temp_cal->new_overtemp_model_available = true;
-
- // Track the total number of model updates, and set trigger to print log data.
-#ifdef OVERTEMPCAL_DBG_ENABLED
- over_temp_cal->debug_num_model_updates++;
- over_temp_cal->debug_print_trigger |= true;
-#endif // OVERTEMPCAL_DBG_ENABLED
-}
-
-void setNearestEstimate(struct OverTempCal *over_temp_cal) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- size_t i = 0;
- float dtemp_new = 0.0f;
- float dtemp_old = FLT_MAX;
- struct OverTempCalDataPt *nearest_estimate = &over_temp_cal->model_data[0];
- for (i = 1; i < over_temp_cal->num_model_pts; i++) {
- dtemp_new = NANO_ABS(over_temp_cal->model_data[i].offset_temp -
- over_temp_cal->temperature_celsius);
- if (dtemp_new < dtemp_old) {
- nearest_estimate = &over_temp_cal->model_data[i];
- dtemp_old = dtemp_new;
- }
- }
-
- // Set the 'latest_offset' to the estimate nearest the current temperature.
- over_temp_cal->latest_offset = nearest_estimate;
-}
-
-bool removeStaleModelData(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- size_t i;
- bool removed_one = false;
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
- if ((timestamp_nanos - over_temp_cal->model_data[i].timestamp_nanos) >
- over_temp_cal->age_limit_nanos) {
- removed_one |= removeModelDataByIndex(over_temp_cal, i);
- }
- }
-
- // Updates the latest offset so that it is the one nearest to the current
- // temperature.
- setNearestEstimate(over_temp_cal);
-
- return removed_one;
-}
-
-bool removeModelDataByIndex(struct OverTempCal *over_temp_cal,
- size_t model_index) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- // This function will not remove all of the model data. At least one model
- // sample will be left.
- if (over_temp_cal->num_model_pts <= 1) {
- return false;
- }
-
- // Remove the model data at 'model_index'.
- size_t i;
- for (i = model_index; i < over_temp_cal->num_model_pts - 1; i++) {
- memcpy(&over_temp_cal->model_data[i], &over_temp_cal->model_data[i + 1],
- sizeof(struct OverTempCalDataPt));
- }
- over_temp_cal->num_model_pts--;
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- CAL_DEBUG_LOG("[OVER_TEMP_CAL:REMOVE]",
- "Removed Stale Data: Model Index = %lu",
- (unsigned long int)model_index);
-#endif // OVERTEMPCAL_DBG_ENABLED
-
- return true;
-}
-
-bool jumpStartModelData(struct OverTempCal *over_temp_cal) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT(over_temp_cal->delta_temp_per_bin > 0);
-
- // Prevent a divide by zero below.
- if (over_temp_cal->delta_temp_per_bin <= 0) {
- return false;
- }
-
- // In normal operation the offset estimates enter into the 'model_data' array
- // complete (i.e., x, y, z values are all provided). Therefore, the jumpstart
- // data produced here requires that the model parameters have all been fully
- // defined (i.e., no models in an initial state) and are all within the valid
- // range (this is assumed to have been checked prior to this function). There
- // must also be no preexisting model data; that is, this function will not
- // replace any actual offset estimates already buffered.
- if (over_temp_cal->num_model_pts > 0 ||
- over_temp_cal->temp_sensitivity[0] >= MODEL_INITIAL_STATE ||
- over_temp_cal->temp_sensitivity[1] >= MODEL_INITIAL_STATE ||
- over_temp_cal->temp_sensitivity[2] >= MODEL_INITIAL_STATE) {
- return false;
- }
-
- // This defines the minimum contiguous set of points to allow a model update
- // when the next offset estimate is received. They are placed at a common
- // temperature range that is likely to get replaced with actual data soon.
- const int32_t start_bin_num = CAL_FLOOR(JUMPSTART_START_TEMP_CELSIUS /
- over_temp_cal->delta_temp_per_bin);
- float offset_temp =
- start_bin_num * (1.5f * over_temp_cal->delta_temp_per_bin);
-
- size_t i;
- size_t j;
- for (i = 0; i < over_temp_cal->min_num_model_pts; i++) {
- float offset[3];
- const uint64_t timestamp_nanos = over_temp_cal->modelupdate_timestamp_nanos;
- for (j = 0; j < 3; j++) {
- offset[j] =
- getCompensatedOffset(offset_temp, over_temp_cal->temp_sensitivity[j],
- over_temp_cal->sensor_intercept[j]);
- }
- over_temp_cal->latest_offset = &over_temp_cal->model_data[i];
- setLatestEstimate(over_temp_cal, offset, offset_temp, timestamp_nanos);
- offset_temp += over_temp_cal->delta_temp_per_bin;
- over_temp_cal->num_model_pts++;
- }
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- if (over_temp_cal->min_num_model_pts > 0) {
- CAL_DEBUG_LOG("[OVER_TEMP_CAL]", "Jump-Started Model: #Points = %lu.",
- (unsigned long int)over_temp_cal->min_num_model_pts);
- }
-#endif // OVERTEMPCAL_DBG_ENABLED
-
- return (over_temp_cal->min_num_model_pts > 0);
-}
-
-void updateModel(const struct OverTempCal *over_temp_cal,
- float *temp_sensitivity, float *sensor_intercept) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(temp_sensitivity);
- ASSERT_NOT_NULL(sensor_intercept);
- ASSERT(over_temp_cal->num_model_pts > 0);
-
- float st = 0.0f, stt = 0.0f;
- float sx = 0.0f, stsx = 0.0f;
- float sy = 0.0f, stsy = 0.0f;
- float sz = 0.0f, stsz = 0.0f;
- const size_t n = over_temp_cal->num_model_pts;
- size_t i = 0;
-
- // First pass computes the mean values.
- for (i = 0; i < n; ++i) {
- st += over_temp_cal->model_data[i].offset_temp;
- sx += over_temp_cal->model_data[i].offset[0];
- sy += over_temp_cal->model_data[i].offset[1];
- sz += over_temp_cal->model_data[i].offset[2];
- }
-
- // Second pass computes the mean corrected second moment values.
- const float inv_n = 1.0f / n;
- for (i = 0; i < n; ++i) {
- const float t = over_temp_cal->model_data[i].offset_temp - st * inv_n;
- stt += t * t;
- stsx += t * over_temp_cal->model_data[i].offset[0];
- stsy += t * over_temp_cal->model_data[i].offset[1];
- stsz += t * over_temp_cal->model_data[i].offset[2];
- }
-
- // Calculates the linear model fit parameters.
- ASSERT(stt > 0);
- const float inv_stt = 1.0f / stt;
- temp_sensitivity[0] = stsx * inv_stt;
- sensor_intercept[0] = (sx - st * temp_sensitivity[0]) * inv_n;
- temp_sensitivity[1] = stsy * inv_stt;
- sensor_intercept[1] = (sy - st * temp_sensitivity[1]) * inv_n;
- temp_sensitivity[2] = stsz * inv_stt;
- sensor_intercept[2] = (sz - st * temp_sensitivity[2]) * inv_n;
-}
-
-void removeSensorOffset(const struct OverTempCal *over_temp_cal, float vi,
- size_t index, float *vo) {
- // Removes the over-temperature compensated offset from the input sensor data.
- if (over_temp_cal->temp_sensitivity[index] >= MODEL_INITIAL_STATE) {
- // If this axis is in its initial state, use the nearest estimate to perform
- // the compensation (in this case the latest estimate will be the nearest):
- // sensor_out = sensor_in - nearest_offset
- *vo = vi - over_temp_cal->latest_offset->offset[index];
- } else {
- // sensor_out = sensor_in - compensated_offset
- // Where,
- // compensated_offset = (temp_sensitivity * temp_meas + sensor_intercept)
- *vo = vi - getCompensatedOffset(over_temp_cal->temperature_celsius,
- over_temp_cal->temp_sensitivity[index],
- over_temp_cal->sensor_intercept[index]);
- }
-}
-
-float getCompensatedOffset(float temperature, float temp_sensitivity,
- float sensor_intercept) {
- return temp_sensitivity * temperature + sensor_intercept;
-}
-
-/////// DEBUG FUNCTION DEFINITIONS ////////////////////////////////////////////
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
-// Debug printout state enumeration.
-enum DebugState {
- IDLE = 0,
- WAIT_STATE,
- PRINT_HEADER,
- PRINT_OFFSET,
- PRINT_SENSITIVITY,
- PRINT_INTERCEPT,
- PRINT_ERROR,
- PRINT_MODEL_PTS,
- PRINT_MODEL_DATA
-};
-
-void overTempCalDebugPrint(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos) {
- ASSERT_NOT_NULL(over_temp_cal);
- ASSERT_NOT_NULL(over_temp_cal->latest_offset);
-
- static enum DebugState debug_state = IDLE;
- static enum DebugState next_state = 0;
- static uint64_t wait_timer = 0;
- static size_t i = 0; // Counter.
-
- // NOTE - The un-initialized model state is indicated by
- // temp_sensitivity=MODEL_INITIAL_STATE. The following filters out this
- // condition for the data printout below.
- float compensated_offset[3];
- float temp_sensitivity[3];
- float max_error[3];
- size_t j;
- for (j = 0; j < 3; j++) {
- temp_sensitivity[j] =
- (over_temp_cal->temp_sensitivity[j] >= MODEL_INITIAL_STATE)
- ? 0.0f
- : over_temp_cal->temp_sensitivity[j];
- }
-
- // This is a state machine that controls the reporting out of debug data.
- switch (debug_state) {
- case IDLE:
- // Wait for a trigger and start the debug printout sequence.
- if (over_temp_cal->debug_print_trigger) {
- debug_state = PRINT_HEADER;
- CAL_DEBUG_LOG(OVERTEMPCAL_REPORT_TAG, "");
- over_temp_cal->debug_print_trigger = false; // Resets trigger.
- } else {
- debug_state = IDLE;
- }
- break;
-
- case PRINT_HEADER:
- // Print out header.
- CAL_DEBUG_LOG(OVERTEMPCAL_REPORT_TAG, "Debug Version: %s",
- OVERTEMPCAL_DEBUG_VERSION_STRING);
-
- // Prints out number of offsets.
- CAL_DEBUG_LOG(OVERTEMPCAL_REPORT_TAG, "Total Offsets = %lu",
- (unsigned long int)over_temp_cal->debug_num_estimates);
-
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_OFFSET; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_OFFSET:
- // Computes the compensated sensor offset based on the current
- // temperature.
- for (j = 0; j < 3; j++) {
- compensated_offset[j] =
- (over_temp_cal->temp_sensitivity[j] >= MODEL_INITIAL_STATE)
- ? over_temp_cal->latest_offset->offset[j]
- : getCompensatedOffset(over_temp_cal->temperature_celsius,
- over_temp_cal->temp_sensitivity[j],
- over_temp_cal->sensor_intercept[j]);
- }
-
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG,
- "Offset|Temp|Time [mdps|C|nsec] = %s%d.%06d, %s%d.%06d, "
- "%s%d.%06d, %s%d.%06d, %llu",
- CAL_ENCODE_FLOAT(compensated_offset[0] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(compensated_offset[1] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(compensated_offset[2] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(over_temp_cal->temperature_celsius, 6),
- (unsigned long long int)
- over_temp_cal->latest_offset->timestamp_nanos);
-
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_SENSITIVITY; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case WAIT_STATE:
- // This helps throttle the print statements.
- if ((timestamp_nanos - wait_timer) >= OVERTEMPCAL_WAIT_TIME_NANOS) {
- debug_state = next_state;
- }
- break;
-
- case PRINT_SENSITIVITY:
- // Prints out the modeled temperature sensitivity.
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG,
- "Modeled Temperature Sensitivity [mdps/C] = %s%d.%06d, %s%d.%06d, "
- "%s%d.%06d",
- CAL_ENCODE_FLOAT(temp_sensitivity[0] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(temp_sensitivity[1] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(temp_sensitivity[2] * RAD_TO_MILLI_DEGREES, 6));
-
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_INTERCEPT; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_INTERCEPT:
- // Prints out the modeled temperature intercept.
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG,
- "Modeled Temperature Intercept [mdps] = %s%d.%06d, %s%d.%06d, "
- "%s%d.%06d",
- CAL_ENCODE_FLOAT(
- over_temp_cal->sensor_intercept[0] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(
- over_temp_cal->sensor_intercept[1] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(
- over_temp_cal->sensor_intercept[2] * RAD_TO_MILLI_DEGREES, 6));
-
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_ERROR; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_ERROR:
- // Computes the maximum error over all of the model data.
- if (over_temp_cal->num_model_pts > 0) {
- getModelError(over_temp_cal, temp_sensitivity,
- over_temp_cal->sensor_intercept, max_error);
-
- // Reports the resulting model error.
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG,
- "Model Error [mdps] = %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(max_error[0] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(max_error[1] * RAD_TO_MILLI_DEGREES, 6),
- CAL_ENCODE_FLOAT(max_error[2] * RAD_TO_MILLI_DEGREES, 6));
- }
-
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_MODEL_PTS; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_MODEL_PTS:
- // Prints out the number of model points/updates.
- CAL_DEBUG_LOG(OVERTEMPCAL_REPORT_TAG, "Number of Model Points = %lu",
- (unsigned long int)over_temp_cal->num_model_pts);
-
- CAL_DEBUG_LOG(OVERTEMPCAL_REPORT_TAG, "Number of Model Updates = %lu",
- (unsigned long int)over_temp_cal->debug_num_model_updates);
-
- i = 0; // Resets the counter.
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_MODEL_DATA; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- break;
-
- case PRINT_MODEL_DATA:
- // Prints out all of the model data.
- if (i < over_temp_cal->num_model_pts) {
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG,
- " Model[%lu] [mdps|C] = %s%d.%06d, %s%d.%06d, %s%d.%06d, "
- "%s%d.%03d ",
- (unsigned long int)i,
- CAL_ENCODE_FLOAT(
- over_temp_cal->model_data[i].offset[0] * RAD_TO_MILLI_DEGREES,
- 6),
- CAL_ENCODE_FLOAT(
- over_temp_cal->model_data[i].offset[1] * RAD_TO_MILLI_DEGREES,
- 6),
- CAL_ENCODE_FLOAT(
- over_temp_cal->model_data[i].offset[2] * RAD_TO_MILLI_DEGREES,
- 6),
- CAL_ENCODE_FLOAT(over_temp_cal->model_data[i].offset_temp, 3));
-
- i++;
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = PRINT_MODEL_DATA; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- } else {
- debug_state = IDLE; // Goes to idle state.
- CAL_DEBUG_LOG(
- OVERTEMPCAL_REPORT_TAG, "Last Model Update [nsec] = %llu",
- (unsigned long long int)over_temp_cal->modelupdate_timestamp_nanos);
- }
- break;
-
- default:
- // Sends this state machine to its idle state.
- wait_timer = timestamp_nanos; // Starts the wait timer.
- next_state = IDLE; // Sets the next state.
- debug_state = WAIT_STATE; // First, go to wait state.
- }
-}
-
-#endif // OVERTEMPCAL_DBG_ENABLED
diff --git a/firmware/os/algos/calibration/over_temp/over_temp_cal.h b/firmware/os/algos/calibration/over_temp/over_temp_cal.h
deleted file mode 100644
index 928576f0..00000000
--- a/firmware/os/algos/calibration/over_temp/over_temp_cal.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This module provides an online algorithm for compensating a 3-axis sensor's
- * offset over its operating temperature:
- *
- * 1) Estimates of sensor offset with associated temperature are consumed,
- * {offset, offset_temperature}.
- * 2) A temperature dependence model is extracted from the collected set of
- * data pairs.
- * 3) Until a "complete" model has been built and a model equation has been
- * computed, the compensation will use the collected offset nearest in
- * temperature. If a model is available, then the compensation will take
- * the form of:
- *
- * Linear Compensation Model Equation:
- * sensor_out = sensor_in - compensated_offset
- * Where,
- * compensated_offset = (temp_sensitivity * current_temp + sensor_intercept)
- *
- * NOTE - 'current_temp' is the current measured temperature. 'temp_sensitivity'
- * is the modeled temperature sensitivity (i.e., linear slope).
- * 'sensor_intercept' is linear model intercept.
- *
- * Assumptions:
- *
- * 1) Sensor hysteresis is negligible.
- * 2) Sensor offset temperature dependence is sufficiently "linear".
- * 3) The impact of long-term offset drift/aging compared to the magnitude of
- * deviation resulting from the thermal sensitivity of the offset is
- * relatively small.
- *
- * Sensor Input and Units:
- * - General 3-axis sensor data.
- * - Temperature measurements [Celsius].
- *
- * NOTE: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- *
- * #define OVERTEMPCAL_DBG_ENABLED to enable debug printout statements.
- * #define OVERTEMPCAL_DBG_LOG_TEMP to periodically printout sensor temperature.
- */
-
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_OVER_TEMP_OVER_TEMP_CAL_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_OVER_TEMP_OVER_TEMP_CAL_H_
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Defines the maximum size of the 'model_data' array.
-#define OVERTEMPCAL_MODEL_SIZE (20)
-
-// Over-temperature sensor offset estimate structure.
-struct OverTempCalDataPt {
- // Sensor offset estimate, temperature, and timestamp.
- float offset[3];
- float offset_temp; // [Celsius]
- uint64_t timestamp_nanos; // [nanoseconds]
- // TODO(davejacobs) - Design option: add variance to provide weighting info.
-};
-
-// The following data structure contains all of the necessary components for
-// modeling a sensor's temperature dependency and providing over-temperature
-// offset corrections.
-struct OverTempCal {
- // Storage for over-temperature model data.
- struct OverTempCalDataPt model_data[OVERTEMPCAL_MODEL_SIZE];
-
- // Total number of model data points collected.
- size_t num_model_pts;
-
- // Modeled temperature sensitivity, dOffset/dTemp [sensor_units/Celsius].
- float temp_sensitivity[3];
-
- // Sensor model equation intercept [sensor_units].
- float sensor_intercept[3];
-
- // Timestamp of the last model update.
- uint64_t modelupdate_timestamp_nanos; // [nanoseconds]
-
- // The temperature at which the offset compensation is performed.
- float temperature_celsius;
-
- // Pointer to the most recent sensor offset estimate. This is also updated
- // periodically to point to the offset estimate closest to the current sensor
- // temperature.
- struct OverTempCalDataPt *latest_offset;
-
- ///// Online Model Identification Parameters ////////////////////////////////
- //
- // The rules for determining whether a new model fit is computed and the
- // resulting fit parameters are accepted are:
- // 1) A minimum number of data points must have been collected:
- // num_model_pts >= min_num_model_pts
- // NOTE: Collecting 'num_model_pts' and given that only one point is
- // kept per temperature bin (spanning a thermal range specified by
- // 'delta_temp_per_bin'), implies that model data covers at least,
- // model_temp_span >= 'num_model_pts' * delta_temp_per_bin
- // 2) New model updates will not occur for intervals less than:
- // (current_timestamp_nanos - modelupdate_timestamp_nanos) <
- // min_update_interval_nanos
- // 3) A new set of model parameters are accepted if:
- // i. The model fit error is less than, 'max_error_limit'. See
- // getModelError() for error metric description.
- // ii. The model fit parameters must be within certain absolute
- // bounds:
- // a. ABS(temp_sensitivity) < temp_sensitivity_limit
- // b. ABS(sensor_intercept) < sensor_intercept_limit
- size_t min_num_model_pts;
- uint64_t min_update_interval_nanos; // [nanoseconds]
- float max_error_limit; // [sensor units]
- float temp_sensitivity_limit; // [sensor units/Celsius]
- float sensor_intercept_limit; // [sensor units]
-
- // The rules for accepting new offset estimates into the 'model_data'
- // collection:
- // 1) The temperature domain is divided into bins each spanning
- // 'delta_temp_per_bin'.
- // 2) Find and replace the i'th 'model_data' estimate data if:
- // Let, bin_num = floor(current_temp / delta_temp_per_bin)
- // temp_lo_check = bin_num * delta_temp_per_bin
- // temp_hi_check = (bin_num + 1) * delta_temp_per_bin
- // Check condition:
- // temp_lo_check <= model_data[i].offset_temp < temp_hi_check
- // 3) If nothing was replaced, and the 'model_data' buffer is not full then
- // add the sensor offset estimate to the array.
- // 4) Otherwise (nothing was replaced and buffer is full), replace the
- // 'latest_offset' with the incoming one.
- // This approach ensures a uniform spread of collected data, keeps the most
- // recent estimates in cases where they arrive frequently near a given
- // temperature, and prevents model oversampling (i.e., dominance of estimates
- // concentrated at given set of temperatures).
- float delta_temp_per_bin; // [Celsius/bin]
-
- // Timer used to limit the rate at which a search for the nearest offset
- // estimate is performed.
- uint64_t nearest_search_timer; // [nanoseconds]
-
- // Timer used to limit the rate at which old estimates are removed from
- // the 'model_data' collection.
- uint64_t stale_data_timer; // [nanoseconds]
-
- // Duration beyond which data will be removed to avoid corrupting the model
- // with drift-compromised data.
- uint64_t age_limit_nanos; // [nanoseconds]
-
- // Flag set by user to control whether over-temp compensation is used.
- bool over_temp_enable;
-
- // True when new compensation model values have been computed; and reset when
- // overTempCalNewModelUpdateAvailable() is called. This variable indicates
- // that the following should be stored/updated in persistent system memory:
- // 1) 'temp_sensitivity' and 'sensor_intercept'.
- // 2) The sensor offset data pointed to by 'latest_offset'
- // (saving timestamp information is not required).
- bool new_overtemp_model_available;
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
- size_t debug_num_model_updates; // Total number of model updates.
- size_t debug_num_estimates; // Total number of offset estimates.
- bool debug_print_trigger; // Flag used to trigger data printout.
-#endif // OVERTEMPCAL_DBG_ENABLED
-};
-
-/////// FUNCTION PROTOTYPES ///////////////////////////////////////////////////
-
-/*
- * Initializes the over-temp calibration model identification parameters.
- *
- * INPUTS:
- * over_temp_cal: Over-temp main data structure.
- * min_num_model_pts: Minimum number of model points per model
- * calculation update.
- * min_update_interval_nanos: Minimum model update interval.
- * delta_temp_per_bin: Temperature span that defines the spacing of
- * collected model estimates.
- * max_error_limit: Model acceptance fit error tolerance.
- * age_limit_nanos: Sets the age limit beyond which a offset
- * estimate is removed from 'model_data'.
- * temp_sensitivity_limit: Values that define the upper limits for the
- * sensor_intercept_limit: model parameters. The acceptance of new model
- * parameters must satisfy:
- * i. ABS(temp_sensitivity) < temp_sensitivity_limit
- * ii. ABS(sensor_intercept) < sensor_intercept_limit
- * over_temp_enable: Flag that determines whether over-temp sensor
- * offset compensation is applied.
- */
-void overTempCalInit(struct OverTempCal *over_temp_cal,
- size_t min_num_model_pts,
- uint64_t min_update_interval_nanos,
- float delta_temp_per_bin, float max_error_limit,
- uint64_t age_limit_nanos, float temp_sensitivity_limit,
- float sensor_intercept_limit, bool over_temp_enable);
-
-/*
- * Sets the over-temp calibration model parameters.
- *
- * INPUTS:
- * over_temp_cal: Over-temp main data structure.
- * offset: Update values for the latest offset estimate (array).
- * offset_temp: Measured temperature for the offset estimate.
- * timestamp_nanos: Timestamp for the offset estimate [nanoseconds].
- * temp_sensitivity: Modeled temperature sensitivity (array).
- * sensor_intercept: Linear model intercept for the over-temp model (array).
- * jump_start_model: When 'true' populates an empty 'model_data' array using
- * valid input model parameters.
- *
- * NOTE: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- */
-void overTempCalSetModel(struct OverTempCal *over_temp_cal, const float *offset,
- float offset_temp, uint64_t timestamp_nanos,
- const float *temp_sensitivity,
- const float *sensor_intercept, bool jump_start_model);
-
-/*
- * Gets the over-temp calibration model parameters.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * OUTPUTS:
- * offset: Offset values for the latest offset estimate (array).
- * offset_temp: Measured temperature for the offset estimate.
- * timestamp_nanos: Timestamp for the offset estimate [nanoseconds].
- * temp_sensitivity: Modeled temperature sensitivity (array).
- * sensor_intercept: Linear model intercept for the over-temp model (array).
- *
- * NOTE: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- */
-void overTempCalGetModel(struct OverTempCal *over_temp_cal, float *offset,
- float *offset_temp, uint64_t *timestamp_nanos,
- float *temp_sensitivity, float *sensor_intercept);
-
-/*
- * Removes the over-temp compensated offset from the input sensor data.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * timestamp_nanos: Timestamp of the sensor estimate update.
- * xi, yi, zi: 3-axis sensor data to be compensated.
- * OUTPUTS:
- * xo, yo, zo: 3-axis sensor data that has been compensated.
- */
-void overTempCalRemoveOffset(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos, float xi, float yi,
- float zi, float *xo, float *yo, float *zo);
-
-// Returns true when a new over-temp model update is available; and the
-// 'new_overtemp_model_available' flag is reset.
-bool overTempCalNewModelUpdateAvailable(struct OverTempCal *over_temp_cal);
-
-/*
- * Updates the sensor's offset estimate and conditionally assimilates it into
- * the over-temp model data set, 'model_data'.
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * timestamp_nanos: Timestamp of the sensor estimate update.
- * offset: 3-axis sensor data to be compensated (array).
- * temperature_celsius: Measured temperature for the new sensor estimate.
- *
- * NOTE: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- */
-void overTempCalUpdateSensorEstimate(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos,
- const float *offset,
- float temperature_celsius);
-
-// Updates the temperature at which the offset compensation is performed (i.e.,
-// the current measured temperature value). This function is provided mainly for
-// flexibility since temperature updates may come in from a source other than
-// the sensor itself, and at a different rate.
-void overTempCalSetTemperature(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos,
- float temperature_celsius);
-
-/*
- * Computes the maximum absolute error between the 'model_data' estimates and
- * the estimate determined by the input model parameters.
- * max_error (over all i)
- * |model_data[i]->offset_xyz -
- * getCompensatedOffset(model_data[i]->offset_temp, temp_sensitivity,
- * sensor_intercept)|
- *
- * INPUTS:
- * over_temp_cal: Over-temp data structure.
- * temp_sensitivity: Model temperature sensitivity to test (array).
- * sensor_intercept: Model intercept to test (array).
- * OUTPUTS:
- * max_error: Maximum absolute error for the candidate model (array).
- *
- * NOTE 1: Arrays are all 3-dimensional with indices: 0=x, 1=y, 2=z.
- * NOTE 2: This function is provided for testing purposes.
- */
-void getModelError(const struct OverTempCal *over_temp_cal,
- const float *temp_sensitivity, const float *sensor_intercept,
- float *max_error);
-
-#ifdef OVERTEMPCAL_DBG_ENABLED
-// This debug printout function assumes the input sensor data is a gyroscope
-// [rad/sec].
-void overTempCalDebugPrint(struct OverTempCal *over_temp_cal,
- uint64_t timestamp_nanos);
-#endif // OVERTEMPCAL_DBG_ENABLED
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_OVER_TEMP_OVER_TEMP_CAL_H_
diff --git a/firmware/os/algos/calibration/util/cal_log.h b/firmware/os/algos/calibration/util/cal_log.h
index 64f70f8e..dca59fdf 100644
--- a/firmware/os/algos/calibration/util/cal_log.h
+++ b/firmware/os/algos/calibration/util/cal_log.h
@@ -1,3 +1,6 @@
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_UTIL_CAL_LOG_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_UTIL_CAL_LOG_H_
+
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -19,23 +22,16 @@
* Logging macros for printing formatted strings to Nanohub.
*/
///////////////////////////////////////////////////////////////
-#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_UTIL_CAL_LOG_H_
-#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_CALIBRATION_UTIL_CAL_LOG_H_
-#ifdef GCC_DEBUG_LOG
-# include <stdio.h>
-# define CAL_DEBUG_LOG(tag, fmt, ...) \
- printf("%s " fmt "\n", tag, ##__VA_ARGS__);
-#else // GCC_DEBUG_LOG
-# include <seos.h>
-# ifndef LOG_FUNC
-# define LOG_FUNC(level, fmt, ...) osLog(level, fmt, ##__VA_ARGS__)
-# endif // LOG_FUNC
-# define LOGD_TAG(tag, fmt, ...) \
- LOG_FUNC(LOG_DEBUG, "%s " fmt "\n", tag, ##__VA_ARGS__)
-# define CAL_DEBUG_LOG(tag, fmt, ...) \
- osLog(LOG_DEBUG, "%s " fmt, tag, ##__VA_ARGS__);
-#endif // GCC_DEBUG_LOG
+
+#ifndef LOG_FUNC
+#include <seos.h>
+#define LOG_FUNC(level, fmt, ...) osLog(level, fmt, ##__VA_ARGS__)
+#define LOGD_TAG(tag, fmt, ...) \
+ LOG_FUNC(LOG_DEBUG, "%s " fmt "\n", tag, ##__VA_ARGS__)
+#endif
+
+#define CAL_DEBUG_LOG LOGD_TAG
#ifdef __cplusplus
extern "C" {