Trace for waveform users - geoscience-community-codes/GISMO GitHub Wiki
Both Trace and waveform classes contains the following types of data:
- channel information
- sequence of data
- sample rate
- time information
- history
- user-defined fields
General differences between using the "old" classes and the modern classes in MATLAB
Old classes were defined by a collection of functions that all were placed in the same @classname
folder. So, waveform classes, for example, would be in @waveform
.
Accessing data and functions of each class required syntax similar to
myfunction(X, [parameters])
, where X was your object (a waveform, scnlobject, or whatever).
Now, the same functionality can be achieved with
X.myfunction([parameters])
. This results in scripts that are easier-to-read and debug. However, the old-style function call still works.
The component data of a class was protected from direct modification. Accessing the data from within the class required using one of the class's functions as a go-between. Often this is in the form of get and set routines. This is still how MATLAB works for handle objects (think plots or files).
With modern classes, fields can be accessed directly, yet STILL have data integrity checks going on in the background. The examples later on this page will demonstrate the difference in access.
Functional differences, by type of information
####Channel Information Both waveforms and traces use the new channelinfo class to contain their information.
For example, here is how one would manipulate station name using waveform
% where W is a single waveform
staName = get(W,'station'); % get the station
W = set(W,'station', staName); % change a station
manipulating station name using Trace:
% where T is a single trace
sta = T.station; % get the station
T.station = sta; % change a station
One thing that has changed is the relative emphasis of all four channel-descriptors: Network, Station, Location, and Channel. This was OK when these scripts ran only locally with our network, but in an interconnected world, the extended description needs to be considered.
To get or set the Network.Station.Location.Channel
string in a trace, simply ask for the Trace's name
.
>> T = Trace;
>> T.name = 'IU.ANMO.00.BHZ'; %automatically parsed!
>> disp(T.station)
ANMO
>> disp(T.name)
IU.ANMO.00.BHZ
####Data
% W is a single waveform
D = get(W,'data'); % or alternatively: D = double(w);
W = set(W,'data',D)); %"set" is the only way to directly change the data
% T = some individual Trace
D = T.data;
T.data = D;
Changing specific elements of the data:
% let idx be an index into the data.
% using WAVEFORM:
dSpecific = W.getsamples(idx); % get specific values
newVals = fn(dSpecific); % change values using some function fn
W = setsamples(W,idx, newVals);% replace specific values
% The above can be be performed in one line
W = setsamples(W, idx, fn(W.getsamples(idx));
% using TRACE:
T.data(idx) = fn(T.data(idx));
####Sample Rate In waveform, sample rate was called "freq". However, because frequencies are a separate, yet inherent part of timeseries analysis, this has been renamed to "samplerate" in Trace.
A = get(W, 'freq'); % get sample rate of waveforms
A = T.samplerate; % get sample rate from Traces
The above work for N-dimensional inputs, so A
will be the same size as W
or T
####Time information
Time is kept in MATLAB date format. In recent versions of MATLAB a datetime
object exists, but is not backwards compatible with previous MATLAB versions. Also, use of the datetime
class, though powerful, is slow.
Trace now provides additional flexibility and convenience functions to handle times.
####History History used to be kept as an Nx2 cell array. The first column was the "what" and the 2nd was "when". For Traces, History has been moved into a Nx1 structure of what & when. This makes accessing individual parts of history more intuitive.
However, the routines used: addhistory
, clearhistory
and history
are all the same.
####User-Defined fields
User Defined fields have been changed. Traces now support user-defined value checking for these fields with the setUserDataRule
function.
Now, User-defined values are not created with addfield
. Instead, they are added by modifying the structure itself.
% Waveform
W = addfield(W, 'height', 184);
% Trace
W.UserData.height = 184;
Philosophical changes between Waveform and Trace
Waveform was designed to try and allow users to do things many different ways. Although that made programming easier for the end user, it creates strong challenges to maintainance and change of the underlying codes. Plus, it encourages sloppy programming practices. Here a few examples that illustrate the types of changes:
Improve consistency
In waveform, capitalization parameters were often ignored. This was OK because almost every call went through a get/set routine that could compare without regard to capitalization. This meant one could ask for "Data" or "data" or "DATA". Sounds great? But there are a few drawbacks:
- This requires additional supporting code which means more chances for errors in waveform.
- This requires additional processing overhead, slowing down the whole program.
- It makes it difficult for the end user to debug their own code, because a search/replace might not catch all the options.
- Using fields to directly access data are inherently case-sensitive. With modern class access, there is pretty much only one name for a field.
eliminating ambiguity
A more substantial example: Adding waveforms. using waveform, it was perfectly valid to say
w = w1 + w2
While this seems innocuous enough, you might expect it to yield the same answer as
w = w2 + w1
It might not. Why? Metadata.
when a waveform is added to another one, who's metadata gets put into w
? With Trace, these sorts of decisions are put back to the programmer. Instead, the user has to explicitly describe the operation:
%T = T1 + T2 % ERROR!
T = T1 + T2.data;
% now yields the same answer as
T = T2.data + T1;