%% Lesson 7c. Transfer function objects
close all; clear; clc;

%% Transfer function overview
% Transfer functions are abstract representations of LTI systems in terms of
% rational functions (numerator and denominator). We used to work with transfer
% functions in terms of MATLAB-style polynomials, but Mathworks has come up
% with a new, supposedly improved way: transfer function objects! These are
% created via `tf` in a variety of ways. For more info, see Mathworks'
% documentation -- these models are most helpful when working with cascades of
% systems, such as for controls modeling.

%% Digital transfer function objects
% To create a digital tf. object, specify a numerator, denominator, and
% sampling time (which may be set to -1 if you want to leave it undefined). The
% numerator and denominator are specified in decreasing power order, with s^0
% or z^0 on the right.
dig_num = [1]; % 1z⁰ = 1
dig_den = [2 -1]; % 2z¹ - 1z⁰ = 2z - 1
timestep = 0.1; % 0.1 s
dig_sys = tf(dig_num, dig_den, timestep);

%% Analog transfer function objects
% Analog transfer functions are created the same way as digital ones, just
% without the timestep.
an_num = [1 -1]; % 1s¹ - 1s⁰ = 1s - 1
an_den = [1 2 1]; % s² + 2s + 1
an_sys = tf(an_num, an_den);

%% Alternate ways of specifying
% MATLAB provides a syntax for creating transfer functions out of coded
% rational expressions, as this can be clearer:
s = tf('s'); % create an s variable that may then be used mathematically
an_sys_2 = (s - 1)/(s + 1)^2; % same as above

%% Investigating the transfer function
% One property of interest is the step response, which we can view thus:
figure;
stepplot(an_sys);

% MATLAB has a built-in function to get a Bode plot, too (though you should
% modify this in post if you want to highlight specific details in the plot).
figure;
bodeplot(an_sys);

%% One application
% This example is stolen from Mathworks' doc page "Control System Modeling with
% Model Objects," as it's an interesting perspective on what you can do with
% these. In it, we model the following system:
%
% x ---> F(s) ---> +( ) ---> C(s) ---> G(s) ---+---> y
%                    -                         |
%                    ^                         |
%                    \---------- S(s) ---------/

% specify the components of a system
G = zpk([], [-1, -1], 1); % no zeroes, double pole at -1, analog
C = pid(2, 1.3, 0.3, 0.5); % PID controller object
S = tf(5, [1 4]);
F = tf(1, [1 1]);

% find the open-loop transfer function (by breaking the loop at the subtract)
open_loop = F*S*G*C; % multiplication in the "frequency" domain

% check out where the poles & zeroes are
figure;
pzplot(open_loop);
title('Open loop pole/zero plot');
xlim([-6 1]);
ylim([-2 2]);

% see what this thing does with a step input
figure;
stepplot(open_loop);
title('Open-loop system step response');
% note that this is *not* stable with a step input, as the PID controller loses
% its shit!

% find the closed-loop, whole_system response using `feedback` to specify a
% feedback connection
full_system = F*feedback(G*C, S);

% see what this thing looks like now in the s-plane
figure;
pzplot(full_system);
title('Full system pole/zero plot');
xlim([-6 1]);
ylim([-2 2]);

% now stable with a step input, as we have feedback
figure;
stepplot(full_system);
title('Full system step response');
