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