Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / config / twostep.cpp
blob5c125ba04adad1251ed7e52a125fa2089eb5ba1c
1 /**
2 ******************************************************************************
4 * @file twostep.cpp
5 * @author Jonathan Brandmeyer <jonathan.brandmeyer@gmail.com>
6 * Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
8 * @{
9 * @addtogroup Config plugin
10 * @{
11 * @brief Implements low-level calibration algorithms
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; Version 3 of the License, and no other
17 * version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <calibration.h>
30 #include <assertions.h>
31 #include <Eigen/Eigen2Support>
33 #include <cstdlib>
35 #undef PRINTF_DEBUGGING
37 #include <iostream>
38 #include <iomanip>
40 #if defined(__APPLE__) || defined(_WIN32)
41 // Qt bug work around
42 #ifndef isnan
43 extern "C" int isnan(double);
44 #endif
45 #ifndef isinf
46 extern "C" int isinf(double);
47 #endif
48 #endif
51 * Alas, this implementation is a fairly direct copy of the contents of the
52 * following papers. You don't have a chance at understanding it without
53 * reading these first. Any bugs should be presumed to be JB's fault rather
54 * than Alonso and Shuster until proven otherwise.
56 * Reference [1]: "A New Algorithm for Attitude-independent magnetometer
57 * calibration", Robert Alonso and Malcolmn D. Shuster, Flight Mechanics/
58 * Estimation Theory Symposium, NASA Goddard, 1994, pp 513-527
60 * Reference [2]: Roberto Alonso and Malcolm D. Shuster, "Complete Linear
61 * Attitude-Independent Magnetometer Calibration", Journal of the Astronautical
62 * Sciences, Vol 50, No 4, 2002, pp 477-490
66 namespace {
67 Vector3f center(const Vector3f samples[],
68 size_t n_samples)
70 Vector3f summation(Vector3f::Zero());
72 for (size_t i = 0; i < n_samples; ++i) {
73 summation += samples[i];
75 return summation / float(n_samples);
78 void inv_fisher_information_matrix(Matrix3f & fisherInv,
79 Matrix3f & fisher,
80 const Vector3f samples[],
81 size_t n_samples,
82 const float noise)
84 MatrixXf column_samples(3, n_samples);
86 for (size_t i = 0; i < n_samples; ++i) {
87 column_samples.col(i) = samples[i];
89 fisher = 4 / noise *
90 column_samples * column_samples.transpose();
91 // Compute the inverse by taking advantage of the results symmetricness
92 fisher.ldlt().solve(Matrix3f::Identity(), &fisherInv);
94 // Eq 14 of the original reference. Computes the gradiant of the cost function
95 // with respect to the bias offset.
96 // @param samples: The vector of measurement samples
97 // @param mags: The vector of sample delta magnitudes
98 // @param b: The estimate of the bias
99 // @param mu: The trace of the noise matrix (3*noise)
100 // @return the negative gradiant of the cost function with respect to the
101 // current value of the estimate, b
102 Vector3f neg_dJdb(const Vector3f samples[],
103 const float mags[],
104 size_t n_samples,
105 const Vector3f & b,
106 float mu,
107 float noise)
109 Vector3f summation(Vector3f::Zero());
110 float b_norm2 = b.squaredNorm();
112 for (size_t i = 0; i < n_samples; ++i) {
113 summation += (mags[i] - 2 * samples[i].dot(b) + b_norm2 - mu)
114 * 2 * (samples[i] - b);
117 return (1.0 / noise) * summation;
119 } // !namespace (anon)
121 Vector3f twostep_bias_only(const Vector3f samples[],
122 size_t n_samples,
123 const Vector3f & referenceField,
124 const float noise)
126 // \tilde{H}
127 Vector3f *centeredSamples = new Vector3f[n_samples];
128 // z_k
129 float sampleDeltaMag[n_samples];
130 // eq 7 and 8 applied to samples
131 Vector3f avg = center(samples, n_samples);
132 float refSquaredNorm = referenceField.squaredNorm();
133 float sampleDeltaMagCenter = 0;
135 for (size_t i = 0; i < n_samples; ++i) {
136 // eq 9 applied to samples
137 centeredSamples[i] = samples[i] - avg;
138 // eqn 2a
139 sampleDeltaMag[i] = samples[i].squaredNorm() - refSquaredNorm;
140 sampleDeltaMagCenter += sampleDeltaMag[i];
142 sampleDeltaMagCenter /= n_samples;
144 Matrix3f P_bb;
145 Matrix3f P_bb_inv;
146 // Due to eq 12b
147 inv_fisher_information_matrix(P_bb, P_bb_inv, centeredSamples, n_samples, noise);
148 // Compute centered magnitudes
149 float sampleDeltaMagCentered[n_samples];
150 for (size_t i = 0; i < n_samples; ++i) {
151 sampleDeltaMagCentered[i] = sampleDeltaMag[i] - sampleDeltaMagCenter;
154 // From eq 12a
155 Vector3f estimate(Vector3f::Zero());
156 for (size_t i = 0; i < n_samples; ++i) {
157 estimate += sampleDeltaMagCentered[i] * centeredSamples[i];
159 estimate = P_bb * ((2 / noise) * estimate);
161 // Newton-Raphson gradient descent to the optimal solution
162 // eq 14a and 14b
163 float mu = -3 * noise;
164 for (int i = 0; i < 6; ++i) {
165 Vector3f neg_gradiant = neg_dJdb(samples, sampleDeltaMag, n_samples,
166 estimate, mu, noise);
167 Matrix3f scale = P_bb_inv + 4 / noise * (avg - estimate) * (avg - estimate).transpose();
168 Vector3f neg_increment;
169 scale.ldlt().solve(neg_gradiant, &neg_increment);
170 // Note that the negative has been done twice
171 estimate += neg_increment;
173 delete[] centeredSamples;
174 return estimate;
177 namespace {
178 // Private utility functions for the version of TWOSTEP that computes bias and
179 // scale factor vectors alone.
181 /** Compute the gradiant of the norm of b with respect to the estimate vector.
183 Matrix<double, 6, 1>
184 dnormb_dtheta(const Matrix<double, 6, 1> & theta)
186 return (Matrix<double, 6, 1>() << 2 * theta.coeff(0) / (1 + theta.coeff(3)),
187 2 * theta.coeff(1) / (1 + theta.coeff(4)),
188 2 * theta.coeff(2) / (1 + theta.coeff(5)),
189 -pow(theta.coeff(0), 2) / pow(1 + theta.coeff(3), 2),
190 -pow(theta.coeff(1), 2) / pow(1 + theta.coeff(4), 2),
191 -pow(theta.coeff(2), 2) / pow(1 + theta.coeff(5), 2)).finished();
195 * Compute the gradiant of the cost function with respect to the optimal
196 * estimate.
198 Matrix<double, 6, 1>
199 dJdb(const Matrix<double, 6, 1> & centerL,
200 double centerMag,
201 const Matrix<double, 6, 1> & theta,
202 const Matrix<double, 6, 1> & dbdtheta,
203 double mu,
204 double noise)
206 // \frac{\delta}{\delta \theta'} |b(\theta')|^2
207 Matrix<double, 6, 1> vectorPart = dbdtheta - centerL;
209 // By equation 35
210 double normbthetaSquared = 0;
211 for (unsigned i = 0; i < 3; ++i) {
212 normbthetaSquared += theta.coeff(i) * theta.coeff(i) / (1 + theta.coeff(3 + i));
214 double scalarPart = (centerMag - centerL.dot(theta) + normbthetaSquared
215 - mu) / noise;
216 return scalarPart * vectorPart;
219 /** Reconstruct the scale factor and bias offset vectors from the transformed
220 * estimate vector.
222 Matrix<double, 1, 6>
223 theta_to_sane(const Matrix<double, 6, 1> & theta)
225 return (Matrix<double, 6, 1>() <<
226 theta.coeff(0) / sqrt(1 + theta.coeff(3)),
227 theta.coeff(1) / sqrt(1 + theta.coeff(4)),
228 theta.coeff(2) / sqrt(1 + theta.coeff(5)),
229 -1 + sqrt(1 + theta.coeff(3)),
230 -1 + sqrt(1 + theta.coeff(4)),
231 -1 + sqrt(1 + theta.coeff(5))).finished();
233 } // !namespace (anon)
236 * Compute the scale factor and bias associated with a vector observer
237 * according to the equation:
238 * B_k = (I_{3x3} + D)^{-1} \times (O^T A_k H_k + b + \epsilon_k)
239 * where k is the sample index,
240 * B_k is the kth measurement
241 * I_{3x3} is a 3x3 identity matrix
242 * D is a 3x3 diagonal matrix of scale factors
243 * O is the orthogonal alignment matrix
244 * A_k is the attitude at the kth sample
245 * b is the bias in the global reference frame
246 * \epsilon_k is the noise at the kth sample
247 * This implementation makes the assumption that \epsilon is a constant white,
248 * gaussian noise source that is common to all k. The misalignment matrix O
249 * is not computed, and the off-diagonal elements of D, corresponding to the
250 * misalignment scale factors are not either.
252 * @param bias[out] The computed bias, in the global frame
253 * @param scale[out] The computed scale factor, in the sensor frame
254 * @param samples[in] An array of measurement samples.
255 * @param n_samples The number of samples in the array.
256 * @param referenceField The magnetic field vector at this location.
257 * @param noise The one-sigma squared standard deviation of the observed noise
258 * in the sensor.
260 void twostep_bias_scale(Vector3f & bias,
261 Vector3f & scale,
262 const Vector3f samples[],
263 const size_t n_samples,
264 const Vector3f & referenceField,
265 const float noise)
267 // Initial estimate for gradiant descent starts at eq 37a of ref 2.
269 // Define L_k by eq 30 and 28 for k = 1 .. n_samples
270 Matrix<double, Dynamic, 6> fullSamples(n_samples, 6);
271 // \hbar{L} by eq 33, simplified by obesrving that the
272 Matrix<double, 1, 6> centerSample = Matrix<double, 1, 6>::Zero();
273 // Define the sample differences z_k by eq 23 a)
274 double sampleDeltaMag[n_samples];
275 // The center value \hbar{z}
276 double sampleDeltaMagCenter = 0;
277 double refSquaredNorm = referenceField.squaredNorm();
279 for (size_t i = 0; i < n_samples; ++i) {
280 fullSamples.row(i) << 2 * samples[i].transpose().cast<double>(),
281 -(samples[i][0] * samples[i][0]),
282 -(samples[i][1] * samples[i][1]),
283 -(samples[i][2] * samples[i][2]);
284 centerSample += fullSamples.row(i);
286 sampleDeltaMag[i] = samples[i].squaredNorm() - refSquaredNorm;
287 sampleDeltaMagCenter += sampleDeltaMag[i];
289 sampleDeltaMagCenter /= n_samples;
290 centerSample /= n_samples;
292 // True for all k.
293 // double mu = -3*noise;
294 // The center value of mu, \bar{mu}
295 // double centerMu = mu;
296 // The center value of mu, \tilde{mu}
297 // double centeredMu = 0;
299 // Define \tilde{L}_k for k = 0 .. n_samples
300 Matrix<double, Dynamic, 6> centeredSamples(n_samples, 6);
301 // Define \tilde{z}_k for k = 0 .. n_samples
302 double centeredMags[n_samples];
303 // Compute the term under the summation of eq 37a
304 Matrix<double, 6, 1> estimateSummation = Matrix<double, 6, 1>::Zero();
305 for (size_t i = 0; i < n_samples; ++i) {
306 centeredSamples.row(i) = fullSamples.row(i) - centerSample;
307 centeredMags[i] = sampleDeltaMag[i] - sampleDeltaMagCenter;
308 estimateSummation += centeredMags[i] * centeredSamples.row(i).transpose();
310 estimateSummation /= noise; // note: paper supplies 1/noise
312 // By eq 37 b). Note, paper supplies 1/noise here
313 Matrix<double, 6, 6> P_theta_theta_inv = (1.0f / noise) *
314 centeredSamples.transpose() * centeredSamples;
315 #ifdef PRINTF_DEBUGGING
316 SelfAdjointEigenSolver<Matrix<double, 6, 6> > eig(P_theta_theta_inv);
317 std::cout << "P_theta_theta_inverse: \n" << P_theta_theta_inv << "\n\n";
318 std::cout << "P_\\tt^-1 eigenvalues: " << eig.eigenvalues().transpose()
319 << "\n";
320 std::cout << "P_\\tt^-1 eigenvectors:\n" << eig.eigenvectors() << "\n";
321 #endif
323 // The Fisher information matrix has a small eigenvalue, with a
324 // corresponding eigenvector of about [1e-2 1e-2 1e-2 0.55, 0.55,
325 // 0.55]. This means that there is relatively little information
326 // about the common gain on the scale factor, which has a
327 // corresponding effect on the bias, too. The fixup is performed by
328 // the first iteration of the second stage of TWOSTEP, as documented in
329 // [1].
330 Matrix<double, 6, 1> estimate;
331 // By eq 37 a), \tilde{Fisher}^-1
332 P_theta_theta_inv.ldlt().solve(estimateSummation, &estimate);
334 #ifdef PRINTF_DEBUGGING
335 Matrix<double, 6, 6> P_theta_theta;
336 P_theta_theta_inv.ldlt().solve(Matrix<double, 6, 6>::Identity(), &P_theta_theta);
337 SelfAdjointEigenSolver<Matrix<double, 6, 6> > eig2(P_theta_theta);
338 std::cout << "eigenvalues: " << eig2.eigenvalues().transpose() << "\n";
339 std::cout << "eigenvectors: \n" << eig2.eigenvectors() << "\n";
340 std::cout << "estimate summation: \n" << estimateSummation.normalized()
341 << "\n";
342 #endif
344 // estimate i+1 = estimate_i - Fisher^{-1}(at estimate_i)*gradiant(theta)
345 // Fisher^{-1} = \tilde{Fisher}^-1 + \hbar{Fisher}^{-1}
346 size_t count = 3;
347 while (count-- > 0) {
348 // eq 40
349 Matrix<double, 1, 6> db_dtheta = dnormb_dtheta(estimate);
351 Matrix<double, 6, 1> dJ_dtheta = dJdb(centerSample,
352 sampleDeltaMagCenter,
353 estimate,
354 db_dtheta,
355 -3 * noise,
356 noise / n_samples);
359 // Eq 39 (with double-negation on term inside parens)
360 db_dtheta = centerSample - db_dtheta;
361 Matrix<double, 6, 6> scale = P_theta_theta_inv +
362 (double(n_samples) / noise) * db_dtheta.transpose() * db_dtheta;
364 // eq 14b, mutatis mutandis (grumble, grumble)
365 Matrix<double, 6, 1> increment;
366 scale.ldlt().solve(dJ_dtheta, &increment);
367 estimate -= increment;
370 // Transform the estimated parameters from [c | e] back into [b | d].
371 for (size_t i = 0; i < 3; ++i) {
372 scale.coeffRef(i) = -1 + sqrt(1 + estimate.coeff(3 + i));
373 bias.coeffRef(i) = estimate.coeff(i) / sqrt(1 + estimate.coeff(3 + i));
377 namespace {
378 // Private functions specific to the scale factor and orthogonal calibration
379 // version of TWOSTEP
382 * Reconstruct the symmetric E matrix from the last 6 elements of the estimate
383 * vector
385 Matrix3d E_theta(const Matrix<double, 9, 1> & theta)
387 // By equation 49b
388 return (Matrix3d() <<
389 theta.coeff(3), theta.coeff(6), theta.coeff(7),
390 theta.coeff(6), theta.coeff(4), theta.coeff(8),
391 theta.coeff(7), theta.coeff(8), theta.coeff(5)).finished();
395 * Compute the gradient of the squared norm of b with respect to theta. Note
396 * that b itself is just a function of theta. Therefore, this function
397 * computes \frac{\delta,\delta\theta'}\left|b(\theta')\right|
398 * From eq 55 of [2].
400 Matrix<double, 9, 1>
401 dnormb_dtheta(const Matrix<double, 9, 1> & theta)
403 // Re-form the matrix E from the vector of theta'
404 Matrix3d E = E_theta(theta);
405 // Compute (I + E)^-1 * c
406 Vector3d IE_inv_c;
408 E.ldlt().solve(theta.end<3>(), &IE_inv_c);
410 return (Matrix<double, 9, 1>() << 2 * IE_inv_c,
411 -IE_inv_c.coeff(0) * IE_inv_c.coeff(0),
412 -IE_inv_c.coeff(1) * IE_inv_c.coeff(1),
413 -IE_inv_c.coeff(2) * IE_inv_c.coeff(2),
415 -2 * IE_inv_c.coeff(0) * IE_inv_c.coeff(1),
416 -2 * IE_inv_c.coeff(0) * IE_inv_c.coeff(2),
417 -2 * IE_inv_c.coeff(1) * IE_inv_c.coeff(2)).finished();
420 // The gradient of the cost function with respect to theta, at a particular
421 // value of theta.
422 // @param centerL: The center of the samples theta'
423 // @param centerMag: The center of the magnitude data
424 // @param theta: The estimate of the bias and scale factor
425 // @return the gradient of the cost function with respect to the
426 // current value of the estimate, theta'
427 Matrix<double, 9, 1>
428 dJ_dtheta(const Matrix<double, 9, 1> & centerL,
429 double centerMag,
430 const Matrix<double, 9, 1> & theta,
431 const Matrix<double, 9, 1> & dbdtheta,
432 double mu,
433 double noise)
435 // \frac{\delta}{\delta \theta'} |b(\theta')|^2
436 Matrix<double, 9, 1> vectorPart = dbdtheta - centerL;
438 // |b(\theta')|^2
439 Matrix3d E = E_theta(theta);
440 Vector3d rhs;
441 (Matrix3d::Identity() + E).ldlt().solve(theta.start<3>(), &rhs);
442 double normbthetaSquared = theta.start<3>().dot(rhs);
444 double scalarPart = (centerMag - centerL.dot(theta) + normbthetaSquared
445 - mu) / noise;
446 return scalarPart * vectorPart;
448 } // !namespace (anonymous)
451 * Compute the scale factor and bias associated with a vector observer
452 * according to the equation:
453 * B_k = (I_{3x3} + D)^{-1} \times (O^T A_k H_k + b + \epsilon_k)
454 * where k is the sample index,
455 * B_k is the kth measurement
456 * I_{3x3} is a 3x3 identity matrix
457 * D is a 3x3 symmetric matrix of scale factors
458 * O is the orthogonal alignment matrix
459 * A_k is the attitude at the kth sample
460 * b is the bias in the global reference frame
461 * \epsilon_k is the noise at the kth sample
463 * After computing the scale factor and bias matrices, the optimal estimate is
464 * given by
465 * \tilde{B}_k = (I_{3x3} + D)B_k - b
467 * This implementation makes the assumption that \epsilon is a constant white,
468 * gaussian noise source that is common to all k. The misalignment matrix O
469 * is not computed.
471 * @param bias[out] The computed bias, in the global frame
472 * @param scale[out] The computed scale factor matrix, in the sensor frame.
473 * @param samples[in] An array of measurement samples.
474 * @param n_samples The number of samples in the array.
475 * @param referenceField The magnetic field vector at this location.
476 * @param noise The one-sigma squared standard deviation of the observed noise
477 * in the sensor.
479 void twostep_bias_scale(Vector3f & bias,
480 Matrix3f & scale,
481 const Vector3f samples[],
482 const size_t n_samples,
483 const Vector3f & referenceField,
484 const float noise)
486 // Define L_k by eq 51 for k = 1 .. n_samples
487 Matrix<double, Dynamic, 9> fullSamples(n_samples, 9);
488 // \hbar{L} by eq 52, simplified by observing that the common noise term
489 // makes this a simple average.
490 Matrix<double, 1, 9> centerSample = Matrix<double, 1, 9>::Zero();
491 // Define the sample differences z_k by eq 23 a)
492 double sampleDeltaMag[n_samples];
493 // The center value \hbar{z}
494 double sampleDeltaMagCenter = 0;
495 // The squared norm of the reference vector
496 double refSquaredNorm = referenceField.squaredNorm();
498 for (size_t i = 0; i < n_samples; ++i) {
499 fullSamples.row(i) << 2 * samples[i].transpose().cast<double>(),
500 -(samples[i][0] * samples[i][0]),
501 -(samples[i][1] * samples[i][1]),
502 -(samples[i][2] * samples[i][2]),
503 -2 * (samples[i][0] * samples[i][1]),
504 -2 * (samples[i][0] * samples[i][2]),
505 -2 * (samples[i][1] * samples[i][2]);
507 centerSample += fullSamples.row(i);
509 sampleDeltaMag[i] = samples[i].squaredNorm() - refSquaredNorm;
510 sampleDeltaMagCenter += sampleDeltaMag[i];
512 sampleDeltaMagCenter /= n_samples;
513 centerSample /= n_samples;
515 // Define \tilde{L}_k for k = 0 .. n_samples
516 Matrix<double, Dynamic, 9> centeredSamples(n_samples, 9);
517 // Define \tilde{z}_k for k = 0 .. n_samples
518 double centeredMags[n_samples];
519 // Compute the term under the summation of eq 57a
520 Matrix<double, 9, 1> estimateSummation = Matrix<double, 9, 1>::Zero();
521 for (size_t i = 0; i < n_samples; ++i) {
522 centeredSamples.row(i) = fullSamples.row(i) - centerSample;
523 centeredMags[i] = sampleDeltaMag[i] - sampleDeltaMagCenter;
524 estimateSummation += centeredMags[i] * centeredSamples.row(i).transpose();
526 estimateSummation /= noise;
528 // By eq 57b
529 Matrix<double, 9, 9> P_theta_theta_inv = (1.0f / noise) *
530 centeredSamples.transpose() * centeredSamples;
532 #ifdef PRINTF_DEBUGGING
533 SelfAdjointEigenSolver<Matrix<double, 9, 9> > eig(P_theta_theta_inv);
534 std::cout << "P_theta_theta_inverse: \n" << P_theta_theta_inv << "\n\n";
535 std::cout << "P_\\tt^-1 eigenvalues: " << eig.eigenvalues().transpose()
536 << "\n";
537 std::cout << "P_\\tt^-1 eigenvectors:\n" << eig.eigenvectors() << "\n";
538 #endif
540 // The current value of the estimate. Initialized to \tilde{\theta}^*
541 Matrix<double, 9, 1> estimate;
542 // By eq 57a
543 P_theta_theta_inv.ldlt().solve(estimateSummation, &estimate);
545 // estimate i+1 = estimate_i - Fisher^{-1}(at estimate_i)*gradient(theta)
546 // Fisher^{-1} = \tilde{Fisher}^-1 + \hbar{Fisher}^{-1}
547 size_t count = 0;
548 double eta = 10000;
549 while (count++ < 200 && eta > 1e-8) {
550 static bool warned = false;
551 if (hasNaN(estimate)) {
552 std::cout << "WARNING: found NaN at time " << count << "\n";
553 warned = true;
555 #if 0
556 SelfAdjointEigenSolver<Matrix3d> eig_E(E_theta(estimate));
557 Vector3d S = eig_E.eigenvalues();
558 Vector3d W; W << -1 + sqrt(1 + S.coeff(0)),
559 -1 + sqrt(1 + S.coeff(1)),
560 -1 + sqrt(1 + S.coeff(2));
561 scale = (eig_E.eigenvectors() * W.asDiagonal() *
562 eig_E.eigenvectors().transpose()).cast<float>();
564 (Matrix3f::Identity() + scale).ldlt().solve(
565 estimate.start<3>().cast<float>(), &bias);
566 std::cout << "\n\nestimated bias: " << bias.transpose()
567 << "\nestimated scale:\n" << scale;
568 #endif
570 Matrix<double, 1, 9> db_dtheta = dnormb_dtheta(estimate);
572 Matrix<double, 9, 1> dJ_dtheta = ::dJ_dtheta(centerSample,
573 sampleDeltaMagCenter,
574 estimate,
575 db_dtheta,
576 -3 * noise,
577 noise / n_samples);
579 // Eq 59, with reused storage on db_dtheta
580 db_dtheta = centerSample - db_dtheta;
581 Matrix<double, 9, 9> scale = P_theta_theta_inv +
582 (double(n_samples) / noise) * db_dtheta.transpose() * db_dtheta;
584 // eq 14b, mutatis mutandis (grumble, grumble)
585 Matrix<double, 9, 1> increment;
586 scale.ldlt().solve(dJ_dtheta, &increment);
587 estimate -= increment;
588 eta = increment.dot(scale * increment);
589 std::cout << "eta: " << eta << "\n";
591 std::cout << "terminated at eta = " << eta
592 << " after " << count << " iterations\n";
594 if (!isnan(eta) && !isinf(eta)) {
595 // Transform the estimated parameters from [c | E] back into [b | D].
596 // See eq 63-65
597 SelfAdjointEigenSolver<Matrix3d> eig_E(E_theta(estimate));
598 Vector3d S = eig_E.eigenvalues();
599 Vector3d W; W << -1 + sqrt(1 + S.coeff(0)),
600 -1 + sqrt(1 + S.coeff(1)),
601 -1 + sqrt(1 + S.coeff(2));
602 scale = (eig_E.eigenvectors() * W.asDiagonal() *
603 eig_E.eigenvectors().transpose()).cast<float>();
605 (Matrix3f::Identity() + scale).ldlt().solve(
606 estimate.start<3>().cast<float>(), &bias);
607 } else {
608 // return nonsense data. The eigensolver can fall ingo
609 // an infinite loop otherwise.
610 // TODO: Add error code return
611 scale = Matrix3f::Ones() * std::numeric_limits<float>::quiet_NaN();
612 bias = Vector3f::Zero();