diff m-toolbox/classes/@ssm/assemble.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ssm/assemble.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,254 @@
+% assembles embedded subsytems, with exogenous inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: assemble assembles embedded subsytems, closes loop
+%             (endogenous inputs disappear) leaving outputs and exogenous
+%             inputs. SSM content is copied.
+%
+% CALL: sys = ltpda_ss_assemble(sys_array)
+%
+% INPUTS: sys_array - array or list of systems to assemble
+%
+% OUTPUTS: sys - assembled system
+%
+%  <a href="matlab:utils.helper.displayMethodInfo('ssm', 'assemble')">Parameters Description</a>
+%
+% VERSION: $Id: assemble.m,v 1.60 2011/04/08 08:56:22 hewitson Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function   varargout = assemble( varargin )
+  
+  %% Check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+
+  %%% Internal call: Only one object + don't look for a plist
+  internal = strcmp(varargin{end}, 'internal');
+  
+  %% send starting message
+  import utils.const.*
+  utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
+  
+  %% collecting input
+  in_names = cell(size(varargin));
+  for ii = 1:nargin,in_names{ii} = inputname(ii);end
+  
+  % Collect all SSMs and plists
+  [sys, ssm_invars] = utils.helper.collect_objects(varargin(:), 'ssm', in_names);
+  
+  Nsys = numel(sys);
+  
+  % We want to force a copy - this is not a modify method
+  if nargout ~= 1
+    error('### assemble cannot be used as a modifier. Please give exactly one output variable.');
+  end
+  
+  %% Decide on a deep copy or a modify, depending on the output
+  sys_array = copy(sys, true);
+  
+  %% begin function body
+  sys_out = ssm;
+  
+  %% checking there is not problem with the timesteps
+  
+  for i=2:Nsys
+    if ~(sys_array(i-1).timestep == sys_array(i).timestep)
+      error(['At least two ssm have incompatible timestep fields : ' ...
+        num2str(sys_array(i-1).timestep) ' for ''' sys_array(i-1).name ''' and '...
+        num2str(sys_array(i).timestep) ' for ''' sys_array(i).name '''' ]);
+    end
+  end
+  
+  %% merging ss data : ss* output* *input
+  names   = cell(1,0);
+  inputs  = ssmblock.initObjectWithSize(1,0);
+  outputs = ssmblock.initObjectWithSize(1,0);
+  states  = ssmblock.initObjectWithSize(1,0);
+  params  = plist;
+  numparams  = plist;
+  
+  sssizes         = zeros(1,0);
+  ssposition      = zeros(1,0);
+  outputsizes     = zeros(1,0);
+  outputposition  = zeros(1,0);
+  inputsizes      = zeros(1,0);
+  inputposition   = zeros(1,0);
+  
+  for i=1:Nsys
+    params.combine(sys_array(i).params);
+    numparams.combine(sys_array(i).numparams); 
+    inputs = inputs.combine(sys_array(i).inputs, false) ;
+    outputs = [outputs, sys_array(i).outputs] ;
+    states = [states, sys_array(i).states] ;
+    
+    names          = [names          sys_array(i).name           ]; %#ok<*AGROW>
+    sssizes        = [sssizes        sys_array(i).sssizes        ];
+    ssposition     = [ssposition     i*ones(1,sys_array(i).Nss)  ];
+    outputsizes    = [outputsizes    sys_array(i).outputsizes    ];
+    outputposition = [outputposition i*ones(1,sys_array(i).Noutputs) ];
+    inputsizes     = [inputsizes     sys_array(i).inputsizes     ];
+    inputposition  = [inputposition  i*ones(1,sys_array(i).Ninputs)  ];
+  end
+  
+  %% data already good to store
+  sys_out.params     = params;
+  sys_out.numparams  = numparams;
+  sys_out.outputs    = outputs;
+  sys_out.states     = states;
+  
+  %% non redundancy checks :  not necessary anymore on the I/O fields
+  % to be added on subfields ??
+  
+  %% building A, and C matrices
+  amats = {};
+  cmats = {};
+  for i=1:Nsys
+    Namats = size(amats,2);
+    amats = ...
+      [amats                             cell(Namats, sys_array(i).Nss)    ; ...
+      cell(sys_array(i).Nss, Namats)     sys_array(i).amats ] ;
+    cmats = ...
+      [cmats                             cell(size(cmats,1), sys_array(i).Nss)    ; ...
+      cell(sys_array(i).Noutputs, size(cmats,2))            sys_array(i).cmats ] ;
+  end
+  
+  %% construction of B_xx and D_xx matrices
+  inputs_ext = ssmblock.initObjectWithSize(1,0);
+  
+  B_in  = cell( numel(sssizes),     numel(outputsizes) );
+  D_in  = cell( numel(outputsizes), numel(outputsizes) );
+  B_ext = cell( numel(sssizes),     0 );
+  D_ext = cell( numel(outputsizes), 0 );
+  inputsizes = [];
+  Ninputs = 0;
+  for i_sys=1:Nsys
+    for i_input = 1:numel(sys(i_sys).inputs)
+      % current input of a subsystem
+      input_name = sys_array(i_sys).inputs(i_input).name;
+      % does the input match a local output ?
+      [pos_output, sum_output] = findBlockWithNames(outputs, input_name, false);
+      % check it is not already in the external input list
+      [pos_input, sum_input] = findBlockWithNames(inputs_ext, input_name, false);
+
+      if sum_output>0
+        %% if it is an internal input
+        % put at the correct place in the B_in and D_in matrices
+        B_in(ssposition==i_sys, pos_output) = sys_array(i_sys).bmats(:,i_input);
+        D_in(outputposition==i_sys, pos_output) = sys_array(i_sys).dmats(:,i_input);
+        % checking sizes match
+        for i_out = pos_output
+          Nin = sys_array(i_sys).inputs(i_input).Nports;
+          if ~( Nin == outputs(i_out).Nports)
+            error(['I/O sizes not matching between input "' sys_array(i_sys).inputs(i_input).name , ...
+              '" of system "'  sys_array(i_sys).name ' of size ' num2str(Nin) ...
+              '" and the output of size ' num2str(outputs(i_out).Nports) ...
+              ' of the system "' sys_array(outputposition(pos_output)).name '"'] )
+          end
+        end
+      else
+        %% if it is external
+        % if it is not there, add to the input plist
+        if sum_input == 0
+          % extend the size of the input fields
+          inputs_ext = [inputs_ext sys_array(i_sys).inputs(i_input)];
+          inputsizes = [inputsizes sys_array(i_sys).inputsizes(i_input)];
+          B_ext = [B_ext cell(size(B_ext,1),1)];
+          D_ext = [D_ext cell(size(D_ext,1),1)];
+          Ninputs = Ninputs +1;
+          
+          pos_input = numel(inputs_ext);
+        end
+        % put at the correct place in the B_ext and D_ext matrices
+        B_ext(ssposition==i_sys, pos_input) = sys_array(i_sys).bmats(:,i_input);
+        D_ext(outputposition==i_sys, pos_input) = sys_array(i_sys).dmats(:,i_input);
+      end
+    end
+  end
+  sys_out.inputs = inputs_ext;
+  
+  B_ext = ssm.blockMatFillDiag(B_ext, sssizes, inputsizes);
+  D_ext = ssm.blockMatFillDiag(D_ext, outputsizes, inputsizes);
+  B_in  = ssm.blockMatFillDiag(B_in, sssizes, outputsizes);
+  D_in  = ssm.blockMatFillDiag(D_in, outputsizes, outputsizes);
+  cmats = ssm.blockMatFillDiag(cmats, outputsizes, sssizes);
+  %% flattening and getting constant feedthrough
+  D_in_f = ssm.blockMatFusion(D_in, outputsizes,outputsizes);
+  G = (eye(size(D_in_f)) - D_in_f);
+  if isnumeric(G)
+    id_D_inv = inv(G);
+  else
+    id_D_inv = evalin(symengine, ['inverse(' char(G) ')']);
+  end
+  id_D_inv = ssm.blockMatRecut(id_D_inv, outputsizes, outputsizes);
+  
+  sys_out.amats = ssm.blockMatAdd(amats, ssm.blockMatMult(B_in, ssm.blockMatMult(id_D_inv, cmats, outputsizes, sssizes) , sssizes , sssizes ));
+  sys_out.bmats = ssm.blockMatAdd(B_ext, ssm.blockMatMult(B_in, ssm.blockMatMult(id_D_inv, D_ext, outputsizes, inputsizes) , sssizes , inputsizes ));
+  sys_out.cmats = ssm.blockMatMult(id_D_inv, cmats, outputsizes , sssizes );
+  sys_out.dmats = ssm.blockMatMult(id_D_inv, D_ext, outputsizes , inputsizes );
+  
+  %% building new name and strings
+  name = 'assemble( ';
+  for i = 1:Nsys
+    if i==1
+      name = [name, sys_array(i).name ];                        %#ok<AGROW>
+    elseif i<=Nsys
+      name = [name,' + ', sys_array(i).name];                   %#ok<AGROW>
+    end
+  end
+  name = [name ' )'];
+  sys_out.name = name;
+  
+  %% getting timestep and checking consitency
+  for i=1:Nsys
+    if i == 1
+      sys_out.timestep = sys_array(i).timestep;
+    elseif ~ sys_out.timestep == sys_array(i).timestep
+      error(['error because systems 1 and ',num2str(i),...
+        ' named ',sys_array(i).name,' and ',sys_array(i).name,...
+        ' have different timesteps :',...
+        num2str(sys_array(i).timestep),' and ',num2str(sys_array(i).timestep) ]);
+    end
+  end
+  
+  %% setting history and validating
+  if ~internal
+    sys_out.addHistory(ssm.getInfo(mfilename), plist , ssm_invars(:), [sys_array(:).hist] );
+    validate(sys_out);
+  end
+  
+  %% parsing output
+  varargout = {sys_out};
+end
+
+
+
+
+
+%--------------------------------------------------------------------------
+% Get Info Object
+%--------------------------------------------------------------------------
+function ii = getInfo(varargin)
+  
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pl   = [];
+  else
+    sets = {'Default'};
+    pl   = getDefaultPlist;
+  end
+  % Build info object
+  ii = minfo(mfilename, 'ssm', 'ltpda', utils.const.categories.op, '$Id: assemble.m,v 1.60 2011/04/08 08:56:22 hewitson Exp $', sets, pl);
+  ii.setModifier(false);
+  ii.setArgsmin(2);
+end
+
+%--------------------------------------------------------------------------
+% Get Default Plist
+%--------------------------------------------------------------------------
+function pl = getDefaultPlist()
+  pl = plist();
+end
+