Finish report
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
%% Controller
|
||||
s = tf('s');
|
||||
K = 4.5724e11*(s+44.46)/((s+8.127e-08)*(s+0.0002334)*(s+384.9));
|
||||
|
||||
%% Open Simulink for Control
|
||||
open rotating_frame_ctrl.slx
|
||||
|
||||
sim rotating_frame_ctrl.slx
|
||||
|
||||
%%
|
||||
figure;
|
||||
hold on;
|
||||
plot(sim_out.Time, sim_out.Data(:, 1));
|
||||
plot(sim_out.Time, sim_out.Data(:, 2));
|
||||
hold off;
|
||||
xlabel('Time (s)');
|
||||
ylabel('Displacement (m)');
|
||||
legend({'Dx', 'Dy'});
|
||||
|
||||
exportFig('D_x_y', 'wide-tall');
|
||||
|
@@ -1,52 +0,0 @@
|
||||
%% Open Simulink file
|
||||
open rotating_frame.slx
|
||||
|
||||
%% Options for Linearized
|
||||
options = linearizeOptions;
|
||||
options.SampleTime = 0;
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fx'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fy'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/dx'], 1, 'output');
|
||||
io(4) = linio([mdl, '/dy'], 1, 'output');
|
||||
|
||||
%% Run the linearization
|
||||
angle_e = 0; rot_speed = 0;
|
||||
G = linearize(mdl, io, 0);
|
||||
|
||||
%% Input/Output names
|
||||
G.InputName = {'Fx', 'Fy'};
|
||||
G.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
%% Run the linearization
|
||||
angle_e = 0; rot_speed = 2*pi;
|
||||
Gr = linearize(mdl, io, 0);
|
||||
|
||||
%% Input/Output names
|
||||
Gr.InputName = {'Fx', 'Fy'};
|
||||
Gr.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
|
||||
%% Run the linearization
|
||||
angle_e = 1*2*pi/180; rot_speed = 2*pi;
|
||||
Ge = linearize(mdl, io, 0);
|
||||
|
||||
%% Input/Output names
|
||||
Ge.InputName = {'Fx', 'Fy'};
|
||||
Ge.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
%%
|
||||
f = figure('visible', 'off');
|
||||
bode(G);
|
||||
exportFig('G_x_y', 'wide-tall');
|
||||
close(f);
|
||||
|
||||
figure;
|
||||
bode(Ge);
|
||||
% exportFig('G_x_y_e', 'normal-normal');
|
||||
|
@@ -1,44 +0,0 @@
|
||||
%% Open Simulink file
|
||||
open rotating_frame.slx
|
||||
|
||||
%% Options for Linearized
|
||||
options = linearizeOptions;
|
||||
options.SampleTime = 0;
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fu'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fv'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/dx'], 1, 'output');
|
||||
io(4) = linio([mdl, '/dy'], 1, 'output');
|
||||
|
||||
%% Run the linearization
|
||||
rot_speed = 2*pi;
|
||||
G = linearize(mdl, io, 0.0);
|
||||
|
||||
%% Input/Output names
|
||||
G.InputName = {'Fu', 'Fv'};
|
||||
G.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
%% Run the linearization
|
||||
G1 = linearize(mdl, io, 0.4);
|
||||
|
||||
%% Input/Output names
|
||||
G1.InputName = {'Fu', 'Fv'};
|
||||
G1.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
%% Run the linearization
|
||||
G2 = linearize(mdl, io, 0.8);
|
||||
|
||||
%% Input/Output names
|
||||
G2.InputName = {'Fu', 'Fv'};
|
||||
G2.OutputName = {'Dx', 'Dy'};
|
||||
|
||||
figure;
|
||||
bode(G, G1, G2);
|
||||
exportFig('G_u_v_to_x_y', 'wide-tall');
|
||||
|
||||
|
@@ -1,46 +0,0 @@
|
||||
%% Open Simulink file
|
||||
open rotating_frame.slx
|
||||
|
||||
%% Options for Linearized
|
||||
options = linearizeOptions;
|
||||
options.SampleTime = 0;
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fu'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fv'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/du'], 1, 'output');
|
||||
io(4) = linio([mdl, '/dv'], 1, 'output');
|
||||
|
||||
%% Run the linearization
|
||||
rot_speed = 0;
|
||||
G = linearize(mdl, io, 0.0);
|
||||
|
||||
%% Input/Output names
|
||||
G.InputName = {'Fu', 'Fv'};
|
||||
G.OutputName = {'Du', 'Dv'};
|
||||
|
||||
%% Run the linearization
|
||||
rot_speed = 2*pi/60;
|
||||
G1 = linearize(mdl, io, 0.0);
|
||||
|
||||
%% Input/Output names
|
||||
G1.InputName = {'Fu', 'Fv'};
|
||||
G1.OutputName = {'Du', 'Dv'};
|
||||
|
||||
%% Run the linearization
|
||||
rot_speed = 2*pi;
|
||||
G2 = linearize(mdl, io, 0.0);
|
||||
|
||||
%% Input/Output names
|
||||
G2.InputName = {'Fu', 'Fv'};
|
||||
G2.OutputName = {'Du', 'Dv'};
|
||||
|
||||
figure;
|
||||
bode(G, G1, G2);
|
||||
legend({'$\omega = 0$', '$\omega = 2pi/60$', '$\omega = 2pi$'})
|
||||
exportFig('G_u_v', 'normal-normal');
|
||||
|
BIN
matlab/mat/nass_controllers.mat
Normal file
BIN
matlab/mat/nass_controllers.mat
Normal file
Binary file not shown.
Binary file not shown.
BIN
matlab/mat/rotating_generic_plants.mat
Normal file
BIN
matlab/mat/rotating_generic_plants.mat
Normal file
Binary file not shown.
BIN
matlab/mat/rotating_nass_plants.mat
Normal file
BIN
matlab/mat/rotating_nass_plants.mat
Normal file
Binary file not shown.
BIN
matlab/mat/uniaxial_micro_station_parameters.mat
Normal file
BIN
matlab/mat/uniaxial_micro_station_parameters.mat
Normal file
Binary file not shown.
BIN
matlab/nass_rotating_model.slx
Normal file
BIN
matlab/nass_rotating_model.slx
Normal file
Binary file not shown.
220
matlab/rotating_1_system_description.m
Normal file
220
matlab/rotating_1_system_description.m
Normal file
@@ -0,0 +1,220 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
% System Poles: Campbell Diagram
|
||||
% The poles of $\mathbf{G}_d$ are the complex solutions $p$ of equation eqref:eq:poles.
|
||||
|
||||
% #+name: eq:poles
|
||||
% \begin{equation}
|
||||
% \left( \frac{p^2}{{\omega_0}^2} + 2 \xi \frac{p}{\omega_0} + 1 - \frac{{\Omega}^2}{{\omega_0}^2} \right)^2 + \left( 2 \frac{\Omega}{\omega_0} \frac{p}{\omega_0} \right)^2 = 0
|
||||
% \end{equation}
|
||||
|
||||
% Supposing small damping ($\xi \ll 1$), two pairs of complex conjugate poles are obtained as shown in equation eqref:eq:pole_values.
|
||||
|
||||
% #+name: eq:pole_values
|
||||
% \begin{subequations}
|
||||
% \begin{align}
|
||||
% p_{+} &= - \xi \omega_0 \left( 1 + \frac{\Omega}{\omega_0} \right) \pm j \omega_0 \left( 1 + \frac{\Omega}{\omega_0} \right) \\
|
||||
% p_{-} &= - \xi \omega_0 \left( 1 - \frac{\Omega}{\omega_0} \right) \pm j \omega_0 \left( 1 - \frac{\Omega}{\omega_0} \right)
|
||||
% \end{align}
|
||||
% \end{subequations}
|
||||
|
||||
|
||||
%% Model parameters for first analysis
|
||||
kn = 1; % Actuator Stiffness [N/m]
|
||||
mn = 1; % Payload Mass [kg]
|
||||
cn = 0.05; % Actuator Damping [N/(m/s)]
|
||||
|
||||
xin = cn/(2*sqrt(kn*mn)); % Modal Damping [-]
|
||||
w0n = sqrt(kn/mn); % Natural Frequency [rad/s]
|
||||
|
||||
%% Computation of the poles as a function of the rotating velocity
|
||||
Wzs = linspace(0, 2, 51); % Vector of rotation speeds [rad/s]
|
||||
|
||||
p_ws = zeros(4, length(Wzs));
|
||||
|
||||
for i = 1:length(Wzs)
|
||||
Wz = Wzs(i);
|
||||
|
||||
pole_G = pole(1/(((s^2)/(w0n^2) + 2*xin*s/w0n + 1 - (Wz^2)/(w0n^2))^2 + (2*Wz*s/(w0n^2))^2));
|
||||
[~, i_sort] = sort(imag(pole_G));
|
||||
p_ws(:, i) = pole_G(i_sort);
|
||||
end
|
||||
|
||||
clear pole_G;
|
||||
|
||||
|
||||
|
||||
% The real and complex parts of these two pairs of complex conjugate poles are represented in Figure ref:fig:rotating_campbell_diagram as a function of the rotational speed $\Omega$.
|
||||
% As the rotational speed increases, $p_{+}$ goes to higher frequencies and $p_{-}$ goes to lower frequencies.
|
||||
% The system becomes unstable for $\Omega > \omega_0$ as the real part of $p_{-}$ is positive.
|
||||
% Physically, the negative stiffness term $-m\Omega^2$ induced by centrifugal forces exceeds the spring stiffness $k$.
|
||||
|
||||
|
||||
%% Campbell diagram - Real and Imaginary parts of the poles as a function of the rotating velocity
|
||||
figure;
|
||||
tiledlayout(1, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(Wzs, real(p_ws(1, :)), '-', 'color', colors(1,:), 'DisplayName', '$p_{+}$')
|
||||
plot(Wzs, real(p_ws(4, :)), '-', 'color', colors(1,:), 'HandleVisibility', 'off')
|
||||
plot(Wzs, real(p_ws(2, :)), '-', 'color', colors(2,:), 'DisplayName', '$p_{-}$')
|
||||
plot(Wzs, real(p_ws(3, :)), '-', 'color', colors(2,:), 'HandleVisibility', 'off')
|
||||
plot(Wzs, zeros(size(Wzs)), 'k--', 'HandleVisibility', 'off')
|
||||
hold off;
|
||||
xlabel('Rotational Speed $\Omega$'); ylabel('Real Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
||||
xlim([0, 2*w0n]);
|
||||
xticks([0,w0n/2,w0n,3/2*w0n,2*w0n])
|
||||
xticklabels({'$0$', '', '$\omega_0$', '', '$2 \omega_0$'})
|
||||
ylim([-3*xin, 3*xin]);
|
||||
yticks([-3*xin, -2*xin, -xin, 0, xin, 2*xin, 3*xin])
|
||||
yticklabels({'', '', '$-\xi\omega_0$', '$0$', ''})
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(Wzs, imag(p_ws(1, :)), '-', 'color', colors(1,:))
|
||||
plot(Wzs, imag(p_ws(4, :)), '-', 'color', colors(1,:))
|
||||
plot(Wzs, imag(p_ws(2, :)), '-', 'color', colors(2,:))
|
||||
plot(Wzs, imag(p_ws(3, :)), '-', 'color', colors(2,:))
|
||||
plot(Wzs, zeros(size(Wzs)), 'k--')
|
||||
hold off;
|
||||
xlabel('Rotational Speed $\Omega$'); ylabel('Imaginary Part');
|
||||
xlim([0, 2*w0n]);
|
||||
xticks([0,w0n/2,w0n,3/2*w0n,2*w0n])
|
||||
xticklabels({'$0$', '', '$\omega_0$', '', '$2 \omega_0$'})
|
||||
ylim([-3*w0n, 3*w0n]);
|
||||
yticks([-3*w0n, -2*w0n, -w0n, 0, w0n, 2*w0n, 3*w0n])
|
||||
yticklabels({'', '', '$-\omega_0$', '$0$', '$\omega_0$', '', ''})
|
||||
|
||||
% Identify Generic Dynamics :noexport:
|
||||
|
||||
%% Sample
|
||||
ms = 0.5; % Sample mass [kg]
|
||||
|
||||
%% Tuv Stage
|
||||
kn = 1; % Stiffness [N/m]
|
||||
mn = 0.5; % Tuv mass [kg]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
%% General Configuration
|
||||
model_config = struct();
|
||||
model_config.controller = "open_loop"; % Default: Open-Loop
|
||||
model_config.Tuv_type = "normal"; % Default: 2DoF stage
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % [Fu, Fv]
|
||||
io(io_i) = linio([mdl, '/fd'], 1, 'openinput'); io_i = io_i + 1; % [Fdu, Fdv]
|
||||
io(io_i) = linio([mdl, '/xf'], 1, 'openinput'); io_i = io_i + 1; % [Dfx, Dfy]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 1, 'openoutput'); io_i = io_i + 1; % [Fmu, Fmv]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 2, 'openoutput'); io_i = io_i + 1; % [Du, Dv]
|
||||
io(io_i) = linio([mdl, '/ext_metrology'], 1, 'openoutput'); io_i = io_i + 1; % [Dx, Dy]
|
||||
|
||||
%% Tested rotating velocities [rad/s]
|
||||
Wzs = [0, 0.1, 0.2, 0.7, 1.2]; % Vector of rotation speeds [rad/s]
|
||||
|
||||
Gs = {zeros(2, 2, length(Wzs))}; % Direct terms
|
||||
|
||||
for i = 1:length(Wzs)
|
||||
Wz = Wzs(i);
|
||||
|
||||
%% Linearize the model
|
||||
G = linearize(mdl, io, 0);
|
||||
|
||||
%% Input/Output definition
|
||||
G.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
|
||||
G.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Gs{:,:,i} = G;
|
||||
end
|
||||
|
||||
%% Save All Identified Plants
|
||||
save('./mat/rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% System Dynamics: Effect of rotation
|
||||
% The system dynamics from actuator forces $[F_u, F_v]$ to the relative motion $[d_u, d_v]$ is identified for several rotating velocities.
|
||||
|
||||
% Looking at the transfer function matrix $\mathbf{G}_d$ in equation eqref:eq:Gd_w0_xi_k, one can see that the two diagonal (direct) terms are equal and that the two off-diagonal (coupling) terms are opposite.
|
||||
% The bode plot of these two terms are shown in Figure ref:fig:rotating_direct_coupling_bode_plot for several rotational speeds $\Omega$.
|
||||
% These plots confirm the expected behavior: the frequency of the two pairs of complex conjugate poles are further separated as $\Omega$ increases.
|
||||
% For $\Omega > \omega_0$, the low frequency pair of complex conjugate poles $p_{-}$ becomes unstable.
|
||||
|
||||
|
||||
%% Bode plot of the direct and coupling terms for several rotating velocities
|
||||
freqs = logspace(-1, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
title('Direct terms: $d_u/F_u$, $d_v/F_v$');
|
||||
ylim([1e-2, 1e2]);
|
||||
yticks([1e-2,1e-1,1,1e1,1e2])
|
||||
yticklabels({'$0.01/k$', '$0.1/k$', '$1/k$', '$10/k$', '$100/k$'})
|
||||
|
||||
ax2 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:), ...
|
||||
'DisplayName', sprintf('$\\Omega = %.1f \\omega_0$', Wzs(i)))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
title('Coupling Terms: $d_u/F_v$, $d_v/F_u$');
|
||||
ldg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [10, 1];
|
||||
ylim([1e-2, 1e2]);
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-1,1,1e1])
|
||||
xticklabels({'$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:));
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1,1,1e1])
|
||||
xticklabels({'$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2,ax3,ax4],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
linkaxes([ax1,ax2],'y');
|
152
matlab/rotating_2_iff_pure_int.m
Normal file
152
matlab/rotating_2_iff_pure_int.m
Normal file
@@ -0,0 +1,152 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
%% Load "Generic" system dynamics
|
||||
load('rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% Effect of the rotation speed on the IFF plant dynamics
|
||||
% The transfer functions from actuator forces $[F_u,\ F_v]$ to the measured force sensors $[f_u,\ f_v]$ are identified for several rotating velocities and shown in Figure ref:fig:rotating_iff_bode_plot_effect_rot.
|
||||
|
||||
% As was expected from the derived equations of motion:
|
||||
% - when $0 < \Omega < \omega_0$: the low frequency gain is no longer zero and two (non-minimum phase) real zero appears at low frequency.
|
||||
% The low frequency gain increases with $\Omega$.
|
||||
% A pair of (minimum phase) complex conjugate zeros appears between the two complex conjugate poles that are split further apart as $\Omega$ increases.
|
||||
% - when $\omega_0 < \Omega$: the low frequency pole becomes unstable.
|
||||
|
||||
|
||||
%% Bode plot of the direct and coupling term for Integral Force Feedback - Effect of rotation
|
||||
figure;
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('fu', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [N/N]');
|
||||
title('Direct terms: $f_u/F_u$, $f_v/F_v$');
|
||||
ylim([1e-3, 1e2]);
|
||||
|
||||
ax2 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('fv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:), ...
|
||||
'DisplayName', sprintf('$\\Omega = %.1f \\omega_0$', Wzs(i)))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
title('Coupling Terms: $f_u/F_v$, $f_v/F_u$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [10, 1];
|
||||
ylim([1e-3, 1e2]);
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('fu', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('fv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:));
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); set(gca, 'YTickLabel',[]);
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2,ax3,ax4],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
linkaxes([ax1,ax2],'y');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_diagram
|
||||
% #+caption: Control diagram for decentralized Integral Force Feedback
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_diagram.png]]
|
||||
|
||||
% The decentralized IFF controller $\bm{K}_F$ corresponds to a diagonal controller with integrators:
|
||||
% #+name: eq:Kf_pure_int
|
||||
% \begin{equation}
|
||||
% \begin{aligned}
|
||||
% \mathbf{K}_{F}(s) &= \begin{bmatrix} K_{F}(s) & 0 \\ 0 & K_{F}(s) \end{bmatrix} \\
|
||||
% K_{F}(s) &= g \cdot \frac{1}{s}
|
||||
% \end{aligned}
|
||||
% \end{equation}
|
||||
|
||||
% In order to see how the IFF controller affects the poles of the closed loop system, a Root Locus plot (Figure ref:fig:rotating_root_locus_iff_pure_int) is constructed as follows: the poles of the closed-loop system are drawn in the complex plane as the controller gain $g$ varies from $0$ to $\infty$ for the two controllers $K_{F}$ simultaneously.
|
||||
% As explained in cite:preumont08_trans_zeros_struc_contr_with,skogestad07_multiv_feedb_contr, the closed-loop poles start at the open-loop poles (shown by $\tikz[baseline=-0.6ex] \node[cross out, draw=black, minimum size=1ex, line width=2pt, inner sep=0pt, outer sep=0pt] at (0, 0){};$) for $g = 0$ and coincide with the transmission zeros (shown by $\tikz[baseline=-0.6ex] \draw[line width=2pt, inner sep=0pt, outer sep=0pt] (0,0) circle[radius=3pt];$) as $g \to \infty$.
|
||||
|
||||
% #+begin_important
|
||||
% Whereas collocated IFF is usually associated with unconditional stability cite:preumont91_activ, this property is lost due to gyroscopic effects as soon as the rotation velocity in non-null.
|
||||
% This can be seen in the Root Locus plot (Figure ref:fig:rotating_root_locus_iff_pure_int) where poles corresponding to the controller are bound to the right half plane implying closed-loop system instability.
|
||||
% #+end_important
|
||||
|
||||
% Physically, this can be explained like so: at low frequency, the loop gain is very large due to the pure integrator in $K_{F}$ and the finite gain of the plant (Figure ref:fig:rotating_iff_bode_plot_effect_rot).
|
||||
% The control system is thus canceling the spring forces which makes the suspended platform no able to hold the payload against centrifugal forces, hence the instability.
|
||||
|
||||
|
||||
%% Root Locus for the Decentralized Integral Force Feedback controller
|
||||
figure;
|
||||
|
||||
Kiff = 1/s*eye(2);
|
||||
|
||||
gains = logspace(-2, 4, 300);
|
||||
Wz_i = [1,3,4];
|
||||
|
||||
hold on;
|
||||
for i = 1:length(Wz_i)
|
||||
plot(real(pole(Gs{Wz_i(i)}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), imag(pole(Gs{Wz_i(i)}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), 'x', 'color', colors(i,:), ...
|
||||
'DisplayName', sprintf('$\\Omega = %.1f \\omega_0 $', Wzs(Wz_i(i))),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i(i)}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), imag(tzero(Gs{Wz_i(i)}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), 'o', 'color', colors(i,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(Gs{Wz_i(i)}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff, -1));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(i,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-1.8, 0.2]); ylim([0, 2]);
|
||||
xticks([-1, 0])
|
||||
xticklabels({'-$\omega_0$', '$0$'})
|
||||
yticks([0, 1, 2])
|
||||
yticklabels({'$0$', '$\omega_0$', '$2 \omega_0$'})
|
||||
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
474
matlab/rotating_3_iff_hpf.m
Normal file
474
matlab/rotating_3_iff_hpf.m
Normal file
@@ -0,0 +1,474 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
%% Load "Generic" system dynamics
|
||||
load('rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% Modified Integral Force Feedback Controller
|
||||
% The Integral Force Feedback Controller is modified such that instead of using pure integrators, pseudo integrators (i.e. low pass filters) are used:
|
||||
% \begin{equation}
|
||||
% K_{\text{IFF}}(s) = g\frac{1}{\omega_i + s} \begin{bmatrix}
|
||||
% 1 & 0 \\
|
||||
% 0 & 1
|
||||
% \end{bmatrix}
|
||||
% \end{equation}
|
||||
% where $\omega_i$ characterize down to which frequency the signal is integrated.
|
||||
|
||||
% Let's arbitrary choose the following control parameters:
|
||||
|
||||
%% Modified IFF - parameters
|
||||
g = 2; % Controller gain
|
||||
wi = 0.1; % HPF Cut-Off frequency [rad/s]
|
||||
|
||||
Kiff = (g/s)*eye(2); % Pure IFF
|
||||
Kiff_hpf = (g/(wi+s))*eye(2); % IFF with added HPF
|
||||
|
||||
|
||||
|
||||
% The loop gains ($K_F(s)$ times the direct dynamics $f_u/F_u$) with and without the added HPF are shown in Figure ref:fig:rotating_iff_modified_loop_gain.
|
||||
% The effect of the added HPF limits the low frequency gain to finite values as expected.
|
||||
|
||||
|
||||
%% Loop gain for the IFF with pure integrator and modified IFF with added high pass filter
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
Wz_i = 2;
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{Wz_i}('fu', 'Fu')*Kiff(1,1), freqs, 'rad/s'))))
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{Wz_i}('fu', 'Fu')*Kiff_hpf(1,1), freqs, 'rad/s'))))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Loop Gain');
|
||||
|
||||
% Phase
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{Wz_i}('fu', 'Fu')*Kiff(1,1), freqs, 'rad/s'))), 'DisplayName', 'IFF')
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{Wz_i}('fu', 'Fu')*Kiff_hpf(1,1), freqs, 'rad/s'))), 'DisplayName', 'IFF + HPF')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
leg = legend('location', 'southwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 20;
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_modified_loop_gain
|
||||
% #+caption: Loop gain for the IFF with pure integrator and modified IFF with added high pass filter ($\Omega = 0.1\omega_0$)
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_modified_loop_gain.png]]
|
||||
|
||||
% The Root Locus plots for the decentralized IFF with and without the HPF are displayed in Figure ref:fig:rotating_iff_root_locus_hpf.
|
||||
% With the added HPF, the poles of the closed loop system are shown to be *stable up to some value of the gain* $g_\text{max}$ given by equation eqref:eq:gmax_iff_hpf.
|
||||
|
||||
% #+name: eq:gmax_iff_hpf
|
||||
% \begin{equation}
|
||||
% \boxed{g_{\text{max}} = \omega_i \left( \frac{{\omega_0}^2}{\Omega^2} - 1 \right)}
|
||||
% \end{equation}
|
||||
|
||||
% It is interesting to note that $g_{\text{max}}$ also corresponds to the controller gain at which the low frequency loop gain (Figure ref:fig:rotating_iff_modified_loop_gain) reaches one.
|
||||
|
||||
|
||||
%% Root Locus for the initial IFF and the modified IFF
|
||||
gains = logspace(-2, 4, 200);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([1,2]);
|
||||
hold on;
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:), 'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:), 'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
% Pure Integrator
|
||||
plot(real(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'x', 'color', colors(1,:), 'DisplayName', 'IFF','MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'o', 'color', colors(1,:), 'HandleVisibility', 'off','MarkerSize',8);
|
||||
% Modified IFF
|
||||
plot(real(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
imag(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
'x', 'color', colors(2,:), 'DisplayName', 'IFF + HPF','MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
imag(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
'o', 'color', colors(2,:), 'HandleVisibility', 'off','MarkerSize',8);
|
||||
hold off;
|
||||
axis square;
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
|
||||
xlim([-2.25, 0.25]); ylim([-1.25, 1.25]);
|
||||
xticks([-2, -1, 0])
|
||||
xticklabels({'$-2\omega_0$', '$-\omega_0$', '$0$'})
|
||||
yticks([-1, 0, 1])
|
||||
yticklabels({'$-\omega_0$', '$0$', '$\omega_0$'})
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
|
||||
end
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
|
||||
end
|
||||
% Pure Integrator
|
||||
plot(real(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'x', 'color', colors(1,:),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'o', 'color', colors(1,:),'MarkerSize',8);
|
||||
% Modified IFF
|
||||
plot(real(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
imag(pole(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
'x', 'color', colors(2,:),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
imag(tzero(Gs{Wz_i}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf)), ...
|
||||
'o', 'color', colors(2,:),'MarkerSize',8);
|
||||
hold off;
|
||||
axis square;
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
title('Zoom near the origin');
|
||||
|
||||
xlim([-0.15, 0.1]); ylim([-0.15, 0.15]);
|
||||
xticks([-0.1, 0, 0.1])
|
||||
xticklabels({'$-0.1\omega_0$', '$0$', '$0.1\omega_0$'})
|
||||
yticks([-0.1, 0, 0.1])
|
||||
yticklabels({'$-0.1\omega_0$', '$0$', '$0.1\omega_0$'})
|
||||
|
||||
% Optimal IFF with HPF parameters $\omega_i$ and $g$
|
||||
% Two parameters can be tuned for the modified controller in equation eqref:eq:iff_lhf: the gain $g$ and the pole's location $\omega_i$.
|
||||
% The optimal values of $\omega_i$ and $g$ are here considered as the values for which the damping of all the closed-loop poles are simultaneously maximized.
|
||||
|
||||
% In order to visualize how $\omega_i$ does affect the attainable damping, the Root Locus plots for several $\omega_i$ are displayed in Figure ref:fig:rotating_root_locus_iff_modified_effect_wi.
|
||||
% It is shown that even though small $\omega_i$ seem to allow more damping to be added to the suspension modes, the control gain $g$ may be limited to small values due to equation eqref:eq:gmax_iff_hpf.
|
||||
|
||||
|
||||
%% High Pass Filter Cut-Off Frequency
|
||||
wis = [0.01, 0.1, 0.5, 1]*Wzs(2); % [rad/s]
|
||||
|
||||
%% Root Locus for the initial IFF and the modified IFF
|
||||
gains = logspace(-2, 4, 200);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
for wi_i = 1:length(wis)
|
||||
wi = wis(wi_i);
|
||||
Kiff = (1/(wi+s))*eye(2);
|
||||
L(wi_i) = plot(nan, nan, '.', 'color', colors(wi_i,:), 'DisplayName', sprintf('$\\omega_i = %.2f \\omega_0$', wi./Wzs(2)));
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(wi_i,:),'MarkerSize',4);
|
||||
end
|
||||
plot(real(pole(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(pole(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'x', 'color', colors(wi_i,:),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(tzero(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'o', 'color', colors(wi_i,:),'MarkerSize',8);
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-2.3, 0.1]); ylim([-1.2, 1.2]);
|
||||
xticks([-2:1:2]); yticks([-2:1:2]);
|
||||
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
clear L
|
||||
|
||||
xlim([-2.25, 0.25]); ylim([-1.25, 1.25]);
|
||||
xticks([-2, -1, 0])
|
||||
xticklabels({'$-2\omega_0$', '$-\omega_0$', '$0$'})
|
||||
yticks([-1, 0, 1])
|
||||
yticklabels({'$-\omega_0$', '$0$', '$\omega_0$'})
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
for wi_i = 1:length(wis)
|
||||
wi = wis(wi_i);
|
||||
Kiff = (1/(wi+s))*eye(2);
|
||||
L(wi_i) = plot(nan, nan, '.', 'color', colors(wi_i,:));
|
||||
for g = gains
|
||||
clpoles = pole(feedback(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff));
|
||||
plot(real(clpoles), imag(clpoles), '.', 'color', colors(wi_i,:),'MarkerSize',4);
|
||||
end
|
||||
plot(real(pole(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(pole(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'x', 'color', colors(wi_i,:),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
imag(tzero(Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), ...
|
||||
'o', 'color', colors(wi_i,:),'MarkerSize',8);
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-2.3, 0.1]); ylim([-1.2, 1.2]);
|
||||
xticks([-2:1:2]); yticks([-2:1:2]);
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
title('Zoom near the origin');
|
||||
clear L
|
||||
|
||||
xlim([-0.15, 0.1]); ylim([-0.15, 0.15]);
|
||||
xticks([-0.1, 0, 0.1])
|
||||
xticklabels({'$-0.1\omega_0$', '$0$', '$0.1\omega_0$'})
|
||||
yticks([-0.1, 0, 0.1])
|
||||
yticklabels({'$-0.1\omega_0$', '$0$', '$0.1\omega_0$'})
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_root_locus_iff_modified_effect_wi
|
||||
% #+caption: Root Locus for several high pass filter cut-off frequency
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_root_locus_iff_modified_effect_wi.png]]
|
||||
|
||||
% In order to study this trade off, the attainable closed-loop damping ratio $\xi_{\text{cl}}$ is computed as a function of $\omega_i/\omega_0$.
|
||||
% The gain $g_{\text{opt}}$ at which this maximum damping is obtained is also displayed and compared with the gain $g_{\text{max}}$ at which the system becomes unstable (Figure ref:fig:rotating_iff_hpf_optimal_gain).
|
||||
|
||||
% Three regions can be observed:
|
||||
% - $\omega_i/\omega_0 < 0.02$: the added damping is limited by the maximum allowed control gain $g_{\text{max}}$
|
||||
% - $0.02 < \omega_i/\omega_0 < 0.2$: the attainable damping ratio is maximized and is reached for $g \approx 2$
|
||||
% - $0.2 < \omega_i/\omega_0$: the added damping decreases as $\omega_i/\omega_0$ increases.
|
||||
|
||||
|
||||
%% Compute the optimal control gain
|
||||
wis = logspace(-2, 1, 100); % [rad/s]
|
||||
|
||||
opt_xi = zeros(1, length(wis)); % Optimal simultaneous damping
|
||||
opt_gain = zeros(1, length(wis)); % Corresponding optimal gain
|
||||
|
||||
for wi_i = 1:length(wis)
|
||||
wi = wis(wi_i);
|
||||
Kiff = 1/(s + wi)*eye(2);
|
||||
|
||||
fun = @(g)computeSimultaneousDamping(g, Gs{2}({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff);
|
||||
|
||||
[g_opt, xi_opt] = fminsearch(fun, 0.5*wi*((1/Wzs(2))^2 - 1));
|
||||
opt_xi(wi_i) = 1/xi_opt;
|
||||
opt_gain(wi_i) = g_opt;
|
||||
end
|
||||
|
||||
%% Attainable damping ratio as a function of wi/w0. Corresponding control gain g_opt and g_max are also shown
|
||||
figure;
|
||||
yyaxis left
|
||||
plot(wis, opt_xi, '-', 'DisplayName', '$\xi_{cl}$');
|
||||
set(gca, 'YScale', 'lin');
|
||||
ylim([0,1]);
|
||||
ylabel('Damping Ratio $\xi$');
|
||||
|
||||
yyaxis right
|
||||
hold on;
|
||||
plot(wis, opt_gain, '-', 'DisplayName', '$g_{opt}$');
|
||||
plot(wis, wis*((1/Wzs(2))^2 - 1), '--', 'DisplayName', '$g_{max}$');
|
||||
set(gca, 'YScale', 'lin');
|
||||
ylim([0,10]);
|
||||
ylabel('Controller gain $g$');
|
||||
|
||||
xlabel('$\omega_i/\omega_0$');
|
||||
set(gca, 'XScale', 'log');
|
||||
legend('location', 'northeast', 'FontSize', 8);
|
||||
|
||||
% Obtained Damped Plant
|
||||
|
||||
% Let's choose $\omega_i = 0.1 \cdot \omega_0$ and compute the damped plant.
|
||||
% The undamped and damped plants are compared in Figure ref:fig:rotating_iff_hpf_damped_plant in blue and red respectively.
|
||||
% A well damped plant is indeed obtained.
|
||||
|
||||
% However, the magnitude of the coupling term ($d_v/F_u$) is larger then IFF is applied.
|
||||
|
||||
|
||||
%% Compute damped plant
|
||||
wi = 0.1; % [rad/s]
|
||||
g = 2; % Gain
|
||||
Kiff_hpf = (g/(wi+s))*eye(2); % IFF with added HPF
|
||||
Kiff_hpf.InputName = {'fu', 'fv'};
|
||||
Kiff_hpf.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
G_iff_hpf = feedback(Gs{2}, Kiff_hpf, 'name');
|
||||
|
||||
isstable(G_iff_hpf) % Verify stability
|
||||
|
||||
%% Damped plant with IFF and added HPF - Transfer function from $F_u$ to $d_u$
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{2}('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros(1,3)], ...
|
||||
'DisplayName', '$d_u/F_u$, OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_iff_hpf('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:)], ...
|
||||
'DisplayName', '$d_u/F_u$, IFF')
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{2}('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$, OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_iff_hpf('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$, IFF')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
leg.ItemTokenSize(1) = 20;
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{2}('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_iff_hpf('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_hpf_damped_plant
|
||||
% #+caption: Damped plant with IFF and added HPF - Transfer function from $F_u$ to $d_u$, $\omega_i = 0.1 \cdot \omega_0$, $\Omega = 0.1 \cdot \omega_0$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_hpf_damped_plant.png]]
|
||||
|
||||
% In order to study how $\omega_i$ affects the coupling of the damped plant, the closed-loop plant is identified for several $\omega_i$.
|
||||
% The direct and coupling terms of the plants are shown in Figure ref:fig:rotating_iff_hpf_damped_plant_effect_wi_coupling (left) and the ratio between the two (i.e. the coupling ratio) is shown in Figure ref:fig:rotating_iff_hpf_damped_plant_effect_wi_coupling (right).
|
||||
|
||||
% The coupling ratio is decreasing as $\omega_i$ increases.
|
||||
% There is therefore a *trade-off between achievable damping and coupling ratio* for the choice of $\omega_i$.
|
||||
% The same trade-off can be seen between achievable damping and loss of compliance at low frequency (see Figure ref:fig:rotating_iff_hpf_effect_wi_compliance).
|
||||
|
||||
|
||||
%% Compute damped plant
|
||||
wis = [0.03, 0.1, 0.5]; % [rad/s]
|
||||
g = 2; % Gain
|
||||
|
||||
Gs_iff_hpf = {};
|
||||
|
||||
for i = 1:length(wis)
|
||||
Kiff_hpf = (g/(wis(i)+s))*eye(2); % IFF with added HPF
|
||||
Kiff_hpf.InputName = {'fu', 'fv'};
|
||||
Kiff_hpf.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
Gs_iff_hpf(i) = {feedback(Gs{2}, Kiff_hpf, 'name')};
|
||||
end
|
||||
|
||||
%% Effect of $\omega_i$ on the damped plant coupling
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(wis)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_iff_hpf{i}('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(i,:)], ...
|
||||
'DisplayName', sprintf('$d_u/F_u$, $\\omega_i = %.2f \\omega_0$', wis(i)))
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_iff_hpf{i}('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(i,:), 0.5], ...
|
||||
'DisplayName', sprintf('$d_v/F_u$, $\\omega_i = %.2f \\omega_0$', wis(i)))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
leg.ItemTokenSize(1) = 20;
|
||||
|
||||
ax3 = nexttile([3,1]);
|
||||
hold on;
|
||||
for i = 1:length(wis)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_iff_hpf{i}('Dv', 'Fu')/Gs_iff_hpf{i}('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(i,:)], ...
|
||||
'DisplayName', sprintf('$\\omega_i = %.2f \\omega_0$', wis(i)))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Coupling Ratio');
|
||||
leg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1);
|
||||
leg.ItemTokenSize(1) = 20;
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(wis)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_iff_hpf{i}('Du', 'Fu'), freqs, 'rad/s'))), '-')
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_hpf_damped_plant_effect_wi_coupling
|
||||
% #+caption: Effect of $\omega_i$ on the damped plant coupling
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_hpf_damped_plant_effect_wi_coupling.png]]
|
||||
|
||||
|
||||
%% Effect of $\omega_i$ on the obtained compliance
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
for i = 1:length(wis)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_iff_hpf{i}('Du', 'Fdx'), freqs, 'rad/s'))), '-', 'color', [colors(i,:)], ...
|
||||
'DisplayName', sprintf('$d_{x}/F_{dx}$, $\\omega_i = %.2f \\omega_0$', wis(i)))
|
||||
end
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{2}('Du', 'Fdx'), freqs, 'rad/s'))), 'k--', ...
|
||||
'DisplayName', '$d_{x}/F_{dx}$, OL')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Compliance [m/N]');
|
||||
leg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
leg.ItemTokenSize(1) = 20;
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
500
matlab/rotating_4_iff_kp.m
Normal file
500
matlab/rotating_4_iff_kp.m
Normal file
@@ -0,0 +1,500 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
%% Load "Generic" system dynamics
|
||||
load('rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% Identify plant with parallel stiffnesses :noexport:
|
||||
|
||||
%% Tuv Stage
|
||||
mn = 0.5; % Tuv mass [kg]
|
||||
|
||||
%% Sample
|
||||
ms = 0.5; % Sample mass [kg]
|
||||
|
||||
%% General Configuration
|
||||
model_config = struct();
|
||||
model_config.controller = "open_loop"; % Default: Open-Loop
|
||||
model_config.Tuv_type = "parallel_k"; % Default: 2DoF stage
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % [Fu, Fv]
|
||||
io(io_i) = linio([mdl, '/fd'], 1, 'openinput'); io_i = io_i + 1; % [Fdu, Fdv]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 1, 'openoutput'); io_i = io_i + 1; % [Fmu, Fmv]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 2, 'openoutput'); io_i = io_i + 1; % [Du, Dv]
|
||||
io(io_i) = linio([mdl, '/ext_metrology'], 1, 'openoutput'); io_i = io_i + 1; % [Dx, Dy]
|
||||
|
||||
% Effect of the parallel stiffness on the IFF plant
|
||||
% The IFF plant (transfer function from $[F_u, F_v]$ to $[f_u, f_v]$) is identified in three different cases:
|
||||
% - without parallel stiffness $k_p = 0$
|
||||
% - with a small parallel stiffness $k_p < m \Omega^2$
|
||||
% - with a large parallel stiffness $k_p > m \Omega^2$
|
||||
|
||||
|
||||
Wz = 0.1; % The rotation speed [rad/s]
|
||||
|
||||
%% No parallel Stiffness
|
||||
kp = 0; % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
G_no_kp = linearize(mdl, io, 0);
|
||||
G_no_kp.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G_no_kp.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Small parallel Stiffness
|
||||
kp = 0.5*(mn+ms)*Wz^2; % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
G_low_kp = linearize(mdl, io, 0);
|
||||
G_low_kp.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G_low_kp.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Large parallel Stiffness
|
||||
kp = 1.5*(mn+ms)*Wz^2; % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
G_high_kp = linearize(mdl, io, 0);
|
||||
G_high_kp.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G_high_kp.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
|
||||
|
||||
% The Bode plots of the obtained dynamics are shown in Figure ref:fig:rotating_iff_effect_kp.
|
||||
% One can see that for $k_p > m \Omega^2$, the two real zeros with $k_p < m \Omega^2$ are transformed into two complex conjugate zeros and the systems shows alternating complex conjugate poles and zeros.
|
||||
|
||||
|
||||
%% Effect of the parallel stiffness on the IFF plant
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_no_kp( 'fu', 'Fu'), freqs, 'rad/s'))), '-', ...
|
||||
'DisplayName', '$k_p = 0$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_low_kp( 'fu', 'Fu'), freqs, 'rad/s'))), '-', ...
|
||||
'DisplayName', '$k_p < m\Omega^2$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_high_kp('fu', 'Fu'), freqs, 'rad/s'))), '-', ...
|
||||
'DisplayName', '$k_p > m\Omega^2$')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [N/N]');
|
||||
ylim([1e-5, 5e1]);
|
||||
legend('location', 'southeast', 'FontSize', 8);
|
||||
|
||||
% Phase
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_no_kp( 'fu', 'Fu'), freqs, 'rad/s'))), '-')
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_low_kp( 'fu', 'Fu'), freqs, 'rad/s'))), '-')
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_high_kp('fu', 'Fu'), freqs, 'rad/s'))), '-')
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
hold off;
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_effect_kp
|
||||
% #+caption: Effect of the parallel stiffness on the IFF plant: Bode plot of $G_{k}(1,1) = f_u/F_u$ without parallel spring, with parallel spring stiffness $k_p < m \Omega^2$ and $k_p > m \Omega^2$, $\Omega = 0.1 \omega_0$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_effect_kp.png]]
|
||||
|
||||
% Figure ref:fig:rotating_iff_kp_root_locus shows the Root Locus plots for $k_p = 0$, $k_p < m \Omega^2$ and $k_p > m \Omega^2$ when $K_F$ is a pure integrator as in Eq. eqref:eq:Kf_pure_int.
|
||||
% It is shown that if the added stiffness is higher than the maximum negative stiffness, the poles of the closed-loop system are bounded on the (stable) left half-plane, and hence the *unconditional stability of IFF is recovered*.
|
||||
|
||||
|
||||
%% Root Locus for IFF without parallel spring, with small parallel spring and with large parallel spring
|
||||
gains = logspace(-2, 2, 200);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([1,2]);
|
||||
hold on;
|
||||
plot(real(pole(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(1,:), ...
|
||||
'DisplayName', '$k_p = 0$','MarkerSize',8);
|
||||
plot(real(tzero(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(1,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_no_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(1,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
|
||||
plot(real(pole(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(2,:), ...
|
||||
'DisplayName', '$k_p < m\Omega^2$','MarkerSize',8);
|
||||
plot(real(tzero(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(2,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_low_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(2,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
|
||||
plot(real(pole(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(3,:), ...
|
||||
'DisplayName', '$k_p > m\Omega^2$','MarkerSize',8);
|
||||
plot(real(tzero(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(3,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_high_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(3,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-2.25, 0.25]); ylim([-1.25, 1.25]);
|
||||
xticks([-2, -1, 0])
|
||||
xticklabels({'$-2\omega_0$', '$-\omega_0$', '$0$'})
|
||||
yticks([-1, 0, 1])
|
||||
yticklabels({'$-\omega_0$', '$0$', '$\omega_0$'})
|
||||
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(real(pole(G_no_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_no_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(1,:), 'MarkerSize',8);
|
||||
plot(real(tzero(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_no_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(1,:), 'MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_no_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(1,:), 'MarkerSize', 4);
|
||||
end
|
||||
|
||||
plot(real(pole(G_low_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_low_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(2,:), 'MarkerSize',8);
|
||||
plot(real(tzero(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_low_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(2,:), 'MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_low_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(2,:), 'MarkerSize', 4);
|
||||
end
|
||||
|
||||
plot(real(pole(G_high_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), imag(pole(G_high_kp( {'fu','fv'},{'Fu','Fv'})*(1/s))), 'x', 'color', colors(3,:), 'MarkerSize',8);
|
||||
plot(real(tzero(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), imag(tzero(G_high_kp({'fu','fv'},{'Fu','Fv'})*(1/s))), 'o', 'color', colors(3,:), 'MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_high_kp({'fu','fv'},{'Fu','Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(3,:), 'MarkerSize',4);
|
||||
end
|
||||
hold off;
|
||||
axis equal;
|
||||
xlim([-0.04, 0.04]); ylim([-0.08, 0.08]);
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
title('Zoom on controller pole')
|
||||
|
||||
% Effect of $k_p$ on the attainable damping
|
||||
|
||||
% Even though the parallel stiffness $k_p$ has no impact on the open-loop poles (as the overall stiffness $k$ is kept constant), it has a large impact on the transmission zeros.
|
||||
% Moreover, as the attainable damping is generally proportional to the distance between poles and zeros cite:preumont18_vibrat_contr_activ_struc_fourt_edition, the parallel stiffness $k_p$ is foreseen to have some impact on the attainable damping.
|
||||
|
||||
% To study this effect, Root Locus plots for several parallel stiffnesses $k_p > m \Omega^2$ are shown in Figure ref:fig:rotating_iff_kp_root_locus_effect_kp.
|
||||
% The frequencies of the transmission zeros of the system are increasing with an increase of the parallel stiffness $k_p$ (thus getting closer to the poles) and the associated attainable damping is reduced.
|
||||
|
||||
% #+begin_important
|
||||
% Therefore, even though the parallel stiffness $k_p$ should be larger than $m \Omega^2$ for stability reasons, it should not be taken too large as this would limit the attainable damping.
|
||||
% #+end_important
|
||||
|
||||
|
||||
%% Tested parallel stiffnesses
|
||||
kps = [2, 20, 40]*(mn + ms)*Wz^2;
|
||||
|
||||
%% Root Locus: Effect of the parallel stiffness on the attainable damping
|
||||
figure;
|
||||
|
||||
gains = logspace(-2, 4, 500);
|
||||
|
||||
hold on;
|
||||
for kp_i = 1:length(kps)
|
||||
kp = kps(kp_i); % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
G = linearize(mdl, io, 0);
|
||||
G.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
plot(real(pole(G({'fu', 'fv'}, {'Fu', 'Fv'})*(1/s*eye(2)))), imag(pole(G({'fu', 'fv'}, {'Fu', 'Fv'})*(1/s*eye(2)))), 'x', 'color', colors(kp_i,:), ...
|
||||
'DisplayName', sprintf('$k_p = %.1f m \\Omega^2$', kp/((mn+ms)*Wz^2)),'MarkerSize',8);
|
||||
plot(real(tzero(G({'fu', 'fv'}, {'Fu', 'Fv'})*(1/s*eye(2)))), imag(tzero(G({'fu', 'fv'}, {'Fu', 'Fv'})*(1/s*eye(2)))), 'o', 'color', colors(kp_i,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G({'fu', 'fv'}, {'Fu', 'Fv'}), (g/s)*eye(2)));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(kp_i,:),'MarkerSize',4, ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
% xlim([-1.15, 0.05]); ylim([0, 1.2]);
|
||||
xlim([-2.25, 0.25]); ylim([-1.25, 1.25]);
|
||||
xticks([-2, -1, 0])
|
||||
xticklabels({'$-2\omega_0$', '$-\omega_0$', '$0$'})
|
||||
yticks([-1, 0, 1])
|
||||
yticklabels({'$-\omega_0$', '$0$', '$\omega_0$'})
|
||||
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 12;
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_kp_root_locus_effect_kp
|
||||
% #+caption: Root Locus: Effect of the parallel stiffness on the attainable damping, $\Omega = 0.1 \omega_0$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_kp_root_locus_effect_kp.png]]
|
||||
|
||||
% This is confirmed by the Figure ref:fig:rotating_iff_kp_optimal_gain where the attainable closed-loop damping ratio $\xi_{\text{cl}}$ and the associated optimal control gain $g_\text{opt}$ are computed as a function of the parallel stiffness.
|
||||
|
||||
|
||||
%% Computes the optimal parameters and attainable simultaneous damping
|
||||
alphas = logspace(-2, 0, 100);
|
||||
alphas(end) = []; % Remove last point
|
||||
|
||||
opt_xi = zeros(1, length(alphas)); % Optimal simultaneous damping
|
||||
opt_gain = zeros(1, length(alphas)); % Corresponding optimal gain
|
||||
|
||||
Kiff = 1/s*eye(2);
|
||||
|
||||
for alpha_i = 1:length(alphas)
|
||||
kp = alphas(alpha_i);
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
G = linearize(mdl, io, 0);
|
||||
G.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
fun = @(g)computeSimultaneousDamping(g, G({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff);
|
||||
|
||||
[g_opt, xi_opt] = fminsearch(fun, 2);
|
||||
opt_xi(alpha_i) = 1/xi_opt;
|
||||
opt_gain(alpha_i) = g_opt;
|
||||
end
|
||||
|
||||
%% Attainable damping as a function of the stiffness ratio
|
||||
figure;
|
||||
yyaxis left
|
||||
plot(alphas, opt_xi, '-', 'DisplayName', '$\xi_{cl}$');
|
||||
set(gca, 'YScale', 'lin');
|
||||
ylim([0,1]);
|
||||
ylabel('Damping Ratio $\xi$');
|
||||
|
||||
yyaxis right
|
||||
hold on;
|
||||
plot(alphas, opt_gain, '-', 'DisplayName', '$g_{opt}$');
|
||||
set(gca, 'YScale', 'lin');
|
||||
ylim([0,2.5]);
|
||||
ylabel('Controller gain $g$');
|
||||
|
||||
set(gca, 'XScale', 'log');
|
||||
legend('location', 'northeast', 'FontSize', 8);
|
||||
|
||||
xlabel('$k_p$');
|
||||
xlim([0.01, 1]);
|
||||
xticks([0.01, 0.1, 1])
|
||||
xticklabels({'$m\Omega^2$', '$10m\Omega^2$', '$100m\Omega^2$'})
|
||||
|
||||
% Damped plant
|
||||
% Let's choose a parallel stiffness equal to $k_p = 2 m \Omega^2$ and compute the damped plant.
|
||||
% The damped and undamped transfer functions from $F_u$ to $d_u$ are compared in Figure ref:fig:rotating_iff_kp_damped_plant.
|
||||
|
||||
% Even though the two resonances are well damped, the IFF changes the low frequency behavior of the plant which is usually not wanted.
|
||||
% This is due to the fact that "pure" integrators are used, and that the low frequency loop gains becomes large below some frequency.
|
||||
|
||||
|
||||
%% Identify dynamics with parallel stiffness = 2mW^2
|
||||
Wz = 0.1; % [rad/s]
|
||||
kp = 2*(mn + ms)*Wz^2; % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
G = linearize(mdl, io, 0);
|
||||
G.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy'};
|
||||
G.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% IFF controller with pure integrator
|
||||
Kiff_kp = (2.2/s)*eye(2);
|
||||
Kiff_kp.InputName = {'fu', 'fv'};
|
||||
Kiff_kp.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
%% Compute the damped plant
|
||||
G_cl_iff_kp = feedback(G, Kiff_kp, 'name');
|
||||
|
||||
%% Damped plant with IFF - Transfer function from $F_u$ to $d_u$
|
||||
freqs = logspace(-3, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3), ...
|
||||
'DisplayName', '$d_u/F_u$ - OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', '$d_u/F_u$ - IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$ - OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$ - IFF + $k_p$')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
ldg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ldg.ItemTokenSize(1) = 20;
|
||||
ylim([1e-6, 1e2]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_iff_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-3,1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.001 \omega_0$', '$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_kp_damped_plant
|
||||
% #+caption: Damped plant with IFF - Transfer function from $F_u$ to $d_u$
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_kp_damped_plant.png]]
|
||||
|
||||
% In order to lower the low frequency gain, an high pass filter is added to the IFF controller (which is equivalent as shifting the controller pole to the left in the complex plane):
|
||||
% \begin{equation}
|
||||
% K_{\text{IFF}}(s) = g\frac{1}{\omega_i + s} \begin{bmatrix}
|
||||
% 1 & 0 \\
|
||||
% 0 & 1
|
||||
% \end{bmatrix}
|
||||
% \end{equation}
|
||||
|
||||
% Let's see how the high pass filter impacts the attainable damping.
|
||||
% The controller gain $g$ is kept constant while $\omega_i$ is changed, and the minimum damping ratio of the damped plant is computed.
|
||||
% The obtained damping ratio as a function of $\omega_i/\omega_0$ (where $\omega_0$ is the resonance of the system without rotation) is shown in Figure ref:fig:rotating_iff_kp_added_hpf_effect_damping.
|
||||
|
||||
|
||||
w0 = sqrt((kn+kp)/(mn+ms)); % Resonance frequency [rad/s]
|
||||
wis = w0*logspace(-2, 0, 100); % LPF cut-off [rad/s]
|
||||
|
||||
%% Computes the obtained damping as a function of the HPF cut-off frequency
|
||||
opt_xi = zeros(1, length(wis)); % Optimal simultaneous damping
|
||||
|
||||
for wi_i = 1:length(wis)
|
||||
Kiff_kp_hpf = (2.2/(s + wis(wi_i)))*eye(2);
|
||||
Kiff_kp_hpf.InputName = {'fu', 'fv'};
|
||||
Kiff_kp_hpf.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
[~, xi] = damp(feedback(G, Kiff_kp_hpf, 'name'));
|
||||
opt_xi(wi_i) = min(xi);
|
||||
end
|
||||
|
||||
%% Effect of the high pass filter cut-off frequency on the obtained damping
|
||||
figure;
|
||||
plot(wis, opt_xi, '-');
|
||||
set(gca, 'XScale', 'log');
|
||||
set(gca, 'YScale', 'lin');
|
||||
ylim([0,1]);
|
||||
ylabel('Damping Ratio $\xi$');
|
||||
xlabel('$\omega_i/\omega_0$');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_iff_kp_added_hpf_effect_damping
|
||||
% #+caption: Effect of the high pass filter cut-off frequency on the obtained damping
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_iff_kp_added_hpf_effect_damping.png]]
|
||||
|
||||
% Let's choose $\omega_i = 0.1 \cdot \omega_0$ and compute the damped plant again.
|
||||
% The Bode plots of the undamped, damped with "pure" IFF, and with added high pass filters are shown in Figure ref:fig:rotating_iff_kp_added_hpf_damped_plant.
|
||||
% The added high pass filter gives almost the same damping properties while giving acceptable low frequency behavior.
|
||||
|
||||
|
||||
%% Compute the damped plant with added High Pass Filter
|
||||
Kiff_kp_hpf = (2.2/(s + 0.1*w0))*eye(2);
|
||||
Kiff_kp_hpf.InputName = {'fu', 'fv'};
|
||||
Kiff_kp_hpf.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
G_cl_iff_hpf_kp = feedback(G, Kiff_kp_hpf, 'name');
|
||||
|
||||
%% Bode plot of the direct and coupling terms for several rotating velocities
|
||||
freqs = logspace(-3, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros( 1,3), ...
|
||||
'DisplayName', '$d_u/F_u$ - OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', '$d_u/F_u$ - IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_hpf_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(2,:), ...
|
||||
'DisplayName', '$d_u/F_u$ - IFF + $k_p$ + HPF')
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros( 1,3), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$ - OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$ - IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_hpf_kp('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(2,:), 0.5], ...
|
||||
'DisplayName', '$d_v/F_u$ - IFF + $k_p$ + HPF')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
ldg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ldg.ItemTokenSize(1) = 20;
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros( 1,3))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_iff_kp( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_iff_hpf_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(2,:))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-3,1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.001 \omega_0$', '$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
185
matlab/rotating_5_rdc.m
Normal file
185
matlab/rotating_5_rdc.m
Normal file
@@ -0,0 +1,185 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
%% Load "Generic" system dynamics
|
||||
load('rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% Decentralized Relative Damping Control
|
||||
% The transfer functions from $[F_u,\ F_v]$ to $[d_u,\ d_v]$ is identified and shown in Figure ref:fig:rotating_rdc_plant_effect_rot for several rotating velocities.
|
||||
|
||||
|
||||
%% Bode plot of the direct and coupling term for the "relative damping control" plant - Effect of rotation
|
||||
figure;
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [N/N]');
|
||||
title('Direct terms: $d_u/F_u$, $d_v/F_v$');
|
||||
ylim([1e-3, 1e2]);
|
||||
|
||||
ax2 = nexttile([2, 1]);
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}('dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:), ...
|
||||
'DisplayName', sprintf('$\\Omega = %.1f \\omega_0$', Wzs(i)))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
title('Coupling Terms: $d_u/F_v$, $d_v/F_u$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [10, 1];
|
||||
ylim([1e-3, 1e2]);
|
||||
|
||||
ax3 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:))
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
ax4 = nexttile;
|
||||
hold on;
|
||||
for i = 1:length(Wzs)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(i,:));
|
||||
end
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); set(gca, 'YTickLabel',[]);
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xticks([1e-2,1e-1,1,1e1])
|
||||
xticklabels({'$0.01 \omega_0$', '$0.1 \omega_0$', '$\omega_0$', '$10 \omega_0$'})
|
||||
|
||||
linkaxes([ax1,ax2,ax3,ax4],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
linkaxes([ax1,ax2],'y');
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_rdc_plant_effect_rot
|
||||
% #+caption: Bode plot of the direct and coupling term for the "relative damping control" plant - Effect of rotation
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_rdc_plant_effect_rot.png]]
|
||||
|
||||
% In order to see if large damping can be added with Relative Damping Control, the root locus is computed (Figure ref:fig:rotating_rdc_root_locus).
|
||||
% The closed-loop system is unconditionally stable and the poles can be damped as much as wanted.
|
||||
|
||||
|
||||
%% Root Locus for Relative Damping Control
|
||||
figure;
|
||||
|
||||
Krdc = s*eye(2); % Relative damping controller
|
||||
|
||||
gains = logspace(-2, 2, 300); % Tested gains
|
||||
Wz_i = [1,3,4];
|
||||
|
||||
hold on;
|
||||
for i = 1:length(Wz_i)
|
||||
plot(real(pole(Gs{Wz_i(i)}({'du', 'dv'}, {'Fu', 'Fv'})*Krdc)), imag(pole(Gs{Wz_i(i)}({'du', 'dv'}, {'Fu', 'Fv'})*Krdc)), 'x', 'color', colors(i,:), ...
|
||||
'DisplayName', sprintf('$\\Omega = %.1f \\omega_0 $', Wzs(Wz_i(i))),'MarkerSize',8);
|
||||
plot(real(tzero(Gs{Wz_i(i)}({'du', 'dv'}, {'Fu', 'Fv'})*Krdc)), imag(tzero(Gs{Wz_i(i)}({'du', 'dv'}, {'Fu', 'Fv'})*Krdc)), 'o', 'color', colors(i,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(Gs{Wz_i(i)}({'du', 'dv'}, {'Fu', 'Fv'}), g*Krdc, -1));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(i,:), ...
|
||||
'HandleVisibility', 'off','MarkerSize',4);
|
||||
end
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-1.8, 0.2]); ylim([0, 2]);
|
||||
xticks([-1, 0])
|
||||
xticklabels({'-$\omega_0$', '$0$'})
|
||||
yticks([0, 1, 2])
|
||||
yticklabels({'$0$', '$\omega_0$', '$2 \omega_0$'})
|
||||
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 8;
|
||||
|
||||
% Damped Plant
|
||||
% Let's select a reasonable "Relative Damping Control" gain, and compute the closed-loop damped system.
|
||||
% The open-loop and damped plants are compared in Figure ref:fig:rotating_rdc_damped_plant.
|
||||
|
||||
% The rotating aspect does not add any complexity for the use of Relative Damping Control.
|
||||
% It does not increase the low frequency coupling as compared to Integral Force Feedback.
|
||||
|
||||
|
||||
i = 2;
|
||||
|
||||
%% Relative Damping Controller
|
||||
Krdc = 2*s*eye(2);
|
||||
Krdc.InputName = {'Du', 'Dv'};
|
||||
Krdc.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
%% Compute the damped plant
|
||||
G_cl_rdc = feedback(Gs{i}, Krdc, 'name');
|
||||
|
||||
%% Damped plant using Relative Damping Control
|
||||
figure;
|
||||
freqs = logspace(-3, 2, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL - $G_d(1,1)$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', 'RDC - $G_d(1,1)$')
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', 'OL - $G_d(2,1)$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:), 0.5], ...
|
||||
'DisplayName', 'RDC - $G_d(2,1)$')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
ldg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ldg.ItemTokenSize(1) = 20;
|
||||
ylim([1e-6, 1e2]);
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_rdc('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
261
matlab/rotating_6_act_damp_comparison.m
Normal file
261
matlab/rotating_6_act_damp_comparison.m
Normal file
@@ -0,0 +1,261 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Simscape model name
|
||||
mdl = 'rotating_model';
|
||||
|
||||
%% Load "Generic" system dynamics
|
||||
load('rotating_generic_plants.mat', 'Gs', 'Wzs');
|
||||
|
||||
% Identify plants :noexport:
|
||||
|
||||
%% The rotating speed is set to $\Omega = 0.1 \omega_0$.
|
||||
Wz = 0.1; % [rad/s]
|
||||
|
||||
%% Masses
|
||||
ms = 0.5; % Sample mass [kg]
|
||||
mn = 0.5; % Tuv mass [kg]
|
||||
|
||||
%% General Configuration
|
||||
model_config = struct();
|
||||
model_config.controller = "open_loop"; % Default: Open-Loop
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % [Fu, Fv]
|
||||
io(io_i) = linio([mdl, '/fd'], 1, 'openinput'); io_i = io_i + 1; % [Fdu, Fdv]
|
||||
io(io_i) = linio([mdl, '/xf'], 1, 'openinput'); io_i = io_i + 1; % [Dfx, Dfy]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 1, 'openoutput'); io_i = io_i + 1; % [Fmu, Fmv]
|
||||
io(io_i) = linio([mdl, '/translation_stage'], 2, 'openoutput'); io_i = io_i + 1; % [Du, Dv]
|
||||
io(io_i) = linio([mdl, '/ext_metrology'], 1, 'openoutput'); io_i = io_i + 1; % [Dx, Dy]
|
||||
|
||||
%% Identifying plant with parallel stiffness
|
||||
|
||||
model_config.Tuv_type = "parallel_k";
|
||||
|
||||
% Parallel stiffness
|
||||
kp = 2*(mn+ms)*Wz^2; % Parallel Stiffness [N/m]
|
||||
cp = 0.001*2*sqrt(kp*(mn+ms)); % Small parallel damping [N/(m/s)]
|
||||
|
||||
% Tuv Stage
|
||||
kn = 1 - kp; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
% Linearize
|
||||
G_kp = linearize(mdl, io, 0);
|
||||
G_kp.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
|
||||
G_kp.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Identifying plant with no parallel stiffness
|
||||
|
||||
model_config.Tuv_type = "normal";
|
||||
|
||||
% Tuv Stage
|
||||
kn = 1; % Stiffness [N/m]
|
||||
cn = 0.01*2*sqrt(kn*(mn+ms)); % Damping [N/(m/s)]
|
||||
|
||||
% Linearize
|
||||
G = linearize(mdl, io, 0);
|
||||
G.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
|
||||
G.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% IFF Controller
|
||||
Kiff = (2.2/(s + 0.1))*eye(2);
|
||||
Kiff.InputName = {'fu', 'fv'};
|
||||
Kiff.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
%% IFF Controller with added stiffness
|
||||
Kiff_kp = (2.2/(s + 0.1))*eye(2);
|
||||
Kiff_kp.InputName = {'fu', 'fv'};
|
||||
Kiff_kp.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
%% Relative Damping Controller
|
||||
Krdc = 2*s*eye(2);
|
||||
Krdc.InputName = {'Du', 'Dv'};
|
||||
Krdc.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
% Root Locus
|
||||
|
||||
% Figure ref:fig:rotating_comp_techniques_root_locus shows the Root Locus plots for the two proposed IFF modifications as well as for relative damping control.
|
||||
% While the two pairs of complex conjugate open-loop poles are identical for both IFF modifications, the transmission zeros are not.
|
||||
% This means that the closed-loop behavior of both systems will differ when large control gains are used.
|
||||
|
||||
% One can observe that the closed loop poles corresponding to the system with added springs (in red) are bounded to the left half plane implying unconditional stability.
|
||||
% This is not the case for the system where the controller is augmented with an HPF (in blue).
|
||||
|
||||
% It is interesting to note that the maximum added damping is very similar for both techniques.
|
||||
|
||||
|
||||
%% Comparison of active damping techniques for rotating platform - Root Locus
|
||||
figure;
|
||||
|
||||
gains = logspace(-2, 2, 500);
|
||||
|
||||
hold on;
|
||||
% IFF
|
||||
plot(real(pole(G({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), imag(pole(G({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), 'x', 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF with HPF', 'MarkerSize', 8);
|
||||
plot(real(tzero(G({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), imag(tzero(G({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff)), 'o', 'color', colors(1,:), ...
|
||||
'HandleVisibility', 'off', 'MarkerSize', 8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(1,:),'MarkerSize',4, ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
% IFF with parallel stiffness
|
||||
plot(real(pole(G_kp({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp)), imag(pole(G_kp({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp)), 'x', 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF with $k_p$', 'MarkerSize', 8);
|
||||
plot(real(tzero(G_kp({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp)), imag(tzero(G_kp({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp)), 'o', 'color', colors(2,:), ...
|
||||
'HandleVisibility', 'off', 'MarkerSize', 8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G_kp({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(2,:),'MarkerSize',4, ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
% RDC
|
||||
plot(real(pole(G({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc)), imag(pole(G({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc)), 'x', 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC', 'MarkerSize', 8);
|
||||
plot(real(tzero(G({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc)), imag(tzero(G({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc)), 'o', 'color', colors(3,:), ...
|
||||
'HandleVisibility', 'off', 'MarkerSize', 8);
|
||||
for g = gains
|
||||
cl_poles = pole(feedback(G({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc));
|
||||
plot(real(cl_poles), imag(cl_poles), '.', 'color', colors(3,:),'MarkerSize',4, ...
|
||||
'HandleVisibility', 'off');
|
||||
end
|
||||
hold off;
|
||||
axis square;
|
||||
xlim([-1.15, 0.05]); ylim([0, 1.2]);
|
||||
|
||||
xlabel('Real Part'); ylabel('Imaginary Part');
|
||||
leg = legend('location', 'northwest', 'FontSize', 8);
|
||||
leg.ItemTokenSize(1) = 12;
|
||||
|
||||
% Obtained Damped Plant
|
||||
% The actively damped plants are computed for the three techniques and compared in Figure ref:fig:rotating_comp_techniques_dampled_plants.
|
||||
|
||||
% #+begin_important
|
||||
% It is shown that while the diagonal (direct) terms of the damped plants are similar for the three active damping techniques, of off-diagonal (coupling) terms are not.
|
||||
% Integral Force Feedback strategy is adding some coupling at low frequency which may negatively impact the positioning performances.
|
||||
% #+end_important
|
||||
|
||||
|
||||
%% Compute Damped plants
|
||||
G_cl_iff = feedback(G, Kiff, 'name');
|
||||
G_cl_iff_kp = feedback(G_kp, Kiff_kp, 'name');
|
||||
G_cl_rdc = feedback(G, Krdc, 'name');
|
||||
|
||||
%% Comparison of the damped plants obtained with the three active damping techniques
|
||||
figure;
|
||||
freqs = logspace(-3, 2, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Magnitude
|
||||
ax1 = nexttile([2, 1]);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + HPF')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC')
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', 'Coupling')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(1,:), 0.5], ...
|
||||
'DisplayName', 'Coupling')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(2,:), 0.5], ...
|
||||
'DisplayName', 'Coupling')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc( 'Dv', 'Fu'), freqs, 'rad/s'))), '-', 'color', [colors(3,:), 0.5], ...
|
||||
'DisplayName', 'Coupling')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); ylabel('Magnitude [m/N]');
|
||||
ldg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ldg.ItemTokenSize = [10, 1];
|
||||
ylim([1e-6, 1e2])
|
||||
|
||||
ax2 = nexttile;
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', zeros(1,3))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_iff( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(1,:))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_iff_kp('Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(2,:))
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(G_cl_rdc( 'Du', 'Fu'), freqs, 'rad/s'))), '-', 'color', colors(3,:))
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Phase [deg]');
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Transmissibility And Compliance
|
||||
% The proposed active damping techniques are now compared in terms of closed-loop transmissibility and compliance.
|
||||
|
||||
% The transmissibility is here defined as the transfer function from a displacement of the rotating stage along $\vec{i}_x$ to the displacement of the payload along the same direction.
|
||||
% It is used to characterize how much vibration is transmitted through the suspended platform to the payload.
|
||||
|
||||
% The compliance describes the displacement response of the payload to external forces applied to it.
|
||||
% This is a useful metric when disturbances are directly applied to the payload.
|
||||
% It is here defined as the transfer function from external forces applied on the payload along $\vec{i}_x$ to the displacement of the payload along the same direction.
|
||||
|
||||
% Very similar results are obtained for the two proposed IFF modifications in terms of transmissibility and compliance (Figure ref:fig:rotating_comp_techniques_transmissibility_compliance).
|
||||
|
||||
% #+begin_important
|
||||
% Using IFF degrades the compliance at low frequency while using relative damping control degrades the transmissibility at high frequency.
|
||||
% This is very well known characteristics of these common active damping techniques that holds when applied to rotating platforms.
|
||||
% #+end_important
|
||||
|
||||
|
||||
%% Comparison of the obtained transmissibilty and compliance for the three tested active damping techniques
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 2, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
% Transmissibility
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Dx', 'Dfx'), freqs, 'rad/s'))), '-', 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff( 'Dx', 'Dfx'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + HPF')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Dx', 'Dfx'), freqs, 'rad/s'))), '-', 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc( 'Dx', 'Dfx'), freqs, 'rad/s'))), '-', 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Transmissibility [m/m]');
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
|
||||
% Compliance
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G( 'Dx', 'Fdx'), freqs, 'rad/s'))), '-', 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff( 'Dx', 'Fdx'), freqs, 'rad/s'))), '-', 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + HPF')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_iff_kp('Dx', 'Fdx'), freqs, 'rad/s'))), '-', 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + $k_p$')
|
||||
plot(freqs, abs(squeeze(freqresp(G_cl_rdc( 'Dx', 'Fdx'), freqs, 'rad/s'))), '-', 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC')
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [rad/s]'); ylabel('Compliance [m/N]');
|
||||
ldg = legend('location', 'southwest', 'FontSize', 8, 'NumColumns', 2);
|
||||
ldg.ItemTokenSize = [10, 1];
|
||||
xlim([freqs(1), freqs(end)]);
|
1206
matlab/rotating_7_nano_hexapod.m
Normal file
1206
matlab/rotating_7_nano_hexapod.m
Normal file
File diff suppressed because it is too large
Load Diff
602
matlab/rotating_8_nass.m
Normal file
602
matlab/rotating_8_nass.m
Normal file
@@ -0,0 +1,602 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
%% Path for functions, data and scripts
|
||||
addpath('./mat/'); % Path for data
|
||||
addpath('./src/'); % Path for Functions
|
||||
|
||||
%% Colors for the figures
|
||||
colors = colororder;
|
||||
|
||||
%% Nano-Hexapod on top of Micro-Station model
|
||||
mdl = 'nass_rotating_model';
|
||||
|
||||
%% Load micro-station parameters
|
||||
load('uniaxial_micro_station_parameters.mat')
|
||||
|
||||
%% Load controllers
|
||||
load('nass_controllers.mat');
|
||||
|
||||
% System dynamics
|
||||
|
||||
|
||||
%% Nano-Hexapod
|
||||
mn = 15; % Nano-Hexapod mass [kg]
|
||||
|
||||
%% Light Sample
|
||||
ms = 1; % Sample Mass [kg]
|
||||
|
||||
%% General Configuration
|
||||
model_config = struct();
|
||||
model_config.controller = "open_loop"; % Default: Open-Loop
|
||||
model_config.Tuv_type = "normal"; % Default: 2DoF stage
|
||||
|
||||
%% Input/Output definition
|
||||
clear io; io_i = 1;
|
||||
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Forces [Fu, Fv]
|
||||
io(io_i) = linio([mdl, '/fd'], 1, 'openinput'); io_i = io_i + 1; % Direct Forces on Sample [Fdx, Fdy]
|
||||
io(io_i) = linio([mdl, '/xf'], 1, 'openinput'); io_i = io_i + 1; % Floor Motion [Dfx, Dfy]
|
||||
io(io_i) = linio([mdl, '/ft'], 1, 'openinput'); io_i = io_i + 1; % Micro-Station Disturbances [Ftx, Fty]
|
||||
io(io_i) = linio([mdl, '/nano_hexapod'], 1, 'openoutput'); io_i = io_i + 1; % [Fmu, Fmv]
|
||||
io(io_i) = linio([mdl, '/nano_hexapod'], 2, 'openoutput'); io_i = io_i + 1; % [Du, Dv]
|
||||
io(io_i) = linio([mdl, '/ext_metrology'],1, 'openoutput'); io_i = io_i + 1; % [Dx, Dy]
|
||||
|
||||
|
||||
|
||||
% The dynamics of the undamped and damped plants are identified.
|
||||
% The active damping parameters used are the optimal ones previously identified (i.e. for the rotating nano-hexapod fixed on a rigid platform).
|
||||
|
||||
|
||||
%% Voice Coil (i.e. soft) Nano-Hexapod
|
||||
kn = 1e4; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.005*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
Wz = 0; % Rotating Velocity [rad/s]
|
||||
G_vc_norot = linearize(mdl, io, 0.0);
|
||||
G_vc_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_vc_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 2*pi; % Rotating Velocity [rad/s]
|
||||
G_vc_fast = linearize(mdl, io, 0.0);
|
||||
G_vc_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_vc_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% APA (i.e. relatively stiff) Nano-Hexapod
|
||||
kn = 1e6; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.005*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
Wz = 0; % Rotating Velocity [rad/s]
|
||||
G_md_norot = linearize(mdl, io, 0.0);
|
||||
G_md_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_md_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 2*pi; % Rotating Velocity [rad/s]
|
||||
G_md_fast = linearize(mdl, io, 0.0);
|
||||
G_md_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_md_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Piezoelectric (i.e. stiff) Nano-Hexapod
|
||||
kn = 1e8; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.005*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
Wz = 0; % Rotating Velocity [rad/s]
|
||||
G_pz_norot = linearize(mdl, io, 0.0);
|
||||
G_pz_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_pz_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 2*pi; % Rotating Velocity [rad/s]
|
||||
G_pz_fast = linearize(mdl, io, 0.0);
|
||||
G_pz_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_pz_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Identify plants with Parallel stiffnesses
|
||||
model_config.Tuv_type = "parallel_k"; % Default: 2DoF stage
|
||||
|
||||
% Voice Coil
|
||||
kp = 1e3;
|
||||
cp = 2*0.001*sqrt((ms + mn)*kp);
|
||||
kn = 1e4-kp; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
Wz = 2*pi; % [rad/s]
|
||||
G_vc_kp_fast = linearize(mdl, io, 0);
|
||||
G_vc_kp_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_vc_kp_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 0; % [rad/s]
|
||||
G_vc_kp_norot = linearize(mdl, io, 0);
|
||||
G_vc_kp_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_vc_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
% APA
|
||||
kp = 1e4;
|
||||
cp = 2*0.001*sqrt((ms + mn)*kp);
|
||||
kn = 1e6 - kp; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
Wz = 2*pi; % [rad/s]
|
||||
G_md_kp_fast = linearize(mdl, io, 0);
|
||||
G_md_kp_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_md_kp_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 0; % [rad/s]
|
||||
G_md_kp_norot = linearize(mdl, io, 0);
|
||||
G_md_kp_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_md_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
% Piezo
|
||||
kp = 1e5;
|
||||
cp = 2*0.001*sqrt((ms + mn)*kp);
|
||||
kn = 1e8 - kp; % Nano-Hexapod Stiffness [N/m]
|
||||
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
|
||||
|
||||
% Identify dynamics
|
||||
Wz = 2*pi; % [rad/s]
|
||||
G_pz_kp_fast = linearize(mdl, io, 0);
|
||||
G_pz_kp_fast.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_pz_kp_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
Wz = 0; % [rad/s]
|
||||
G_pz_kp_norot = linearize(mdl, io, 0);
|
||||
G_pz_kp_norot.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy', 'Ftx', 'Fty'};
|
||||
G_pz_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
|
||||
|
||||
%% Closed Loop Plants - IFF with HPF
|
||||
G_vc_norot_iff_hpf = feedback(G_vc_norot, Kiff_hpf_vc, 'name');
|
||||
G_vc_fast_iff_hpf = feedback(G_vc_fast, Kiff_hpf_vc, 'name');
|
||||
|
||||
G_md_norot_iff_hpf = feedback(G_md_norot, Kiff_hpf_md, 'name');
|
||||
G_md_fast_iff_hpf = feedback(G_md_fast, Kiff_hpf_md, 'name');
|
||||
|
||||
G_pz_norot_iff_hpf = feedback(G_pz_norot, Kiff_hpf_pz, 'name');
|
||||
G_pz_fast_iff_hpf = feedback(G_pz_fast, Kiff_hpf_pz, 'name');
|
||||
|
||||
%% Closed Loop Plants - IFF with Parallel Stiffness
|
||||
G_vc_norot_iff_kp = feedback(G_vc_kp_norot, Kiff_kp_vc, 'name');
|
||||
G_vc_fast_iff_kp = feedback(G_vc_kp_fast, Kiff_kp_vc, 'name');
|
||||
|
||||
G_md_norot_iff_kp = feedback(G_md_kp_norot, Kiff_kp_md, 'name');
|
||||
G_md_fast_iff_kp = feedback(G_md_kp_fast, Kiff_kp_md, 'name');
|
||||
|
||||
G_pz_norot_iff_kp = feedback(G_pz_kp_norot, Kiff_kp_pz, 'name');
|
||||
G_pz_fast_iff_kp = feedback(G_pz_kp_fast, Kiff_kp_pz, 'name');
|
||||
|
||||
%% Closed Loop Plants - RDC
|
||||
G_vc_norot_rdc = feedback(G_vc_norot, Krdc_vc, 'name');
|
||||
G_vc_fast_rdc = feedback(G_vc_fast, Krdc_vc, 'name');
|
||||
|
||||
G_md_norot_rdc = feedback(G_md_norot, Krdc_md, 'name');
|
||||
G_md_fast_rdc = feedback(G_md_fast, Krdc_md, 'name');
|
||||
|
||||
G_pz_norot_rdc = feedback(G_pz_norot, Krdc_pz, 'name');
|
||||
G_pz_fast_rdc = feedback(G_pz_fast, Krdc_pz, 'name');
|
||||
|
||||
|
||||
|
||||
% The undamped and damped plants are shown in Figure ref:fig:rotating_nass_plant_comp_stiffness.
|
||||
% Three nano-hexapod velocities are shown (from left to right): $k_n = \SI{0.01}{\N\per\mu\m}$, $k_n = \SI{1}{\N\per\mu\m}$ and $k_n = \SI{100}{\N\per\mu\m}$.
|
||||
% The direct terms are shown by the solid curves while the coupling terms are shown by the shaded ones.
|
||||
|
||||
% #+begin_important
|
||||
% It can be observed on Figure ref:fig:rotating_nass_plant_comp_stiffness that:
|
||||
% - Coupling (ratio between the off-diagonal and direct terms) is larger for the soft nano-hexapod
|
||||
% - Damping added by the three proposed techniques is quite high and the obtained plant is rather easy to control
|
||||
% - There is some coupling between nano-hexapod and micro-station dynamics for the stiff nano-hexapod (mode at 200Hz)
|
||||
% - The two proposed IFF modification yields similar results
|
||||
% #+end_important
|
||||
|
||||
|
||||
%% Bode plot of the transfer function from nano-hexapod actuator to measured motion by the external metrology
|
||||
freqs_vc = logspace(-1, 2, 1000);
|
||||
freqs_md = logspace(0, 3, 1000);
|
||||
freqs_pz = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(3, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast('Dy', 'Fu'), freqs_vc, 'Hz'))), 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', 'Coupling');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dy', 'Fu'), freqs_vc, 'Hz'))), 'color', [colors(1,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dy', 'Fu'), freqs_vc, 'Hz'))), 'color', [colors(2,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_rdc('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_rdc('Dy', 'Fu'), freqs_vc, 'Hz'))), 'color', [colors(3,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
ylabel('Magnitude [m/N]'); set(gca, 'XTickLabel',[]);
|
||||
ylim([1e-12, 1e-2])
|
||||
title('$k_n = 0.01\,N/\mu m$');
|
||||
|
||||
ax2 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast('Dy', 'Fu'), freqs_md, 'Hz'))), 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', 'Coupling');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dy', 'Fu'), freqs_md, 'Hz'))), 'color', [colors(1,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_kp('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_kp('Dy', 'Fu'), freqs_md, 'Hz'))), 'color', [colors(2,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_rdc('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_rdc('Dy', 'Fu'), freqs_md, 'Hz'))), 'color', [colors(3,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
ylim([1e-12, 1e-2])
|
||||
title('$k_n = 1\,N/\mu m$');
|
||||
|
||||
ax3 = nexttile([2,1]);
|
||||
hold on;
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast('Dy', 'Fu'), freqs_pz, 'Hz'))), 'color', [zeros(1,3), 0.5], ...
|
||||
'DisplayName', 'Coupling');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dy', 'Fu'), freqs_pz, 'Hz'))), 'color', [colors(1,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dy', 'Fu'), freqs_pz, 'Hz'))), 'color', [colors(2,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_rdc('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_rdc('Dy', 'Fu'), freqs_pz, 'Hz'))), 'color', [colors(3,:), 0.5], ...
|
||||
'HandleVisibility', 'off');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
|
||||
ylim([1e-12, 1e-2])
|
||||
ldg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [20, 1];
|
||||
title('$k_n = 100\,N/\mu m$');
|
||||
|
||||
ax1b = nexttile;
|
||||
hold on;
|
||||
plot(freqs_vc, 180/pi*unwrap(angle(squeeze(freqresp(G_vc_fast('Dx', 'Fu'), freqs_vc, 'Hz')))), 'color', zeros(1,3));
|
||||
plot(freqs_vc, 180/pi*unwrap(angle(squeeze(freqresp(G_vc_fast_iff_hpf('Dx', 'Fu'), freqs_vc, 'Hz')))), 'color', colors(1,:));
|
||||
plot(freqs_vc, 180/pi*unwrap(angle(squeeze(freqresp(G_vc_fast_iff_kp('Dx', 'Fu'), freqs_vc, 'Hz')))), 'color', colors(2,:));
|
||||
plot(freqs_vc, 180/pi*unwrap(angle(squeeze(freqresp(G_vc_fast_rdc('Dx', 'Fu'), freqs_vc, 'Hz')))), 'color', colors(3,:));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-270, 90]);
|
||||
|
||||
ax2b = nexttile;
|
||||
hold on;
|
||||
plot(freqs_md, 180/pi*unwrap(angle(squeeze(freqresp(G_md_fast('Dx', 'Fu'), freqs_md, 'Hz')))), 'color', zeros(1,3));
|
||||
plot(freqs_md, 180/pi*unwrap(angle(squeeze(freqresp(G_md_fast_iff_hpf('Dx', 'Fu'), freqs_md, 'Hz')))), 'color', colors(1,:));
|
||||
plot(freqs_md, 180/pi*unwrap(angle(squeeze(freqresp(G_md_fast_iff_kp('Dx', 'Fu'), freqs_md, 'Hz')))), 'color', colors(2,:));
|
||||
plot(freqs_md, 180/pi*unwrap(angle(squeeze(freqresp(G_md_fast_rdc('Dx', 'Fu'), freqs_md, 'Hz')))), 'color', colors(3,:));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-270, 90]);
|
||||
|
||||
ax3b = nexttile;
|
||||
hold on;
|
||||
plot(freqs_pz, 180/pi*unwrap(angle(squeeze(freqresp(G_pz_fast('Dx', 'Fu'), freqs_pz, 'Hz')))), 'color', zeros(1,3));
|
||||
plot(freqs_pz, 180/pi*unwrap(angle(squeeze(freqresp(G_pz_fast_iff_hpf('Dx', 'Fu'), freqs_pz, 'Hz')))), 'color', colors(1,:));
|
||||
plot(freqs_pz, 180/pi*unwrap(angle(squeeze(freqresp(G_pz_fast_iff_kp('Dx', 'Fu'), freqs_pz, 'Hz')))), 'color', colors(2,:));
|
||||
plot(freqs_pz, 180/pi*unwrap(angle(squeeze(freqresp(G_pz_fast_rdc('Dx', 'Fu'), freqs_pz, 'Hz')))), 'color', colors(3,:));
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
hold off;
|
||||
yticks(-360:90:360);
|
||||
ylim([-270, 90]);
|
||||
|
||||
linkaxes([ax1,ax1b],'x');
|
||||
xlim([freqs_vc(1), freqs_vc(end)]);
|
||||
|
||||
linkaxes([ax2,ax2b],'x');
|
||||
xlim([freqs_md(1), freqs_md(end)]);
|
||||
|
||||
linkaxes([ax3,ax3b],'x');
|
||||
xlim([freqs_pz(1), freqs_pz(end)]);
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_nass_plant_comp_stiffness
|
||||
% #+caption: Bode plot of the transfer function from nano-hexapod actuator to measured motion by the external metrology
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_nass_plant_comp_stiffness.png]]
|
||||
|
||||
% To confirm that the coupling is smaller when the stiffness of the nano-hexapod is increase, the /coupling ratio/ for the three nano-hexapod stiffnesses are shown in Figure ref:fig:rotating_nass_plant_coupling_comp.
|
||||
|
||||
|
||||
%% Coupling ratio for the proposed active damping techniques evaluated for the three nano-hexapod stiffnesses
|
||||
figure;
|
||||
freqs_vc = logspace(-1, 2, 1000);
|
||||
freqs_md = logspace(0, 3, 1000);
|
||||
freqs_pz = logspace(0, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast('Dy', 'Fu')/G_vc_fast('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dy', 'Fu')/G_vc_fast_iff_hpf('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dy', 'Fu')/G_vc_fast_iff_kp('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_rdc('Dy', 'Fu')/G_vc_fast_rdc('Dx', 'Fu'), freqs_vc, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Coupling Ratio');
|
||||
title('$k_n = 0.01\,N/\mu m$');
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast('Dy', 'Fu')/G_md_fast('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dy', 'Fu')/G_md_fast_iff_hpf('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_kp('Dy', 'Fu')/G_md_fast_iff_kp('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_rdc('Dy', 'Fu')/G_md_fast_rdc('Dx', 'Fu'), freqs_md, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
title('$k_n = 1\,N/\mu m$');
|
||||
|
||||
ax3 = nexttile();
|
||||
hold on;
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast('Dy', 'Fu')/G_pz_fast('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dy', 'Fu')/G_pz_fast_iff_hpf('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dy', 'Fu')/G_pz_fast_iff_kp('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_rdc('Dy', 'Fu')/G_pz_fast_rdc('Dx', 'Fu'), freqs_pz, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
title('$k_n = 100\,N/\mu m$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [20, 1];
|
||||
|
||||
linkaxes([ax1,ax2,ax3], 'y')
|
||||
|
||||
% Effect of disturbances
|
||||
|
||||
% The effect of three disturbances are considered:
|
||||
% - Floor motion (Figure ref:fig:rotating_nass_effect_floor_motion)
|
||||
% - Micro-Station vibrations (Figure ref:fig:rotating_nass_effect_stage_vibration)
|
||||
% - Direct force applied on the payload (Figure ref:fig:rotating_nass_effect_direct_forces)
|
||||
|
||||
% #+begin_important
|
||||
% Conclusions are similar than with the uniaxial (non-rotating) model:
|
||||
% - Regarding the effect of floor motion and forces applied on the payload:
|
||||
% - The stiffer, the better (magnitudes are lower for the right curves, Figures ref:fig:rotating_nass_effect_floor_motion and ref:fig:rotating_nass_effect_direct_forces)
|
||||
% - Integral Force Feedback degrades the performances at low frequency compared to relative damping control
|
||||
% - Regarding the effect of micro-station vibrations:
|
||||
% - Having a soft nano-hexapod allows to filter these vibrations between the suspensions modes of the nano-hexapod and some flexible modes of the micro-station. Using relative damping control reduce this filtering (Figure ref:fig:rotating_nass_effect_stage_vibration, left).
|
||||
% #+end_important
|
||||
|
||||
|
||||
%% Effect of Floor motion on the position error - Comparison of active damping techniques for the three nano-hexapod stiffnesses
|
||||
freqs = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast('Dx', 'Dfx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_rdc('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude $d_x/D_{f,x}$ [m/N]');
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 0.01\,N/\mu m$');
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast('Dx', 'Dfx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_kp('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_rdc('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 1\,N/\mu m$');
|
||||
|
||||
ax3 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast('Dx', 'Dfx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_rdc('Dx', 'Dfx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 100\,N/\mu m$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [20, 1];
|
||||
|
||||
linkaxes([ax1,ax2,ax3], 'y')
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_nass_effect_floor_motion
|
||||
% #+caption: Effect of Floor motion on the position error - Comparison of active damping techniques for the three nano-hexapod stiffnesses
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_nass_effect_floor_motion.png]]
|
||||
|
||||
|
||||
%% Effect of micro-station vibrations on the position error - Comparison of active damping techniques for the three nano-hexapod stiffnesses
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast('Dx', 'Ftx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_rdc('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude $d_x/f_{t,x}$ [m/N]');
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 0.01\,N/\mu m$');
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast('Dx', 'Ftx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_kp('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_rdc('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 1\,N/\mu m$');
|
||||
|
||||
ax3 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast('Dx', 'Ftx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_rdc('Dx', 'Ftx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 100\,N/\mu m$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [20, 1];
|
||||
|
||||
linkaxes([ax1,ax2,ax3], 'y')
|
||||
|
||||
|
||||
|
||||
% #+name: fig:rotating_nass_effect_stage_vibration
|
||||
% #+caption: Effect of micro-station vibrations on the position error - Comparison of active damping techniques for the three nano-hexapod stiffnesses
|
||||
% #+RESULTS:
|
||||
% [[file:figs/rotating_nass_effect_stage_vibration.png]]
|
||||
|
||||
|
||||
%% Effect of sample forces on the position error - Comparison of active damping techniques for the three nano-hexapod stiffnesses
|
||||
figure;
|
||||
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
|
||||
|
||||
ax1 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast('Dx', 'Fdx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_hpf('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_iff_kp('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_vc_fast_rdc('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude $d_x/f_{s,x}$ [m/N]');
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 0.01\,N/\mu m$');
|
||||
|
||||
ax2 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast('Dx', 'Fdx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_hpf('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_iff_kp('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_md_fast_rdc('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 1\,N/\mu m$');
|
||||
|
||||
ax3 = nexttile();
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast('Dx', 'Fdx'), freqs, 'Hz'))), 'color', zeros(1,3), ...
|
||||
'DisplayName', 'OL');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_hpf('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(1,:), ...
|
||||
'DisplayName', 'IFF + $k_p$');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_iff_kp('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(2,:), ...
|
||||
'DisplayName', 'IFF + HPF');
|
||||
plot(freqs, abs(squeeze(freqresp(G_pz_fast_rdc('Dx', 'Fdx'), freqs, 'Hz'))), 'color', colors(3,:), ...
|
||||
'DisplayName', 'RDC');
|
||||
hold off;
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); set(gca, 'YTickLabel',[]);
|
||||
xticks([1e-1, 1e0, 1e1, 1e2, 1e3]);
|
||||
xtickangle(0)
|
||||
title('$k_n = 100\,N/\mu m$');
|
||||
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
|
||||
ldg.ItemTokenSize = [20, 1];
|
||||
|
||||
linkaxes([ax1,ax2,ax3], 'y')
|
Binary file not shown.
BIN
matlab/rotating_model.slx
Normal file
BIN
matlab/rotating_model.slx
Normal file
Binary file not shown.
@@ -1,623 +0,0 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
addpath('./mat/');
|
||||
|
||||
% Initialization
|
||||
% Let's load the previously defined parameters for the model.
|
||||
|
||||
|
||||
load('parameters.mat');
|
||||
|
||||
bode_opts = bodeoptions;
|
||||
bode_opts.FreqUnits = 'Hz';
|
||||
bode_opts.MagUnits = 'abs';
|
||||
bode_opts.MagScale = 'log';
|
||||
bode_opts.Grid = 'on';
|
||||
bode_opts.PhaseVisible = 'off';
|
||||
bode_opts.Title.FontSize = 10;
|
||||
bode_opts.XLabel.FontSize = 10;
|
||||
bode_opts.YLabel.FontSize = 10;
|
||||
bode_opts.TickLabel.FontSize = 10;
|
||||
|
||||
open rotating_frame.slx
|
||||
|
||||
|
||||
|
||||
% First we define the parameters that must be defined in order to run the Simscape simulation.
|
||||
|
||||
w = 2*pi; % Rotation speed [rad/s]
|
||||
|
||||
theta_e = 0; % Static measurement error on the angle theta [rad]
|
||||
|
||||
m = 5; % mass of the sample [kg]
|
||||
|
||||
mTuv = 30;% Mass of the moving part of the Tuv stage [kg]
|
||||
kTuv = 1e8; % Stiffness of the Tuv stage [N/m]
|
||||
cTuv = 0; % Damping of the Tuv stage [N/(m/s)]
|
||||
|
||||
|
||||
|
||||
% Then, we defined parameters that will be used in the following analysis.
|
||||
|
||||
mlight = 5; % Mass for light sample [kg]
|
||||
mheavy = 55; % Mass for heavy sample [kg]
|
||||
|
||||
wlight = 2*pi; % Max rot. speed for light sample [rad/s]
|
||||
wheavy = 2*pi/60; % Max rot. speed for heavy sample [rad/s]
|
||||
|
||||
kvc = 1e3; % Voice Coil Stiffness [N/m]
|
||||
kpz = 1e8; % Piezo Stiffness [N/m]
|
||||
|
||||
d = 0.01; % Maximum excentricity from rotational axis [m]
|
||||
|
||||
freqs = logspace(-2, 3, 1000); % Frequency vector for analysis [Hz]
|
||||
|
||||
% Identification in the rotating referenced frame
|
||||
% We initialize the inputs and outputs of the system to identify:
|
||||
% - Inputs: $f_u$ and $f_v$
|
||||
% - Outputs: $d_u$ and $d_v$
|
||||
|
||||
|
||||
%% Options for Linearized
|
||||
options = linearizeOptions;
|
||||
options.SampleTime = 0;
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fu'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fv'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/du'], 1, 'output');
|
||||
io(4) = linio([mdl, '/dv'], 1, 'output');
|
||||
|
||||
|
||||
|
||||
% We start we identify the transfer functions at high speed with the light sample.
|
||||
|
||||
w = wlight; % Rotation speed [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
|
||||
kTuv = kpz;
|
||||
Gpz_light = linearize(mdl, io, 0.1);
|
||||
Gpz_light.InputName = {'Fu', 'Fv'};
|
||||
Gpz_light.OutputName = {'Du', 'Dv'};
|
||||
|
||||
kTuv = kvc;
|
||||
Gvc_light = linearize(mdl, io, 0.1);
|
||||
Gvc_light.InputName = {'Fu', 'Fv'};
|
||||
Gvc_light.OutputName = {'Du', 'Dv'};
|
||||
|
||||
|
||||
|
||||
% Then we identify the system with an heavy mass and low speed.
|
||||
|
||||
w = wheavy; % Rotation speed [rad/s]
|
||||
m = mheavy; % mass of the sample [kg]
|
||||
|
||||
kTuv = kpz;
|
||||
Gpz_heavy = linearize(mdl, io, 0.1);
|
||||
Gpz_heavy.InputName = {'Fu', 'Fv'};
|
||||
Gpz_heavy.OutputName = {'Du', 'Dv'};
|
||||
|
||||
kTuv = kvc;
|
||||
Gvc_heavy = linearize(mdl, io, 0.1);
|
||||
Gvc_heavy.InputName = {'Fu', 'Fv'};
|
||||
Gvc_heavy.OutputName = {'Du', 'Dv'};
|
||||
|
||||
% Coupling ratio between $f_{uv}$ and $d_{uv}$
|
||||
% In order to validate the equations written, we can compute the coupling ratio using the simscape model and compare with the equations.
|
||||
|
||||
% From the previous identification, we plot the coupling ratio in both case (figure [[fig:coupling_ratio_light_heavy]]).
|
||||
|
||||
% We obtain the same result than the analytical case (figures [[fig:coupling_light]] and [[fig:coupling_heavy]]).
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc_light('Du', 'Fu'), freqs, 'Hz')))./abs(squeeze(freqresp(Gvc_light('Dv', 'Fu'), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Gpz_light('Du', 'Fu'), freqs, 'Hz')))./abs(squeeze(freqresp(Gpz_light('Dv', 'Fu'), freqs, 'Hz'))));
|
||||
set(gca,'ColorOrderIndex',1);
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc_heavy('Du', 'Fu'), freqs, 'Hz')))./abs(squeeze(freqresp(Gvc_heavy('Dv', 'Fu'), freqs, 'Hz'))), '--');
|
||||
plot(freqs, abs(squeeze(freqresp(Gpz_heavy('Du', 'Fu'), freqs, 'Hz')))./abs(squeeze(freqresp(Gpz_heavy('Dv', 'Fu'), freqs, 'Hz'))), '--');
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Coupling ratio');
|
||||
legend({'light - VC', 'light - PZ', 'heavy - VC', 'heavy - PZ'}, 'Location', 'northeast')
|
||||
|
||||
% Transfer function from force to force sensor (IFF plant)
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fu'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fv'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/fum'], 1, 'output');
|
||||
io(4) = linio([mdl, '/fvm'], 1, 'output');
|
||||
|
||||
|
||||
|
||||
% We start we identify the transfer functions at high speed with the light sample.
|
||||
|
||||
w = wlight; % Rotation speed [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
|
||||
kTuv = kpz;
|
||||
Gpz_light = linearize(mdl, io, 0.1);
|
||||
Gpz_light.InputName = {'Fu', 'Fv'};
|
||||
Gpz_light.OutputName = {'Fum', 'Fvm'};
|
||||
|
||||
kTuv = kvc;
|
||||
Gvc_light = linearize(mdl, io, 0.1);
|
||||
Gvc_light.InputName = {'Fu', 'Fv'};
|
||||
Gvc_light.OutputName = {'Fum', 'Fvm'};
|
||||
|
||||
|
||||
|
||||
% Then we identify the system with an heavy mass and low speed.
|
||||
|
||||
w = wheavy; % Rotation speed [rad/s]
|
||||
m = mheavy; % mass of the sample [kg]
|
||||
|
||||
kTuv = kpz;
|
||||
Gpz_heavy = linearize(mdl, io, 0.1);
|
||||
Gpz_heavy.InputName = {'Fu', 'Fv'};
|
||||
Gpz_heavy.OutputName = {'Fum', 'Fvm'};
|
||||
|
||||
kTuv = kvc;
|
||||
Gvc_heavy = linearize(mdl, io, 0.1);
|
||||
Gvc_heavy.InputName = {'Fu', 'Fv'};
|
||||
Gvc_heavy.OutputName = {'Fum', 'Fvm'};
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc_heavy('Fum', 'Fu'), freqs, 'Hz'))));
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Coupling ratio');
|
||||
legend({'light - VC', 'light - PZ', 'heavy - VC', 'heavy - PZ'}, 'Location', 'northeast')
|
||||
|
||||
% Plant identification
|
||||
% The goal is to study the control problems due to the coupling that appears because of the rotation.
|
||||
|
||||
|
||||
%% Options for Linearized
|
||||
options = linearizeOptions;
|
||||
options.SampleTime = 0;
|
||||
|
||||
%% Name of the Simulink File
|
||||
mdl = 'rotating_frame';
|
||||
|
||||
%% Input/Output definition
|
||||
io(1) = linio([mdl, '/fu'], 1, 'input');
|
||||
io(2) = linio([mdl, '/fv'], 1, 'input');
|
||||
|
||||
io(3) = linio([mdl, '/du'], 1, 'output');
|
||||
io(4) = linio([mdl, '/dv'], 1, 'output');
|
||||
|
||||
|
||||
|
||||
% First, we identify the system when the rotation speed is null and then when the rotation speed is equal to 60rpm.
|
||||
|
||||
% The actuators are voice coil with some damping added.
|
||||
|
||||
% The bode plot of the system not rotating and rotating at 60rpm is shown figure [[fig:Gvc_speed]].
|
||||
|
||||
|
||||
w = 0; % Rotation speed [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
kTuv = kvc;
|
||||
cTuv = 0.1*sqrt(kTuv*m);
|
||||
|
||||
Gvc = linearize(mdl, io, 0.1);
|
||||
Gvc.InputName = {'Fu', 'Fv'};
|
||||
Gvc.OutputName = {'Du', 'Dv'};
|
||||
|
||||
w = wlight; % Rotation speed [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
kTuv = kvc;
|
||||
cTuv = 0.1*sqrt(kTuv*m);
|
||||
|
||||
Gtvc = linearize(mdl, io, 0.1);
|
||||
Gtvc.InputName = {'Fu', 'Fv'};
|
||||
Gtvc.OutputName = {'Du', 'Dv'};
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,2,1);
|
||||
title('From $F_u$ to $D_u$');
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc(1, 1), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Gtvc(1, 1), freqs, 'Hz'))));
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,2,3);
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gvc(1, 1), freqs, 'Hz'))), 'DisplayName', 'Gvc - $\omega = 0$');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gtvc(1, 1), freqs, 'Hz'))), 'DisplayName', 'Gvc - $\omega = 60$rpm');
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'northeast');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
ax1 = subplot(2,2,2);
|
||||
title('From $F_u$ to $D_v$');
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc(1, 2), freqs, 'Hz'))));
|
||||
plot(freqs, abs(squeeze(freqresp(Gtvc(1, 2), freqs, 'Hz'))));
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
|
||||
ax2 = subplot(2,2,4);
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gvc(1, 2), freqs, 'Hz'))), 'DisplayName', 'Gvc - $\omega = 0$');
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gtvc(1, 2), freqs, 'Hz'))), 'DisplayName', 'Gvc - $\omega = 60$rpm');
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]');
|
||||
legend('Location', 'northeast');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Effect of rotation speed
|
||||
% We first identify the system (voice coil and light mass) for multiple rotation speed.
|
||||
% Then we compute the bode plot of the system (figure [[fig:Guu_uv_ws]]).
|
||||
|
||||
% As the rotation frequency increases:
|
||||
% - one pole goes to lower frequencies while the other goes to higher frequencies
|
||||
% - one zero appears between the two poles
|
||||
% - the zero disappears when $\omega > \sqrt{\frac{k}{m}}$ and the low frequency pole becomes unstable (positive real part)
|
||||
|
||||
% To stabilize the unstable pole, we need a control bandwidth of at least twice of frequency of the unstable pole.
|
||||
|
||||
|
||||
ws = linspace(0, 2*pi, 5); % Rotation speed vector [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
|
||||
kTuv = kvc;
|
||||
cTuv = 0.1*sqrt(kTuv*m);
|
||||
|
||||
Gs_vc = {zeros(1, length(ws))};
|
||||
|
||||
for i = 1:length(ws)
|
||||
w = ws(i);
|
||||
Gs_vc{i} = linearize(mdl, io, 0.1);
|
||||
Gs_vc{i}.InputName = {'Fu', 'Fv'};
|
||||
Gs_vc{i}.OutputName = {'Du', 'Dv'};
|
||||
end
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,2,1);
|
||||
title('$D_u/F_u$');
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_vc{i}(1, 1), freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
ylim([1e-8, 1]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,2,3);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_vc{i}(1, 1), freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
ax1 = subplot(2,2,2);
|
||||
title('$D_v/F_u$');
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_vc{i}(1, 2), freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
ylim([1e-8, 1]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
set(gca, 'YTickLabel',[]);
|
||||
|
||||
ax2 = subplot(2,2,4);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_vc{i}(1, 2), freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
set(gca, 'YTickLabel',[]);
|
||||
xlabel('Frequency [Hz]');
|
||||
legend('Location', 'northeast');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
|
||||
|
||||
% #+LABEL: fig:Guu_uv_ws
|
||||
% #+CAPTION: Diagonal term as a function of the rotation frequency
|
||||
% [[file:figs/Guu_uv_ws.png]]
|
||||
|
||||
% Then, we can look at the same plots for the piezoelectric actuator (figure [[fig:Guu_ws_pz]]). The effect of the rotation frequency has very little effect on the dynamics of the system to control.
|
||||
|
||||
|
||||
ws = linspace(0, 2*pi, 5); % Rotation speed vector [rad/s]
|
||||
m = mlight; % mass of the sample [kg]
|
||||
|
||||
kTuv = kpz;
|
||||
cTuv = 0.1*sqrt(kTuv*m);
|
||||
|
||||
Gs_pz = {zeros(1, length(ws))};
|
||||
|
||||
for i = 1:length(ws)
|
||||
w = ws(i);
|
||||
Gs_pz{i} = linearize(mdl, io, 0.1);
|
||||
Gs_pz{i}.InputName = {'Fu', 'Fv'};
|
||||
Gs_pz{i}.OutputName = {'Du', 'Dv'};
|
||||
end
|
||||
|
||||
freqs = logspace(2, 3, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_pz{i}(1, 1), freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_pz{i}(1, 1), freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'northeast');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Controller design
|
||||
% We design a controller based on the identification when the system is not rotating.
|
||||
|
||||
% The obtained controller is a lead-lag controller with the following transfer function.
|
||||
|
||||
Kll = 2.0698e09*(s+40.45)*(s+1.181)/((s+0.01)*(s+198.4)*(s+2790));
|
||||
K = [Kll 0;
|
||||
0 Kll];
|
||||
|
||||
K.InputName = {'Du', 'Dv'};
|
||||
K.OutputName = {'Fu', 'Fv'};
|
||||
|
||||
|
||||
|
||||
% The loop gain is displayed figure [[fig:Gvc_loop_gain]].
|
||||
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
% Amplitude
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gvc('Du', 'fu')*Kll, freqs, 'Hz'))), '-');
|
||||
set(gca,'xscale','log'); set(gca,'yscale','log');
|
||||
ylabel('Amplitude [m/N]');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
% Phase
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gvc('Du', 'fu')*Kll, freqs, 'Hz')))), '-');
|
||||
set(gca,'xscale','log');
|
||||
yticks(-180:180:180);
|
||||
ylim([-180 180]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Controlling the rotating system
|
||||
% We here want to see if the system is robust with respect to the rotation speed.
|
||||
% We use the controller that was designed based on the dynamics of the non-rotating system.
|
||||
|
||||
% Let's first plot the SISO loop gain.
|
||||
|
||||
|
||||
freqs = logspace(-2, 2, 1000);
|
||||
|
||||
figure;
|
||||
% Amplitude
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_vc{1}(1, 1)*Kll, freqs, 'Hz'))), '-');
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_vc{2}(1, 1)*Kll, freqs, 'Hz'))), '-');
|
||||
plot(freqs, abs(squeeze(freqresp(Gs_vc{5}(1, 1)*Kll, freqs, 'Hz'))), '-');
|
||||
set(gca,'xscale','log'); set(gca,'yscale','log');
|
||||
ylabel('Amplitude [m/N]');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
hold off;
|
||||
|
||||
% Phase
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_vc{1}(1, 1)*Kll, freqs, 'Hz'))), 'DisplayName', sprintf('%.0f rpm', ws(1)./(2*pi).*60));
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_vc{2}(1, 1)*Kll, freqs, 'Hz'))), 'DisplayName', sprintf('%.0f rpm', ws(2)./(2*pi).*60));
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs_vc{5}(1, 1)*Kll, freqs, 'Hz'))), 'DisplayName', sprintf('%.0f rpm', ws(5)./(2*pi).*60));
|
||||
set(gca,'xscale','log');
|
||||
yticks(-180:180:180);
|
||||
ylim([-180 180]);
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
hold off;
|
||||
legend('Location', 'northeast');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
|
||||
|
||||
% #+NAME: fig:loop_gain_turning
|
||||
% #+CAPTION: Loop Gain $G_u * K$
|
||||
% [[file:figs/loop_gain_turning.png]]
|
||||
|
||||
% We can now compute the close-loop systems.
|
||||
|
||||
Gvc_cl = {zeros(1, length(ws))};
|
||||
for i = 1:length(ws)
|
||||
Gvc_cl{i} = feedback(Gs_vc{i}, K, 'name');
|
||||
end
|
||||
|
||||
|
||||
|
||||
% Let's now look on figure [[fig:evolution_poles_u]] at the evolution of the poles of the system when closing only one loop (controlling only one direction). We see that two complex conjugate poles are approaching the real axis and then they separate: one goes to positive real part and the other goes to negative real part.
|
||||
% The system then goes unstable at some point (here for $\omega=60rpm$).
|
||||
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
sys = feedback(Gs_vc{i}(1, 1), K(1, 1), 'name');
|
||||
plot(real(pole(sys)), imag(pole(sys)), 'x', 'DisplayName', sprintf('$\\omega = %.0f rpm$', ws(i)/(2*pi)*60));
|
||||
end
|
||||
hold off;
|
||||
xlim([-80, 10]);
|
||||
xlabel('Real Axis'); ylabel('Imaginary Axis');
|
||||
legend('Location', 'northeast');
|
||||
|
||||
|
||||
|
||||
% #+NAME: fig:evolution_poles_u
|
||||
% #+CAPTION: Evolution of the poles of the closed-loop system when closing just one loop
|
||||
% [[file:figs/evolution_poles_u.png]]
|
||||
|
||||
% If we look at the poles of the closed loop-system for multiple rotating speed (figure [[fig:poles_cl_system]]) when closing the two loops (MIMO system), we see that they all have a negative real part (stable system), and their evolution on the complex plane is rather small compare to the open loop evolution.
|
||||
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(real(pole(Gvc_cl{i})), imag(pole(Gvc_cl{i})), 'x', 'DisplayName', sprintf('$\\omega = %.0f rpm$', ws(i)/(2*pi)*60));
|
||||
end
|
||||
hold off;
|
||||
xlim([-80, 0]);
|
||||
xlabel('Real Axis'); ylabel('Imaginary Axis');
|
||||
legend('Location', 'northeast');
|
||||
|
||||
% Close loop performance
|
||||
% First, we create the closed loop systems. Then, we plot the transfer function from the reference signals $[r_u, r_v]$ to the output $[d_u, d_v]$ (figure [[fig:perfcomp]]).
|
||||
|
||||
|
||||
freqs = logspace(-2, 3, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(1,2,1);
|
||||
title('$G_{r_u \to d_u}$')
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
sys = Gvc_cl{i}*K;
|
||||
plot(freqs, abs(squeeze(freqresp(sys(1, 1), freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
ylim([1e-4, 10]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]'); ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(1,2,2);
|
||||
title('$G_{r_u \to d_v}$')
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
sys = Gvc_cl{i}*K;
|
||||
plot(freqs, abs(squeeze(freqresp(sys(1, 2), freqs, 'Hz'))), 'DisplayName', sprintf('$\\omega = %.0f rpm$', ws(i)/(2*pi)*60));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
ylim([1e-4, 10]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
xlabel('Frequency [Hz]');
|
||||
legend('Location', 'northeast')
|
||||
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Campbell Diagram for the close loop system
|
||||
|
||||
|
||||
m = mlight;
|
||||
k = kvc;
|
||||
c = 0.1*sqrt(k*m);
|
||||
|
||||
wsvc = linspace(0, 10, 100); % [rad/s]
|
||||
|
||||
polesvc = zeros(8, length(wsvc));
|
||||
|
||||
for i = 1:length(wsvc)
|
||||
Gs = (m*s^2 + (k-m*w^2))/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2);
|
||||
Gcs = (2*m*w*s)/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2);
|
||||
|
||||
G = [Gs, Gcs; Gcs, Gs];
|
||||
G.InputName = {'Fu', 'Fv'};
|
||||
G.OutputName = {'Du', 'Dv'};
|
||||
|
||||
polei = pole(feedback(G, K, 'name'));
|
||||
polesvc(:, i) = sort(polei(imag(polei) > 0));
|
||||
|
||||
polei = pole(feedback(G, 10*K, 'name'));
|
||||
polesvcb(:, i) = sort(polei(imag(polei) > 0));
|
||||
end
|
||||
|
||||
figure;
|
||||
% Amplitude
|
||||
ax1 = subplot(1,2,1);
|
||||
hold on;
|
||||
for i = 1:8
|
||||
plot(wsvc, real(polesvc(i, :)), 'b')
|
||||
plot(wsvc, real(polesvcb(i, :)), 'r')
|
||||
end
|
||||
plot(wsvc, zeros(size(wsvc)), 'k--')
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Real Part');
|
||||
|
||||
ax2 = subplot(1,2,2);
|
||||
hold on;
|
||||
for i = 1:8
|
||||
plot(wsvc, imag(polesvc(i, :)), 'b')
|
||||
plot(wsvc, imag(polesvcb(i, :)), 'r')
|
||||
end
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Imaginary Part');
|
10
matlab/src/computeSimultaneousDamping.m
Normal file
10
matlab/src/computeSimultaneousDamping.m
Normal file
@@ -0,0 +1,10 @@
|
||||
% =computeSimultaneousDamping=
|
||||
|
||||
function [xi_min] = computeSimultaneousDamping(g, G, K)
|
||||
[~, xi] = damp(minreal(feedback(G, g*K), [], false));
|
||||
xi_min = 1/min(xi);
|
||||
|
||||
if xi_min < 0
|
||||
xi_min = 1e8;
|
||||
end
|
||||
end
|
@@ -1,397 +0,0 @@
|
||||
%% Clear Workspace and Close figures
|
||||
clear; close all; clc;
|
||||
|
||||
%% Intialize Laplace variable
|
||||
s = zpk('s');
|
||||
|
||||
% Numerical Values for the NASS
|
||||
% Let's define the parameters for the NASS.
|
||||
|
||||
mlight = 35; % Mass for light sample [kg]
|
||||
mheavy = 85; % Mass for heavy sample [kg]
|
||||
|
||||
wlight = 2*pi; % Max rot. speed for light sample [rad/s]
|
||||
wheavy = 2*pi/60; % Max rot. speed for heavy sample [rad/s]
|
||||
|
||||
kvc = 1e3; % Voice Coil Stiffness [N/m]
|
||||
kpz = 1e8; % Piezo Stiffness [N/m]
|
||||
|
||||
wdot = 1; % Maximum rotation acceleration [rad/s2]
|
||||
|
||||
d = 0.01; % Maximum excentricity from rotational axis [m]
|
||||
ddot = 0.2; % Maximum Horizontal speed [m/s]
|
||||
|
||||
save('./mat/parameters.mat');
|
||||
|
||||
labels = {'Light sample mass [kg]', ...
|
||||
'Heavy sample mass [kg]', ...
|
||||
'Max rot. speed - light [rpm]', ...
|
||||
'Max rot. speed - heavy [rpm]', ...
|
||||
'Voice Coil Stiffness [N/m]', ...
|
||||
'Piezo Stiffness [N/m]', ...
|
||||
'Max rot. acceleration [rad/s2]', ...
|
||||
'Max mass excentricity [m]', ...
|
||||
'Max Horizontal speed [m/s]'};
|
||||
data = [mlight, mheavy, 60*wlight/2/pi, 60*wheavy/2/pi, kvc, kpz, wdot, d, ddot];
|
||||
data2orgtable(data', labels, {}, ' %.1e ')
|
||||
|
||||
% Euler and Coriolis forces - Numerical Result
|
||||
% First we will determine the value for Euler and Coriolis forces during regular experiment.
|
||||
% - *Euler forces*: $m d_v \ddot{\theta}$
|
||||
% - *Coriolis forces*: $2 m \dot{d_v} \dot{\theta}$
|
||||
|
||||
|
||||
Felight = mlight*d*wdot;
|
||||
Feheavy = mheavy*d*wdot;
|
||||
|
||||
Fclight = 2*mlight*ddot*wlight;
|
||||
Fcheavy = 2*mheavy*ddot*wheavy;
|
||||
|
||||
|
||||
|
||||
% The obtained values are displayed in table [[tab:euler_coriolis]].
|
||||
|
||||
|
||||
data = [Fclight, Fcheavy ;
|
||||
Felight, Feheavy];
|
||||
data2orgtable(data, {'Coriolis', 'Euler'}, {'Light', 'Heavy'}, ' %.1fN ')
|
||||
|
||||
% Negative Spring Effect - Numerical Result
|
||||
% The negative stiffness due to the rotation is equal to $-m{\omega_0}^2$.
|
||||
|
||||
|
||||
Klight = mlight*wlight^2;
|
||||
Kheavy = mheavy*wheavy^2;
|
||||
|
||||
|
||||
|
||||
% The values for the negative spring effect are displayed in table [[tab:negative_spring]].
|
||||
|
||||
% This is definitely negligible when using piezoelectric actuators. It may not be the case when using voice coil actuators.
|
||||
|
||||
|
||||
data = [Klight, Kheavy];
|
||||
data2orgtable(data, {'Neg. Spring'}, {'Light', 'Heavy'}, ' %.1f[N/m] ')
|
||||
|
||||
% Numerical Analysis
|
||||
% We plot on the same graph $\frac{|-m \omega^2 + (k - m {\omega_0}^2)|}{|2 m \omega_0 \omega|}$ for the voice coil and the piezo:
|
||||
% - with the light sample (figure [[fig:coupling_light]]).
|
||||
% - with the heavy sample (figure [[fig:coupling_heavy]]).
|
||||
|
||||
|
||||
f = logspace(-1, 3, 1000);
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, abs(-mlight*(2*pi*f).^2 + kvc - mlight * wlight^2)./abs(2*mlight*wlight*2*pi*f), 'DisplayName', 'Voice Coil')
|
||||
plot(f, abs(-mlight*(2*pi*f).^2 + kpz - mlight * wlight^2)./abs(2*mlight*wlight*2*pi*f), 'DisplayName', 'Piezo')
|
||||
plot(f, ones(1, length(f)), 'k--', 'HandleVisibility', 'off')
|
||||
hold off;
|
||||
xlim([f(1), f(end)]);
|
||||
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
||||
xlabel('Frequency [Hz]');
|
||||
legend('Location', 'northeast');
|
||||
|
||||
|
||||
|
||||
% #+LABEL: fig:coupling_light
|
||||
% #+CAPTION: Relative Coupling for light mass and high rotation speed
|
||||
% [[file:./figs/coupling_light.png]]
|
||||
|
||||
|
||||
figure;
|
||||
hold on;
|
||||
plot(f, abs(-mheavy*(2*pi*f).^2 + kvc - mheavy * wheavy^2)./abs(2*mheavy*wheavy*2*pi*f), 'DisplayName', 'Voice Coil')
|
||||
plot(f, abs(-mheavy*(2*pi*f).^2 + kpz - mheavy * wheavy^2)./abs(2*mheavy*wheavy*2*pi*f), 'DisplayName', 'Piezo')
|
||||
plot(f, ones(1, length(f)), 'k--', 'HandleVisibility', 'off')
|
||||
hold off;
|
||||
xlim([f(1), f(end)]);
|
||||
set(gca, 'xscale', 'log'); set(gca, 'yscale', 'log');
|
||||
xlabel('Frequency [Hz]');
|
||||
legend('Location', 'northeast');
|
||||
|
||||
% Limitations due to negative stiffness effect
|
||||
% If $\max{\dot{\theta}} \ll \sqrt{\frac{k}{m}}$, then the negative spring effect is negligible and $k - m\dot{\theta}^2 \approx k$.
|
||||
|
||||
% Let's estimate what is the maximum rotation speed for which the negative stiffness effect is still negligible ($\omega_\text{max} = 0.1 \sqrt{\frac{k}{m}}$). Results are shown table [[tab:negative_stiffness]].
|
||||
|
||||
data = 0.1*60*(1/2/pi)*[sqrt(kvc/mlight), sqrt(kpz/mlight);
|
||||
sqrt(kvc/mheavy), sqrt(kpz/mheavy)];
|
||||
data2orgtable(data, {'Light', 'Heavy'}, {'Voice Coil', 'Piezo'}, ' %.0f[rpm] ')
|
||||
|
||||
|
||||
|
||||
% #+NAME: tab:negative_stiffness
|
||||
% #+CAPTION: Maximum rotation speed at which negative stiffness is negligible ($0.1\sqrt{\frac{k}{m}}$)
|
||||
% #+RESULTS:
|
||||
% | | Voice Coil | Piezo |
|
||||
% |-------+------------+-----------|
|
||||
% | Light | 5[rpm] | 1614[rpm] |
|
||||
% | Heavy | 3[rpm] | 1036[rpm] |
|
||||
|
||||
% The negative spring effect is proportional to the rotational speed $\omega$.
|
||||
% The system dynamics will be much more affected when using soft actuator.
|
||||
|
||||
% #+begin_important
|
||||
% Negative stiffness effect has very important effect when using soft actuators.
|
||||
% #+end_important
|
||||
|
||||
% The system can even goes unstable when $m \omega^2 > k$, that is when the centrifugal forces are higher than the forces due to stiffness.
|
||||
|
||||
% From this analysis, we can determine the lowest practical stiffness that is possible to use: $k_\text{min} = 10 m \omega^2$ (table sec:tab:min_k)
|
||||
|
||||
|
||||
data = 10*[mlight*2*pi, mheavy*2*pi/60]
|
||||
data2orgtable(data, {'k min [N/m]'}, {'Light', 'Heavy'}, ' %.0f ')
|
||||
|
||||
% Voice coil actuator
|
||||
|
||||
m = mlight;
|
||||
k = kvc;
|
||||
|
||||
ws = linspace(0, 2*pi, 5); % Rotation speed vector [rad/s]
|
||||
|
||||
Gs = {zeros(1, length(ws))};
|
||||
Gcs = {zeros(1, length(ws))};
|
||||
|
||||
for i = 1:length(ws)
|
||||
w = ws(i);
|
||||
Gs(i) = {(m*s^2 + (k-m*w^2))/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2)};
|
||||
Gcs(i) = {(2*m*w*s)/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2)};
|
||||
end
|
||||
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}, freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}, freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'southwest');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
|
||||
|
||||
% #+LABEL: fig:G_ws_vc
|
||||
% #+CAPTION: Bode plot of the direct transfer function term (from $F_u$ to $D_u$) for multiple rotation speed - Voice coil
|
||||
% [[file:figs/G_ws_vc.png]]
|
||||
|
||||
|
||||
|
||||
freqs = logspace(-2, 1, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gcs{i}, freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gcs{i}, freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'southwest');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Piezoelectric actuator
|
||||
|
||||
m = mlight;
|
||||
k = kpz;
|
||||
|
||||
ws = linspace(0, 2*pi, 5); % Rotation speed vector [rad/s]
|
||||
|
||||
Gs = {zeros(1, length(ws))};
|
||||
Gcs = {zeros(1, length(ws))};
|
||||
|
||||
for i = 1:length(ws)
|
||||
w = ws(i);
|
||||
Gs(i) = {(m*s^2 + (k-m*w^2))/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2)};
|
||||
Gcs(i) = {(2*m*w*s)/((m*s^2 + (k - m*w^2))^2 + (2*m*w*s)^2)};
|
||||
end
|
||||
|
||||
freqs = logspace(2, 3, 1000);
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gs{i}, freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gs{i}, freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'southwest');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
|
||||
|
||||
% #+LABEL: fig:G_ws_pz
|
||||
% #+CAPTION: Bode plot of the direct transfer function term (from $F_u$ to $D_u$) for multiple rotation speed - Piezoelectric actuator
|
||||
% [[file:figs/G_ws_pz.png]]
|
||||
|
||||
|
||||
figure;
|
||||
ax1 = subplot(2,1,1);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, abs(squeeze(freqresp(Gcs{i}, freqs, 'Hz'))));
|
||||
end
|
||||
hold off;
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
|
||||
set(gca, 'XTickLabel',[]);
|
||||
ylabel('Magnitude [m/N]');
|
||||
|
||||
ax2 = subplot(2,1,2);
|
||||
hold on;
|
||||
for i = 1:length(ws)
|
||||
plot(freqs, 180/pi*angle(squeeze(freqresp(Gcs{i}, freqs, 'Hz'))), 'DisplayName', sprintf('w = %.0f [rpm]', ws(i)*60/2/pi));
|
||||
end
|
||||
hold off;
|
||||
yticks(-180:90:180);
|
||||
ylim([-180 180]);
|
||||
xlim([freqs(1), freqs(end)]);
|
||||
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
|
||||
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
|
||||
legend('Location', 'southwest');
|
||||
linkaxes([ax1,ax2],'x');
|
||||
|
||||
% Campbell diagram
|
||||
% The poles of the system are computed for multiple values of the rotation frequency. To simplify the computation of the poles, we add some damping to the system.
|
||||
|
||||
|
||||
m = mlight;
|
||||
k = kvc;
|
||||
c = 0.1*sqrt(k*m);
|
||||
|
||||
wsvc = linspace(0, 10, 100); % [rad/s]
|
||||
|
||||
polesvc = zeros(2, length(wsvc));
|
||||
|
||||
for i = 1:length(wsvc)
|
||||
polei = pole(1/((m*s^2 + c*s + (k - m*wsvc(i)^2))^2 + (2*m*wsvc(i)*s)^2));
|
||||
polesvc(:, i) = sort(polei(imag(polei) > 0));
|
||||
end
|
||||
|
||||
m = mlight;
|
||||
k = kpz;
|
||||
c = 0.1*sqrt(k*m);
|
||||
|
||||
wspz = linspace(0, 1000, 100); % [rad/s]
|
||||
|
||||
polespz = zeros(2, length(wspz));
|
||||
|
||||
for i = 1:length(wspz)
|
||||
polei = pole(1/((m*s^2 + c*s + (k - m*wspz(i)^2))^2 + (2*m*wspz(i)*s)^2));
|
||||
polespz(:, i) = sort(polei(imag(polei) > 0));
|
||||
end
|
||||
|
||||
|
||||
|
||||
% We then plot the real and imaginary part of the poles as a function of the rotation frequency (figures [[fig:poles_w_vc]] and [[fig:poles_w_pz]]).
|
||||
|
||||
% When the real part of one pole becomes positive, the system goes unstable.
|
||||
|
||||
% For the voice coil (figure [[fig:poles_w_vc]]), the system is unstable when the rotation speed is above 5 rad/s. The real and imaginary part of the poles of the system with piezoelectric actuators are changing much less (figure [[fig:poles_w_pz]]).
|
||||
|
||||
|
||||
figure;
|
||||
% Amplitude
|
||||
ax1 = subplot(1,2,1);
|
||||
hold on;
|
||||
plot(wsvc, real(polesvc(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wsvc, real(polesvc(2, :)))
|
||||
plot(wsvc, zeros(size(wsvc)), 'k--')
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Real Part');
|
||||
ax2 = subplot(1,2,2);
|
||||
hold on;
|
||||
plot(wsvc, imag(polesvc(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wsvc, -imag(polesvc(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wsvc, imag(polesvc(2, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wsvc, -imag(polesvc(2, :)))
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Imaginary Part');
|
||||
|
||||
|
||||
|
||||
% #+LABEL: fig:poles_w_vc
|
||||
% #+CAPTION: Real and Imaginary part of the poles of the system as a function of the rotation speed - Voice Coil and light sample
|
||||
% [[file:figs/poles_w_vc.png]]
|
||||
|
||||
|
||||
|
||||
figure;
|
||||
% Amplitude
|
||||
ax1 = subplot(1,2,1);
|
||||
hold on;
|
||||
plot(wspz, real(polespz(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wspz, real(polespz(2, :)))
|
||||
plot(wspz, zeros(size(wspz)), 'k--')
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Real Part');
|
||||
ax2 = subplot(1,2,2);
|
||||
hold on;
|
||||
plot(wspz, imag(polespz(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wspz, -imag(polespz(1, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wspz, imag(polespz(2, :)))
|
||||
set(gca,'ColorOrderIndex',1)
|
||||
plot(wspz, -imag(polespz(2, :)))
|
||||
hold off;
|
||||
xlabel('Rotation Frequency [rad/s]');
|
||||
ylabel('Pole Imaginary Part');
|
Reference in New Issue
Block a user