line source
+ − % JOIN multiple AOs into a single AO.
+ − %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ − %
+ − % DESCRIPTION: JOIN multiple AOs into a single AO.
+ − % If any two AOs overlap, then the values from the first appear
+ − % in the output AO.
+ − %
+ − % Note: If the input AOs are of type 'tsdata', then they will
+ − % be sorted in ascending order according the t0 of each
+ − % object.
+ − %
+ − %
+ − % CALL: bs = join(a1,a2,a3,...,pl)
+ − % bs = join(as,pl)
+ − % bs = as.join(pl)
+ − %
+ − % INPUTS: aN - input analysis objects
+ − % as - input analysis objects array
+ − % pl - input parameter list
+ − %
+ − % OUTPUTS: b - output analysis object
+ − %
+ − % <a href="matlab:utils.helper.displayMethodInfo('ao', 'join')">Parameters Description</a>
+ − %
+ − % REMARK: Input AOs should be of the same type; if not, only AOs of the
+ − % type of the first input AO will be joined together to produce
+ − % the output.
+ − %
+ − % VERSION: $Id: join.m,v 1.60 2011/09/02 11:11:51 ingo Exp $
+ − %
+ − %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ −
+ − % PARAMETERS: 'zerofill' - Fills with zeros the gaps between the data
+ − % points of the subsequent aos. [Default: 'no']
+ − % 'sameT0' - Does not recalculate t0 but uses the common
+ − % one. [Default: 'no']
+ − % Note: the t0 among different objects must be the same!
+ − %
+ −
+ − function varargout = join(varargin)
+ −
+ − % 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);
+ −
+ − % 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);
+ − pl = utils.helper.collect_objects(varargin(:), 'plist', in_names);
+ −
+ − % Combine plists
+ − pl = parse(pl, getDefaultPlist);
+ −
+ −
+ −
+ − %----------------------------------------------
+ − % Get data type from the first AO
+ − dtype = class(as(1).data);
+ −
+ − % Sort the input AOs by t0, if applicable
+ − if strcmp(dtype, 'tsdata')
+ − times = as.t0.double;
+ − [~, idx] = sort(times);
+ − as = as(idx);
+ − end
+ −
+ − %----------------------------------------------
+ − % Go through each AO and collect the data of type 'dtype'
+ −
+ − histin = [];
+ − xo = [];
+ − yo = [];
+ − dxo = [];
+ − dyo = [];
+ − enbw0 = [];
+ − fs = -1;
+ − aname = '';
+ − adescr = '';
+ − plotinfo = [];
+ − if as(1).data.isprop('xunits')
+ − xunitsSimple = simplify(as(1).data.xunits);
+ − xunits = as(1).data.xunits;
+ − end
+ − yunitsSimple = simplify(as(1).data.yunits);
+ − yunits = as(1).data.yunits;
+ −
+ − % Get the tolerance for considering fs equal
+ − fstol = find(pl, 'fstol');
+ −
+ − % Compute time offset for tsdata objects to avoid rounding errors later
+ − minT0milli = getMinT0(as);
+ −
+ − % loop over AOs
+ − for jj=1:numel(as)
+ − % Only get the data type we want
+ − if isa(as(jj).data, dtype)
+ − switch lower(dtype)
+ − case 'tsdata'
+ − % here we concatonate time-series
+ − t0 = (as(jj).data.t0.utc_epoch_milli - minT0milli)/1000;
+ − % make proper time vector
+ − x = as(jj).x + t0;
+ −
+ − % only add samples past the end of existing (first loop)
+ − if isempty(xo)
+ − yo = as(jj).y;
+ − xo = x;
+ − if numel(as(jj).dx) == 0
+ − dxo = zeros(numel(as(jj).x),1);
+ − elseif numel(as(jj).dx) == 1
+ − dxo = ones(numel(as(jj).x),1) .* as(jj).dx;
+ − else
+ − dxo = as(jj).dx;
+ − end
+ − if numel(as(jj).dy) == 0
+ − dyo = zeros(numel(as(jj).y),1);
+ − elseif numel(as(jj).dy) == 1
+ − dyo = ones(numel(as(jj).y),1) .* as(jj).dy;
+ − else
+ − dyo = as(jj).dy;
+ − end
+ − else
+ − idxPost = find(x > max(xo));
+ − idxPre = find(x < min(xo));
+ −
+ − %%%%%%%%%% Fill the gaps with zeros %%%%%%%%%%
+ − zerofill = utils.prog.yes2true(find(pl, 'zerofill'));
+ −
+ − if zerofill
+ − % Check if there is a gap between the x-values and the pre-values.
+ − if ~isempty(idxPre)
+ − interStart = x(idxPre(end));
+ − interEnd = xo(1);
+ − nsecsPre2no = interEnd - interStart;
+ −
+ − % The gap must be larger than 1/fs in order to
+ − % fill the gap with zeros
+ − if nsecsPre2no > 1/fs
+ − x_interPre = linspace(interStart+1/fs, interEnd-1/fs, nsecsPre2no*fs-2*1/fs).';
+ − y_interPre = zeros(length(x_interPre), 1);
+ − else
+ − x_interPre = [];
+ − y_interPre = [];
+ − end
+ − else
+ − x_interPre = [];
+ − y_interPre = [];
+ − end
+ −
+ − % Check if there is a gap between the x-values and the post-values.
+ − if ~isempty(idxPost)
+ − interStart = xo(end);
+ − interEnd = x(idxPost(1));
+ − nsecsPost2no = interEnd - interStart;
+ −
+ − % The gap must be larger than 1/fs in order to
+ − % fill the gap with zeros
+ − if nsecsPost2no > 1/fs
+ − x_interPost = linspace(interStart+1/fs, interEnd-1/fs, nsecsPost2no*fs-1/fs).';
+ − y_interPost = zeros(length(x_interPost), 1);
+ − else
+ − x_interPost = [];
+ − y_interPost = [];
+ − end
+ − else
+ − x_interPost = [];
+ − y_interPost = [];
+ − end
+ −
+ − else
+ − %%%%%%%%%% Don't fill the gaps with zeros %%%%%%%%%%
+ − x_interPre = [];
+ − y_interPre = [];
+ − x_interPost = [];
+ − y_interPost = [];
+ − end
+ − xo = [x(idxPre); x_interPre; xo; x_interPost; x(idxPost)];
+ − yo = [as(jj).data.getY(idxPre); y_interPre; yo; y_interPost; as(jj).data.getY(idxPost)];
+ −
+ − %%% Collect errors
+ − if numel(as(jj).dx) == 0
+ − dx = zeros(numel(as(jj).x),1);
+ − elseif numel(as(jj).dx) == 1
+ − dx = ones(numel(as(jj).x),1) .* as(jj).dx;
+ − else
+ − dx = as(jj).dx;
+ − end
+ −
+ − if numel(as(jj).dy) == 0
+ − dy = zeros(numel(as(jj).y),1);
+ − elseif numel(as(jj).dy) == 1
+ − dy = ones(numel(as(jj).y),1) .* as(jj).dy;
+ − else
+ − dy = [dyo; as(jj).dy];
+ − end
+ −
+ − x_interPre = zeros(numel(x_interPre),1);
+ − y_interPre = zeros(numel(y_interPre),1);
+ − x_interPost = zeros(numel(x_interPost),1);
+ − y_interPost = zeros(numel(y_interPost),1);
+ − dxo = [dx(idxPre); x_interPre; dxo; x_interPost; dx(idxPost)];
+ − dyo = [dy(idxPre); y_interPre; dyo; y_interPost; dy(idxPost)];
+ −
+ − end
+ −
+ − % check fs
+ − if (fs > 0) && (abs(as(jj).fs - fs) > fstol*fs)
+ − error('### Data has different sample rates');
+ − end
+ − % store fs
+ − fs = as(jj).fs;
+ −
+ − % check xunits
+ − if ~eq(xunitsSimple, simplify(as(jj).xunits))
+ − error('### The x-units of the analysis objects are not the same %s <-> %s', char(xunits), char(as(jj).xunits));
+ − end
+ − % check yunits
+ − if ~eq(yunitsSimple, simplify(as(jj).yunits))
+ − error('### The y-units of the analysis objects are not the same %s <-> %s', char(yunits), char(as(jj).yunits));
+ − end
+ −
+ − % store T0
+ − T0s(jj) = as(jj).t0;
+ −
+ − case 'fsdata'
+ −
+ − %%% Collect all fsdata samples
+ − if isempty(xo)
+ − idxBefore = 1:numel(as(jj).x);
+ − idxAfter = [];
+ − else
+ − idxBefore = find(as(jj).x < xo(1));
+ − idxAfter = find(as(jj).x > xo(end));
+ − end
+ − xo = [as(jj).x(idxBefore); xo; as(jj).x(idxAfter)];
+ − yo = [as(jj).y(idxBefore); yo; as(jj).y(idxAfter)];
+ −
+ − %%% Collect all errors
+ − % dx
+ − if numel(as(jj).dx) == 0
+ − dx = zeros(numel(as(jj).x),1);
+ − elseif numel(as(jj).dx) == 1
+ − dx = ones(numel(as(jj).x),1) .* as(jj).dx;
+ − else
+ − dx = as(jj).dx;
+ − end
+ − dxo = [dx(idxBefore); dxo; dx(idxAfter)];
+ − % dy
+ − if numel(as(jj).dy) == 0
+ − dy = zeros(numel(as(jj).y),1);
+ − elseif numel(as(jj).dy) == 1
+ − dy = ones(numel(as(jj).y),1) .* as(jj).dy;
+ − else
+ − dy = as(jj).dy;
+ − end
+ − dyo = [dy(idxBefore); dyo; dy(idxAfter)];
+ − % enbw
+ − if numel(as(jj).data.enbw) == 0
+ − enbw = NaN(numel(as(jj).y),1);
+ − elseif numel(as(jj).data.enbw) == 1
+ − enbw = ones(numel(as(jj).y),1) .* as(jj).data.enbw;
+ − else
+ − enbw = as(jj).data.enbw;
+ − end
+ − enbw0 = [enbw(idxBefore); enbw0; enbw(idxAfter)];
+ −
+ − % check fs
+ − if (fs > 0) && (abs(as(jj).fs - fs) > fstol*fs)
+ − error('### Data has different sample rates');
+ − end
+ − % store fs
+ − fs = as(jj).fs;
+ −
+ − % check xunits
+ − if ~eq(xunitsSimple, simplify(as(jj).xunits))
+ − error('### The x-units of the analysis objects are not the same %s <-> %s', char(xunits), char(as(jj).xunits));
+ − end
+ − % check yunits
+ − if ~eq(yunitsSimple, simplify(as(jj).yunits))
+ − error('### The y-units of the analysis objects are not the same %s <-> %s', char(yunits), char(as(jj).yunits));
+ − end
+ −
+ − case 'xydata'
+ − xo = [xo; as(jj).x];
+ − yo = [yo; as(jj).y];
+ − if numel(as(jj).dx) == 0
+ − dx = zeros(numel(as(jj).x),1);
+ − elseif numel(as(jj).dx) == 1
+ − dx = ones(numel(as(jj).x),1) .* as(jj).dx;
+ − else
+ − dx = as(jj).dx;
+ − end
+ − dxo = [dxo; dx];
+ − if numel(as(jj).dy) == 0
+ − dy = zeros(numel(as(jj).y),1);
+ − elseif numel(as(jj).dy) == 1
+ − dy = ones(numel(as(jj).y),1) .* as(jj).dy;
+ − else
+ − dy = as(jj).dy;
+ − end
+ − dyo = [dyo; dy];
+ −
+ − % check xunits
+ − if ~eq(xunitsSimple, simplify(as(jj).xunits))
+ − error('### The x-units of the analysis objects are not the same %s <-> %s', char(xunits), char(as(jj).xunits));
+ − end
+ − % check yunits
+ − if ~eq(yunitsSimple, simplify(as(jj).yunits))
+ − error('### The y-units of the analysis objects are not the same %s <-> %s', char(yunits), char(as(jj).yunits));
+ − end
+ −
+ − case 'cdata'
+ − try
+ − yo = [yo; as(jj).y];
+ − if numel(as(jj).dy) == 0
+ − dy = zeros(numel(as(jj).y),1);
+ − elseif numel(as(jj).dy) == 1
+ − dy = ones(numel(as(jj).y),1) .* as(jj).dy;
+ − else
+ − dy = as(jj).dy;
+ − end
+ − dyo = [dyo; dy];
+ − catch E
+ − disp(E.message)
+ − error('### It is not possible to join the data or error because they have different dimensions.');
+ − end
+ −
+ − % check yunits
+ − if ~eq(yunitsSimple, simplify(as(jj).yunits))
+ − error('### The y-units of the analysis objects are not the same %s <-> %s', char(yunits), char(as(jj).yunits));
+ − end
+ −
+ − otherwise
+ − error('### Unknown data type');
+ − end
+ − % Collect this input history
+ − histin = [histin as(jj).hist];
+ − % Collect the 'plotinfo'
+ − if ~isempty(as(jj).plotinfo)
+ − plotinfo = combine(plotinfo, as(jj).plotinfo);
+ − end
+ − % Collect the descriptions
+ − adescr = strcat(adescr, as(jj).description);
+ − % Collect names, invars
+ − if ~isempty(aname)
+ − if ~strcmp(aname, as(jj).name)
+ − aname = [aname ',' as(jj).name];
+ − end
+ − else
+ − aname = as(jj).name;
+ − end
+ − else
+ − warning('!!! Ignoring AO input with data type %s', dtype);
+ − end
+ − end
+ −
+ − %----------------------------------------------
+ − % Now sort output vectors
+ − if ~isempty(xo)
+ − [xos, idx] = sort(xo);
+ − yos = yo(idx);
+ − dxos = dxo(idx);
+ − dyos = dyo(idx);
+ − else
+ − xos = xo;
+ − yos = yo;
+ − dxos = dxo;
+ − dyos = dyo;
+ − end
+ −
+ − if all(dxos == 0)
+ − dxos = [];
+ − elseif all(diff(dxos) == 0)
+ − dxos = dxos(1);
+ − end
+ − if all(dyos == 0)
+ − dyos = [];
+ − elseif all(diff(dyos) == 0)
+ − dyos = dyos(1);
+ − end
+ −
+ − % Keep the data shape if the input AO
+ − if size(as(1).data.y,1) == 1
+ − xos = xos.';
+ − yos = yos.';
+ − end
+ −
+ − %%% Build output data object
+ − switch lower(dtype)
+ − case 'tsdata'
+ − sameT0 = utils.prog.yes2true(find(pl, 'sameT0'));
+ −
+ − % % Check that all objects share the t0
+ − % for kk = 1:numel(T0s)
+ − % if ne(T0s(kk), T0s(1))
+ − % sameT0 = false;
+ − % end
+ − % end
+ − % if sameT0
+ − % data = tsdata(xos, yos, fs);
+ − % data.setT0(minT0milli/1000);
+ − % else
+ − % get t0
+ − % toffset = xos(1);
+ − % xos = xos - toffset;
+ − data = tsdata(xos, yos, fs);
+ − data.setT0((minT0milli/1000));
+ − % data.setToffset(toffset*1000);
+ − % end
+ − data.setDx(dxos);
+ − data.setDy(dyos);
+ − data.setXunits(xunits);
+ − data.setYunits(yunits);
+ − data.collapseX;
+ − case 'fsdata'
+ − if all(isnan(enbw0))
+ − enbw0 = [];
+ − elseif all(diff(enbw0) == 0)
+ − enbw0 = enbw0(1);
+ − end
+ − data = fsdata(xos, yos);
+ − data.setDx(dxos);
+ − data.setDy(dyos);
+ − data.setEnbw(enbw0);
+ − data.setFs(fs);
+ − data.setXunits(xunits);
+ − data.setYunits(yunits);
+ − case 'xydata'
+ − data = xydata(xos, yos);
+ − data.setDx(dxos);
+ − data.setDy(dyos);
+ − data.setXunits(xunits);
+ − data.setYunits(yunits);
+ − case 'cdata'
+ − data = cdata(yos);
+ − data.setDy(dyos);
+ − data.setYunits(yunits);
+ − end
+ −
+ − %----------------------------------------------
+ − % Build output AO
+ − if nargout == 0
+ − a = as(1);
+ − a.data = data;
+ − else
+ − a = ao(data);
+ − end
+ − % Set name
+ − a.name = aname;
+ − % Set description
+ − a.description = adescr;
+ − % Set plotinfo
+ − a.plotinfo = plotinfo;
+ − % Add history
+ − a.addHistory(getInfo('None'), pl, ao_invars, histin);
+ −
+ − %----------------------------------------------
+ − % set output
+ − varargout{1} = a;
+ − 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, 'ao', 'ltpda', utils.const.categories.helper, '$Id: join.m,v 1.60 2011/09/02 11:11:51 ingo Exp $', sets, pl);
+ − ii.setArgsmin(2);
+ − end
+ −
+ − %--------------------------------------------------------------------------
+ − % Get Default Plist
+ − %--------------------------------------------------------------------------
+ − function plout = getDefaultPlist()
+ − persistent pl;
+ − if exist('pl', 'var')==0 || isempty(pl)
+ − pl = buildplist();
+ − end
+ − plout = pl;
+ − end
+ −
+ − function pl = buildplist()
+ −
+ − pl = plist();
+ −
+ − % Zero fill
+ − p = param({'zerofill','Fills with zeros the gaps between the data points of the subsequent aos.'}, paramValue.YES_NO);
+ − p.val.setValIndex(2);
+ − pl.append(p);
+ −
+ − % Same T0
+ − p = param({'sameT0', ['Does not recalculate t0 but uses the common one.<br>', ...
+ − 'Note: the t0 among different objects must be the same!']}, paramValue.YES_NO);
+ − p.val.setValIndex(2);
+ − pl.append(p);
+ −
+ − % fstol
+ − p = param({'fstol', ['Relative tolerance between sampling frequency of different objects.<br>', ...
+ − 'Jitter in the sampling frequency by less than this amount will be neglected.<br>', ...
+ − 'If the difference is more than the set value, an error will occur.']}, paramValue.DOUBLE_VALUE(1e-6));
+ − pl.append(p);
+ − end
+ −
+ −
+ − %--------------------------------------------------------------------------
+ − % Get Offset of this set of time-vectors
+ − %--------------------------------------------------------------------------
+ − function Toff = getMinT0(as)
+ − Toff = min(double(as.t0))*1e3;
+ − end
+ −