diff scripts/control/system/dmr2d.m @ 3431:99ab64f4a09d

[project @ 2000-01-14 03:53:03 by jwe]
author jwe
date Fri, 14 Jan 2000 04:12:41 +0000
parents
children 04aef7306dca
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/scripts/control/system/dmr2d.m
@@ -0,0 +1,259 @@
+## Copyright (C) 1998 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 2, 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, write to the Free
+## Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+
+## -*- 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
+## list of states with sampling time @code{sysgettsam(@var{sys})} (may
+## be empty)
+## @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, ..., _dn to indicate their
+## delay from the starting time k @var{Ts2}, i.e.
+## u = [u_1; u_1_d1; ..., u_1_dn] where u_1_dk is the input
+## k*Ts1 units of time after u_1 is sampled. (Ts1 is
+## the original sampling time of discrete time sys 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 | nargout > 2)
+    usage("[dsys,fidx] = dmr2d (sys, idx, sprefix, Ts2 {,cuflg})");
+
+  elseif (!is_struct(sys))
+    error("sys must be in system data structure form");
+
+  elseif(!is_digital(sys))
+    error("sys must be discrete-time; continuous time passed");
+
+  elseif (!(is_vector(idx) | isempty(idx)))
+    error(["idx(",num2str(rows(idx)),"x",num2str(columns(idx)), ...
+      ") must be a vector"]);
+
+  elseif (any(idx <= 0))
+    idv = find(idx <= 0);
+    ii = idv(1);
+    error(["idx(",num2str(ii),")=",num2str(idx(ii)), ...
+      "; entries of idx must be positive"]);
+
+  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=",num2str(Ts2),"; invalid sampling time"]);
+
+  endif
+
+  ## optional argument: cuflg
+  if(nargin <= 4)
+    cuflg = 1;          # default: constant inputs over Ts2 sampling interv.
+  elseif( !is_scalar(cuflg) )
+    error("cuflg must be a scalar")
+  elseif( cuflg != 0 | cuflg != 1)
+    error(["cuflg = ",num2str(cuflg),", should be 0 or 1"]);
+  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=",num2str(Ts1),"< Ts2=",num2str(Ts2)]);
+  endif
+  nstp = floor(Ts2/Ts1+0.5);
+  if(abs((Ts2 - Ts1*nstp)/Ts1) > 1e-12)
+    warning(["dmr2d: Ts1=",num2str(Ts1),", Ts2=",num2str(Ts2), ...
+      ", selecting nsteps=",num2str(nstp),"; mismatch"]);
+  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 = nth(sprefix,kk);  # get next prefix and length
+      spl = length(spk);
+
+      ## check each state name
+      for ii=1:nz
+        sti = nth(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 = ", num2str(nstp)," < 0; this shouldn't be!"]);
+  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
+    nzdx = find(max(abs(b1)) != 0);  # FIXME: check tolerance relative to ||b1||
+    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 = strappend(innamenz,["_d",num2str(kk-1)]);
+      inname = append(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 = ss2sys(da,db,dc,dd,Ts2,0,nz,stname,inname,outname,find(yd == 1));
+
+endfunction