Code covered by the BSD License  

Highlights from
The Waveform Suite for MATLAB

image thumbnail
from The Waveform Suite for MATLAB by Celso Reyes
Allows seismic data retrieval from varied sources and simplified creation of sophisticated programs

waveform(varargin)
function w = waveform(varargin)
%WAVEFORM Creates or imports one or more waveform objects (seismic traces)
%   w = WAVEFORM(datasource, scnlobjects, starttimes, endtimes)
%          loads waveform from the specified DATASOURCE
%          SCNL stands for STATION-CHANNEL-NETWORK-LOCATION.
%          multiple start-endtime pairs may be used, while station-channel
%          pairs can be provided as an array of scnlobjects
%
%   w = WAVEFORM() creates a blank waveform out of thin air
%       The default waveform has STATION = '', CHANNEL = '', data = [],
%       starttime = '1/1/1970', and UNITS = 'counts'
%
%   w = WAVEFORM(station, channel, samplerate, starttime, data)
%          manually puts together a waveform object from the minimum
%          required fields.
%
%      STATION - which seismic station, ex. 'OKCF'  (default '')
%      CHANNEL - 'BHZ', 'SHZ', and the like         (default '')
%      SAMPLERATE - Sampling frequency, in Hz       (default nan)
%      DATA - a vector of seismic amplitudes        (default [])
%      STARTTIME - Start time, in most any format   (default '1/1/1970')
%      ENDTIME - end time, in most any format
%
%  w = WAVEFORM(...,'nocombine')
%    If the data requested by waveform consists of multiple segments, then
%    these segments will be combined, with NaN filling any data gaps.  Set
%    the last argument to 'nocombine' to override this behavior.  Be aware
%    that with the nocombine option, the returned value may include
%    multiple waveforms for each starttime-endtime combination.
%
% 
%  DATASOURCES
%    Waveform can retrieve data from the following datasources, with
%    caveats and requirements as noted below:
%  
%    FILE, SAC, SEISAN, ANTELOPE, WINSTON, IRISDMCWS, (plus user-defined)
%
%    ANTELOPE  requires the Antelope Toolbox be installed.
%
%    WINSTON   requires usgs.jar (or equivalent), available through the
%              winston wave server or from SWARM. See *JAR NOTE* below
%
%              Winston data is not automatically adjusted instrument gain.
%              To fix this, multiply it by the gain.  Ex.  W = W .* 6.67; 
% 
%    IRISDMCWS Accessing data from the IRIS-DMC requires the IRIS Web
%              Services Java Library (IRIS-WS Library). For more
%              information on integrating this into MATLAB, please visit
%              http://www.iris.edu/manuals/javawslibrary/
%
%              See *JAR NOTE* below
%      
%
%    *JAR NOTE* - using WAVEFORM with java libraries:
%      Winston and IRIS-DMC access each require access to specific java
%      archives (.jar files).  These may be added to the MATLAB search path
%      dynamically with "javaaddpath"; doing so in the startup.m will make
%      the .jar available each time MATLAB starts. 
%   
%      Another way to make a java library perminently available is
%      to edit Matlab's classpath.txt file (located in the toolbox/local 
%      directory) and add the full path to the appropriate .jar file.
%
%
%  Examples of accessing waveform data
%    Example:
%      % Retrieve data stored in .mat files in a directory structure 
%      % like this: /data/YYYY/MM/STATION_DD 
%      ds = datasource('file','/data/%4d/%02d/%s_%02d','year','month','station','day');
%      scnls = scnlobject('STA1','BHZ','AA','--');
%      w = waveform(ds, scnls, '6/25/1998 08:00:00', '6/26/1998 09:00:00');
%      
%    
%    Example:
%      % Get a few minutes of data from a ficticious winston wave server.
%      myStations = {'OKCF','PV6','SSLS'}; 
%      myChannels = 'EHZ';
%      scnls = scnlobject(myStations,myChannels,'AV','--');
%      ds = datasource('winston','servername.here.edu',1255);
%      w = waveform(ds, scnls, now - 1, now - .98);
%
%    Example:
%      % Get some data from IRIS, then plot it
%      ds = datasource('irisdmcws');
%      scnls = scnlobject('ANMO', '?HZ', 'IU', '*')
%      w = waveform(ds, scnl, '2010-02-27 06:30:00','2010-02-27 07:30:00')
%      plot(w)
%
%    More Examples are available in the datasource documentation.
%
%
%  REFERENCE / CITATION:
%     Reyes, C. G. and West, M. E., 2011. "The Waveform Suite: A Robust
%     Platform for Manipulating Waveforms in MATLAB", SRL 82 (1) 104-110. 
%  
%
% see also SCNLOBJECT, DATASOURCE, ADDPATH

% VERSION: 1.1 of waveform objects
% AUTHOR: Celso Reyes (celso@gi.alaska.edu)
% LASTUPDATE: 11/24/2009

global WaveformNamespaceIsLoaded
if isempty(WaveformNamespaceIsLoaded)
  WaveformNamespaceIsLoaded = loadGlobalNamespace();
end;

%global mep2dep dep2mep; %#ok<NUSED>

% do we combine waveforms, or not?  If NOT, then the last argument will be
% 'nocombine'.
% if 'nocombine' isn't listed, then the constructor will combine waveforms
% by default.
argCount = nargin;
if argCount>0 && ischar(varargin{end}) && strcmpi(varargin{end},'nocombine')
  varargin = varargin(1:end-1);
  COMBINE_WAVES = false;
  argCount = argCount -1;
else
  COMBINE_WAVES = true;
end
updateWarningID = 'Waveform:waveform:oldUsage';

switch argCount
  case 0 % create a generic waveform
    w = genericWaveform();
    
  case 1   %"copy" a waveform object
    
    anyV = varargin{1};
    if isa(anyV, 'waveform')
      % INPUT: waveform (station)
      w = anyV;
    end;
    
  case 4
    if isa(varargin{1},'datasource')
      % invoke the "standard" way of importing a waveform
      % eg.  w = waveform(datasource, scnlobjects,startTimes,endTimes)
      
      % reassign the function arguments into meaningful variables
      [ds, scnls, startt, endt] = deal(varargin{:});
      %ds = varargin{1};
      %scnls = varargin{2};
      %startt = datenum(varargin{3});
      %endt = datenum(varargin{4});
      
      % ensure proper date formatting
      if ischar(startt), startt = {startt}; end
      if ischar (endt), endt = {endt}; end;
      startt = reshape(datenum(startt(:)),size(startt));
      endt = reshape(datenum(endt(:)),size(endt));
      
      % -------------------------------------------------------------------
      % if there is no specifically assigned load function, then
      % determine the load function based upon the datasource's type
      
      if isVoidInterpreter(ds)
        ds_type  = get(ds,'type');
        switch lower(ds_type)
          
          % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          % file, sac, and seisan all do not require fancy handling.  The
          % load routine and interpreter will be set, and the waveform will
          % be loaded in the following section, along with any user-defined
          % load functions.
          case {'file','sac','seisan'}
            myLoadRoutine = eval(['@load_',ds_type]);
            ds = setinterpreter(ds,myLoadRoutine); %update interpeter funct
            
            % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            % both winston and antelope are database types, which require
            % fancier handling.  Their waveforms will be loaded right here.
          case {'winston'}
            myLoadRoutine = eval(['@load_',ds_type]);
            w = myLoadRoutine( makeDataRequest(ds,scnls,startt,endt) );
          case {'antelope'}
            myLoadRoutine = eval(['@load_',ds_type]);
            w = myLoadRoutine( makeDataRequest(ds,scnls,startt,endt) ,COMBINE_WAVES);
            
            % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            % Future pre-defined load types would have case statments here
            % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            
            % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
            % There was no interpreter set, but there was no default type
            % set, either.
          case {'irisdmcws'}
            myLoadRoutine = eval(['@load_',ds_type]);
            w = myLoadRoutine( makeDataRequest(ds, scnls, startt, endt) , COMBINE_WAVES);
                
          otherwise
            error('Waveform:waveform:noDatasourceInterpreter',...
              'user defined datasources should be associated with an interpreter');
        end
      end
      
      
      % -------------------------------------------------------------------
      % if the datasource is file based, or if it requires a user-defined
      % intepreter function, then do what follows.  Otherwise, we're done
      
      if ~isVoidInterpreter(ds)
        myLoadFunc = get(ds,'interpreter');
        
        %user_defined datasource
        for j = 1:numel(startt)
          myStartTime = startt(j);
          myEndTime = endt(j);
          
          % grab all files for date range, discarding duplicates
          fn = getfilename(ds, scnls,subdivide_files_by_date(ds,myStartTime, myEndTime));
          fn = unique(fn);
          
          %load all waveforms for these files
          clear somew
          for i=1:numel(fn)
            possiblefiles = dir(fn{i});
            if isempty(possiblefiles)
              disp(['no file:',fn{i}]);
              continue,
            end
            
            %             if ~exist(fn{i},'file'),
            %               disp(['no file:',fn{i}]);
            %               continue,
            %             end
            %            w = myLoadFunc(fn{i});
            
            [PATHSTR,NAME,EXT] = fileparts(fn{i});
            for nfiles = 1:numel(possiblefiles)
              w(nfiles) = myLoadFunc(fullfile(PATHSTR,possiblefiles(nfiles).name));
            end
            if isempty(w)
              warning('Waveform:waveform:noData','no data retrieved');
              return
            end
            %combine and get rid of exterreneous waveforms
            w = w(ismember(w,scnls)); %keep only appropriate station/chan
            if isempty(w)
              warning('Waveform:waveform:noData','no relevent data retrieved');
              return
            end
            % subset and consolidate
            [wstarts, wends] = gettimerange(w);
            w = w(wstarts < myEndTime & wends > myStartTime);
            if numel(w) > 0 %9/23/2009 condition
              w = extract(w,'time',myStartTime,myEndTime);
              somew(i) = {w(:)'};
            else
              disp('empty waveform')
              continue;
            end
          end
          if ~exist('somew','var')
            w = waveform; w = w([]);
          else
            if COMBINE_WAVES,
              w = combine([somew{:}]);
            else
              w = [somew{:}];
            end
          end
          allw(j) = {w};
        end %each start time
        w = [allw{:}];
        
        
      end %~isVoidInterpreter
      
    else
      %old waveform way of doing things
      warning(updateWarningID,updateWarningMessage);
      w = waveform(datasource('uaf_continuous'),...
        scnlobject(varargin{1},varargin{2}),...
        datenum(varargin{3}),...
        datenum(varargin{4}));
    end
    
  case 5
    if ischar(varargin{5})
      
      warning(updateWarningID,updateWarningMessage);
      ds = datasource('antelope',varargin{5});
      scnl = scnlobject(varargin{1},varargin{2});
      % INPUT: waveform (station, channel, starttime, endtime,
      % alternatedirectory)
      w = waveform(ds,scnl,varargin{3}, varargin{4});
      
    else
      % Building a waveform from input pieces
      % INPUT: waveform (station, channel, frequency, starttime,
      % data)
      
      w = set(waveform,...
        'station',  varargin{1},...
        'channel',varargin{2},...
        'Freq',     varargin{3},...
        'start',    varargin{4},...
        'data',     varargin{5});
    end;
    w = addhistory(set(w,'history',{}),'CREATED');
  case 8
    DEFAULT_CHAN = 'EHZ';
    DEFAULT_STATION = 'UNK';
    DEFAULT_START = datenum([1970 1 1 0 0 0]);
    DEFAULT_END = DEFAULT_START + datenum([0,0,0,0,5,0]); %five minutes
    
    % the following are for WINSTON access...
    DEFAULT_NETWORK = '';
    DEFAULT_LOCATION = '';
    DEFAULT_SERVER = 'churchill.giseis.alaska.edu';
    DEFAULT_PORT = 16022;
    warning(updateWarningID,updateWarningMessage);
    
    % INPUT: waveform (station, channel, start, end, network,
    %                  location, server, port)
    MyDefaults = {DEFAULT_STATION, DEFAULT_CHAN, DEFAULT_START, ...
      DEFAULT_END, DEFAULT_NETWORK, DEFAULT_LOCATION,...
      DEFAULT_SERVER, DEFAULT_PORT}; %#ok<NASGU>
    
    MyVars = {'station', 'channel', 'Tstart', 'Tend', 'netwk', ...
      'location', 'server', 'port'};
    
    %Fill in all the variables with the appropriate default values
    for N = 1:argCount
      if isempty(varargin{N}),
        eval([MyVars{N},' = MyDefaults{N};'])
      else
        eval([MyVars{N},' = varargin{N};'])
      end
    end
    theseSCNLs = scnlobject(station,channel,netwk,location);
    
    mydatasource = datasource('winston',server,port);
    w = waveform(mydatasource,theseSCNLs,datenum(Tstart),datenum(Tend));
    
  otherwise
    
    disp('Invalid arguments in waveform constructor:');
    disp(varargin);
    disp('valid ways of calling waveform include: ');
    disp('   w = WAVEFORM() creates a default waveform');
    disp('   w = WAVEFORM(datasource, scnls, starttimes, endtimes)  *preferred*');
    disp('   w = WAVEFORM(station, channel, samplefreq, starttime, data)');
end

%%
function tf = isVoidInterpreter(ds)
tf = strcmpi(func2str(get(ds,'interpreter')),'void_interpreter');

function datarequest = makeDataRequest(ds, scnls, st, ed)
datarequest = struct(...
  'dataSource', ds, ...
  'scnls', scnls, ...
  'startTimes', st,...
  'endTimes',ed);

function w = genericWaveform()
%create a fresh waveform.  All calls to the waveform object, aside
%from the "copy" call (case nargin==1) will be initated HERE.
%Thereafter, the waveform will be modified by set/get.
%THIS_VERSION = 1.2;
%DEFAULT_UNIT = 'Counts';
%DEFAULT_FREQ = nan;
%DEFAULT_CHAN = '';
%DEFAULT_STATION = '';
%DEFAULT_START = 719529; % which is equiv to datenum('1/1/1970');
w.scnl = scnlobject;%(DEFAULT_STATION,DEFAULT_CHAN);
w.Fs = nan;
w.start = 719529;
w.data = double([]);
w.units = 'Counts'; %units for data (nm? counts?)
w.version = 1.2; %version of waveform object (internal)
w.misc_fields = {}; %add'l fields, such as "comments", or "trig"
w.misc_values = {}; %values for these fields
w.history = {'created', now};
w = class(w, 'waveform');

%w = addhistory(w,'CREATED'); %got rid of "created" add-history.



function s = updateWarningMessage()

updateMessageBase = ...
  ['Instead, please call the waveform constructor with '...
  ' a datasource and snclobject. \n'...
  'USAGE: w = waveform(datasource, scnlobjects, starttimes, endtimes)\n'...
  '   ...modifying request and proceeding.'];
s = sprintf('%s',updateMessageBase);

Contact us at files@mathworks.com