Fusion.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright (C) 2011 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <stdio.h>
  17. #include <utils/Log.h>
  18. #include "Fusion.h"
  19. namespace android {
  20. // -----------------------------------------------------------------------
  21. /*
  22. * gyroVAR gives the measured variance of the gyro's output per
  23. * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro,
  24. * which is independent of the sampling frequency.
  25. *
  26. * The variance of gyro's output at a given sampling period can be
  27. * calculated as:
  28. * variance(T) = gyroVAR / T
  29. *
  30. * The variance of the INTEGRATED OUTPUT at a given sampling period can be
  31. * calculated as:
  32. * variance_integrate_output(T) = gyroVAR * T
  33. *
  34. */
  35. static const float gyroVAR = 1e-7; // (rad/s)^2 / Hz
  36. static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed)
  37. /*
  38. * Standard deviations of accelerometer and magnetometer
  39. */
  40. static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05)
  41. static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5)
  42. static const float SYMMETRY_TOLERANCE = 1e-10f;
  43. /*
  44. * Accelerometer updates will not be performed near free fall to avoid
  45. * ill-conditioning and div by zeros.
  46. * Threshhold: 10% of g, in m/s^2
  47. */
  48. static const float FREE_FALL_THRESHOLD = 0.981f;
  49. static const float FREE_FALL_THRESHOLD_SQ =
  50. FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
  51. /*
  52. * The geomagnetic-field should be between 30uT and 60uT.
  53. * Fields strengths greater than this likely indicate a local magnetic
  54. * disturbance which we do not want to update into the fused frame.
  55. */
  56. static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT
  57. static const float MAX_VALID_MAGNETIC_FIELD_SQ =
  58. MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD;
  59. /*
  60. * Values of the field smaller than this should be ignored in fusion to avoid
  61. * ill-conditioning. This state can happen with anomalous local magnetic
  62. * disturbances canceling the Earth field.
  63. */
  64. static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT
  65. static const float MIN_VALID_MAGNETIC_FIELD_SQ =
  66. MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD;
  67. /*
  68. * If the cross product of two vectors has magnitude squared less than this,
  69. * we reject it as invalid due to alignment of the vectors.
  70. * This threshold is used to check for the case where the magnetic field sample
  71. * is parallel to the gravity field, which can happen in certain places due
  72. * to magnetic field disturbances.
  73. */
  74. static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3;
  75. static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
  76. MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
  77. // -----------------------------------------------------------------------
  78. template <typename TYPE, size_t C, size_t R>
  79. static mat<TYPE, R, R> scaleCovariance(
  80. const mat<TYPE, C, R>& A,
  81. const mat<TYPE, C, C>& P) {
  82. // A*P*transpose(A);
  83. mat<TYPE, R, R> APAt;
  84. for (size_t r=0 ; r<R ; r++) {
  85. for (size_t j=r ; j<R ; j++) {
  86. double apat(0);
  87. for (size_t c=0 ; c<C ; c++) {
  88. double v(A[c][r]*P[c][c]*0.5);
  89. for (size_t k=c+1 ; k<C ; k++)
  90. v += A[k][r] * P[c][k];
  91. apat += 2 * v * A[c][j];
  92. }
  93. APAt[j][r] = apat;
  94. APAt[r][j] = apat;
  95. }
  96. }
  97. return APAt;
  98. }
  99. template <typename TYPE, typename OTHER_TYPE>
  100. static mat<TYPE, 3, 3> crossMatrix(const vec<TYPE, 3>& p, OTHER_TYPE diag) {
  101. mat<TYPE, 3, 3> r;
  102. r[0][0] = diag;
  103. r[1][1] = diag;
  104. r[2][2] = diag;
  105. r[0][1] = p.z;
  106. r[1][0] =-p.z;
  107. r[0][2] =-p.y;
  108. r[2][0] = p.y;
  109. r[1][2] = p.x;
  110. r[2][1] =-p.x;
  111. return r;
  112. }
  113. template<typename TYPE, size_t SIZE>
  114. class Covariance {
  115. mat<TYPE, SIZE, SIZE> mSumXX;
  116. vec<TYPE, SIZE> mSumX;
  117. size_t mN;
  118. public:
  119. Covariance() : mSumXX(0.0f), mSumX(0.0f), mN(0) { }
  120. void update(const vec<TYPE, SIZE>& x) {
  121. mSumXX += x*transpose(x);
  122. mSumX += x;
  123. mN++;
  124. }
  125. mat<TYPE, SIZE, SIZE> operator()() const {
  126. const float N = 1.0f / mN;
  127. return mSumXX*N - (mSumX*transpose(mSumX))*(N*N);
  128. }
  129. void reset() {
  130. mN = 0;
  131. mSumXX = 0;
  132. mSumX = 0;
  133. }
  134. size_t getCount() const {
  135. return mN;
  136. }
  137. };
  138. // -----------------------------------------------------------------------
  139. Fusion::Fusion() {
  140. Phi[0][1] = 0;
  141. Phi[1][1] = 1;
  142. Ba.x = 0;
  143. Ba.y = 0;
  144. Ba.z = 1;
  145. Bm.x = 0;
  146. Bm.y = 1;
  147. Bm.z = 0;
  148. x0 = 0;
  149. x1 = 0;
  150. init();
  151. }
  152. void Fusion::init() {
  153. mInitState = 0;
  154. mGyroRate = 0;
  155. mCount[0] = 0;
  156. mCount[1] = 0;
  157. mCount[2] = 0;
  158. mData = 0;
  159. }
  160. void Fusion::initFusion(const vec4_t& q, float dT)
  161. {
  162. // initial estimate: E{ x(t0) }
  163. x0 = q;
  164. x1 = 0;
  165. // process noise covariance matrix: G.Q.Gt, with
  166. //
  167. // G = | -1 0 | Q = | q00 q10 |
  168. // | 0 1 | | q01 q11 |
  169. //
  170. // q00 = sv^2.dt + 1/3.su^2.dt^3
  171. // q10 = q01 = 1/2.su^2.dt^2
  172. // q11 = su^2.dt
  173. //
  174. const float dT2 = dT*dT;
  175. const float dT3 = dT2*dT;
  176. // variance of integrated output at 1/dT Hz (random drift)
  177. const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3;
  178. // variance of drift rate ramp
  179. const float q11 = biasVAR * dT;
  180. const float q10 = 0.5f * biasVAR * dT2;
  181. const float q01 = q10;
  182. GQGt[0][0] = q00; // rad^2
  183. GQGt[1][0] = -q10;
  184. GQGt[0][1] = -q01;
  185. GQGt[1][1] = q11; // (rad/s)^2
  186. // initial covariance: Var{ x(t0) }
  187. // TODO: initialize P correctly
  188. P = 0;
  189. }
  190. bool Fusion::hasEstimate() const {
  191. return (mInitState == (MAG|ACC|GYRO));
  192. }
  193. bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
  194. if (hasEstimate())
  195. return true;
  196. if (what == ACC) {
  197. mData[0] += d * (1/length(d));
  198. mCount[0]++;
  199. mInitState |= ACC;
  200. } else if (what == MAG) {
  201. mData[1] += d * (1/length(d));
  202. mCount[1]++;
  203. mInitState |= MAG;
  204. } else if (what == GYRO) {
  205. mGyroRate = dT;
  206. mData[2] += d*dT;
  207. mCount[2]++;
  208. if (mCount[2] == 64) {
  209. // 64 samples is good enough to estimate the gyro drift and
  210. // doesn't take too much time.
  211. mInitState |= GYRO;
  212. }
  213. }
  214. if (mInitState == (MAG|ACC|GYRO)) {
  215. // Average all the values we collected so far
  216. mData[0] *= 1.0f/mCount[0];
  217. mData[1] *= 1.0f/mCount[1];
  218. mData[2] *= 1.0f/mCount[2];
  219. // calculate the MRPs from the data collection, this gives us
  220. // a rough estimate of our initial state
  221. mat33_t R;
  222. vec3_t up(mData[0]);
  223. vec3_t east(cross_product(mData[1], up));
  224. east *= 1/length(east);
  225. vec3_t north(cross_product(up, east));
  226. R << east << north << up;
  227. const vec4_t q = matrixToQuat(R);
  228. initFusion(q, mGyroRate);
  229. }
  230. return false;
  231. }
  232. void Fusion::handleGyro(const vec3_t& w, float dT) {
  233. if (!checkInitComplete(GYRO, w, dT))
  234. return;
  235. predict(w, dT);
  236. }
  237. status_t Fusion::handleAcc(const vec3_t& a) {
  238. // ignore acceleration data if we're close to free-fall
  239. if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) {
  240. return BAD_VALUE;
  241. }
  242. if (!checkInitComplete(ACC, a))
  243. return BAD_VALUE;
  244. const float l = 1/length(a);
  245. update(a*l, Ba, accSTDEV*l);
  246. return NO_ERROR;
  247. }
  248. status_t Fusion::handleMag(const vec3_t& m) {
  249. // the geomagnetic-field should be between 30uT and 60uT
  250. // reject if too large to avoid spurious magnetic sources
  251. const float magFieldSq = length_squared(m);
  252. if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) {
  253. return BAD_VALUE;
  254. } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) {
  255. // Also reject if too small since we will get ill-defined (zero mag)
  256. // cross-products below
  257. return BAD_VALUE;
  258. }
  259. if (!checkInitComplete(MAG, m))
  260. return BAD_VALUE;
  261. // Orthogonalize the magnetic field to the gravity field, mapping it into
  262. // tangent to Earth.
  263. const vec3_t up( getRotationMatrix() * Ba );
  264. const vec3_t east( cross_product(m, up) );
  265. // If the m and up vectors align, the cross product magnitude will
  266. // approach 0.
  267. // Reject this case as well to avoid div by zero problems and
  268. // ill-conditioning below.
  269. if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) {
  270. return BAD_VALUE;
  271. }
  272. // If we have created an orthogonal magnetic field successfully,
  273. // then pass it in as the update.
  274. vec3_t north( cross_product(up, east) );
  275. const float l = 1 / length(north);
  276. north *= l;
  277. update(north, Bm, magSTDEV*l);
  278. return NO_ERROR;
  279. }
  280. void Fusion::checkState() {
  281. // P needs to stay positive semidefinite or the fusion diverges. When we
  282. // detect divergence, we reset the fusion.
  283. // TODO(braun): Instead, find the reason for the divergence and fix it.
  284. if (!isPositiveSemidefinite(P[0][0], SYMMETRY_TOLERANCE) ||
  285. !isPositiveSemidefinite(P[1][1], SYMMETRY_TOLERANCE)) {
  286. ALOGW("Sensor fusion diverged; resetting state.");
  287. P = 0;
  288. }
  289. }
  290. vec4_t Fusion::getAttitude() const {
  291. return x0;
  292. }
  293. vec3_t Fusion::getBias() const {
  294. return x1;
  295. }
  296. mat33_t Fusion::getRotationMatrix() const {
  297. return quatToMatrix(x0);
  298. }
  299. mat34_t Fusion::getF(const vec4_t& q) {
  300. mat34_t F;
  301. // This is used to compute the derivative of q
  302. // F = | [q.xyz]x |
  303. // | -q.xyz |
  304. F[0].x = q.w; F[1].x =-q.z; F[2].x = q.y;
  305. F[0].y = q.z; F[1].y = q.w; F[2].y =-q.x;
  306. F[0].z =-q.y; F[1].z = q.x; F[2].z = q.w;
  307. F[0].w =-q.x; F[1].w =-q.y; F[2].w =-q.z;
  308. return F;
  309. }
  310. void Fusion::predict(const vec3_t& w, float dT) {
  311. const vec4_t q = x0;
  312. const vec3_t b = x1;
  313. const vec3_t we = w - b;
  314. // q(k+1) = O(we)*q(k)
  315. // --------------------
  316. //
  317. // O(w) = | cos(0.5*||w||*dT)*I33 - [psi]x psi |
  318. // | -psi' cos(0.5*||w||*dT) |
  319. //
  320. // psi = sin(0.5*||w||*dT)*w / ||w||
  321. //
  322. //
  323. // P(k+1) = Phi(k)*P(k)*Phi(k)' + G*Q(k)*G'
  324. // ----------------------------------------
  325. //
  326. // G = | -I33 0 |
  327. // | 0 I33 |
  328. //
  329. // Phi = | Phi00 Phi10 |
  330. // | 0 1 |
  331. //
  332. // Phi00 = I33
  333. // - [w]x * sin(||w||*dt)/||w||
  334. // + [w]x^2 * (1-cos(||w||*dT))/||w||^2
  335. //
  336. // Phi10 = [w]x * (1 - cos(||w||*dt))/||w||^2
  337. // - [w]x^2 * (||w||*dT - sin(||w||*dt))/||w||^3
  338. // - I33*dT
  339. const mat33_t I33(1);
  340. const mat33_t I33dT(dT);
  341. const mat33_t wx(crossMatrix(we, 0));
  342. const mat33_t wx2(wx*wx);
  343. const float lwedT = length(we)*dT;
  344. const float hlwedT = 0.5f*lwedT;
  345. const float ilwe = 1/length(we);
  346. const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
  347. const float k1 = sinf(lwedT);
  348. const float k2 = cosf(hlwedT);
  349. const vec3_t psi(sinf(hlwedT)*ilwe*we);
  350. const mat33_t O33(crossMatrix(-psi, k2));
  351. mat44_t O;
  352. O[0].xyz = O33[0]; O[0].w = -psi.x;
  353. O[1].xyz = O33[1]; O[1].w = -psi.y;
  354. O[2].xyz = O33[2]; O[2].w = -psi.z;
  355. O[3].xyz = psi; O[3].w = k2;
  356. Phi[0][0] = I33 - wx*(k1*ilwe) + wx2*k0;
  357. Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
  358. x0 = O*q;
  359. if (x0.w < 0)
  360. x0 = -x0;
  361. P = Phi*P*transpose(Phi) + GQGt;
  362. checkState();
  363. }
  364. void Fusion::update(const vec3_t& z, const vec3_t& Bi, float sigma) {
  365. vec4_t q(x0);
  366. // measured vector in body space: h(p) = A(p)*Bi
  367. const mat33_t A(quatToMatrix(q));
  368. const vec3_t Bb(A*Bi);
  369. // Sensitivity matrix H = dh(p)/dp
  370. // H = [ L 0 ]
  371. const mat33_t L(crossMatrix(Bb, 0));
  372. // gain...
  373. // K = P*Ht / [H*P*Ht + R]
  374. vec<mat33_t, 2> K;
  375. const mat33_t R(sigma*sigma);
  376. const mat33_t S(scaleCovariance(L, P[0][0]) + R);
  377. const mat33_t Si(invert(S));
  378. const mat33_t LtSi(transpose(L)*Si);
  379. K[0] = P[0][0] * LtSi;
  380. K[1] = transpose(P[1][0])*LtSi;
  381. // update...
  382. // P = (I-K*H) * P
  383. // P -= K*H*P
  384. // | K0 | * | L 0 | * P = | K0*L 0 | * | P00 P10 | = | K0*L*P00 K0*L*P10 |
  385. // | K1 | | K1*L 0 | | P01 P11 | | K1*L*P00 K1*L*P10 |
  386. // Note: the Joseph form is numerically more stable and given by:
  387. // P = (I-KH) * P * (I-KH)' + K*R*R'
  388. const mat33_t K0L(K[0] * L);
  389. const mat33_t K1L(K[1] * L);
  390. P[0][0] -= K0L*P[0][0];
  391. P[1][1] -= K1L*P[1][0];
  392. P[1][0] -= K0L*P[1][0];
  393. P[0][1] = transpose(P[1][0]);
  394. const vec3_t e(z - Bb);
  395. const vec3_t dq(K[0]*e);
  396. const vec3_t db(K[1]*e);
  397. q += getF(q)*(0.5f*dq);
  398. x0 = normalize_quat(q);
  399. x1 += db;
  400. checkState();
  401. }
  402. // -----------------------------------------------------------------------
  403. }; // namespace android