1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "calibration/common/diversity_checker.h"
18
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "common/math/vec.h"
24
25 #define MAX_FIT_MAG 70.0f
26 #define MIN_FIT_MAG 20.0f
27
28 // Struct initialization.
diversityCheckerInit(struct DiversityChecker * diverse_data,size_t min_num_diverse_vectors,size_t max_num_max_distance,float var_threshold,float max_min_threshold,float local_field,float threshold_tuning_param,float max_distance_tuning_param)29 void diversityCheckerInit(
30 struct DiversityChecker* diverse_data,
31 size_t min_num_diverse_vectors,
32 size_t max_num_max_distance,
33 float var_threshold,
34 float max_min_threshold,
35 float local_field,
36 float threshold_tuning_param,
37 float max_distance_tuning_param) {
38 ASSERT_NOT_NULL(diverse_data);
39
40 // Initialize parameters.
41 diverse_data->threshold_tuning_param_sq =
42 (threshold_tuning_param * threshold_tuning_param);
43 diverse_data->max_distance_tuning_param_sq =
44 (max_distance_tuning_param * max_distance_tuning_param);
45
46 // Updating the threshold and max_distance using assumed local field.
47 // Testing for zero and negative local_field.
48 if (local_field <= 0) {
49 local_field = 1;
50 }
51 diversityCheckerLocalFieldUpdate(diverse_data, local_field);
52 diverse_data->min_num_diverse_vectors = min_num_diverse_vectors;
53
54 // Checking for min_num_diverse_vectors = 0.
55 if (min_num_diverse_vectors < 1) {
56 diverse_data->min_num_diverse_vectors = 1;
57 }
58 diverse_data->max_num_max_distance = max_num_max_distance;
59 diverse_data->var_threshold = var_threshold;
60 diverse_data->max_min_threshold = max_min_threshold;
61
62 // Setting the rest to zero.
63 diversityCheckerReset(diverse_data);
64 }
65
66 // Reset
diversityCheckerReset(struct DiversityChecker * diverse_data)67 void diversityCheckerReset(struct DiversityChecker* diverse_data) {
68 ASSERT_NOT_NULL(diverse_data);
69 // Clear data memory.
70 memset(&diverse_data->diverse_data, 0,
71 sizeof(diverse_data->diverse_data));
72
73 // Resetting counters and data full bit.
74 diverse_data->num_points = 0;
75 diverse_data->num_max_dist_violations = 0;
76 diverse_data->data_full = false;
77 }
78
diversityCheckerUpdate(struct DiversityChecker * diverse_data,float x,float y,float z)79 void diversityCheckerUpdate(
80 struct DiversityChecker* diverse_data, float x, float y, float z) {
81 ASSERT_NOT_NULL(diverse_data);
82
83 // Converting three single inputs to a vector.
84 const float vec[3] = {x, y, z};
85
86 // Result vector for vector difference.
87 float vec_diff[3];
88
89 // normSquared result (k)
90 float norm_squared_result;
91
92 // If memory is full, no need to run through the data.
93 if (!diverse_data->data_full) {
94 size_t i;
95 // Running over all existing data points
96 for (i = 0; i < diverse_data->num_points; ++i) {
97 // v = v1 - v2;
98 vecSub(vec_diff,
99 &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
100 vec,
101 THREE_AXIS_DATA_DIM);
102
103 // k = |v|^2
104 norm_squared_result = vecNormSquared(vec_diff, THREE_AXIS_DATA_DIM);
105
106 // if k < Threshold then leave the function.
107 if (norm_squared_result < diverse_data->threshold) {
108 return;
109 }
110
111 // if k > max_distance, count and leave the function.
112 if (norm_squared_result > diverse_data->max_distance) {
113 diverse_data->num_max_dist_violations++;
114 return;
115 }
116 }
117
118 // If none of the above caused to leave the function, data is diverse.
119 // Notice that the first data vector will be stored no matter what.
120 memcpy(&diverse_data->
121 diverse_data[diverse_data->num_points * THREE_AXIS_DATA_DIM],
122 vec,
123 sizeof(float) * THREE_AXIS_DATA_DIM);
124 // Count new data point.
125 diverse_data->num_points++;
126
127 // Setting data_full to 1, if memory is full.
128 if (diverse_data->num_points == NUM_DIVERSE_VECTORS) {
129 diverse_data->data_full = true;
130 }
131 }
132 }
133
diversityCheckerNormQuality(struct DiversityChecker * diverse_data,float x_bias,float y_bias,float z_bias)134 bool diversityCheckerNormQuality(struct DiversityChecker* diverse_data,
135 float x_bias,
136 float y_bias,
137 float z_bias) {
138 ASSERT_NOT_NULL(diverse_data);
139 // If not enough diverse data points or max distance violations return false.
140 if (diverse_data->num_points <= diverse_data->min_num_diverse_vectors ||
141 diverse_data->num_max_dist_violations >=
142 diverse_data->max_num_max_distance) {
143 return false;
144 }
145 float vec_bias[3] = {x_bias, y_bias, z_bias};
146 float vec_bias_removed[3];
147 float norm_results;
148 float acc_norm = 0.0f;
149 float acc_norm_square = 0.0f;
150 float max;
151 float min;
152 size_t i;
153 for (i = 0; i < diverse_data->num_points; ++i) {
154 // v = v1 - v_bias;
155 vecSub(vec_bias_removed,
156 &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
157 vec_bias,
158 THREE_AXIS_DATA_DIM);
159
160 // norm = ||v||
161 norm_results = vecNorm(vec_bias_removed, THREE_AXIS_DATA_DIM);
162
163 // Accumulate for mean and VAR.
164 acc_norm += norm_results;
165 acc_norm_square += norm_results * norm_results ;
166
167 if (i == 0) {
168 min = norm_results;
169 max = norm_results;
170 }
171 // Finding min
172 if (norm_results < min) {
173 min = norm_results;
174 }
175
176 // Finding max.
177 if (norm_results > max) {
178 max = norm_results;
179 }
180 // can leave the function if max-min is violated
181 // no need to continue.
182 if ((max - min) > diverse_data->max_min_threshold) {
183 return false;
184 }
185 }
186
187 float inv = 1.0f / diverse_data->num_points;
188 float var = (acc_norm_square - (acc_norm * acc_norm) * inv) * inv;
189 return (var < diverse_data->var_threshold);
190 }
191
diversityCheckerLocalFieldUpdate(struct DiversityChecker * diverse_data,float local_field)192 void diversityCheckerLocalFieldUpdate(struct DiversityChecker* diverse_data,
193 float local_field) {
194 if ((local_field < MAX_FIT_MAG) && (local_field > MIN_FIT_MAG)) {
195 // Updating threshold based on the local field information.
196 diverse_data->threshold = diverse_data->threshold_tuning_param_sq *
197 (local_field * local_field);
198
199 // Updating max distance based on the local field information.
200 diverse_data->max_distance = diverse_data->max_distance_tuning_param_sq *
201 (local_field * local_field);
202 }
203 }
204