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

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

% Excitation Data

fs = 1e4;
Ts = 1/fs;



% We generate white noise with the "random number" simulink block, and we filter that noise.


Gi = (1)/(1+s/2/pi/100);

c2d(Gi, Ts, 'tustin')

% Input / Output data
% The identification data is loaded

ux = load('mat/data_ux.mat', 't', 'ux', 'yx', 'yy');
uy = load('mat/data_uy.mat', 't', 'uy', 'yx', 'yy');



% We remove the first seconds where the Cercalo is turned on.

i0x = 20*fs;

i0y = 10*fs;

ux.t  = ux.t( i0x:end) - ux.t(i0x);
ux.ux = ux.ux(i0x:end);
ux.yx = ux.yx(i0x:end);
ux.yy = ux.yy(i0x:end);

uy.t  = uy.t( i0y:end) - uy.t(i0x);
uy.uy = uy.uy(i0y:end);
uy.yx = uy.yx(i0y:end);
uy.yy = uy.yy(i0y:end);

ux.ux = ux.ux-mean(ux.ux);
ux.yx = ux.yx-mean(ux.yx);
ux.yy = ux.yy-mean(ux.yy);

uy.ux = uy.ux-mean(uy.ux);
uy.yx = uy.yx-mean(uy.yx);
uy.yy = uy.yy-mean(uy.yy);

figure;
ax1 = subplot(1, 2, 1);
plot(ux.t, ux.ux);
xlabel('Time [s]');
ylabel('Amplitude [V]');
legend({'$u_x$'});

ax2 = subplot(1, 2, 2);
hold on;
plot(ux.t, ux.yx, 'DisplayName', '$y_x$');
plot(ux.t, ux.yy, 'DisplayName', '$y_y$');
hold off;
xlabel('Time [s]');
ylabel('Amplitude [V]');
legend()

linkaxes([ax1,ax2],'x');
xlim([ux.t(1), ux.t(end)])



% #+NAME: fig:identification_ux
% #+CAPTION: Identification signals when exciting the $x$ axis ([[./figs/identification_ux.png][png]], [[./figs/identification_ux.pdf][pdf]])
% [[file:figs/identification_ux.png]]



figure;
ax1 = subplot(1, 2, 1);
plot(uy.t, uy.uy);
xlabel('Time [s]');
ylabel('Amplitude [V]');
legend({'$u_y$'});

ax2 = subplot(1, 2, 2);
hold on;
plot(uy.t, uy.yy, 'DisplayName', '$y_y$');
plot(uy.t, uy.yx, 'DisplayName', '$y_x$');
hold off;
xlabel('Time [s]');
ylabel('Amplitude [V]');
legend()

linkaxes([ax1,ax2],'x');
xlim([uy.t(1), uy.t(end)])

% Estimation of the Frequency Response Function Matrix
% We compute an estimate of the transfer functions.

[tf_ux_yx, f] = tfestimate(ux.ux, ux.yx, hanning(ceil(1*fs)), [], [], fs);
[tf_ux_yy, ~] = tfestimate(ux.ux, ux.yy, hanning(ceil(1*fs)), [], [], fs);
[tf_uy_yx, ~] = tfestimate(uy.uy, uy.yx, hanning(ceil(1*fs)), [], [], fs);
[tf_uy_yy, ~] = tfestimate(uy.uy, uy.yy, hanning(ceil(1*fs)), [], [], fs);

figure;
ax11 = subplot(2, 2, 1);
hold on;
plot(f, abs(tf_ux_yx))
title('Frequency Response Function $\frac{y_x}{u_x}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
ylabel('Amplitude')
hold off;

ax12 = subplot(2, 2, 2);
hold on;
plot(f, abs(tf_uy_yx))
title('Frequency Response Function $\frac{y_x}{u_y}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
hold off;

ax21 = subplot(2, 2, 3);
hold on;
plot(f, abs(tf_ux_yy))
title('Frequency Response Function $\frac{y_y}{u_x}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
ylabel('Amplitude')
xlabel('Frequency [Hz]')
hold off;

ax22 = subplot(2, 2, 4);
hold on;
plot(f, abs(tf_uy_yy))
title('Frequency Response Function $\frac{y_y}{u_y}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
xlabel('Frequency [Hz]')
hold off;

linkaxes([ax11,ax12,ax21,ax22],'x');
xlim([10, 1000]);
linkaxes([ax11,ax12,ax21,ax22],'y');
ylim([1e-2, 1e3])

% Coherence

[coh_ux_yx, f] = mscohere(ux.ux, ux.yx, hanning(ceil(1*fs)), [], [], fs);
[coh_ux_yy, ~] = mscohere(ux.ux, ux.yy, hanning(ceil(1*fs)), [], [], fs);
[coh_uy_yx, ~] = mscohere(uy.uy, uy.yx, hanning(ceil(1*fs)), [], [], fs);
[coh_uy_yy, ~] = mscohere(uy.uy, uy.yy, hanning(ceil(1*fs)), [], [], fs);

figure;
ax11 = subplot(2, 2, 1);
hold on;
plot(f, coh_ux_yx)
set(gca, 'Xscale', 'log');
title('Coherence $\frac{y_x}{u_x}$')
ylabel('Coherence')
hold off;

ax12 = subplot(2, 2, 2);
hold on;
plot(f, coh_uy_yx)
set(gca, 'Xscale', 'log');
title('Coherence $\frac{y_x}{u_y}$')
hold off;

ax21 = subplot(2, 2, 3);
hold on;
plot(f, coh_ux_yy)
set(gca, 'Xscale', 'log');
title('Coherence $\frac{y_y}{u_x}$')
ylabel('Coherence')
xlabel('Frequency [Hz]')
hold off;

ax22 = subplot(2, 2, 4);
hold on;
plot(f, coh_uy_yy)
set(gca, 'Xscale', 'log');
title('Coherence $\frac{y_y}{u_y}$')
xlabel('Frequency [Hz]')
hold off;

linkaxes([ax11,ax12,ax21,ax22],'x');
xlim([10, 1000]);
linkaxes([ax11,ax12,ax21,ax22],'y');
ylim([0, 1])

% Extraction of a transfer function matrix
% First we define the initial guess for the resonance frequencies and the weights associated.

freqs_res = [410, 250]; % [Hz]
freqs_res_weights = [10, 10]; % [Hz]



% From the number of resonance frequency we want to fit, we define the order =N= of the system we want to obtain.

N = 2*length(freqs_res);



% We then make an initial guess on the complex values of the poles.

xi = 0.001; % Approximate modal damping
poles = [2*pi*freqs_res*(xi + 1i), 2*pi*freqs_res*(xi - 1i)];



% We then define the weight that will be used for the fitting.
% Basically, we want more weight around the resonance and at low frequency (below the first resonance).
% Also, we want more importance where we have a better coherence.

weight = ones(1, length(f));
% weight = G_coh';

% alpha = 0.1;

% for freq_i = 1:length(freqs_res)
%   weight(f>(1-alpha)*freqs_res(freq_i) & omega<(1 + alpha)*2*pi*freqs_res(freq_i)) = freqs_res_weights(freq_i);
% end



% Ignore data above some frequency.

weight(f>1000) = 0;

figure;
hold on;
plot(f, weight);
plot(freqs_res, ones(size(freqs_res)), 'rx');
hold off;
xlabel('Frequency [Hz]');
xlabel('Weight Amplitude');
set(gca, 'xscale', 'log');
xlim([f(1), f(end)]);



% #+NAME: fig:weights
% #+CAPTION: Weights amplitude ([[./figs/weights.png][png]], [[./figs/weights.pdf][pdf]])
% [[file:figs/weights.png]]

% When we set some options for =vfit3=.

opts = struct();

opts.stable = 1;    % Enforce stable poles
opts.asymp = 1;     % Force D matrix to be null
opts.relax = 1;     % Use vector fitting with relaxed non-triviality constraint
opts.skip_pole = 0; % Do NOT skip pole identification
opts.skip_res = 0;  % Do NOT skip identification of residues (C,D,E)
opts.cmplx_ss = 0;  % Create real state space model with block diagonal A

opts.spy1 = 0;      % No plotting for first stage of vector fitting
opts.spy2 = 0;      % Create magnitude plot for fitting of f(s)



% We define the number of iteration.

Niter = 5;



% An we run the =vectfit3= algorithm.

for iter = 1:Niter
  [SER_ux_yx, poles, ~, fit_ux_yx] = vectfit3(tf_ux_yx.', 1i*2*pi*f, poles, weight, opts);
end
for iter = 1:Niter
  [SER_uy_yx, poles, ~, fit_uy_yx] = vectfit3(tf_uy_yx.', 1i*2*pi*f, poles, weight, opts);
end
for iter = 1:Niter
  [SER_ux_yy, poles, ~, fit_ux_yy] = vectfit3(tf_ux_yy.', 1i*2*pi*f, poles, weight, opts);
end
for iter = 1:Niter
  [SER_uy_yy, poles, ~, fit_uy_yy] = vectfit3(tf_uy_yy.', 1i*2*pi*f, poles, weight, opts);
end

figure;
ax11 = subplot(2, 2, 1);
hold on;
plot(f, abs(tf_ux_yx))
plot(f, abs(fit_ux_yx))
title('Frequency Response Function $\frac{y_x}{u_x}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
ylabel('Amplitude')
hold off;

ax12 = subplot(2, 2, 2);
hold on;
plot(f, abs(tf_uy_yx))
plot(f, abs(fit_uy_yx))
title('Frequency Response Function $\frac{y_x}{u_y}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
hold off;

ax21 = subplot(2, 2, 3);
hold on;
plot(f, abs(tf_ux_yy))
plot(f, abs(fit_ux_yy))
title('Frequency Response Function $\frac{y_y}{u_x}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
ylabel('Amplitude')
xlabel('Frequency [Hz]')
hold off;

ax22 = subplot(2, 2, 4);
hold on;
plot(f, abs(tf_uy_yy))
plot(f, abs(fit_uy_yy))
title('Frequency Response Function $\frac{y_y}{u_y}$')
set(gca, 'Xscale', 'log'); set(gca, 'Yscale', 'log');
xlabel('Frequency [Hz]')
hold off;

linkaxes([ax11,ax12,ax21,ax22],'x');
xlim([10, 1000]);
linkaxes([ax11,ax12,ax21,ax22],'y');
ylim([1e-2, 1e3])



% #+NAME: fig:identification_matrix_fit
% #+CAPTION: Transfer Function Extraction of the FRF matrix ([[./figs/identification_matrix_fit.png][png]], [[./figs/identification_matrix_fit.pdf][pdf]])
% [[file:figs/identification_matrix_fit.png]]

% And finally, we create the identified state space model:

G_ux_yx = minreal(ss(full(SER_ux_yx.A),SER_ux_yx.B,SER_ux_yx.C,SER_ux_yx.D));
G_uy_yx = minreal(ss(full(SER_uy_yx.A),SER_uy_yx.B,SER_uy_yx.C,SER_uy_yx.D));
G_ux_yy = minreal(ss(full(SER_ux_yy.A),SER_ux_yy.B,SER_ux_yy.C,SER_ux_yy.D));
G_uy_yy = minreal(ss(full(SER_uy_yy.A),SER_uy_yy.B,SER_uy_yy.C,SER_uy_yy.D));

G = [G_ux_yx, G_uy_yx;
     G_ux_yy, G_uy_yy];

save('mat/plant.mat', 'G');
