You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

125 lines
3.7 KiB

  1. %
  2. % Problem 1a: Gradient estimation for mass-spring-damper system (Exercise 1a)
  3. %
  4. clear
  5. % True system parameters
  6. m_true = 1.315;
  7. b_true = 0.225;
  8. k_true = 0.725;
  9. % Simulation parameters
  10. Ts = 0.001;
  11. T_total = 30;
  12. t = 0:Ts:T_total;
  13. N = length(t);
  14. % Gamma setup
  15. gamma = 0.33;
  16. use_normalization = true; % Set to false to disable normalization
  17. fprintf('Using gamma = %.4f\n', gamma);
  18. if use_normalization
  19. fprintf('Using normalized gradient update.\n');
  20. else
  21. fprintf('Using unnormalized gradient update.\n');
  22. end
  23. % Define both input cases
  24. input_cases = {...
  25. struct('name', 'constant', 'u', 2.5 * ones(1, N)), ...
  26. struct('name', 'sine', 'u', 2.5 * sin(t)) ...
  27. };
  28. fprintf('True m: %.4f, b: %.4f, k: %.4f\n', m_true, b_true, k_true);
  29. for case_idx = 1:length(input_cases)
  30. input_case = input_cases{case_idx};
  31. u = input_case.u;
  32. % Preallocate state variables
  33. x = zeros(1, N);
  34. dx = zeros(1, N);
  35. ddx = zeros(1, N);
  36. % Initial conditions
  37. x(1) = 0;
  38. dx(1) = 0;
  39. % Simulate true system using RK4
  40. for k = 1:N-1
  41. f = @(x_, dx_, u_) (1/m_true) * (u_ - b_true * dx_ - k_true * x_);
  42. k1 = f(x(k), dx(k), u(k));
  43. k2 = f(x(k) + Ts/2 * dx(k), dx(k) + Ts/2 * k1, u(k));
  44. k3 = f(x(k) + Ts/2 * dx(k), dx(k) + Ts/2 * k2, u(k));
  45. k4 = f(x(k) + Ts * dx(k), dx(k) + Ts * k3, u(k));
  46. ddx(k) = k1; % store first derivative (for later reuse)
  47. dx(k+1) = dx(k) + Ts/6 * (k1 + 2*k2 + 2*k3 + k4);
  48. x(k+1) = x(k) + Ts * dx(k);
  49. end
  50. % Approximate acceleration using finite differences
  51. ddx(1:end-1) = diff(dx) / Ts;
  52. ddx(end) = ddx(end-1); % replicate last value
  53. % Gradient estimation setup
  54. theta_hat = zeros(3, N); % rows: [m; b; k]
  55. theta_hat(:, 1) = [1; 1; 1]; % initial guesses
  56. % Run gradient estimator
  57. for k = 1:N-1
  58. u_vec = [ddx(k); dx(k); x(k)];
  59. y = u(k);
  60. y_hat = theta_hat(:, k)' * u_vec;
  61. e = y - y_hat;
  62. if use_normalization
  63. norm_factor = 1 + norm(u_vec)^2;
  64. theta_hat(:, k+1) = theta_hat(:, k) + Ts * gamma * (e / norm_factor) * u_vec;
  65. else
  66. theta_hat(:, k+1) = theta_hat(:, k) + Ts * gamma * e * u_vec;
  67. end
  68. end
  69. % Print final estimated values to console
  70. fprintf('\nFinal estimates for input: %s\n', input_case.name);
  71. fprintf('Estimated m: %.4f, b: %.4f, k: %.4f\n', theta_hat(1,end), theta_hat(2,end), theta_hat(3,end));
  72. % Plot estimated parameters
  73. figure('Name', ['Estimated Parameters - ' input_case.name], 'Position', [100, 100, 1280, 860]);
  74. normalization_text = ternary(use_normalization, 'Normalized', 'Unnormalized');
  75. sgtitle(sprintf('Input: %s | Gamma = %.3f | %s', input_case.name, gamma, normalization_text), 'FontWeight', 'bold');
  76. subplot(3,1,1);
  77. plot(t, theta_hat(1,:), 'b', 'LineWidth', 1.5);
  78. ylabel('$$\hat{m}(t)$$ [kg]', 'Interpreter', 'latex');
  79. grid on;
  80. title('Εκτίμηση μάζας');
  81. subplot(3,1,2);
  82. plot(t, theta_hat(2,:), 'r', 'LineWidth', 1.5);
  83. ylabel('$$\hat{b}(t)$$ [Ns/m]', 'Interpreter', 'latex');
  84. grid on;
  85. title('Εκτίμηση απόσβεσης');
  86. subplot(3,1,3);
  87. plot(t, theta_hat(3,:), 'k', 'LineWidth', 1.5);
  88. ylabel('$$\hat{k}(t)$$ [N/m]', 'Interpreter', 'latex');
  89. xlabel('t [sec]');
  90. grid on;
  91. title('Εκτίμηση ελαστικότητας');
  92. % Save figure
  93. if ~exist('output', 'dir')
  94. mkdir('output');
  95. end
  96. saveas(gcf, sprintf('output/Prob1a_estimation_%s_gamma%.3f_%s_%ds.png', input_case.name, gamma, normalization_text, T_total));
  97. end
  98. function out = ternary(cond, val_true, val_false)
  99. if cond
  100. out = val_true;
  101. else
  102. out = val_false;
  103. end
  104. end