% TOGAC19_MSD_StabilityofAydinetal.m

% This file takes the transfer function from Towards  Collaborative  Drilling  with  a
% Cobot  Using  Admittance  Controller the work of Aydin et al
% The values for all their controller variables G(s) C(s) Zeq(s) and H(s)
% are featured here and the stability of the system is analyzed using phase
% margin and closed loop poles

%%% It has been acknowledged that CL poles should be analyzed using a
%%% different method, and the method in this file is no longer valid. See
%%% the following files for a correct stability analysis:


% TOGAC24_MSD_TrueAydinetalStability.m
% Impedance_select.m
% TFAydin.m
% AydinStabMap.m
% CostTransMapAydin.m
% Check_stable.m

% Created by Brevin Banks
% Modified 3/13/2023

%default values

%human impedance
mh = 5;%5; Worst case reported mass from Aydin et al.
bh = 41;%41; Worst case reported damping from Aydin et al.
kh = 401;%401; Worst case reported stiffness from Aydin et al.

%environoment impedance
me = 0;%unused assumed only largely stiff
be = 0;%unused assumed only largely stiff
ke = 16599;% Worst case reported stiffness from Aydin et al.

m_ad = 50; % Desired impedance mass
b_ad = 500; % Desired impedance damping

Zhs = tf([mh bh],[1]) + tf([kh],[1 0]); % Impedance human
Ze = tf([me be],[1])+tf([ke],[1 0]); % Impedance from environment
Z = Zhs+Ze;

% Aydin et al paper G(s) values from system Identification
k2   =  -0.1896;
k4   =  1.6550;
k6   =  -0.4654;

% T2 from aydin et al
a1=25.69;
b1=749.3;
mt1 = 1;
bt1 = 29.04;
kt1 = 752.7;
Ps1 = k2*tf([a1 b1],[mt1 bt1 kt1]);

% T4 from aydin et al
a2=65.99;
b2=1679;
mt2 = 1;
bt2 = 72.97;
kt2 = 1723;
Ps2 = k4*tf([a2 b2],[mt2 bt2 kt2]);

% T6 from aydin et al
a3=63.77;
b3=6564;
mt3 = 1;
bt3 = 95.39;
kt3 = 6513;
Ps3 = k6*tf([a3 b3],[mt3 bt3 kt3]);

% The admittance controller
Ys = tf([1],[m_ad b_ad]);

% The resultant plant
Gs = Ps1+Ps2+Ps3;

%Filter
[b,a] = butter(2,5/(30/2));
%sampled at 30Hz with a cuttoff of 5Hz
Hs = tf(b,a);

fprintf('The system transfer function is: \n');
T = (Gs*Ys)/(1+(Gs*Ys*Hs*Z)) % total system CL transfer function
figure('name','Bode Plot of Aydin et al CL Transfer Function')
bode(T)
title('The resonse of the CL transfer function From Aydin et al.')

T = Ys*Gs*Hs*Z;% total system OL transfer function
figure('name','Bode Plot of Aydin et al OL Transfer Function')
bode(T)
title('The resonse of the OL transfer function From Aydin et al.')

%% Test for stability with phase margin and then closed loop poles

% Step size/refinement for testing stability is 60. 
unstablemabas = [0;0]; % record the values for which ma and ba make the system unstable
stable_stienen=ones(60,60); % initiate map for phase margin tests, a map of ones
stable_aydin=ones(60,60); % initiate map for closed loop tests, a map of ones
ma_values = linspace(1,200,60); % mass lin space from 1 to 200 with 60 steps
ba_values = linspace(1,1000,60);% damping lin space from 1 to 1000 with 60 steps

for masses = 1:length(ma_values)
    for dampers = 1:length(ba_values)
        m_ad = ma_values(masses);% assign the mass admittance values
        b_ad = ba_values(dampers);% assign the damping admittance values

        % The admittance controller
        Ys = tf([1],[m_ad b_ad]);

        Ya = Ys*Gs*Hs; % Open loop transfer function no impedance

        % Stienen et al. stability method by evaluating the phase margin

        % grab the phase margin of the system Ya*Zs
        [mag,phase1] = margin(Ya*Z);

        % Check if stable or not
        if isinf(phase1) % Stable if infinite
            stable_stienen(masses,dampers) = true;
        elseif phase1 <= 0 % unstable if negative
            stable_stienen(masses,dampers) = false;
        elseif phase1 > 0 % stable if positive
            stable_stienen(masses,dampers) = true;
        end


        % Aydin et al. stability method by analysing closed loop poles

        T = (Gs*Ys)/(1+(Gs*Ys*Hs*Z)); % total system CL transfer function
        poles = pole(T);

        for tester=1:length(poles)
            if real(poles(tester))>0
                stable_aydin(masses,dampers) =0;
                if unstablemabas(1,end)==m_ad
                    unstablemabas(1:2,end) = [m_ad;b_ad];
                else
                    unstablemabas(1:2,end+1) = [m_ad;b_ad];
                end
            end
        end
    end
end


stable_string = stringstable(stable_stienen);
fprintf("Stability according to Phase Margin\n"+stable_string)
fprintf('%d\n',poles);


formatSpec = 'Stability according to CL Poles: %s with the following CL poles \n';
stable_string = stringstable(stable_aydin);
fprintf(formatSpec,stable_string)
fprintf('%d\n',poles);



% This function will check the boolean case for the stable_condition
% variable. Because the above stability testers initialize the map with
% ones, but the stability checks return 1 for unstable, this will flip the
% response to return the correct variable to place in the map.
% Input:
%   stable_condition - a boolean for the stability of a TF for a given ma
%   and ba
function stable_string = stringstable(stable_condition)
if stable_condition==true
    stable_string = 'Stable';
else
    stable_string = 'Unstable';
end
end

