Mercurial > octave-nkf
view scripts/control/system/dmr2d.m @ 7135:8aa770b6c5bf
[project @ 2007-11-08 18:54:10 by jwe]
author | jwe |
---|---|
date | Thu, 08 Nov 2007 18:54:10 +0000 |
parents | 1d0d7be2d0f8 |
children |
line wrap: on
line source
## Copyright (C) 1998, 2000, 2002, 2004, 2005, 2006, 2007 ## Auburn University. All rights reserved. ## ## This file is part of Octave. ## ## Octave 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. ## ## Octave 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 Octave; 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