function sys = tf(varargin)
%TF  Construct transfer function or convert to transfer function.
%
%  Construction:
%    SYS = TF(NUM,DEN) creates a continuous-time transfer function SYS with
%    numerator NUM and denominator DEN. SYS is an object of type TF when 
%    NUM,DEN are numeric arrays, of type GENSS when NUM,DEN depend on tunable 
%    parameters (see REALP and GENMAT), and of type USS when NUM,DEN are 
%    uncertain (requires Robust Control Toolbox).
%
%    SYS = TF(NUM,DEN,TS) creates a discrete-time transfer function with
%    sample time TS (set TS=-1 if the sample time is undetermined).
%
%    S = TF('s') specifies the transfer function H(s) = s (Laplace variable).
%    Z = TF('z',TS) specifies H(z) = z with sample time TS.
%    You can then specify transfer functions directly as expressions in S
%    or Z, for example,
%       s = tf('s');  H = exp(-s)*(s+1)/(s^2+3*s+1)
%
%    SYS = TF creates an empty TF object.
%    SYS = TF(M) specifies a static gain matrix M.
%
%    You can set additional model properties by using name/value pairs.
%    For example,
%       sys = tf(1,[1 2 5],0.1,'Variable','q','ioDelay',3)
%    also sets the variable and transport delay. Type "properties(tf)"
%    for a complete list of model properties, and type
%       help tf.<PropertyName>
%    for help on a particular property. For example, "help tf.Variable"
%    provides information about the "Variable" property.
%
%    By default, transfer functions are displayed as functions of 's' or 'z'.
%    Alternatively, you can use the variable 'p' in continuous time and the
%    variables 'z^-1', 'q', or 'q^-1' in discrete time by modifying the
%    "Variable" property.
%
%  Data format:
%    For SISO models, NUM and DEN are row vectors listing the numerator
%    and denominator coefficients in descending powers of s,p,z,q or in
%    ascending powers of z^-1 (DSP convention). For example,
%       sys = tf([1 2],[1 0 10])
%    specifies the transfer function (s+2)/(s^2+10) while
%       sys = tf([1 2],[1 5 10],0.1,'Variable','z^-1')
%    specifies (1 + 2 z^-1)/(1 + 5 z^-1 + 10 z^-2).
%
%    For MIMO models with NY outputs and NU inputs, NUM and DEN are
%    NY-by-NU cell arrays of row vectors where NUM{i,j} and DEN{i,j}
%    specify the transfer function from input j to output i. For example,
%       H = tf( {-5 ; [1 -5 6]} , {[1 -1] ; [1 1 0]})
%    specifies the two-output, one-input transfer function
%       [     -5 /(s-1)      ]
%       [ (s^2-5s+6)/(s^2+s) ]
%
%  Arrays of transfer functions:
%    You can create arrays of transfer functions by using ND cell arrays
%    for NUM and DEN above. For example, if NUM and DEN are cell arrays
%    of size [NY NU 3 4], then
%       SYS = TF(NUM,DEN)
%    creates the 3-by-4 array of transfer functions
%       SYS(:,:,k,m) = TF(NUM(:,:,k,m),DEN(:,:,k,m)),  k=1:3,  m=1:4.
%    Each of these transfer functions has NY outputs and NU inputs.
%
%    To pre-allocate an array of zero transfer functions with NY outputs
%    and NU inputs, use the syntax
%       SYS = TF(ZEROS([NY NU k1 k2...])) .
%
%  Conversion:
%    SYS = TF(SYS) converts any dynamic system SYS to the transfer function 
%    representation. The resulting SYS is always of class TF.
%
%  See also TF/EXP, FILT, TFDATA, ZPK, SS, FRD, GENSS, USS, DYNAMICSYSTEM.

%   Copyright 2009-2010 The MathWorks, Inc.

% Dissect input list
ni = nargin;
PVStart = min([ni+1 find(cellfun(@(x) (ischar(x) || isStringScalar(x)),varargin),1)]);
DataInputs = PVStart-1;
try
   switch DataInputs
      case 1
         % tf(GENMAT/UMAT)
         sys = ss(varargin{1});
      case {2,3}
         num = localCheckNumDen(varargin{1});
         den = localCheckNumDen(varargin{2});
         if DataInputs<3
            Ts = 0;
         else
            Ts = ltipack.utValidateTs(varargin{3});
         end
         
         % Harmonize types of NUM,DEN (either numeric or StaticModel at this point)
         [num,den] = ltipack.matchType('',num,den);
         
         % Construct GENSS or USS model
         sys = tfModel_(num,den,Ts);
      otherwise
         error(message('Control:general:InvalidSyntaxForCommand','tf','tf'))
   end
   % Process additional settings
   if PVStart<=ni
      sys = set(sys,varargin{PVStart:ni});
   end
catch ME
   throw(ME)
end


%----------------
function M = localCheckNumDen(M)
% Check that M is a numeric or StaticModel row vector
if isnumeric(M)
   % Convert to full double
   if issparse(M)
      M = full(M);
   end
   M = double(M);
elseif ~isa(M,'StaticModel')
   error(message('Control:lftmodel:tf1'))
elseif size(M,1)~=1
   error(message('Control:lftmodel:tf2'))
end

