phd-nass-rotating-3dof-model/matlab/rotating_7_nano_hexapod.m

1206 lines
52 KiB
Mathematica
Raw Normal View History

2023-02-28 14:09:18 +01:00
%% 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';
% Identify NASS dynamics :noexport:
% First, the dynamics is identified for all the considered cases.
%% 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; % [Fu, Fv]
io(io_i) = linio([mdl, '/fd'], 1, 'openinput'); io_i = io_i + 1; % [Fdx, Fdy]
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]
%% 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'};
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'};
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'};
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'};
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'};
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'};
G_pz_fast.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
% Nano-Active-Stabilization-System - Plant Dynamics
% For the NASS, the maximum rotating velocity is $\Omega = \SI[parse-numbers=false]{2\pi}{\radian\per\s}$ for a suspended mass on top of the nano-hexapod's actuators equal to $m_n + m_s = \SI{16}{\kilo\gram}$.
% The parallel stiffness corresponding to the centrifugal forces is $m \Omega^2 \approx \SI{0.6}{\newton\per\mm}$.
%% Compute negative spring in [N/m]
Kneg_light = (15+1)*(2*pi)^2;
% The transfer functions from nano-hexapod actuator force $F_u$ to the displacement of the nano-hexapod in the same direction $d_u$ as well as in the orthogonal direction $d_v$ (coupling) are shown in Figure ref:fig:rotating_nano_hexapod_dynamics for all three considered nano-hexapod stiffnesses.
% #+begin_important
% It is shown that the rotation has the largest effect on the soft nano-hexapod:
% - larger coupling (the ratio of the coupling term to the direct term is larger for the sort nano-hexapod)
% - larger shift of poles as a function of the rotating velocity
% #+end_important
%% Effect of rotation on the nano-hexapod dynamics
freqs = logspace(0, 3, 1000);
figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(G_vc_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(1,:), ...
'DisplayName', '$k_n = 0.01\,N/\mu m$');
plot(freqs, abs(squeeze(freqresp(G_vc_fast( 'Du', 'Fu'), freqs, 'Hz'))), '-' , 'color', colors(1,:), ...
'DisplayName', '$\Omega = 60\,$rpm, $D_u/F_u$');
plot(freqs, abs(squeeze(freqresp(G_vc_fast( 'Dv', 'Fu'), freqs, 'Hz'))), '-' , 'color', [colors(1,:), 0.5], ...
'DisplayName', '$\Omega = 60\,$rpm, $D_v/F_u$');
plot(freqs, abs(squeeze(freqresp(G_md_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(2,:), ...
'DisplayName', '$k_n = 1\,N/\mu m$');
plot(freqs, abs(squeeze(freqresp(G_md_fast( 'Du', 'Fu'), freqs, 'Hz'))), '-' , 'color', colors(2,:), ...
'DisplayName', '$\Omega = 60\,$rpm, $D_u/F_u$');
plot(freqs, abs(squeeze(freqresp(G_md_fast( 'Dv', 'Fu'), freqs, 'Hz'))), '-' , 'color', [colors(2,:), 0.5], ...
'DisplayName', '$\Omega = 60\,$rpm, $D_v/F_u$');
plot(freqs, abs(squeeze(freqresp(G_pz_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(3,:), ...
'DisplayName', '$k_n = 100\,N/\mu m$');
plot(freqs, abs(squeeze(freqresp(G_pz_fast( 'Du', 'Fu'), freqs, 'Hz'))), '-' , 'color', colors(3,:), ...
'DisplayName', '$\Omega = 60\,$rpm, $D_u/F_u$');
plot(freqs, abs(squeeze(freqresp(G_pz_fast( 'Dv', 'Fu'), freqs, 'Hz'))), '-' , 'color', [colors(3,:), 0.5], ...
'DisplayName', '$\Omega = 60\,$rpm, $D_v/F_u$');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Magnitude [m/N]'); set(gca, 'XTickLabel',[]);
ylim([1e-12, 1e-2])
ldg = legend('location', 'northeast', 'FontSize', 8, 'NumColumns', 3);
ldg.ItemTokenSize = [20, 1];
ax2 = nexttile;
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(G_vc_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(1,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_vc_fast( 'Du', 'Fu'), freqs, 'Hz'))), '-' , 'color', colors(1,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_md_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(2,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_md_fast( 'Du', 'Fu'), freqs, 'Hz'))), '-' , 'color', colors(2,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_pz_norot('Du', 'Fu'), freqs, 'Hz'))), '--', 'color', colors(3,:));
plot(freqs, 180/pi*angle(squeeze(freqresp(G_pz_fast( 'Du', 'Fu'), freqs, '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([-180, 0]);
linkaxes([ax1,ax2],'x');
xlim([1, 1e3]);
% Coupling :noexport:
% Let's define the /coupling ratio/ $\mathcal{C}$ in the system as the ratio of the magnitude of the coupling term $G_c$ to the magnitude of the direct term $G_d$:
% \begin{equation}
% \mathcal{C}(\omega) = \frac{|G_c(j\omega)|}{|G_d(j\omega)|}
% \end{equation}
% This gives some information in the coupling in the system.
% This is quite important as high coupling can affect the closed-loop stability.
% The coupling ratio for the three nano-hexapod stiffnesses are shown in Figure ref:fig:rotating_coupling_ratio_nano_hexapod for the maximum rotating velocity $\Omega = 60\,\text{rpm}$.
% #+begin_important
% It is shown that the low frequency coupling is inversely proportional to the nano-hexapod stiffness (Figure ref:fig:rotating_coupling_ratio_nano_hexapod).
% High nano-hexapod stiffness makes the system better decoupled and therefore easier to control.
% #+end_important
%% Coupling ratio of the nano-hexapod at maximum velocity
figure;
tiledlayout(1, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
hold on;
plot(freqs, abs(squeeze(freqresp(G_vc_fast('Dv', 'Fu')/G_vc_fast('Du', 'Fu'), freqs, 'Hz'))), ...
'DisplayName', '$k_n = 0.01\,N/\mu m$');
plot(freqs, abs(squeeze(freqresp(G_md_fast('Dv', 'Fu')/G_md_fast('Du', 'Fu'), freqs, 'Hz'))), ...
'DisplayName', '$k_n = 1\,N/\mu m$');
plot(freqs, abs(squeeze(freqresp(G_pz_fast('Dv', 'Fu')/G_pz_fast('Du', 'Fu'), freqs, 'Hz'))), ...
'DisplayName', '$k_n = 100\,N/\mu m$');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('Coupling ratio');
xlim([1, 500]);
legend('location', 'southeast', 'FontSize', 8, 'NumColumns', 1);
% Optimal IFF with High Pass Filter
% Let's apply Integral Force Feedback with an added High Pass Filter to the three nano-hexapods.
% First, let's find the parameters of the IFF controller that yield best simultaneous damping.
% The results are shown in Figure ref:fig:rotating_iff_hpf_nass_optimal_gain.
% The added damping for the soft nano-hexapod is quite low and is limited by the maximum usable gain.
%% Compute the optimal control gain
wis = logspace(-2, 3, 200); % [rad/s]
opt_iff_hpf_xi_vc = zeros(1, length(wis)); % Optimal simultaneous damping
opt_iff_hpf_gain_vc = zeros(1, length(wis)); % Corresponding optimal gain
opt_iff_hpf_xi_md = zeros(1, length(wis)); % Optimal simultaneous damping
opt_iff_hpf_gain_md = zeros(1, length(wis)); % Corresponding optimal gain
opt_iff_hpf_xi_pz = zeros(1, length(wis)); % Optimal simultaneous damping
opt_iff_hpf_gain_pz = 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, G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_hpf_xi_vc(wi_i) = 1/xi_opt;
opt_iff_hpf_gain_vc(wi_i) = g_opt;
fun = @(g)computeSimultaneousDamping(g, G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_hpf_xi_md(wi_i) = 1/xi_opt;
opt_iff_hpf_gain_md(wi_i) = g_opt;
fun = @(g)computeSimultaneousDamping(g, G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_hpf_xi_pz(wi_i) = 1/xi_opt;
opt_iff_hpf_gain_pz(wi_i) = g_opt;
end
%% Optimal modified IFF parameters that yields maximum simultaneous damping
figure;
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
yyaxis left
plot(wis, opt_iff_hpf_xi_vc, '-', 'DisplayName', '$\xi_{cl}$');
set(gca, 'YScale', 'lin');
ylim([0,1]);
ylabel('Damping Ratio $\xi$');
yyaxis right
hold on;
plot(wis, opt_iff_hpf_gain_vc, '-', 'DisplayName', '$g_{opt}$');
plot(wis, wis*((sqrt(1e4/16)/(2*pi))^2 - 1), '--', 'DisplayName', '$g_{max}$');
set(gca, 'YScale', 'lin');
ylim([0,200]);
xlabel('$\omega_i$ [rad/s]');
set(gca, 'YTickLabel',[]);
% ylabel('Controller gain $g$');
set(gca, 'XScale', 'log');
xticks([1e-2,1,1e2])
legend('location', 'northwest', 'FontSize', 8);
title('$k_n = 0.01\,N/\mu m$');
ax2 = nexttile();
yyaxis left
plot(wis, opt_iff_hpf_xi_md, '-');
set(gca, 'YScale', 'lin');
ylim([0,1]);
% ylabel('Damping Ratio $\xi$');
set(gca, 'YTickLabel',[]);
yyaxis right
hold on;
plot(wis, opt_iff_hpf_gain_md, '-');
plot(wis, wis*((sqrt(1e6/16)/(2*pi))^2 - 1), '--');
set(gca, 'YScale', 'lin');
ylim([0,1000]);
xlabel('$\omega_i$ [rad/s]');
% ylabel('Controller gain $g$');
set(gca, 'YTickLabel',[]);
set(gca, 'XScale', 'log');
xticks([1e-2,1,1e2])
title('$k_n = 1\,N/\mu m$');
ax3 = nexttile();
yyaxis left
plot(wis, opt_iff_hpf_xi_pz, '-');
set(gca, 'YScale', 'lin');
ylim([0,1]);
set(gca, 'YTickLabel',[]);
% ylabel('Damping Ratio $\xi$');
yyaxis right
hold on;
plot(wis, opt_iff_hpf_gain_pz, '-');
plot(wis, wis*((sqrt(1e8/16)/(2*pi))^2 - 1), '--');
set(gca, 'YScale', 'lin');
ylim([0,10000]);
xlabel('$\omega_i$ [rad/s]');
set(gca, 'YTickLabel',[]);
ylabel('Controller gain $g$');
set(gca, 'XScale', 'log');
xticks([1e-2,1,1e2])
title('$k_n = 100\,N/\mu m$');
% #+name: fig:rotating_iff_hpf_nass_optimal_gain
% #+caption: Optimal high pass filter cut-off frequency $\omega_i$ that yields maximum simultaneous damping
% #+RESULTS:
% [[file:figs/rotating_iff_hpf_nass_optimal_gain.png]]
% The IFF parameters are chosen as follow:
% - for $k_n = \SI{0.01}{\N\per\mu\m}$: $\omega_i$ is chosen such that the maximum damping is achieved while the gain is less than half of the maximum gain at which the system is unstable.
% This is done to have some control robustness.
% - for $k_n = \SI{1}{\N\per\mu\m}$ and $k_n = \SI{100}{\N\per\mu\m}$: the largest $\omega_i$ is chosen such that obtained damping is $\SI{95}{\percent}$ of the maximum achievable damping.
% Large $\omega_i$ is chosen here to limit the loss of compliance and the increase of coupling at low frequency as was shown in Section ref:sec:rotating_iff_pseudo_int.
% The obtained IFF parameters and the achievable damping are summarized in Table ref:tab:iff_hpf_opt_iff_hpf_params_nass.
%% Find optimal parameters with at least a gain margin of 2
i_iff_hpf_vc = find(opt_iff_hpf_gain_vc < 0.5*(wis*((sqrt(1e4/16)/(2*pi))^2 - 1)));
i_iff_hpf_vc = i_iff_hpf_vc(1);
i_iff_hpf_md = find(opt_iff_hpf_xi_md > 0.95*max(opt_iff_hpf_xi_md));
i_iff_hpf_md = i_iff_hpf_md(end)+1;
i_iff_hpf_pz = find(opt_iff_hpf_xi_pz > 0.95*max(opt_iff_hpf_xi_pz));
i_iff_hpf_pz = i_iff_hpf_pz(end)+1;
% #+name: tab:iff_hpf_opt_iff_hpf_params_nass
% #+caption: Obtained optimal parameters for the modified IFF controller
% #+attr_latex: :environment tabularx :width 0.5\linewidth :align lXXX
% #+attr_latex: :center t :booktabs t
% #+RESULTS:
% | | $\omega_i$ | $g$ | $\xi$ |
% |-----------------------+------------+---------+-------|
% | $k_n = 0.01\,N/\mu m$ | 7.32 | 51.13 | 0.45 |
% | $k_n = 1\,N/\mu m$ | 39.17 | 426.95 | 0.93 |
% | $k_n = 100\,N/\mu m$ | 499.45 | 3774.63 | 0.94 |
% The Root Locus for all three nano-hexapods are shown in Figure ref:fig:rotating_root_locus_iff_hpf_nass with included optimal chosen gains.
%% Optimal IFF with added HPF
Kiff_hpf_vc = opt_iff_hpf_gain_vc(i_iff_hpf_vc)/(s + wis(i_iff_hpf_vc))*eye(2);
Kiff_hpf_vc.InputName = {'fu', 'fv'};
Kiff_hpf_vc.OutputName = {'Fu', 'Fv'};
Kiff_hpf_md = opt_iff_hpf_gain_md(i_iff_hpf_md)/(s + wis(i_iff_hpf_md))*eye(2);
Kiff_hpf_md.InputName = {'fu', 'fv'};
Kiff_hpf_md.OutputName = {'Fu', 'Fv'};
Kiff_hpf_pz = opt_iff_hpf_gain_pz(i_iff_hpf_pz)/(s + wis(i_iff_hpf_pz))*eye(2);
Kiff_hpf_pz.InputName = {'fu', 'fv'};
Kiff_hpf_pz.OutputName = {'Fu', 'Fv'};
%% Root Locus for optimal parameters - Comparison of attainable damping with the soft and moderately stiff nano-hexapods
gains = logspace(-2, 3, 200);
figure;
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
% Voice coil Nano-Hexapod
ax1 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 0$');
plot(real(pole(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
imag(pole(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
'x', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
imag(tzero(G_vc_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
'o', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
for g = gains
clpoles = pole(feedback(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 60$ rpm');
plot(real(pole(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
imag(pole(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
'x', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
imag(tzero(G_vc_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_vc)), ...
'o', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot([0, -1e2*opt_iff_hpf_xi_vc(i_iff_hpf_vc)], [0, 1e2*cos(asin(opt_iff_hpf_xi_vc(i_iff_hpf_vc)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_hpf_xi_vc(i_iff_hpf_vc)), 'color', [zeros(1,3), 0.5])
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-65, 5]); ylim([-35, 35]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 0.01\,N/\mu m$');
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
ldg.ItemTokenSize = [10, 1];
% APA Nano-Hexapod
ax2 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
imag(pole(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
imag(tzero(G_md_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
for g = gains
clpoles = pole(feedback(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
imag(pole(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
imag(tzero(G_md_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_md)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e3*opt_iff_hpf_xi_md(i_iff_hpf_md)], [0, 1e3*cos(asin(opt_iff_hpf_xi_md(i_iff_hpf_md)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_hpf_xi_md(i_iff_hpf_md)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-520, 20]); ylim([-270, 270]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 1\,N/\mu m$');
% Piezo Nano-Hexapod
ax3 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
imag(pole(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
imag(tzero(G_pz_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
for g = gains
clpoles = pole(feedback(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_hpf_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_hpf_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
imag(pole(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
imag(tzero(G_pz_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_hpf_pz)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e4*opt_iff_hpf_xi_pz(i_iff_hpf_pz)], [0, 1e4*cos(asin(opt_iff_hpf_xi_pz(i_iff_hpf_pz)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_hpf_xi_pz(i_iff_hpf_pz)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-5200, 20]); ylim([-2700, 2700]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 100\,N/\mu m$');
% Optimal IFF with Parallel Stiffness
% For each considered nano-hexapod stiffness, the parallel stiffness $k_p$ is varied from $k_{p,\text{min}} = m\Omega^2$ (the minimum stiffness to have unconditional stability) to $k_{p,\text{max}} = k_n$ (the total nano-hexapod stiffness).
% In order to keep the overall stiffness constant, the actuator stiffness $k_a$ is decreased when $k_p$ is increased:
% \begin{equation}
% k_a = k_n - k_p
% \end{equation}
% With $k_n$ the total nano-hexapod stiffness.
% An high pass filter is also added to limit the low frequency gain.
% The cut-off frequency $\omega_i$ is chosen to be one tenth of the system resonance:
% \begin{equation}
% \omega_i = \omega_0/10
% \end{equation}
%% Maximum rotating velocity
Wz = 2*pi; % [rad/s]
%% Minimum parallel stiffness
kp_min = (mn + ms) * Wz^2; % [N/m]
%% Parameters for simulation
mn = 15; % Nano-Hexapod mass [kg]
ms = 1; % Sample Mass [kg]
%% IFF Controller
Kiff_vc = 1/(s + 0.1*sqrt(1e4/(mn+ms)))*eye(2); % IFF
Kiff_md = 1/(s + 0.1*sqrt(1e6/(mn+ms)))*eye(2); % IFF
Kiff_pz = 1/(s + 0.1*sqrt(1e8/(mn+ms)))*eye(2); % IFF
%% General Configuration
model_config = struct();
model_config.controller = "open_loop"; % Default: Open-Loop
model_config.Tuv_type = "parallel_k"; % Default: 2DoF stage
%% Computes the optimal parameters and attainable simultaneous damping - Voice Coil nano-hexapod
kps_vc = logspace(log10(kp_min), log10(1e4), 100); % Tested parallel stiffnesses [N/m]
kps_vc(end) = [];
opt_iff_kp_xi_vc = zeros(1, length(kps_vc)); % Optimal simultaneous damping
opt_iff_kp_gain_vc = zeros(1, length(kps_vc)); % Corresponding optimal gain
for kp_i = 1:length(kps_vc)
% Voice Coil Nano-Hexapod
kp = kps_vc(kp_i);
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
Giff_vc = linearize(mdl, io, 0);
Giff_vc.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
Giff_vc.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
fun = @(g)computeSimultaneousDamping(g, Giff_vc({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_vc);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_kp_xi_vc(kp_i) = 1/xi_opt;
opt_iff_kp_gain_vc(kp_i) = g_opt;
end
%% Computes the optimal parameters and attainable simultaneous damping - APA nano-hexapod
kps_md = logspace(log10(kp_min), log10(1e6), 100); % Tested parallel stiffnesses [N/m]
kps_md(end) = [];
opt_iff_kp_xi_md = zeros(1, length(kps_md)); % Optimal simultaneous damping
opt_iff_kp_gain_md = zeros(1, length(kps_md)); % Corresponding optimal gain
for kp_i = 1:length(kps_md)
% Voice Coil Nano-Hexapod
kp = kps_md(kp_i);
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
Giff_md = linearize(mdl, io, 0);
Giff_md.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
Giff_md.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
fun = @(g)computeSimultaneousDamping(g, Giff_md({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_md);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_kp_xi_md(kp_i) = 1/xi_opt;
opt_iff_kp_gain_md(kp_i) = g_opt;
end
%% Computes the optimal parameters and attainable simultaneous damping - Piezo nano-hexapod
kps_pz = logspace(log10(kp_min), log10(1e8), 100); % Tested parallel stiffnesses [N/m]
kps_pz(end) = [];
opt_iff_kp_xi_pz = zeros(1, length(kps_pz)); % Optimal simultaneous damping
opt_iff_kp_gain_pz = zeros(1, length(kps_pz)); % Corresponding optimal gain
for kp_i = 1:length(kps_pz)
% Voice Coil Nano-Hexapod
kp = kps_pz(kp_i);
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
Giff_pz = linearize(mdl, io, 0);
Giff_pz.InputName = {'Fu', 'Fv', 'Fdx', 'Fdy', 'Dfx', 'Dfy'};
Giff_pz.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
fun = @(g)computeSimultaneousDamping(g, Giff_pz({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_pz);
[g_opt, xi_opt] = fminsearch(fun, 0.1);
opt_iff_kp_xi_pz(kp_i) = 1/xi_opt;
opt_iff_kp_gain_pz(kp_i) = g_opt;
end
% The achievable maximum simultaneous damping of all the modes is computed as a function of the parallel stiffnesses.
% The comparison for the nano-hexapod stiffnesses is done in Figure ref:fig:rotating_iff_kp_nass_optimal_gain.
% It is shown that *the soft nano-hexapod cannot yield good damping*.
% For the two stiff options, the achievable damping starts to significantly decrease when the parallel stiffness is one tenth of the total stiffness $k_p = k_n/10$.
%% Optimal IFF gain and associated simultaneous damping as a function of the parallel stiffness
figure;
hold on;
plot(kps_vc, opt_iff_kp_xi_vc, '-', 'DisplayName', '$k_n = 0.01\,N/\mu m$');
plot(kps_md, opt_iff_kp_xi_md, '-', 'DisplayName', '$k_n = 1\,N/\mu m$');
plot(kps_pz, opt_iff_kp_xi_pz, '-', 'DisplayName', '$k_n = 100\,N/\mu m$');
hold off;
xlabel('$k_p [N/m]$');
ylabel('Damping Ratio $\xi$');
set(gca, 'XScale', 'log');
set(gca, 'YScale', 'lin');
ylim([0,1]);
legend('location', 'southeast', 'FontSize', 8);
xlim([kps_pz(1), kps_pz(end)])
% #+name: fig:rotating_iff_kp_nass_optimal_gain
% #+caption: Maximum achievable simultaneous damping with IFF as a function of the parallel stiffness for all three nano-hexapod stiffnesses
% #+RESULTS:
% [[file:figs/rotating_iff_kp_nass_optimal_gain.png]]
% Let's choose $k_p = \SI{e3}{\newton\per\m}$, $k_p = \SI{e4}{\newton\per\m}$ and $k_p = \SI{e6}{\newton\per\m}$ for the three considered nano-hexapods respectively based on Figure ref:fig:rotating_iff_kp_nass_optimal_gain.
% The corresponding optimal controller gains are shown in Table ref:tab:iff_kp_opt_iff_kp_params_nass.
%% Find result with wanted parallel stiffness
[~, i_kp_vc] = min(abs(kps_vc - 1e3));
[~, i_kp_md] = min(abs(kps_md - 1e4));
[~, i_kp_pz] = min(abs(kps_pz - 1e6));
% #+name: tab:iff_kp_opt_iff_kp_params_nass
% #+caption: Obtained optimal parameters for the modified IFF controller
% #+attr_latex: :environment tabularx :width 0.4\linewidth :align lXX
% #+attr_latex: :center t :booktabs t
% #+RESULTS:
% | | $g$ | $\xi_{\text{opt}}$ |
% |-----------------------+---------+--------------------|
% | $k_n = 0.01\,N/\mu m$ | 47.9 | 0.44 |
% | $k_n = 1\,N/\mu m$ | 465.57 | 0.97 |
% | $k_n = 100\,N/\mu m$ | 4624.25 | 1.0 |
% The root locus for the three nano-hexapod with parallel stiffnesses are shown in Figure ref:fig:rotating_root_locus_iff_kp_nass.
% #+begin_important
% Similarly to what was found with the IFF and added High Pass Filter:
% - the stiff nano-hexapod is less affected by the rotation than the soft one
% - the achievable damping is much larger with the stiff nano-hexapods
% #+end_important
%% Optimal IFF with added parallel stiffness
Kiff_kp_vc = opt_iff_kp_gain_vc(i_kp_vc)/(s + 0.1*sqrt(1e4/(ms+mn)))*eye(2);
Kiff_kp_vc.InputName = {'fu', 'fv'};
Kiff_kp_vc.OutputName = {'Fu', 'Fv'};
Kiff_kp_md = opt_iff_kp_gain_md(i_kp_md)/(s + 0.1*sqrt(1e6/(ms+mn)))*eye(2);
Kiff_kp_md.InputName = {'fu', 'fv'};
Kiff_kp_md.OutputName = {'Fu', 'Fv'};
Kiff_kp_pz = opt_iff_kp_gain_pz(i_kp_pz)/(s + 0.1*sqrt(1e8/(ms+mn)))*eye(2);
Kiff_kp_pz.InputName = {'fu', 'fv'};
Kiff_kp_pz.OutputName = {'Fu', 'Fv'};
%% Identify plant with optimal parallel stiffness - Soft nano-hexapod
kp = kps_vc(i_kp_vc);
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'};
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'};
G_vc_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
%% Identify plant with optimal parallel stiffness - Stiff nano-hexapod
kp = kps_md(i_kp_md);
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'};
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'};
G_md_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
%% Identify plant with optimal parallel stiffness - Stiff nano-hexapod
kp = kps_pz(i_kp_pz);
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'};
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'};
G_pz_kp_norot.OutputName = {'fu', 'fv', 'Du', 'Dv', 'Dx', 'Dy'};
%% Root Locus for optimal parameters - Comparison of attainable damping with the soft and moderately stiff nano-hexapods
gains = logspace(-2, 2, 400);
figure;
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
hold on;
% Soft Nano-Hexapod - No Rotation
for g = gains
clpoles = pole(feedback(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 0$');
plot(real(pole(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
imag(pole(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
'x', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
imag(tzero(G_vc_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
'o', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
% Soft Nano-Hexapod - High Speed Rotation
for g = gains
clpoles = pole(feedback(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 60$ rpm');
plot(real(pole(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
imag(pole(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
'x', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
imag(tzero(G_vc_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_vc)), ...
'o', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot([0, -1e2*opt_iff_kp_xi_vc(i_kp_vc)], [0, 1e2*cos(asin(opt_iff_kp_xi_vc(i_kp_vc)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_kp_xi_vc(i_kp_vc)), 'color', [zeros(1,3), 0.5]);
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-65, 5]); ylim([-35, 35]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 0.01\,N/\mu m$');
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
ldg.ItemTokenSize = [10, 1];
ax2 = nexttile();
hold on;
% Stiff Nano-Hexapod - No Rotation
for g = gains
clpoles = pole(feedback(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
imag(pole(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
imag(tzero(G_md_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
% Stiff Nano-Hexapod - High Speed Rotation
for g = gains
clpoles = pole(feedback(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
imag(pole(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
imag(tzero(G_md_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_md)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e3*opt_iff_kp_xi_md(i_kp_md)], [0, 1e3*cos(asin(opt_iff_kp_xi_md(i_kp_md)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_kp_xi_md(i_kp_md)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
xlim([-520, 20]); ylim([-270, 270]);
title('$k_n = 1\,N/\mu m$');
ax3 = nexttile();
hold on;
% Stiff Nano-Hexapod - No Rotation
for g = gains
clpoles = pole(feedback(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
imag(pole(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
imag(tzero(G_pz_kp_norot({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
% Stiff Nano-Hexapod - High Speed Rotation
for g = gains
clpoles = pole(feedback(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), g*Kiff_kp_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'}), Kiff_kp_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
imag(pole(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
imag(tzero(G_pz_kp_fast({'fu', 'fv'}, {'Fu', 'Fv'})*Kiff_kp_pz)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e4*opt_iff_kp_xi_pz(i_kp_pz)], [0, 1e4*cos(asin(opt_iff_kp_xi_pz(i_kp_pz)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', opt_iff_kp_xi_pz(i_kp_pz)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
xlim([-5200, 200]); ylim([-2700, 2700]);
title('$k_n = 100\,N/\mu m$');
% Optimal Relative Motion Control
% For each considered nano-hexapod stiffness, relative damping control is applied and the achievable damping ratio as a function of the controller gain is shown in Figure ref:fig:rotating_rdc_optimal_gain.
%% Computes the optimal parameters and attainable simultaneous damping - Piezo nano-hexapod
rdc_gains = 2*logspace(1, 5, 200);
% Obtained simultaneous damping
rdc_xi_vc = zeros(1, length(rdc_gains));
rdc_xi_md = zeros(1, length(rdc_gains));
rdc_xi_pz = zeros(1, length(rdc_gains));
Krdc = s*eye(2);
Krdc.InputName = {'Du', 'Dv'};
Krdc.OutputName = {'Fu', 'Fv'};
for g_i = 1:length(rdc_gains)
[~, xi] = damp(feedback(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), rdc_gains(g_i)*Krdc));
rdc_xi_vc(g_i) = min(xi);
[~, xi] = damp(feedback(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), rdc_gains(g_i)*Krdc));
rdc_xi_md(g_i) = min(xi);
[~, xi] = damp(feedback(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), rdc_gains(g_i)*Krdc));
rdc_xi_pz(g_i) = min(xi);
end
%% Optimal IFF gain and associated simultaneous damping as a function of the parallel stiffness
figure;
hold on;
plot(rdc_gains, rdc_xi_vc, '-', 'DisplayName', '$k_n = 0.01\,N/\mu m$');
plot(rdc_gains, rdc_xi_md, '-', 'DisplayName', '$k_n = 1\,N/\mu m$');
plot(rdc_gains, rdc_xi_pz, '-', 'DisplayName', '$k_n = 100\,N/\mu m$');
hold off;
xlabel('Relative Damping Controller gain $g$');
ylabel('Damping Ratio $\xi$');
set(gca, 'XScale', 'log');
set(gca, 'YScale', 'lin');
ylim([0,1]);
xlim([rdc_gains(1), rdc_gains(end)])
legend('location', 'southeast', 'FontSize', 8);
% #+name: fig:rotating_rdc_optimal_gain
% #+caption: Achievable simultaneous damping with "Relative Damping Control" as a function of the controller gain for all three nano-hexapod stiffnesses
% #+RESULTS:
% [[file:figs/rotating_rdc_optimal_gain.png]]
% The gain is chosen is chosen such that 99% of modal damping is obtained.
% The root locus for all three nano-hexapod stiffnesses are shown in Figure ref:fig:rotating_root_locus_rdc_nass.
% #+begin_important
% Relative damping control is much less impacted by gyroscopic effects.
% It can be easily applied on the nano-hexapod with and without rotation without much differences.
% #+end_important
%% Optimal RDC
[~, i_rdc_vc] = min(abs(rdc_xi_vc - 0.99));
[~, i_rdc_md] = min(abs(rdc_xi_md - 0.99));
[~, i_rdc_pz] = min(abs(rdc_xi_pz - 0.99));
Krdc_vc = rdc_gains(i_rdc_vc)*Krdc;
Krdc_md = rdc_gains(i_rdc_md)*Krdc;
Krdc_pz = rdc_gains(i_rdc_pz)*Krdc;
%% Root Locus for optimal parameters - Comparison of attainable damping with the soft and moderately strdc nano-hexapods
gains = logspace(-2, 3, 200);
figure;
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
% Voice coil Nano-Hexapod
ax1 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 0$');
plot(real(pole(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
imag(pole(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
'x', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
imag(tzero(G_vc_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
'o', 'color', colors(1,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
for g = gains
clpoles = pole(feedback(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4, ...
'HandleVisibility', 'off');
end
clpoles = pole(feedback(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_vc));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15, ...
'DisplayName', '$\Omega = 60$ rpm');
plot(real(pole(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
imag(pole(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
'x', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot(real(tzero(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
imag(tzero(G_vc_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_vc)), ...
'o', 'color', colors(2,:),'MarkerSize',8, ...
'HandleVisibility', 'off');
plot([0, -1e2*rdc_xi_vc(i_rdc_vc)], [0, 1e2*cos(asin(rdc_xi_vc(i_rdc_vc)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', rdc_xi_vc(i_rdc_vc)), 'color', [zeros(1,3), 0.5])
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-65, 5]); ylim([-35, 35]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 0.01\,N/\mu m$');
ldg = legend('location', 'northwest', 'FontSize', 8, 'NumColumns', 1);
ldg.ItemTokenSize = [10, 1];
% APA Nano-Hexapod
ax2 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
imag(pole(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
imag(tzero(G_md_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
for g = gains
clpoles = pole(feedback(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_md));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
imag(pole(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
imag(tzero(G_md_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_md)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e3*rdc_xi_md(i_rdc_md)], [0, 1e3*cos(asin(rdc_xi_md(i_rdc_md)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', rdc_xi_md(i_rdc_md)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-520, 20]); ylim([-270, 270]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 1\,N/\mu m$');
% Piezo Nano-Hexapod
ax3 = nexttile();
hold on;
for g = gains
clpoles = pole(feedback(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(1,:),'MarkerSize', 15);
plot(real(pole(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
imag(pole(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
'x', 'color', colors(1,:),'MarkerSize',8);
plot(real(tzero(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
imag(tzero(G_pz_norot({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
'o', 'color', colors(1,:),'MarkerSize',8);
for g = gains
clpoles = pole(feedback(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), g*Krdc_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize',4);
end
clpoles = pole(feedback(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'}), Krdc_pz));
plot(real(clpoles), imag(clpoles), '.', 'color', colors(2,:),'MarkerSize', 15);
plot(real(pole(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
imag(pole(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
'x', 'color', colors(2,:),'MarkerSize',8);
plot(real(tzero(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
imag(tzero(G_pz_fast({'Du', 'Dv'}, {'Fu', 'Fv'})*Krdc_pz)), ...
'o', 'color', colors(2,:),'MarkerSize',8);
L = plot([0, -1e4*rdc_xi_pz(i_rdc_pz)], [0, 1e4*cos(asin(rdc_xi_pz(i_rdc_pz)))], '-', ...
'DisplayName', sprintf('$\\xi = %.2f$', rdc_xi_pz(i_rdc_pz)), 'color', [zeros(1,3), 0.5]);
leg = legend(L, 'location', 'northwest', 'FontSize', 8);
leg.ItemTokenSize(1) = 10;
hold off;
axis square;
xlabel('Real Part'); ylabel('Imaginary Part');
xlim([-5200, 20]); ylim([-2700, 2700]);
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 100\,N/\mu m$');
%% 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');
%% Comparison of the damped plants (direct and coupling terms) for the three proposed active damping techniques (IFF with HPF, IFF with $k_p$ and RDC) applied on the three nano-hexapod stiffnesses
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( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [zeros(1,3)]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast( 'Dv', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [zeros(1,3), 0.5]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_hpf( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(1,:)]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_hpf( 'Dv', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(1,:), 0.5]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_kp( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(2,:)]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_iff_kp( 'Dv', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(2,:), 0.5]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_rdc( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(3,:)]);
plot(freqs_vc, abs(squeeze(freqresp(G_vc_fast_rdc( 'Dv', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(3,:), 0.5]);
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Magnitude [m/N]'); set(gca, 'XTickLabel',[]);
title('$k_n = 0.01\,N/\mu m$');
ax2 = nexttile([2,1]);
hold on;
plot(freqs_md, abs(squeeze(freqresp(G_md_fast( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [zeros(1,3)]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast( 'Dv', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [zeros(1,3), 0.5]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_hpf( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(1,:)]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_hpf( 'Dv', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(1,:), 0.5]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_kp( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(2,:)]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_iff_kp( 'Dv', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(2,:), 0.5]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_rdc( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(3,:)]);
plot(freqs_md, abs(squeeze(freqresp(G_md_fast_rdc( 'Dv', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(3,:), 0.5]);
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); set(gca, 'YTickLabel',[]);
title('$k_n = 1\,N/\mu m$');
ax3 = nexttile([2,1]);
hold on;
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [zeros(1,3)], ...
'DisplayName', 'OL');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast( 'Dv', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [zeros(1,3), 0.5], ...
'DisplayName', 'Coupling');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_hpf( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(1,:)], ...
'DisplayName', 'IFF + HPF');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_hpf( 'Dv', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(1,:), 0.5], ...
'HandleVisibility', 'off');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_kp( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(2,:)], ...
'DisplayName', 'IFF + $k_p$');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_iff_kp( 'Dv', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(2,:), 0.5], ...
'HandleVisibility', 'off');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_rdc( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(3,:)], ...
'DisplayName', 'RDC');
plot(freqs_pz, abs(squeeze(freqresp(G_pz_fast_rdc( 'Dv', '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', 'northwest', 'FontSize', 8, 'NumColumns', 1);
ldg.ItemTokenSize = [20, 1];
title('$k_n = 100\,N/\mu m$');
ax1b = nexttile;
hold on;
plot(freqs_vc, 180/pi*angle(squeeze(freqresp(G_vc_fast( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [zeros(1,3)]);
plot(freqs_vc, 180/pi*angle(squeeze(freqresp(G_vc_fast_iff_hpf( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(1,:)]);
plot(freqs_vc, 180/pi*angle(squeeze(freqresp(G_vc_fast_iff_kp( 'Du', 'Fu'), freqs_vc, 'Hz'))), '-' , 'color', [colors(2,:)]);
plot(freqs_vc, 180/pi*angle(squeeze(freqresp(G_vc_fast_rdc( 'Du', '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([-180, 180]);
xlim([freqs_vc(1), freqs_vc(end)]);
ax2b = nexttile;
hold on;
plot(freqs_md, 180/pi*angle(squeeze(freqresp(G_md_fast( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [zeros(1,3)]);
plot(freqs_md, 180/pi*angle(squeeze(freqresp(G_md_fast_iff_hpf( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(1,:)]);
plot(freqs_md, 180/pi*angle(squeeze(freqresp(G_md_fast_iff_kp( 'Du', 'Fu'), freqs_md, 'Hz'))), '-' , 'color', [colors(2,:)]);
plot(freqs_md, 180/pi*angle(squeeze(freqresp(G_md_fast_rdc( 'Du', '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([-180, 180]);
xlim([freqs_md(1), freqs_md(end)]);
ax3b = nexttile;
hold on;
plot(freqs_pz, 180/pi*angle(squeeze(freqresp(G_pz_fast( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [zeros(1,3)]);
plot(freqs_pz, 180/pi*angle(squeeze(freqresp(G_pz_fast_iff_hpf( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(1,:)]);
plot(freqs_pz, 180/pi*angle(squeeze(freqresp(G_pz_fast_iff_kp( 'Du', 'Fu'), freqs_pz, 'Hz'))), '-' , 'color', [colors(2,:)]);
plot(freqs_pz, 180/pi*angle(squeeze(freqresp(G_pz_fast_rdc( 'Du', '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([-180, 180]);
xlim([freqs_pz(1), freqs_pz(end)]);
linkaxes([ax1,ax2,ax3],'y');
linkaxes([ax1b,ax2b,ax3b],'y');
linkaxes([ax1,ax1b],'x');
linkaxes([ax2,ax2b],'x');
linkaxes([ax3,ax3b],'x');