1## Copyright (C) 2009-2016   Lukas F. Reichlin
2##
3## This file is part of LTI Syncope.
4##
5## LTI Syncope is free software: you can redistribute it and/or modify
6## it under the terms of the GNU General Public License as published by
7## the Free Software Foundation, either version 3 of the License, or
8## (at your option) any later version.
9##
10## LTI Syncope is distributed in the hope that it will be useful,
11## but WITHOUT ANY WARRANTY; without even the implied warranty of
12## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13## GNU General Public License for more details.
14##
15## You should have received a copy of the GNU General Public License
16## along with LTI Syncope.  If not, see <http://www.gnu.org/licenses/>.
17
18## -*- texinfo -*-
19## @deftypefn {Function File} {@var{s} =} zpk (@var{'s'})
20## @deftypefnx {Function File} {@var{z} =} zpk (@var{'z'}, @var{tsam})
21## @deftypefnx {Function File} {@var{sys} =} zpk (@var{sys})
22## @deftypefnx {Function File} {@var{sys} =} zpk (@var{k}, @dots{})
23## @deftypefnx {Function File} {@var{sys} =} zpk (@var{z}, @var{p}, @var{k}, @dots{})
24## @deftypefnx {Function File} {@var{sys} =} zpk (@var{z}, @var{p}, @var{k}, @var{tsam}, @dots{})
25## @deftypefnx {Function File} {@var{sys} =} zpk (@var{z}, @var{p}, @var{k}, @var{tsam}, @dots{})
26## Create transfer function model from zero-pole-gain data.
27## This is just a stop-gap compatibility wrapper since zpk
28## models are not yet implemented.
29##
30## @strong{Inputs}
31## @table @var
32## @item sys
33## @acronym{LTI} model to be converted to transfer function.
34## @item z
35## Cell of vectors containing the zeros for each channel.
36## z@{i,j@} contains the zeros from input j to output i.
37## In the SISO case, a single vector is accepted as well.
38## @item p
39## Cell of vectors containing the poles for each channel.
40## p@{i,j@} contains the poles from input j to output i.
41## In the SISO case, a single vector is accepted as well.
42## @item k
43## Matrix containing the gains for each channel.
44## k(i,j) contains the gain from input j to output i.
45## @item tsam
46## Sampling time in seconds.  If @var{tsam} is not specified,
47## a continuous-time model is assumed.
48## @item @dots{}
49## Optional pairs of properties and values.
50## Type @command{set (tf)} for more information.
51## @end table
52##
53## @strong{Outputs}
54## @table @var
55## @item sys
56## Transfer function model.
57## @end table
58##
59## @seealso{tf, ss, dss, frd}
60## @end deftypefn
61
62## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
63## Created: September 2011
64## Version: 0.2
65
66function sys = zpk (varargin)
67
68  if (nargin <= 1)                  # zpk (),  zpk (sys),  zpk (k),  zpk ('s')
69    sys = tf (varargin{:});
70    return;
71  elseif (nargin == 2 ...
72          && ischar (varargin{1}))  # zpk ('z', tsam)
73    sys = tf (varargin{:});
74    return;
75  endif
76
77  z = {}; p = {}; k = [];           # default values
78  tsam = 0;                         # default sampling time
79
80  [mat_idx, opt_idx] = __lti_input_idx__ (varargin);
81
82  switch (numel (mat_idx))
83    case 1
84      k = varargin{mat_idx};
85    case 3
86      [z, p, k] = varargin{mat_idx};
87    case 4
88      [z, p, k, tsam] = varargin{mat_idx};
89      if (isempty (tsam) && is_real_matrix (tsam))
90        tsam = -1;
91      elseif (! issample (tsam, -10))
92        error ("zpk: invalid sampling time");
93      endif
94    case 0
95      ## nothing to do here, just prevent case 'otherwise'
96    otherwise
97      print_usage ();
98  endswitch
99
100  varargin = varargin(opt_idx);
101
102  if (isempty (z) && isempty (p) && is_real_matrix (k))
103    sys = tf (k, varargin{:});
104    return;
105  endif
106
107  if (! iscell (z))
108    z = {z};
109  endif
110
111  if (! iscell (p))
112    p = {p};
113  endif
114
115  if (! size_equal (z, p, k))
116    error ("zpk: arguments 'z', 'p' and 'k' must have equal dimensions");
117  endif
118
119  ## NOTE: accept [], scalars and vectors but not matrices as 'z' and 'p'
120  ##       because  poly (matrix)  returns the characteristic polynomial
121  ##       if the matrix is square!
122
123  if (! is_zp_vector (z{:}, 1))  # last argument 1 needed if z is empty cell
124    error ("zpk: first argument 'z' must be a vector or a cell of vectors");
125  endif
126
127  if (! is_zp_vector (p{:}, 1))
128    error ("zpk: second argument 'p' must be a vector or a cell of vectors")
129  endif
130
131  if (! is_real_matrix (k))
132    error ("zpk: third argument 'k' must be a real-valued gain matrix");
133  endif
134
135  num = cellfun (@(zer, gain) real (gain * poly (zer)), z, num2cell (k), "uniformoutput", false);
136  den = cellfun (@(pol) real (poly (pol)), p, "uniformoutput", false);
137
138  sys = tf (num, den, tsam, varargin{:});
139
140endfunction
141