Mercurial > hg > ltpda
diff m-toolbox/classes/@ao/join.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/join.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,526 @@ +% 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 +