Home | History | Annotate | Download | only in accelerometer
      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 <errno.h>
     20 #include <inttypes.h>
     21 #include <math.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 
     25 #include "calibration/util/cal_log.h"
     26 
     27 // clang-format off
     28 #define KSCALE \
     29   0.101936799f         // Scaling from m/s^2 to g (0.101 = 1/(9.81 m/s^2)).
     30 #define KSCALE2 9.81f  // Scaling from g to m/s^2.
     31 #define PHI 0.707f     // = 1/sqrt(2) gives a 45 degree angle for sorting data.
     32 #define PHIb -0.707f
     33 #define PHIZ 0.866f    // smaller Z sphere cap, opening angle is 30 degrees.
     34 #define PHIZb -0.866f
     35 #define G_NORM_MAX \
     36   1.38f  // Norm during stillness should be 1 g, checking from max min values.
     37 #define G_NORM_MIN 0.68f
     38 #define MAX_OFF 0.1f    // Will not accept offsets that are larger than 100 mg.
     39 #define MIN_TEMP 20.0f  // No Data is collected below 20 degree C.
     40 #define MAX_TEMP 45.0f  // No Data is collected above 45 degree C.
     41 #define TEMP_CUT 30     // Separation point for temperature buckets 30 degree C.
     42 #define EIGEN_RATIO 0.35f  // EIGEN_RATIO (must be greater than 0.35).
     43 #define EIGEN_MAG 0.97f    // Eigen value magnitude (must be greater than 0.97).
     44 #define ACCEL_NEW_BIAS_THRESHOLD (0.0f)  // Bias update detection threshold.
     45 #ifdef ACCEL_CAL_DBG_ENABLED
     46 #define TEMP_HIST_LOW \
     47   16  // Putting all Temp counts in first bucket for temp < 16 degree C.
     48 #define TEMP_HIST_HIGH \
     49   62  // Putting all Temp counts in last bucket for temp > 62 degree C.
     50 #define HIST_COUNT 9
     51 #endif
     52 #ifdef IMU_TEMP_DBG_ENABLED
     53 #define IMU_TEMP_DELTA_TIME_NANOS \
     54   5000000000   // Printing every 5 seconds IMU temp.
     55 #endif
     56 // clang-format on
     57 
     58 /////////// Start Debug //////////////////////
     59 
     60 #ifdef ACCEL_CAL_DBG_ENABLED
     61 // Total bucket Counter.
     62 static void accelStatsCounter(struct AccelStillDet *asd,
     63                               struct AccelStatsMem *adf) {
     64   // Sorting the data in the different buckets
     65   // x bucket ntx.
     66   if (PHI < asd->mean_x) {
     67     adf->ntx += 1;
     68   }
     69   // Negative x bucket ntxb.
     70   if (PHIb > asd->mean_x) {
     71     adf->ntxb += 1;
     72   }
     73   // Y bucket nty.
     74   if (PHI < asd->mean_y) {
     75     adf->nty += 1;
     76   }
     77   // Negative y bucket ntyb.
     78   if (PHIb > asd->mean_y) {
     79     adf->ntyb += 1;
     80   }
     81   // Z bucket ntz.
     82   if (PHIZ < asd->mean_z) {
     83     adf->ntz += 1;
     84   }
     85   // Negative z bucket ntzb.
     86   if (PHIZb > asd->mean_z) {
     87     adf->ntzb += 1;
     88   }
     89   // The leftover bucket ntle.
     90   if (PHI > asd->mean_x && PHIb < asd->mean_x && PHI > asd->mean_y &&
     91       PHIb < asd->mean_y && PHIZ > asd->mean_z && PHIZb < asd->mean_z) {
     92     adf->ntle += 1;
     93   }
     94 }
     95 
     96 // Temp histogram generation.
     97 static void accelTempHisto(struct AccelStatsMem *adf, float temp) {
     98   int index = 0;
     99 
    100   // Take temp at every stillness detection.
    101   adf->start_time_nanos = 0;
    102   if (temp <= TEMP_HIST_LOW) {
    103     adf->t_hist[0] += 1;
    104     return;
    105   }
    106   if (temp >= TEMP_HIST_HIGH) {
    107     adf->t_hist[TEMP_HISTOGRAM - 1] += 1;
    108     return;
    109   }
    110   index = (int)(((temp - TEMP_HIST_LOW) / 2) + 1);
    111   adf->t_hist[index] += 1;
    112 }
    113 
    114 #endif
    115 ///////// End Debug ////////////////////
    116 
    117 // Stillness detector reset.
    118 static void asdReset(struct AccelStillDet *asd) {
    119   asd->nsamples = 0;
    120   asd->start_time = 0;
    121   asd->acc_x = asd->acc_y = asd->acc_z = 0.0f;
    122   asd->acc_xx = asd->acc_yy = asd->acc_zz = 0.0f;
    123 }
    124 
    125 // Stillness detector init.
    126 static void accelStillInit(struct AccelStillDet *asd, uint32_t t0, uint32_t n_s,
    127                            float th) {
    128   memset(asd, 0, sizeof(struct AccelStillDet));
    129   asd->var_th = th;
    130   asd->min_batch_window = t0;
    131   asd->max_batch_window = t0 + 100000000;
    132   asd->min_batch_size = n_s;
    133   asd->n_still = 0;
    134 }
    135 
    136 // Good data reset.
    137 static void agdReset(struct AccelGoodData *agd) {
    138   agd->nx = agd->nxb = 0;
    139   agd->ny = agd->nyb = 0;
    140   agd->nz = agd->nzb = 0;
    141   agd->nle = 0;
    142   agd->acc_t = agd->acc_tt = 0;
    143   agd->e_x = agd->e_y = agd->e_z = 0;
    144 }
    145 
    146 // Good data init.
    147 static void accelGoodDataInit(struct AccelGoodData *agd, uint32_t fx,
    148                               uint32_t fxb, uint32_t fy, uint32_t fyb,
    149                               uint32_t fz, uint32_t fzb, uint32_t fle) {
    150   memset(agd, 0, sizeof(struct AccelGoodData));
    151   agd->nfx = fx;
    152   agd->nfxb = fxb;
    153   agd->nfy = fy;
    154   agd->nfyb = fyb;
    155   agd->nfz = fz;
    156   agd->nfzb = fzb;
    157   agd->nfle = fle;
    158   agd->var_t = 0;
    159   agd->mean_t = 0;
    160 }
    161 
    162 // Accel cal algo init (ready for temp buckets).
    163 static void accelCalAlgoInit(struct AccelCalAlgo *acc, uint32_t fx,
    164                              uint32_t fxb, uint32_t fy, uint32_t fyb,
    165                              uint32_t fz, uint32_t fzb, uint32_t fle) {
    166   accelGoodDataInit(&acc->agd, fx, fxb, fy, fyb, fz, fzb, fle);
    167   kasaInit(&acc->akf);
    168 }
    169 
    170 // Returns true when a new accel calibration is available.
    171 bool accelCalNewBiasAvailable(struct AccelCal *acc) {
    172   return fabsf(acc->x_bias - acc->x_bias_new) > ACCEL_NEW_BIAS_THRESHOLD ||
    173          fabsf(acc->y_bias - acc->y_bias_new) > ACCEL_NEW_BIAS_THRESHOLD ||
    174          fabsf(acc->z_bias - acc->z_bias_new) > ACCEL_NEW_BIAS_THRESHOLD;
    175 }
    176 
    177 // Accel cal init.
    178 void accelCalInit(struct AccelCal *acc,
    179                   const struct AccelCalParameters *parameters) {
    180   // Init core accel data.
    181   accelCalAlgoInit(&acc->ac1[0], parameters->fx, parameters->fxb,
    182                    parameters->fy, parameters->fyb, parameters->fz,
    183                    parameters->fzb, parameters->fle);
    184   accelCalAlgoInit(&acc->ac1[1], parameters->fx, parameters->fxb,
    185                    parameters->fy, parameters->fyb, parameters->fz,
    186                    parameters->fzb, parameters->fle);
    187 
    188   // Stillness Reset.
    189   accelStillInit(&acc->asd, parameters->t0, parameters->n_s, parameters->th);
    190 
    191 // Debug data init.
    192 #ifdef ACCEL_CAL_DBG_ENABLED
    193   memset(&acc->adf, 0, sizeof(struct AccelStatsMem));
    194 #endif
    195 
    196   acc->x_bias = acc->y_bias = acc->z_bias = 0;
    197   acc->x_bias_new = acc->y_bias_new = acc->z_bias_new = 0;
    198   acc->average_temperature_celsius = 0;
    199 
    200 #ifdef IMU_TEMP_DBG_ENABLED
    201   acc->temp_time_nanos = 0;
    202 #endif
    203 }
    204 
    205 // Stillness time check.
    206 static int stillnessBatchComplete(struct AccelStillDet *asd,
    207                                   uint64_t sample_time_nanos) {
    208   int complete = 0;
    209 
    210   // Checking if enough data is accumulated to calc Mean and Var.
    211   if ((sample_time_nanos - asd->start_time > asd->min_batch_window) &&
    212       (asd->nsamples > asd->min_batch_size)) {
    213     if (sample_time_nanos - asd->start_time < asd->max_batch_window) {
    214       complete = 1;
    215     } else {
    216       // Checking for too long batch window, if yes reset and start over.
    217       asdReset(asd);
    218       return complete;
    219     }
    220   } else if (sample_time_nanos - asd->start_time > asd->min_batch_window &&
    221              (asd->nsamples < asd->min_batch_size)) {
    222     // Not enough samples collected in max_batch_window during sample window.
    223     asdReset(asd);
    224   }
    225   return complete;
    226 }
    227 
    228 // Releasing Memory.
    229 void accelCalDestroy(struct AccelCal *acc) { (void)acc; }
    230 
    231 // Stillness Detection.
    232 static int accelStillnessDetection(struct AccelStillDet *asd,
    233                                    uint64_t sample_time_nanos, float x, float y,
    234                                    float z) {
    235   float inv = 0.0f;
    236   int complete = 0.0f;
    237   float g_norm = 0.0f;
    238 
    239   // Accumulate for mean and VAR.
    240   asd->acc_x += x;
    241   asd->acc_xx += x * x;
    242   asd->acc_y += y;
    243   asd->acc_yy += y * y;
    244   asd->acc_z += z;
    245   asd->acc_zz += z * z;
    246 
    247   // Setting a new start time and wait until T0 is reached.
    248   if (++asd->nsamples == 1) {
    249     asd->start_time = sample_time_nanos;
    250   }
    251   if (stillnessBatchComplete(asd, sample_time_nanos)) {
    252     // Getting 1/#samples and checking asd->nsamples != 0.
    253     if (0 < asd->nsamples) {
    254       inv = 1.0f / asd->nsamples;
    255     } else {
    256       // Something went wrong resetting and start over.
    257       asdReset(asd);
    258       return complete;
    259     }
    260     // Calculating the VAR = sum(x^2)/n - sum(x)^2/n^2.
    261     asd->var_x = (asd->acc_xx - (asd->acc_x * asd->acc_x) * inv) * inv;
    262     asd->var_y = (asd->acc_yy - (asd->acc_y * asd->acc_y) * inv) * inv;
    263     asd->var_z = (asd->acc_zz - (asd->acc_z * asd->acc_z) * inv) * inv;
    264     // Checking if sensor is still.
    265     if (asd->var_x < asd->var_th && asd->var_y < asd->var_th &&
    266         asd->var_z < asd->var_th) {
    267       // Calcluating the MEAN = sum(x) / n.
    268       asd->mean_x = asd->acc_x * inv;
    269       asd->mean_y = asd->acc_y * inv;
    270       asd->mean_z = asd->acc_z * inv;
    271       // Calculating g_norm^2.
    272       g_norm = asd->mean_x * asd->mean_x + asd->mean_y * asd->mean_y +
    273                asd->mean_z * asd->mean_z;
    274       // Magnitude check, still passsing when we have worse case offset.
    275       if (g_norm < G_NORM_MAX && g_norm > G_NORM_MIN) {
    276         complete = 1;
    277         asd->n_still += 1;
    278       }
    279     }
    280     asdReset(asd);
    281   }
    282   return complete;
    283 }
    284 
    285 // Good data detection, sorting and accumulate the data for Kasa.
    286 static int accelGoodData(struct AccelStillDet *asd, struct AccelCalAlgo *ac1,
    287                          float temp) {
    288   int complete = 0;
    289   float inv = 0.0f;
    290 
    291   // Sorting the data in the different buckets and accum
    292   // x bucket nx.
    293   if (PHI < asd->mean_x && ac1->agd.nx < ac1->agd.nfx) {
    294     ac1->agd.nx += 1;
    295     ac1->agd.acc_t += temp;
    296     ac1->agd.acc_tt += temp * temp;
    297     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    298   }
    299   // Negative x bucket nxb.
    300   if (PHIb > asd->mean_x && ac1->agd.nxb < ac1->agd.nfxb) {
    301     ac1->agd.nxb += 1;
    302     ac1->agd.acc_t += temp;
    303     ac1->agd.acc_tt += temp * temp;
    304     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    305   }
    306   // Y bucket ny.
    307   if (PHI < asd->mean_y && ac1->agd.ny < ac1->agd.nfy) {
    308     ac1->agd.ny += 1;
    309     ac1->agd.acc_t += temp;
    310     ac1->agd.acc_tt += temp * temp;
    311     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    312   }
    313   // Negative y bucket nyb.
    314   if (PHIb > asd->mean_y && ac1->agd.nyb < ac1->agd.nfyb) {
    315     ac1->agd.nyb += 1;
    316     ac1->agd.acc_t += temp;
    317     ac1->agd.acc_tt += temp * temp;
    318     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    319   }
    320   // Z bucket nz.
    321   if (PHIZ < asd->mean_z && ac1->agd.nz < ac1->agd.nfz) {
    322     ac1->agd.nz += 1;
    323     ac1->agd.acc_t += temp;
    324     ac1->agd.acc_tt += temp * temp;
    325     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    326   }
    327   // Negative z bucket nzb.
    328   if (PHIZb > asd->mean_z && ac1->agd.nzb < ac1->agd.nfzb) {
    329     ac1->agd.nzb += 1;
    330     ac1->agd.acc_t += temp;
    331     ac1->agd.acc_tt += temp * temp;
    332     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    333   }
    334   // The leftover bucket nle.
    335   if (PHI > asd->mean_x && PHIb < asd->mean_x && PHI > asd->mean_y &&
    336       PHIb < asd->mean_y && PHIZ > asd->mean_z && PHIZb < asd->mean_z &&
    337       ac1->agd.nle < ac1->agd.nfle) {
    338     ac1->agd.nle += 1;
    339     ac1->agd.acc_t += temp;
    340     ac1->agd.acc_tt += temp * temp;
    341     kasaAccumulate(&ac1->akf, asd->mean_x, asd->mean_y, asd->mean_z);
    342   }
    343   // Checking if all buckets are full.
    344   if (ac1->agd.nx == ac1->agd.nfx && ac1->agd.nxb == ac1->agd.nfxb &&
    345       ac1->agd.ny == ac1->agd.nfy && ac1->agd.nyb == ac1->agd.nfyb &&
    346       ac1->agd.nz == ac1->agd.nfz && ac1->agd.nzb == ac1->agd.nfzb) {
    347     //  Check if akf->nsamples is zero.
    348     if (ac1->akf.nsamples == 0) {
    349       agdReset(&ac1->agd);
    350       kasaReset(&ac1->akf);
    351       complete = 0;
    352       return complete;
    353     }
    354 
    355     // Normalize the data to the sample numbers.
    356     kasaNormalize(&ac1->akf);
    357 
    358     // Calculate the temp VAR and MEAN.
    359     inv = 1.0f / ac1->akf.nsamples;
    360     ac1->agd.var_t =
    361         (ac1->agd.acc_tt - (ac1->agd.acc_t * ac1->agd.acc_t) * inv) * inv;
    362     ac1->agd.mean_t = ac1->agd.acc_t * inv;
    363     complete = 1;
    364   }
    365 
    366   // If any of the buckets has a bigger number as specified, reset and start
    367   // over.
    368   if (ac1->agd.nx > ac1->agd.nfx || ac1->agd.nxb > ac1->agd.nfxb ||
    369       ac1->agd.ny > ac1->agd.nfy || ac1->agd.nyb > ac1->agd.nfyb ||
    370       ac1->agd.nz > ac1->agd.nfz || ac1->agd.nzb > ac1->agd.nfzb) {
    371     agdReset(&ac1->agd);
    372     kasaReset(&ac1->akf);
    373     complete = 0;
    374     return complete;
    375   }
    376   return complete;
    377 }
    378 
    379 // Eigen value magnitude and ratio test.
    380 static int accEigenTest(struct KasaFit *akf, struct AccelGoodData *agd) {
    381   // covariance matrix.
    382   struct Mat33 S;
    383   S.elem[0][0] = akf->acc_xx - akf->acc_x * akf->acc_x;
    384   S.elem[0][1] = S.elem[1][0] = akf->acc_xy - akf->acc_x * akf->acc_y;
    385   S.elem[0][2] = S.elem[2][0] = akf->acc_xz - akf->acc_x * akf->acc_z;
    386   S.elem[1][1] = akf->acc_yy - akf->acc_y * akf->acc_y;
    387   S.elem[1][2] = S.elem[2][1] = akf->acc_yz - akf->acc_y * akf->acc_z;
    388   S.elem[2][2] = akf->acc_zz - akf->acc_z * akf->acc_z;
    389 
    390   struct Vec3 eigenvals;
    391   struct Mat33 eigenvecs;
    392   mat33GetEigenbasis(&S, &eigenvals, &eigenvecs);
    393 
    394   float evmax = (eigenvals.x > eigenvals.y) ? eigenvals.x : eigenvals.y;
    395   evmax = (eigenvals.z > evmax) ? eigenvals.z : evmax;
    396 
    397   float evmin = (eigenvals.x < eigenvals.y) ? eigenvals.x : eigenvals.y;
    398   evmin = (eigenvals.z < evmin) ? eigenvals.z : evmin;
    399 
    400   float eigenvals_sum = eigenvals.x + eigenvals.y + eigenvals.z;
    401 
    402   // Testing for negative number.
    403   float evmag = (eigenvals_sum > 0) ? sqrtf(eigenvals_sum) : 0;
    404 
    405   // Passing when evmin/evmax> EIGEN_RATIO.
    406   int eigen_pass = (evmin > evmax * EIGEN_RATIO) && (evmag > EIGEN_MAG);
    407 
    408   agd->e_x = eigenvals.x;
    409   agd->e_y = eigenvals.y;
    410   agd->e_z = eigenvals.z;
    411 
    412   return eigen_pass;
    413 }
    414 
    415 // Updating the new bias and save to pointers. Return true if the bias changed.
    416 bool accelCalUpdateBias(struct AccelCal *acc, float *x, float *y, float *z) {
    417   *x = acc->x_bias_new;
    418   *y = acc->y_bias_new;
    419   *z = acc->z_bias_new;
    420 
    421   // Check to see if the bias changed since last call to accelCalUpdateBias.
    422   // Compiler does not allow us to use "==" and "!=" when comparing floats, so
    423   // just use "<" and ">".
    424   if ((acc->x_bias < acc->x_bias_new) || (acc->x_bias > acc->x_bias_new) ||
    425       (acc->y_bias < acc->y_bias_new) || (acc->y_bias > acc->y_bias_new) ||
    426       (acc->z_bias < acc->z_bias_new) || (acc->z_bias > acc->z_bias_new)) {
    427     acc->x_bias = acc->x_bias_new;
    428     acc->y_bias = acc->y_bias_new;
    429     acc->z_bias = acc->z_bias_new;
    430     return true;
    431   }
    432 
    433   return false;
    434 }
    435 
    436 // Set the (initial) bias.
    437 void accelCalBiasSet(struct AccelCal *acc, float x, float y, float z) {
    438   acc->x_bias = acc->x_bias_new = x;
    439   acc->y_bias = acc->y_bias_new = y;
    440   acc->z_bias = acc->z_bias_new = z;
    441 }
    442 
    443 // Removing the bias.
    444 void accelCalBiasRemove(struct AccelCal *acc, float *x, float *y, float *z) {
    445   *x = *x - acc->x_bias;
    446   *y = *y - acc->y_bias;
    447   *z = *z - acc->z_bias;
    448 }
    449 
    450 // Accel Cal Runner.
    451 void accelCalRun(struct AccelCal *acc, uint64_t sample_time_nanos, float x,
    452                  float y, float z, float temp) {
    453   // Scaling to 1g, better for the algorithm.
    454   x *= KSCALE;
    455   y *= KSCALE;
    456   z *= KSCALE;
    457 
    458   // DBG: IMU temp messages every 5s.
    459 #ifdef IMU_TEMP_DBG_ENABLED
    460   if ((sample_time_nanos - acc->temp_time_nanos) > IMU_TEMP_DELTA_TIME_NANOS) {
    461     CAL_DEBUG_LOG("IMU Temp Data: ",
    462                   ", " CAL_FORMAT_3DIGITS ",  %" PRIu64
    463                   ", " CAL_FORMAT_6DIGITS_TRIPLET " \n",
    464                   CAL_ENCODE_FLOAT(temp, 3),
    465                   sample_time_nanos,
    466                   CAL_ENCODE_FLOAT(acc->x_bias_new, 6),
    467                   CAL_ENCODE_FLOAT(acc->y_bias_new, 6),
    468                   CAL_ENCODE_FLOAT(acc->z_bias_new, 6));
    469     acc->temp_time_nanos = sample_time_nanos;
    470   }
    471 #endif
    472 
    473   int temp_gate = 0;
    474 
    475   // Temp GATE.
    476   if (temp < MAX_TEMP && temp > MIN_TEMP) {
    477     // Checking if accel is still.
    478     if (accelStillnessDetection(&acc->asd, sample_time_nanos, x, y, z)) {
    479 #ifdef ACCEL_CAL_DBG_ENABLED
    480       // Creating temp hist data.
    481       accelTempHisto(&acc->adf, temp);
    482 #endif
    483 
    484       // Two temp buckets.
    485       if (temp < TEMP_CUT) {
    486         temp_gate = 0;
    487       } else {
    488         temp_gate = 1;
    489       }
    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
    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