%% Header
% Purpose:  Producing controller transfer function from a set of
%           controller parameters.
% Author:   Axel Lødemel Holene
% E-mail:   axel.holene@gmail.com
% Date:     13. 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 ;
    cType   = parm.cType ;
    ctrlr   = parm.ctrlr ;
    cNum    = parm.cNum ;
    modelId = parm.modelId ;
    dFilter = parm.dFilter ;

    if cType == 4 % If smithDist, calculate Smith controller
        cType = 3 ;
    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
            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 = pidstd(C.Kc, C.tau_i, C.tau_d) ;
                        C.tf = C.Kc*(1 + 1/C.tau_i/s)*...
                              (C.tau_d*s+1) ;
                    end
                case 2  % PI
                    C.type = 'simc:pi' ;
                    C.tf = pidstd(C.Kc, C.tau_i) ;
            end
        case 3 % SMITH
            switch ctrlr
                case 1 % PID
                    C.type = 'smith:pid' ;
                    C.Kc = ctrl(1); C.I = ctrl(2); C.D = ctrl(3);
                    C.alph = parm.alph; C.F = C.alph*C.D ;
                    switch cNum
                        case 1  % Chriss': C = Kc((1 - I - D) + I/s + Ds)
                            if dFilter % is active
                                C.tfstd = C.Kc*((1-C.I-C.D) + ...
                                          C.I/s + C.D*s/...
                                          (C.alph*C.D*s+1)) ;
                            else
                                C.tfstd = C.Kc*((1-C.I-C.D) + ...
                                          C.I/s + C.D*s) ; 
                            end % dFilter
                        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)
                            if dFilter % is active
                                C.tfstd = C.Kc*(1+C.I/s + ...
                                    C.D*s/(C.alph*C.D*s + 1)) ;
                            else
                                C.tfstd = C.Kc*(1+C.I/s+C.D*s) ;
                            end
                            % C.tfstd = pidstd(C.Kc, C.I, C.D) ;
                        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
    end
end