C++程序  |  204行  |  6.28 KB

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "calibration/common/diversity_checker.h"

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "common/math/vec.h"

#define MAX_FIT_MAG 70.0f
#define MIN_FIT_MAG 20.0f

// Struct initialization.
void diversityCheckerInit(
    struct DiversityChecker* diverse_data,
    size_t min_num_diverse_vectors,
    size_t max_num_max_distance,
    float var_threshold,
    float max_min_threshold,
    float local_field,
    float threshold_tuning_param,
    float max_distance_tuning_param) {
  ASSERT_NOT_NULL(diverse_data);

  // Initialize parameters.
  diverse_data->threshold_tuning_param_sq =
      (threshold_tuning_param * threshold_tuning_param);
  diverse_data->max_distance_tuning_param_sq =
      (max_distance_tuning_param * max_distance_tuning_param);

  // Updating the threshold and max_distance using assumed local field.
  // Testing for zero and negative local_field.
  if (local_field <= 0) {
    local_field = 1;
  }
  diversityCheckerLocalFieldUpdate(diverse_data, local_field);
  diverse_data->min_num_diverse_vectors = min_num_diverse_vectors;

  // Checking for min_num_diverse_vectors = 0.
  if (min_num_diverse_vectors < 1) {
    diverse_data->min_num_diverse_vectors = 1;
  }
  diverse_data->max_num_max_distance = max_num_max_distance;
  diverse_data->var_threshold = var_threshold;
  diverse_data->max_min_threshold = max_min_threshold;

  // Setting the rest to zero.
  diversityCheckerReset(diverse_data);
}

// Reset
void diversityCheckerReset(struct DiversityChecker* diverse_data) {
  ASSERT_NOT_NULL(diverse_data);
  // Clear data memory.
  memset(&diverse_data->diverse_data, 0,
         sizeof(diverse_data->diverse_data));

  // Resetting counters and data full bit.
  diverse_data->num_points = 0;
  diverse_data->num_max_dist_violations = 0;
  diverse_data->data_full = false;
}

void diversityCheckerUpdate(
    struct DiversityChecker* diverse_data, float x, float y, float z) {
  ASSERT_NOT_NULL(diverse_data);

  // Converting three single inputs to a vector.
  const float vec[3] = {x, y, z};

  // Result vector for vector difference.
  float vec_diff[3];

  // normSquared result (k)
  float norm_squared_result;

  // If memory is full, no need to run through the data.
  if (!diverse_data->data_full) {
    size_t i;
    // Running over all existing data points
    for (i = 0; i < diverse_data->num_points; ++i) {
      // v = v1 - v2;
      vecSub(vec_diff,
             &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
             vec,
             THREE_AXIS_DATA_DIM);

      // k = |v|^2
      norm_squared_result = vecNormSquared(vec_diff, THREE_AXIS_DATA_DIM);

      // if k < Threshold then leave the function.
      if (norm_squared_result < diverse_data->threshold) {
        return;
      }

      // if k > max_distance, count and leave the function.
      if (norm_squared_result > diverse_data->max_distance) {
        diverse_data->num_max_dist_violations++;
        return;
      }
    }

    // If none of the above caused to leave the function, data is diverse.
    // Notice that the first data vector will be stored no matter what.
    memcpy(&diverse_data->
           diverse_data[diverse_data->num_points * THREE_AXIS_DATA_DIM],
           vec,
           sizeof(float) * THREE_AXIS_DATA_DIM);
    // Count new data point.
    diverse_data->num_points++;

    // Setting data_full to 1, if memory is full.
    if (diverse_data->num_points == NUM_DIVERSE_VECTORS) {
      diverse_data->data_full = true;
    }
  }
}

bool diversityCheckerNormQuality(struct DiversityChecker* diverse_data,
                                 float x_bias,
                                 float y_bias,
                                 float z_bias) {
  ASSERT_NOT_NULL(diverse_data);
  // If not enough diverse data points or max distance violations return false.
  if (diverse_data->num_points <= diverse_data->min_num_diverse_vectors ||
      diverse_data->num_max_dist_violations >=
      diverse_data->max_num_max_distance) {
    return false;
  }
  float vec_bias[3] = {x_bias, y_bias, z_bias};
  float vec_bias_removed[3];
  float norm_results;
  float acc_norm = 0.0f;
  float acc_norm_square = 0.0f;
  float max;
  float min;
  size_t i;
  for (i = 0; i < diverse_data->num_points; ++i) {
    // v = v1 - v_bias;
    vecSub(vec_bias_removed,
           &diverse_data->diverse_data[i * THREE_AXIS_DATA_DIM],
           vec_bias,
           THREE_AXIS_DATA_DIM);

    // norm = ||v||
    norm_results = vecNorm(vec_bias_removed, THREE_AXIS_DATA_DIM);

    // Accumulate for mean and VAR.
    acc_norm += norm_results;
    acc_norm_square += norm_results * norm_results ;

    if (i == 0) {
      min = norm_results;
      max = norm_results;
    }
    // Finding min
    if (norm_results < min) {
      min = norm_results;
    }

    // Finding max.
    if (norm_results > max) {
      max = norm_results;
    }
    // can leave the function if max-min is violated
    // no need to continue.
    if ((max - min) > diverse_data->max_min_threshold) {
      return false;
    }
  }

  float inv = 1.0f / diverse_data->num_points;
  float var = (acc_norm_square - (acc_norm * acc_norm) * inv) * inv;
  return (var < diverse_data->var_threshold);
}

void diversityCheckerLocalFieldUpdate(struct DiversityChecker* diverse_data,
                                      float local_field) {
  if ((local_field < MAX_FIT_MAG) && (local_field > MIN_FIT_MAG)) {
    // Updating threshold based on the local field information.
    diverse_data->threshold = diverse_data->threshold_tuning_param_sq *
        (local_field * local_field);

    // Updating max distance based on the local field information.
    diverse_data->max_distance = diverse_data->max_distance_tuning_param_sq *
        (local_field * local_field);
  }
}