function sys = pid(varargin)
%PID  Create a PID controller in parallel form.
%
%  Construction:
%    SYS = PID(Kp,Ki,Kd,Tf) creates a continuous-time PID controller
%    in parallel form with a first-order derivative filter:
%
%               Ki      Kd*s
%         Kp + ---- + --------
%               s      Tf*s+1
%
%    The scalars Kp, Ki, Kd, and Tf specify the proportional gain,
%    integral gain, derivative gain, and filter time constant. The Tf
%    value must be nonnegative for stability. The default values are
%    Kp=1, Ki=0, Kd=0, and Tf=0. If a parameter is omitted, its default
%    value is used. For example, PID(Kp,Ki,Kd) creates a PID controller
%    with pure derivative term. The resulting SYS is of type PID if
%    Kp,Ki,Kd,Tf are all real, and of type GENSS if one of the gains
%    is tunable (see REALP and GENMAT).
%
%    SYS = PID(Kp,Ki,Kd,Tf,Ts) creates a discrete-time PID controller
%    with sample time Ts>0. The discrete-time PID formula is
%
%                                 Kd
%         Kp + Ki * IF(z) + --------------
%                             Tf  +  DF(z)
%
%    where IF(z) and DF(z) are the discrete integrator formulas for the
%    integral and derivative terms. Use the "IFormula" and "DFormula"
%    properties to specify these formulas. Available formulas include:
%
%        'ForwardEuler'        Ts/(z-1)
%        'BackwardEuler'      Ts*z/(z-1)
%        'Trapezoidal'     (Ts/2)*(z+1)/(z-1)
%
%    The default formula is ForwardEuler. The 'IFormula' and 'DFormula'
%    settings are ignored for continuous-time PIDs. The following
%    settings are disallowed because they generate unstable PIDs:
%
%        (1) Type='PID' and DFormula='Trapezoidal'
%        (2) Type='PIDF' and DFormula='ForwardEuler' and Ts>=2*Tf
%
%    You can set additional properties by using name/value pairs.
%    For example,
%        sys = pid(1,2,3,0.5,0.1,'IFormula','T','TimeUnit','min')
%    also specifies the integral-term formula and the time units. Type
%    "properties(pid)" for a complete list of PID properties, and type
%        help pid.<PropertyName>
%    for help on a particular property.
%
%    You can create arrays of PID objects by specifying arrays of values
%    for Kp,Ki,Kd,Tf. For example, if Kp and Ki are 3-by-4 arrays,
%    PID(Kp,Ki) creates a 3-by-4 array of PID controllers.
%
%  Conversion:
%    PIDSYS = PID(SYS) converts the dynamic system SYS to a PID object.
%    An error is thrown when SYS cannot be expressed as a PID controller
%    in parallel form.
%
%    PIDSYS = PID(SYS,'IFormula',Value1,'DFormula',Value2) returns an
%    equivalent PID controller with different formulas for the integral
%    and derivative terms.
%
%  See also PIDSTD, PID2, PIDSTD2, tunablePID, tunablePID2, TF.

%   Copyright 2009-2012 The MathWorks, Inc.

[DataInputs,Ts,IF,DF,Options] = StaticModel.utProcessPIDInputs('1dof',varargin{:});

if DataInputs>5
    error(message('Control:general:InvalidSyntaxForCommand','pid','pid'))
end

% Process numerical data
Ki = [];  Kd = [];  Tf = []; % defaults
try
    switch DataInputs
        case 1
            % PID(Kp)
            Kp = StaticModel.utCheckPIDGain('Kp',varargin{1});
        case 2
            % PID(Kp,Ki)
            Kp = StaticModel.utCheckPIDGain('Kp',varargin{1});
            Ki = StaticModel.utCheckPIDGain('Ki',varargin{2});
        case 3
            % PID(Kp,Ki,Kd): Not supported (improper)
            error(message('Control:lftmodel:pid3'))
        otherwise
            % PID(Kp,Ki,Kd,Tf,...)
            Kp = StaticModel.utCheckPIDGain('Kp',varargin{1});
            Ki = StaticModel.utCheckPIDGain('Ki',varargin{2});
            Kd = StaticModel.utCheckPIDGain('Kd',varargin{3});
            Tf = StaticModel.utCheckPIDGain('Tf',varargin{4});
    end
    
    sys = StaticModel.utConstructPID(Kp,Ki,Kd,Tf,Ts,IF,DF,Options);
catch ME
    throw(ME)
end

