diff m-toolbox/classes/@ao/split.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/@ao/split.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,653 @@
+% SPLIT split an analysis object into the specified segments.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: SPLIT split an analysis object into the specified segments.
+%
+% CALL:        b = split(a, pl)
+%
+% INPUTS:      a  - input analysis object
+%              pl - input parameter list (see below for parameters)
+%
+% OUTPUTS:     b  - array of analysis objects
+%
+%
+% EXAMPLES:    1.) Split method by frequency. Get the values from 10-100 Hz
+%                  pl = plist('frequencies', [10 100]);
+%                  ao_new = split(a1, pl);
+%
+%              2.) Split method by time.
+%                  Get the values from 0.0 to 1.0 Seconds AND from 1.0 to 2.5 seconds
+%                  pl = plist('times', [0.0 1.0 1.0 2.5]);
+%                  ao_new = split(a1, pl);
+%
+%              3.) Split method by samples.
+%                  Get the samples from 1 to 50 AND from 150 to 200.
+%                  pl = plist('samples',     [1 50 150 200]);
+%                  ao_new = split(a1, pl);
+%
+%              4.1) Select an interval with strings
+%                   --> t0 = time('14:00:00')
+%                   pl = plist('start_time', '14:00:01', ...
+%                              'end_time',   '14:00:02');
+%                   ao_new = split(a1, pl);
+%
+%                   --> t0 = time('14:00:00')
+%                   pl = plist('start_time', '14:00:01', ...
+%                              'duration',   '00:00:02');
+%                   ao_new = split(a1, pl);
+%
+%                   Select an interval with seconds
+%                   --> t0 = time(3)
+%                   pl = plist('start_time', 5, ...
+%                              'end_time',   7);
+%                   ao_new = split(a1, pl);
+%
+%              4.2) Select an interval with time objects
+%                   --> t0 = time('14:00:00')
+%                   pl = plist('start_time', time('14:00:01'), ...
+%                              'end_time',   time('14:00:03'));
+%                   ao_new = split(a1, pl);
+%
+%                   --> t0 = time(3)
+%                   pl = plist('start_time', time(5), ...
+%                              'duration',   time(2));
+%                   ao_new = split(a1, pl);
+%
+%              4.3) Select an interval with a time span object
+%                   --> t0 = time('14:00:00')
+%                   pl = plist('timespan', timespan('14:00:00', '14:00:05'));
+%                   ao_new = split(a1, pl);
+%
+% <a href="matlab:utils.helper.displayMethodInfo('ao', 'split')">Parameters Description</a>
+%
+% VERSION:     $Id: split.m,v 1.112 2011/10/05 15:43:36 ingo Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function varargout = split(varargin)
+  
+  callerIsMethod = utils.helper.callerIsMethod;
+  
+  %%% Check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+  
+  import utils.const.*
+  utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
+  
+  if nargout == 0
+    error('### split cannot be used as a modifier. Please give an output variable.');
+  end
+  
+  % Collect input variable names
+  in_names = cell(size(varargin));
+  for ii = 1:nargin,in_names{ii} = inputname(ii);end
+  
+  % Collect all AOs
+  [as, ao_invars] = utils.helper.collect_objects(varargin(:), 'ao', in_names);
+  pli             = utils.helper.collect_objects(varargin(:), 'plist', in_names);
+  
+  % copy input plist
+  pl = combine(pli, plist);
+  % combine input plists (if the input plists are more than one)
+  pl = parse(pl);
+  
+  % Unpack parameter list
+  split_type = find(pl, 'split_type');
+  
+  % Set 'split_type' if some other key-word is set.
+  if pl.isparam('samples')
+    split_type = 'samples';
+  elseif pl.isparam('times') || pl.isparam('frequencies')
+    split_type = 'times';
+  elseif pl.isparam('chunks') || pl.isparam('N')
+    split_type = 'chunks';
+  elseif pl.isparam('start_time') || pl.isparam('timespan')
+    split_type = 'interval';
+  end
+  
+  if isempty(split_type)
+    error('### please specify the key ''split_type'' in the parameter list');
+  end
+  
+  %%% go through analysis objects
+  bo = [];
+  inhists = [];
+  
+  for jj=1:numel(as)
+    
+    % gather the input history objects
+    inhists = [inhists as(jj).hist];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %                       splitting by time or frequency                        %
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    switch lower(split_type)
+      case {'times', 'frequencies'}
+        
+        times       = find(pl, 'times');
+        frequencies = find(pl, 'frequencies');
+        
+        if ~isempty(times)
+          utils.helper.msg(msg.PROC1, 'splitting by time');
+          split_x_axis.type  = 'times';
+          split_x_axis.value =  times;
+          if ~(isa(as(jj).data, 'tsdata') || isa(as(jj).data, 'xydata'))
+            error('### I can only split time-series by times');
+          end
+        else
+          utils.helper.msg(msg.PROC1, 'splitting by frequency');
+          split_x_axis.type  = 'frequencies';
+          split_x_axis.value =  frequencies;
+          if ~isa(as(jj).data, 'fsdata')
+            error('### I can only split frequency-series by frequencies');
+          end
+        end
+        
+        % examine time list
+        ntimes = length(split_x_axis.value);
+        if mod(ntimes, 2) ~= 0
+          error('### please specify a start and stop for each interval.')
+        end
+        % go over each interval now
+        for ii=1:2:ntimes
+          is = split_x_axis.value(ii);
+          ie = split_x_axis.value(ii+1);
+          ish = is; % Backup the start time for the history
+          ieh = ie; % Backup the end time for the history
+          
+          if ie < 0 % indicates count from end
+            if isa(as(jj).data, 'tsdata')
+              ie = as(jj).data.nsecs + as(jj).toffset + ie;
+            else
+              ie = as(jj).x(end) + ie;
+            end
+            if ie < is
+              error('### End time is before the start time.');
+            end
+          elseif ie == 0 % Go to end of vector
+            % x(end) is to small because the find command compares only to
+            % 'less' and not to 'less or equal'
+            ie = as(jj).x(end)+1/as(jj).fs;
+          else
+            ie = ie;
+          end
+          
+          % copy the data-object because we change the values.
+          d = copy(as(jj).data, nargout);
+          
+          % create index of the interval
+          idx = as(jj).x >= is & as(jj).x < ie;
+          
+          % set output data
+          if isempty(as(jj).data.x)
+            % set t0 rounding at a multiplier of the sampling interval
+            if is < as(jj).toffset
+              % Don't change the toffset because the start time is smaller
+              % than the toffset and this means that we collect all data
+              % from the begin of the samples.
+            else
+              d.setToffset((ceil(is*d.fs)/d.fs)*1e3);
+            end
+          else
+            d.setX(as(jj).x(idx));
+          end
+          d.setY(as(jj).data.y(idx));
+          if numel(as(jj).data.dx) > 1
+            d.setDx(as(jj).data.dx(idx));
+          end
+          if numel(as(jj).data.dy) > 1
+            d.setDy(as(jj).data.dy(idx));
+          end
+          if isprop(as(jj).data, 'enbw')
+            if numel(as(jj).data.enbw) > 1
+              d.setEnbw(as(jj).data.enbw(idx));
+            end
+          end
+          
+          % Set nsecs for tsdata
+          if isa(d, 'tsdata')
+            d.collapseX;
+            if ~isempty(d.x)
+              d.setNsecs(d.x(end) - d.x(1) + 1/d.fs);
+            else
+              d.setNsecs(length(d.y)/d.fs);
+            end
+          end
+          
+          % Copy input AO
+          b = copy(as(jj), nargout);
+          b.data = d;
+          
+          if ~callerIsMethod
+            % create new output history
+            b.addHistory(getInfo('None'), pl.pset(split_x_axis.type, [ish ieh]), ao_invars(jj), inhists(jj));
+            % set name
+            b.name = sprintf('split(%s)', ao_invars{jj});
+          end
+          % Add to output array
+          bo = [bo b];
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %                            splitting by samples                             %
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+      case 'samples'
+        
+        utils.helper.msg(msg.PROC1, 'splitting by samples');
+        
+        % examine time list
+        samples = find(pl, 'samples');
+        npairs  = length(samples);
+        if mod(npairs, 2) ~= 0
+          error('### please specify a start and stop for each interval.')
+        end
+        
+        % check data
+        if isa(as(jj).data, 'data2D') && length(as(jj).x) ~= length(as(jj).y)
+          error('### Something is wrong with the x/y vectors. I can''t split this data.');
+        end
+        
+        % go over each interval now
+        for ii=1:2:npairs
+          is = samples(ii);
+          ie = samples(ii+1);
+          
+          utils.helper.msg(msg.PROC1, sprintf('Split: %03d [%d..%d]', (ii+1)/2, is, ie));
+          
+          % copy the data object.
+          d = copy(as(jj).data, nargout);
+          if is > length(d.getY)
+            idx = [];
+          else
+            idx = is:min(ie, length(d.getY));
+          end
+          if isa(d, 'cdata')
+            d.setY(d.getY(idx));
+            if numel(d.getDy) > 1
+              d.setDy(d.getDy(idx));
+            end
+          else
+            % set new samples
+            
+            d.setXY(d.getX(idx), d.getY(idx));
+            % set 'dx' and 'dy' and 'enbw'
+            if numel(d.getDx) > 1
+              d.setDx(d.getDx(idx));
+            end
+            if numel(d.getDy) > 1
+              d.setDy(d.getDy(idx));
+            end
+            if isprop(d, 'enbw')
+              if numel(d.enbw) > 1
+                d.setEnbw(d.enbw(idx));
+              end
+            end
+            % if this is tsdata, we can collapse it again, maybe
+            if isa(d, 'tsdata')
+              [fs,t0,fitted] = tsdata.fitfs(d.x);
+              if ~fitted
+                d.collapseX();
+              end
+            end
+          end
+          
+          % Copy input AO
+          b = copy(as(jj), nargout);
+          b.data = d;
+          
+          if ~callerIsMethod
+            % create new output history
+            b.addHistory(getInfo('None'), pl.pset('samples', [is ie]), ao_invars(jj), inhists(jj));
+            % set name
+            b.name = sprintf('split(%s)[%d]', ao_invars{jj},(ii+1)/2);
+          end
+          % Add to output array
+          bo = [bo b];
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %                            splitting into chunks                            %
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+      case 'chunks'
+        
+        pl = combine(pl, getDefaultPlist('By chunks'));
+        N = find(pl, 'N');
+        if isempty(N)
+          N = pl.find('chunks');
+        end
+        match = pl.find('match');
+        utils.helper.msg(msg.PROC1, 'splitting into %d chunks', N);
+        
+        y = as(jj).y;
+        
+        % chunk size
+        csize = floor(length(y)/N);
+        % generate list of indices
+        is = 1:csize:length(y);
+        ie = csize:csize:length(y);
+        
+        idx = sort([is(1:N) ie(1:N)]);
+        
+        if match == true
+          idx(end) = length(y);
+        end
+        
+        % one call to split with these samples
+        b = ltpda_run_method(@split, as(jj), plist('split_type', 'samples', 'samples', idx));
+        
+        % Add to output array
+        bo = [bo b];
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        %                           splitting into interval                           %
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+      case 'interval'
+        
+        %%% Skip an AO if the data is not a time-series object
+        if ~isa(as(jj).data, 'tsdata')
+          continue
+        end
+        
+        %%% get values from the parameter list
+        duration   = find(pl, 'duration');
+        start_time = find(pl, 'start_time');
+        end_time   = find(pl, 'stop_time', find(pl, 'end_time'));
+        time_span  = find(pl, 'timespan');
+        
+        %%% Some checks
+        if (~isempty(start_time) || ~isempty(end_time)) && ~isempty(time_span)
+          error('### Please specify only a timespan and not additionally the start/end time');
+        end
+        
+        if isa(time_span, 'history')
+          % The timespan object may have been replaced with its history in
+          % the previous loop exection in the call to ao/addHistory
+          time_span = rebuild(time_span);
+          pl.pset('timespan', time_span);
+        end
+        
+        %%% Convert the start_time into a time object
+        if ~isempty(start_time) && ~isa(start_time, 'time')
+          start_time = time(start_time);
+        end
+        
+        %%% Convert the end_time into a time object
+        if ~isempty(end_time) && ~isa(end_time, 'time')
+          end_time = time(end_time);
+        end
+        
+        %%% Convert the duration
+        if ~isempty(end_time) && ~isempty(duration)
+          error('### Please specify only a duration or an end time');
+        end
+        if ~isempty(duration)
+          duration = time(duration);
+          end_time = start_time + duration;
+          end_time = time(end_time);
+        end
+        
+        %%% Set start/end time with a timespan object
+        
+        if ~isempty(time_span)
+          if ~isa(time_span, 'timespan')
+            error('### The timespan must be a timespan object')
+          end
+          if ~isempty(start_time) || ~isempty(end_time)
+            error('### Please specify only a timespan OR a start/end time');
+          end
+          
+          start_time = time_span.startT;
+          end_time   = time_span.endT;
+        end
+        
+        t0_time = as(jj).data.t0;
+        
+        %%% Compute the start/end time
+        ts = double(start_time) - double(t0_time);
+        te = double(end_time)   - double(t0_time);
+        
+        idx = as(jj).x >= ts & as(jj).x < te;
+        
+        %%% create new output data
+        d = copy(as(jj).data, nargout);
+        
+        % set output data
+        if isempty(d.x)
+          % set t0 rounding at a multiplier of the sampling interval
+          if any(ts < d.toffset/1e3)
+            % Don't change the toffset because the start time is smaller
+            % than the toffset and this means that we collect all data from
+            % the begin of the samples.
+          else
+            % d.setToffset(d.toffset + (ceil(ts*d.fs)/d.fs)*1e3);
+            d.setToffset((ceil(ts*d.fs)/d.fs)*1e3);
+          end
+        else
+          d.setX(d.getX(idx));
+        end
+        d.setY(d.y(idx));
+        
+        if (numel(d.getDx) > 1)
+          d.setDx(d.getDx(idx));
+        end
+        if (numel(d.getDy) > 1)
+          d.setDy(d.getDy(idx));
+        end
+        if isprop(d, 'enbw')
+          if numel(d.enbw) > 1
+            d.setEnbw(d.enbw(idx));
+          end
+        end
+        
+        % Set nsecs for tsdata
+        if isa(d, 'tsdata')
+          d.collapseX;
+          if ~isempty(d.x)
+            d.setNsecs(d.x(end) - d.x(1) + 1/d.fs);
+          else
+            d.setNsecs(length(d.y)/d.fs);
+          end
+        end
+        
+        % Copy input AO
+        b = copy(as(jj), nargout);
+        b.data = d;
+        
+        if ~callerIsMethod
+          % create new output history
+          b.addHistory(getInfo('None'), pl, ao_invars(jj), inhists(jj));
+          % set name
+          b.name = sprintf('split(%s)', ao_invars{jj});
+        end
+        % Add to output array
+        bo = [bo b];
+      otherwise
+        error('### Unknown split type %s', split_type);
+        
+    end % switch lower(split_type)
+    
+  end % for jj = 1:numel(as)
+  
+  % Set output
+  if nargout == numel(bo)
+    % List of outputs
+    for ii = 1:numel(bo)
+      varargout{ii} = bo(ii);
+    end
+  else
+    % Single output
+    varargout{1} = bo;
+  end
+end
+
+%--------------------------------------------------------------------------
+% Get Info Object
+%--------------------------------------------------------------------------
+
+function ii = getInfo(varargin)
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pls   = [];
+  elseif nargin == 1 && ~isempty(varargin{1}) && ischar(varargin{1})
+    sets{1} = varargin{1};
+    pls = getDefaultPlist(sets{1});
+  else
+    sets = {...
+      'Default', ...
+      'By Times', ...
+      'By Frequencies', ...
+      'By Samples', ...
+      'By Chunks', ...
+      'By Interval Start/End', ...
+      'By Interval Start/Duration', ...
+      'By Interval Timespan'};
+    pls = [];
+    for kk=1:numel(sets)
+      pls = [pls getDefaultPlist(sets{kk})];
+    end
+  end
+  % Build info object
+  ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.sigproc, '$Id: split.m,v 1.112 2011/10/05 15:43:36 ingo Exp $', sets, pls);
+  ii.setModifier(false);
+end
+
+%--------------------------------------------------------------------------
+% Get Default Plist
+%--------------------------------------------------------------------------
+function plout = getDefaultPlist(set)
+  persistent pl;
+  persistent lastset;
+  if ~exist('pl', 'var') || isempty(pl) || ~strcmp(lastset, set)
+    pl = buildplist(set);
+    lastset = set;
+  end
+  plout = pl;
+end
+
+function pl = buildplist(set)
+  
+  pl = plist();
+  
+  switch lower(set)
+    case 'default'
+      
+      pl = getDefaultPlist('by times');
+      
+    case 'by times'
+      % Times
+      p = param({'times',['Split the ao into time segments.<br>' ....
+        'An array of start/stop times to split by. A negative stop time is ',...
+        'taken from the end of the vector, e.g., [10 -10] removes 10 seconds ',...
+        'from the beginning and end of the vector. An end time of 0 indicates ',...
+        'the end of the vector.']}, paramValue.EMPTY_DOUBLE);
+      pl.append(p);
+      
+    case 'by frequencies'
+      
+      % Frequencies
+      p = param({'frequencies','An array of start/stop frequencies to split by.'}, paramValue.EMPTY_DOUBLE);
+      pl.append(p);
+      
+    case 'by samples'
+      
+      % samples
+      p = param({'samples','An array of start/stop samples to split by.'}, paramValue.EMPTY_DOUBLE);
+      pl.append(p);
+      
+    case 'by chunks'
+      
+      % N
+      p = param({'N','Split into N contiguous pieces.'}, paramValue.EMPTY_DOUBLE);
+      pl.append(p);
+      
+      % match
+      p = param({'match','Define if the last chunk should keep any remaining data samples.'}, paramValue.TRUE_FALSE);
+      pl.append(p);
+      
+    case 'by interval start/end'
+      
+      % start_time
+      p = param({'start_time','Start time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
+      pl.append(p);
+      
+      % end_time
+      p = param({'end_time','End time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
+      pl.append(p);
+      
+    case 'by interval start/duration'
+      
+      % start_time
+      p = param({'start_time','Start time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
+      pl.append(p);
+      
+      % duration
+      p = param({'duration','Duration can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
+      pl.append(p);
+      
+    case 'by interval timespan'
+      
+      % timespan
+      p = param({'timespan','The start/end time are specified in the time span object.'}, {1, {timespan(0,0)}, paramValue.OPTIONAL});
+      pl.append(p);
+      
+    otherwise
+      error('### Unknown parameter set [%s].', set);
+  end
+  
+end
+
+
+% PARAMETERS: <key>         <value>        <description>
+%             'split_type'  'times'        split the ao into time segments
+%                           'frequencies'  split the ao into frequencies segments
+%                           'samples'      split the ao into sample segments
+%                           'chunks'       split the ao into chunks
+%                           'interval'     select a duration of a tsdata
+%
+% Necessary for the individual split types:
+%             <split type>  <key>         <description>
+%             'times'       'times'       an array of start/stop times to
+%                                         split by. A negative stop time is
+%                                         taken from the end of the vector,
+%                                         e.g., [10 -10] removes 10 seconds
+%                                         from the beginning and end of the
+%                                         vector. An end time of 0
+%                                         indicates the end of the vector.
+%             -------------------------------------------------------------
+%             'frequencies' 'frequencies' an array of start/stop
+%                                         frequencies to split by
+%             -------------------------------------------------------------
+%             'samples'     'samples'     an array of start/stop samples to
+%                                         split by
+%             -------------------------------------------------------------
+%             'chunks'      'N'           split into N contiguous pieces
+%                           'match'       define if the last chunk should
+%                                         keep the remaining data samples
+%                                         which couldn't split in all chunks
+%                                         default [true]
+%             -------------------------------------------------------------
+%             'interval'    'start_time', 'end_time'
+%                             start/stop time can be either a string or a
+%                             time object
+%             'interval'    'start_time', 'duration'
+%                             start time and the duration can be either a
+%                             string or a time object
+%             'interval'    'timespan'
+%                             the start/end time are specified in the time
+%                             span object.
+%             -------------------------------------------------------------
+%              The UTC time format is: 'yyyy-mm-dd HH:MM:SS'
+%
+%              If more than one splitting method is specified, the priority
+%              goes like the list above.
+%
+%              The time vector in the output AO retains the original
+%              time values (i.e. it doesn't start from zero).
+%
+%              The splitting is done as  s<=t<e.
+%
+%              Arrays of start/stop values should be like: [s1 e1 s2 e2
+%              ....]