Contents

classdef ts_data
    % TiSKit time series data class
    %
    % for details, type "doc ts_data"

PUBLIC PROPERTIES

    properties
        channel=ts_channel();	% Array of ts_channel objects
        figureinfo=ts_plotparm();   % Information about how to plot time figures
    end

DEPENDENT PROPERTIES

    properties (Dependent=true)
        numchans;    % Number of channels of data
    end

PUBLIC METHODS

    methods

CREATOR

        function obj = ts_data(data,arg)
            %ts_data Create an ts_data object (time series data and parameters)
            %
            % Usage:
            %	tdata = ts_data(data,sampfreq);
            % 	tdata = ts_data(data,datafile);
            % Inputs:
            %     data      The data matrix: each row is a separate channel
            %       -or-    a ts_channel object
            %     sampfreq  The sampling rate (samps/sec).
            %     datafile  An ts_file object containing instrument information.
            %               The number of 'readchannels' in this object must equal
            %               the number of rows in the data matrix
            %
            % Example
            %      tdata = ts_data([1:200;sin([1:200]/20),10);
            %
            % ts_data objects are most commonly created using
            %           ts_file.read()

            % W Crawford 10/99. Upgraded to OO 01/2011

            ts_init;	% Set up global variables
            if nargin==0; return; end    % Handle zero-argument case

            % First, initialize a generic ts_data class.
            if exist('data','var'),
                ts_debug(1,'data matrix exists');
                if isa(data,'ts_channel');
                    if length(data) > 1,
                        error('can''t put in a matrix of ts_channels (yet!)');
                    end
                    obj.channel=data;
                    return
                elseif ~isnumeric(data)
                    error('data matrix is neither ts_channel nor numeric');
                end
                [M,N] = size(data);
                if (M>N)    % channels are in columns, transpose matrix
                    ts_verbose(0,'There are more rows than columns, transposing data matrix');
                    data=data';
                    M=size(data);
                end
                if ~exist('arg','var');
                    arg=1;
                    ts_warning('No sampling rate specified, assuming 1 sps');
                end
                if isa(arg,'double'),	% If the 2nd argument is  the samp rate
                    if length(arg)>1,
                        error('sampling rate must be a scalar');
                    end
                    dfile=ts_file('','');
                    dfile.samprate=arg;
                    dfile.nChannels=M;
                    dfile.readchans=1:M;
                elseif isa(arg,'ts_file'),
                    dfile=arg;
                else
                    error('First argument is not a numeric nor a ts_file object');
                end
                % stuff data into channels
                chfile=dfile;
                for i=1:M,
                    chfile.readchans=dfile.readchans(i);
                    obj.channel(i)=ts_channel(data(i,:),chfile);
                end
            end
            %tdata.figureinfo.numsubplots=tdata.numchans;
        end % Creator
ans = 

SET METHODS (ELIMINATE BAD INPUTS)

        function obj=set.channel(obj,value)
            if ~isa(value,'ts_channel'), error('value must be a ts_channel object'); end
            obj.channel=value;
        end
        function obj=set.figureinfo(obj,value)
            if ~isa(value,'ts_plotparm'), error('value must be a ts_plotparm object'); end
            obj.figureinfo=value;
        end

ACCESS METHODS FOR DEPENDENT VARIABLES

        function out=get.numchans(obj)
            out=length(obj.channel);
        end
        function obj=set.numchans(obj,value)
            if ~isnumeric(value), error('non-numeric value'); end
            if value < 0, error('value less than 0'); end
            value=round(value);
            numchans=obj.numchans;
            if value>numchans,
                for i=numchans+1:value,
                    obj.channel(i)=ts_channel();
                end
            elseif value < numchans,
                for i=numchans:-1:value,
                    obj.channel(i)=[];
                end
            end
        end
    numchans: 1
  figureinfo: ts_plotparm object
    channels: ts_channel objects
      CHANNEL1:
                   samprate: 
                  starttime: NULL ('ts_datetime' object)
                   numsamps: 0
                    station: 'ts_station' object
                                   name: ''
                                network: ''
                            information: ''
                               timezero: NULL
                               tzoffset: 0
                             clockdrift: 0
                                    lat: 0
                                    lon: 0
                                   elev: 0
                                 wdepth: 0
                  component: 
                   response: 'ts_response' object
                               gain: 1           
                              poles:  
                              zeros:  
                            inUnits: ''
                           outUnits: ''
                subplotinfo: 'ts_subplotparm' object
                                            1        
                                      grid: xy       
                                      xmin: NaN      
                                      xmax: NaN      
                                      ymin: 7.000000e-01 
                                      ymax: 5.300000e+00 
                                  linetype: -        
                                    marker: none     
                                    yrange: NaN      
                                removegain: off      
                               demultiplex: 0        
                   fileinfo: 'ts_file' object

DISPLAY AND CHAR METHODS

        function txt=char(obj,padding)
            % padding pads the left side, to give an offset
            if ~exist('padding','var'), padding=0; end
            pformat=sprintf('%%%ds',padding);
            pad=sprintf(pformat,'');

            txt=     sprintf('%s%12s: %g\n',pad,'numchans',obj.numchans);
            txt=[txt sprintf('%s%12s: %s object\n',pad,'figureinfo',class(obj.figureinfo))];
            txt=[txt sprintf('%s%12s: %s objects\n',pad,'channels',class(obj.channel))];
            for i=1:obj.numchans,
                txt=[txt sprintf('%s  %11s%d:\n',pad,'CHANNEL',i)];
                txt=[txt sprintf('%s\n',char(obj.channel(i),12+padding))];
            end
        end
        function disp(obj)
            disp(char(obj));
        end

DATA PROCESSING METHODS

        function obj=detrend(obj,N);
            % detrend all channels
            % see ts_channel.detrend() for details
            if ~exist('N','var'); N=1; end
            for i=1:obj.numchans;
                obj.channel(i)=detrend(obj.channel(i),N);
            end
        end
        function obj=resample(obj,newsamprate)
            % resample data
            % See ts_channel.resample() for details
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            for i=1:obj.numchans,
%                start,endat     % DEBUG
                obj.channel(i)=resample(obj.channel(i),newsamprate);
            end
        end
       function obj = trueAmplitude(obj,minfreq)
            % calculate true channel amplitudes
            % See ts_channel.trueAmplitude() for details
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            if isempty(obj), return; end
            for i=1:obj.numchans,
                obj.channel(i)=obj.channel(i).trueAmplitude(minfreq);
            end
        end
        function obj = filter(obj,varargin)
            % One-way causal Butterworth filter
            % Just passes on variables to ts_channel.filter() for each
            % channel
            % For details, See Also:
            %    ts_channel.filter
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            for i=1:obj.numchans
                obj.channel(i)=obj.channel(i).filter(varargin{:});
            end
        end

OTHER METHODS

        function obj=setstarttimes(obj,value)   % Set starttime of all channels to the same value
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            value=ts_datetime(value);   % Converts string if necessary
            for i=1:obj.numchans,
                obj.channel(i).starttime=value;
            end
        end
        function out=isempty(obj)
            out = (length(obj.channel)==1 && isempty(obj.channel(1)));
        end
        function obj=cut(obj,start,endat)
            % Cut out a section of ts_data, using ts_channel.cut()
            % See ts_channel.cut() for details
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            for i=1:obj.numchans,
%                start,endat     % DEBUG
                obj.channel(i)=cut(obj.channel(i),start,endat);
            end
        end
        function out=issynchronized(obj)
            % Returns 1 if channels all have same length, samprate, and
            % starttimes are grouped within 1 data sample
            out=1;
            if obj.numchans<=1, return; end
            basenumsamps=obj.channel(1).numsamps;
            basesamprate=obj.channel(1).samprate;
            basestarttime=obj.channel(1).starttime;
            maxoffset=0;
            minoffset=0;
            for i=2:obj.numchans,
                if obj.channel(i).numsamps ~= basenumsamps,
                    out=0;
                    return;
                elseif obj.channel(i).samprate ~= basesamprate,
                    out=0;
                    return;
                else
                    offset=obj.channel(i).starttime-basestarttime;
                    if offset> maxoffset, maxoffset=offset;
                    elseif offset < minoffset, minoffset=offset;
                    end
                end
            end
            if maxoffset-minoffset > 1/basesamprate,
                out=0;
                ts_verbose(1,'data is not synced (max diff between starttimes (%g s) > sample step (%g s)', ...
                    maxoffset-minoffset,1/basesamprate);
            end
        end
        function objout = extract(obj,channels)
            % Extract selected channels from a ts_data object
            % tdatanew = extract(tdataorig,channels)
            %	where channels is a list of channels to keep

            %oldnumchans = obj.numchans;
            %             badchans = find(channels> obj.numchans | channels < 1);
            %             if ~isempty(badchans),
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            badchans = (channels> obj.numchans) | (channels < 1);
            if ~any(badchans),
                error(['Bad channel list: ' num2str(channels)]);
            end

            ts_verbose(1,'Extracting ts_data channels...')
            objout = obj;
            for i = 1:length(channels);
                objout.channel(i) = obj.channel(i);
            end
            ts_verbose(1,'done');
        end
        function obj = cat(obj,varargin)
            % Concatenate two or more ts_data objects (end to end)
            % obj = cat(obj1,obj2,...) concatenates the data in two or more ts_data objects
            % Only works if the objects have the same # of channels and each channel has the
            % same sample rate and is consecutive in time.  Prints a warning message if the data are not consecutive in time.
            % Keeps filter, name, etc parameters from first data set
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end

            ts_debug(1,'Starting...'); tic
            if nargout ==0, error('Must provide an output argument'); end

            numargs = length(varargin);
            if numargs < 2,
                error('%d arguments, need at least 2',numargs);
            end

            ts_verbose(1,'Concatenating %d data sets',numargs);
            if isempty(obj); error('first object is empty'); end
            numchans=obj.nChannels;
            for iobj=2:numargs,
                catobj = varargin{iarg};
                if catobj.numchans ~= numchans,
                    error('object #%d has different # of channels than object #1',iobj);
                end
                % Check if can be concatenated
                for i = 1:numchans,
                    if (obj.channel(1).samprate ~= catobj.channel(i).samprate)
                        error('Object %d, channel %d samprate is different from object 1',iobj,i);
                    elseif isnotconsecutive(obj.channel(i),catobj.channel(i))
                        error('Object %d, channel %d is not consecutive with object 1',iobj,i);
                    end
                end
                % Concatenate
                for i=1:numchans,
                    obj.channel(i) = cat(obj.channel(i),catobj.channel(i));
                end

            end
            ts_debug(1,'%5.2f seconds elapsed',toc);
        end % CAT
        function obj=merge(obj,obj2)
            % add a new channel.  Replaced by "+" operator
            if nargout==0, error('You ran this function without any output argument!  The result will go nowhere!'); end
            ts_warning('ts_data.merge() is replaced by "+": Use c=a+b instead of c=merge(a,b)');
            obj=obj+obj2;
        end
        function obj=plus(obj,obj2)
            obj.channel(obj.nChannels+1:obj.nChannels+obj2.nChannels)=obj2.channel;
        end
        [sobj, raw, offsetlist] = calcSpectra(obj,varargin)
        obj =   clean(obj,xfunc,minmaxfreqs,varargin);    % DEFINED IN FILE
        xdata = clean_calc(obj,chanlist,windowlen,outlratio)
        [axhand,linehand] = plot(obj,start,plotlength,varargin); % DEFINED IN FILE
        obj = synchronize(obj,newsamprate); % DEFINED IN FILE
        filename = writeSAC(obj,outfname);
        filename = writeSEGY(tdata,fname,siteName,shotInfo,delay,lengthSecs,traceFormat);
        filename = writeSEISAN(tdata,fname);
    end % PUBLIC METHODS
end % CLASSDEF
%     methods (Access=private) % Access by class methods only
%
%         %         function [address,delay] = calcAddress(tdata,ich,time);
%         %             [address,delay]=calcAddress(obj.channel(ich),time);
%         %         end
%
%     end