summaryrefslogtreecommitdiff
path: root/firmware/os/algos/calibration/common/diversity_checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/os/algos/calibration/common/diversity_checker.c')
-rw-r--r--firmware/os/algos/calibration/common/diversity_checker.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/firmware/os/algos/calibration/common/diversity_checker.c b/firmware/os/algos/calibration/common/diversity_checker.c
new file mode 100644
index 00000000..8e5c3e28
--- /dev/null
+++ b/firmware/os/algos/calibration/common/diversity_checker.c
@@ -0,0 +1,165 @@
+/*
+ * 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);
+}