Home | History | Annotate | Download | only in mag_cal
      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/magnetometer/mag_cal/mag_cal.h"
     18 
     19 #include <errno.h>
     20 #include <inttypes.h>
     21 #include <string.h>
     22 
     23 #include "calibration/util/cal_log.h"
     24 
     25 // Local helper macro for printing log messages.
     26 #ifdef MAG_CAL_DEBUG_ENABLE
     27 #ifdef CAL_NO_FLOAT_FORMAT_STRINGS
     28 #define CAL_FORMAT_MAG_MEMORY                                          \
     29   "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, " \
     30   "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, " \
     31   "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, " \
     32   "%s%d.%03d, %s%d.%03d"
     33 #else
     34 #define CAL_FORMAT_MAG_MEMORY                                                \
     35   "%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, " \
     36   "%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f"
     37 #endif  // CAL_NO_FLOAT_FORMAT_STRINGS
     38 #endif  // MAG_CAL_DEBUG_ENABLE
     39 
     40 // clang-format off
     41 #define MAX_EIGEN_RATIO 15.0f
     42 #define MAX_EIGEN_MAG 70.0f          // uT
     43 #define MIN_EIGEN_MAG 20.0f          // uT
     44 #define MAX_FIT_MAG 70.0f
     45 #define MIN_FIT_MAG 20.0f
     46 #define MAX_BATCH_WINDOW 15000000UL  // 15 sec
     47 #define MIN_BATCH_SIZE 25            // samples
     48 #define MAX_DISTANCE_VIOLATIONS 2
     49 // clang-format
     50 
     51 // eigen value magnitude and ratio test.
     52 static int moc_eigen_test(struct KasaFit *kasa) {
     53   // covariance matrix.
     54   struct Mat33 S;
     55   S.elem[0][0] = kasa->acc_xx - kasa->acc_x * kasa->acc_x;
     56   S.elem[0][1] = S.elem[1][0] = kasa->acc_xy - kasa->acc_x * kasa->acc_y;
     57   S.elem[0][2] = S.elem[2][0] = kasa->acc_xz - kasa->acc_x * kasa->acc_z;
     58   S.elem[1][1] = kasa->acc_yy - kasa->acc_y * kasa->acc_y;
     59   S.elem[1][2] = S.elem[2][1] = kasa->acc_yz - kasa->acc_y * kasa->acc_z;
     60   S.elem[2][2] = kasa->acc_zz - kasa->acc_z * kasa->acc_z;
     61 
     62   struct Vec3 eigenvals;
     63   struct Mat33 eigenvecs;
     64   mat33GetEigenbasis(&S, &eigenvals, &eigenvecs);
     65 
     66   float evmax = (eigenvals.x > eigenvals.y) ? eigenvals.x : eigenvals.y;
     67   evmax = (eigenvals.z > evmax) ? eigenvals.z : evmax;
     68 
     69   float evmin = (eigenvals.x < eigenvals.y) ? eigenvals.x : eigenvals.y;
     70   evmin = (eigenvals.z < evmin) ? eigenvals.z : evmin;
     71 
     72   float eigenvals_sum = eigenvals.x + eigenvals.y + eigenvals.z;
     73 
     74   // Testing for negative number.
     75   float evmag = (eigenvals_sum > 0) ? sqrtf(eigenvals_sum) : 0;
     76 
     77   int eigen_pass = (evmin * MAX_EIGEN_RATIO > evmax) &&
     78                    (evmag > MIN_EIGEN_MAG) && (evmag < MAX_EIGEN_MAG);
     79 
     80   return eigen_pass;
     81 }
     82 
     83 void magCalReset(struct MagCal *moc) {
     84   kasaReset(&moc->kasa);
     85   diversityCheckerReset(&moc->diversity_checker);
     86   moc->start_time = 0;
     87   moc->kasa_batching = false;
     88 }
     89 
     90 static bool moc_batch_complete(struct MagCal *moc, uint64_t sample_time_us) {
     91   bool complete = false;
     92 
     93   if ((sample_time_us - moc->start_time > moc->min_batch_window_in_micros) &&
     94       (moc->kasa.nsamples > MIN_BATCH_SIZE)) {
     95     complete = true;
     96 
     97   } else if (sample_time_us - moc->start_time > MAX_BATCH_WINDOW) {
     98     // not enough samples collected in MAX_BATCH_WINDOW or too many
     99     // maximum distance violations detected.
    100     magCalReset(moc);
    101   }
    102 
    103   return complete;
    104 }
    105 
    106 void initMagCal(struct MagCal *moc,
    107                 const struct MagCalParameters *mag_cal_parameters,
    108                 const struct DiversityCheckerParameters *diverse_parameters) {
    109   magCalReset(moc);
    110   moc->update_time = 0;
    111   moc->min_batch_window_in_micros =
    112       mag_cal_parameters->min_batch_window_in_micros;
    113   moc->radius = 0.0f;
    114 
    115   moc->x_bias = mag_cal_parameters->x_bias;
    116   moc->y_bias = mag_cal_parameters->y_bias;
    117   moc->z_bias = mag_cal_parameters->z_bias;
    118 
    119   moc->c00 = mag_cal_parameters->c00;
    120   moc->c01 = mag_cal_parameters->c01;
    121   moc->c02 = mag_cal_parameters->c02;
    122   moc->c10 = mag_cal_parameters->c10;
    123   moc->c11 = mag_cal_parameters->c11;
    124   moc->c12 = mag_cal_parameters->c12;
    125   moc->c20 = mag_cal_parameters->c20;
    126   moc->c21 = mag_cal_parameters->c21;
    127   moc->c22 = mag_cal_parameters->c22;
    128 
    129 #ifdef MAG_CAL_DEBUG_ENABLE
    130   moc->mag_dbg.mag_trigger_count = 0;
    131   moc->mag_dbg.kasa_count = 0;
    132 #endif  // MAG_CAL_DEBUG_ENABLE
    133 
    134   // Diversity Checker
    135   diversityCheckerInit(&moc->diversity_checker, diverse_parameters);
    136 }
    137 
    138 void magCalDestroy(struct MagCal *moc) { (void)moc; }
    139 
    140 enum MagUpdate magCalUpdate(struct MagCal *moc, uint64_t sample_time_us,
    141                             float x, float y, float z) {
    142   enum MagUpdate new_bias = NO_UPDATE;
    143 
    144   // Diversity Checker Update.
    145   diversityCheckerUpdate(&moc->diversity_checker, x, y, z);
    146 
    147   // 1. run accumulators
    148   kasaAccumulate(&moc->kasa, x, y, z);
    149 
    150   if (moc->kasa.nsamples == 1) {
    151     moc->start_time = sample_time_us;
    152     moc->kasa_batching = true;
    153   }
    154 
    155   // 2. batch has enough samples?
    156   if (moc_batch_complete(moc, sample_time_us)) {
    157     kasaNormalize(&moc->kasa);
    158 
    159     // 3. eigen test
    160     if (moc_eigen_test(&moc->kasa)) {
    161       struct Vec3 bias;
    162       float radius;
    163       // 4. Kasa sphere fitting
    164       if (kasaFit(&moc->kasa, &bias, &radius, MAX_FIT_MAG, MIN_FIT_MAG)) {
    165 #ifdef MAG_CAL_DEBUG_ENABLE
    166         moc->mag_dbg.kasa_count++;
    167         CAL_DEBUG_LOG("[MAG_CAL:KASA UPDATE] :", CAL_FORMAT_3DIGITS_TRIPLET
    168                       ", " CAL_FORMAT_3DIGITS ", %" PRIu32 ", %" PRIu32,
    169                       CAL_ENCODE_FLOAT(bias.x, 3), CAL_ENCODE_FLOAT(bias.y, 3),
    170                       CAL_ENCODE_FLOAT(bias.z, 3), CAL_ENCODE_FLOAT(radius, 3),
    171                       moc->mag_dbg.kasa_count, moc->mag_dbg.mag_trigger_count);
    172 #endif  // MAG_CAL_DEBUG_ENABLE
    173 
    174         // Update the local field.
    175         diversityCheckerLocalFieldUpdate(&moc->diversity_checker, radius);
    176 
    177         // checking if data is diverse.
    178         if (diversityCheckerNormQuality(&moc->diversity_checker, bias.x, bias.y,
    179                                         bias.z) &&
    180             moc->diversity_checker.num_max_dist_violations <=
    181                 MAX_DISTANCE_VIOLATIONS) {
    182           // DEBUG PRINT OUT.
    183 #ifdef MAG_CAL_DEBUG_ENABLE
    184           moc->mag_dbg.mag_trigger_count++;
    185           moc->diversity_checker.diversity_dbg.new_trigger = 1;
    186           CAL_DEBUG_LOG(
    187               "[MAG_CAL:BIAS UPDATE] :", CAL_FORMAT_3DIGITS_TRIPLET ", "
    188               CAL_FORMAT_3DIGITS ", " CAL_FORMAT_6DIGITS ", "
    189               CAL_FORMAT_3DIGITS_TRIPLET ", %zu, " CAL_FORMAT_3DIGITS ", "
    190               CAL_FORMAT_3DIGITS ", %" PRIu32 ", %" PRIu32 ", %" PRIu64 ", "
    191               CAL_FORMAT_3DIGITS_TRIPLET ", %" PRIu64 "",
    192               CAL_ENCODE_FLOAT(bias.x, 3), CAL_ENCODE_FLOAT(bias.y, 3),
    193               CAL_ENCODE_FLOAT(bias.z, 3), CAL_ENCODE_FLOAT(radius, 3),
    194               CAL_ENCODE_FLOAT(moc->diversity_checker.diversity_dbg.var_log, 6),
    195               CAL_ENCODE_FLOAT(moc->diversity_checker.diversity_dbg.mean_log,
    196                                3),
    197               CAL_ENCODE_FLOAT(moc->diversity_checker.diversity_dbg.max_log, 3),
    198               CAL_ENCODE_FLOAT(moc->diversity_checker.diversity_dbg.min_log, 3),
    199               moc->diversity_checker.num_points,
    200               CAL_ENCODE_FLOAT(moc->diversity_checker.threshold, 3),
    201               CAL_ENCODE_FLOAT(moc->diversity_checker.max_distance, 3),
    202               moc->mag_dbg.mag_trigger_count,
    203               moc->mag_dbg.kasa_count,
    204               sample_time_us,
    205               CAL_ENCODE_FLOAT(moc->x_bias, 3),
    206               CAL_ENCODE_FLOAT(moc->y_bias, 3),
    207               CAL_ENCODE_FLOAT(moc->z_bias, 3),
    208               moc->update_time);
    209 #endif  // MAG_CAL_DEBUG_ENABLE
    210           moc->x_bias = bias.x;
    211           moc->y_bias = bias.y;
    212           moc->z_bias = bias.z;
    213 
    214           moc->radius = radius;
    215           moc->update_time = sample_time_us;
    216 
    217           new_bias = UPDATE_BIAS;
    218         }
    219       }
    220     }
    221     // 5. reset for next batch
    222     magCalReset(moc);
    223   }
    224 
    225   return new_bias;
    226 }
    227 
    228 void magCalGetBias(const struct MagCal *moc, float *x, float *y, float *z) {
    229   *x = moc->x_bias;
    230   *y = moc->y_bias;
    231   *z = moc->z_bias;
    232 }
    233 
    234 void magCalAddBias(struct MagCal *moc, float x, float y, float z) {
    235   moc->x_bias += x;
    236   moc->y_bias += y;
    237   moc->z_bias += z;
    238 }
    239 
    240 void magCalRemoveBias(struct MagCal *moc, float xi, float yi, float zi,
    241                       float *xo, float *yo, float *zo) {
    242   *xo = xi - moc->x_bias;
    243   *yo = yi - moc->y_bias;
    244   *zo = zi - moc->z_bias;
    245 }
    246 
    247 void magCalSetSoftiron(struct MagCal *moc, float c00, float c01, float c02,
    248                        float c10, float c11, float c12, float c20, float c21,
    249                        float c22) {
    250   moc->c00 = c00;
    251   moc->c01 = c01;
    252   moc->c02 = c02;
    253   moc->c10 = c10;
    254   moc->c11 = c11;
    255   moc->c12 = c12;
    256   moc->c20 = c20;
    257   moc->c21 = c21;
    258   moc->c22 = c22;
    259 }
    260 
    261 void magCalRemoveSoftiron(struct MagCal *moc, float xi, float yi, float zi,
    262                           float *xo, float *yo, float *zo) {
    263   *xo = moc->c00 * xi + moc->c01 * yi + moc->c02 * zi;
    264   *yo = moc->c10 * xi + moc->c11 * yi + moc->c12 * zi;
    265   *zo = moc->c20 * xi + moc->c21 * yi + moc->c22 * zi;
    266 }
    267 
    268 #if defined MAG_CAL_DEBUG_ENABLE
    269 // This function prints every second sample parts of the dbg diverse_data_log,
    270 // which ensures that all the messages get printed into the log file.
    271 void magLogPrint(struct DiversityChecker *diverse_data, float temp) {
    272   // Sample counter.
    273   static size_t sample_counter = 0;
    274   const float *data_log_ptr = &diverse_data->diversity_dbg.diverse_data_log[0];
    275   if (diverse_data->diversity_dbg.new_trigger == 1) {
    276     sample_counter++;
    277     if (sample_counter == 2) {
    278       CAL_DEBUG_LOG(
    279           "[MAG_CAL:MEMORY X] :", "%" PRIu32 ", " CAL_FORMAT_MAG_MEMORY ", "
    280           CAL_FORMAT_3DIGITS,
    281           diverse_data->diversity_dbg.diversity_count,
    282           CAL_ENCODE_FLOAT(data_log_ptr[0 * 3], 3),
    283           CAL_ENCODE_FLOAT(data_log_ptr[1 * 3], 3),
    284           CAL_ENCODE_FLOAT(data_log_ptr[2 * 3], 3),
    285           CAL_ENCODE_FLOAT(data_log_ptr[3 * 3], 3),
    286           CAL_ENCODE_FLOAT(data_log_ptr[4 * 3], 3),
    287           CAL_ENCODE_FLOAT(data_log_ptr[5 * 3], 3),
    288           CAL_ENCODE_FLOAT(data_log_ptr[6 * 3], 3),
    289           CAL_ENCODE_FLOAT(data_log_ptr[7 * 3], 3),
    290           CAL_ENCODE_FLOAT(data_log_ptr[8 * 3], 3),
    291           CAL_ENCODE_FLOAT(data_log_ptr[9 * 3], 3),
    292           CAL_ENCODE_FLOAT(data_log_ptr[10 * 3], 3),
    293           CAL_ENCODE_FLOAT(data_log_ptr[11 * 3], 3),
    294           CAL_ENCODE_FLOAT(data_log_ptr[12 * 3], 3),
    295           CAL_ENCODE_FLOAT(data_log_ptr[13 * 3], 3),
    296           CAL_ENCODE_FLOAT(data_log_ptr[14 * 3], 3),
    297           CAL_ENCODE_FLOAT(data_log_ptr[15 * 3], 3),
    298           CAL_ENCODE_FLOAT(data_log_ptr[16 * 3], 3),
    299           CAL_ENCODE_FLOAT(data_log_ptr[17 * 3], 3),
    300           CAL_ENCODE_FLOAT(data_log_ptr[18 * 3], 3),
    301           CAL_ENCODE_FLOAT(data_log_ptr[19 * 3], 3), CAL_ENCODE_FLOAT(temp, 3));
    302     }
    303 
    304     if (sample_counter == 4) {
    305       CAL_DEBUG_LOG(
    306           "[MAG_CAL:MEMORY Y] :", "%" PRIu32 ", " CAL_FORMAT_MAG_MEMORY,
    307           diverse_data->diversity_dbg.diversity_count,
    308           CAL_ENCODE_FLOAT(data_log_ptr[0 * 3 + 1], 3),
    309           CAL_ENCODE_FLOAT(data_log_ptr[1 * 3 + 1], 3),
    310           CAL_ENCODE_FLOAT(data_log_ptr[2 * 3 + 1], 3),
    311           CAL_ENCODE_FLOAT(data_log_ptr[3 * 3 + 1], 3),
    312           CAL_ENCODE_FLOAT(data_log_ptr[4 * 3 + 1], 3),
    313           CAL_ENCODE_FLOAT(data_log_ptr[5 * 3 + 1], 3),
    314           CAL_ENCODE_FLOAT(data_log_ptr[6 * 3 + 1], 3),
    315           CAL_ENCODE_FLOAT(data_log_ptr[7 * 3 + 1], 3),
    316           CAL_ENCODE_FLOAT(data_log_ptr[8 * 3 + 1], 3),
    317           CAL_ENCODE_FLOAT(data_log_ptr[9 * 3 + 1], 3),
    318           CAL_ENCODE_FLOAT(data_log_ptr[10 * 3 + 1], 3),
    319           CAL_ENCODE_FLOAT(data_log_ptr[11 * 3 + 1], 3),
    320           CAL_ENCODE_FLOAT(data_log_ptr[12 * 3 + 1], 3),
    321           CAL_ENCODE_FLOAT(data_log_ptr[13 * 3 + 1], 3),
    322           CAL_ENCODE_FLOAT(data_log_ptr[14 * 3 + 1], 3),
    323           CAL_ENCODE_FLOAT(data_log_ptr[15 * 3 + 1], 3),
    324           CAL_ENCODE_FLOAT(data_log_ptr[16 * 3 + 1], 3),
    325           CAL_ENCODE_FLOAT(data_log_ptr[17 * 3 + 1], 3),
    326           CAL_ENCODE_FLOAT(data_log_ptr[18 * 3 + 1], 3),
    327           CAL_ENCODE_FLOAT(data_log_ptr[19 * 3 + 1], 3));
    328     }
    329     if (sample_counter == 6) {
    330       CAL_DEBUG_LOG(
    331           "[MAG_CAL:MEMORY Z] :", "%" PRIu32 ", " CAL_FORMAT_MAG_MEMORY,
    332           diverse_data->diversity_dbg.diversity_count,
    333           CAL_ENCODE_FLOAT(data_log_ptr[0 * 3 + 2], 3),
    334           CAL_ENCODE_FLOAT(data_log_ptr[1 * 3 + 2], 3),
    335           CAL_ENCODE_FLOAT(data_log_ptr[2 * 3 + 2], 3),
    336           CAL_ENCODE_FLOAT(data_log_ptr[3 * 3 + 2], 3),
    337           CAL_ENCODE_FLOAT(data_log_ptr[4 * 3 + 2], 3),
    338           CAL_ENCODE_FLOAT(data_log_ptr[5 * 3 + 2], 3),
    339           CAL_ENCODE_FLOAT(data_log_ptr[6 * 3 + 2], 3),
    340           CAL_ENCODE_FLOAT(data_log_ptr[7 * 3 + 2], 3),
    341           CAL_ENCODE_FLOAT(data_log_ptr[8 * 3 + 2], 3),
    342           CAL_ENCODE_FLOAT(data_log_ptr[9 * 3 + 2], 3),
    343           CAL_ENCODE_FLOAT(data_log_ptr[10 * 3 + 2], 3),
    344           CAL_ENCODE_FLOAT(data_log_ptr[11 * 3 + 2], 3),
    345           CAL_ENCODE_FLOAT(data_log_ptr[12 * 3 + 2], 3),
    346           CAL_ENCODE_FLOAT(data_log_ptr[13 * 3 + 2], 3),
    347           CAL_ENCODE_FLOAT(data_log_ptr[14 * 3 + 2], 3),
    348           CAL_ENCODE_FLOAT(data_log_ptr[15 * 3 + 2], 3),
    349           CAL_ENCODE_FLOAT(data_log_ptr[16 * 3 + 2], 3),
    350           CAL_ENCODE_FLOAT(data_log_ptr[17 * 3 + 2], 3),
    351           CAL_ENCODE_FLOAT(data_log_ptr[18 * 3 + 2], 3),
    352           CAL_ENCODE_FLOAT(data_log_ptr[19 * 3 + 2], 3));
    353       sample_counter = 0;
    354       diverse_data->diversity_dbg.new_trigger = 0;
    355     }
    356   }
    357 }
    358 #endif  // MAG_CAL_DEBUG_ENABLE
    359