Time Standard Constraints#
First, we will state what we define as the finite set of time issues the framework needed to support:
The data for passive array recording can be assumed to be based on a global timing standard. Today that usually means GPS clocks but older data used a variety of timing instrumentation that has evolved with time. The only difference in older data is timing precision. We lump all such data by tagging them the
TimeReferenceTypeasUTC. There are other global time standards like GPS time (such data do not include leap seconds) but we assume such data are converted to UTC on import. Data derived from a UTC standard can be in one of two states:
Set with time 0 defined as UTC 0 time. That is, the instant of New Year in 1970 (Jan. 1, 1970:00:00:00.0). Time tag for a given sample (the output of the time method in BasicTimeSeries) is then a unix epoch seconds since epoch time 0. Note for obpsy users that time is identical to the output of the timestamp method of UTCDateTime.
An algorithm can apply the ator method that will produce an internal shift of time 0 by a specified number of seconds. Two choices of that shift are most common. First, shifting by the origin of an event converts time to travel times. Second, MsPASS has an algorithm called
ArrivalTimeReferencethat shifts data so time 0 is the arrival time of a particular phase. Note that time could be a predicted time from an earth model and hypocenter estimate or a time measured by picking or correlation method. The arrival time reference is commonly used to improve plotting (visualization) of data or simply to reduce the volume of data to handle. That is, algorithms aimed to process data around a specific section of data defined relative to a seismic phase nearly always window data using this time standard. SAC users may understand the output of ator method as a generalization of the finite list of time standards supported in SAC.Unshifted UTC data normally have the internal boolean attribute
t0shift_is_validset false because no conversion shift is being stored. Callingatorstores the supplied UTC reference time, changes the reference type to Relative, and sets this flag true sortoacan reverse the conversion. Custom readers for unusual formats must set the time standard deliberately. Python uses thetrefproperty for that purpose; C++ providesset_tref.Active source data are normally best loaded with the TimeReferenceType set as
Relative(TimeReferenceType.Relative in python or TimeReferenceType::Relative in C++). Relative time in this context is nearly always equivalent to having time 0 set to the shot time. In the design of MsPASS, however, we aimed to support the range of instrumentation in active source data acquisition with three different absolute time precisions:
Much old data had very imprecise absolute timing or none at all. It is common, for example, with old SEGY files to find none of the absolute fields defined. That is the case because in traditional active source processing like classic seismic reflection processing all that matters in processing is travel time. In that case absolute time tags are baggage useful only for bookkeeping.
Newer data seismic reflection data loggers always have a system clock that keeps time but not necessarily with high accuracy. These data loggers always write a date stamp to their internal file format, but it cannot be used to converted accurately to absolute time using that time stamp.
Many of newer systems record time synchronized with GPS receivers. IRIS PASSCAL instruments beginning with the old SGR’s through the most recent (at this writing) Nodal instruments depend upon accurate internal clocks. Data from this type of instrumentation is conceptually identical to data that begins as UTC but is time shifted so TimeReferenceType is “Relative” and the time is shifted so 0 is the shot time.
The common denominator for all active source data is that the they should have TimeReferenceType set to “Relative”. The first two cases when the absolute timing is not reliable should have the internal attribute
t0shift_is_validset to False. That assures the users won’t make the mistake of calling the rtoa function and creating a potentially misleading (at best) data set. In Python, assignd.tref = TimeReferenceType.Relative; changingtrefalone does not create or validate a stored UTC shift. The complete set of methods available to handle this issue are discussed at the end of this document.
Synthetic seismograms are a special case that have to be handled with care. The reason is putting synthetic seismogram signals into this framework almost always has to be carefully aware of the distinction between UTC and Relative time. I know of now synthetic seismogram generator that internally uses anything other than the equivalent of a Relative time standard with 0 being source origin time. Matching recorded signals, however, may require shifting either the data to relative time or shifting the synthetics to UTC time. The two are completely equivalent but how they impact MsPASS is very different and must be considered. Shifting data with a UTC time stamp to relative time is simplest - it involves only a call to ator. The inverse requires some care with the synthetics as you would need to override the safeties described below.
The time stamp that is to handle time 0 is managed in C++ by a getter with he simple name
t0()and a setter calledset_t0(). In python these are merged to a single symbol t0 with decorators in a fairly standard way to make t0 appear like a class attribute as in the following:d.t0 = arrival_time # t0 as a setter (calls the C++ set_t0 implementation) t = d.t0 # t0 as a getterThere are several convenience methods that are useful for managing time as a variable. The
time(int i)method can be used get the computed time (Relative or absolute depending on the TimeReferenceType set) of sample number i.endtime()is a special case that returnstime(npts-1)where npts is the number of points in the signal. Finally, there is the inverse functionsample_number(double t)that returns the integer sample number computed for time t rounded to the nearest sample. Users are cautioned that none of these methods check the validity of a time or sample number with respect to the data. e.g. it would be ill-advised to use the output ofsample_number(t)as an index into the data array without checking the result is >=0 and < npts.There are two methods to switch between UTC and Relative time standards. Use
ator(time_shift)to translate the time origin to the time defined by the epoch timetime_shift. Note a convenient way to get such a time from a date string is the use obspy’s UTCDateTime and read thetimestampproperty on the UTCDateTime object. The inverse ofatorisrtoa(). Note the method has no arguments and uses the value of time_shift applied whenatoris called to restore time to UTC. Finally, there is ashift(delta_time)method intended to be used to tweek time 0. That method should only be used if the data are in Relative time created by an earlier call to the ator method. The main use of theshiftmethod is for things like switching between two relative time stamps (e.g. between two phase arrival times or between source origin time and a phase time).The problem of how to define if a relative time standard should be treated as reliable is managed internally by a private (technically protected in C++ but private from a python perspective), boolean attribute called
t0shift_is_validin the C++ code. That attribute can be interrogated with the methodshifted(). Theshiftedmethod returns that flag’s value: true means a stored UTC conversion shift is available. It is normally false for unshifted UTC data and for relative active-source data without reliable absolute timing. Python changes the time-reference enum with thetrefproperty; the C++ method isset_tref(rtype).The dangerous setter
force_t0_shift(t)storestas the conversion shift and makesshifted()true, but it does not changet0ortref. Its primary purpose is matching a relative synthetic to data stored in UTC. For a synthetic whose time axis is already relative to origin, use it as follows:synthetic.tref = TimeReferenceType.Relative synthetic.force_t0_shift(origin_time) synthetic.rtoa()After
rtoa, the time standard is UTC andorigin_timehas been added to the relativet0. Do not useforce_t0_shiftwhen the absolute reference is unknown; doing so bypasses the safeguard that normally makesrtoareject that conversion.