%% Clear Workspace and Close figures
clear; close all; clc;

%% Intialize Laplace variable
s = zpk('s');

addpath('APA300ML/');

open('APA300ML.slx');

% Import Mass Matrix, Stiffness Matrix, and Interface Nodes Coordinates
% We first extract the stiffness and mass matrices.

K = readmatrix('APA300ML_mat_K.CSV');
M = readmatrix('APA300ML_mat_M.CSV');



% #+caption: First 10x10 elements of the Mass matrix
% #+RESULTS:
% |    0.01 |  -2e-06 |  1e-06 |  6e-09 |  5e-05 | -5e-09 | -0.0005 |  -7e-07 |  6e-07 | -3e-09 |
% |  -2e-06 |    0.01 |  8e-07 | -2e-05 | -8e-09 |  2e-09 |  -9e-07 | -0.0002 |  1e-08 | -9e-07 |
% |   1e-06 |   8e-07 |  0.009 |  5e-10 |  1e-09 | -1e-09 |  -5e-07 |   3e-08 |  6e-05 |  1e-10 |
% |   6e-09 |  -2e-05 |  5e-10 |  3e-07 |  2e-11 | -3e-12 |   3e-09 |   9e-07 | -4e-10 |  3e-09 |
% |   5e-05 |  -8e-09 |  1e-09 |  2e-11 |  6e-07 | -4e-11 |  -1e-06 |  -2e-09 |  1e-09 | -8e-12 |
% |  -5e-09 |   2e-09 | -1e-09 | -3e-12 | -4e-11 |  1e-07 |  -2e-09 |  -1e-09 | -4e-10 | -5e-12 |
% | -0.0005 |  -9e-07 | -5e-07 |  3e-09 | -1e-06 | -2e-09 |    0.01 |   1e-07 | -3e-07 | -2e-08 |
% |  -7e-07 | -0.0002 |  3e-08 |  9e-07 | -2e-09 | -1e-09 |   1e-07 |    0.01 | -4e-07 |  2e-05 |
% |   6e-07 |   1e-08 |  6e-05 | -4e-10 |  1e-09 | -4e-10 |  -3e-07 |  -4e-07 |  0.009 | -2e-10 |
% |  -3e-09 |  -9e-07 |  1e-10 |  3e-09 | -8e-12 | -5e-12 |  -2e-08 |   2e-05 | -2e-10 |  3e-07 |


% Then, we extract the coordinates of the interface nodes.

[int_xyz, int_i, n_xyz, n_i, nodes] = extractNodes('APA300ML_out_nodes_3D.txt');

% Piezoelectric parameters
% In order to make the conversion from applied voltage to generated force or from the strain to the generated voltage, we need to defined some parameters corresponding to the piezoelectric material:

d33 = 300e-12; % Strain constant [m/V]
n   = 80;      % Number of layers per stack
eT  = 1.6e-8;  % Permittivity under constant stress [F/m]
sD  = 1e-11;   % Compliance under constant electric displacement [m2/N]
ka  = 235e6;   % Stack stiffness [N/m]
C   = 5e-6;    % Stack capactiance [F]



% The ratio of the developed force to applied voltage is:
% #+name: eq:piezo_voltage_to_force
% \begin{equation}
%   F_a = g_a V_a, \quad g_a = d_{33} n k_a
% \end{equation}
% where:
% - $F_a$: developed force in [N]
% - $n$: number of layers of the actuator stack
% - $d_{33}$: strain constant in [m/V]
% - $k_a$: actuator stack stiffness in [N/m]
% - $V_a$: applied voltage in [V]

% If we take the numerical values, we obtain:

d33*n*ka % [N/V]



% #+RESULTS:
% : 5.64

% From cite:fleming14_desig_model_contr_nanop_system (page 123), the relation between relative displacement of the sensor stack and generated voltage is:
% #+name: eq:piezo_strain_to_voltage
% \begin{equation}
%   V_s = \frac{d_{33}}{\epsilon^T s^D n} \Delta h
% \end{equation}
% where:
% - $V_s$: measured voltage in [V]
% - $d_{33}$: strain constant in [m/V]
% - $\epsilon^T$: permittivity under constant stress in [F/m]
% - $s^D$: elastic compliance under constant electric displacement in [m^2/N]
% - $n$: number of layers of the sensor stack
% - $\Delta h$: relative displacement in [m]

% If we take the numerical values, we obtain:

1e-6*d33/(eT*sD*n) % [V/um]

% Stiffness

m = 0.001;



% The transfer function from vertical external force to the relative vertical displacement is identified.


%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'],  1, 'openoutput'); io_i = io_i + 1;

G = linearize(mdl, io);



% The inverse of its DC gain is the axial stiffness of the APA:

1e-6/dcgain(G) % [N/um]

% Resonance Frequency
% The resonance frequency is specified to be between 650Hz and 840Hz.
% This is also the case for the FEM model (Figure [[fig:apa300ml_resonance]]).


freqs = logspace(2, 4, 5000);

figure;
hold on;
plot(freqs, abs(squeeze(freqresp(G, freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('Amplitude');
hold off;

% Amplification factor
% The amplification factor is the ratio of the vertical displacement to the stack displacement.


%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/F'], 1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;
io(io_i) = linio([mdl, '/d'], 1, 'openoutput'); io_i = io_i + 1;

G = linearize(mdl, io);



% The ratio of the two displacement is computed from the FEM model.

abs(dcgain(G(1,1))./dcgain(G(2,1)))



% #+RESULTS:
% : 5.0749

% This is actually correct and approximately corresponds to the ratio of the piezo height and length:

75/15

% Stroke

% Estimation of the actuator stroke:
% \[ \Delta H = A n \Delta L \]
% with:
% - $\Delta H$ Axial Stroke of the APA
% - $A$ Amplification factor (5 for the APA300ML)
% - $n$ Number of stack used
% - $\Delta L$ Stroke of the stack (0.1% of its length)


1e6 * 5 * 3 * 20e-3 * 0.1e-2

% Identification of the Dynamics from actuator to replace displacement
% We first set the mass to be approximately zero.

m = 0.01;



% The dynamics is identified from the applied force to the measured relative displacement.

%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/F'], 1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;

Gh = -linearize(mdl, io);



% The same dynamics is identified for a payload mass of 10Kg.

m = 10;

%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/F'], 1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'], 1, 'openoutput'); io_i = io_i + 1;

Ghm = -linearize(mdl, io);

freqs = logspace(0, 4, 5000);

figure;
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(Gh, freqs, 'Hz'))), '-');
plot(freqs, abs(squeeze(freqresp(Ghm, freqs, 'Hz'))), '-');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
hold off;

ax2 = nexttile;
hold on;
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Gh, freqs, 'Hz')))), '-', ...
     'DisplayName', '$m = 0kg$');
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Ghm, freqs, 'Hz')))), '-', ...
     'DisplayName', '$m = 10kg$');
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
yticks(-360:90:360);
ylim([-360 0]);
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]);
legend('location', 'southwest');



% #+name: fig:apa300ml_plant_dynamics
% #+caption: Transfer function from forces applied by the stack to the axial displacement of the APA
% #+RESULTS:
% [[file:figs/apa300ml_plant_dynamics.png]]

% The root locus corresponding to Direct Velocity Feedback with a mass of 10kg is shown in Figure [[fig:apa300ml_dvf_root_locus]].

figure;

gains = logspace(0, 5, 500);

hold on;
plot(real(pole(Ghm)),  imag(pole(G)), 'kx');
plot(real(tzero(Ghm)),  imag(tzero(G)), 'ko');
for k = 1:length(gains)
    cl_poles = pole(feedback(Ghm, gains(k)*s));
    plot(real(cl_poles), imag(cl_poles), 'k.');
end
hold off;
axis square;
xlim([-500, 10]); ylim([0, 510]);

xlabel('Real Part'); ylabel('Imaginary Part');

% Identification of the Dynamics from actuator to force sensor
% Let's use 2 stacks as a force sensor and 1 stack as force actuator.

% The transfer function from actuator voltage to sensor voltage is identified and shown in Figure [[fig:apa300ml_iff_plant]].

m = 10;

%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Va'], 1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1;

Giff = -linearize(mdl, io);

freqs = logspace(0, 4, 5000);

figure;
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(Giff, freqs, 'Hz'))), '-');
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
hold off;

ax2 = nexttile;
hold on;
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(Giff, freqs, 'Hz')))), '-');
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
yticks(-360:90:360);
ylim([-180 180]);
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]);



% #+name: fig:apa300ml_iff_plant
% #+caption: Transfer function from actuator to force sensor
% #+RESULTS:
% [[file:figs/apa300ml_iff_plant.png]]

% For root locus corresponding to IFF is shown in Figure [[fig:apa300ml_iff_root_locus]].

figure;

gains = logspace(0, 5, 500);

hold on;
plot(real(pole(Giff)),  imag(pole(Giff)), 'kx');
plot(real(tzero(Giff)),  imag(tzero(Giff)), 'ko');
for k = 1:length(gains)
    cl_poles = pole(feedback(Giff, gains(k)/s));
    plot(real(cl_poles), imag(cl_poles), 'k.');
end
hold off;
axis square;
xlim([-500, 10]); ylim([0, 510]);

xlabel('Real Part'); ylabel('Imaginary Part');

% Identification for a simpler model
% The goal in this section is to identify the parameters of a simple APA model from the FEM.
% This can be useful is a lower order model is to be used for simulations.

% The presented model is based on cite:souleille18_concep_activ_mount_space_applic.

% The model represents the Amplified Piezo Actuator (APA) from Cedrat-Technologies (Figure [[fig:souleille18_model_piezo]]).
% The parameters are shown in the table below.

% #+name: fig:souleille18_model_piezo
% #+caption: Picture of an APA100M from Cedrat Technologies. Simplified model of a one DoF payload mounted on such isolator
% [[file:./figs/souleille18_model_piezo.png]]

% #+caption:Parameters used for the model of the APA 100M
% |       | Meaning                                                        |
% |-------+----------------------------------------------------------------|
% | $k_e$ | Stiffness used to adjust the pole of the isolator              |
% | $k_1$ | Stiffness of the metallic suspension when the stack is removed |
% | $k_a$ | Stiffness of the actuator                                      |
% | $c_1$ | Added viscous damping                                          |

% The goal is to determine $k_e$, $k_a$ and $k_1$ so that the simplified model fits the FEM model.

% \[ \alpha = \frac{x_1}{f}(\omega=0) = \frac{\frac{k_e}{k_e + k_a}}{k_1 + \frac{k_e k_a}{k_e + k_a}} \]
% \[ \beta = \frac{x_1}{F}(\omega=0) = \frac{1}{k_1 + \frac{k_e k_a}{k_e + k_a}} \]

% If we can fix $k_a$, we can determine $k_e$ and $k_1$ with:
% \[ k_e = \frac{k_a}{\frac{\beta}{\alpha} - 1} \]
% \[ k_1 = \frac{1}{\beta} - \frac{k_e k_a}{k_e + k_a} \]


m = 10;

%% Name of the Simulink File
mdl = 'APA300ML';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput');  io_i = io_i + 1; % External Vertical Force [N]
io(io_i) = linio([mdl, '/w'],  1, 'openinput');  io_i = io_i + 1; % Base Motion [m]
io(io_i) = linio([mdl, '/Fa'], 1, 'openinput');  io_i = io_i + 1; % Actuator Force [N]
io(io_i) = linio([mdl, '/z'],  1, 'openoutput'); io_i = io_i + 1; % Vertical Displacement [m]
io(io_i) = linio([mdl, '/Vs'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensor [V]
io(io_i) = linio([mdl, '/d'],  1, 'openoutput'); io_i = io_i + 1; % Stack Displacement [m]

G = linearize(mdl, io);

G.InputName = {'Fd', 'w', 'Fa'};
G.OutputName = {'y', 'Fs', 'd'};



% From the identified dynamics, compute $\alpha$ and $\beta$

alpha = abs(dcgain(G('y', 'Fa')));
beta  = abs(dcgain(G('y', 'Fd')));



% $k_a$ is estimated using the following formula:

ka = 0.8/abs(dcgain(G('y', 'Fa')));


% The factor can be adjusted to better match the curves.

% Then $k_e$ and $k_1$ are computed.

ke = ka/(beta/alpha - 1);
k1 = 1/beta - ke*ka/(ke + ka);



% #+RESULTS:
% |    | Value [N/um] |
% |----+--------------|
% | ka |         40.5 |
% | ke |          1.5 |
% | k1 |          0.4 |

% The damping in the system is adjusted to match the FEM model if necessary.

c1 = 1e2;



% The analytical model of the simpler system is defined below:

Ga = 1/(m*s^2 + k1 + c1*s + ke*ka/(ke + ka)) * ...
     [ 1 ,              k1 + c1*s + ke*ka/(ke + ka)  , ke/(ke + ka) ;
      -ke*ka/(ke + ka), ke*ka/(ke + ka)*m*s^2 ,       -ke/(ke + ka)*(m*s^2 + c1*s + k1)];

Ga.InputName = {'Fd', 'w', 'Fa'};
Ga.OutputName = {'y', 'Fs'};



% And the DC gain is adjusted for the force sensor:

F_gain = dcgain(G('Fs', 'Fd'))/dcgain(Ga('Fs', 'Fd'));



% The dynamics of the FEM model and the simpler model are compared in Figure [[fig:apa300ml_comp_simpler_model]].


freqs = logspace(0, 5, 1000);

figure;
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Ga('y', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/w$ [m/m]');
ylim([1e-6, 1e2]);

ax2 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fa'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Ga('y', 'Fa'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/f$ [m/N]');
ylim([1e-14, 1e-6]);

ax3 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fd'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Ga('y', 'Fd'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/F$ [m/N]');
ylim([1e-14, 1e-4]);

ax4 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/w$ [m/m]');
ylim([1e2, 1e8]);

ax5 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fa'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'Fa'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/f$ [m/N]');
ylim([1e-4, 1e1]);

ax6 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fd'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Ga('Fs', 'Fd'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/F$ [m/N]');
ylim([1e-7, 1e2]);

linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');



% #+name: fig:apa300ml_comp_simpler_model
% #+caption: Comparison of the Dynamics between the FEM model and the simplified one
% #+RESULTS:
% [[file:figs/apa300ml_comp_simpler_model.png]]

% The simplified model has also been implemented in Simscape.

% The dynamics of the Simscape simplified model is identified and compared with the FEM one in Figure [[fig:apa300ml_comp_simpler_simscape]].

%% Name of the Simulink File
mdl = 'APA300ML_simplified';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/Fd'], 1, 'openinput');  io_i = io_i + 1; % External Vertical Force [N]
io(io_i) = linio([mdl, '/w'],  1, 'openinput');  io_i = io_i + 1; % Base Motion [m]
io(io_i) = linio([mdl, '/Fa'], 1, 'openinput');  io_i = io_i + 1; % Actuator Force [N]
io(io_i) = linio([mdl, '/y'],  1, 'openoutput'); io_i = io_i + 1; % Vertical Displacement [m]
io(io_i) = linio([mdl, '/Fs'], 1, 'openoutput'); io_i = io_i + 1; % Force Sensor [V]

Gs = linearize(mdl, io);

Gs.InputName = {'Fd', 'w', 'Fa'};
Gs.OutputName = {'y', 'Fs'};

freqs = logspace(0, 5, 1000);

figure;
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gs('y', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/w$ [m/m]');
ylim([1e-6, 1e2]);

ax2 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fa'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gs('y', 'Fa'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/f$ [m/N]');
ylim([1e-14, 1e-6]);

ax3 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'y', 'Fd'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Gs('y', 'Fd'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]);
ylabel('$x_1/F$ [m/N]');
ylim([1e-14, 1e-4]);

ax4 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/w$ [m/m]');
ylim([1e2, 1e8]);

ax5 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fa'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'Fa'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/f$ [m/N]');
ylim([1e-4, 1e1]);

ax6 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G( 'Fs', 'Fd'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(F_gain*Gs('Fs', 'Fd'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]');
ylabel('$F_s/F$ [m/N]');
ylim([1e-7, 1e2]);

linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');

% Integral Force Feedback
% In this section, Integral Force Feedback control architecture is applied on the APA300ML.

% First, the plant (dynamics from voltage actuator to voltage sensor is identified).

Kiff = tf(0);



% The payload mass is set to 10kg.

m = 10;

%% Name of the Simulink File
mdl = 'APA300ML_IFF';

%% Input/Output definition
clear io; io_i = 1;
io(io_i) = linio([mdl, '/w'],         1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/F'],         1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/Fd'],        1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'],         1, 'openoutput'); io_i = io_i + 1;
io(io_i) = linio([mdl, '/APA300ML'],  1, 'openoutput'); io_i = io_i + 1;

G_ol = linearize(mdl, io);
G_ol.InputName  = {'w', 'f', 'F'};
G_ol.OutputName  = {'x1', 'Fs'};

G = G_ol({'Fs'}, {'f'});



% The obtained dynamics is shown in Figure [[fig:piezo_amplified_iff_plant]].


freqs = logspace(1, 5, 1000);

figure;
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(G, freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
hold off;

ax2 = nexttile;
hold on;
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G, freqs, 'Hz')))));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
yticks(-360:90:360);
ylim([-390 30]);
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]);



% #+name: fig:piezo_amplified_iff_plant
% #+caption: IFF Plant
% #+RESULTS:
% [[file:figs/piezo_amplified_iff_plant.png]]

% The controller is defined below and the loop gain is shown in Figure [[fig:piezo_amplified_iff_loop_gain]].

Kiff = -1e3/s;

freqs = logspace(1, 5, 1000);

figure;
tiledlayout(3, 1, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile([2,1]);
hold on;
plot(freqs, abs(squeeze(freqresp(G*Kiff, freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
ylabel('Amplitude'); set(gca, 'XTickLabel',[]);
hold off;

ax2 = nexttile;
hold on;
plot(freqs, 180/pi*unwrap(angle(squeeze(freqresp(G*Kiff, freqs, 'Hz')))));
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'lin');
yticks(-360:90:360);
ylim([-180 180]);
xlabel('Frequency [Hz]'); ylabel('Phase [deg]');
hold off;
linkaxes([ax1,ax2],'x');
xlim([freqs(1), freqs(end)]);



% #+name: fig:piezo_amplified_iff_loop_gain
% #+caption: IFF Loop Gain
% #+RESULTS:
% [[file:figs/piezo_amplified_iff_loop_gain.png]]

% Now the closed-loop system is identified again and compare with the open loop system in Figure [[fig:piezo_amplified_iff_comp]].

% It is the expected behavior as shown in the Figure [[fig:souleille18_results]] (from cite:souleille18_concep_activ_mount_space_applic).


clear io; io_i = 1;
io(io_i) = linio([mdl, '/w'],         1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/F'],         1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/Fd'],        1, 'openinput');  io_i = io_i + 1;
io(io_i) = linio([mdl, '/z'],         1, 'openoutput'); io_i = io_i + 1;
io(io_i) = linio([mdl, '/APA300ML'],  1, 'output');     io_i = io_i + 1;

Giff = linearize(mdl, io);
Giff.InputName  = {'w', 'f', 'F'};
Giff.OutputName  = {'x1', 'Fs'};

freqs = logspace(0, 3, 1000);

figure;
tiledlayout(2, 3, 'TileSpacing', 'None', 'Padding', 'None');

ax1 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('$x_1/w$ [m/m]')

ax2 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'f'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'f'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('$x_1/f$ [m/N]');

ax3 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('x1', 'F'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('x1', 'F'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
set(gca, 'XTickLabel',[]); ylabel('$x_1/F$ [m/N]');

ax4 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'w'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'w'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('$F_s/w$ [N/m]');

ax5 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'f'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'f'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('$F_s/f$ [N/N]');

ax6 = nexttile;
hold on;
plot(freqs, abs(squeeze(freqresp(G_ol('Fs', 'F'), freqs, 'Hz'))));
plot(freqs, abs(squeeze(freqresp(Giff('Fs', 'F'), freqs, 'Hz'))));
hold off;
set(gca, 'XScale', 'log'); set(gca, 'YScale', 'log');
xlabel('Frequency [Hz]'); ylabel('$F_s/F$ [N/N]');

linkaxes([ax1,ax2,ax3,ax4,ax5,ax6],'x');
