FuseMagnetometer.m 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. function [...
  2. nextQuat, ... % quaternion state vector after fusion of measurements
  3. nextStates, ... % state vector after fusion of measurements
  4. nextP, ... % state covariance matrix after fusion of corrections
  5. innovation, ... % Declination innovation - rad
  6. varInnov] ... %
  7. = FuseMagnetometer( ...
  8. quat, ... % predicted quaternion states
  9. states, ... % predicted states
  10. P, ... % predicted covariance
  11. magData, ... % body frame magnetic flux measurements
  12. decl, ... % magnetic field declination from true north
  13. gPhi, gPsi, gTheta) % gimbal yaw, roll, pitch angles
  14. q0 = quat(1);
  15. q1 = quat(2);
  16. q2 = quat(3);
  17. q3 = quat(4);
  18. magX = magData(1);
  19. magY = magData(2);
  20. magZ = magData(3);
  21. R_MAG = 0.1745^2;
  22. % Calculate observation Jacobian
  23. H = calcH_MAG(gPhi,gPsi,gTheta,magX,magY,magZ,q0,q1,q2,q3);
  24. % Calculate innovation variance and Kalman gains
  25. % Take advantage of the fact that only the first 3 elements in H are non zero
  26. varInnov = (H(1,1:3)*P(1:3,1:3)*transpose(H(1,1:3)) + R_MAG);
  27. Kfusion = (P(:,1:3)*transpose(H(1,1:3)))/varInnov;
  28. % Calculate the innovation
  29. innovation = calcMagAng(decl,gPhi,gPsi,gTheta,magX,magY,magZ,q0,q1,q2,q3);
  30. if (innovation > pi)
  31. innovation = innovation - 2*pi;
  32. elseif (innovation < -pi)
  33. innovation = innovation + 2*pi;
  34. end
  35. if (innovation > 0.5)
  36. innovation = 0.5;
  37. elseif (innovation < -0.5)
  38. innovation = -0.5;
  39. end
  40. % correct the state vector
  41. states(1:3) = 0;
  42. states = states - Kfusion * innovation;
  43. % the first 3 states represent the angular misalignment vector. This is
  44. % is used to correct the estimate quaternion
  45. % Convert the error rotation vector to its equivalent quaternion
  46. % error = truth - estimate
  47. rotationMag = sqrt(states(1)^2 + states(2)^2 + states(3)^2);
  48. if rotationMag<1e-6
  49. deltaQuat = single([1;0;0;0]);
  50. else
  51. deltaQuat = [cos(0.5*rotationMag); [states(1);states(2);states(3)]/rotationMag*sin(0.5*rotationMag)];
  52. end
  53. % Update the quaternion states by rotating from the previous attitude through
  54. % the delta angle rotation quaternion
  55. nextQuat = [quat(1)*deltaQuat(1)-transpose(quat(2:4))*deltaQuat(2:4); quat(1)*deltaQuat(2:4) + deltaQuat(1)*quat(2:4) + cross(quat(2:4),deltaQuat(2:4))];
  56. % normalise the updated quaternion states
  57. quatMag = sqrt(nextQuat(1)^2 + nextQuat(2)^2 + nextQuat(3)^2 + nextQuat(4)^2);
  58. if (quatMag > 1e-6)
  59. nextQuat = nextQuat / quatMag;
  60. end
  61. % correct the covariance P = P - K*H*P
  62. % Take advantage of the fact that only the first 3 elements in H are non zero
  63. P = P - Kfusion*H(1,1:3)*P(1:3,:);
  64. % Force symmetry on the covariance matrix to prevent ill-conditioning
  65. % of the matrix which would cause the filter to blow-up
  66. P = 0.5*(P + transpose(P));
  67. % ensure diagonals are positive
  68. for i=1:9
  69. if P(i,i) < 0
  70. P(i,i) = 0;
  71. end
  72. end
  73. % Set default output for states and covariance
  74. nextP = P;
  75. nextStates = states;
  76. end