Mercurial > hg > ltpda
diff m-toolbox/classes/@ssm/bode.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/bode.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,264 @@ +% BODE makes a bode plot from the given inputs to outputs. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: BODE makes a bode plot from the given inputs to outputs. +% +% CALL: mat_out = bode(sys, pl) +% mat_out = bode(sys, 'key1', 'option1') +% +% INPUTS: +% 'sys' - ssm object +% 'pl' - plist of options +% +% OUTPUTS: +% +% 'mat_out' - matrix of output AOs containing the requested responses. +% +% <a href="matlab:utils.helper.displayMethodInfo('ssm', 'bode')">Parameter Sets</a> +% +% VERSION: $Id: bode.m,v 1.40 2011/04/17 21:28:05 adrien Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function varargout = bode(varargin) + + % use the caller is method flag + callerIsMethod = utils.helper.callerIsMethod; + + % Check if this is a call for parameters + if utils.helper.isinfocall(varargin{:}) + varargout{1} = getInfo(varargin{3}); + return + end + + if callerIsMethod + % assume bode(sys,pl) + system = varargin{1}; + pl = applyDefaults(getDefaultPlist(), varargin{2}); + else + % starting initial checks + + utils.helper.msg(utils.const.msg.PROC3, ['running ', mfilename]); + + % Collect input variable names + in_names = cell(size(varargin)); + for ii = 1:nargin,in_names{ii} = inputname(ii);end + + % Collect all AOs and plists + [system, ssm_invars, rest] = utils.helper.collect_objects(varargin(:), 'ssm', in_names); + [pl, invars2, rest] = utils.helper.collect_objects(rest(:), 'plist'); + + % combine default plist + if ~isempty(rest) + pl = combine(pl, plist(rest{:})); + end + pl = combine(pl, getDefaultPlist()); + + % retrieving system's infos + if numel(system)~=1 + error('we should have only one ssm and one plist object as an input') + end + + inhist = system.hist; + if ~system.isStable + error('input ssm is not stable!') + end + + end + + if (system.isnumerical == 0) + warning(['The system ' system.name ' is symbolic. The system is made numeric for bode calculation.']) + sys = copy(system,1); + sys.keepParameters; + else + sys = system; + end + + % Compute frequency vector + f = pl.find('f'); + if isempty(f) + % finding "f2" + if isempty(pl.find('f2')) + if sys.timestep>0 + f2 = 0.5/sys.timestep; + else + f2 = 1; + end + else + f2 = pl.find('f2'); + end + % finding "f1" + if isempty(pl.find('f1')) + f1 = f2*1e-5; + else + f1 = pl.find('f1'); + end + nf = pl.find('nf'); + scale = pl.find('scale'); + % building "f" vector + switch lower(scale) + case 'log' + f = logspace(log10(f1), log10(f2), nf); + case 'lin' + f = linspace(f1, f2, nf); + otherwise + error('### Unknown scale option'); + end + end + + % Is the f vector in an AO? + if isa(f, 'ao') && (isa(f.data, 'fsdata') || isa(f.data, 'xydata')) + f = f.x; + end + + % Compute omega + w = 2*pi*f; + + if find(pl, 'reorganize') + sys = reorganize(sys, pl, 'set', 'for bode', 'internal', 'internal'); + end + + % getting system's i/o sizes + timestep = sys.timestep; + fs = 1/timestep; + + inputSizes = sys.inputsizes; + outputSizes = sys.outputsizes; + + Nin = inputSizes(1); + NstatesOut = outputSizes(1); + NoutputsOut = outputSizes(2); + + A = sys.amats{1,1}; + Coutputs = sys.cmats{2,1}; + Cstates = sys.cmats{1,1}; + B = sys.bmats{1,1}; + D = sys.dmats{2,1}; + Dstates = zeros(size(Cstates,1), size(D,2)); + + % bode computation + resps = ssm.doBode(A, B, [Cstates; Coutputs], [Dstates; D], w, timestep); + + numericOutput = pl.find('numeric output'); + + % build AO + if numericOutput + % just output pure numbers + count = 1; + + for ii=1:Nin + for oo=1:NoutputsOut + y = squeeze(resps(NstatesOut+oo,ii,:)); + varargout{count} = y; + count = count + 1; + end + end + return; + else + % First make outputs and set the data + ao_out = ao.initObjectWithSize(NstatesOut+NoutputsOut, Nin); + for ii=1:Nin + for oo=1:NstatesOut + ao_out(oo,ii).setData(fsdata(f, squeeze(resps(oo,ii,:)), fs)); + end + for oo=1:NoutputsOut + y = squeeze(resps(NstatesOut+oo,ii,:)); + fsd = fsdata(f, y, fs); + ao_out(NstatesOut+oo,ii).setData(fsd); + end + end + + if ~callerIsMethod + % set names, units, description, and add history + isysStr = sys.name; + + for ii=1:Nin + for oo=1:NstatesOut + ao_out(oo,ii).setName( [sys.inputs(1).ports(ii).name '-->' sys.outputs(1).ports(oo).name]); + ao_out(oo,ii).setXunits('Hz'); + ao_out(oo,ii).setYunits( simplify(sys.outputs(1).ports(oo).units / sys.inputs(1).ports(ii).units)); + ao_out(oo,ii).setDescription(... + ['Bode of ' isysStr, ' from ', sys.inputs(1).ports(ii).description,... + ' to ' sys.outputs(1).ports(oo).description]); + end + for oo=1:NoutputsOut + ao_out(NstatesOut+oo,ii).setName( [sys.inputs(1).ports(ii).name '-->' sys.outputs(2).ports(oo).name]); + ao_out(NstatesOut+oo,ii).setXunits('Hz'); + ao_out(NstatesOut+oo,ii).setYunits( simplify(sys.outputs(2).ports(oo).units / sys.inputs(1).ports(ii).units)); + ao_out(NstatesOut+oo,ii).setDescription(... + ['Bode of ' isysStr, ' from ', sys.inputs(1).ports(ii).description,... + ' to ' sys.outputs(2).ports(oo).description]); + end + end + end + end + + %% construct output matrix object + out = matrix(ao_out); + if callerIsMethod + % do nothing + else + myinfo = getInfo('None'); + out.addHistory(myinfo, pl , ssm_invars(1), inhist ); + end + + %% Set output depending on nargout + if nargout == 1; + varargout = {out}; + elseif nargout == 0; + iplot(ao_out); + else + error('Wrong number of outputs') + end + +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.sigproc, '$Id: bode.m,v 1.40 2011/04/17 21:28:05 adrien Exp $', sets, pl); +end + +%-------------------------------------------------------------------------- +% Get Default Plist +%-------------------------------------------------------------------------- +function pl = getDefaultPlist() + pl = ssm.getInfo('reorganize', 'for bode').plists; + pl.remove('set'); + + p = param({'f', 'A frequency vector (replaces f1, f2 and nf).'}, paramValue.EMPTY_DOUBLE) ; + pl.append(p); + + p = param({'f2', 'The maximum frequency. Default is Nyquist or 1Hz.'}, paramValue.EMPTY_DOUBLE); + pl.append(p); + + p = param({'f1', 'The minimum frequency. Default is f2*1e-5.'}, paramValue.EMPTY_DOUBLE); + pl.append(p); + + p = param({'nf', 'The number of frequency bins.'}, paramValue.DOUBLE_VALUE(1000)); + pl.append(p); + + p = param({'scale', 'Distribute frequencies on a ''log'' or ''lin'' scale.'}, {1, {'log', 'lin'}, paramValue.SINGLE}); + pl.append(p); + + p = param({'reorganize', 'When set to 0, this means the ssm does not need be modified to match the requested i/o. Faster but dangerous!'}, paramValue.TRUE_FALSE); + pl.append(p); + + p = param({'numeric output', 'When set to ture, the output of bode will be purely numeric - no analysis objects.'}, paramValue.FALSE_TRUE); + pl.append(p); + +end + + +