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/accelerometer/accel_cal.h"
18
19 #include <inttypes.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #if defined(ACCEL_CAL_DBG_ENABLED) || defined(IMU_TEMP_DBG_ENABLED)
25 #include "calibration/util/cal_log.h"
26 #endif // ACCEL_CAL_DBG_ENABLED || IMU_TEMP_DBG_ENABLED
27
28 // clang-format off
29 #define KSCALE \
30 0.101936799f // Scaling from m/s^2 to g (0.101 = 1/(9.81 m/s^2)).
31 #define KSCALE2 9.81f // Scaling from g to m/s^2.
32 #define PHI 0.707f // = 1/sqrt(2) gives a 45 degree angle for sorting data.
33 #define PHIb -0.707f
34 #define PHIZ 0.866f // smaller Z sphere cap, opening angle is 30 degrees.
35 #define PHIZb -0.866f
36 #define G_NORM_MAX \
37 1.38f // Norm during stillness should be 1 g, checking from max min values.
38 #define G_NORM_MIN 0.68f
39 #define MAX_OFF 0.1f // Will not accept offsets that are larger than 100 mg.
40 #define MIN_TEMP 20.0f // No Data is collected below 20 degree C.
41 #define MAX_TEMP 45.0f // No Data is collected above 45 degree C.
42 #define TEMP_CUT \
43 ((MAX_TEMP - MIN_TEMP) / \
44 ACCEL_CAL_NUM_TEMP_WINDOWS) // Separation window size for temperature buckets
45 // in degrees C.
46 #define EIGEN_RATIO 0.35f // EIGEN_RATIO (must be greater than 0.35).
47 #define EIGEN_MAG 0.97f // Eigen value magnitude (must be greater than 0.97).
48 #define ACCEL_NEW_BIAS_THRESHOLD (0.0f) // Bias update detection threshold.
49 #ifdef ACCEL_CAL_DBG_ENABLED
50 #define TEMP_HIST_LOW \
51 16 // Putting all Temp counts in first bucket for temp < 16 degree C.
52 #define TEMP_HIST_HIGH \
53 62 // Putting all Temp counts in last bucket for temp > 62 degree C.
54 #define HIST_COUNT 9
55 #endif
56 #ifdef IMU_TEMP_DBG_ENABLED
57 #define IMU_TEMP_DELTA_TIME_NANOS \
58 5000000000 // Printing every 5 seconds IMU temp.
59 #endif
60 // clang-format on
61
62 /////////// Start Debug //////////////////////
63
64 #ifdef ACCEL_CAL_DBG_ENABLED
65 // Total bucket Counter.
accelStatsCounter(struct AccelStillDet * asd,struct AccelStatsMem * adf)66 static void accelStatsCounter(struct AccelStillDet *asd,
67 struct AccelStatsMem *adf) {
68 // Sorting the data in the different buckets
69 // x bucket ntx.
70 if (PHI < asd->mean_x) {
71 adf->ntx += 1;
72 }
73 // Negative x bucket ntxb.
74 if (PHIb > asd->mean_x) {
75 adf->ntxb += 1;
76 }
77 // Y bucket nty.
78 if (PHI < asd->mean_y) {
79 adf->nty += 1;
80 }
81 // Negative y bucket ntyb.
82 if (PHIb > asd->mean_y) {
83 adf->ntyb += 1;
84 }
85 // Z bucket ntz.
86 if (PHIZ < asd->mean_z) {
87 adf->ntz += 1;
88 }
89 // Negative z bucket ntzb.
90 if (PHIZb > asd->mean_z) {
91 adf->ntzb += 1;
92 }
93 // The leftover bucket ntle.
94 if (PHI > asd->mean_x && PHIb < asd->mean_x && PHI > asd->mean_y &&
95 PHIb < asd->mean_y && PHIZ > asd->mean_z && PHIZb < asd->mean_z) {
96 adf->ntle += 1;
97 }
98 }
99
100 // Temp histogram generation.
accelTempHisto(struct AccelStatsMem * adf,float temp)101 static void accelTempHisto(struct AccelStatsMem *adf, float temp) {
102 int index = 0;
103
104 // Take temp at every stillness detection.
105 adf->start_time_nanos = 0;
106 if (temp <= TEMP_HIST_LOW) {
107 adf->t_hist[0] += 1;
108 return;
109 }
110 if (temp >= TEMP_HIST_HIGH) {
111 adf->t_hist[TEMP_HISTOGRAM - 1] += 1;
112 return;
113 }
114 index = (int)(((temp - TEMP_HIST_LOW) / 2) + 1);
115 adf->t_hist[index] += 1;
116 }
117
118 #endif
119 ///////// End Debug ////////////////////
120
121 // Stillness detector reset.
asdReset(struct AccelStillDet * asd)122 static void asdReset(struct AccelStillDet *asd) {
123 asd->nsamples = 0;
124 asd->start_time = 0;
125 asd->acc_x = asd->acc_y = asd->acc_z = 0.0f;
126 asd->acc_xx = asd->acc_yy = asd->acc_zz = 0.0f;
127 }
128
129 // Stillness detector init.
accelStillInit(struct AccelStillDet * asd,uint32_t t0,uint32_t n_s,float th)130 static void accelStillInit(struct AccelStillDet *asd, uint32_t t0, uint32_t n_s,
131 float th) {
132 memset(asd, 0, sizeof(struct AccelStillDet));
133 asd->var_th = th;
134 asd->min_batch_window = t0;
135 asd->max_batch_window = t0 + 100000000;
136 asd->min_batch_size = n_s;
137 asd->n_still = 0;
138 }
139
140 // Good data reset.
agdReset(struct AccelGoodData * agd)141 static void agdReset(struct AccelGoodData *agd) {
142 agd->nx = agd->nxb = 0;
143 agd->ny = agd->nyb = 0;
144 agd->nz = agd->nzb = 0;
145 agd->nle = 0;
146 agd->acc_t = agd->acc_tt = 0;
147 agd->e_x = agd->e_y = agd->e_z = 0;
148 }
149
150 // Good data init.
accelGoodDataInit(struct AccelGoodData * agd,uint32_t fx,uint32_t fxb,uint32_t fy,uint32_t fyb,uint32_t fz,uint32_t fzb,uint32_t fle)151 static void accelGoodDataInit(struct AccelGoodData *agd, uint32_t fx,
152 uint32_t fxb, uint32_t fy, uint32_t fyb,
153 uint32_t fz, uint32_t fzb, uint32_t fle) {
154 memset(agd, 0, sizeof(struct AccelGoodData));
155 agd->nfx = fx;
156 agd->nfxb = fxb;
157 agd->nfy = fy;
158 agd->nfyb = fyb;
159 agd->nfz = fz;
160 agd->nfzb = fzb;
161 agd->nfle = fle;
162 agd->var_t = 0;
163 agd->mean_t = 0;
164 }
165
166 // Accel cal algo init (ready for temp buckets).
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)167 static void accelCalAlgoInit(struct AccelCalAlgo *acc, uint32_t fx,
168 uint32_t fxb, uint32_t fy, uint32_t fyb,
169 uint32_t fz, uint32_t fzb, uint32_t fle) {
170 accelGoodDataInit(&acc->agd, fx, fxb, fy, fyb, fz, fzb, fle);
171 kasaInit(&acc->akf);
172 }
173
174 // Returns true when a new accel calibration is available.
accelCalNewBiasAvailable(struct AccelCal * acc)175 bool accelCalNewBiasAvailable(struct AccelCal *acc) {
176 return fabsf(acc->x_bias - acc->x_bias_new) > ACCEL_NEW_BIAS_THRESHOLD ||
177 fabsf(acc->y_bias - acc->y_bias_new) > ACCEL_NEW_BIAS_THRESHOLD ||
178 fabsf(acc->z_bias - acc->z_bias_new) > ACCEL_NEW_BIAS_THRESHOLD;
179 }
180
181 // Accel cal init.
accelCalInit(struct AccelCal * acc,const struct AccelCalParameters * parameters)182 void accelCalInit(struct AccelCal *acc,
183 const struct AccelCalParameters *parameters) {
184 int i;
185
186 for (i = 0; i < ACCEL_CAL_NUM_TEMP_WINDOWS; ++i) {
187 // Init core accel data.
188 accelCalAlgoInit(&acc->ac1[i], parameters->fx, parameters->fxb,
189 parameters->fy, parameters->fyb, parameters->fz,
190 parameters->fzb, parameters->fle);
191 }
192
193 // Stillness Reset.
194 accelStillInit(&acc->asd, parameters->t0, parameters->n_s, parameters->th);
195
196 // Debug data init.
197 #ifdef ACCEL_CAL_DBG_ENABLED
198 memset(&acc->adf, 0, sizeof(struct AccelStatsMem));
199 #endif
200
201 acc->x_bias = acc->y_bias = acc->z_bias = 0;
202 acc->x_bias_new = acc->y_bias_new = acc->z_bias_new = 0;
203 acc->average_temperature_celsius = 0;
204
205 #ifdef IMU_TEMP_DBG_ENABLED
206 acc->temp_time_nanos = 0;
207 #endif
208 }
209
210 // Stillness time check.
stillnessBatchComplete(struct AccelStillDet * asd,uint64_t sample_time_nanos)211 static int stillnessBatchComplete(struct AccelStillDet *asd,
212 uint64_t sample_time_nanos) {
213 int complete = 0;
214
215 // Checking if enough data is accumulated to calc Mean and Var.
216 if ((sample_time_nanos - asd->start_time > asd->min_batch_window) &&
217 (asd->nsamples > asd->min_batch_size)) {
218 if (sample_time_nanos - asd->start_time < asd->max_batch_window) {
219 complete = 1;
220 } else {
221 // Checking for too long batch window, if yes reset and start over.
222 asdReset(asd);
223 return complete;
224 }
225 } else if (sample_time_nanos - asd->start_time > asd->min_batch_window &&
226 (asd->nsamples < asd->min_batch_size)) {
227 // Not enough samples collected in max_batch_window during sample window.
228 asdReset(asd);
229 }
230 return complete;
231 }
232
233 // Releasing Memory.
accelCalDestroy(struct AccelCal * acc)234 void accelCalDestroy(struct AccelCal *acc) { (void)acc; }
235
236 // Stillness Detection.
accelStillnessDetection(struct AccelStillDet * asd,uint64_t sample_time_nanos,float x,float y,float z)237 static int accelStillnessDetection(struct AccelStillDet *asd,
238 uint64_t sample_time_nanos, float x, float y,
239 float z) {
240 float inv = 0.0f;
241 int complete = 0.0f;
242 float g_norm = 0.0f;
243
244 // Accumulate for mean and VAR.
245 asd->acc_x += x;
246 asd->acc_xx += x * x;
247 asd->acc_y += y;
248 asd->acc_yy += y * y;
249 asd->acc_z += z;
250 asd->acc_zz += z * z;
251
252 // Setting a new start time and wait until T0 is reached.
253 if (++asd->nsamples == 1) {
254 asd->start_time = sample_time_nanos;
255 }
256 if (stillnessBatchComplete(asd, sample_time_nanos)) {
257 // Getting 1/#samples and checking asd->nsamples != 0.
258 if (0 < asd->nsamples) {
259 inv = 1.0f / asd->nsamples;
260 } else {
261 // Something went wrong resetting and start over.
262 asdReset(asd);
263 return complete;
264 }
265 // Calculating the VAR = sum(x^2)/n - sum(x)^2/n^2.
266 asd->var_x = (asd->acc_xx - (asd->acc_x * asd->acc_x) * inv) * inv;
267 asd->var_y = (asd->acc_yy - (asd->acc_y * asd->acc_y) * inv) * inv;
268 asd->var_z = (asd->acc_zz - (asd->acc_z * asd->acc_z) * inv) * inv;
269 // Checking if sensor is still.
270 if (asd->var_x < asd->var_th && asd->var_y < asd->var_th &&
271 asd->var_z < asd->var_th) {
272 // Calcluating the MEAN = sum(x) / n.
273 asd->mean_x = asd->acc_x * inv;
274 asd->mean_y = asd->acc_y * inv;
275 asd->mean_z = asd->acc_z * inv;
276 // Calculating g_norm^2.
277 g_norm = asd->mean_x * asd->mean_x + asd->mean_y * asd->mean_y +
278 asd->mean_z * asd->mean_z;
279 // Magnitude check, still passsing when we have worse case offset.
280 if (g_norm < G_NORM_MAX && g_norm > G_NORM_MIN) {
281 complete = 1;
282 asd->n_still += 1;
283 }
284 }
285 asdReset(asd);
286 }
287 return complete;
288 }
289
290 // Good data detection, sorting and accumulate the data for Kasa.
accelGoodData(struct AccelStillDet * asd,struct AccelCalAlgo * ac1,float temp)291 static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
292 float temp) {
293 int complete = 0;
294 float inv = 0.0f;
295
296 // Sorting the data in the different buckets and accum
297 // x bucket nx.
298 if (PHI < asd->mean_x && ac1->agd.nx < ac1->agd.nfx) {
299 ac1->agd.nx += 1;
300 ac1->agd.acc_t += temp;
301 ac1->agd.acc_tt += temp * temp;
302 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
303 }
304 // Negative x bucket nxb.
305 if (PHIb > asd->mean_x && ac1->agd.nxb < ac1->agd.nfxb) {
306 ac1->agd.nxb += 1;
307 ac1->agd.acc_t += temp;
308 ac1->agd.acc_tt += temp * temp;
309 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
310 }
311 // Y bucket ny.
312 if (PHI < asd->mean_y && ac1->agd.ny < ac1->agd.nfy) {
313 ac1->agd.ny += 1;
314 ac1->agd.acc_t += temp;
315 ac1->agd.acc_tt += temp * temp;
316 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
317 }
318 // Negative y bucket nyb.
319 if (PHIb > asd->mean_y && ac1->agd.nyb < ac1->agd.nfyb) {
320 ac1->agd.nyb += 1;
321 ac1->agd.acc_t += temp;
322 ac1->agd.acc_tt += temp * temp;
323 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
324 }
325 // Z bucket nz.
326 if (PHIZ < asd->mean_z && ac1->agd.nz < ac1->agd.nfz) {
327 ac1->agd.nz += 1;
328 ac1->agd.acc_t += temp;
329 ac1->agd.acc_tt += temp * temp;
330 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
331 }
332 // Negative z bucket nzb.
333 if (PHIZb > asd->mean_z && ac1->agd.nzb < ac1->agd.nfzb) {
334 ac1->agd.nzb += 1;
335 ac1->agd.acc_t += temp;
336 ac1->agd.acc_tt += temp * temp;
337 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
338 }
339 // The leftover bucket nle.
340 if (PHI > asd->mean_x && PHIb < asd->mean_x && PHI > asd->mean_y &&
341 PHIb < asd->mean_y && PHIZ > asd->mean_z && PHIZb < asd->mean_z &&
342 ac1->agd.nle < ac1->agd.nfle) {
343 ac1->agd.nle += 1;
344 ac1->agd.acc_t += temp;
345 ac1->agd.acc_tt += temp * temp;
346 kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
347 }
348 // Checking if all buckets are full.
349 if (ac1->agd.nx == ac1->agd.nfx && ac1->agd.nxb == ac1->agd.nfxb &&
350 ac1->agd.ny == ac1->agd.nfy && ac1->agd.nyb == ac1->agd.nfyb &&
351 ac1->agd.nz == ac1->agd.nfz && ac1->agd.nzb == ac1->agd.nfzb) {
352 // Check if akf->nsamples is zero.
353 if (ac1->akf.nsamples == 0) {
354 agdReset(&ac1->agd);
355 kasaReset(&ac1->akf);
356 complete = 0;
357 return complete;
358 }
359
360 // Normalize the data to the sample numbers.
361 kasaNormalize(&ac1->akf);
362
363 // Calculate the temp VAR and MEAN.
364 inv = 1.0f / ac1->akf.nsamples;
365 ac1->agd.var_t =
366 (ac1->agd.acc_tt - (ac1->agd.acc_t * ac1->agd.acc_t) * inv) * inv;
367 ac1->agd.mean_t = ac1->agd.acc_t * inv;
368 complete = 1;
369 }
370
371 // If any of the buckets has a bigger number as specified, reset and start
372 // over.
373 if (ac1->agd.nx > ac1->agd.nfx || ac1->agd.nxb > ac1->agd.nfxb ||
374 ac1->agd.ny > ac1->agd.nfy || ac1->agd.nyb > ac1->agd.nfyb ||
375 ac1->agd.nz > ac1->agd.nfz || ac1->agd.nzb > ac1->agd.nfzb) {
376 agdReset(&ac1->agd);
377 kasaReset(&ac1->akf);
378 complete = 0;
379 return complete;
380 }
381 return complete;
382 }
383
384 // Eigen value magnitude and ratio test.
accEigenTest(struct KasaFit * akf,struct AccelGoodData * agd)385 static int accEigenTest(struct KasaFit *akf, struct AccelGoodData *agd) {
386 // covariance matrix.
387 struct Mat33 S;
388 S.elem[0][0] = akf->acc_xx - akf->acc_x * akf->acc_x;
389 S.elem[0][1] = S.elem[1][0] = akf->acc_xy - akf->acc_x * akf->acc_y;
390 S.elem[0][2] = S.elem[2][0] = akf->acc_xz - akf->acc_x * akf->acc_z;
391 S.elem[1][1] = akf->acc_yy - akf->acc_y * akf->acc_y;
392 S.elem[1][2] = S.elem[2][1] = akf->acc_yz - akf->acc_y * akf->acc_z;
393 S.elem[2][2] = akf->acc_zz - akf->acc_z * akf->acc_z;
394
395 struct Vec3 eigenvals;
396 struct Mat33 eigenvecs;
397 mat33GetEigenbasis(&S, &eigenvals, &eigenvecs);
398
399 float evmax = (eigenvals.x > eigenvals.y) ? eigenvals.x : eigenvals.y;
400 evmax = (eigenvals.z > evmax) ? eigenvals.z : evmax;
401
402 float evmin = (eigenvals.x < eigenvals.y) ? eigenvals.x : eigenvals.y;
403 evmin = (eigenvals.z < evmin) ? eigenvals.z : evmin;
404
405 float eigenvals_sum = eigenvals.x + eigenvals.y + eigenvals.z;
406
407 // Testing for negative number.
408 float evmag = (eigenvals_sum > 0) ? sqrtf(eigenvals_sum) : 0;
409
410 // Passing when evmin/evmax> EIGEN_RATIO.
411 int eigen_pass = (evmin > evmax * EIGEN_RATIO) && (evmag > EIGEN_MAG);
412
413 agd->e_x = eigenvals.x;
414 agd->e_y = eigenvals.y;
415 agd->e_z = eigenvals.z;
416
417 return eigen_pass;
418 }
419
420 // Updating the new bias and save to pointers. Return true if the bias changed.
accelCalUpdateBias(struct AccelCal * acc,float * x,float * y,float * z)421 bool accelCalUpdateBias(struct AccelCal *acc, float *x, float *y, float *z) {
422 *x = acc->x_bias_new;
423 *y = acc->y_bias_new;
424 *z = acc->z_bias_new;
425
426 // Check to see if the bias changed since last call to accelCalUpdateBias.
427 // Compiler does not allow us to use "==" and "!=" when comparing floats, so
428 // just use "<" and ">".
429 if ((acc->x_bias < acc->x_bias_new) || (acc->x_bias > acc->x_bias_new) ||
430 (acc->y_bias < acc->y_bias_new) || (acc->y_bias > acc->y_bias_new) ||
431 (acc->z_bias < acc->z_bias_new) || (acc->z_bias > acc->z_bias_new)) {
432 acc->x_bias = acc->x_bias_new;
433 acc->y_bias = acc->y_bias_new;
434 acc->z_bias = acc->z_bias_new;
435 return true;
436 }
437
438 return false;
439 }
440
441 // Set the (initial) bias.
accelCalBiasSet(struct AccelCal * acc,float x,float y,float z)442 void accelCalBiasSet(struct AccelCal *acc, float x, float y, float z) {
443 acc->x_bias = acc->x_bias_new = x;
444 acc->y_bias = acc->y_bias_new = y;
445 acc->z_bias = acc->z_bias_new = z;
446 }
447
448 // Removing the bias.
accelCalBiasRemove(struct AccelCal * acc,float * x,float * y,float * z)449 void accelCalBiasRemove(struct AccelCal *acc, float *x, float *y, float *z) {
450 *x = *x - acc->x_bias;
451 *y = *y - acc->y_bias;
452 *z = *z - acc->z_bias;
453 }
454
455 // Accel Cal Runner.
accelCalRun(struct AccelCal * acc,uint64_t sample_time_nanos,float x,float y,float z,float temp)456 void accelCalRun(struct AccelCal *acc, uint64_t sample_time_nanos, float x,
457 float y, float z, float temp) {
458 // Scaling to 1g, better for the algorithm.
459 x *= KSCALE;
460 y *= KSCALE;
461 z *= KSCALE;
462
463 // DBG: IMU temp messages every 5s.
464 #ifdef IMU_TEMP_DBG_ENABLED
465 if ((sample_time_nanos - acc->temp_time_nanos) > IMU_TEMP_DELTA_TIME_NANOS) {
466 CAL_DEBUG_LOG("IMU Temp Data: ",
467 ", " CAL_FORMAT_3DIGITS ", %" PRIu64
468 ", " CAL_FORMAT_6DIGITS_TRIPLET " \n",
469 CAL_ENCODE_FLOAT(temp, 3),
470 sample_time_nanos,
471 CAL_ENCODE_FLOAT(acc->x_bias_new, 6),
472 CAL_ENCODE_FLOAT(acc->y_bias_new, 6),
473 CAL_ENCODE_FLOAT(acc->z_bias_new, 6));
474 acc->temp_time_nanos = sample_time_nanos;
475 }
476 #endif
477
478 int temp_gate = 0;
479
480 // Temp GATE.
481 if (temp < MAX_TEMP && temp > MIN_TEMP) {
482 // Checking if accel is still.
483 if (accelStillnessDetection(&acc->asd, sample_time_nanos, x, y, z)) {
484 #ifdef ACCEL_CAL_DBG_ENABLED
485 // Creating temp hist data.
486 accelTempHisto(&acc->adf, temp);
487 #endif
488
489 temp_gate = (int) ((temp - MIN_TEMP) / TEMP_CUT);
490 #ifdef ACCEL_CAL_DBG_ENABLED
491 accelStatsCounter(&acc->asd, &acc->adf);
492 #endif
493 // If still -> pass the averaged accel data (mean) to the
494 // sorting, counting and accum function.
495 if (accelGoodData(&acc->asd, &acc->ac1[temp_gate], temp)) {
496 // Running the Kasa fit.
497 struct Vec3 bias;
498 float radius;
499
500 // Grabbing the fit from the MAG cal.
501 kasaFit(&acc->ac1[temp_gate].akf, &bias, &radius, G_NORM_MAX,
502 G_NORM_MIN);
503
504 // If offset is too large don't take.
505 if (fabsf(bias.x) < MAX_OFF && fabsf(bias.y) < MAX_OFF &&
506 fabsf(bias.z) < MAX_OFF) {
507 // Eigen Ratio Test.
508 if (accEigenTest(&acc->ac1[temp_gate].akf,
509 &acc->ac1[temp_gate].agd)) {
510 // Storing the new offsets and average temperature.
511 acc->x_bias_new = bias.x * KSCALE2;
512 acc->y_bias_new = bias.y * KSCALE2;
513 acc->z_bias_new = bias.z * KSCALE2;
514 acc->average_temperature_celsius = acc->ac1[temp_gate].agd.mean_t;
515 }
516 #ifdef ACCEL_CAL_DBG_ENABLED
517 //// Debug ///////
518 acc->adf.noff += 1;
519 // Resetting the counter for the offset history.
520 if (acc->adf.n_o > HIST_COUNT) {
521 acc->adf.n_o = 0;
522 }
523
524 // Storing the Debug data.
525 acc->adf.x_o[acc->adf.n_o] = bias.x;
526 acc->adf.y_o[acc->adf.n_o] = bias.y;
527 acc->adf.z_o[acc->adf.n_o] = bias.z;
528 acc->adf.e_x[acc->adf.n_o] = acc->ac1[temp_gate].agd.e_x;
529 acc->adf.e_y[acc->adf.n_o] = acc->ac1[temp_gate].agd.e_y;
530 acc->adf.e_z[acc->adf.n_o] = acc->ac1[temp_gate].agd.e_z;
531 acc->adf.var_t[acc->adf.n_o] = acc->ac1[temp_gate].agd.var_t;
532 acc->adf.mean_t[acc->adf.n_o] = acc->ac1[temp_gate].agd.mean_t;
533 acc->adf.cal_time[acc->adf.n_o] = sample_time_nanos;
534 acc->adf.rad[acc->adf.n_o] = radius;
535 acc->adf.n_o += 1;
536 #endif
537 } else {
538 #ifdef ACCEL_CAL_DBG_ENABLED
539 acc->adf.noff_max += 1;
540 #endif
541 }
542 ///////////////
543
544 // Resetting the structs for a new accel cal run.
545 agdReset(&acc->ac1[temp_gate].agd);
546 kasaReset(&acc->ac1[temp_gate].akf);
547 }
548 }
549 }
550 }
551
552 #ifdef ACCEL_CAL_DBG_ENABLED
553
554 // Local helper macro for printing log messages.
555 #ifdef CAL_NO_FLOAT_FORMAT_STRINGS
556 #define CAL_FORMAT_ACCEL_HISTORY \
557 "%s%d.%06d,%s%d.%06d,%s%d.%06d,%s%d.%06d,%s%d.%06d,%s%d.%06d,%s%d.%06d," \
558 "%s%d.%06d,%s%d.%06d,%s%d.%06d"
559 #else
560 #define CAL_FORMAT_ACCEL_HISTORY \
561 "%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f"
562 #endif // CAL_NO_FLOAT_FORMAT_STRINGS
563
564 // Debug Print Output
accelCalDebPrint(struct AccelCal * acc,float temp)565 void accelCalDebPrint(struct AccelCal *acc, float temp) {
566 static int32_t kk = 0;
567 if (++kk == 1000) {
568 // X offset history last 10 values.
569 CAL_DEBUG_LOG("[ACCEL_CAL]",
570 "{11," CAL_FORMAT_ACCEL_HISTORY "}(x_off history)\n",
571 CAL_ENCODE_FLOAT(acc->adf.x_o[0], 6),
572 CAL_ENCODE_FLOAT(acc->adf.x_o[1], 6),
573 CAL_ENCODE_FLOAT(acc->adf.x_o[2], 6),
574 CAL_ENCODE_FLOAT(acc->adf.x_o[3], 6),
575 CAL_ENCODE_FLOAT(acc->adf.x_o[4], 6),
576 CAL_ENCODE_FLOAT(acc->adf.x_o[5], 6),
577 CAL_ENCODE_FLOAT(acc->adf.x_o[6], 6),
578 CAL_ENCODE_FLOAT(acc->adf.x_o[7], 6),
579 CAL_ENCODE_FLOAT(acc->adf.x_o[8], 6),
580 CAL_ENCODE_FLOAT(acc->adf.x_o[9], 6));
581
582 // Y offset history last 10 values.
583 CAL_DEBUG_LOG("[ACCEL_CAL]",
584 "{12," CAL_FORMAT_ACCEL_HISTORY "}(y_off history)\n",
585 CAL_ENCODE_FLOAT(acc->adf.y_o[0], 6),
586 CAL_ENCODE_FLOAT(acc->adf.y_o[1], 6),
587 CAL_ENCODE_FLOAT(acc->adf.y_o[2], 6),
588 CAL_ENCODE_FLOAT(acc->adf.y_o[3], 6),
589 CAL_ENCODE_FLOAT(acc->adf.y_o[4], 6),
590 CAL_ENCODE_FLOAT(acc->adf.y_o[5], 6),
591 CAL_ENCODE_FLOAT(acc->adf.y_o[6], 6),
592 CAL_ENCODE_FLOAT(acc->adf.y_o[7], 6),
593 CAL_ENCODE_FLOAT(acc->adf.y_o[8], 6),
594 CAL_ENCODE_FLOAT(acc->adf.y_o[9], 6));
595
596 // Z offset history last 10 values.
597 CAL_DEBUG_LOG("[ACCEL_CAL]",
598 "{13," CAL_FORMAT_ACCEL_HISTORY "}(z_off history)\n",
599 CAL_ENCODE_FLOAT(acc->adf.z_o[0], 6),
600 CAL_ENCODE_FLOAT(acc->adf.z_o[1], 6),
601 CAL_ENCODE_FLOAT(acc->adf.z_o[2], 6),
602 CAL_ENCODE_FLOAT(acc->adf.z_o[3], 6),
603 CAL_ENCODE_FLOAT(acc->adf.z_o[4], 6),
604 CAL_ENCODE_FLOAT(acc->adf.z_o[5], 6),
605 CAL_ENCODE_FLOAT(acc->adf.z_o[6], 6),
606 CAL_ENCODE_FLOAT(acc->adf.z_o[7], 6),
607 CAL_ENCODE_FLOAT(acc->adf.z_o[8], 6),
608 CAL_ENCODE_FLOAT(acc->adf.z_o[9], 6));
609
610 // Temp history variation VAR of offset.
611 CAL_DEBUG_LOG("[ACCEL_CAL]",
612 "{14," CAL_FORMAT_ACCEL_HISTORY "}(VAR temp history)\n",
613 CAL_ENCODE_FLOAT(acc->adf.var_t[0], 6),
614 CAL_ENCODE_FLOAT(acc->adf.var_t[1], 6),
615 CAL_ENCODE_FLOAT(acc->adf.var_t[2], 6),
616 CAL_ENCODE_FLOAT(acc->adf.var_t[3], 6),
617 CAL_ENCODE_FLOAT(acc->adf.var_t[4], 6),
618 CAL_ENCODE_FLOAT(acc->adf.var_t[5], 6),
619 CAL_ENCODE_FLOAT(acc->adf.var_t[6], 6),
620 CAL_ENCODE_FLOAT(acc->adf.var_t[7], 6),
621 CAL_ENCODE_FLOAT(acc->adf.var_t[8], 6),
622 CAL_ENCODE_FLOAT(acc->adf.var_t[9], 6));
623
624 // Temp mean history of offset.
625 CAL_DEBUG_LOG("[ACCEL_CAL]",
626 "{15," CAL_FORMAT_ACCEL_HISTORY "}(MEAN Temp history)\n",
627 CAL_ENCODE_FLOAT(acc->adf.mean_t[0], 6),
628 CAL_ENCODE_FLOAT(acc->adf.mean_t[1], 6),
629 CAL_ENCODE_FLOAT(acc->adf.mean_t[2], 6),
630 CAL_ENCODE_FLOAT(acc->adf.mean_t[3], 6),
631 CAL_ENCODE_FLOAT(acc->adf.mean_t[4], 6),
632 CAL_ENCODE_FLOAT(acc->adf.mean_t[5], 6),
633 CAL_ENCODE_FLOAT(acc->adf.mean_t[6], 6),
634 CAL_ENCODE_FLOAT(acc->adf.mean_t[7], 6),
635 CAL_ENCODE_FLOAT(acc->adf.mean_t[8], 6),
636 CAL_ENCODE_FLOAT(acc->adf.mean_t[9], 6));
637
638 // KASA radius history.
639 CAL_DEBUG_LOG("[ACCEL_CAL]", "{16," CAL_FORMAT_ACCEL_HISTORY "}(radius)\n",
640 CAL_ENCODE_FLOAT(acc->adf.rad[0], 6),
641 CAL_ENCODE_FLOAT(acc->adf.rad[1], 6),
642 CAL_ENCODE_FLOAT(acc->adf.rad[2], 6),
643 CAL_ENCODE_FLOAT(acc->adf.rad[3], 6),
644 CAL_ENCODE_FLOAT(acc->adf.rad[4], 6),
645 CAL_ENCODE_FLOAT(acc->adf.rad[5], 6),
646 CAL_ENCODE_FLOAT(acc->adf.rad[6], 6),
647 CAL_ENCODE_FLOAT(acc->adf.rad[7], 6),
648 CAL_ENCODE_FLOAT(acc->adf.rad[8], 6),
649 CAL_ENCODE_FLOAT(acc->adf.rad[9], 6));
650 kk = 0;
651 }
652
653 if (kk == 750) {
654 // Eigen Vector X.
655 CAL_DEBUG_LOG("[ACCEL_CAL]", "{ 7," CAL_FORMAT_ACCEL_HISTORY "}(eigen x)\n",
656 CAL_ENCODE_FLOAT(acc->adf.e_x[0], 6),
657 CAL_ENCODE_FLOAT(acc->adf.e_x[1], 6),
658 CAL_ENCODE_FLOAT(acc->adf.e_x[2], 6),
659 CAL_ENCODE_FLOAT(acc->adf.e_x[3], 6),
660 CAL_ENCODE_FLOAT(acc->adf.e_x[4], 6),
661 CAL_ENCODE_FLOAT(acc->adf.e_x[5], 6),
662 CAL_ENCODE_FLOAT(acc->adf.e_x[6], 6),
663 CAL_ENCODE_FLOAT(acc->adf.e_x[7], 6),
664 CAL_ENCODE_FLOAT(acc->adf.e_x[8], 6),
665 CAL_ENCODE_FLOAT(acc->adf.e_x[9], 6));
666 // Y.
667 CAL_DEBUG_LOG("[ACCEL_CAL]", "{ 8," CAL_FORMAT_ACCEL_HISTORY "}(eigen y)\n",
668 CAL_ENCODE_FLOAT(acc->adf.e_y[0], 6),
669 CAL_ENCODE_FLOAT(acc->adf.e_y[1], 6),
670 CAL_ENCODE_FLOAT(acc->adf.e_y[2], 6),
671 CAL_ENCODE_FLOAT(acc->adf.e_y[3], 6),
672 CAL_ENCODE_FLOAT(acc->adf.e_y[4], 6),
673 CAL_ENCODE_FLOAT(acc->adf.e_y[5], 6),
674 CAL_ENCODE_FLOAT(acc->adf.e_y[6], 6),
675 CAL_ENCODE_FLOAT(acc->adf.e_y[7], 6),
676 CAL_ENCODE_FLOAT(acc->adf.e_y[8], 6),
677 CAL_ENCODE_FLOAT(acc->adf.e_y[9], 6));
678 // Z.
679 CAL_DEBUG_LOG("[ACCEL_CAL]", "{ 9," CAL_FORMAT_ACCEL_HISTORY "}(eigen z)\n",
680 CAL_ENCODE_FLOAT(acc->adf.e_z[0], 6),
681 CAL_ENCODE_FLOAT(acc->adf.e_z[1], 6),
682 CAL_ENCODE_FLOAT(acc->adf.e_z[2], 6),
683 CAL_ENCODE_FLOAT(acc->adf.e_z[3], 6),
684 CAL_ENCODE_FLOAT(acc->adf.e_z[4], 6),
685 CAL_ENCODE_FLOAT(acc->adf.e_z[5], 6),
686 CAL_ENCODE_FLOAT(acc->adf.e_z[6], 6),
687 CAL_ENCODE_FLOAT(acc->adf.e_z[7], 6),
688 CAL_ENCODE_FLOAT(acc->adf.e_z[8], 6),
689 CAL_ENCODE_FLOAT(acc->adf.e_z[9], 6));
690 // Accel Time in ns.
691 CAL_DEBUG_LOG("[ACCEL_CAL]",
692 "{10,%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64
693 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64
694 "}(timestamp ns)\n",
695 acc->adf.cal_time[0], acc->adf.cal_time[1],
696 acc->adf.cal_time[2], acc->adf.cal_time[3],
697 acc->adf.cal_time[4], acc->adf.cal_time[5],
698 acc->adf.cal_time[6], acc->adf.cal_time[7],
699 acc->adf.cal_time[8], acc->adf.cal_time[9]);
700 }
701
702 if (kk == 500) {
703 // Total bucket count.
704 CAL_DEBUG_LOG("[ACCEL_CAL]",
705 "{ 0,%2d, %2d, %2d, %2d, %2d, %2d, %2d}(Total Bucket #)\n",
706 (unsigned)acc->adf.ntx, (unsigned)acc->adf.ntxb,
707 (unsigned)acc->adf.nty, (unsigned)acc->adf.ntyb,
708 (unsigned)acc->adf.ntz, (unsigned)acc->adf.ntzb,
709 (unsigned)acc->adf.ntle);
710 // Live bucket count lower.
711 CAL_DEBUG_LOG("[ACCEL_CAL]",
712 "{ 1,%2d, %2d, %2d, %2d, %2d, %2d, %2d, %3d}(Bucket # "
713 "lower)\n",
714 (unsigned)acc->ac1[0].agd.nx, (unsigned)acc->ac1[0].agd.nxb,
715 (unsigned)acc->ac1[0].agd.ny, (unsigned)acc->ac1[0].agd.nyb,
716 (unsigned)acc->ac1[0].agd.nz, (unsigned)acc->ac1[0].agd.nzb,
717 (unsigned)acc->ac1[0].agd.nle,
718 (unsigned)acc->ac1[0].akf.nsamples);
719 // Live bucket count hogher.
720 CAL_DEBUG_LOG("[ACCEL_CAL]",
721 "{ 2,%2d, %2d, %2d, %2d, %2d, %2d, %2d, %3d}(Bucket # "
722 "higher)\n",
723 (unsigned)acc->ac1[1].agd.nx, (unsigned)acc->ac1[1].agd.nxb,
724 (unsigned)acc->ac1[1].agd.ny, (unsigned)acc->ac1[1].agd.nyb,
725 (unsigned)acc->ac1[1].agd.nz, (unsigned)acc->ac1[1].agd.nzb,
726 (unsigned)acc->ac1[1].agd.nle,
727 (unsigned)acc->ac1[1].akf.nsamples);
728 // Offset used.
729 CAL_DEBUG_LOG("[ACCEL_CAL]",
730 "{ 3,"CAL_FORMAT_6DIGITS_TRIPLET", %2d}(updated offset "
731 "x,y,z, total # of offsets)\n",
732 CAL_ENCODE_FLOAT(acc->x_bias, 6),
733 CAL_ENCODE_FLOAT(acc->y_bias, 6),
734 CAL_ENCODE_FLOAT(acc->z_bias, 6), (unsigned)acc->adf.noff);
735 // Offset New.
736 CAL_DEBUG_LOG("[ACCEL_CAL]",
737 "{ 4," CAL_FORMAT_6DIGITS_TRIPLET ", " CAL_FORMAT_6DIGITS
738 "}(New offset x,y,z, live temp)\n",
739 CAL_ENCODE_FLOAT(acc->x_bias_new, 6),
740 CAL_ENCODE_FLOAT(acc->y_bias_new, 6),
741 CAL_ENCODE_FLOAT(acc->z_bias_new, 6),
742 CAL_ENCODE_FLOAT(temp, 6));
743 // Temp Histogram.
744 CAL_DEBUG_LOG("[ACCEL_CAL]",
745 "{ 5,%7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, "
746 "%7d, %7d}(temp histo)\n",
747 (unsigned)acc->adf.t_hist[0], (unsigned)acc->adf.t_hist[1],
748 (unsigned)acc->adf.t_hist[2], (unsigned)acc->adf.t_hist[3],
749 (unsigned)acc->adf.t_hist[4], (unsigned)acc->adf.t_hist[5],
750 (unsigned)acc->adf.t_hist[6], (unsigned)acc->adf.t_hist[7],
751 (unsigned)acc->adf.t_hist[8], (unsigned)acc->adf.t_hist[9],
752 (unsigned)acc->adf.t_hist[10], (unsigned)acc->adf.t_hist[11],
753 (unsigned)acc->adf.t_hist[12]);
754 CAL_DEBUG_LOG("[ACCEL_CAL]",
755 "{ 6,%7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, %7d, "
756 "%7d}(temp histo)\n",
757 (unsigned)acc->adf.t_hist[13], (unsigned)acc->adf.t_hist[14],
758 (unsigned)acc->adf.t_hist[15], (unsigned)acc->adf.t_hist[16],
759 (unsigned)acc->adf.t_hist[17], (unsigned)acc->adf.t_hist[18],
760 (unsigned)acc->adf.t_hist[19], (unsigned)acc->adf.t_hist[20],
761 (unsigned)acc->adf.t_hist[21], (unsigned)acc->adf.t_hist[22],
762 (unsigned)acc->adf.t_hist[23], (unsigned)acc->adf.t_hist[24]);
763 }
764 }
765 #endif
766