115 lines
3.6 KiB

  1. % === Problem 3a: Effect of Noise on Parameter Estimation ===
  2. clear; close all;
  3. % True system parameters
  4. m = 0.75;
  5. L = 1.25;
  6. c = 0.15;
  7. g = 9.81;
  8. mL2_true = m * L^2;
  9. mgL_true = m * g * L;
  10. theta_true = [mL2_true; c; mgL_true];
  11. % Load clean data
  12. data = readtable('output/problem1_data.csv');
  13. t = data.t;
  14. q_clean = data.q;
  15. u = data.u;
  16. Ts = t(2) - t(1);
  17. N = length(t);
  18. % Derivatives from clean q
  19. dq_clean = zeros(N,1);
  20. ddq_clean = zeros(N,1);
  21. for k = 2:N-1
  22. dq_clean(k) = (q_clean(k+1) - q_clean(k-1)) / (2*Ts);
  23. ddq_clean(k) = (q_clean(k+1) - 2*q_clean(k) + q_clean(k-1)) / Ts^2;
  24. end
  25. % LS estimation on clean data
  26. X_clean = [ddq_clean, dq_clean, q_clean];
  27. theta_hat_clean = (X_clean' * X_clean) \ (X_clean' * u);
  28. rel_error_clean = abs((theta_hat_clean - theta_true) ./ theta_true) * 100;
  29. % Reconstruct q̂_clean
  30. q_hat_clean = zeros(N, 1);
  31. dq_hat_clean = zeros(N, 1);
  32. q_hat_clean(1) = q_clean(1);
  33. dq_hat_clean(1) = dq_clean(1);
  34. for k = 2:N
  35. ddq_hat_clean_k = (1/theta_hat_clean(1)) * ...
  36. (u(k-1) - theta_hat_clean(2)*dq_clean(k-1) - theta_hat_clean(3)*q_clean(k-1));
  37. dq_hat_clean(k) = dq_hat_clean(k-1) + Ts * ddq_hat_clean_k;
  38. q_hat_clean(k) = q_hat_clean(k-1) + Ts * dq_hat_clean(k-1);
  39. end
  40. % === Loop over noise levels ===
  41. noise_levels = [0.001, 0.0025];
  42. for i = 1:length(noise_levels)
  43. noise_std = noise_levels(i);
  44. q_noisy = q_clean + noise_std * randn(size(q_clean));
  45. % Derivatives from noisy q
  46. dq_noisy = zeros(N,1);
  47. ddq_noisy = zeros(N,1);
  48. for k = 2:N-1
  49. dq_noisy(k) = (q_noisy(k+1) - q_noisy(k-1)) / (2*Ts);
  50. ddq_noisy(k) = (q_noisy(k+1) - 2*q_noisy(k) + q_noisy(k-1)) / Ts^2;
  51. end
  52. % LS estimation on noisy data
  53. X_noisy = [ddq_noisy, dq_noisy, q_noisy];
  54. theta_hat_noisy = (X_noisy' * X_noisy) \ (X_noisy' * u);
  55. rel_error_noisy = abs((theta_hat_noisy - theta_true) ./ theta_true) * 100;
  56. % Reconstruct q̂_noisy
  57. q_hat_noisy = zeros(N,1);
  58. dq_hat_noisy = zeros(N,1);
  59. q_hat_noisy(1) = q_noisy(1);
  60. dq_hat_noisy(1) = dq_noisy(1);
  61. for k = 2:N
  62. ddq_hat_noisy_k = (1/theta_hat_noisy(1)) * ...
  63. (u(k-1) - theta_hat_noisy(2)*dq_noisy(k-1) - theta_hat_noisy(3)*q_noisy(k-1));
  64. dq_hat_noisy(k) = dq_hat_noisy(k-1) + Ts * ddq_hat_noisy_k;
  65. q_hat_noisy(k) = q_hat_noisy(k-1) + Ts * dq_hat_noisy(k-1);
  66. end
  67. % Print results
  68. fprintf('\n--- Noise std = %.4f ---\n', noise_std);
  69. fprintf('Clean: mL2=%.4f (%.2f%%), c=%.4f (%.2f%%), mgL=%.4f (%.2f%%)\n', ...
  70. theta_hat_clean(1), rel_error_clean(1), ...
  71. theta_hat_clean(2), rel_error_clean(2), ...
  72. theta_hat_clean(3), rel_error_clean(3));
  73. fprintf('Noisy: mL2=%.4f (%.2f%%), c=%.4f (%.2f%%), mgL=%.4f (%.2f%%)\n', ...
  74. theta_hat_noisy(1), rel_error_noisy(1), ...
  75. theta_hat_noisy(2), rel_error_noisy(2), ...
  76. theta_hat_noisy(3), rel_error_noisy(3));
  77. % === Combined plot ===
  78. figure('Name', sprintf('Noise std = %.4f', noise_std), 'Position', [100, 100, 1000, 800]);
  79. subplot(2,1,1);
  80. plot(t, q_clean, 'b', ...
  81. t, q_hat_clean, 'g--', ...
  82. t, q_hat_noisy, 'r:');
  83. legend('Actual q(t)', 'Estimated (clean)', 'Estimated (noisy)');
  84. title(sprintf('Estimated Output (σ = %.4f)', noise_std));
  85. ylabel('q(t) [rad]');
  86. grid on;
  87. subplot(2,1,2);
  88. bar([rel_error_clean, rel_error_noisy]);
  89. set(gca, 'XTickLabel', {'mL^2', 'c', 'mgL'});
  90. legend({'No Noise', sprintf('With Noise (σ=%.4f)', noise_std)}, 'Location', 'northwest');
  91. ylabel('Relative Error [%]');
  92. title('Estimation Error');
  93. grid on;
  94. % Save figure
  95. filename = sprintf('output/Prob3a_NoiseStd%.4f.png', noise_std);
  96. saveas(gcf, filename);
  97. end