File: dmr2d.m

package info (click to toggle)
octave-control 1.0.11-2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,628 kB
  • ctags: 160
  • sloc: makefile: 64; sh: 4
file content (255 lines) | stat: -rw-r--r-- 8,220 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
## Copyright (C) 1998, 2000, 2002, 2004, 2005, 2006, 2007
##               Auburn University.  All rights reserved.
##
##
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## This program is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn {Function File} {[@var{dsys}, @var{fidx}] =} dmr2d (@var{sys}, @var{idx}, @var{sprefix}, @var{ts2}, @var{cuflg})
## convert a multirate digital system to a single rate digital system
## states specified by @var{idx}, @var{sprefix} are sampled at @var{ts2}, all
## others are assumed sampled at @var{ts1} = @code{sysgettsam (@var{sys})}.
##
## @strong{Inputs}
## @table @var
## @item   sys
## discrete time system;
## @code{dmr2d} exits with an error if @var{sys} is not discrete
## @item   idx
## indices or names of states with sampling time 
## @code{sysgettsam(@var{sys})} (may be empty); see @code{cellidx}
## @item   sprefix
## list of string prefixes of states with sampling time
## @code{sysgettsam(@var{sys})} (may be empty)
## @item   ts2
## sampling time of states not specified by @var{idx}, @var{sprefix}
## must be an integer multiple of @code{sysgettsam(@var{sys})}
## @item   cuflg
## "constant u flag" if @var{cuflg} is nonzero then the system inputs are
## assumed to be constant over the revised sampling interval @var{ts2}.
## Otherwise, since the inputs can change during the interval
## @var{t} in @math{[k ts2, (k+1) ts2]}, an additional set of inputs is
## included in the revised B matrix so that these intersample inputs
## may be included in the single-rate system.
## default @var{cuflg} = 1.
## @end table
##
## @strong{Outputs}
## @table @var
## @item   dsys
## equivalent discrete time system with sampling time @var{ts2}.
##
## The sampling time of sys is updated to @var{ts2}.
##
## if @var{cuflg}=0 then a set of additional inputs is added to
## the system with suffixes _d1, @dots{}, _dn to indicate their
## delay from the starting time k @var{ts2}, i.e.
## u = [u_1; u_1_d1; @dots{}, u_1_dn] where u_1_dk is the input
## k*ts1 units of time after u_1 is sampled. (@var{ts1} is
## the original sampling time of the discrete time system and
## @var{ts2} = (n+1)*ts1)
##
## @item   fidx
## indices of "formerly fast" states specified by @var{idx} and @var{sprefix};
## these states are updated to the new (slower) sampling interval @var{ts2}.
## @end table
##
## @strong{WARNING} Not thoroughly tested yet; especially when
## @var{cuflg} == 0.
## @end deftypefn

## Adapted from c2d by a.s.hodel@eng.auburn.edu

function [dsys, fidx] = dmr2d (sys, idx, sprefix, Ts2, cuflg)

  ## parse input arguments
  if (nargin != 4)
    print_usage ();
  elseif (! isstruct (sys))
    error ("sys must be in system data structure form");
  elseif (! is_digital (sys))
    error ("sys must be discrete-time; continuous time passed");
  endif

  if (is_signal_list (idx) || ischar (idx))
    idx = sysidx (sys, "st", idx);
  elseif (! (isvector (idx) || isempty (idx)))
    error ("idx(%dx%d) must be a vector", rows (idx), columns (idx));
  elseif (any (idx <= 0))
    idv = find (idx <= 0);
    ii = idv(1);
    error ("idx(%d)=%g; entries of idx must be positive", ii, idx(ii));
  elseif (! (is_signal_list (sprefix) || isempty (sprefix)))
    error ("sprefix must be a signal list (see is_signal_list) or empty");
  elseif (! is_sample (Ts2))
    error ("Ts2=%g; invalid sampling time", Ts2);
  endif

  ## optional argument: cuflg
  if (nargin <= 4)
    cuflg = 1;          # default: constant inputs over Ts2 sampling interv.
  elseif (! isscalar (cuflg))
    error ("cuflg must be a scalar")
  elseif (cuflg != 0 || cuflg != 1)
    error ("cuflg = %g, should be 0 or 1", cuflg);
  endif

  ## extract  state space information
  [da, db, dc, dd, Ts1, nc, nz, stname, inname, outname, yd] = sys2ss (sys);

  ## compute number of steps
  if (Ts1 > Ts2)
    error ("Current sampling time=%g > Ts2=%g", Ts1, Ts2);
  endif
  nstp = floor (Ts2/Ts1+0.5);
  if (abs ((Ts2 - Ts1*nstp)/Ts1) > 1e-12)
    warning ("dmr2d: Ts1=%g, Ts2=%g, selecting nsteps=%d; mismatch",
	     Ts1, Ts2, nstp);
  endif

  if (isempty (sprefix) && isempty (idx))
    warning ("both sprefix and idx are empty; returning dsys=sys");
    fidx = [];
    dsys = sys;
    return
  elseif (isempty (sprefix))
    fidx = idx;
  else
    fidx = reshape (idx, 1, length(idx));
    ## find states whose name begins with any strings in sprefix.
    ns = length (sprefix);
    for kk = 1:ns
      spk = sprefix{kk};  # get next prefix and length
      spl = length (spk);

      ## check each state name
      for ii = 1:nz
        sti = stname{ii};  # compare spk with this state name
        if (length (sti) >= spl)
          ## if the prefix matches and ii isn't already in the list, add ii
          if (strcmp (sti(1:spl), spk) && ! any (fidx == ii))
            fidx = sort ([fidx, ii]);
          endif
        endif
      endfor
    endfor
  endif

  if (nstp == 0)
    warning ("dmr2d: nstp = 0; setting tsam and returning");
    dsys = syschtsam (sys, Ts2);
    return;
  elseif (nstp < 0)
    error ("nstp = %d < 0; this shouldn't be!", nstp);
  endif

  ## permute system matrices
  pv = sysreorder (nz, fidx);
  pv = pv(nz:-1:1);          # reverse order to put fast modes in leading block

  ## construct inverse permutation
  Inz = eye (nz);
  pvi = (Inz(pv,:)'*[1:nz]')';

  ## permute A, B (stname permuted for debugging only)
  da = da(pv,pv);
  db = db(pv,:);
  stname = stname (pv);

  ## partition A, B:
  lfidx = length (fidx);
  bki = 1:lfidx;
  a11 = da(bki,bki);
  b1 = db(bki,:);

  if (lfidx < nz)
    lfidx1 = lfidx+1;
    bki2 = (lfidx1):nz;
    a12 = da(bki,bki2);
    b2 = db(bki2,:);
  else
    warning ("dmr2d: converting entire A,B matrices to new sampling rate");
    lfidx1 = -1;
    bki2 = [];
  endif

  ## begin system conversion: nstp steps

  ## compute abar_{n-1}*a12 and appropriate b matrix stuff
  a12b = a12;      # running  total of abar_{n-1}*a12
  a12w = a12;      # current a11^n*a12  (start with n = 0)
  if (cuflg)
    b1b = b1;
    b1w = b1;
  else
    ## cuflg == 0, need to keep track of intersample inputs too
    ## FIXME: check tolerance relative to ||b1||
    nzdx = find (max (abs (b1)) != 0);
    b1w = b1(nzdx);
    innamenz = inname(nzdx);
    b1b = b1;                        # initial b1 must match columns in b2
  endif

  ## compute a11h = a11^nstp by squaring
  a11h = eye (size (a11));
  p2 = 1;
  a11p2 = a11;        #a11^p2

  nstpw = nstp;       # workspace for computing a11^nstp
  while (nstpw > 0.5)
    oddv = rem (nstpw, 2);
    if (oddv)
      a11h = a11h*a11p2;
    endif
    nstpw = (nstpw-oddv)/2;
    if (nstpw > 0.5)
      a11p2 = a11p2*a11p2;    # a11^(next power of 2)
    endif
  endwhile

  ## FIXME: this part should probably also use squaring, but
  ## that would require exponentially growing memory.  What do do?
  for kk = 2:nstp
    ## update a12 block to sum(a12 + ... + a11^(kk-1)*a12)
    a12w = a11*a12w;
    a12b = a12b + a12w;

    ## similar for b1 block (checking for cuflg first!)
    b1w = a11*b1w;
    if (cuflg)
      b1b = b1b + b1w;        # update b1 block just like we did a12
    else
      b1b = [b1b, b1w];       # append new inputs
      newin = sprintf ("%s_d%d", innamenz, kk-1);
      inname = __sysconcat__ (inname, newin);
    endif
  endfor

  ## reconstruct system and return
  da(bki,bki) = a11h;
  db(bki,1:columns(b1b)) = b1b;
  if (! isempty (bki2))
    da(bki,bki2) = a12b;
  endif

  da = da(pvi,pvi);
  db = db(pvi,:);
  stname = stname(pvi);

  ## construct new system and return
  dsys = ss (da, db, dc, dd, Ts2, 0, nz, stname, inname, outname,
	     find (yd == 1));

endfunction