Mercurial > hg > ltpda
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 +% ....]