%% Header
% Purpose:  Producing controller transfer function from a set of
%           controller parameters.
% Author:   Axel Lodemel Holene
% E-mail:   axel.holene@gmail.com
% Date:     February 2013
% About:    Chriss': C = Kc((1-I-D)+I/s+Ds)
%           Parallel: C = Kc(1+1/I/s+D*s)
%           Alt. parallel: C = Kc(1+I/s+D*s)
%           Cascade controller
function C = controller(varargin)
    s = zpk('s') ;

    if nargin == 1
        parm = varargin{1} ;
    elseif nargin == 2
        ctrl = varargin{1} ; 
        parm = varargin{2} ; 
    else
        fprintf('Too many controller arguments. \n')
    end
    G       = parm.G ;
    modelId = parm.modelId ;
    cType   = parm.cType ;
    ctrlr   = parm.ctrlr ;
    cNum    = parm.cNum ;
    dFilter = parm.dFilter ;
    distOpt = parm.distOpt ;

    if cType == 4 || cType == 5        % If smithDist or nyquist
        cType = distOpt ;              % produce Smith Predictor
    end

    if (ctrlr == 3 && cType ~= 3)
        C.Kc = ctrl(1) ;
        C.tf = C.Kc ;
        return
    end

    switch cType
        case 1 % PO
            switch ctrlr
                case 1 % PID
                    C.type = 'pid' ;
                    C.Kc=ctrl(1);C.I=ctrl(2);C.D=ctrl(3);
                    switch cNum
                        case 1  % Chriss': C=Kc((1-I-D)+I/s+Ds)
                            C.tf = C.Kc*((1 - C.I - C.D) + ...
                                   C.I/s + C.D*s) ; 
                        case 2  % Parallel: C=Kc(1+1/I/s+D*s)
                            C.tf = C.Kc*(1 + 1/C.I/s + C.D*s) ;
                        case 3  % Alt. parallel: C=Kc(1+I/s+D*s)
                            C.tf = C.Kc*(1 + C.I/s + C.D*s) ;
                        case 4 % Cascade controller 
                            C.tf = C.Kc*(C.I*s + 1)/...
                            C.I/s*(C.D*s + 1) ;
                    end
                case 2 % PI
                    C.type = 'pi' ;
                    C.Kc = ctrl(1); C.I = ctrl(2);
                    switch cNum
                        case 1  % Chriss
                            C.tf = C.Kc*((1 - C.I) + C.I/s) ; 
                        case 2  % Parallel
                            C.tf = C.Kc*(1 + 1/C.I/s) ;
                        case 3  % AltParallel
                            C.tf = C.Kc*(1 + C.I/s) ;
                        case 4  % Cascade
                            C.tf = C.Kc*(1 + 1/C.I/s) ;
                    end
            end
        case 2 % SIMC
            C.tau_c = parm.tau_c ;   % Closed-loop time constant
            C.Kc    = (1/G.k)*(G.tau1/(C.tau_c+G.theta)) ;
            if modelId == 10
                C.tau_i = 4*(C.tau_c+G.theta) ;
            else
                C.tau_i = min(G.tau1, 4*(C.tau_c+G.theta)) ;
            end % modelId==10
            switch ctrlr
                case 1  % PID
                    C.type = 'simc:pid' ;
                    if modelId > 9
                        C.tf = C.Kc*(1 + 1/C.tau_i/s) ;
                    else
                        C.tau_d = parm.G.tau2 ;
                        C.tf = C.Kc*(1 + 1/C.tau_i/s)*...
                              (C.tau_d*s+1) ;
                    end % modelId
                case 2  % PI
                    C.type = 'simc:pi' ;
                    C.tf = pidstd(C.Kc, C.tau_i) ;
            end % switch ctrlr
        case 3 % SMITH
            C.modelId = parm.modelId ;
            switch ctrlr
                case 1 % PID
                    C.type = 'smith:pid' ;
                    C.Kc=ctrl(1);C.I=ctrl(2);C.D=ctrl(3);
                    if dFilter
                        C.alph = parm.alph; C.tau_f=C.alph*C.D ;
                    end % dFilter
                    switch cNum
                        case 1   % Chriss': C=Kc((1-I-D)+I/s+Ds)
                                C.tfstd = C.Kc*((1-C.I-C.D) +...
                                          C.I/s + C.D*s) ; 
                        case 2     % Parallel: C=Kc(1+1/I/s+D*s)
                            C.tfstd = pidstd(C.Kc,C.I,C.D) ;
                        case 3  % Alt. parallel: C=Kc(1+I/s+D*s)
                                C.tfstd = C.Kc*(1+C.I/s+C.D*s) ;
                        case 4 % Cascade controller 
                            if dFilter % is active
                               C.tfstd = C.Kc*(C.I*s + 1)/   ...
                               C.I/s*(C.D*s+1)/(C.alph*C.D*s+1);
                            else
                                C.tfstd = C.Kc*(C.I*s + 1)/  ...
                                          C.I/s*(C.D*s+1) ;
                            end % dFilter
                    end % switch cNum 
                    C.tf = C.tfstd/(1 + C.tfstd*G.tfnd*...
                        (1 - exp(-G.theta*s))) ;
                case 2 % PI
                    C.type = 'smith:pi' ;
                    C.Kc = ctrl(1); C.I = ctrl(2);
                    switch cNum
                        case 1  % Chriss
                            C.tfstd = C.Kc*((1 - C.I) + C.I/s) ; 
                        case 2  % Parallel
                            C.tfstd = C.Kc*(1 + 1/C.I/s) ;
                        case 3  % AltParallel
                            C.tfstd = C.Kc*(1 + C.I/s) ;
                        case 4  % Cascade
                            C.tfstd = C.Kc*(1 + 1/C.I/s) ;
                    end
                    C.tf = C.tfstd/(1 + C.tfstd*G.tfnd*...
                        (1 - exp(-G.theta*s))) ;
                case 3 % P
                    C.type = 'smith:p' ;
                    C.Kc = ctrl ;
                    C.tfstd = C.Kc ;
                    C.tf = C.tfstd/(1 + C.tfstd*G.tfnd*...
                        (1 - exp(-G.theta*s))) ; 
            end % ctrlr
        case 4
            %
        case 5
            %
        case 6
            %
        case 7
            switch ctrlr
                case 1 % smith simc pid
                    C.type = 'smith:simc:pid' ;
                    C.tau_c = parm.tau_c ;
                    C.alph  = parm.alph ;
                    C.Kc = (1/G.k)*(G.tau1/(C.tau_c)) ;
                    C.tau_i = min(G.tau1,4*(C.tau_c)) ;
                    C.tau_d = parm.G.tau2 ;
                    C.tau_f = C.tau_d*C.alph ;
                    C.pidtf = C.Kc*(1 + 1/C.tau_i/s)*...
                              (C.tau_d*s+1)/(C.tau_f*s + 1) ;
                    C.tf = C.pidtf/(1+C.pidtf*G.tfnd*...
                            (1-exp(-G.theta*s))) ;
                case 2 % smith simc pi
                    C.type = 'smith:simc:pi' ;
                    C.tau_c = parm.tau_c ;
                    C.Kc = (1/G.k)*G.tau1/C.tau_c ;
                    if modelId == 10
                        C.tau_i = 4*(C.tau_c) ;
                    else
                        C.tau_i = min(G.tau1,4*C.tau_c) ;
                    end
                    C.pidtf = C.Kc*(1+1/C.tau_i/s) ;
                    C.tf = C.pidtf/(1+C.pidtf*G.tfnd*...
                            (1-exp(-G.theta*s))) ;
            end % ctrlr
        case 8
            C.Lmax = 1.7*parm.dMax*G.theta ;
            C.Kc = G.tau1/G.k/C.Lmax ;
            C.tau_i = G.theta ;
            C.tfstd = C.Kc*(C.tau_i*s + 1)/C.tau_i/s ;
            C.tf = C.tfstd/(1 + C.tfstd*G.tfnd*...
                        (1 - exp(-G.theta*s))) ; 
    end % cType
end