phd-nass-uniaxial-model/matlab/uniaxial_2_nano_hexapod_model.m
2023-02-17 11:28:06 +01:00

225 lines
8.0 KiB
Matlab

%% 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;
%% Uniaxial Simscape model name
mdl = 'nass_uniaxial_model';
%% Frequency Vector [Hz]
freqs = logspace(0, 3, 1000);
%% Load the micro-station parameters
load('uniaxial_micro_station_parameters.mat')
% Nano-Hexapod Parameters
% The parameters for the nano-hexapod and sample are:
% - $m_s$ the sample mass that can vary from 1kg up to 50kg
% - $m_n$ the nano-hexapod mass which is set to 15kg
% - $k_n$ the nano-hexapod stiffness, which can vary depending on the chosen architecture/technology
% As a first example, let's choose a nano-hexapod stiffness of $10\,N/\mu m$ and a sample mass of 10kg.
%% Nano-Hexapod Parameters
mn = 15; % [kg]
kn = 1e7; % [N/m]
cn = 2*0.01*sqrt(mn*kn); % [N/(m/s)]
%% Sample Mass
ms = 10; % [kg]
% Obtained Dynamics
% The sensitivity to disturbances (i.e. $x_f$, $f_t$ and $f_s$) are shown in Figure ref:fig:uniaxial_sensitivity_dist_first_params.
% The /plant/ (i.e. the transfer function from actuator force $f$ to measured displacement $d$) is shown in Figure ref:fig:uniaxial_plant_first_params.
% For further analysis, 9 configurations are considered: three nano-hexapod stiffnesses ($k_n = 0.01\,N/\mu m$, $k_n = 1\,N/\mu m$ and $k_n = 100\,N/\mu m$) combined with three sample's masses ($m_s = 1\,kg$, $m_s = 25\,kg$ and $m_s = 50\,kg$).
%% Use 1DoF Nano-Hexpod model
model_config = struct();
model_config.nhexa = "1dof";
model_config.controller = "open_loop";
%% Identify the transfer function from disturbances and force actuator to d
clear io; io_i = 1;
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % Force Actuator
io(io_i) = linio([mdl, '/fs'], 1, 'openinput'); io_i = io_i + 1; % Force applied on the sample
io(io_i) = linio([mdl, '/micro_station/xf'], 1, 'openinput'); io_i = io_i + 1; % Floor Motion
io(io_i) = linio([mdl, '/micro_station/ft'], 1, 'openinput'); io_i = io_i + 1; % Stage disturbances
io(io_i) = linio([mdl, '/d'] , 1, 'openoutput'); io_i = io_i + 1; % Metrology
%% Perform the model extraction
G_ol = linearize(mdl, io, 0.0);
G_ol.InputName = {'f', 'fs', 'xf', 'ft'};
G_ol.OutputName = {'d'};
%% Sensitivity to disturbances
figure;
tiledlayout(1, 3, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile();
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('d', 'fs'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude $d/f_{s}$ [m/N]'); xlabel('Frequency [Hz]');
xticks([1e0, 1e1, 1e2]);
ax2 = nexttile();
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('d', 'ft'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude $d/f_{t}$ [m/N]'); xlabel('Frequency [Hz]');
xticks([1e0, 1e1, 1e2]);
ax3 = nexttile();
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('d', 'xf'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude $d/x_{f}$ [m/m]'); xlabel('Frequency [Hz]');
xticks([1e0, 1e1, 1e2]);
linkaxes([ax1,ax2,ax3],'x');
xlim([1, 500]);
% #+name: fig:uniaxial_sensitivity_dist_first_params
% #+caption: Sensitivity to disturbances
% #+RESULTS:
% [[file:figs/uniaxial_sensitivity_dist_first_params.png]]
%% Bode Plot of the transfer function from actuator forces to measured displacement by the metrology
figure;
tiledlayout(3, 1, 'TileSpacing', 'Compact', 'Padding', 'None');
ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('d', 'f'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude $d/f$ [m/N]'); set(gca, 'XTickLabel',[]);
ax2 = nexttile;
hold on;
plot(freqs, 180/pi*angle(squeeze(freqresp(G_ol('d', 'f'), freqs, 'Hz'))));
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, 500]);
% Identification of all combination of stiffnesses / masses :noexport:
%% Use 1DoF Nano-Hexpod model
model_config = struct();
model_config.nhexa = "1dof";
model_config.controller = "open_loop";
%% Nano-Hexapod Mass
mn = 15; % Nano-Hexapod mass [kg]
%% Identification of all combination of stiffnesses / masses
clear io; io_i = 1;
io(io_i) = linio([mdl, '/controller'], 1, 'openinput'); io_i = io_i + 1; % Actuator Force
io(io_i) = linio([mdl, '/micro_station/xf'], 1, 'openinput'); io_i = io_i + 1; % Floor Motion
io(io_i) = linio([mdl, '/micro_station/ft'], 1, 'openinput'); io_i = io_i + 1; % Stage vibrations
io(io_i) = linio([mdl, '/fs'], 1, 'openinput'); io_i = io_i + 1; % Direct sample forces
io(io_i) = linio([mdl, '/dL'], 1, 'openoutput'); io_i = io_i + 1; % Relative Motion Sensor
io(io_i) = linio([mdl, '/fm'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensor
io(io_i) = linio([mdl, '/vn'] , 1, 'openoutput'); io_i = io_i + 1; % Geophone
io(io_i) = linio([mdl, '/d'] , 1, 'openoutput'); io_i = io_i + 1; % Metrology Output
%% Light Sample
ms = 1; % Sample Mass [kg]
% Voice Coil (i.e. soft) Nano-Hexapod
kn = 1e4; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_vc_light = linearize(mdl, io, 0.0);
G_vc_light.InputName = {'f', 'xf', 'ft', 'fs'};
G_vc_light.OutputName = {'dL', 'fm', 'vn', 'd'};
% APA (i.e. relatively stiff) Nano-Hexapod
kn = 1e6; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_md_light = linearize(mdl, io, 0.0);
G_md_light.InputName = {'f', 'xf', 'ft', 'fs'};
G_md_light.OutputName = {'dL', 'fm', 'vn', 'd'};
% Piezoelectric (i.e. stiff) Nano-Hexapod
kn = 1e8; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_pz_light = linearize(mdl, io, 0.0);
G_pz_light.InputName = {'f', 'xf', 'ft', 'fs'};
G_pz_light.OutputName = {'dL', 'fm', 'vn', 'd'};
%% Mid Sample
ms = 25; % Sample Mass [kg]
% Voice Coil (i.e. soft) Nano-Hexapod
kn = 1e4; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_vc_mid = linearize(mdl, io, 0.0);
G_vc_mid.InputName = {'f', 'xf', 'ft', 'fs'};
G_vc_mid.OutputName = {'dL', 'fm', 'vn', 'd'};
% APA (i.e. relatively stiff) Nano-Hexapod
kn = 1e6; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_md_mid = linearize(mdl, io, 0.0);
G_md_mid.InputName = {'f', 'xf', 'ft', 'fs'};
G_md_mid.OutputName = {'dL', 'fm', 'vn', 'd'};
% Piezoelectric (i.e. stiff) Nano-Hexapod
kn = 1e8; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_pz_mid = linearize(mdl, io, 0.0);
G_pz_mid.InputName = {'f', 'xf', 'ft', 'fs'};
G_pz_mid.OutputName = {'dL', 'fm', 'vn', 'd'};
%% Heavy Sample
ms = 50; % Sample Mass [kg]
% Voice Coil (i.e. soft) Nano-Hexapod
kn = 1e4; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_vc_heavy = linearize(mdl, io, 0.0);
G_vc_heavy.InputName = {'f', 'xf', 'ft', 'fs'};
G_vc_heavy.OutputName = {'dL', 'fm', 'vn', 'd'};
% APA (i.e. relatively stiff) Nano-Hexapod
kn = 1e6; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_md_heavy = linearize(mdl, io, 0.0);
G_md_heavy.InputName = {'f', 'xf', 'ft', 'fs'};
G_md_heavy.OutputName = {'dL', 'fm', 'vn', 'd'};
% Piezoelectric (i.e. stiff) Nano-Hexapod
kn = 1e8; % Nano-Hexapod Stiffness [N/m]
cn = 2*0.01*sqrt((ms + mn)*kn); % Nano-Hexapod Damping [N/(m/s)]
G_pz_heavy = linearize(mdl, io, 0.0);
G_pz_heavy.InputName = {'f', 'xf', 'ft', 'fs'};
G_pz_heavy.OutputName = {'dL', 'fm', 'vn', 'd'};
%% Save All Identified Plants
save('./mat/uniaxial_plants.mat', 'G_vc_light', 'G_md_light', 'G_pz_light', ...
'G_vc_mid', 'G_md_mid', 'G_pz_mid', ...
'G_vc_heavy', 'G_md_heavy', 'G_pz_heavy');