227 lines
6.3 KiB
Mathematica
227 lines
6.3 KiB
Mathematica
|
%% Clear Workspace and Close figures
|
||
|
clear; close all; clc;
|
||
|
|
||
|
%% Intialize Laplace variable
|
||
|
s = zpk('s');
|
||
|
|
||
|
addpath('./mat/');
|
||
|
|
||
|
% Load Data
|
||
|
% The experimental data is loaded and any offset is removed.
|
||
|
|
||
|
id_ol = load('identification_noise_bis.mat', 'd', 'acc_1', 'acc_2', 'geo_1', 'geo_2', 'f_meas', 'u', 't');
|
||
|
|
||
|
id_ol.d = detrend(id_ol.d, 0);
|
||
|
id_ol.acc_1 = detrend(id_ol.acc_1, 0);
|
||
|
id_ol.acc_2 = detrend(id_ol.acc_2, 0);
|
||
|
id_ol.geo_1 = detrend(id_ol.geo_1, 0);
|
||
|
id_ol.geo_2 = detrend(id_ol.geo_2, 0);
|
||
|
id_ol.f_meas = detrend(id_ol.f_meas, 0);
|
||
|
id_ol.u = detrend(id_ol.u, 0);
|
||
|
|
||
|
% Experimental Data
|
||
|
% The transfer function from force actuator to force sensors is estimated.
|
||
|
|
||
|
% The coherence shown in Figure [[fig:iff_identification_coh]] shows that the excitation signal is good enough.
|
||
|
|
||
|
|
||
|
Ts = id_ol.t(2) - id_ol.t(1);
|
||
|
win = hann(ceil(10/Ts));
|
||
|
|
||
|
[tf_fmeas_est, f] = tfestimate(id_ol.u, id_ol.f_meas, win, [], [], 1/Ts); % [V/m]
|
||
|
[co_fmeas_est, ~] = mscohere( id_ol.u, id_ol.f_meas, win, [], [], 1/Ts);
|
||
|
|
||
|
figure;
|
||
|
hold on;
|
||
|
plot(f, co_fmeas_est, '-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||
|
ylabel('Coherence'); xlabel('Frequency [Hz]');
|
||
|
hold off;
|
||
|
xlim([1, 1e3]); ylim([0, 1])
|
||
|
|
||
|
|
||
|
|
||
|
% #+name: fig:iff_identification_coh
|
||
|
% #+caption: Coherence for the identification of the IFF plant
|
||
|
% #+RESULTS:
|
||
|
% [[file:figs/iff_identification_coh.png]]
|
||
|
|
||
|
% The obtained dynamics is shown in Figure [[fig:iff_identification_bode_plot]].
|
||
|
|
||
|
|
||
|
figure;
|
||
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||
|
|
||
|
ax1 = nexttile([2,1]);
|
||
|
hold on;
|
||
|
plot(f, abs(tf_fmeas_est), '-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||
|
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
|
||
|
hold off;
|
||
|
ylim([1e-1, 1e3]);
|
||
|
|
||
|
ax2 = nexttile;
|
||
|
hold on;
|
||
|
plot(f, 180/pi*angle(tf_fmeas_est), '-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||
|
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||
|
hold off;
|
||
|
ylim([-180, 180]);
|
||
|
yticks([-180, -90, 0, 90, 180]);
|
||
|
|
||
|
linkaxes([ax1,ax2], 'x');
|
||
|
xlim([1, 1e3]);
|
||
|
|
||
|
% Model of the IFF Plant
|
||
|
% In order to plot the root locus for the IFF control strategy, a model of the identified plant is developed.
|
||
|
|
||
|
% It consists of several poles and zeros are shown below.
|
||
|
|
||
|
wz = 2*pi*102;
|
||
|
xi_z = 0.01;
|
||
|
wp = 2*pi*239.4;
|
||
|
xi_p = 0.015;
|
||
|
|
||
|
Giff = 2.2*(s^2 + 2*xi_z*s*wz + wz^2)/(s^2 + 2*xi_p*s*wp + wp^2) * ... % Dynamics
|
||
|
10*(s/3/pi/(1 + s/3/pi)) * ... % Low pass filter and gain of the voltage amplifier
|
||
|
exp(-Ts*s); % Time delay induced by ADC/DAC
|
||
|
|
||
|
|
||
|
|
||
|
% The comparison of the identified dynamics and the developed model is done in Figure [[fig:iff_plant_model]].
|
||
|
|
||
|
|
||
|
figure;
|
||
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||
|
|
||
|
ax1 = nexttile([2,1]);
|
||
|
hold on;
|
||
|
plot(f, abs(tf_fmeas_est), '.')
|
||
|
plot(f, abs(squeeze(freqresp(Giff, f, 'Hz'))), 'k-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||
|
ylabel('Amplitude [V/V]'); set(gca, 'XTickLabel',[]);
|
||
|
hold off;
|
||
|
ylim([1e-2, 1e3])
|
||
|
|
||
|
ax2 = nexttile;
|
||
|
hold on;
|
||
|
plot(f, 180/pi*angle(tf_fmeas_est), '.')
|
||
|
plot(f, 180/pi*angle(squeeze(freqresp(Giff, f, 'Hz'))), 'k-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||
|
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||
|
hold off;
|
||
|
ylim([-180, 180]);
|
||
|
yticks([-180, -90, 0, 90, 180]);
|
||
|
|
||
|
linkaxes([ax1,ax2], 'x');
|
||
|
xlim([0.5, 5e3]);
|
||
|
|
||
|
% Root Locus and optimal Controller
|
||
|
% Now, the root locus for the Integral Force Feedback strategy is computed and shown in Figure [[fig:iff_root_locus]].
|
||
|
|
||
|
% Note that the controller used is not a pure integrator but rather a first order low pass filter with a cut-off frequency set at 2Hz.
|
||
|
|
||
|
|
||
|
gains = logspace(0, 5, 1000);
|
||
|
|
||
|
figure;
|
||
|
hold on;
|
||
|
plot(real(pole(Giff)), imag(pole(Giff)), 'kx');
|
||
|
plot(real(tzero(Giff)), imag(tzero(Giff)), 'ko');
|
||
|
for i = 1:length(gains)
|
||
|
cl_poles = pole(feedback(Giff, gains(i)/(s + 2*pi*2)));
|
||
|
plot(real(cl_poles), imag(cl_poles), 'k.');
|
||
|
end
|
||
|
cl_poles = pole(feedback(Giff, 102/(s + 2*pi*2)));
|
||
|
plot(real(cl_poles), imag(cl_poles), 'rx');
|
||
|
ylim([0, 1800]);
|
||
|
xlim([-1600,200]);
|
||
|
xlabel('Real Part')
|
||
|
ylabel('Imaginary Part')
|
||
|
axis square
|
||
|
|
||
|
|
||
|
|
||
|
% #+name: fig:iff_root_locus
|
||
|
% #+caption: Root Locus for the IFF control
|
||
|
% #+RESULTS:
|
||
|
% [[file:figs/iff_root_locus.png]]
|
||
|
|
||
|
% The controller that yield maximum damping (shown by the red cross in Figure [[fig:iff_root_locus]]) is:
|
||
|
|
||
|
Kiff_opt = 102/(s + 2*pi*2);
|
||
|
|
||
|
% Verification of the achievable damping
|
||
|
% A new identification is performed with the IFF control strategy applied to the system.
|
||
|
|
||
|
% Data is loaded and offset removed.
|
||
|
|
||
|
id_cl = load('identification_noise_iff_bis.mat', 'd', 'acc_1', 'acc_2', 'geo_1', 'geo_2', 'f_meas', 'u', 't');
|
||
|
|
||
|
id_cl.d = detrend(id_cl.d, 0);
|
||
|
id_cl.acc_1 = detrend(id_cl.acc_1, 0);
|
||
|
id_cl.acc_2 = detrend(id_cl.acc_2, 0);
|
||
|
id_cl.geo_1 = detrend(id_cl.geo_1, 0);
|
||
|
id_cl.geo_2 = detrend(id_cl.geo_2, 0);
|
||
|
id_cl.f_meas = detrend(id_cl.f_meas, 0);
|
||
|
id_cl.u = detrend(id_cl.u, 0);
|
||
|
|
||
|
|
||
|
|
||
|
% The open-loop and closed-loop dynamics are estimated.
|
||
|
|
||
|
[tf_G_ol_est, f] = tfestimate(id_ol.u, id_ol.d, win, [], [], 1/Ts);
|
||
|
[co_G_ol_est, ~] = mscohere( id_ol.u, id_ol.d, win, [], [], 1/Ts);
|
||
|
[tf_G_cl_est, ~] = tfestimate(id_cl.u, id_cl.d, win, [], [], 1/Ts);
|
||
|
[co_G_cl_est, ~] = mscohere( id_cl.u, id_cl.d, win, [], [], 1/Ts);
|
||
|
|
||
|
|
||
|
|
||
|
% The obtained coherence is shown in Figure [[fig:Gd_identification_iff_coherence]] and the dynamics in Figure [[fig:Gd_identification_iff_bode_plot]].
|
||
|
|
||
|
|
||
|
figure;
|
||
|
hold on;
|
||
|
plot(f, co_G_ol_est, '-', 'DisplayName', 'OL')
|
||
|
plot(f, co_G_cl_est, '-', 'DisplayName', 'IFF')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||
|
ylabel('Coherence'); xlabel('Frequency [Hz]');
|
||
|
hold off;
|
||
|
xlim([1, 1e3]); ylim([0, 1])
|
||
|
legend('location', 'southwest');
|
||
|
|
||
|
|
||
|
|
||
|
% #+name: fig:Gd_identification_iff_coherence
|
||
|
% #+caption: Coherence for the transfer function from F to d, with and without IFF
|
||
|
% #+RESULTS:
|
||
|
% [[file:figs/Gd_identification_iff_coherence.png]]
|
||
|
|
||
|
|
||
|
|
||
|
figure;
|
||
|
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');
|
||
|
|
||
|
ax1 = nexttile([2,1]);
|
||
|
hold on;
|
||
|
plot(f, abs(tf_G_ol_est), '-', 'DisplayName', 'OL')
|
||
|
plot(f, abs(tf_G_cl_est), '-', 'DisplayName', 'IFF')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
|
||
|
ylabel('Amplitude [m/V]'); set(gca, 'XTickLabel',[]);
|
||
|
hold off;
|
||
|
legend('location', 'northeast');
|
||
|
ylim([2e-7, 2e-4]);
|
||
|
|
||
|
ax2 = nexttile;
|
||
|
hold on;
|
||
|
plot(f, 180/pi*angle(tf_G_ol_est), '-')
|
||
|
plot(f, 180/pi*angle(tf_G_cl_est), '-')
|
||
|
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'lin');
|
||
|
ylabel('Phase'); xlabel('Frequency [Hz]');
|
||
|
hold off;
|
||
|
ylim([-180, 180]);
|
||
|
yticks([-180, -90, 0, 90, 180]);
|
||
|
|
||
|
linkaxes([ax1,ax2], 'x');
|
||
|
xlim([1, 1e3]);
|