(Mostly) remove Hungarian notation
This commit is contained in:
parent
61cab7d7cd
commit
d41f607b20
8 changed files with 527 additions and 530 deletions
418
fusion.c
418
fusion.c
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2014, Freescale Semiconductor, Inc.
|
||||
// All rights reserved.
|
||||
// vim: set ts=4:
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
// * Neither the name of Freescale Semiconductor, Inc. nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
|
@ -61,10 +61,6 @@
|
|||
#define ONEOVER3840 0.0002604166667F // 1 / 3840
|
||||
|
||||
|
||||
#define SENSORFS 100
|
||||
#define OVERSAMPLE_RATIO 4
|
||||
|
||||
|
||||
|
||||
static void fqAeq1(Quaternion_t *pqA);
|
||||
static void feCompassNED(float fR[][3], float *pfDelta, const float fBc[], const float fGp[]);
|
||||
|
|
@ -86,68 +82,69 @@ static float fatan_15deg(float x);
|
|||
|
||||
|
||||
// function initializes the 9DOF Kalman filter
|
||||
void fInit_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV, int16_t iSensorFS, int16_t iOverSampleRatio)
|
||||
void fInit_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV)
|
||||
{
|
||||
int8_t i, j; // loop counters
|
||||
|
||||
// reset the flag denoting that a first 9DOF orientation lock has been achieved
|
||||
SV->iFirstOrientationLock = 0;
|
||||
SV->FirstOrientationLock = 0;
|
||||
|
||||
// compute and store useful product terms to save floating point calculations later
|
||||
SV->fFastdeltat = 1.0F / (float) iSensorFS;
|
||||
SV->fdeltat = (float) iOverSampleRatio * SV->fFastdeltat;
|
||||
SV->fdeltatsq = SV->fdeltat * SV->fdeltat;
|
||||
SV->fcasq = FCA_9DOF_GBY_KALMAN * FCA_9DOF_GBY_KALMAN;
|
||||
SV->fcdsq = FCD_9DOF_GBY_KALMAN * FCD_9DOF_GBY_KALMAN;
|
||||
SV->fQwbplusQvG = FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN;
|
||||
SV->Fastdeltat = 1.0F / (float)SENSORFS;
|
||||
SV->deltat = (float)OVERSAMPLE_RATIO * SV->Fastdeltat;
|
||||
SV->deltatsq = SV->deltat * SV->deltat;
|
||||
SV->casq = FCA_9DOF_GBY_KALMAN * FCA_9DOF_GBY_KALMAN;
|
||||
SV->cdsq = FCD_9DOF_GBY_KALMAN * FCD_9DOF_GBY_KALMAN;
|
||||
SV->QwbplusQvG = FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN;
|
||||
|
||||
// initialize the fixed entries in the measurement matrix C
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (j = 0; j < 12; j++) {
|
||||
SV->fC6x12[i][j]= 0.0F;
|
||||
SV->C6x12[i][j]= 0.0F;
|
||||
}
|
||||
}
|
||||
SV->fC6x12[0][6] = SV->fC6x12[1][7] = SV->fC6x12[2][8] = 1.0F;
|
||||
SV->fC6x12[3][9] = SV->fC6x12[4][10] = SV->fC6x12[5][11] = -1.0F;
|
||||
SV->C6x12[0][6] = SV->C6x12[1][7] = SV->C6x12[2][8] = 1.0F;
|
||||
SV->C6x12[3][9] = SV->C6x12[4][10] = SV->C6x12[5][11] = -1.0F;
|
||||
|
||||
// zero a posteriori orientation, error vector xe+ (thetae+, be+, de+, ae+) and b+ and inertial
|
||||
f3x3matrixAeqI(SV->fRPl);
|
||||
fqAeq1(&(SV->fqPl));
|
||||
f3x3matrixAeqI(SV->RPl);
|
||||
fqAeq1(&(SV->qPl));
|
||||
for (i = X; i <= Z; i++) {
|
||||
SV->fThErrPl[i] = SV->fbErrPl[i] = SV->faErrSePl[i] = SV->fdErrSePl[i] = SV->fbPl[i] = 0.0F;
|
||||
SV->ThErrPl[i] = SV->bErrPl[i] = SV->aErrSePl[i] = SV->dErrSePl[i] = SV->bPl[i] = 0.0F;
|
||||
}
|
||||
|
||||
// initialize the reference geomagnetic vector (uT, global frame)
|
||||
SV->fDeltaPl = 0.0F;
|
||||
SV->DeltaPl = 0.0F;
|
||||
// initialize NED geomagnetic vector to zero degrees inclination
|
||||
SV->fmGl[X] = DEFAULTB;
|
||||
SV->fmGl[Y] = 0.0F;
|
||||
SV->fmGl[Z] = 0.0F;
|
||||
SV->mGl[X] = DEFAULTB;
|
||||
SV->mGl[Y] = 0.0F;
|
||||
SV->mGl[Z] = 0.0F;
|
||||
|
||||
// initialize noise variances for Qv and Qw matrix updates
|
||||
SV->fQvAA = FQVA_9DOF_GBY_KALMAN + FQWA_9DOF_GBY_KALMAN + FDEGTORAD * FDEGTORAD * SV->fdeltatsq * (FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN);
|
||||
SV->fQvMM = FQVM_9DOF_GBY_KALMAN + FQWD_9DOF_GBY_KALMAN + FDEGTORAD * FDEGTORAD * SV->fdeltatsq * DEFAULTB * DEFAULTB * (FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN);
|
||||
SV->QvAA = FQVA_9DOF_GBY_KALMAN + FQWA_9DOF_GBY_KALMAN + FDEGTORAD * FDEGTORAD * SV->deltatsq * (FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN);
|
||||
SV->QvMM = FQVM_9DOF_GBY_KALMAN + FQWD_9DOF_GBY_KALMAN + FDEGTORAD * FDEGTORAD * SV->deltatsq * DEFAULTB * DEFAULTB * (FQWB_9DOF_GBY_KALMAN + FQVG_9DOF_GBY_KALMAN);
|
||||
|
||||
// initialize the 12x12 noise covariance matrix Qw of the a priori error vector xe-
|
||||
// Qw is then recursively updated as P+ = (1 - K * C) * P- = (1 - K * C) * Qw and Qw updated from P+
|
||||
// Qw is then recursively updated as P+ = (1 - K * C) * P- = (1 - K * C) * Qw and Qw
|
||||
// updated from P+
|
||||
// zero the matrix Qw
|
||||
for (i = 0; i < 12; i++) {
|
||||
for (j = 0; j < 12; j++) {
|
||||
SV->fQw12x12[i][j] = 0.0F;
|
||||
SV->Qw12x12[i][j] = 0.0F;
|
||||
}
|
||||
}
|
||||
// loop over non-zero values
|
||||
for (i = 0; i < 3; i++) {
|
||||
// theta_e * theta_e terms
|
||||
SV->fQw12x12[i][i] = FQWINITTHTH_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i][i] = FQWINITTHTH_9DOF_GBY_KALMAN;
|
||||
// b_e * b_e terms
|
||||
SV->fQw12x12[i + 3][i + 3] = FQWINITBB_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 3][i + 3] = FQWINITBB_9DOF_GBY_KALMAN;
|
||||
// th_e * b_e terms
|
||||
SV->fQw12x12[i][i + 3] = SV->fQw12x12[i + 3][i] = FQWINITTHB_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i][i + 3] = SV->Qw12x12[i + 3][i] = FQWINITTHB_9DOF_GBY_KALMAN;
|
||||
// a_e * a_e terms
|
||||
SV->fQw12x12[i + 6][i + 6] = FQWINITAA_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 6][i + 6] = FQWINITAA_9DOF_GBY_KALMAN;
|
||||
// d_e * d_e terms
|
||||
SV->fQw12x12[i + 9][i + 9] = FQWINITDD_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 9][i + 9] = FQWINITDD_9DOF_GBY_KALMAN;
|
||||
}
|
||||
|
||||
// clear the reset flag
|
||||
|
|
@ -160,8 +157,8 @@ void fInit_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV, int16_t iSensorFS, int16_t
|
|||
// 9DOF orientation function implemented using a 12 element Kalman filter
|
||||
void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
||||
const AccelSensor_t *Accel, const MagSensor_t *Mag, const GyroSensor_t *Gyro,
|
||||
const MagCalibration_t *MagCal, int16_t iOverSampleRatio)
|
||||
{
|
||||
const MagCalibration_t *MagCal)
|
||||
{
|
||||
// local scalars and arrays
|
||||
float fopp, fadj, fhyp; // opposite, adjacent and hypoteneuse
|
||||
float fsindelta, fcosdelta; // sin and cos of inclination angle delta
|
||||
|
|
@ -193,7 +190,7 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
|
||||
// do a reset and return if requested
|
||||
if (SV->resetflag) {
|
||||
fInit_9DOF_GBY_KALMAN(SV, SENSORFS, OVERSAMPLE_RATIO);
|
||||
fInit_9DOF_GBY_KALMAN(SV);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -201,16 +198,16 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// initial orientation lock to accelerometer and magnetometer eCompass orientation
|
||||
// *********************************************************************************
|
||||
|
||||
// do a once-only orientation lock after the first valid magnetic calibration
|
||||
if (MagCal->iValidMagCal && !SV->iFirstOrientationLock) {
|
||||
// do a once-only orientation lock after the first valid magnetic calibration
|
||||
if (MagCal->ValidMagCal && !SV->FirstOrientationLock) {
|
||||
// get the 6DOF orientation matrix and initial inclination angle
|
||||
feCompassNED(SV->fRPl, &(SV->fDeltaPl), Mag->fBcFast, Accel->fGpFast);
|
||||
feCompassNED(SV->RPl, &(SV->DeltaPl), Mag->BcFast, Accel->GpFast);
|
||||
|
||||
// get the orientation quaternion from the orientation matrix
|
||||
fQuaternionFromRotationMatrix(SV->fRPl, &(SV->fqPl));
|
||||
fQuaternionFromRotationMatrix(SV->RPl, &(SV->qPl));
|
||||
|
||||
// set the orientation lock flag so this initial alignment is only performed once
|
||||
SV->iFirstOrientationLock = 1;
|
||||
SV->FirstOrientationLock = 1;
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
|
|
@ -219,31 +216,31 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
|
||||
// compute the angular velocity from the averaged high frequency gyro reading.
|
||||
// omega[k] = yG[k] - b-[k] = yG[k] - b+[k-1] (deg/s)
|
||||
SV->fOmega[X] = Gyro->fYp[X] - SV->fbPl[X];
|
||||
SV->fOmega[Y] = Gyro->fYp[Y] - SV->fbPl[Y];
|
||||
SV->fOmega[Z] = Gyro->fYp[Z] - SV->fbPl[Z];
|
||||
SV->Omega[X] = Gyro->Yp[X] - SV->bPl[X];
|
||||
SV->Omega[Y] = Gyro->Yp[Y] - SV->bPl[Y];
|
||||
SV->Omega[Z] = Gyro->Yp[Z] - SV->bPl[Z];
|
||||
|
||||
// initialize the a priori orientation quaternion to the previous a posteriori estimate
|
||||
SV->fqMi = SV->fqPl;
|
||||
SV->qMi = SV->qPl;
|
||||
|
||||
// integrate the buffered high frequency (typically 200Hz) gyro readings
|
||||
for (j = 0; j < iOverSampleRatio; j++) {
|
||||
for (j = 0; j < OVERSAMPLE_RATIO; j++) {
|
||||
// compute the incremental fast (typically 200Hz) rotation vector rvec (deg)
|
||||
for (i = X; i <= Z; i++) {
|
||||
rvec[i] = (((float)Gyro->iYpFast[j][i] * DEG_PER_SEC_PER_COUNT) - SV->fbPl[i])
|
||||
* SV->fFastdeltat;
|
||||
rvec[i] = (((float)Gyro->YpFast[j][i] * DEG_PER_SEC_PER_COUNT) - SV->bPl[i])
|
||||
* SV->Fastdeltat;
|
||||
}
|
||||
|
||||
// compute the incremental quaternion fDeltaq from the rotation vector
|
||||
fQuaternionFromRotationVectorDeg(&(SV->fDeltaq), rvec, 1.0F);
|
||||
fQuaternionFromRotationVectorDeg(&(SV->Deltaq), rvec, 1.0F);
|
||||
|
||||
// incrementally rotate the a priori orientation quaternion fqMi
|
||||
// the a posteriori quaternion fqPl is re-normalized later so this update is stable
|
||||
qAeqAxB(&(SV->fqMi), &(SV->fDeltaq));
|
||||
qAeqAxB(&(SV->qMi), &(SV->Deltaq));
|
||||
}
|
||||
|
||||
// get the a priori rotation matrix from the a priori quaternion
|
||||
fRotationMatrixFromQuaternion(SV->fRMi, &(SV->fqMi));
|
||||
fRotationMatrixFromQuaternion(SV->RMi, &(SV->qMi));
|
||||
|
||||
// *********************************************************************************
|
||||
// calculate a priori gyro, accelerometer and magnetometer estimates
|
||||
|
|
@ -255,22 +252,25 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// compute the a priori gyro estimate of the gravitational vector (g, sensor frame)
|
||||
// using an absolute rotation of the global frame gravity vector (with magnitude 1g)
|
||||
// NED gravity is along positive z axis
|
||||
SV->fgSeGyMi[i] = SV->fRMi[i][Z];
|
||||
SV->gSeGyMi[i] = SV->RMi[i][Z];
|
||||
|
||||
// compute a priori acceleration (a-) (g, sensor frame) from decayed a posteriori estimate (g, sensor frame)
|
||||
SV->faSeMi[i] = FCA_9DOF_GBY_KALMAN * SV->faSePl[i];
|
||||
// compute a priori acceleration (a-) (g, sensor frame) from decayed a
|
||||
// posteriori estimate (g, sensor frame)
|
||||
SV->aSeMi[i] = FCA_9DOF_GBY_KALMAN * SV->aSePl[i];
|
||||
|
||||
// compute the a priori gravity error vector (accelerometer minus gyro estimates) (g, sensor frame)
|
||||
// compute the a priori gravity error vector (accelerometer minus gyro estimates)
|
||||
// (g, sensor frame)
|
||||
// NED and Windows 8 have positive sign for gravity: y = g - a and g = y + a
|
||||
SV->fgErrSeMi[i] = Accel->fGpFast[i] + SV->faSeMi[i] - SV->fgSeGyMi[i];
|
||||
SV->gErrSeMi[i] = Accel->GpFast[i] + SV->aSeMi[i] - SV->gSeGyMi[i];
|
||||
|
||||
// compute the a priori gyro estimate of the geomagnetic vector (uT, sensor frame)
|
||||
// using an absolute rotation of the global frame geomagnetic vector (with magnitude B uT)
|
||||
// NED y component of geomagnetic vector in global frame is zero
|
||||
SV->fmSeGyMi[i] = SV->fRMi[i][X] * SV->fmGl[X] + SV->fRMi[i][Z] * SV->fmGl[Z];
|
||||
SV->mSeGyMi[i] = SV->RMi[i][X] * SV->mGl[X] + SV->RMi[i][Z] * SV->mGl[Z];
|
||||
|
||||
// compute the a priori geomagnetic error vector (magnetometer minus gyro estimates) (g, sensor frame)
|
||||
SV->fmErrSeMi[i] = Mag->fBcFast[i] - SV->fmSeGyMi[i];
|
||||
// compute the a priori geomagnetic error vector (magnetometer minus gyro estimates)
|
||||
// (g, sensor frame)
|
||||
SV->mErrSeMi[i] = Mag->BcFast[i] - SV->mSeGyMi[i];
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
|
|
@ -278,30 +278,30 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// *********************************************************************************
|
||||
|
||||
// update measurement matrix C with -alpha(g-)x and -alpha(m-)x from gyro (g, uT, sensor frame)
|
||||
SV->fC6x12[0][1] = FDEGTORAD * SV->fgSeGyMi[Z];
|
||||
SV->fC6x12[0][2] = -FDEGTORAD * SV->fgSeGyMi[Y];
|
||||
SV->fC6x12[1][2] = FDEGTORAD * SV->fgSeGyMi[X];
|
||||
SV->fC6x12[1][0] = -SV->fC6x12[0][1];
|
||||
SV->fC6x12[2][0] = -SV->fC6x12[0][2];
|
||||
SV->fC6x12[2][1] = -SV->fC6x12[1][2];
|
||||
SV->fC6x12[3][1] = FDEGTORAD * SV->fmSeGyMi[Z];
|
||||
SV->fC6x12[3][2] = -FDEGTORAD * SV->fmSeGyMi[Y];
|
||||
SV->fC6x12[4][2] = FDEGTORAD * SV->fmSeGyMi[X];
|
||||
SV->fC6x12[4][0] = -SV->fC6x12[3][1];
|
||||
SV->fC6x12[5][0] = -SV->fC6x12[3][2];
|
||||
SV->fC6x12[5][1] = -SV->fC6x12[4][2];
|
||||
SV->fC6x12[0][4] = -SV->fdeltat * SV->fC6x12[0][1];
|
||||
SV->fC6x12[0][5] = -SV->fdeltat * SV->fC6x12[0][2];
|
||||
SV->fC6x12[1][5] = -SV->fdeltat * SV->fC6x12[1][2];
|
||||
SV->fC6x12[1][3]= -SV->fC6x12[0][4];
|
||||
SV->fC6x12[2][3]= -SV->fC6x12[0][5];
|
||||
SV->fC6x12[2][4]= -SV->fC6x12[1][5];
|
||||
SV->fC6x12[3][4] = -SV->fdeltat * SV->fC6x12[3][1];
|
||||
SV->fC6x12[3][5] = -SV->fdeltat * SV->fC6x12[3][2];
|
||||
SV->fC6x12[4][5] = -SV->fdeltat * SV->fC6x12[4][2];
|
||||
SV->fC6x12[4][3] = -SV->fC6x12[3][4];
|
||||
SV->fC6x12[5][3] = -SV->fC6x12[3][5];
|
||||
SV->fC6x12[5][4] = -SV->fC6x12[4][5];
|
||||
SV->C6x12[0][1] = FDEGTORAD * SV->gSeGyMi[Z];
|
||||
SV->C6x12[0][2] = -FDEGTORAD * SV->gSeGyMi[Y];
|
||||
SV->C6x12[1][2] = FDEGTORAD * SV->gSeGyMi[X];
|
||||
SV->C6x12[1][0] = -SV->C6x12[0][1];
|
||||
SV->C6x12[2][0] = -SV->C6x12[0][2];
|
||||
SV->C6x12[2][1] = -SV->C6x12[1][2];
|
||||
SV->C6x12[3][1] = FDEGTORAD * SV->mSeGyMi[Z];
|
||||
SV->C6x12[3][2] = -FDEGTORAD * SV->mSeGyMi[Y];
|
||||
SV->C6x12[4][2] = FDEGTORAD * SV->mSeGyMi[X];
|
||||
SV->C6x12[4][0] = -SV->C6x12[3][1];
|
||||
SV->C6x12[5][0] = -SV->C6x12[3][2];
|
||||
SV->C6x12[5][1] = -SV->C6x12[4][2];
|
||||
SV->C6x12[0][4] = -SV->deltat * SV->C6x12[0][1];
|
||||
SV->C6x12[0][5] = -SV->deltat * SV->C6x12[0][2];
|
||||
SV->C6x12[1][5] = -SV->deltat * SV->C6x12[1][2];
|
||||
SV->C6x12[1][3]= -SV->C6x12[0][4];
|
||||
SV->C6x12[2][3]= -SV->C6x12[0][5];
|
||||
SV->C6x12[2][4]= -SV->C6x12[1][5];
|
||||
SV->C6x12[3][4] = -SV->deltat * SV->C6x12[3][1];
|
||||
SV->C6x12[3][5] = -SV->deltat * SV->C6x12[3][2];
|
||||
SV->C6x12[4][5] = -SV->deltat * SV->C6x12[4][2];
|
||||
SV->C6x12[4][3] = -SV->C6x12[3][4];
|
||||
SV->C6x12[5][3] = -SV->C6x12[3][5];
|
||||
SV->C6x12[5][4] = -SV->C6x12[4][5];
|
||||
|
||||
// *********************************************************************************
|
||||
// calculate the Kalman gain matrix K
|
||||
|
|
@ -322,10 +322,10 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
*pftmpA12x6ij = 0.0F;
|
||||
|
||||
// initialize pfC6x12jk for current j, k=0
|
||||
pfC6x12jk = SV->fC6x12[j];
|
||||
pfC6x12jk = SV->C6x12[j];
|
||||
|
||||
// initialize pfQw12x12ik for current i, k=0
|
||||
pfQw12x12ik = SV->fQw12x12[i];
|
||||
pfQw12x12ik = SV->Qw12x12[i];
|
||||
|
||||
// sum matrix products over inner loop over k
|
||||
for (k = 0; k < 12; k++) {
|
||||
|
|
@ -342,27 +342,27 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
pfC6x12jk++;
|
||||
pfQw12x12ik++;
|
||||
|
||||
} // end of loop over k
|
||||
}
|
||||
|
||||
// increment pftmpA12x6ij for next iteration of j
|
||||
pftmpA12x6ij++;
|
||||
|
||||
} // end of loop over j
|
||||
} // end of loop over i
|
||||
}
|
||||
}
|
||||
|
||||
// set symmetric P+ (6x6 scratch sub-matrix) to C * P- * C^T + Qv
|
||||
// = C * (Qw * C^T) + Qv = C * ftmpA12x6 + Qv
|
||||
// both C and ftmpA12x6 are sparse but not symmetric
|
||||
for (i = 0; i < 6; i++) { // loop over rows of P+
|
||||
// initialize pfPPlus12x12ij for current i, j=i
|
||||
pfPPlus12x12ij = SV->fPPlus12x12[i] + i;
|
||||
pfPPlus12x12ij = SV->PPlus12x12[i] + i;
|
||||
|
||||
for (j = i; j < 6; j++) { // loop over above diagonal columns of P+
|
||||
// zero P+[i][j]
|
||||
// zero P+[i][j]
|
||||
*pfPPlus12x12ij = 0.0F;
|
||||
|
||||
// initialize pfC6x12ik for current i, k=0
|
||||
pfC6x12ik = SV->fC6x12[i];
|
||||
pfC6x12ik = SV->C6x12[i];
|
||||
|
||||
// initialize pftmpA12x6kj for current j, k=0
|
||||
pftmpA12x6kj = *ftmpA12x6 + j;
|
||||
|
|
@ -379,33 +379,33 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
}
|
||||
|
||||
// update pfC6x12ik and pftmpA12x6kj for next iteration of k
|
||||
pfC6x12ik++;
|
||||
pfC6x12ik++;
|
||||
pftmpA12x6kj += 6;
|
||||
|
||||
} // end of loop over k
|
||||
}
|
||||
|
||||
// increment pfPPlus12x12ij for next iteration of j
|
||||
pfPPlus12x12ij++;
|
||||
|
||||
} // end of loop over j
|
||||
} // end of loop over i
|
||||
}
|
||||
}
|
||||
|
||||
// add in noise covariance terms to the diagonal
|
||||
SV->fPPlus12x12[0][0] += SV->fQvAA;
|
||||
SV->fPPlus12x12[1][1] += SV->fQvAA;
|
||||
SV->fPPlus12x12[2][2] += SV->fQvAA;
|
||||
SV->fPPlus12x12[3][3] += SV->fQvMM;
|
||||
SV->fPPlus12x12[4][4] += SV->fQvMM;
|
||||
SV->fPPlus12x12[5][5] += SV->fQvMM;
|
||||
SV->PPlus12x12[0][0] += SV->QvAA;
|
||||
SV->PPlus12x12[1][1] += SV->QvAA;
|
||||
SV->PPlus12x12[2][2] += SV->QvAA;
|
||||
SV->PPlus12x12[3][3] += SV->QvMM;
|
||||
SV->PPlus12x12[4][4] += SV->QvMM;
|
||||
SV->PPlus12x12[5][5] += SV->QvMM;
|
||||
|
||||
// copy above diagonal elements of P+ (6x6 scratch sub-matrix) to below diagonal
|
||||
for (i = 1; i < 6; i++)
|
||||
for (j = 0; j < i; j++)
|
||||
SV->fPPlus12x12[i][j] = SV->fPPlus12x12[j][i];
|
||||
for (i = 1; i < 6; i++)
|
||||
for (j = 0; j < i; j++)
|
||||
SV->PPlus12x12[i][j] = SV->PPlus12x12[j][i];
|
||||
|
||||
// calculate inverse of P+ (6x6 scratch sub-matrix) = inv(C * P- * C^T + Qv) = inv(C * Qw * C^T + Qv)
|
||||
for (i = 0; i < 6; i++) {
|
||||
pfRows[i] = SV->fPPlus12x12[i];
|
||||
pfRows[i] = SV->PPlus12x12[i];
|
||||
}
|
||||
fmatrixAeqInvA(pfRows, iColInd, iRowInd, iPivot, 3);
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// K is not symmetric because C is not symmetric
|
||||
for (i = 0; i < 12; i++) { // loop over rows of K12x6
|
||||
// initialize pfK12x6ij for current i, j=0
|
||||
pfK12x6ij = SV->fK12x6[i];
|
||||
pfK12x6ij = SV->K12x6[i];
|
||||
|
||||
for (j = 0; j < 6; j++) { // loop over columns of K12x6
|
||||
// zero the matrix element fK12x6[i][j]
|
||||
|
|
@ -425,7 +425,7 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
pftmpA12x6ik = ftmpA12x6[i];
|
||||
|
||||
// initialize pfPPlus12x12kj for current j, k=0
|
||||
pfPPlus12x12kj = *SV->fPPlus12x12 + j;
|
||||
pfPPlus12x12kj = *SV->PPlus12x12 + j;
|
||||
|
||||
// sum matrix products over inner loop over k
|
||||
for (k = 0; k < 6; k++) {
|
||||
|
|
@ -437,13 +437,13 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
pftmpA12x6ik++;
|
||||
pfPPlus12x12kj += 12;
|
||||
|
||||
} // end of loop over k
|
||||
}
|
||||
|
||||
// increment pfK12x6ij for the next iteration of j
|
||||
pfK12x6ij++;
|
||||
|
||||
} // end of loop over j
|
||||
} // end of loop over i
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
// calculate a posteriori error estimate: xe+ = K * ze-
|
||||
|
|
@ -452,40 +452,40 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// first calculate all four error vector components using accelerometer error component only
|
||||
// for fThErrPl, fbErrPl, faErrSePl but also magnetometer for fdErrSePl
|
||||
for (i = X; i <= Z; i++) {
|
||||
SV->fThErrPl[i] = SV->fK12x6[i][0] * SV->fgErrSeMi[X] +
|
||||
SV->fK12x6[i][1] * SV->fgErrSeMi[Y] +
|
||||
SV->fK12x6[i][2] * SV->fgErrSeMi[Z];
|
||||
SV->fbErrPl[i] = SV->fK12x6[i + 3][0] * SV->fgErrSeMi[X] +
|
||||
SV->fK12x6[i + 3][1] * SV->fgErrSeMi[Y] +
|
||||
SV->fK12x6[i + 3][2] * SV->fgErrSeMi[Z];
|
||||
SV->faErrSePl[i] = SV->fK12x6[i + 6][0] * SV->fgErrSeMi[X] +
|
||||
SV->fK12x6[i + 6][1] * SV->fgErrSeMi[Y] +
|
||||
SV->fK12x6[i + 6][2] * SV->fgErrSeMi[Z];
|
||||
SV->fdErrSePl[i] = SV->fK12x6[i + 9][0] * SV->fgErrSeMi[X] +
|
||||
SV->fK12x6[i + 9][1] * SV->fgErrSeMi[Y] +
|
||||
SV->fK12x6[i + 9][2] * SV->fgErrSeMi[Z] +
|
||||
SV->fK12x6[i + 9][3] * SV->fmErrSeMi[X] +
|
||||
SV->fK12x6[i + 9][4] * SV->fmErrSeMi[Y] +
|
||||
SV->fK12x6[i + 9][5] * SV->fmErrSeMi[Z];
|
||||
SV->ThErrPl[i] = SV->K12x6[i][0] * SV->gErrSeMi[X] +
|
||||
SV->K12x6[i][1] * SV->gErrSeMi[Y] +
|
||||
SV->K12x6[i][2] * SV->gErrSeMi[Z];
|
||||
SV->bErrPl[i] = SV->K12x6[i + 3][0] * SV->gErrSeMi[X] +
|
||||
SV->K12x6[i + 3][1] * SV->gErrSeMi[Y] +
|
||||
SV->K12x6[i + 3][2] * SV->gErrSeMi[Z];
|
||||
SV->aErrSePl[i] = SV->K12x6[i + 6][0] * SV->gErrSeMi[X] +
|
||||
SV->K12x6[i + 6][1] * SV->gErrSeMi[Y] +
|
||||
SV->K12x6[i + 6][2] * SV->gErrSeMi[Z];
|
||||
SV->dErrSePl[i] = SV->K12x6[i + 9][0] * SV->gErrSeMi[X] +
|
||||
SV->K12x6[i + 9][1] * SV->gErrSeMi[Y] +
|
||||
SV->K12x6[i + 9][2] * SV->gErrSeMi[Z] +
|
||||
SV->K12x6[i + 9][3] * SV->mErrSeMi[X] +
|
||||
SV->K12x6[i + 9][4] * SV->mErrSeMi[Y] +
|
||||
SV->K12x6[i + 9][5] * SV->mErrSeMi[Z];
|
||||
}
|
||||
|
||||
// set the magnetic jamming flag if there is a significant magnetic error power after calibration
|
||||
ftmp = SV->fdErrSePl[X] * SV->fdErrSePl[X] + SV->fdErrSePl[Y] * SV->fdErrSePl[Y] +
|
||||
SV->fdErrSePl[Z] * SV->fdErrSePl[Z];
|
||||
iMagJamming = (MagCal->iValidMagCal) && (ftmp > MagCal->fFourBsq);
|
||||
ftmp = SV->dErrSePl[X] * SV->dErrSePl[X] + SV->dErrSePl[Y] * SV->dErrSePl[Y] +
|
||||
SV->dErrSePl[Z] * SV->dErrSePl[Z];
|
||||
iMagJamming = (MagCal->ValidMagCal) && (ftmp > MagCal->FourBsq);
|
||||
|
||||
// add the remaining magnetic error terms if there is calibration and no magnetic jamming
|
||||
if (MagCal->iValidMagCal && !iMagJamming) {
|
||||
if (MagCal->ValidMagCal && !iMagJamming) {
|
||||
for (i = X; i <= Z; i++) {
|
||||
SV->fThErrPl[i] += SV->fK12x6[i][3] * SV->fmErrSeMi[X] +
|
||||
SV->fK12x6[i][4] * SV->fmErrSeMi[Y] +
|
||||
SV->fK12x6[i][5] * SV->fmErrSeMi[Z];
|
||||
SV->fbErrPl[i] += SV->fK12x6[i + 3][3] * SV->fmErrSeMi[X] +
|
||||
SV->fK12x6[i + 3][4] * SV->fmErrSeMi[Y] +
|
||||
SV->fK12x6[i + 3][5] * SV->fmErrSeMi[Z];
|
||||
SV->faErrSePl[i] += SV->fK12x6[i + 6][3] * SV->fmErrSeMi[X] +
|
||||
SV->fK12x6[i + 6][4] * SV->fmErrSeMi[Y] +
|
||||
SV->fK12x6[i + 6][5] * SV->fmErrSeMi[Z];
|
||||
SV->ThErrPl[i] += SV->K12x6[i][3] * SV->mErrSeMi[X] +
|
||||
SV->K12x6[i][4] * SV->mErrSeMi[Y] +
|
||||
SV->K12x6[i][5] * SV->mErrSeMi[Z];
|
||||
SV->bErrPl[i] += SV->K12x6[i + 3][3] * SV->mErrSeMi[X] +
|
||||
SV->K12x6[i + 3][4] * SV->mErrSeMi[Y] +
|
||||
SV->K12x6[i + 3][5] * SV->mErrSeMi[Z];
|
||||
SV->aErrSePl[i] += SV->K12x6[i + 6][3] * SV->mErrSeMi[X] +
|
||||
SV->K12x6[i + 6][4] * SV->mErrSeMi[Y] +
|
||||
SV->K12x6[i + 6][5] * SV->mErrSeMi[Z];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -494,61 +494,61 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// *********************************************************************************
|
||||
|
||||
// get the a posteriori delta quaternion
|
||||
fQuaternionFromRotationVectorDeg(&(SV->fDeltaq), SV->fThErrPl, -1.0F);
|
||||
fQuaternionFromRotationVectorDeg(&(SV->Deltaq), SV->ThErrPl, -1.0F);
|
||||
|
||||
// compute the a posteriori orientation quaternion fqPl = fqMi * Deltaq(-thetae+)
|
||||
// the resulting quaternion may have negative scalar component q0
|
||||
qAeqBxC(&(SV->fqPl), &(SV->fqMi), &(SV->fDeltaq));
|
||||
qAeqBxC(&(SV->qPl), &(SV->qMi), &(SV->Deltaq));
|
||||
|
||||
// normalize the a posteriori orientation quaternion to stop error propagation
|
||||
// normalize the a posteriori orientation quaternion to stop error propagation
|
||||
// the renormalization function ensures that the scalar component q0 is non-negative
|
||||
fqAeqNormqA(&(SV->fqPl));
|
||||
fqAeqNormqA(&(SV->qPl));
|
||||
|
||||
// compute the a posteriori rotation matrix from the a posteriori quaternion
|
||||
fRotationMatrixFromQuaternion(SV->fRPl, &(SV->fqPl));
|
||||
fRotationMatrixFromQuaternion(SV->RPl, &(SV->qPl));
|
||||
|
||||
// compute the rotation vector from the a posteriori quaternion
|
||||
fRotationVectorDegFromQuaternion(&(SV->fqPl), SV->fRVecPl);
|
||||
fRotationVectorDegFromQuaternion(&(SV->qPl), SV->RVecPl);
|
||||
|
||||
// update the a posteriori gyro offset vector b+ and
|
||||
// assign the entire linear acceleration error vector to update the linear acceleration
|
||||
for (i = X; i <= Z; i++) {
|
||||
// b+[k] = b-[k] - be+[k] = b+[k] - be+[k] (deg/s)
|
||||
SV->fbPl[i] -= SV->fbErrPl[i];
|
||||
SV->bPl[i] -= SV->bErrPl[i];
|
||||
// a+ = a- - ae+ (g, sensor frame)
|
||||
SV->faSePl[i] = SV->faSeMi[i] - SV->faErrSePl[i];
|
||||
SV->aSePl[i] = SV->aSeMi[i] - SV->aErrSePl[i];
|
||||
}
|
||||
|
||||
// compute the linear acceleration in the global frame from the accelerometer measurement (sensor frame).
|
||||
// de-rotate the accelerometer measurement from the sensor to global frame using the inverse (transpose)
|
||||
// de-rotate the accelerometer measurement from the sensor to global frame using the inverse (transpose)
|
||||
// of the a posteriori rotation matrix
|
||||
SV->faGlPl[X] = SV->fRPl[X][X] * Accel->fGpFast[X] + SV->fRPl[Y][X] * Accel->fGpFast[Y] +
|
||||
SV->fRPl[Z][X] * Accel->fGpFast[Z];
|
||||
SV->faGlPl[Y] = SV->fRPl[X][Y] * Accel->fGpFast[X] + SV->fRPl[Y][Y] * Accel->fGpFast[Y] +
|
||||
SV->fRPl[Z][Y] * Accel->fGpFast[Z];
|
||||
SV->faGlPl[Z] = SV->fRPl[X][Z] * Accel->fGpFast[X] + SV->fRPl[Y][Z] * Accel->fGpFast[Y] +
|
||||
SV->fRPl[Z][Z] * Accel->fGpFast[Z];
|
||||
// remove gravity and correct the sign if the coordinate system is gravity positive / acceleration negative
|
||||
SV->aGlPl[X] = SV->RPl[X][X] * Accel->GpFast[X] + SV->RPl[Y][X] * Accel->GpFast[Y] +
|
||||
SV->RPl[Z][X] * Accel->GpFast[Z];
|
||||
SV->aGlPl[Y] = SV->RPl[X][Y] * Accel->GpFast[X] + SV->RPl[Y][Y] * Accel->GpFast[Y] +
|
||||
SV->RPl[Z][Y] * Accel->GpFast[Z];
|
||||
SV->aGlPl[Z] = SV->RPl[X][Z] * Accel->GpFast[X] + SV->RPl[Y][Z] * Accel->GpFast[Y] +
|
||||
SV->RPl[Z][Z] * Accel->GpFast[Z];
|
||||
// remove gravity and correct the sign if the coordinate system is gravity positive / acceleration negative
|
||||
// gravity positive NED
|
||||
SV->faGlPl[X] = -SV->faGlPl[X];
|
||||
SV->faGlPl[Y] = -SV->faGlPl[Y];
|
||||
SV->faGlPl[Z] = -(SV->faGlPl[Z] - 1.0F);
|
||||
SV->aGlPl[X] = -SV->aGlPl[X];
|
||||
SV->aGlPl[Y] = -SV->aGlPl[Y];
|
||||
SV->aGlPl[Z] = -(SV->aGlPl[Z] - 1.0F);
|
||||
|
||||
// update the reference geomagnetic vector using magnetic disturbance error if valid calibration and no jamming
|
||||
if (MagCal->iValidMagCal && !iMagJamming) {
|
||||
if (MagCal->ValidMagCal && !iMagJamming) {
|
||||
// de-rotate the NED magnetic disturbance error de+ from the sensor to the global reference frame
|
||||
// using the inverse (transpose) of the a posteriori rotation matrix
|
||||
SV->fdErrGlPl[X] = SV->fRPl[X][X] * SV->fdErrSePl[X] +
|
||||
SV->fRPl[Y][X] * SV->fdErrSePl[Y] +
|
||||
SV->fRPl[Z][X] * SV->fdErrSePl[Z];
|
||||
SV->fdErrGlPl[Z] = SV->fRPl[X][Z] * SV->fdErrSePl[X] +
|
||||
SV->fRPl[Y][Z] * SV->fdErrSePl[Y] +
|
||||
SV->fRPl[Z][Z] * SV->fdErrSePl[Z];
|
||||
SV->dErrGlPl[X] = SV->RPl[X][X] * SV->dErrSePl[X] +
|
||||
SV->RPl[Y][X] * SV->dErrSePl[Y] +
|
||||
SV->RPl[Z][X] * SV->dErrSePl[Z];
|
||||
SV->dErrGlPl[Z] = SV->RPl[X][Z] * SV->dErrSePl[X] +
|
||||
SV->RPl[Y][Z] * SV->dErrSePl[Y] +
|
||||
SV->RPl[Z][Z] * SV->dErrSePl[Z];
|
||||
|
||||
// compute components of the new geomagnetic vector
|
||||
// the north pointing component fadj must always be non-negative
|
||||
fopp = SV->fmGl[Z] - SV->fdErrGlPl[Z];
|
||||
fadj = SV->fmGl[X] - SV->fdErrGlPl[X];
|
||||
fopp = SV->mGl[Z] - SV->dErrGlPl[Z];
|
||||
fadj = SV->mGl[X] - SV->dErrGlPl[X];
|
||||
if (fadj < 0.0F) {
|
||||
fadj = 0.0F;
|
||||
}
|
||||
|
|
@ -571,19 +571,19 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
}
|
||||
|
||||
// compute the new geomagnetic vector (always north pointing)
|
||||
SV->fDeltaPl = fasin_deg(fsindelta);
|
||||
SV->fmGl[X] = MagCal->fB * fcosdelta;
|
||||
SV->fmGl[Z] = MagCal->fB * fsindelta;
|
||||
SV->DeltaPl = fasin_deg(fsindelta);
|
||||
SV->mGl[X] = MagCal->B * fcosdelta;
|
||||
SV->mGl[Z] = MagCal->B * fsindelta;
|
||||
} // end hyp == 0.0F
|
||||
} // end iValidMagCal
|
||||
} // end ValidMagCal
|
||||
|
||||
// *********************************************************************************
|
||||
// compute the a posteriori Euler angles from the orientation matrix
|
||||
// *********************************************************************************
|
||||
|
||||
// calculate the NED Euler angles
|
||||
fNEDAnglesDegFromRotationMatrix(SV->fRPl, &(SV->fPhiPl), &(SV->fThePl), &(SV->fPsiPl),
|
||||
&(SV->fRhoPl), &(SV->fChiPl));
|
||||
fNEDAnglesDegFromRotationMatrix(SV->RPl, &(SV->PhiPl), &(SV->ThePl), &(SV->PsiPl),
|
||||
&(SV->RhoPl), &(SV->ChiPl));
|
||||
|
||||
// ***********************************************************************************
|
||||
// calculate (symmetric) a posteriori error covariance matrix P+
|
||||
|
|
@ -597,17 +597,17 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// the resulting matrix is sparse but not symmetric
|
||||
for (i = 0; i < 6; i++) {
|
||||
// initialize pfPPlus12x12ij for current i, j=0
|
||||
pfPPlus12x12ij = SV->fPPlus12x12[i];
|
||||
pfPPlus12x12ij = SV->PPlus12x12[i];
|
||||
|
||||
for (j = 0; j < 12; j++) {
|
||||
// zero P+[i][j]
|
||||
// zero P+[i][j]
|
||||
*pfPPlus12x12ij = 0.0F;
|
||||
|
||||
// initialize pfC6x12ik for current i, k=0
|
||||
pfC6x12ik = SV->fC6x12[i];
|
||||
pfC6x12ik = SV->C6x12[i];
|
||||
|
||||
// initialize pfQw12x12kj for current j, k=0
|
||||
pfQw12x12kj = &SV->fQw12x12[0][j];
|
||||
pfQw12x12kj = &SV->Qw12x12[0][j];
|
||||
|
||||
// sum matrix products over inner loop over k
|
||||
for (k = 0; k < 12; k++) {
|
||||
|
|
@ -624,13 +624,13 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
pfC6x12ik++;
|
||||
pfQw12x12kj += 12;
|
||||
|
||||
} // end of loop over k
|
||||
}
|
||||
|
||||
// increment pfPPlus12x12ij for next iteration of j
|
||||
pfPPlus12x12ij++;
|
||||
|
||||
} // end of loop over j
|
||||
} // end of loop over i
|
||||
}
|
||||
}
|
||||
|
||||
// compute P+ = (I12 - K * C) * Qw = Qw - K * (C * Qw) = Qw - K * P+ (6x12 sub-matrix)
|
||||
// storing result P+ in Qw and over-writing Qw which is OK since Qw is later computed from P+
|
||||
|
|
@ -638,14 +638,14 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// only on and above diagonal terms of P+ are computed since P+ is symmetric
|
||||
for (i = 0; i < 12; i++) {
|
||||
// initialize pfQw12x12ij for current i, j=i
|
||||
pfQw12x12ij = SV->fQw12x12[i] + i;
|
||||
pfQw12x12ij = SV->Qw12x12[i] + i;
|
||||
|
||||
for (j = i; j < 12; j++) {
|
||||
// initialize pfK12x6ik for current i, k=0
|
||||
pfK12x6ik = SV->fK12x6[i];
|
||||
pfK12x6ik = SV->K12x6[i];
|
||||
|
||||
// initialize pfPPlus12x12kj for current j, k=0
|
||||
pfPPlus12x12kj = *SV->fPPlus12x12 + j;
|
||||
pfPPlus12x12kj = *SV->PPlus12x12 + j;
|
||||
|
||||
// compute on and above diagonal matrix entry
|
||||
for (k = 0; k < 6; k++) {
|
||||
|
|
@ -653,34 +653,30 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
if (*pfPPlus12x12kj != 0.0F) {
|
||||
*pfQw12x12ij -= *pfK12x6ik * *pfPPlus12x12kj;
|
||||
}
|
||||
|
||||
// increment pfK12x6ik and pfPPlus12x12kj for next iteration of k
|
||||
pfK12x6ik++;
|
||||
pfPPlus12x12kj += 12;
|
||||
|
||||
} // end of loop over k
|
||||
}
|
||||
|
||||
// increment pfQw12x12ij for next iteration of j
|
||||
pfQw12x12ij++;
|
||||
|
||||
} // end of loop over j
|
||||
} // end of loop over i
|
||||
}
|
||||
}
|
||||
|
||||
// Qw now holds the on and above diagonal elements of P+
|
||||
// so perform a simple copy to the all elements of P+
|
||||
// after execution of this code P+ is valid but Qw remains invalid
|
||||
for (i = 0; i < 12; i++) {
|
||||
// initialize pfPPlus12x12ij and pfQw12x12ij for current i, j=i
|
||||
pfPPlus12x12ij = SV->fPPlus12x12[i] + i;
|
||||
pfQw12x12ij = SV->fQw12x12[i] + i;
|
||||
pfPPlus12x12ij = SV->PPlus12x12[i] + i;
|
||||
pfQw12x12ij = SV->Qw12x12[i] + i;
|
||||
|
||||
// copy the on-diagonal elements and increment pointers to enter loop at j=i+1
|
||||
*(pfPPlus12x12ij++) = *(pfQw12x12ij++);
|
||||
|
||||
// loop over above diagonal columns j copying to below-diagonal elements
|
||||
for (j = i + 1; j < 12; j++)
|
||||
{
|
||||
*(pfPPlus12x12ij++)= SV->fPPlus12x12[j][i] = *(pfQw12x12ij++);
|
||||
for (j = i + 1; j < 12; j++) {
|
||||
*(pfPPlus12x12ij++)= SV->PPlus12x12[j][i] = *(pfQw12x12ij++);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -693,26 +689,26 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
// zero the matrix Qw
|
||||
for (i = 0; i < 12; i++) {
|
||||
for (j = 0; j < 12; j++) {
|
||||
SV->fQw12x12[i][j] = 0.0F;
|
||||
SV->Qw12x12[i][j] = 0.0F;
|
||||
}
|
||||
}
|
||||
|
||||
// update the covariance matrix components
|
||||
for (i = 0; i < 3; i++) {
|
||||
// Qw[th-th-] = Qw[0-2][0-2] = E[th-(th-)^T] = Q[th+th+] + deltat^2 * (Q[b+b+] + (Qwb + QvG) * I)
|
||||
SV->fQw12x12[i][i] = SV->fPPlus12x12[i][i] + SV->fdeltatsq * (SV->fPPlus12x12[i + 3][i + 3] + SV->fQwbplusQvG);
|
||||
SV->Qw12x12[i][i] = SV->PPlus12x12[i][i] + SV->deltatsq * (SV->PPlus12x12[i + 3][i + 3] + SV->QwbplusQvG);
|
||||
|
||||
// Qw[b-b-] = Qw[3-5][3-5] = E[b-(b-)^T] = Q[b+b+] + Qwb * I
|
||||
SV->fQw12x12[i + 3][i + 3] = SV->fPPlus12x12[i + 3][i + 3] + FQWB_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 3][i + 3] = SV->PPlus12x12[i + 3][i + 3] + FQWB_9DOF_GBY_KALMAN;
|
||||
|
||||
// Qw[th-b-] = Qw[0-2][3-5] = E[th-(b-)^T] = -deltat * (Q[b+b+] + Qwb * I) = -deltat * Qw[b-b-]
|
||||
SV->fQw12x12[i][i + 3] = SV->fQw12x12[i + 3][i] = -SV->fdeltat * SV->fQw12x12[i + 3][i + 3];
|
||||
SV->Qw12x12[i][i + 3] = SV->Qw12x12[i + 3][i] = -SV->deltat * SV->Qw12x12[i + 3][i + 3];
|
||||
|
||||
// Qw[a-a-] = Qw[6-8][6-8] = E[a-(a-)^T] = ca^2 * Q[a+a+] + Qwa * I
|
||||
SV->fQw12x12[i + 6][i + 6] = SV->fcasq * SV->fPPlus12x12[i + 6][i + 6] + FQWA_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 6][i + 6] = SV->casq * SV->PPlus12x12[i + 6][i + 6] + FQWA_9DOF_GBY_KALMAN;
|
||||
|
||||
// Qw[d-d-] = Qw[9-11][9-11] = E[d-(d-)^T] = cd^2 * Q[d+d+] + Qwd * I
|
||||
SV->fQw12x12[i + 9][i + 9] = SV->fcdsq * SV->fPPlus12x12[i + 9][i + 9] + FQWD_9DOF_GBY_KALMAN;
|
||||
SV->Qw12x12[i + 9][i + 9] = SV->cdsq * SV->PPlus12x12[i + 9][i + 9] + FQWD_9DOF_GBY_KALMAN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -731,7 +727,7 @@ void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
|||
void f3DOFTiltNED(float fR[][3], float fGp[])
|
||||
{
|
||||
// the NED self-consistency twist occurs at 90 deg pitch
|
||||
|
||||
|
||||
// local variables
|
||||
int16_t i; // counter
|
||||
float fmodGxyz; // modulus of the x, y, z accelerometer readings
|
||||
|
|
@ -788,7 +784,7 @@ void f3DOFTiltNED(float fR[][3], float fGp[])
|
|||
|
||||
// Aerospace NED magnetometer 3DOF flat eCompass function computing rotation matrix fR
|
||||
void f3DOFMagnetometerMatrixNED(float fR[][3], float fBc[])
|
||||
{
|
||||
{
|
||||
// local variables
|
||||
float fmodBxy; // modulus of the x, y magnetometer readings
|
||||
|
||||
|
|
@ -804,7 +800,7 @@ void f3DOFMagnetometerMatrixNED(float fR[][3], float fBc[])
|
|||
// define the fixed entries in the z row and column
|
||||
fR[Z][X] = fR[Z][Y] = fR[X][Z] = fR[Y][Z] = 0.0F;
|
||||
fR[Z][Z] = 1.0F;
|
||||
|
||||
|
||||
// define the remaining entries
|
||||
fR[X][X] = fR[Y][Y] = fBc[X] / fmodBxy;
|
||||
fR[Y][X] = fBc[Y] / fmodBxy;
|
||||
|
|
@ -912,7 +908,7 @@ static void fNEDAnglesDegFromRotationMatrix(float R[][3], float *pfPhiDeg,
|
|||
// for NED, the compass heading Rho equals the yaw angle Psi
|
||||
*pfRhoDeg = *pfPsiDeg;
|
||||
|
||||
// calculate the tilt angle from vertical Chi (0 <= Chi <= 180 deg)
|
||||
// calculate the tilt angle from vertical Chi (0 <= Chi <= 180 deg)
|
||||
*pfChiDeg = facos_deg(R[Z][Z]);
|
||||
|
||||
return;
|
||||
|
|
@ -1099,7 +1095,7 @@ void fRotationVectorDegFromRotationMatrix(float R[][3], float rvecdeg[])
|
|||
if ((R[Y][Z] - R[Z][Y]) < 0.0F) rvecdeg[X] = -rvecdeg[X];
|
||||
if ((R[Z][X] - R[X][Z]) < 0.0F) rvecdeg[Y] = -rvecdeg[Y];
|
||||
if ((R[X][Y] - R[Y][X]) < 0.0F) rvecdeg[Z] = -rvecdeg[Z];
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1117,12 +1113,12 @@ static void fRotationVectorDegFromQuaternion(Quaternion_t *pq, float rvecdeg[])
|
|||
fetarad = 0.0F;
|
||||
fetadeg = 0.0F;
|
||||
} else {
|
||||
// general case returning 0 < eta < 360 deg
|
||||
fetarad = 2.0F * acosf(pq->q0);
|
||||
// general case returning 0 < eta < 360 deg
|
||||
fetarad = 2.0F * acosf(pq->q0);
|
||||
fetadeg = fetarad * FRADTODEG;
|
||||
}
|
||||
|
||||
// map the rotation angle onto the range -180 deg <= eta < 180 deg
|
||||
// map the rotation angle onto the range -180 deg <= eta < 180 deg
|
||||
if (fetadeg >= 180.0F) {
|
||||
fetadeg -= 360.0F;
|
||||
fetarad = fetadeg * FDEGTORAD;
|
||||
|
|
@ -1133,7 +1129,7 @@ static void fRotationVectorDegFromQuaternion(Quaternion_t *pq, float rvecdeg[])
|
|||
|
||||
// calculate the rotation vector (deg)
|
||||
if (sinhalfeta == 0.0F) {
|
||||
// the rotation angle eta is zero and the axis is irrelevant
|
||||
// the rotation angle eta is zero and the axis is irrelevant
|
||||
rvecdeg[X] = rvecdeg[Y] = rvecdeg[Z] = 0.0F;
|
||||
} else {
|
||||
// general case with non-zero rotation angle
|
||||
|
|
@ -1339,7 +1335,7 @@ static float fatan_deg(float x)
|
|||
|
||||
// reset all flags
|
||||
ixisnegative = ixexceeds1 = ixmapped = 0;
|
||||
|
||||
|
||||
// test for negative argument to allow use of tan(-x)=-tan(x)
|
||||
if (x < 0.0F) {
|
||||
x = -x;
|
||||
|
|
@ -1369,7 +1365,7 @@ static float fatan_deg(float x)
|
|||
if (ixmapped) fangledeg += 30.0F;
|
||||
if (ixexceeds1) fangledeg = 90.0F - fangledeg;
|
||||
if (ixisnegative) fangledeg = -fangledeg;
|
||||
|
||||
|
||||
return (fangledeg);
|
||||
}
|
||||
|
||||
|
|
@ -1386,7 +1382,7 @@ static float fatan2_deg(float y, float x)
|
|||
// otherwise y= 0.0 and return 0 deg (invalid arguments)
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
|
||||
// from here onwards, x is guaranteed to be non-zero
|
||||
// compute atan2 for quadrant 1 (0 to 90 deg) and quadrant 4 (-90 to 0 deg)
|
||||
if (x > 0.0F) return (fatan_deg(y / x));
|
||||
|
|
|
|||
12
imuread.c
12
imuread.c
|
|
@ -23,18 +23,18 @@ static void glut_display_callback(void)
|
|||
|
||||
static void glut_keystroke_callback(unsigned char ch, int x, int y)
|
||||
{
|
||||
if (magcal.fFitErrorpc > 9.0) {
|
||||
if (magcal.FitError > 9.0) {
|
||||
printf("Poor Calibration: ");
|
||||
printf("soft iron fit error = %.1f%%\n", magcal.fFitErrorpc);
|
||||
printf("soft iron fit error = %.1f%%\n", magcal.FitError);
|
||||
return;
|
||||
}
|
||||
printf("Magnetic Calibration: (%.1f%% fit error)\n", magcal.fFitErrorpc);
|
||||
printf("Magnetic Calibration: (%.1f%% fit error)\n", magcal.FitError);
|
||||
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||
magcal.fV[0], magcal.finvW[0][0], magcal.finvW[0][1], magcal.finvW[0][2]);
|
||||
magcal.V[0], magcal.invW[0][0], magcal.invW[0][1], magcal.invW[0][2]);
|
||||
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||
magcal.fV[1], magcal.finvW[1][0], magcal.finvW[1][1], magcal.finvW[1][2]);
|
||||
magcal.V[1], magcal.invW[1][0], magcal.invW[1][1], magcal.invW[1][2]);
|
||||
printf(" %7.2f %6.3f %6.3f %6.3f\n",
|
||||
magcal.fV[2], magcal.finvW[2][0], magcal.finvW[2][1], magcal.finvW[2][2]);
|
||||
magcal.V[2], magcal.invW[2][0], magcal.invW[2][1], magcal.invW[2][2]);
|
||||
send_calibration();
|
||||
}
|
||||
|
||||
|
|
|
|||
136
imuread.h
136
imuread.h
|
|
@ -76,26 +76,26 @@ void MagCal_Run(void);
|
|||
|
||||
// magnetic calibration & buffer structure
|
||||
typedef struct {
|
||||
float fV[3]; // current hard iron offset x, y, z, (uT)
|
||||
float finvW[3][3]; // current inverse soft iron matrix
|
||||
float fB; // current geomagnetic field magnitude (uT)
|
||||
float fFourBsq; // current 4*B*B (uT^2)
|
||||
float fFitErrorpc; // current fit error %
|
||||
float fFitErrorAge; // current fit error % (grows automatically with age)
|
||||
float ftrV[3]; // trial value of hard iron offset z, y, z (uT)
|
||||
float ftrinvW[3][3]; // trial inverse soft iron matrix size
|
||||
float ftrB; // trial value of geomagnetic field magnitude in uT
|
||||
float ftrFitErrorpc; // trial value of fit error %
|
||||
float fA[3][3]; // ellipsoid matrix A
|
||||
float finvA[3][3]; // inverse of ellipsoid matrix A
|
||||
float fmatA[10][10]; // scratch 10x10 matrix used by calibration algorithms
|
||||
float fmatB[10][10]; // scratch 10x10 matrix used by calibration algorithms
|
||||
float fvecA[10]; // scratch 10x1 vector used by calibration algorithms
|
||||
float fvecB[4]; // scratch 4x1 vector used by calibration algorithms
|
||||
int8_t iValidMagCal; // integer value 0, 4, 7, 10 denoting both valid calibration and solver used
|
||||
int16_t iBpFast[3][MAGBUFFSIZE]; // uncalibrated magnetometer readings
|
||||
float V[3]; // current hard iron offset x, y, z, (uT)
|
||||
float invW[3][3]; // current inverse soft iron matrix
|
||||
float B; // current geomagnetic field magnitude (uT)
|
||||
float FourBsq; // current 4*B*B (uT^2)
|
||||
float FitError; // current fit error %
|
||||
float FitErrorAge; // current fit error % (grows automatically with age)
|
||||
float trV[3]; // trial value of hard iron offset z, y, z (uT)
|
||||
float trinvW[3][3]; // trial inverse soft iron matrix size
|
||||
float trB; // trial value of geomagnetic field magnitude in uT
|
||||
float trFitErrorpc; // trial value of fit error %
|
||||
float A[3][3]; // ellipsoid matrix A
|
||||
float invA[3][3]; // inverse of ellipsoid matrix A
|
||||
float matA[10][10]; // scratch 10x10 matrix used by calibration algorithms
|
||||
float matB[10][10]; // scratch 10x10 matrix used by calibration algorithms
|
||||
float vecA[10]; // scratch 10x1 vector used by calibration algorithms
|
||||
float vecB[4]; // scratch 4x1 vector used by calibration algorithms
|
||||
int8_t ValidMagCal; // integer value 0, 4, 7, 10 denoting both valid calibration and solver used
|
||||
int16_t BpFast[3][MAGBUFFSIZE]; // uncalibrated magnetometer readings
|
||||
int8_t valid[MAGBUFFSIZE]; // 1=has data, 0=empty slot
|
||||
int16_t iMagBufferCount; // number of magnetometer readings
|
||||
int16_t MagBufferCount; // number of magnetometer readings
|
||||
} MagCalibration_t;
|
||||
|
||||
extern MagCalibration_t magcal;
|
||||
|
|
@ -113,15 +113,17 @@ void fmatrixAeqInvA(float *A[], int8_t iColInd[], int8_t iRowInd[], int8_t iPivo
|
|||
void fmatrixAeqRenormRotA(float A[][3]);
|
||||
|
||||
|
||||
#define SENSORFS 100
|
||||
#define OVERSAMPLE_RATIO 4
|
||||
|
||||
|
||||
// accelerometer sensor structure definition
|
||||
#define G_PER_COUNT 0.0001220703125F // = 1/8192
|
||||
typedef struct
|
||||
{
|
||||
//int32_t iSumGpFast[3]; // sum of fast measurements
|
||||
float fGpFast[3]; // fast (typically 200Hz) readings (g)
|
||||
float fGp[3]; // slow (typically 25Hz) averaged readings (g)
|
||||
float GpFast[3]; // fast (typically 200Hz) readings (g)
|
||||
float Gp[3]; // slow (typically 25Hz) averaged readings (g)
|
||||
//float fgPerCount; // initialized to FGPERCOUNT
|
||||
//int16_t iGpFast[3]; // fast (typically 200Hz) readings
|
||||
//int16_t iGp[3]; // slow (typically 25Hz) averaged readings (counts)
|
||||
|
|
@ -134,8 +136,8 @@ typedef struct
|
|||
//int32_t iSumBpFast[3]; // sum of fast measurements
|
||||
//float fBpFast[3]; // fast (typically 200Hz) raw readings (uT)
|
||||
//float fBp[3]; // slow (typically 25Hz) averaged raw readings (uT)
|
||||
float fBcFast[3]; // fast (typically 200Hz) calibrated readings (uT)
|
||||
float fBc[3]; // slow (typically 25Hz) averaged calibrated readings (uT)
|
||||
float BcFast[3]; // fast (typically 200Hz) calibrated readings (uT)
|
||||
float Bc[3]; // slow (typically 25Hz) averaged calibrated readings (uT)
|
||||
//float fuTPerCount; // initialized to FUTPERCOUNT
|
||||
//float fCountsPeruT; // initialized to FCOUNTSPERUT
|
||||
//int16_t iBpFast[3]; // fast (typically 200Hz) raw readings (counts)
|
||||
|
|
@ -148,9 +150,9 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
//int32_t iSumYpFast[3]; // sum of fast measurements
|
||||
float fYp[3]; // raw gyro sensor output (deg/s)
|
||||
float Yp[3]; // raw gyro sensor output (deg/s)
|
||||
//float fDegPerSecPerCount; // initialized to FDEGPERSECPERCOUNT
|
||||
int16_t iYpFast[OVERSAMPLE_RATIO][3]; // fast (typically 200Hz) readings
|
||||
int16_t YpFast[OVERSAMPLE_RATIO][3]; // fast (typically 200Hz) readings
|
||||
//int16_t iYp[3]; // averaged gyro sensor output (counts)
|
||||
} GyroSensor_t;
|
||||
|
||||
|
|
@ -161,62 +163,62 @@ typedef struct
|
|||
{
|
||||
// start: elements common to all motion state vectors
|
||||
// Euler angles
|
||||
float fPhiPl; // roll (deg)
|
||||
float fThePl; // pitch (deg)
|
||||
float fPsiPl; // yaw (deg)
|
||||
float fRhoPl; // compass (deg)
|
||||
float fChiPl; // tilt from vertical (deg)
|
||||
float PhiPl; // roll (deg)
|
||||
float ThePl; // pitch (deg)
|
||||
float PsiPl; // yaw (deg)
|
||||
float RhoPl; // compass (deg)
|
||||
float ChiPl; // tilt from vertical (deg)
|
||||
// orientation matrix, quaternion and rotation vector
|
||||
float fRPl[3][3]; // a posteriori orientation matrix
|
||||
Quaternion_t fqPl; // a posteriori orientation quaternion
|
||||
float fRVecPl[3]; // rotation vector
|
||||
float RPl[3][3]; // a posteriori orientation matrix
|
||||
Quaternion_t qPl; // a posteriori orientation quaternion
|
||||
float RVecPl[3]; // rotation vector
|
||||
// angular velocity
|
||||
float fOmega[3]; // angular velocity (deg/s)
|
||||
float Omega[3]; // angular velocity (deg/s)
|
||||
// systick timer for benchmarking
|
||||
int32_t systick; // systick timer;
|
||||
// end: elements common to all motion state vectors
|
||||
|
||||
// elements transmitted over bluetooth in kalman packet
|
||||
float fbPl[3]; // gyro offset (deg/s)
|
||||
float fThErrPl[3]; // orientation error (deg)
|
||||
float fbErrPl[3]; // gyro offset error (deg/s)
|
||||
float bPl[3]; // gyro offset (deg/s)
|
||||
float ThErrPl[3]; // orientation error (deg)
|
||||
float bErrPl[3]; // gyro offset error (deg/s)
|
||||
// end elements transmitted in kalman packet
|
||||
|
||||
float fdErrGlPl[3]; // magnetic disturbance error (uT, global frame)
|
||||
float fdErrSePl[3]; // magnetic disturbance error (uT, sensor frame)
|
||||
float faErrSePl[3]; // linear acceleration error (g, sensor frame)
|
||||
float faSeMi[3]; // linear acceleration (g, sensor frame)
|
||||
float fDeltaPl; // inclination angle (deg)
|
||||
float faSePl[3]; // linear acceleration (g, sensor frame)
|
||||
float faGlPl[3]; // linear acceleration (g, global frame)
|
||||
float fgErrSeMi[3]; // difference (g, sensor frame) of gravity vector (accel) and gravity vector (gyro)
|
||||
float fmErrSeMi[3]; // difference (uT, sensor frame) of geomagnetic vector (magnetometer) and geomagnetic vector (gyro)
|
||||
float fgSeGyMi[3]; // gravity vector (g, sensor frame) measurement from gyro
|
||||
float fmSeGyMi[3]; // geomagnetic vector (uT, sensor frame) measurement from gyro
|
||||
float fmGl[3]; // geomagnetic vector (uT, global frame)
|
||||
float fQvAA; // accelerometer terms of Qv
|
||||
float fQvMM; // magnetometer terms of Qv
|
||||
float fPPlus12x12[12][12]; // covariance matrix P+
|
||||
float fK12x6[12][6]; // kalman filter gain matrix K
|
||||
float fQw12x12[12][12]; // covariance matrix Qw
|
||||
float fC6x12[6][12]; // measurement matrix C
|
||||
float fRMi[3][3]; // a priori orientation matrix
|
||||
Quaternion_t fDeltaq; // delta quaternion
|
||||
Quaternion_t fqMi; // a priori orientation quaternion
|
||||
float fcasq; // FCA * FCA;
|
||||
float fcdsq; // FCD * FCD;
|
||||
float fFastdeltat; // sensor sampling interval (s) = 1 / SENSORFS
|
||||
float fdeltat; // kalman filter sampling interval (s) = OVERSAMPLE_RATIO / SENSORFS
|
||||
float fdeltatsq; // fdeltat * fdeltat
|
||||
float fQwbplusQvG; // FQWB + FQVG
|
||||
int16_t iFirstOrientationLock; // denotes that 9DOF orientation has locked to 6DOF
|
||||
float dErrGlPl[3]; // magnetic disturbance error (uT, global frame)
|
||||
float dErrSePl[3]; // magnetic disturbance error (uT, sensor frame)
|
||||
float aErrSePl[3]; // linear acceleration error (g, sensor frame)
|
||||
float aSeMi[3]; // linear acceleration (g, sensor frame)
|
||||
float DeltaPl; // inclination angle (deg)
|
||||
float aSePl[3]; // linear acceleration (g, sensor frame)
|
||||
float aGlPl[3]; // linear acceleration (g, global frame)
|
||||
float gErrSeMi[3]; // difference (g, sensor frame) of gravity vector (accel) and gravity vector (gyro)
|
||||
float mErrSeMi[3]; // difference (uT, sensor frame) of geomagnetic vector (magnetometer) and geomagnetic vector (gyro)
|
||||
float gSeGyMi[3]; // gravity vector (g, sensor frame) measurement from gyro
|
||||
float mSeGyMi[3]; // geomagnetic vector (uT, sensor frame) measurement from gyro
|
||||
float mGl[3]; // geomagnetic vector (uT, global frame)
|
||||
float QvAA; // accelerometer terms of Qv
|
||||
float QvMM; // magnetometer terms of Qv
|
||||
float PPlus12x12[12][12]; // covariance matrix P+
|
||||
float K12x6[12][6]; // kalman filter gain matrix K
|
||||
float Qw12x12[12][12]; // covariance matrix Qw
|
||||
float C6x12[6][12]; // measurement matrix C
|
||||
float RMi[3][3]; // a priori orientation matrix
|
||||
Quaternion_t Deltaq; // delta quaternion
|
||||
Quaternion_t qMi; // a priori orientation quaternion
|
||||
float casq; // FCA * FCA;
|
||||
float cdsq; // FCD * FCD;
|
||||
float Fastdeltat; // sensor sampling interval (s) = 1 / SENSORFS
|
||||
float deltat; // kalman filter sampling interval (s) = OVERSAMPLE_RATIO / SENSORFS
|
||||
float deltatsq; // fdeltat * fdeltat
|
||||
float QwbplusQvG; // FQWB + FQVG
|
||||
int16_t FirstOrientationLock; // denotes that 9DOF orientation has locked to 6DOF
|
||||
int8_t resetflag; // flag to request re-initialization on next pass
|
||||
} SV_9DOF_GBY_KALMAN_t;
|
||||
|
||||
void fInit_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV, int16_t iSensorFS, int16_t iOverSampleRatio);
|
||||
void fInit_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV);
|
||||
void fRun_9DOF_GBY_KALMAN(SV_9DOF_GBY_KALMAN_t *SV,
|
||||
const AccelSensor_t *Accel, const MagSensor_t *Mag, const GyroSensor_t *Gyro,
|
||||
const MagCalibration_t *MagCal, int16_t iOverSampleRatio);
|
||||
const MagCalibration_t *MagCal);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
348
magcal.c
348
magcal.c
|
|
@ -44,8 +44,8 @@
|
|||
#define MINMEASUREMENTS4CAL 40 // minimum number of measurements for 4 element calibration
|
||||
#define MINMEASUREMENTS7CAL 100 // minimum number of measurements for 7 element calibration
|
||||
#define MINMEASUREMENTS10CAL 150 // minimum number of measurements for 10 element calibration
|
||||
#define MINBFITUT 22.0F // minimum geomagnetic field B (uT) for valid calibration
|
||||
#define MAXBFITUT 67.0F // maximum geomagnetic field B (uT) for valid calibration
|
||||
#define MINBFITUT 15.0F // minimum geomagnetic field B (uT) for valid calibration
|
||||
#define MAXBFITUT 80.0F // maximum geomagnetic field B (uT) for valid calibration
|
||||
#define FITERRORAGINGSECS 7200.0F // 2 hours: time for fit error to increase (age) by e=2.718
|
||||
|
||||
static void fUpdateCalibration4INV(MagCalibration_t *MagCal);
|
||||
|
|
@ -73,9 +73,9 @@ void MagCal_Run(void)
|
|||
|
||||
if (count < MINMEASUREMENTS4CAL) return;
|
||||
|
||||
if (magcal.iValidMagCal) {
|
||||
if (magcal.ValidMagCal) {
|
||||
// age the existing fit error to avoid one good calibration locking out future updates
|
||||
magcal.fFitErrorAge *= 1.01f;
|
||||
magcal.FitErrorAge *= 1.01f;
|
||||
}
|
||||
|
||||
// is enough data collected
|
||||
|
|
@ -91,25 +91,25 @@ void MagCal_Run(void)
|
|||
}
|
||||
|
||||
// the trial geomagnetic field must be in range (earth is 22uT to 67uT)
|
||||
if ((magcal.ftrB >= MINBFITUT) && (magcal.ftrB <= MAXBFITUT)) {
|
||||
if ((magcal.trB >= MINBFITUT) && (magcal.trB <= MAXBFITUT)) {
|
||||
// always accept the calibration if
|
||||
// 1: no previous calibration exists
|
||||
// 2: the calibration fit is reduced or
|
||||
// 3: an improved solver was used giving a good trial calibration (4% or under)
|
||||
if ((magcal.iValidMagCal == 0) ||
|
||||
(magcal.ftrFitErrorpc <= magcal.fFitErrorAge) ||
|
||||
((isolver > magcal.iValidMagCal) && (magcal.ftrFitErrorpc <= 4.0F))) {
|
||||
if ((magcal.ValidMagCal == 0) ||
|
||||
(magcal.trFitErrorpc <= magcal.FitErrorAge) ||
|
||||
((isolver > magcal.ValidMagCal) && (magcal.trFitErrorpc <= 4.0F))) {
|
||||
// accept the new calibration solution
|
||||
//printf("new magnetic cal, B=%.2f uT\n", magcal.ftrB);
|
||||
magcal.iValidMagCal = isolver;
|
||||
magcal.fFitErrorpc = magcal.ftrFitErrorpc;
|
||||
magcal.fFitErrorAge = magcal.ftrFitErrorpc;
|
||||
magcal.fB = magcal.ftrB;
|
||||
magcal.fFourBsq = 4.0F * magcal.ftrB * magcal.ftrB;
|
||||
//printf("new magnetic cal, B=%.2f uT\n", magcal.trB);
|
||||
magcal.ValidMagCal = isolver;
|
||||
magcal.FitError = magcal.trFitErrorpc;
|
||||
magcal.FitErrorAge = magcal.trFitErrorpc;
|
||||
magcal.B = magcal.trB;
|
||||
magcal.FourBsq = 4.0F * magcal.trB * magcal.trB;
|
||||
for (i = X; i <= Z; i++) {
|
||||
magcal.fV[i] = magcal.ftrV[i];
|
||||
magcal.V[i] = magcal.trV[i];
|
||||
for (j = X; j <= Z; j++) {
|
||||
magcal.finvW[i][j] = magcal.ftrinvW[i][j];
|
||||
magcal.invW[i][j] = magcal.trinvW[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ static void fUpdateCalibration4INV(MagCalibration_t *MagCal)
|
|||
int16_t iOffset[3]; // offset to remove large DC hard iron bias in matrix
|
||||
int16_t iCount; // number of measurements counted
|
||||
int i, j, k; // loop counters
|
||||
|
||||
|
||||
// working arrays for 4x4 matrix inversion
|
||||
float *pfRows[4];
|
||||
int8_t iColInd[4];
|
||||
|
|
@ -140,15 +140,15 @@ static void fUpdateCalibration4INV(MagCalibration_t *MagCal)
|
|||
|
||||
// the trial inverse soft iron matrix invW always equals
|
||||
// the identity matrix for 4 element calibration
|
||||
f3x3matrixAeqI(MagCal->ftrinvW);
|
||||
f3x3matrixAeqI(MagCal->trinvW);
|
||||
|
||||
// zero fSumBp4=Y^T.Y, fvecB=X^T.Y (4x1) and on and above
|
||||
// diagonal elements of fmatA=X^T*X (4x4)
|
||||
// zero fSumBp4=Y^T.Y, vecB=X^T.Y (4x1) and on and above
|
||||
// diagonal elements of matA=X^T*X (4x4)
|
||||
fSumBp4 = 0.0F;
|
||||
for (i = 0; i < 4; i++) {
|
||||
MagCal->fvecB[i] = 0.0F;
|
||||
MagCal->vecB[i] = 0.0F;
|
||||
for (j = i; j < 4; j++) {
|
||||
MagCal->fmatA[i][j] = 0.0F;
|
||||
MagCal->matA[i][j] = 0.0F;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,41 +162,41 @@ static void fUpdateCalibration4INV(MagCalibration_t *MagCal)
|
|||
// use first valid magnetic buffer entry as estimate (in counts) for offset
|
||||
if (iCount == 0) {
|
||||
for (k = X; k <= Z; k++) {
|
||||
iOffset[k] = MagCal->iBpFast[k][j];
|
||||
iOffset[k] = MagCal->BpFast[k][j];
|
||||
}
|
||||
}
|
||||
|
||||
// store scaled and offset fBp[XYZ] in fvecA[0-2] and fBp[XYZ]^2 in fvecA[3-5]
|
||||
// store scaled and offset fBp[XYZ] in vecA[0-2] and fBp[XYZ]^2 in vecA[3-5]
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->fvecA[k] = (float)((int32_t)MagCal->iBpFast[k][j]
|
||||
MagCal->vecA[k] = (float)((int32_t)MagCal->BpFast[k][j]
|
||||
- (int32_t)iOffset[k]) * fscaling;
|
||||
MagCal->fvecA[k + 3] = MagCal->fvecA[k] * MagCal->fvecA[k];
|
||||
MagCal->vecA[k + 3] = MagCal->vecA[k] * MagCal->vecA[k];
|
||||
}
|
||||
|
||||
// calculate fBp2 = fBp[X]^2 + fBp[Y]^2 + fBp[Z]^2 (scaled uT^2)
|
||||
fBp2 = MagCal->fvecA[3] + MagCal->fvecA[4] + MagCal->fvecA[5];
|
||||
// calculate fBp2 = Bp[X]^2 + Bp[Y]^2 + Bp[Z]^2 (scaled uT^2)
|
||||
fBp2 = MagCal->vecA[3] + MagCal->vecA[4] + MagCal->vecA[5];
|
||||
|
||||
// accumulate fBp^4 over all measurements into fSumBp4=Y^T.Y
|
||||
fSumBp4 += fBp2 * fBp2;
|
||||
|
||||
// now we have fBp2, accumulate fvecB[0-2] = X^T.Y =sum(fBp2.fBp[XYZ])
|
||||
// now we have fBp2, accumulate vecB[0-2] = X^T.Y =sum(Bp2.Bp[XYZ])
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->fvecB[k] += MagCal->fvecA[k] * fBp2;
|
||||
MagCal->vecB[k] += MagCal->vecA[k] * fBp2;
|
||||
}
|
||||
|
||||
//accumulate fvecB[3] = X^T.Y =sum(fBp2)
|
||||
MagCal->fvecB[3] += fBp2;
|
||||
//accumulate vecB[3] = X^T.Y =sum(fBp2)
|
||||
MagCal->vecB[3] += fBp2;
|
||||
|
||||
// accumulate on and above-diagonal terms of fmatA = X^T.X ignoring fmatA[3][3]
|
||||
MagCal->fmatA[0][0] += MagCal->fvecA[X + 3];
|
||||
MagCal->fmatA[0][1] += MagCal->fvecA[X] * MagCal->fvecA[Y];
|
||||
MagCal->fmatA[0][2] += MagCal->fvecA[X] * MagCal->fvecA[Z];
|
||||
MagCal->fmatA[0][3] += MagCal->fvecA[X];
|
||||
MagCal->fmatA[1][1] += MagCal->fvecA[Y + 3];
|
||||
MagCal->fmatA[1][2] += MagCal->fvecA[Y] * MagCal->fvecA[Z];
|
||||
MagCal->fmatA[1][3] += MagCal->fvecA[Y];
|
||||
MagCal->fmatA[2][2] += MagCal->fvecA[Z + 3];
|
||||
MagCal->fmatA[2][3] += MagCal->fvecA[Z];
|
||||
// accumulate on and above-diagonal terms of matA = X^T.X ignoring matA[3][3]
|
||||
MagCal->matA[0][0] += MagCal->vecA[X + 3];
|
||||
MagCal->matA[0][1] += MagCal->vecA[X] * MagCal->vecA[Y];
|
||||
MagCal->matA[0][2] += MagCal->vecA[X] * MagCal->vecA[Z];
|
||||
MagCal->matA[0][3] += MagCal->vecA[X];
|
||||
MagCal->matA[1][1] += MagCal->vecA[Y + 3];
|
||||
MagCal->matA[1][2] += MagCal->vecA[Y] * MagCal->vecA[Z];
|
||||
MagCal->matA[1][3] += MagCal->vecA[Y];
|
||||
MagCal->matA[2][2] += MagCal->vecA[Z + 3];
|
||||
MagCal->matA[2][3] += MagCal->vecA[Z];
|
||||
|
||||
// increment the counter for next iteration
|
||||
iCount++;
|
||||
|
|
@ -204,77 +204,77 @@ static void fUpdateCalibration4INV(MagCalibration_t *MagCal)
|
|||
}
|
||||
|
||||
// set the last element of the measurement matrix to the number of buffer elements used
|
||||
MagCal->fmatA[3][3] = (float) iCount;
|
||||
MagCal->matA[3][3] = (float) iCount;
|
||||
|
||||
// store the number of measurements accumulated
|
||||
MagCal->iMagBufferCount = iCount;
|
||||
MagCal->MagBufferCount = iCount;
|
||||
|
||||
// use above diagonal elements of symmetric fmatA to set both fmatB and fmatA to X^T.X
|
||||
// use above diagonal elements of symmetric matA to set both matB and matA to X^T.X
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = i; j < 4; j++) {
|
||||
MagCal->fmatB[i][j] = MagCal->fmatB[j][i]
|
||||
= MagCal->fmatA[j][i] = MagCal->fmatA[i][j];
|
||||
MagCal->matB[i][j] = MagCal->matB[j][i]
|
||||
= MagCal->matA[j][i] = MagCal->matA[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
// calculate in situ inverse of fmatB = inv(X^T.X) (4x4) while fmatA still holds X^T.X
|
||||
// calculate in situ inverse of matB = inv(X^T.X) (4x4) while matA still holds X^T.X
|
||||
for (i = 0; i < 4; i++) {
|
||||
pfRows[i] = MagCal->fmatB[i];
|
||||
pfRows[i] = MagCal->matB[i];
|
||||
}
|
||||
fmatrixAeqInvA(pfRows, iColInd, iRowInd, iPivot, 4);
|
||||
|
||||
// calculate fvecA = solution beta (4x1) = inv(X^T.X).X^T.Y = fmatB * fvecB
|
||||
// calculate vecA = solution beta (4x1) = inv(X^T.X).X^T.Y = matB * vecB
|
||||
for (i = 0; i < 4; i++) {
|
||||
MagCal->fvecA[i] = 0.0F;
|
||||
MagCal->vecA[i] = 0.0F;
|
||||
for (k = 0; k < 4; k++) {
|
||||
MagCal->fvecA[i] += MagCal->fmatB[i][k] * MagCal->fvecB[k];
|
||||
MagCal->vecA[i] += MagCal->matB[i][k] * MagCal->vecB[k];
|
||||
}
|
||||
}
|
||||
|
||||
// calculate P = r^T.r = Y^T.Y - 2 * beta^T.(X^T.Y) + beta^T.(X^T.X).beta
|
||||
// = fSumBp4 - 2 * fvecA^T.fvecB + fvecA^T.fmatA.fvecA
|
||||
// first set P = Y^T.Y - 2 * beta^T.(X^T.Y) = fSumBp4 - 2 * fvecA^T.fvecB
|
||||
// = fSumBp4 - 2 * vecA^T.vecB + vecA^T.matA.vecA
|
||||
// first set P = Y^T.Y - 2 * beta^T.(X^T.Y) = SumBp4 - 2 * vecA^T.vecB
|
||||
fE = 0.0F;
|
||||
for (i = 0; i < 4; i++) {
|
||||
fE += MagCal->fvecA[i] * MagCal->fvecB[i];
|
||||
fE += MagCal->vecA[i] * MagCal->vecB[i];
|
||||
}
|
||||
fE = fSumBp4 - 2.0F * fE;
|
||||
|
||||
// set fvecB = (X^T.X).beta = fmatA.fvecA
|
||||
// set vecB = (X^T.X).beta = matA.vecA
|
||||
for (i = 0; i < 4; i++) {
|
||||
MagCal->fvecB[i] = 0.0F;
|
||||
MagCal->vecB[i] = 0.0F;
|
||||
for (k = 0; k < 4; k++) {
|
||||
MagCal->fvecB[i] += MagCal->fmatA[i][k] * MagCal->fvecA[k];
|
||||
MagCal->vecB[i] += MagCal->matA[i][k] * MagCal->vecA[k];
|
||||
}
|
||||
}
|
||||
|
||||
// complete calculation of P by adding beta^T.(X^T.X).beta = fvecA^T * fvecB
|
||||
// complete calculation of P by adding beta^T.(X^T.X).beta = vecA^T * vecB
|
||||
for (i = 0; i < 4; i++) {
|
||||
fE += MagCal->fvecB[i] * MagCal->fvecA[i];
|
||||
fE += MagCal->vecB[i] * MagCal->vecA[i];
|
||||
}
|
||||
|
||||
// compute the hard iron vector (in uT but offset and scaled by FMATRIXSCALING)
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->ftrV[k] = 0.5F * MagCal->fvecA[k];
|
||||
MagCal->trV[k] = 0.5F * MagCal->vecA[k];
|
||||
}
|
||||
|
||||
// compute the scaled geomagnetic field strength B (in uT but scaled by FMATRIXSCALING)
|
||||
MagCal->ftrB = sqrtf(MagCal->fvecA[3] + MagCal->ftrV[X] * MagCal->ftrV[X] +
|
||||
MagCal->ftrV[Y] * MagCal->ftrV[Y] + MagCal->ftrV[Z] * MagCal->ftrV[Z]);
|
||||
MagCal->trB = sqrtf(MagCal->vecA[3] + MagCal->trV[X] * MagCal->trV[X] +
|
||||
MagCal->trV[Y] * MagCal->trV[Y] + MagCal->trV[Z] * MagCal->trV[Z]);
|
||||
|
||||
// calculate the trial fit error (percent) normalized to number of measurements
|
||||
// and scaled geomagnetic field strength
|
||||
MagCal->ftrFitErrorpc = sqrtf(fE / (float) MagCal->iMagBufferCount) * 100.0F /
|
||||
(2.0F * MagCal->ftrB * MagCal->ftrB);
|
||||
MagCal->trFitErrorpc = sqrtf(fE / (float) MagCal->MagBufferCount) * 100.0F /
|
||||
(2.0F * MagCal->trB * MagCal->trB);
|
||||
|
||||
// correct the hard iron estimate for FMATRIXSCALING and the offsets applied (result in uT)
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->ftrV[k] = MagCal->ftrV[k] * DEFAULTB
|
||||
MagCal->trV[k] = MagCal->trV[k] * DEFAULTB
|
||||
+ (float)iOffset[k] * FXOS8700_UTPERCOUNT;
|
||||
}
|
||||
|
||||
// correct the geomagnetic field strength B to correct scaling (result in uT)
|
||||
MagCal->ftrB *= DEFAULTB;
|
||||
MagCal->trB *= DEFAULTB;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -302,43 +302,43 @@ static void fUpdateCalibration7EIG(MagCalibration_t *MagCal)
|
|||
// the offsets are guaranteed to be set from the first element but to avoid compiler error
|
||||
iOffset[X] = iOffset[Y] = iOffset[Z] = 0;
|
||||
|
||||
// zero the on and above diagonal elements of the 7x7 symmetric measurement matrix fmatA
|
||||
// zero the on and above diagonal elements of the 7x7 symmetric measurement matrix matA
|
||||
for (m = 0; m < 7; m++) {
|
||||
for (n = m; n < 7; n++) {
|
||||
MagCal->fmatA[m][n] = 0.0F;
|
||||
MagCal->matA[m][n] = 0.0F;
|
||||
}
|
||||
}
|
||||
|
||||
// place from MINEQUATIONS to MAXEQUATIONS entries into product matrix fmatA
|
||||
// place from MINEQUATIONS to MAXEQUATIONS entries into product matrix matA
|
||||
iCount = 0;
|
||||
for (j = 0; j < MAGBUFFSIZE; j++) {
|
||||
if (MagCal->valid[j]) {
|
||||
// use first valid magnetic buffer entry as offset estimate (bit counts)
|
||||
if (iCount == 0) {
|
||||
for (k = X; k <= Z; k++) {
|
||||
iOffset[k] = MagCal->iBpFast[k][j];
|
||||
iOffset[k] = MagCal->BpFast[k][j];
|
||||
}
|
||||
}
|
||||
|
||||
// apply the offset and scaling and store in fvecA
|
||||
// apply the offset and scaling and store in vecA
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->fvecA[k + 3] = (float)((int32_t)MagCal->iBpFast[k][j]
|
||||
MagCal->vecA[k + 3] = (float)((int32_t)MagCal->BpFast[k][j]
|
||||
- (int32_t)iOffset[k]) * fscaling;
|
||||
MagCal->fvecA[k] = MagCal->fvecA[k + 3] * MagCal->fvecA[k + 3];
|
||||
MagCal->vecA[k] = MagCal->vecA[k + 3] * MagCal->vecA[k + 3];
|
||||
}
|
||||
|
||||
// accumulate the on-and above-diagonal terms of
|
||||
// MagCal->fmatA=Sigma{fvecA^T * fvecA}
|
||||
// with the exception of fmatA[6][6] which will sum to the number
|
||||
// of measurements and remembering that fvecA[6] equals 1.0F
|
||||
// update the right hand column [6] of fmatA except for fmatA[6][6]
|
||||
// MagCal->matA=Sigma{vecA^T * vecA}
|
||||
// with the exception of matA[6][6] which will sum to the number
|
||||
// of measurements and remembering that vecA[6] equals 1.0F
|
||||
// update the right hand column [6] of matA except for matA[6][6]
|
||||
for (m = 0; m < 6; m++) {
|
||||
MagCal->fmatA[m][6] += MagCal->fvecA[m];
|
||||
MagCal->matA[m][6] += MagCal->vecA[m];
|
||||
}
|
||||
// update the on and above diagonal terms except for right hand column 6
|
||||
for (m = 0; m < 6; m++) {
|
||||
for (n = m; n < 6; n++) {
|
||||
MagCal->fmatA[m][n] += MagCal->fvecA[m] * MagCal->fvecA[n];
|
||||
MagCal->matA[m][n] += MagCal->vecA[m] * MagCal->vecA[n];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -347,71 +347,71 @@ static void fUpdateCalibration7EIG(MagCalibration_t *MagCal)
|
|||
}
|
||||
}
|
||||
|
||||
// finally set the last element fmatA[6][6] to the number of measurements
|
||||
MagCal->fmatA[6][6] = (float) iCount;
|
||||
// finally set the last element matA[6][6] to the number of measurements
|
||||
MagCal->matA[6][6] = (float) iCount;
|
||||
|
||||
// store the number of measurements accumulated
|
||||
MagCal->iMagBufferCount = iCount;
|
||||
MagCal->MagBufferCount = iCount;
|
||||
|
||||
// copy the above diagonal elements of fmatA to below the diagonal
|
||||
// copy the above diagonal elements of matA to below the diagonal
|
||||
for (m = 1; m < 7; m++) {
|
||||
for (n = 0; n < m; n++) {
|
||||
MagCal->fmatA[m][n] = MagCal->fmatA[n][m];
|
||||
MagCal->matA[m][n] = MagCal->matA[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
// set tmpA7x1 to the unsorted eigenvalues and fmatB to the unsorted eigenvectors of fmatA
|
||||
eigencompute(MagCal->fmatA, MagCal->fvecA, MagCal->fmatB, 7);
|
||||
// set tmpA7x1 to the unsorted eigenvalues and matB to the unsorted eigenvectors of matA
|
||||
eigencompute(MagCal->matA, MagCal->vecA, MagCal->matB, 7);
|
||||
|
||||
// find the smallest eigenvalue
|
||||
j = 0;
|
||||
for (i = 1; i < 7; i++) {
|
||||
if (MagCal->fvecA[i] < MagCal->fvecA[j]) {
|
||||
if (MagCal->vecA[i] < MagCal->vecA[j]) {
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
|
||||
// set ellipsoid matrix A to the solution vector with smallest eigenvalue,
|
||||
// compute its determinant and the hard iron offset (scaled and offset)
|
||||
f3x3matrixAeqScalar(MagCal->fA, 0.0F);
|
||||
f3x3matrixAeqScalar(MagCal->A, 0.0F);
|
||||
det = 1.0F;
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->fA[k][k] = MagCal->fmatB[k][j];
|
||||
det *= MagCal->fA[k][k];
|
||||
MagCal->ftrV[k] = -0.5F * MagCal->fmatB[k + 3][j] / MagCal->fA[k][k];
|
||||
MagCal->A[k][k] = MagCal->matB[k][j];
|
||||
det *= MagCal->A[k][k];
|
||||
MagCal->trV[k] = -0.5F * MagCal->matB[k + 3][j] / MagCal->A[k][k];
|
||||
}
|
||||
|
||||
// negate A if it has negative determinant
|
||||
if (det < 0.0F) {
|
||||
f3x3matrixAeqMinusA(MagCal->fA);
|
||||
MagCal->fmatB[6][j] = -MagCal->fmatB[6][j];
|
||||
f3x3matrixAeqMinusA(MagCal->A);
|
||||
MagCal->matB[6][j] = -MagCal->matB[6][j];
|
||||
det = -det;
|
||||
}
|
||||
|
||||
// set ftmp to the square of the trial geomagnetic field strength B
|
||||
// (counts times FMATRIXSCALING)
|
||||
ftmp = -MagCal->fmatB[6][j];
|
||||
ftmp = -MagCal->matB[6][j];
|
||||
for (k = X; k <= Z; k++) {
|
||||
ftmp += MagCal->fA[k][k] * MagCal->ftrV[k] * MagCal->ftrV[k];
|
||||
ftmp += MagCal->A[k][k] * MagCal->trV[k] * MagCal->trV[k];
|
||||
}
|
||||
|
||||
// calculate the trial normalized fit error as a percentage
|
||||
MagCal->ftrFitErrorpc = 50.0F *
|
||||
sqrtf(fabs(MagCal->fvecA[j]) / (float) MagCal->iMagBufferCount) / fabs(ftmp);
|
||||
MagCal->trFitErrorpc = 50.0F *
|
||||
sqrtf(fabs(MagCal->vecA[j]) / (float) MagCal->MagBufferCount) / fabs(ftmp);
|
||||
|
||||
// normalize the ellipsoid matrix A to unit determinant
|
||||
f3x3matrixAeqAxScalar(MagCal->fA, powf(det, -(ONETHIRD)));
|
||||
f3x3matrixAeqAxScalar(MagCal->A, powf(det, -(ONETHIRD)));
|
||||
|
||||
// convert the geomagnetic field strength B into uT for normalized
|
||||
// soft iron matrix A and normalize
|
||||
MagCal->ftrB = sqrtf(fabs(ftmp)) * DEFAULTB * powf(det, -(ONESIXTH));
|
||||
MagCal->trB = sqrtf(fabs(ftmp)) * DEFAULTB * powf(det, -(ONESIXTH));
|
||||
|
||||
// compute trial invW from the square root of A also with normalized
|
||||
// determinant and hard iron offset in uT
|
||||
f3x3matrixAeqI(MagCal->ftrinvW);
|
||||
f3x3matrixAeqI(MagCal->trinvW);
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->ftrinvW[k][k] = sqrtf(fabs(MagCal->fA[k][k]));
|
||||
MagCal->ftrV[k] = MagCal->ftrV[k] * DEFAULTB + (float)iOffset[k] * FXOS8700_UTPERCOUNT;
|
||||
MagCal->trinvW[k][k] = sqrtf(fabs(MagCal->A[k][k]));
|
||||
MagCal->trV[k] = MagCal->trV[k] * DEFAULTB + (float)iOffset[k] * FXOS8700_UTPERCOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -435,14 +435,14 @@ static void fUpdateCalibration10EIG(MagCalibration_t *MagCal)
|
|||
// the offsets are guaranteed to be set from the first element but to avoid compiler error
|
||||
iOffset[X] = iOffset[Y] = iOffset[Z] = 0;
|
||||
|
||||
// zero the on and above diagonal elements of the 10x10 symmetric measurement matrix fmatA
|
||||
// zero the on and above diagonal elements of the 10x10 symmetric measurement matrix matA
|
||||
for (m = 0; m < 10; m++) {
|
||||
for (n = m; n < 10; n++) {
|
||||
MagCal->fmatA[m][n] = 0.0F;
|
||||
MagCal->matA[m][n] = 0.0F;
|
||||
}
|
||||
}
|
||||
|
||||
// sum between MINEQUATIONS to MAXEQUATIONS entries into the 10x10 product matrix fmatA
|
||||
// sum between MINEQUATIONS to MAXEQUATIONS entries into the 10x10 product matrix matA
|
||||
iCount = 0;
|
||||
for (j = 0; j < MAGBUFFSIZE; j++) {
|
||||
if (MagCal->valid[j] != -1) {
|
||||
|
|
@ -450,34 +450,34 @@ static void fUpdateCalibration10EIG(MagCalibration_t *MagCal)
|
|||
// to help solution (bit counts)
|
||||
if (iCount == 0) {
|
||||
for (k = X; k <= Z; k++) {
|
||||
iOffset[k] = MagCal->iBpFast[k][j];
|
||||
iOffset[k] = MagCal->BpFast[k][j];
|
||||
}
|
||||
}
|
||||
|
||||
// apply the fixed offset and scaling and enter into fvecA[6-8]
|
||||
// apply the fixed offset and scaling and enter into vecA[6-8]
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->fvecA[k + 6] = (float)((int32_t)MagCal->iBpFast[k][j]
|
||||
MagCal->vecA[k + 6] = (float)((int32_t)MagCal->BpFast[k][j]
|
||||
- (int32_t)iOffset[k]) * fscaling;
|
||||
}
|
||||
|
||||
// compute measurement vector elements fvecA[0-5] from fvecA[6-8]
|
||||
MagCal->fvecA[0] = MagCal->fvecA[6] * MagCal->fvecA[6];
|
||||
MagCal->fvecA[1] = 2.0F * MagCal->fvecA[6] * MagCal->fvecA[7];
|
||||
MagCal->fvecA[2] = 2.0F * MagCal->fvecA[6] * MagCal->fvecA[8];
|
||||
MagCal->fvecA[3] = MagCal->fvecA[7] * MagCal->fvecA[7];
|
||||
MagCal->fvecA[4] = 2.0F * MagCal->fvecA[7] * MagCal->fvecA[8];
|
||||
MagCal->fvecA[5] = MagCal->fvecA[8] * MagCal->fvecA[8];
|
||||
// compute measurement vector elements vecA[0-5] from vecA[6-8]
|
||||
MagCal->vecA[0] = MagCal->vecA[6] * MagCal->vecA[6];
|
||||
MagCal->vecA[1] = 2.0F * MagCal->vecA[6] * MagCal->vecA[7];
|
||||
MagCal->vecA[2] = 2.0F * MagCal->vecA[6] * MagCal->vecA[8];
|
||||
MagCal->vecA[3] = MagCal->vecA[7] * MagCal->vecA[7];
|
||||
MagCal->vecA[4] = 2.0F * MagCal->vecA[7] * MagCal->vecA[8];
|
||||
MagCal->vecA[5] = MagCal->vecA[8] * MagCal->vecA[8];
|
||||
|
||||
// accumulate the on-and above-diagonal terms of fmatA=Sigma{fvecA^T * fvecA}
|
||||
// with the exception of fmatA[9][9] which equals the number of measurements
|
||||
// update the right hand column [9] of fmatA[0-8][9] ignoring fmatA[9][9]
|
||||
// accumulate the on-and above-diagonal terms of matA=Sigma{vecA^T * vecA}
|
||||
// with the exception of matA[9][9] which equals the number of measurements
|
||||
// update the right hand column [9] of matA[0-8][9] ignoring matA[9][9]
|
||||
for (m = 0; m < 9; m++) {
|
||||
MagCal->fmatA[m][9] += MagCal->fvecA[m];
|
||||
MagCal->matA[m][9] += MagCal->vecA[m];
|
||||
}
|
||||
// update the on and above diagonal terms of fmatA ignoring right hand column 9
|
||||
// update the on and above diagonal terms of matA ignoring right hand column 9
|
||||
for (m = 0; m < 9; m++) {
|
||||
for (n = m; n < 9; n++) {
|
||||
MagCal->fmatA[m][n] += MagCal->fvecA[m] * MagCal->fvecA[n];
|
||||
MagCal->matA[m][n] += MagCal->vecA[m] * MagCal->vecA[n];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -486,121 +486,121 @@ static void fUpdateCalibration10EIG(MagCalibration_t *MagCal)
|
|||
}
|
||||
}
|
||||
|
||||
// set the last element fmatA[9][9] to the number of measurements
|
||||
MagCal->fmatA[9][9] = (float) iCount;
|
||||
// set the last element matA[9][9] to the number of measurements
|
||||
MagCal->matA[9][9] = (float) iCount;
|
||||
|
||||
// store the number of measurements accumulated
|
||||
MagCal->iMagBufferCount = iCount;
|
||||
MagCal->MagBufferCount = iCount;
|
||||
|
||||
// copy the above diagonal elements of symmetric product matrix fmatA to below the diagonal
|
||||
// copy the above diagonal elements of symmetric product matrix matA to below the diagonal
|
||||
for (m = 1; m < 10; m++) {
|
||||
for (n = 0; n < m; n++) {
|
||||
MagCal->fmatA[m][n] = MagCal->fmatA[n][m];
|
||||
MagCal->matA[m][n] = MagCal->matA[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
// set MagCal->fvecA to the unsorted eigenvalues and fmatB to the unsorted
|
||||
// normalized eigenvectors of fmatA
|
||||
eigencompute(MagCal->fmatA, MagCal->fvecA, MagCal->fmatB, 10);
|
||||
// set MagCal->vecA to the unsorted eigenvalues and matB to the unsorted
|
||||
// normalized eigenvectors of matA
|
||||
eigencompute(MagCal->matA, MagCal->vecA, MagCal->matB, 10);
|
||||
|
||||
// set ellipsoid matrix A from elements of the solution vector column j with
|
||||
// smallest eigenvalue
|
||||
j = 0;
|
||||
for (i = 1; i < 10; i++) {
|
||||
if (MagCal->fvecA[i] < MagCal->fvecA[j]) {
|
||||
if (MagCal->vecA[i] < MagCal->vecA[j]) {
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
MagCal->fA[0][0] = MagCal->fmatB[0][j];
|
||||
MagCal->fA[0][1] = MagCal->fA[1][0] = MagCal->fmatB[1][j];
|
||||
MagCal->fA[0][2] = MagCal->fA[2][0] = MagCal->fmatB[2][j];
|
||||
MagCal->fA[1][1] = MagCal->fmatB[3][j];
|
||||
MagCal->fA[1][2] = MagCal->fA[2][1] = MagCal->fmatB[4][j];
|
||||
MagCal->fA[2][2] = MagCal->fmatB[5][j];
|
||||
MagCal->A[0][0] = MagCal->matB[0][j];
|
||||
MagCal->A[0][1] = MagCal->A[1][0] = MagCal->matB[1][j];
|
||||
MagCal->A[0][2] = MagCal->A[2][0] = MagCal->matB[2][j];
|
||||
MagCal->A[1][1] = MagCal->matB[3][j];
|
||||
MagCal->A[1][2] = MagCal->A[2][1] = MagCal->matB[4][j];
|
||||
MagCal->A[2][2] = MagCal->matB[5][j];
|
||||
|
||||
// negate entire solution if A has negative determinant
|
||||
det = f3x3matrixDetA(MagCal->fA);
|
||||
det = f3x3matrixDetA(MagCal->A);
|
||||
if (det < 0.0F) {
|
||||
f3x3matrixAeqMinusA(MagCal->fA);
|
||||
MagCal->fmatB[6][j] = -MagCal->fmatB[6][j];
|
||||
MagCal->fmatB[7][j] = -MagCal->fmatB[7][j];
|
||||
MagCal->fmatB[8][j] = -MagCal->fmatB[8][j];
|
||||
MagCal->fmatB[9][j] = -MagCal->fmatB[9][j];
|
||||
f3x3matrixAeqMinusA(MagCal->A);
|
||||
MagCal->matB[6][j] = -MagCal->matB[6][j];
|
||||
MagCal->matB[7][j] = -MagCal->matB[7][j];
|
||||
MagCal->matB[8][j] = -MagCal->matB[8][j];
|
||||
MagCal->matB[9][j] = -MagCal->matB[9][j];
|
||||
det = -det;
|
||||
}
|
||||
|
||||
// compute the inverse of the ellipsoid matrix
|
||||
f3x3matrixAeqInvSymB(MagCal->finvA, MagCal->fA);
|
||||
f3x3matrixAeqInvSymB(MagCal->invA, MagCal->A);
|
||||
|
||||
// compute the trial hard iron vector in offset bit counts times FMATRIXSCALING
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->ftrV[k] = 0.0F;
|
||||
MagCal->trV[k] = 0.0F;
|
||||
for (m = X; m <= Z; m++) {
|
||||
MagCal->ftrV[k] += MagCal->finvA[k][m] * MagCal->fmatB[m + 6][j];
|
||||
MagCal->trV[k] += MagCal->invA[k][m] * MagCal->matB[m + 6][j];
|
||||
}
|
||||
MagCal->ftrV[k] *= -0.5F;
|
||||
MagCal->trV[k] *= -0.5F;
|
||||
}
|
||||
|
||||
// compute the trial geomagnetic field strength B in bit counts times FMATRIXSCALING
|
||||
MagCal->ftrB = sqrtf(fabs(MagCal->fA[0][0] * MagCal->ftrV[X] * MagCal->ftrV[X] +
|
||||
2.0F * MagCal->fA[0][1] * MagCal->ftrV[X] * MagCal->ftrV[Y] +
|
||||
2.0F * MagCal->fA[0][2] * MagCal->ftrV[X] * MagCal->ftrV[Z] +
|
||||
MagCal->fA[1][1] * MagCal->ftrV[Y] * MagCal->ftrV[Y] +
|
||||
2.0F * MagCal->fA[1][2] * MagCal->ftrV[Y] * MagCal->ftrV[Z] +
|
||||
MagCal->fA[2][2] * MagCal->ftrV[Z] * MagCal->ftrV[Z] - MagCal->fmatB[9][j]));
|
||||
MagCal->trB = sqrtf(fabs(MagCal->A[0][0] * MagCal->trV[X] * MagCal->trV[X] +
|
||||
2.0F * MagCal->A[0][1] * MagCal->trV[X] * MagCal->trV[Y] +
|
||||
2.0F * MagCal->A[0][2] * MagCal->trV[X] * MagCal->trV[Z] +
|
||||
MagCal->A[1][1] * MagCal->trV[Y] * MagCal->trV[Y] +
|
||||
2.0F * MagCal->A[1][2] * MagCal->trV[Y] * MagCal->trV[Z] +
|
||||
MagCal->A[2][2] * MagCal->trV[Z] * MagCal->trV[Z] - MagCal->matB[9][j]));
|
||||
|
||||
// calculate the trial normalized fit error as a percentage
|
||||
MagCal->ftrFitErrorpc = 50.0F * sqrtf(
|
||||
fabs(MagCal->fvecA[j]) / (float) MagCal->iMagBufferCount) /
|
||||
(MagCal->ftrB * MagCal->ftrB);
|
||||
MagCal->trFitErrorpc = 50.0F * sqrtf(
|
||||
fabs(MagCal->vecA[j]) / (float) MagCal->MagBufferCount) /
|
||||
(MagCal->trB * MagCal->trB);
|
||||
|
||||
// correct for the measurement matrix offset and scaling and
|
||||
// get the computed hard iron offset in uT
|
||||
for (k = X; k <= Z; k++) {
|
||||
MagCal->ftrV[k] = MagCal->ftrV[k] * DEFAULTB + (float)iOffset[k] * FXOS8700_UTPERCOUNT;
|
||||
MagCal->trV[k] = MagCal->trV[k] * DEFAULTB + (float)iOffset[k] * FXOS8700_UTPERCOUNT;
|
||||
}
|
||||
|
||||
// convert the trial geomagnetic field strength B into uT for
|
||||
// un-normalized soft iron matrix A
|
||||
MagCal->ftrB *= DEFAULTB;
|
||||
MagCal->trB *= DEFAULTB;
|
||||
|
||||
// normalize the ellipsoid matrix A to unit determinant and
|
||||
// correct B by root of this multiplicative factor
|
||||
f3x3matrixAeqAxScalar(MagCal->fA, powf(det, -(ONETHIRD)));
|
||||
MagCal->ftrB *= powf(det, -(ONESIXTH));
|
||||
f3x3matrixAeqAxScalar(MagCal->A, powf(det, -(ONETHIRD)));
|
||||
MagCal->trB *= powf(det, -(ONESIXTH));
|
||||
|
||||
// compute trial invW from the square root of fA (both with normalized determinant)
|
||||
// set fvecA to the unsorted eigenvalues and fmatB to the unsorted eigenvectors of fmatA
|
||||
// where fmatA holds the 3x3 matrix fA in its top left elements
|
||||
// compute trial invW from the square root of fA (both with normalized determinant)
|
||||
// set vecA to the unsorted eigenvalues and matB to the unsorted eigenvectors of matA
|
||||
// where matA holds the 3x3 matrix fA in its top left elements
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
MagCal->fmatA[i][j] = MagCal->fA[i][j];
|
||||
MagCal->matA[i][j] = MagCal->A[i][j];
|
||||
}
|
||||
}
|
||||
eigencompute(MagCal->fmatA, MagCal->fvecA, MagCal->fmatB, 3);
|
||||
eigencompute(MagCal->matA, MagCal->vecA, MagCal->matB, 3);
|
||||
|
||||
// set MagCal->fmatB to be eigenvectors . diag(sqrt(sqrt(eigenvalues))) =
|
||||
// fmatB . diag(sqrt(sqrt(fvecA))
|
||||
// set MagCal->matB to be eigenvectors . diag(sqrt(sqrt(eigenvalues))) =
|
||||
// matB . diag(sqrt(sqrt(vecA))
|
||||
for (j = 0; j < 3; j++) { // loop over columns j
|
||||
ftmp = sqrtf(sqrtf(fabs(MagCal->fvecA[j])));
|
||||
ftmp = sqrtf(sqrtf(fabs(MagCal->vecA[j])));
|
||||
for (i = 0; i < 3; i++) { // loop over rows i
|
||||
MagCal->fmatB[i][j] *= ftmp;
|
||||
MagCal->matB[i][j] *= ftmp;
|
||||
}
|
||||
}
|
||||
|
||||
// set ftrinvW to eigenvectors * diag(sqrt(eigenvalues)) * eigenvectors^T =
|
||||
// fmatB * fmatB^T = sqrt(fA) (guaranteed symmetric)
|
||||
// set trinvW to eigenvectors * diag(sqrt(eigenvalues)) * eigenvectors^T =
|
||||
// matB * matB^T = sqrt(fA) (guaranteed symmetric)
|
||||
// loop over rows
|
||||
for (i = 0; i < 3; i++) {
|
||||
// loop over on and above diagonal columns
|
||||
for (j = i; j < 3; j++) {
|
||||
MagCal->ftrinvW[i][j] = 0.0F;
|
||||
MagCal->trinvW[i][j] = 0.0F;
|
||||
// accumulate the matrix product
|
||||
for (k = 0; k < 3; k++) {
|
||||
MagCal->ftrinvW[i][j] += MagCal->fmatB[i][k] * MagCal->fmatB[j][k];
|
||||
MagCal->trinvW[i][j] += MagCal->matB[i][k] * MagCal->matB[j][k];
|
||||
}
|
||||
// copy to below diagonal element
|
||||
MagCal->ftrinvW[j][i] = MagCal->ftrinvW[i][j];
|
||||
MagCal->trinvW[j][i] = MagCal->trinvW[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
matrix.c
4
matrix.c
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2014, Freescale Semiconductor, Inc.
|
||||
// All rights reserved.
|
||||
// vim: set ts=4:
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
// * Neither the name of Freescale Semiconductor, Inc. nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
|
|
|||
89
rawdata.c
89
rawdata.c
|
|
@ -10,14 +10,14 @@ SV_9DOF_GBY_KALMAN_t fusionstate;
|
|||
void raw_data_reset(void)
|
||||
{
|
||||
rawcount = OVERSAMPLE_RATIO;
|
||||
fInit_9DOF_GBY_KALMAN(&fusionstate, 100, OVERSAMPLE_RATIO);
|
||||
fInit_9DOF_GBY_KALMAN(&fusionstate);
|
||||
memset(&magcal, 0, sizeof(magcal));
|
||||
magcal.fV[2] = 80.0f; // initial guess
|
||||
magcal.finvW[0][0] = 1.0f;
|
||||
magcal.finvW[1][1] = 1.0f;
|
||||
magcal.finvW[2][2] = 1.0f;
|
||||
magcal.fFitErrorpc = 100.0f;
|
||||
magcal.fFitErrorAge = 100.0f;
|
||||
magcal.V[2] = 80.0f; // initial guess
|
||||
magcal.invW[0][0] = 1.0f;
|
||||
magcal.invW[1][1] = 1.0f;
|
||||
magcal.invW[2][2] = 1.0f;
|
||||
magcal.FitError = 100.0f;
|
||||
magcal.FitErrorAge = 100.0f;
|
||||
}
|
||||
|
||||
static void add_magcal_data(const int16_t *data)
|
||||
|
|
@ -36,9 +36,9 @@ static void add_magcal_data(const int16_t *data)
|
|||
if (i >= MAGBUFFSIZE) {
|
||||
for (i=0; i < MAGBUFFSIZE; i++) {
|
||||
for (j=i+1; j < MAGBUFFSIZE; j++) {
|
||||
dx = magcal.iBpFast[0][i] - magcal.iBpFast[0][j];
|
||||
dy = magcal.iBpFast[1][i] - magcal.iBpFast[1][j];
|
||||
dz = magcal.iBpFast[2][i] - magcal.iBpFast[2][j];
|
||||
dx = magcal.BpFast[0][i] - magcal.BpFast[0][j];
|
||||
dy = magcal.BpFast[1][i] - magcal.BpFast[1][j];
|
||||
dz = magcal.BpFast[2][i] - magcal.BpFast[2][j];
|
||||
distsq = (int64_t)dx * (int64_t)dx;
|
||||
distsq += (int64_t)dy * (int64_t)dy;
|
||||
distsq += (int64_t)dz * (int64_t)dz;
|
||||
|
|
@ -51,9 +51,9 @@ static void add_magcal_data(const int16_t *data)
|
|||
i = minindex;
|
||||
}
|
||||
// add it to the cal buffer
|
||||
magcal.iBpFast[0][i] = data[6];
|
||||
magcal.iBpFast[1][i] = data[7];
|
||||
magcal.iBpFast[2][i] = data[8];
|
||||
magcal.BpFast[0][i] = data[6];
|
||||
magcal.BpFast[1][i] = data[7];
|
||||
magcal.BpFast[2][i] = data[8];
|
||||
magcal.valid[i] = 1;
|
||||
}
|
||||
|
||||
|
|
@ -75,47 +75,46 @@ void raw_data(const int16_t *data)
|
|||
x = (float)data[0] * G_PER_COUNT;
|
||||
y = (float)data[1] * G_PER_COUNT;
|
||||
z = (float)data[2] * G_PER_COUNT;
|
||||
accel.fGpFast[0] = x;
|
||||
accel.fGpFast[1] = y;
|
||||
accel.fGpFast[2] = y;
|
||||
accel.fGp[0] += x;
|
||||
accel.fGp[1] += y;
|
||||
accel.fGp[2] += y;
|
||||
accel.GpFast[0] = x;
|
||||
accel.GpFast[1] = y;
|
||||
accel.GpFast[2] = y;
|
||||
accel.Gp[0] += x;
|
||||
accel.Gp[1] += y;
|
||||
accel.Gp[2] += y;
|
||||
|
||||
x = (float)data[3] * DEG_PER_SEC_PER_COUNT;
|
||||
y = (float)data[4] * DEG_PER_SEC_PER_COUNT;
|
||||
z = (float)data[5] * DEG_PER_SEC_PER_COUNT;
|
||||
gyro.fYp[0] += x;
|
||||
gyro.fYp[1] += y;
|
||||
gyro.fYp[2] += z;
|
||||
gyro.iYpFast[rawcount][0] = data[3];
|
||||
gyro.iYpFast[rawcount][1] = data[4];
|
||||
gyro.iYpFast[rawcount][2] = data[5];
|
||||
gyro.Yp[0] += x;
|
||||
gyro.Yp[1] += y;
|
||||
gyro.Yp[2] += z;
|
||||
gyro.YpFast[rawcount][0] = data[3];
|
||||
gyro.YpFast[rawcount][1] = data[4];
|
||||
gyro.YpFast[rawcount][2] = data[5];
|
||||
|
||||
apply_calibration(data[6], data[7], data[8], &point);
|
||||
mag.fBcFast[0] = point.x;
|
||||
mag.fBcFast[1] = point.y;
|
||||
mag.fBcFast[2] = point.z;
|
||||
mag.fBc[0] += point.x;
|
||||
mag.fBc[1] += point.y;
|
||||
mag.fBc[2] += point.z;
|
||||
mag.BcFast[0] = point.x;
|
||||
mag.BcFast[1] = point.y;
|
||||
mag.BcFast[2] = point.z;
|
||||
mag.Bc[0] += point.x;
|
||||
mag.Bc[1] += point.y;
|
||||
mag.Bc[2] += point.z;
|
||||
|
||||
rawcount++;
|
||||
if (rawcount >= OVERSAMPLE_RATIO) {
|
||||
ratio = 1.0f / (float)OVERSAMPLE_RATIO;
|
||||
accel.fGp[0] *= ratio;
|
||||
accel.fGp[1] *= ratio;
|
||||
accel.fGp[2] *= ratio;
|
||||
gyro.fYp[0] *= ratio;
|
||||
gyro.fYp[1] *= ratio;
|
||||
gyro.fYp[2] *= ratio;
|
||||
mag.fBc[0] *= ratio;
|
||||
mag.fBc[1] *= ratio;
|
||||
mag.fBc[2] *= ratio;
|
||||
fRun_9DOF_GBY_KALMAN(&fusionstate, &accel, &mag, &gyro,
|
||||
&magcal, OVERSAMPLE_RATIO);
|
||||
accel.Gp[0] *= ratio;
|
||||
accel.Gp[1] *= ratio;
|
||||
accel.Gp[2] *= ratio;
|
||||
gyro.Yp[0] *= ratio;
|
||||
gyro.Yp[1] *= ratio;
|
||||
gyro.Yp[2] *= ratio;
|
||||
mag.Bc[0] *= ratio;
|
||||
mag.Bc[1] *= ratio;
|
||||
mag.Bc[2] *= ratio;
|
||||
fRun_9DOF_GBY_KALMAN(&fusionstate, &accel, &mag, &gyro, &magcal);
|
||||
|
||||
memcpy(¤t_orientation, &(fusionstate.fqPl), sizeof(Quaternion_t));
|
||||
memcpy(¤t_orientation, &(fusionstate.qPl), sizeof(Quaternion_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,11 +158,11 @@ int send_calibration(void)
|
|||
*p++ = 117; // 2 byte signature
|
||||
*p++ = 84;
|
||||
for (i=0; i < 3; i++) {
|
||||
p = copy_lsb_first(p, magcal.fV[i]); // 12 bytes offset/hardiron
|
||||
p = copy_lsb_first(p, magcal.V[i]); // 12 bytes offset/hardiron
|
||||
}
|
||||
for (i=0; i < 3; i++) {
|
||||
for (j=0; j < 3; j++) {
|
||||
p = copy_lsb_first(p, magcal.finvW[i][j]); // 36 bytes softiron
|
||||
p = copy_lsb_first(p, magcal.invW[i][j]); // 36 bytes softiron
|
||||
}
|
||||
}
|
||||
crc = 0xFFFF;
|
||||
|
|
|
|||
34
serialdata.c
34
serialdata.c
|
|
@ -50,30 +50,30 @@ static int packet_magnetic_cal(const unsigned char *data)
|
|||
z = (data[13] << 8) | data[12];
|
||||
|
||||
if (id == 1) {
|
||||
magcal.fV[0] = (float)x * 0.1f;
|
||||
magcal.fV[1] = (float)y * 0.1f;
|
||||
magcal.fV[2] = (float)z * 0.1f;
|
||||
magcal.V[0] = (float)x * 0.1f;
|
||||
magcal.V[1] = (float)y * 0.1f;
|
||||
magcal.V[2] = (float)z * 0.1f;
|
||||
return 1;
|
||||
} else if (id == 2) {
|
||||
magcal.finvW[0][0] = (float)x * 0.001f;
|
||||
magcal.finvW[1][1] = (float)y * 0.001f;
|
||||
magcal.finvW[2][2] = (float)z * 0.001f;
|
||||
magcal.invW[0][0] = (float)x * 0.001f;
|
||||
magcal.invW[1][1] = (float)y * 0.001f;
|
||||
magcal.invW[2][2] = (float)z * 0.001f;
|
||||
return 1;
|
||||
} else if (id == 3) {
|
||||
magcal.finvW[0][1] = (float)x / 1000.0f;
|
||||
magcal.finvW[1][0] = (float)x / 1000.0f; // TODO: check this assignment
|
||||
magcal.finvW[0][2] = (float)y / 1000.0f;
|
||||
magcal.finvW[1][2] = (float)y / 1000.0f; // TODO: check this assignment
|
||||
magcal.finvW[1][2] = (float)z / 1000.0f;
|
||||
magcal.finvW[2][1] = (float)z / 1000.0f; // TODO: check this assignment
|
||||
magcal.invW[0][1] = (float)x / 1000.0f;
|
||||
magcal.invW[1][0] = (float)x / 1000.0f; // TODO: check this assignment
|
||||
magcal.invW[0][2] = (float)y / 1000.0f;
|
||||
magcal.invW[1][2] = (float)y / 1000.0f; // TODO: check this assignment
|
||||
magcal.invW[1][2] = (float)z / 1000.0f;
|
||||
magcal.invW[2][1] = (float)z / 1000.0f; // TODO: check this assignment
|
||||
return 1;
|
||||
} else if (id >= 10 && id < MAGBUFFSIZE+10) {
|
||||
n = id - 10;
|
||||
if (magcal.valid[n] == 0 || x != magcal.iBpFast[0][n]
|
||||
|| y != magcal.iBpFast[1][n] || z != magcal.iBpFast[2][n]) {
|
||||
magcal.iBpFast[0][n] = x;
|
||||
magcal.iBpFast[1][n] = y;
|
||||
magcal.iBpFast[2][n] = z;
|
||||
if (magcal.valid[n] == 0 || x != magcal.BpFast[0][n]
|
||||
|| y != magcal.BpFast[1][n] || z != magcal.BpFast[2][n]) {
|
||||
magcal.BpFast[0][n] = x;
|
||||
magcal.BpFast[1][n] = y;
|
||||
magcal.BpFast[2][n] = z;
|
||||
magcal.valid[n] = 1;
|
||||
printf("mag cal, n=%3d: %5d %5d %5d\n", n, x, y, z);
|
||||
}
|
||||
|
|
|
|||
16
visualize.c
16
visualize.c
|
|
@ -50,12 +50,12 @@ void apply_calibration(int16_t rawx, int16_t rawy, int16_t rawz, Point_t *out)
|
|||
{
|
||||
float x, y, z;
|
||||
|
||||
x = ((float)rawx * UT_PER_COUNT) - magcal.fV[0];
|
||||
y = ((float)rawy * UT_PER_COUNT) - magcal.fV[1];
|
||||
z = ((float)rawz * UT_PER_COUNT) - magcal.fV[2];
|
||||
out->x = x * magcal.finvW[0][0] + y * magcal.finvW[0][1] + z * magcal.finvW[0][2];
|
||||
out->y = x * magcal.finvW[1][0] + y * magcal.finvW[1][1] + z * magcal.finvW[1][2];
|
||||
out->z = x * magcal.finvW[2][0] + y * magcal.finvW[2][1] + z * magcal.finvW[2][2];
|
||||
x = ((float)rawx * UT_PER_COUNT) - magcal.V[0];
|
||||
y = ((float)rawy * UT_PER_COUNT) - magcal.V[1];
|
||||
z = ((float)rawz * UT_PER_COUNT) - magcal.V[2];
|
||||
out->x = x * magcal.invW[0][0] + y * magcal.invW[0][1] + z * magcal.invW[0][2];
|
||||
out->y = x * magcal.invW[1][0] + y * magcal.invW[1][1] + z * magcal.invW[1][2];
|
||||
out->z = x * magcal.invW[2][0] + y * magcal.invW[2][1] + z * magcal.invW[2][2];
|
||||
}
|
||||
|
||||
static void quad_to_rotation(const Quaternion_t *quat, float *rmatrix)
|
||||
|
|
@ -119,8 +119,8 @@ void display_callback(void)
|
|||
//if (caldata[i].valid) {
|
||||
if (magcal.valid[i]) {
|
||||
//apply_calibration(&caldata[i], &point);
|
||||
apply_calibration(magcal.iBpFast[0][i], magcal.iBpFast[1][i],
|
||||
magcal.iBpFast[2][i], &point);
|
||||
apply_calibration(magcal.BpFast[0][i], magcal.BpFast[1][i],
|
||||
magcal.BpFast[2][i], &point);
|
||||
sumx += point.x;
|
||||
sumy += point.y;
|
||||
sumz += point.z;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue