ADS_cal_EKF.m 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. % Implementation of a simple 3-state EKF that can identify the scale
  2. % factor that needs to be applied to a true airspeed measurement
  3. % Paul Riseborough 27 June 2013
  4. % Inputs:
  5. % Measured true airsped (m/s)
  6. clear all;
  7. % Define wind speed used for truth model
  8. vwn_truth = 4.0;
  9. vwe_truth = 3.0;
  10. vwd_truth = -0.5; % convection can produce values of up to 1.5 m/s, however
  11. % average will zero over longer periods at lower altitudes
  12. % Slope lift will be persistent
  13. % Define airspeed scale factor used for truth model
  14. K_truth = 1.2;
  15. % Use a 1 second time step
  16. DT = 1.0;
  17. % Define the initial state error covariance matrix
  18. % Assume initial wind uncertainty of 10 m/s and scale factor uncertainty of
  19. % 0.2
  20. P = diag([10^2 10^2 0.001^2]);
  21. % Define state error growth matrix assuming wind changes at a rate of 0.1
  22. % m/s/s and scale factor drifts at a rate of 0.001 per second
  23. Q = diag([0.1^2 0.1^2 0.001^2])*DT^2;
  24. % Define the initial state matrix assuming zero wind and a scale factor of
  25. % 1.0
  26. x = [0;0;1.0];
  27. for i = 1:1000
  28. %% Calculate truth values
  29. % calculate ground velocity by simulating a wind relative
  30. % circular path of of 60m radius and 16 m/s airspeed
  31. time = i*DT;
  32. radius = 60;
  33. TAS_truth = 16;
  34. vwnrel_truth = TAS_truth*cos(TAS_truth*time/radius);
  35. vwerel_truth = TAS_truth*sin(TAS_truth*time/radius);
  36. vwdrel_truth = 0.0;
  37. vgn_truth = vwnrel_truth + vwn_truth;
  38. vge_truth = vwerel_truth + vwe_truth;
  39. vgd_truth = vwdrel_truth + vwd_truth;
  40. % calculate measured ground velocity and airspeed, adding some noise and
  41. % adding a scale factor to the airspeed measurement.
  42. vgn_mea = vgn_truth + 0.1*rand;
  43. vge_mea = vge_truth + 0.1*rand;
  44. vgd_mea = vgd_truth + 0.1*rand;
  45. TAS_mea = K_truth * TAS_truth + 0.5*rand;
  46. %% Perform filter processing
  47. % This benefits from a matrix library that can handle up to 3x3
  48. % matrices
  49. % Perform the covariance prediction
  50. % Q is a diagonal matrix so only need to add three terms in
  51. % C code implementation
  52. P = P + Q;
  53. % Perform the predicted measurement using the current state estimates
  54. % No state prediction required because states are assumed to be time
  55. % invariant plus process noise
  56. % Ignore vertical wind component
  57. TAS_pred = x(3) * sqrt((vgn_mea - x(1))^2 + (vge_mea - x(2))^2 + vgd_mea^2);
  58. % Calculate the observation Jacobian H_TAS
  59. SH1 = (vge_mea - x(2))^2 + (vgn_mea - x(1))^2;
  60. SH2 = 1/sqrt(SH1);
  61. H_TAS = zeros(1,3);
  62. H_TAS(1,1) = -(x(3)*SH2*(2*vgn_mea - 2*x(1)))/2;
  63. H_TAS(1,2) = -(x(3)*SH2*(2*vge_mea - 2*x(2)))/2;
  64. H_TAS(1,3) = 1/SH2;
  65. % Calculate the fusion innovaton covariance assuming a TAS measurement
  66. % noise of 1.0 m/s
  67. S = H_TAS*P*H_TAS' + 1.0; % [1 x 3] * [3 x 3] * [3 x 1] + [1 x 1]
  68. % Calculate the Kalman gain
  69. KG = P*H_TAS'/S; % [3 x 3] * [3 x 1] / [1 x 1]
  70. % Update the states
  71. x = x + KG*(TAS_mea - TAS_pred); % [3 x 1] + [3 x 1] * [1 x 1]
  72. % Update the covariance matrix
  73. P = P - KG*H_TAS*P; % [3 x 3] *
  74. % force symmetry on the covariance matrix - necessary due to rounding
  75. % errors
  76. % Implementation will also need a further check to prevent diagonal
  77. % terms becoming negative due to rounding errors
  78. % This step can be made more efficient by excluding diagonal terms
  79. % (would reduce processing by 1/3)
  80. P = 0.5*(P + P'); % [1 x 1] * ( [3 x 3] + [3 x 3])
  81. %% Store results
  82. output(i,:) = [time,x(1),x(2),x(3),vwn_truth,vwe_truth,K_truth];
  83. end
  84. %% Plot output
  85. figure;
  86. subplot(3,1,1);plot(output(:,1),[output(:,2),output(:,5)]);
  87. ylabel('Wind Vel North (m/s)');
  88. xlabel('time (sec)');
  89. grid on;
  90. subplot(3,1,2);plot(output(:,1),[output(:,3),output(:,6)]);
  91. ylabel('Wind Vel East (m/s)');
  92. xlabel('time (sec)');
  93. grid on;
  94. subplot(3,1,3);plot(output(:,1),[output(:,4),output(:,7)]);
  95. ylim([0 1.5]);
  96. ylabel('Airspeed scale factor correction');
  97. xlabel('time (sec)');
  98. grid on;