%% 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

%% 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');
