comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:f0afece42f48
1 % SPLIT split an analysis object into the specified segments.
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %
4 % DESCRIPTION: SPLIT split an analysis object into the specified segments.
5 %
6 % CALL: b = split(a, pl)
7 %
8 % INPUTS: a - input analysis object
9 % pl - input parameter list (see below for parameters)
10 %
11 % OUTPUTS: b - array of analysis objects
12 %
13 %
14 % EXAMPLES: 1.) Split method by frequency. Get the values from 10-100 Hz
15 % pl = plist('frequencies', [10 100]);
16 % ao_new = split(a1, pl);
17 %
18 % 2.) Split method by time.
19 % Get the values from 0.0 to 1.0 Seconds AND from 1.0 to 2.5 seconds
20 % pl = plist('times', [0.0 1.0 1.0 2.5]);
21 % ao_new = split(a1, pl);
22 %
23 % 3.) Split method by samples.
24 % Get the samples from 1 to 50 AND from 150 to 200.
25 % pl = plist('samples', [1 50 150 200]);
26 % ao_new = split(a1, pl);
27 %
28 % 4.1) Select an interval with strings
29 % --> t0 = time('14:00:00')
30 % pl = plist('start_time', '14:00:01', ...
31 % 'end_time', '14:00:02');
32 % ao_new = split(a1, pl);
33 %
34 % --> t0 = time('14:00:00')
35 % pl = plist('start_time', '14:00:01', ...
36 % 'duration', '00:00:02');
37 % ao_new = split(a1, pl);
38 %
39 % Select an interval with seconds
40 % --> t0 = time(3)
41 % pl = plist('start_time', 5, ...
42 % 'end_time', 7);
43 % ao_new = split(a1, pl);
44 %
45 % 4.2) Select an interval with time objects
46 % --> t0 = time('14:00:00')
47 % pl = plist('start_time', time('14:00:01'), ...
48 % 'end_time', time('14:00:03'));
49 % ao_new = split(a1, pl);
50 %
51 % --> t0 = time(3)
52 % pl = plist('start_time', time(5), ...
53 % 'duration', time(2));
54 % ao_new = split(a1, pl);
55 %
56 % 4.3) Select an interval with a time span object
57 % --> t0 = time('14:00:00')
58 % pl = plist('timespan', timespan('14:00:00', '14:00:05'));
59 % ao_new = split(a1, pl);
60 %
61 % <a href="matlab:utils.helper.displayMethodInfo('ao', 'split')">Parameters Description</a>
62 %
63 % VERSION: $Id: split.m,v 1.112 2011/10/05 15:43:36 ingo Exp $
64 %
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66
67 function varargout = split(varargin)
68
69 callerIsMethod = utils.helper.callerIsMethod;
70
71 %%% Check if this is a call for parameters
72 if utils.helper.isinfocall(varargin{:})
73 varargout{1} = getInfo(varargin{3});
74 return
75 end
76
77 import utils.const.*
78 utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
79
80 if nargout == 0
81 error('### split cannot be used as a modifier. Please give an output variable.');
82 end
83
84 % Collect input variable names
85 in_names = cell(size(varargin));
86 for ii = 1:nargin,in_names{ii} = inputname(ii);end
87
88 % Collect all AOs
89 [as, ao_invars] = utils.helper.collect_objects(varargin(:), 'ao', in_names);
90 pli = utils.helper.collect_objects(varargin(:), 'plist', in_names);
91
92 % copy input plist
93 pl = combine(pli, plist);
94 % combine input plists (if the input plists are more than one)
95 pl = parse(pl);
96
97 % Unpack parameter list
98 split_type = find(pl, 'split_type');
99
100 % Set 'split_type' if some other key-word is set.
101 if pl.isparam('samples')
102 split_type = 'samples';
103 elseif pl.isparam('times') || pl.isparam('frequencies')
104 split_type = 'times';
105 elseif pl.isparam('chunks') || pl.isparam('N')
106 split_type = 'chunks';
107 elseif pl.isparam('start_time') || pl.isparam('timespan')
108 split_type = 'interval';
109 end
110
111 if isempty(split_type)
112 error('### please specify the key ''split_type'' in the parameter list');
113 end
114
115 %%% go through analysis objects
116 bo = [];
117 inhists = [];
118
119 for jj=1:numel(as)
120
121 % gather the input history objects
122 inhists = [inhists as(jj).hist];
123
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 % splitting by time or frequency %
126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 switch lower(split_type)
128 case {'times', 'frequencies'}
129
130 times = find(pl, 'times');
131 frequencies = find(pl, 'frequencies');
132
133 if ~isempty(times)
134 utils.helper.msg(msg.PROC1, 'splitting by time');
135 split_x_axis.type = 'times';
136 split_x_axis.value = times;
137 if ~(isa(as(jj).data, 'tsdata') || isa(as(jj).data, 'xydata'))
138 error('### I can only split time-series by times');
139 end
140 else
141 utils.helper.msg(msg.PROC1, 'splitting by frequency');
142 split_x_axis.type = 'frequencies';
143 split_x_axis.value = frequencies;
144 if ~isa(as(jj).data, 'fsdata')
145 error('### I can only split frequency-series by frequencies');
146 end
147 end
148
149 % examine time list
150 ntimes = length(split_x_axis.value);
151 if mod(ntimes, 2) ~= 0
152 error('### please specify a start and stop for each interval.')
153 end
154 % go over each interval now
155 for ii=1:2:ntimes
156 is = split_x_axis.value(ii);
157 ie = split_x_axis.value(ii+1);
158 ish = is; % Backup the start time for the history
159 ieh = ie; % Backup the end time for the history
160
161 if ie < 0 % indicates count from end
162 if isa(as(jj).data, 'tsdata')
163 ie = as(jj).data.nsecs + as(jj).toffset + ie;
164 else
165 ie = as(jj).x(end) + ie;
166 end
167 if ie < is
168 error('### End time is before the start time.');
169 end
170 elseif ie == 0 % Go to end of vector
171 % x(end) is to small because the find command compares only to
172 % 'less' and not to 'less or equal'
173 ie = as(jj).x(end)+1/as(jj).fs;
174 else
175 ie = ie;
176 end
177
178 % copy the data-object because we change the values.
179 d = copy(as(jj).data, nargout);
180
181 % create index of the interval
182 idx = as(jj).x >= is & as(jj).x < ie;
183
184 % set output data
185 if isempty(as(jj).data.x)
186 % set t0 rounding at a multiplier of the sampling interval
187 if is < as(jj).toffset
188 % Don't change the toffset because the start time is smaller
189 % than the toffset and this means that we collect all data
190 % from the begin of the samples.
191 else
192 d.setToffset((ceil(is*d.fs)/d.fs)*1e3);
193 end
194 else
195 d.setX(as(jj).x(idx));
196 end
197 d.setY(as(jj).data.y(idx));
198 if numel(as(jj).data.dx) > 1
199 d.setDx(as(jj).data.dx(idx));
200 end
201 if numel(as(jj).data.dy) > 1
202 d.setDy(as(jj).data.dy(idx));
203 end
204 if isprop(as(jj).data, 'enbw')
205 if numel(as(jj).data.enbw) > 1
206 d.setEnbw(as(jj).data.enbw(idx));
207 end
208 end
209
210 % Set nsecs for tsdata
211 if isa(d, 'tsdata')
212 d.collapseX;
213 if ~isempty(d.x)
214 d.setNsecs(d.x(end) - d.x(1) + 1/d.fs);
215 else
216 d.setNsecs(length(d.y)/d.fs);
217 end
218 end
219
220 % Copy input AO
221 b = copy(as(jj), nargout);
222 b.data = d;
223
224 if ~callerIsMethod
225 % create new output history
226 b.addHistory(getInfo('None'), pl.pset(split_x_axis.type, [ish ieh]), ao_invars(jj), inhists(jj));
227 % set name
228 b.name = sprintf('split(%s)', ao_invars{jj});
229 end
230 % Add to output array
231 bo = [bo b];
232 end
233
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 % splitting by samples %
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 case 'samples'
238
239 utils.helper.msg(msg.PROC1, 'splitting by samples');
240
241 % examine time list
242 samples = find(pl, 'samples');
243 npairs = length(samples);
244 if mod(npairs, 2) ~= 0
245 error('### please specify a start and stop for each interval.')
246 end
247
248 % check data
249 if isa(as(jj).data, 'data2D') && length(as(jj).x) ~= length(as(jj).y)
250 error('### Something is wrong with the x/y vectors. I can''t split this data.');
251 end
252
253 % go over each interval now
254 for ii=1:2:npairs
255 is = samples(ii);
256 ie = samples(ii+1);
257
258 utils.helper.msg(msg.PROC1, sprintf('Split: %03d [%d..%d]', (ii+1)/2, is, ie));
259
260 % copy the data object.
261 d = copy(as(jj).data, nargout);
262 if is > length(d.getY)
263 idx = [];
264 else
265 idx = is:min(ie, length(d.getY));
266 end
267 if isa(d, 'cdata')
268 d.setY(d.getY(idx));
269 if numel(d.getDy) > 1
270 d.setDy(d.getDy(idx));
271 end
272 else
273 % set new samples
274
275 d.setXY(d.getX(idx), d.getY(idx));
276 % set 'dx' and 'dy' and 'enbw'
277 if numel(d.getDx) > 1
278 d.setDx(d.getDx(idx));
279 end
280 if numel(d.getDy) > 1
281 d.setDy(d.getDy(idx));
282 end
283 if isprop(d, 'enbw')
284 if numel(d.enbw) > 1
285 d.setEnbw(d.enbw(idx));
286 end
287 end
288 % if this is tsdata, we can collapse it again, maybe
289 if isa(d, 'tsdata')
290 [fs,t0,fitted] = tsdata.fitfs(d.x);
291 if ~fitted
292 d.collapseX();
293 end
294 end
295 end
296
297 % Copy input AO
298 b = copy(as(jj), nargout);
299 b.data = d;
300
301 if ~callerIsMethod
302 % create new output history
303 b.addHistory(getInfo('None'), pl.pset('samples', [is ie]), ao_invars(jj), inhists(jj));
304 % set name
305 b.name = sprintf('split(%s)[%d]', ao_invars{jj},(ii+1)/2);
306 end
307 % Add to output array
308 bo = [bo b];
309 end
310
311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312 % splitting into chunks %
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314 case 'chunks'
315
316 pl = combine(pl, getDefaultPlist('By chunks'));
317 N = find(pl, 'N');
318 if isempty(N)
319 N = pl.find('chunks');
320 end
321 match = pl.find('match');
322 utils.helper.msg(msg.PROC1, 'splitting into %d chunks', N);
323
324 y = as(jj).y;
325
326 % chunk size
327 csize = floor(length(y)/N);
328 % generate list of indices
329 is = 1:csize:length(y);
330 ie = csize:csize:length(y);
331
332 idx = sort([is(1:N) ie(1:N)]);
333
334 if match == true
335 idx(end) = length(y);
336 end
337
338 % one call to split with these samples
339 b = ltpda_run_method(@split, as(jj), plist('split_type', 'samples', 'samples', idx));
340
341 % Add to output array
342 bo = [bo b];
343
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345 % splitting into interval %
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 case 'interval'
348
349 %%% Skip an AO if the data is not a time-series object
350 if ~isa(as(jj).data, 'tsdata')
351 continue
352 end
353
354 %%% get values from the parameter list
355 duration = find(pl, 'duration');
356 start_time = find(pl, 'start_time');
357 end_time = find(pl, 'stop_time', find(pl, 'end_time'));
358 time_span = find(pl, 'timespan');
359
360 %%% Some checks
361 if (~isempty(start_time) || ~isempty(end_time)) && ~isempty(time_span)
362 error('### Please specify only a timespan and not additionally the start/end time');
363 end
364
365 if isa(time_span, 'history')
366 % The timespan object may have been replaced with its history in
367 % the previous loop exection in the call to ao/addHistory
368 time_span = rebuild(time_span);
369 pl.pset('timespan', time_span);
370 end
371
372 %%% Convert the start_time into a time object
373 if ~isempty(start_time) && ~isa(start_time, 'time')
374 start_time = time(start_time);
375 end
376
377 %%% Convert the end_time into a time object
378 if ~isempty(end_time) && ~isa(end_time, 'time')
379 end_time = time(end_time);
380 end
381
382 %%% Convert the duration
383 if ~isempty(end_time) && ~isempty(duration)
384 error('### Please specify only a duration or an end time');
385 end
386 if ~isempty(duration)
387 duration = time(duration);
388 end_time = start_time + duration;
389 end_time = time(end_time);
390 end
391
392 %%% Set start/end time with a timespan object
393
394 if ~isempty(time_span)
395 if ~isa(time_span, 'timespan')
396 error('### The timespan must be a timespan object')
397 end
398 if ~isempty(start_time) || ~isempty(end_time)
399 error('### Please specify only a timespan OR a start/end time');
400 end
401
402 start_time = time_span.startT;
403 end_time = time_span.endT;
404 end
405
406 t0_time = as(jj).data.t0;
407
408 %%% Compute the start/end time
409 ts = double(start_time) - double(t0_time);
410 te = double(end_time) - double(t0_time);
411
412 idx = as(jj).x >= ts & as(jj).x < te;
413
414 %%% create new output data
415 d = copy(as(jj).data, nargout);
416
417 % set output data
418 if isempty(d.x)
419 % set t0 rounding at a multiplier of the sampling interval
420 if any(ts < d.toffset/1e3)
421 % Don't change the toffset because the start time is smaller
422 % than the toffset and this means that we collect all data from
423 % the begin of the samples.
424 else
425 % d.setToffset(d.toffset + (ceil(ts*d.fs)/d.fs)*1e3);
426 d.setToffset((ceil(ts*d.fs)/d.fs)*1e3);
427 end
428 else
429 d.setX(d.getX(idx));
430 end
431 d.setY(d.y(idx));
432
433 if (numel(d.getDx) > 1)
434 d.setDx(d.getDx(idx));
435 end
436 if (numel(d.getDy) > 1)
437 d.setDy(d.getDy(idx));
438 end
439 if isprop(d, 'enbw')
440 if numel(d.enbw) > 1
441 d.setEnbw(d.enbw(idx));
442 end
443 end
444
445 % Set nsecs for tsdata
446 if isa(d, 'tsdata')
447 d.collapseX;
448 if ~isempty(d.x)
449 d.setNsecs(d.x(end) - d.x(1) + 1/d.fs);
450 else
451 d.setNsecs(length(d.y)/d.fs);
452 end
453 end
454
455 % Copy input AO
456 b = copy(as(jj), nargout);
457 b.data = d;
458
459 if ~callerIsMethod
460 % create new output history
461 b.addHistory(getInfo('None'), pl, ao_invars(jj), inhists(jj));
462 % set name
463 b.name = sprintf('split(%s)', ao_invars{jj});
464 end
465 % Add to output array
466 bo = [bo b];
467 otherwise
468 error('### Unknown split type %s', split_type);
469
470 end % switch lower(split_type)
471
472 end % for jj = 1:numel(as)
473
474 % Set output
475 if nargout == numel(bo)
476 % List of outputs
477 for ii = 1:numel(bo)
478 varargout{ii} = bo(ii);
479 end
480 else
481 % Single output
482 varargout{1} = bo;
483 end
484 end
485
486 %--------------------------------------------------------------------------
487 % Get Info Object
488 %--------------------------------------------------------------------------
489
490 function ii = getInfo(varargin)
491 if nargin == 1 && strcmpi(varargin{1}, 'None')
492 sets = {};
493 pls = [];
494 elseif nargin == 1 && ~isempty(varargin{1}) && ischar(varargin{1})
495 sets{1} = varargin{1};
496 pls = getDefaultPlist(sets{1});
497 else
498 sets = {...
499 'Default', ...
500 'By Times', ...
501 'By Frequencies', ...
502 'By Samples', ...
503 'By Chunks', ...
504 'By Interval Start/End', ...
505 'By Interval Start/Duration', ...
506 'By Interval Timespan'};
507 pls = [];
508 for kk=1:numel(sets)
509 pls = [pls getDefaultPlist(sets{kk})];
510 end
511 end
512 % Build info object
513 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);
514 ii.setModifier(false);
515 end
516
517 %--------------------------------------------------------------------------
518 % Get Default Plist
519 %--------------------------------------------------------------------------
520 function plout = getDefaultPlist(set)
521 persistent pl;
522 persistent lastset;
523 if ~exist('pl', 'var') || isempty(pl) || ~strcmp(lastset, set)
524 pl = buildplist(set);
525 lastset = set;
526 end
527 plout = pl;
528 end
529
530 function pl = buildplist(set)
531
532 pl = plist();
533
534 switch lower(set)
535 case 'default'
536
537 pl = getDefaultPlist('by times');
538
539 case 'by times'
540 % Times
541 p = param({'times',['Split the ao into time segments.<br>' ....
542 'An array of start/stop times to split by. A negative stop time is ',...
543 'taken from the end of the vector, e.g., [10 -10] removes 10 seconds ',...
544 'from the beginning and end of the vector. An end time of 0 indicates ',...
545 'the end of the vector.']}, paramValue.EMPTY_DOUBLE);
546 pl.append(p);
547
548 case 'by frequencies'
549
550 % Frequencies
551 p = param({'frequencies','An array of start/stop frequencies to split by.'}, paramValue.EMPTY_DOUBLE);
552 pl.append(p);
553
554 case 'by samples'
555
556 % samples
557 p = param({'samples','An array of start/stop samples to split by.'}, paramValue.EMPTY_DOUBLE);
558 pl.append(p);
559
560 case 'by chunks'
561
562 % N
563 p = param({'N','Split into N contiguous pieces.'}, paramValue.EMPTY_DOUBLE);
564 pl.append(p);
565
566 % match
567 p = param({'match','Define if the last chunk should keep any remaining data samples.'}, paramValue.TRUE_FALSE);
568 pl.append(p);
569
570 case 'by interval start/end'
571
572 % start_time
573 p = param({'start_time','Start time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
574 pl.append(p);
575
576 % end_time
577 p = param({'end_time','End time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
578 pl.append(p);
579
580 case 'by interval start/duration'
581
582 % start_time
583 p = param({'start_time','Start time can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
584 pl.append(p);
585
586 % duration
587 p = param({'duration','Duration can be either a string or a time object.'}, {1, {time(0)}, paramValue.OPTIONAL});
588 pl.append(p);
589
590 case 'by interval timespan'
591
592 % timespan
593 p = param({'timespan','The start/end time are specified in the time span object.'}, {1, {timespan(0,0)}, paramValue.OPTIONAL});
594 pl.append(p);
595
596 otherwise
597 error('### Unknown parameter set [%s].', set);
598 end
599
600 end
601
602
603 % PARAMETERS: <key> <value> <description>
604 % 'split_type' 'times' split the ao into time segments
605 % 'frequencies' split the ao into frequencies segments
606 % 'samples' split the ao into sample segments
607 % 'chunks' split the ao into chunks
608 % 'interval' select a duration of a tsdata
609 %
610 % Necessary for the individual split types:
611 % <split type> <key> <description>
612 % 'times' 'times' an array of start/stop times to
613 % split by. A negative stop time is
614 % taken from the end of the vector,
615 % e.g., [10 -10] removes 10 seconds
616 % from the beginning and end of the
617 % vector. An end time of 0
618 % indicates the end of the vector.
619 % -------------------------------------------------------------
620 % 'frequencies' 'frequencies' an array of start/stop
621 % frequencies to split by
622 % -------------------------------------------------------------
623 % 'samples' 'samples' an array of start/stop samples to
624 % split by
625 % -------------------------------------------------------------
626 % 'chunks' 'N' split into N contiguous pieces
627 % 'match' define if the last chunk should
628 % keep the remaining data samples
629 % which couldn't split in all chunks
630 % default [true]
631 % -------------------------------------------------------------
632 % 'interval' 'start_time', 'end_time'
633 % start/stop time can be either a string or a
634 % time object
635 % 'interval' 'start_time', 'duration'
636 % start time and the duration can be either a
637 % string or a time object
638 % 'interval' 'timespan'
639 % the start/end time are specified in the time
640 % span object.
641 % -------------------------------------------------------------
642 % The UTC time format is: 'yyyy-mm-dd HH:MM:SS'
643 %
644 % If more than one splitting method is specified, the priority
645 % goes like the list above.
646 %
647 % The time vector in the output AO retains the original
648 % time values (i.e. it doesn't start from zero).
649 %
650 % The splitting is done as s<=t<e.
651 %
652 % Arrays of start/stop values should be like: [s1 e1 s2 e2
653 % ....]