Function index
Types
Seis.Trace — TypeTraceEvenly-sampled time series recorded at a single seismic station. The start time of the trace, in s, is in the b property, whilst the sampling interval, in s, is delta. The trace itself is accessed using the trace method, like trace(t).
All Traces are relative to the event time evt.time if it is defined, regardless of what the event is. For example, evt.time could be the origin time of an earthquake, or a picked arrival time.
The trace then contains information about an associated Event in evt and the Station in sta. picks holds a dictionary which contains pairs of pick times relative to the origin and names (which can be missing). Access picks with the picks method, and add picks with add_pick!.
The meta Dict holds any other information about the trace.
If the event time is set, then the trace beginning time b is relative to this.
Find the trace start time relative to the origin time using starttime. The absolute start time and date, if an origin time is set, is given by startdate.
Seis.AbstractTrace — TypeAbstractTrace <: AbstractDataAbstract type from which you should subtype if creating new types of traces. AbstractTraces are time-domain recordings (or synthetics) at a single channel.
Interface
The formal interface for AbstractTraces is still a work in progress and may change with a minor version increment.
The following methods should be defined for all AbstractTraces t:
trace(t): Return the data for the trace.times(t): Return the time at each sample oft.starttime(t): The time of the first sample.nsamples(t): The number of samples int.Base.eltype(t): The element type of the data samples.t.evt: Return theEventassociated with this trace.t.sta: Return theStationat which this trace was recorded.t.meta: Return aSeisDict{Symbol,Any}into which metadata may be placed.
Seis.CartTrace — TypeCartTraceAlias for Trace where Event and Station coordinates are Seis.Cartesian rather than Seis.Geographic
Seis.Event — TypeEventType containing information about a seismic event. Fields lon and lat are epicentral location in °; dep is depth below the reference (e.g., sea level) in km. time is a Dates.DateTime giving the event origin date and time, while id is a string holding the event identifier. meta is a Dict holding any extra information about the event.
Missing information is allowed and stored as missing.
Seis.CartEvent — TypeCartEvent{T}Alias for Event{T, Cartesian{T}} where T, representing an Event with Cartesian coordinates.
This type is useful for dispatch, allowing one to write methods which are only applicable when a Event has Cartesian coordinates.
Example
julia> using Geodesy
julia> Geodesy.LLA(evt::CartEvent) = LLA(evt.x, evt.y, evt.z)Seis.FourierTrace — TypeFourierTrace <: AbstractFourierTraceThe Fourier transform of a Trace.
FourierTraces contain all the information contained in their corresponding Trace, but with the addition of information on the original number of samples in the time domain trace, and an element type which much be Complex. Therefore, the fields b, delta, evt, sta, picks, and meta are all part of the public API and can be accessed the same way as for Traces.
The usual way to create FourierTraces is by calling fft on a Trace. To convert back to a Trace, call ifft.
FourierTraces share many fields with the Trace they came from, including the station and event, plus picks and metadata. These fields are not copied across, and are instead references to the same Station, Event, and so on. Therefore, any changes to the FourierTrace will be reflected in the corresponding Trace. To avoid this, do f = fft(deepcopy(t)).
FourierTrace{T,V,P}(b, delta, nsamples, data, evt, sta, picks, meta)Create a new FourierTrace which corresponds to a Trace with start time b s, sampling interval delta s and nsamples data points. data contains a set of Fourier coefficients, starting at 0 frequency up to the Nyquist frequency. (The coefficient normalisation is defined to be the same as that used by FFTW.) evt, sta, picks and meta should be taken from the original Trace.
One usually creates FourierTraces by calling fft on a Trace. Users are advised to use the keyword constructor (below) if creating new FourierTraces from scratch.
FourierTrace(; b, delta, data, nsamples=(2*length(data) - 1), evt=Event(), sta=Station(), picks=nothing, meta=nothing)Create a FourierTrace directly from a set of Fourier coefficients. Users will usually construct a FourierTrace by calling fft on a Trace instead of using this constructor.
Keyword arguments
b: The starting time in s of the original recording this frequency domain trace represents.delta: The original sampling interval in s of the equivalent time domain trace.data: AnAbstractArray{<:Complex}containing the set of Fourier coefficients for this frequency domain trace. Note that this is a 'one-sided' set, where the first index corresponds to 0 Hz and the final index is the Nyquist frequency. This is becauseTraces represent real quantities.nsamples: The number of time domain samples in the origin time domain trace which this frequency domain trace represents. This allows theFourierTraceto be converted back to the originalTracewith no loss of the number of points.evt: AnEventwhich defines the source and origin time for the data. Normally this should be taken from theTracebeing used to construct theFourierTrace.sta: AStationwhich defines the recording station for the data. Normally this should be taken from theTracebeing used to construct theFourierTrace.
Seis.AbstractFourierTrace — TypeAbstractFourierTrace <: AbstractRecordingAbstract type from which you should subtype if creating new types of frequency-domain traces. Note that this is a subtype of AbstractData, meaning methods which work for AbstractData objects should work for AbstractFourierTrace objects too.
Interface
The formal interface for AbstractFourierTraces is still a work in progress and may change in a minor version increment.
The following methods should be defined for all AbstractFourierTraces f:
trace(f): Return the data for the Fourier trace.frequencies(f): Return the frequency at each point of the Fourier series.times(f): Return the time at each sample of the time domain trace corresponding tof.starttime(f): The time of the first sample of the corresponding time domain trace.nsamples(f): The number of samples in the time domain trace corresponding tof.nfrequencies(f): The number of frequencies in the Fourier tracef.Base.eltype(f): The element type of the frequency domain data samples.
Seis.Station — TypeStationStruct containing information about a seismic station. Fields net, sta, loc and cha are the station, network, channel and location codes respectively, whilst lon and lat are the location in °. Set station elevation elev in m relative to the reference level. The azimuth azi and inclination inc of the channel in ° are respectively measured from north to east, and downward from the vertical. (E.g., a "BHN" channel typically will have a azi == 0 and inc == 90.)
meta is a Dict holding any extra information about the station or channel, such as burial depth in m.
Missing information is allowed and stored as missing.
Seis.CartStation — TypeCartStation{T} where TAlias for Station{T, Cartesian{T}} where T, representing a Station with Cartesian coordinates.
This type is useful for dispatch, allowing one to write methods which are only applicable when a Station has Cartesian coordinates.
Example
Create a function which obtains the east-north-up coordinates of a Station
julia> using Geodesy
julia> Geodesy.ENU(sta::CartStation) = ENU(sta.x, sta.y, sta.z)
julia> ENU(CartStation(x=1, y=2, z=3))Accessor functions
Seis.are_orthogonal — Functionare_orthogonal(sta1, sta2[, sta3]; tol) -> ::Bool
are_orthogonal(t1, t2[, t3]; tol) -> ::BoolReturn true if Stations sta1 and sta2 are orthogonal to each other, or if sta1, sta2 and sta3 form a mutually-orthogonal set.
The comparison can also be performed on Traces in the second form.
Directions are considered orthogonal if they differ from 90° by less than tol°, with a default value given by Seis._angle_tol.
Examples
julia> e, n, z = sample_data(:regional)[1:3];
julia> are_orthogonal(e, n)
true
julia> are_orthogonal(e, n, z)
true
julia> are_orthogonal(Station(azi=0, inc=90), Station(azi=91, inc=90))
falseSeis.channel_code — Functionchannel_code(t::Trace) -> code
channel_code(s::Station) -> codeReturn the channel code for trace t or station s, in the form of "⟨network⟩.⟨name⟩.⟨location⟩.⟨component⟩". Missing fields are left blank. The information is taken respectively from the net, sta, cha and loc fields of the Station.
Seis.dates — Functiondates(t) -> date_rangeReturn a date_range which contains the dates for each sample of t, so long as t.evt.time is defined. If not, an error is thrown.
N.B. This function assumes that the sampling interval t.delta is representable as an integer number of milliseconds, and rounds it accordingly. Dates.DateTimes have precision of 1 ms. An error is thrown if t.delta < 1e-3 s.
Example
julia> t = sample_data();
julia> dates(t)
1981-03-29T10:39:06.66:10 milliseconds:1981-03-29T10:39:16.65See also: times.
Seis.enddate — Functionenddate(t) -> dateReturn the date of the last sample of the trace t.
N.B. This function assumes that the sampling interval t.delta is representable as an integer number of milliseconds, and rounds it accordingly. Dates.DateTimes have precision of 1 ms. An error is thrown if t.delta < 1e-3 s.
Example
julia> t = sample_data(); t.evt.time
1981-03-29T10:38:14
julia> enddate(t)
1981-03-29T10:39:16.65See also: startdate.
Seis.endtime — Functionendtime(t) -> timeReturn the end time of trace t in seconds.
Example
julia> t = Trace(5, 1, 3); # 3 samples at 1 Hz, starting at 5 s
julia> endtime(t)
7.0See also: starttime.
Seis.frequencies — Functionfrequencies(f)Return the frequency in Hz of each data point in the frequency domain trace f.
Example
julia> f = fft(sample_data());
julia> frequencies(f)
0.0f0:0.1f0:50.0f0Seis.is_east — Functionis_east(s::Station; tol) -> ::Bool
is_east(t::AbstractTrace; tol) -> ::BoolReturn true if the trace t or station s is horizontal and points to the east.
The azimuth and inclination of the trace is compared to east and the horizontal within a tolerance of tol°. The default is set to be appropriate for the floating-point type used for the station or trace, but can be overridden by passing a comparison to tol.
See also: is_north, is_vertical
Seis.is_north — Functionis_north(s::Station{T}; tol) where T -> ::Bool
is_north(t::AbstractTrace; tol) -> ::BoolReturn true if the trace t is horizontal and points to the north.
The azimuth and inclination of the trace is compared to east and the horizontal within a tolerance of tol°. The default is set to be appropriate for the floating-point type used for the station or trace, but can be overridden by passing a comparison to tol.
See also: is_east, is_vertical
Seis.is_horizontal — Functionis_horizontal(s::Station; tol)
is_horizontal(t::AbstractTrace; tol) -> ::BoolReturn true if the trace t is horizontal (i.e., its inclination is 90° from the vertical), and false otherwise.
The inclination of the trace is compared to the horizontal within a tolerance of tol°. The default is set to be appropriate for the floating-point type used for the station or trace, but can be overridden by passing a comparison to tol.
Examples
julia> s = Station(azi=0, inc=90);
julia> is_horizontal(s)
true
julia> t = sample_data();
julia> is_horizontal(t)
false
julia> t.sta.inc
0.0f0See also: is_vertical, is_east, is_north.
Seis.is_vertical — Functionis_vertical(s::Station{T}; tol=eps(T)) where T
is_vertical(t::AbstractTrace; tol=eps(eltype(trace(t)))) -> ::BoolReturn true if the trace t is vertical (i.e., its inclination is 0°), and false otherwise.
The inclination of the trace is compared to the vertical within a tolerance of tol°. The default is set to be appropriate for the floating-point type used for the station or trace, but can be overridden by passing a comparison to tol.
Examples
julia> s = Station(azi=0, inc=90);
julia> is_vertical(s)
false
julia> t = sample_data();
julia> is_vertical(t)
trueSee also: is_horizontal.
Seis.nearest_sample — Functionnearest_sample(t::AbstractTrace, time; inside=true) -> iReturn the index i of the nearest sample of the trace t to time seconds.
If inside is true (the default), return nothing when time lies outside the trace. Set inside to false to instead return the first or last index when time is outside the trace.
Examples
julia> t = Trace(0, 1, rand(5)); # Trace starting at 0 s, 1 Hz sampling
julia> nearest_sample(t, 2)
3
julia> nearest_sample(t, -1)
julia> nearest_sample(t, -1, inside=false)
1nearest_sample(t::AbstractTrace, datetime::DateTime; inside=true)Form of nearest_sample where datetime is given as absolute time.
An error is thrown if no origin time is specified for t.evt.time.
Example
julia> using Dates: DateTime, Second
julia> t = sample_data();
julia> nearest_sample(t, DateTime(1981, 03, 29, 10, 39, 7))
35
julia> nearest_sample(t, startdate(t) - Second(10)) # 10 s before the first sample
julia> nearest_sample(t, startdate(t) - Second(10), inside=false)
1Seis.nfrequencies — Functionnfrequencies(f)Return the number of frequency points in the frequency domain trace f.
Example
julia> f = fft(sample_data());
julia> nfrequencies(f)
501See also: nsamples
Seis.nsamples — Functionnsamples(f::AbstraceFourierTrace[; even::Bool])For a FourierTrace f, return the number of samples in the equivalent time domain trace.
The Fourier trace f records the number of points in the original trace used to create it with a call to fft, however if the length of the trace has been changed, the number of samples of the time-domain equivalent of f may be odd or even. In this case, pass either even=true to return the even number of sample, or even=false for the odd.
Example
julia> t = sample_data(); nsamples(t)
1000
julia> f = fft(t);
julia> nsamples(f)
1000See also: nfrequencies
nsamples(t) -> nReturn the number of samples n in a trace t.
Example
julia> data = rand(4);
julia> t = Trace(0, 1, data);
julia> nsamples(t)
4nsamples(t, b, e) -> nReturn the number of samples n in a trace t between times b and e seconds.
This function only counts samples that are strictly on or later than the b time, and before or on the e time.
Example
julia> t = Trace(0, 1, 25); # 25 samples from 0s to 24 s
julia> nsamples(t, 3, 4.1)
2See also: nearest_sample.
nsamples(t, start::DateTime, stop::DateTime) -> nReturn the number of samples n in a trace t between dates start and stop.
Example
julia> using Dates
julia> t = Trace(10, 1, 20); # 20 samples from 10 to 30 s
julia> t.evt.time = DateTime(3000)
3000-01-01T00:00:00
julia> nsamples(t, DateTime(3000), DateTime(3000) + Second(9))
0
julia> nsamples(t, DateTime(3000) + Second(20), DateTime(3000) + Second(22))
3Seis.origin_time — Functionorigin_time(t, time::DateTime; picks=true) -> t′Return a copy to t where the event origin time is shifted to time.
See the in-place version origin_time! for more details.
origin_time(t) -> ::Dates.DateTimeReturn the origin time of the trace t, which is the point in time to which samples are referenced. In this single-argument method, the trace t is unchanged.
Example
julia> t = sample_data();
julia> origin_time(t)
1981-03-29T10:38:14Seis.picks — Functionpicks(t; sort=:time) -> p::Vector{Tuple{<:AbstractString,<:AbstractFloat}}Return a vector p of Seis.Picks, which contain pairs of pick times and names associated with the Trace t.
sort can be one of:
:time(the default): Picks are returned in order of increasing time:name: Picks are sorted alphanumerically by name, with unnamed picks first
The returned vector can be iterated like:
julia> t = Trace(0, 1, rand(10));
julia> add_pick!.(t, (1,2), ("P","S"));
julia> for (time, name) in picks(t) @show time, name end
(time, name) = (1.0, "P")
(time, name) = (2.0, "S")picks(t, name::AbstractString; sort=:time) -> p
picks(t, pattern::Regex; sort=:time) -> pReturn a vector p of pairs of pick names and times associated with the Trace t which either are exactly name or match the regular expression pattern.
By default, picks are returned in order of increasing time. Use sort=:name to sort alphanumerically by name (where unnamed picks appear first).
Example
julia> t = Trace(0, 1, 2); t.picks.P = (1, "Pn"); t.picks.S = (1.8, "S");
julia> t.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float64}} with 2 entries:
:P => Seis.Pick{Float64}(time=1.0, name="Pn")
:S => Seis.Pick{Float64}(time=1.8, name="S")
julia> picks(t, "S")
1-element Array{Seis.Pick{Float64},1}:
Seis.Pick{Float64}(time=1.8, name="S")
julia> picks(t, r"^P")
1-element Array{Seis.Pick{Float64},1}:
Seis.Pick{Float64}(time=1.0, name="Pn")Seis.startdate — Functionstartdate(t) -> dateReturn the date of the first sample of the trace t.
N.B. This function assumes that the sampling interval t.delta is representable as an integer number of milliseconds, and rounds it accordingly. Dates.DateTimes have precision of 1 ms. An error is thrown if t.delta < 1e-3 s.
Example
julia> t = sample_data(); t.evt.time
1981-03-29T10:38:14
julia> startdate(t)
1981-03-29T10:39:06.66See also: enddate.
Seis.starttime — Functionstarttime(f::FourierTrace)Return the time of the first sample of the equivalent time-domain recording which would be obtained by ifft
starttime(t) -> timeReturn the start time of trace t in seconds.
Example
julia> t = Trace(-3, 0.01, rand(20)) # Set start time to -3;
julia> starttime(t)
-3.0See also: endtime.
Seis.times — Functiontimes(t) -> rangeReturn the set of times range at which each sample of the trace t is defined.
Example
julia> t = sample_data();
julia> times(t)
52.66f0:0.01f0:62.65f0See also: dates.
Seis.trace — Functiontrace(f::FourierTrace)Return the data for a FourierTrace object.
trace(t) -> dataReturn an array data containing the values of the Trace t at each sampling point. data is now a variable bound to ts values, and changing data will change t. trace(t) may itself also be modified and the trace will be updated.
The value returned by trace is a variable bound to an internal field of the trace. Therefore, assigning another value to trace(t) or data will not update the values in t. Instead, update the values in-place using the . operator (like data .= 1). See examples below.
The underlying data array holding the trace can be rebound by assigning to the trace's field t, but this is unsupported and may break in future.
Examples
Retrieving the data values for a trace, and modifying the first value.
julia> t = sample_data();
julia> data = trace(t)
1000-element Array{Float32,1}:
-0.09728001
-0.09728001
⋮
-0.0768
-0.0768
julia> data[1] = 0;
julia> trace(t)
1000-element Array{Float32,1}:
0.0
-0.09728001
⋮
-0.0768
-0.0768Setting the data values for a new synthetic trace.
julia> t = Trace(0, 0.01, 1000); # 1000-point, 100 Hz trace with random data
julia> trace(t) .= sin.(π.*times(t));
julia> trace(t)
1000-element Array{Float64,1}:
0.0
0.03141075907812829
⋮
-0.06279051952931425
-0.031410759078131116Setter functions
Seis.add_pick! — Functionadd_pick!(t, time [, name=missing]) -> ::Seis.PickAdd an arrival time pick to the Trace t, ensuring existing picks are not overwritten, and return the Seis.Pick object added to the trace
If name is not missing, then the key of this pick will be Symbol(name), unless another pick with the same key already exists. In that case, the name will be appended with a number which increases until an available key is found.
If name is missing, then the pick is added to a numbered set of picks.
(Direct manipulation of picks is easy: just do t.picks.PKP = (1001, "PKP") to set a picks with name "PKP", time 1001 s and key :PKP.)
Example
julia> t = Trace(0, 1, 2);
julia> add_pick!.(t, [1, 2], ["A", missing]);
julia> t.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float64}} with 2 entries:
:A => Seis.Pick{Float64}(time=1.0, name="A")
1 => Seis.Pick{Float64}(time=2.0, name=missing)
julia> add_pick!(t, 4)
Seis.Pick{Float64}(time=4.0, name=missing)
julia> t.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float64}} with 3 entries:
:A => Seis.Pick{Float64}(time=1.0, name="A")
2 => Seis.Pick{Float64}(time=4.0, name=missing)
1 => Seis.Pick{Float64}(time=2.0, name=missing)
julia> t.picks.A
Seis.Pick{Float64}(time=1.0, name="A")
julia> t.picks[1]
Seis.Pick{Float64}(time=2.0, name=missing)See also: Seis.Pick.
add_pick!(t, date::Dates.AbstractDateTime[, name=missing]) -> ::Seis.PickAdd a time pick based on absolute time, given as a DateTime or another AbstractDateTime.
The pick is converted to relative time, so does not remain independent of any changes to t.b or t.evt.time if you update the trace manually. Use origin_time! to change the origin time whilst preserving the absolute time of picks.
Example
julia> t = sample_data();
julia> using Dates
julia> add_pick!(t, DateTime("1981-03-29T10:39:10"), "Coffee time")
Seis.Pick{Float32}(time=56.0, name="Coffee time")
julia> picks(t)
3-element Vector{Seis.Pick{Float32}}:
Seis.Pick{Float32}(time=53.670002, name=missing)
Seis.Pick{Float32}(time=56.0, name="Coffee time")
Seis.Pick{Float32}(time=60.980003, name=missing)add_pick!(t, p::Pick, name=p.name) -> pAdd a travel time pick to the Trace t from a Seis.Pick. By default, the pick name is used.
Example
julia> t1 = Trace(0, 1, 20); t2 = sample_data();
julia> add_pick!(t1, t2.picks.A, "A")
Seis.Pick{Float64}(time=53.67000198364258, name="A")
julia> t1.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float64}} with 1 entry:
:A => Seis.Pick{Float64}(time=53.67000198364258, name="A")Seis.add_picks! — Functionadd_picks!Add picks to traces based on seismic phases' predicted arrival time.
Seis does not itself implement seismic phase travel time computation. See SeisTau for one implementation which adds methods to add_pick!.
Seis.clear_picks! — Functionclear_picks!(t)Remove all picks associated with the Trace t.
Example
julia> t = sample_data();
julia> picks(t)
2-element Array{Seis.Pick{Float32},1}:
Seis.Pick{Float32}(time=53.670002, name=missing)
Seis.Pick{Float32}(time=60.980003, name=missing)
julia> clear_picks!(t);
julia> picks(t)
0-element Array{Seis.Pick{Float32},1}Seis.origin_time! — Functionorigin_time!(t, time::DateTime; picks=true) -> tSet the origin time of the trace t and shift the start time of the trace (stored in its .b field) so that the absolute time of all samples remains the same.
origin_time! will also shift all pick times so that they remain at the same absolute time. Set picks=false to leave picks at the same time relative to the trace start time.
If t.evt.time is missing (i.e., unset), then it is simply set to time and no times are shifted.
Example
julia> using Dates
julia> t = sample_data(); t.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float32}} with 2 entries:
:F => Seis.Pick{Float32}(time=60.980003, name=missing)
:A => Seis.Pick{Float32}(time=53.670002, name=missing)
julia> t.evt.time
1981-03-29T10:38:14
julia> origin_time!(t, t.evt.time + Second(1)); t.evt.time
1981-03-29T10:38:15
julia> t.picks
Seis.SeisDict{Union{Int64, Symbol},Seis.Pick{Float32}} with 2 entries:
:F => Seis.Pick{Float32}(time=59.980003, name=missing)
:A => Seis.Pick{Float32}(time=52.670002, name=missing)Geometry functions
Seis.azimuth — Functionazimuth(trace; sphere=false, flattening=Geodesics.F_WGS84) -> az
azimuth(event, station; sphere=false, flattening=Geodesics.F_WGS84) -> azReturn the azimuth az from the event to the station (a seismic station) in degrees east from local north at the event for a trace. Alternatively specify the event and station individually.
Optionally specify the flattening of the ellipsoid of rotation on which this is computed, which defaults to that of the WGS84 ellipsoid. If sphere is true, then flattening is set to zero and the calculation is performed on a sphere.
Seis.backazimuth — Functionbackazimuth(trace; flattening=0.0033528106718309896) -> baz
backazimuth(station, event; flattening=0.0033528106718309896) -> bazReturn the backazimuth baz from the station (a seismic station) to an event in degrees east from local north at the station for a trace. Alternatively specify the station and event individually.
Optionally specify the flattening of the ellipsoid of rotation on which this is computed, which defaults to that of the WGS84 ellipsoid. If sphere is true, then flattening is set to zero and the calculation is performed on a sphere.
Seis.distance_deg — Functiondistance_deg(trace; sphere=false, flattening=0.0033528106718309896) -> Δ
distance_deg(station, event; sphere=false, flattening=0.0033528106718309896) -> Δ
distance_deg(event, station; sphere=false, flattening=0.0033528106718309896) -> ΔFor a trace or an event-station pair, return the epicentral angular distance Δ in degrees.
Optionally specify the flattening of the ellipsoid of rotation on which this is computed, which defaults to that of the WGS84 ellipsoid. If sphere is true, then flattening is set to zero and the calculation is performed on a sphere.
Seis.distance_direct — Functiondistance_direct(trace)
distance_direct(event, station)
distance_direct(station, event)For a cartesian trace or event-station pair, return the straight-line distance between them in m.
Seis.distance_km — Functiondistance_km(event, station; sphere=false, a=6378.137, flattening=0.0033528106718309896) -> dFor a geographic trace or event–station pair, return the epicentral surface distance d in km between them.
Optionally specify the semimajor radius a in km and flattening of the ellipsoid of rotation on which this is computed, which defaults to that of the WGS84 ellipsoid. If sphere is true, then flattening is set to zero and the calculation is performed on a sphere.
distance_km(event, station) -> dFor a cartesian trace or event-station pair, return the epicentral distance in km between them.
Seis.incidence — Functionincidence(event, station) -> i
incidence(trace) -> iReturn the angle of incidence i° between a cartesian event and station, or a cartesian trace. The angle of incidence is defined downwards from the positive z (upward) direction.
Trace operations
Seis.cut! — Functioncut!(t, start, end; allowempty=false, warn=true) -> tCut a Trace t in place between start and end. An error is thrown if either start or end are missing.
An error is thrown if the trace would be empty because either the end cut time is before the start of the trace, or the start cut is after the end, unless allowempty is true.
By default, a warning is shown if cut times lie outside the trace; set warn to false to turn this off.
Example
julia> t = Trace(0, 1, [0, 1, 2, 3, 4, 5]);
julia> trace(cut!(t, 2, 4))
3-element Array{Float64,1}:
2.0
3.0
4.0cut!(t, start_date, end_date; kwargs...) -> tCut a Trace t in place between dates start_date and end_date.
Example
Create a trace starting at midnight on 1 January 3000, and cut to between 10 s and 1 minute after midnight:
julia> using Dates: DateTime
julia> t = Trace(0, 1, 100); # 1 Hz sampling for 100 s;
julia> t.evt.time = DateTime(3000, 1, 1); # The year 3000;
julia> cut!(t, DateTime(3000, 1, 1, 0, 0, 10), DateTime(3000, 1, 1, 0, 1, 0))
Seis.Trace{Float64,Vector{Float64},Seis.Geographic{Float64}}:
b: 10.0
delta: 1.0
GeogStation{Float64}:
sta.meta: Seis.SeisDict{Symbol, Any}()
GeogEvent{Float64}:
evt.time: 3000-01-01T00:00:00
evt.meta: Seis.SeisDict{Symbol, Any}()
Trace:
picks: 0
meta:
julia> startdate(t), enddate(t)
(DateTime("3000-01-01T00:00:10"), DateTime("3000-01-01T00:01:00"))cut!(t, pick1, offset1, pick2, offset; kwargs...) -> t
cut!(t, pick, offset1, offset2; kwargs...) ->Cut a trace t in place between offset1 s after the first pick pick1 and offset2 s after pick2.
In the second form, both offsets are relative to pick.
The values of pick1, pick2 and pick are passed to picks and so may be a Symbol (giving the key of the pick), a String (giving the pick name) or a Regex (which matches the pick name).
Example
julia> t = sample_data();
julia> starttime(t), endtime(t)
(52.66f0, 62.65f0)
julia> cut!(t, :A, 0, :F, 1);
julia> starttime(t), endtime(t)
(53.67f0, 61.979996f0)Seis.cut — Functioncut(t, start, end; kwargs...) -> t′
cut(t, start_date, end_date; kwargs...) -> t′
cut(t, pick1, offset1, pick2, offset2; kwargs...) -> t′
cut(t, pick, offset1, offset2; kwargs...) -> t′Return a copy of the trace t cut between start and end s relative to the event origin. You may also specify a start_date and end_date, or choose times offset1 and offset2 s relative to pick1 and pick2 respectively. Both offset times may also be specified relative to one pick.
Seis.decimate! — Functiondecimate!(t, n; antialias=true) -> t
decimate(t, n; antialias=true) -> t′Decimate the trace t by removing all except every n points. The sampling interval is increased n times. In the first form, update the trace in place and return it. In the second form, return an updated copy.
By default, an antialiasing and decimation FIR filter is applied. This may cause artifacts in the signal at the extremes of the trace.
If antialias is false, then no antialiasing filtering is applied during decimation. This means the decimated trace may contain spurious signals.
Seis.decimate — Functiondecimate!(t, n; antialias=true) -> t
decimate(t, n; antialias=true) -> t′Decimate the trace t by removing all except every n points. The sampling interval is increased n times. In the first form, update the trace in place and return it. In the second form, return an updated copy.
By default, an antialiasing and decimation FIR filter is applied. This may cause artifacts in the signal at the extremes of the trace.
If antialias is false, then no antialiasing filtering is applied during decimation. This means the decimated trace may contain spurious signals.
Seis.differentiate! — Functiondifferentiate!(t::Trace; points=2) -> t
differentiate(t::Trace; points=2) -> t′Differentiate the trace t by performing points-point finite differencing. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Available algorithms
points == 2: Two-point.dsdt.t[i] = (t.t[i+1] - t.t[i])/t.delta. Non-central difference, sot.bis increased by halft.delta. The trace length is reduced by 1 samples.points == 3: Three-point.dsdt.t[i] = (t.t[i+1] - t.t[i-1])/(2 * t.delta). Central difference.t.bis increased byt.delta; the trace length is reduced by 2 samples.points == 5: Five-point.dsdt.t[i] = (2/3)*(t.t[i+1] - t.t[i-1])/t.delta - (1/12)*(t.t[i+2] - t.t[i-2])/t.delta, except for the first and last points, which use a three-point central difference meaning only two points fewer are retained as forpoints == 3. Central difference.t.bis increased byt.delta;nptsreduced by 2.
Example
julia> t = Trace(0, 1, [0, 1, -1, 0]);
julia> d = differentiate(t); trace(d)
3-element Array{Float64,1}:
1.0
-2.0
1.0
julia> starttime(d)
0.5differentiate!(t::AbstractFourierTrace) -> tDifferentiate the frequency-domain trace t in the Fourier domain by multiplying the cofficients $Y_k$ by $2\pi f_k i k$, where $k <= N/2$ and $N$ is the number of samples in the time-domain trace ifft(t) and $f_k$ is the frequency corresponding to that coefficient. The operation is performed in-place.
To return an updated copy, use the out-of-place form differentiate(::AbstractFourierTrace).
Seis.differentiate — Functiondifferentiate!(t::Trace; points=2) -> t
differentiate(t::Trace; points=2) -> t′Differentiate the trace t by performing points-point finite differencing. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Available algorithms
points == 2: Two-point.dsdt.t[i] = (t.t[i+1] - t.t[i])/t.delta. Non-central difference, sot.bis increased by halft.delta. The trace length is reduced by 1 samples.points == 3: Three-point.dsdt.t[i] = (t.t[i+1] - t.t[i-1])/(2 * t.delta). Central difference.t.bis increased byt.delta; the trace length is reduced by 2 samples.points == 5: Five-point.dsdt.t[i] = (2/3)*(t.t[i+1] - t.t[i-1])/t.delta - (1/12)*(t.t[i+2] - t.t[i-2])/t.delta, except for the first and last points, which use a three-point central difference meaning only two points fewer are retained as forpoints == 3. Central difference.t.bis increased byt.delta;nptsreduced by 2.
Example
julia> t = Trace(0, 1, [0, 1, -1, 0]);
julia> d = differentiate(t); trace(d)
3-element Array{Float64,1}:
1.0
-2.0
1.0
julia> starttime(d)
0.5Seis.envelope! — Functionenvelope!(t::Trace) -> t
envelope(t::Trace) -> t′Replace the trace t with its envelope. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [0, 0, 0, 1, -1, 0, 0, 0]);
julia> trace(envelope(t))
8-element Array{Float64,1}:
0.10355339059327379
0.10355339059327379
0.6035533905932737
1.1680225577002512
1.1680225577002512
0.6035533905932737
0.10355339059327373
0.10355339059327379Seis.envelope — Functionenvelope!(t::Trace) -> t
envelope(t::Trace) -> t′Replace the trace t with its envelope. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [0, 0, 0, 1, -1, 0, 0, 0]);
julia> trace(envelope(t))
8-element Array{Float64,1}:
0.10355339059327379
0.10355339059327379
0.6035533905932737
1.1680225577002512
1.1680225577002512
0.6035533905932737
0.10355339059327373
0.10355339059327379AbstractFFTs.fft — Methodfft(t::Trace) -> f::FourierTraceConvert the trace t into its equivalent frequency domain trace f by performing a Fourier transform. The object returned is a FourierTrace.
Example
julia> t = Trace(0, 0.01, 1000); trace(t) .= sin.(2π.*times(t)); # Sine wave of frequency 1 Hz
julia> f = fft(t);
julia> indmax = argmax(abs.(trace(f))); # Get index of maximum power
julia> frequencies(f)[indmax] # Maximum frequency in Hz is 1 as expected
1.0See also: ifft.
Seis.flip! — Functionflip!(t) -> t
flip(t) -> t′Reverse the direction of a trace so that it points the opposite way. This preserves the sense of the data; for example, a positive signal on an eastward-pointing channel becomes a negative signal on the flipped westward pointing channel. Both before and after, the signal is positive eastwards.
The t.sta must contain both azimuth and inclination information.
In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [0, 1, 0]); # Positive arrival at 1 s
julia> t.sta.azi, t.sta.inc = 0, 90 # North horizontal component
(0, 90)
julia> flip!(t)
Seis.Trace{Float64,Array{Float64,1},Seis.Geographic{Float64}}:
b: 0.0
delta: 1.0
Station{Float64,Seis.Geographic{Float64}}:
sta.cha: 180.0
sta.azi: 180.0
sta.inc: 90.0
sta.meta: Seis.SeisDict{Symbol,Any}()
Event{Float64,Seis.Geographic{Float64}}:
evt.meta: Seis.SeisDict{Symbol,Any}()
Trace:
picks: 0
meta:
julia> trace(t)
3-element Array{Float64,1}:
-0.0
-1.0
-0.0Seis.flip — Functionflip!(t) -> t
flip(t) -> t′Reverse the direction of a trace so that it points the opposite way. This preserves the sense of the data; for example, a positive signal on an eastward-pointing channel becomes a negative signal on the flipped westward pointing channel. Both before and after, the signal is positive eastwards.
The t.sta must contain both azimuth and inclination information.
In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [0, 1, 0]); # Positive arrival at 1 s
julia> t.sta.azi, t.sta.inc = 0, 90 # North horizontal component
(0, 90)
julia> flip!(t)
Seis.Trace{Float64,Array{Float64,1},Seis.Geographic{Float64}}:
b: 0.0
delta: 1.0
Station{Float64,Seis.Geographic{Float64}}:
sta.cha: 180.0
sta.azi: 180.0
sta.inc: 90.0
sta.meta: Seis.SeisDict{Symbol,Any}()
Event{Float64,Seis.Geographic{Float64}}:
evt.meta: Seis.SeisDict{Symbol,Any}()
Trace:
picks: 0
meta:
julia> trace(t)
3-element Array{Float64,1}:
-0.0
-1.0
-0.0AbstractFFTs.ifft — Methodifft(t::FourierTrace[, d=2*nfrequencies(f) - 2]) -> t::TraceConvert the frequency domain FourierTrace f back into its equivalent time domain Trace t.
Because FourierTraces are usually constructed by calling fft on a Trace, the original number of time samples is kept in f and t therefore contains the same number of samples as before so long as the raw data in f has not been shortened or lengthened. If it has, then it is assumed that t should have an even number of points. If instead t should have an odd number of point, pass d=npts, where npts is the number of points needed. d must be either one or two less than double the number of frequency points in t.
Example
Showing that taking the inverse Fourier transform of the Fourier domain trace f gets us back to t:
julia> t = sample_data();
julia> f = fft(t);
julia> t′ = ifft(f);
julia> isapprox(trace(t), trace(t′))
trueA crude method to upsample a trace:
julia> t = Trace(0, 1, [0, 1, 0, -1, 0]);
julia> f = fft(t);
julia> append!(trace(f), zeros(nfrequencies(f)));
julia> trace(ifft(f))
10-element Vector{Float64}:
0.0
0.447213595499958
1.0
0.894427190999916
-1.7763568394002506e-16
-0.894427190999916
-1.0
-0.44721359549995787
1.7763568394002506e-16
0.0See also: fft.
Seis.integrate! — Functionintegrate!(t::Trace, method=:trapezium) -> t
integrate(t::Trace, method=:trapezium) -> t′Replace t with its time-integral. This is done by default using the trapezium rule. Use method=:rectangle to use the rectangle rule.
In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
If method==:trapezium (the default), then the number of samples is reduced by one and the begin time is increased by half the sampling interval.
Example
julia> t = Trace(0, 0.1, [0, 1, 1, 0]);
julia> trace(integrate(t))
3-element Array{Float64,1}:
0.05
0.15000000000000002
0.2
julia> trace(integrate(t, :rectangle))
4-element Array{Float64,1}:
0.0
0.1
0.2
0.2integrate!(t::AbstractFourierTrace) -> tIntegrate the frequency-domain trace t in the Fourier domain by dividing the cofficients $Y_k$ by $2\pi f_k i k$, where $k <= N/2$ and $N$ is the number of samples in the time-domain trace ifft(t) and $f_k$ is the frequency corresponding to that coefficient. The operation is performed in-place.
Note that in this implementation, the zero-frequency (DC) term is set to zero, such that differentiating the result of this function may produce a different trace to that which was originally integrated.
To return an updated copy, use the out-of-place form integrate(::AbstractFourierTrace).
Seis.integrate — Functionintegrate!(t::Trace, method=:trapezium) -> t
integrate(t::Trace, method=:trapezium) -> t′Replace t with its time-integral. This is done by default using the trapezium rule. Use method=:rectangle to use the rectangle rule.
In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
If method==:trapezium (the default), then the number of samples is reduced by one and the begin time is increased by half the sampling interval.
Example
julia> t = Trace(0, 0.1, [0, 1, 1, 0]);
julia> trace(integrate(t))
3-element Array{Float64,1}:
0.05
0.15000000000000002
0.2
julia> trace(integrate(t, :rectangle))
4-element Array{Float64,1}:
0.0
0.1
0.2
0.2Base.merge! — Methodmerge!(t1::AbstractTrace, ts::AbstractArray{<:AbstractTrace}; gaps=:zero, overlaps=:mean, sample_tol=0.1, check=true) -> t1
merge!(t1, ts...; kwargs...) -> t1
merge!([t1, ts...]; kwargs...) -> t1
merge(t1::AbstractTrace, ts::AbstractArray{<:AbstractTrace}; gaps=:zero, overlaps=:mean, sample_tol=0.1, check=true) -> t1
merge(t1, ts...; kwargs...) -> t1
merge([t1, ts...]; kwargs...) -> t1Merge two or more traces together into the first trace, retaining only station and event information from the first trace.
In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
All traces must have the same sampling interval. They must also have the same channel code (see channel_code), unless check is false. The traces do not need to have the same element type or geometry.
Where gaps between traces occur, these may be filled in a number of different ways, or an error may be thrown. Tapering may be applied to the data either side of gaps. See 'Keyword arguments' below for details.
Likewise, where overlaps occur, either data from the first or last trace in each overlap may be used, or the mean of the traces used. Other options are also possible.
If the start times of traces (and hence each sample itself) are not quantised in time in the same way, then an error is thrown, unless the difference in quantisation is less than a fraction of sample_tol of the sampling interval. Hence sample_tol should be between 0 and 0.5.
If all traces have an event time set, then merging is done in absolute time. If not all have an event time set, then all times are assumed to be relative to the same origin and only the traces' b fields are used. To perform merging in relative time regardless of whether the origin time is set, pass relative = true.
Empty traces are checked for matching channel codes, but are not otherwise merged into the final trace. If all traces are empty, the first is returned unaltered.
Keyword arguments
gaps
gaps controls how gaps between continuous segments of data are treated, and may take one of the following values:
:zero(default): Fill any gaps with zero:error: Throw an error if any gaps are present:linear: Linearly interpolate between the last sample before the gap and the first sample after the gap. Cannot be used with tapering.value: Fill withvalue, which must be convertable to the element type oft1.
overlaps
overlaps controls how the new merged trace uses traces which overlap in time, and may take one of the following values:
:mean(default): Take the mean of the values at each overlapping sample:first: Use the data from the first (in time) trace in the overlap:last: Use the data from the last (in time) trace:zero: Zero out any overlapping periods:error: Throw an error if any overlaps are present and the data are not identical. (Note that the error type is not at present defined but may be in a future version.)value: Fill withvalue, which must be convertable to the element type oft1.
sample_tol
Any trace which does not have its samples quantised to the same as t1 to within a fraction of a sampling interval sample_tol will cause an error to be thrown. Set this to a value between 0 and 0.5 to control this. A value of 0.5 will mean any quantisation differences are ignored.
taper
If taper is set to a fractional width, a taper is performed on the ends of traces adjoining gaps, with taper defining the proportional length of the taper relative to the gap length. Values are tapered to 0.
Note that if taper is used with a number for gaps, then sharp jumps will occur at the first and last sample of each gap to whatever value is supplied to the gaps argument
taper_form
Determines the type of taper applied around gaps if taper is set. This can be one of :hanning (the default), :hamming or :cosine. See taper! for details.
relative
If relative is true, then ignore any origin times in traces and merge them all only with regard to their starttime. By default merging is done in absolute time if all traces have .evt.time set.
metadata
If true (the default), then entries in the .meta field of each trace are merged into the .meta field of the first trace. Entries of the first trace are preserved, while entries not in the first trace are added in turn from the last trace to the first. This means duplicate entries are not overwritten in the first trace, and entries present in more than one of the other traces are taken from the second, third, etc., trace in preference to any later traces.
Base.merge — Methodmerge(t1::AbstractTrace, t2::AbstractTrace...) -> t_merged
merge(t1::AbstractTrace, ::Vararg{AbstractTrace}) -> t_merged
merge(ts::AbstractArray{<:AbstractTrace}) -> t_mergedFor details of out-of-place trace merging, see merge!.
Seis.normalise! — Functionnormalise!(t::Trace, val=1) -> t
normalise(t::Trace, val=1) -> t′Normalise the trace t so that its maximum absolute amplitude is val. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
This function can also be spelled normalize[!].
Example
julia> t = Trace(0, 0.1, [0, -1, 2]);
julia> trace(normalise(t))
3-element Array{Float64,1}:
0.0
-0.5
1.0
julia> trace(normalise(t, 2))
3-element Array{Float64,1}:
0.0
-1.0
2.0Seis.normalise — Functionnormalise!(t::Trace, val=1) -> t
normalise(t::Trace, val=1) -> t′Normalise the trace t so that its maximum absolute amplitude is val. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
This function can also be spelled normalize[!].
Example
julia> t = Trace(0, 0.1, [0, -1, 2]);
julia> trace(normalise(t))
3-element Array{Float64,1}:
0.0
-0.5
1.0
julia> trace(normalise(t, 2))
3-element Array{Float64,1}:
0.0
-1.0
2.0LinearAlgebra.normalize! — Functionnormalise!(t::Trace, val=1) -> t
normalise(t::Trace, val=1) -> t′Normalise the trace t so that its maximum absolute amplitude is val. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
This function can also be spelled normalize[!].
Example
julia> t = Trace(0, 0.1, [0, -1, 2]);
julia> trace(normalise(t))
3-element Array{Float64,1}:
0.0
-0.5
1.0
julia> trace(normalise(t, 2))
3-element Array{Float64,1}:
0.0
-1.0
2.0LinearAlgebra.normalize — Functionnormalise!(t::Trace, val=1) -> t
normalise(t::Trace, val=1) -> t′Normalise the trace t so that its maximum absolute amplitude is val. In the first form, update the trace in place and return the trace. In the second form, return an updated copy.
This function can also be spelled normalize[!].
Example
julia> t = Trace(0, 0.1, [0, -1, 2]);
julia> trace(normalise(t))
3-element Array{Float64,1}:
0.0
-0.5
1.0
julia> trace(normalise(t, 2))
3-element Array{Float64,1}:
0.0
-1.0
2.0Seis.remove_mean! — Functionremove_mean!(t::Trace) -> t
remove_mean(t::Trace) -> t′Remove the mean of trace t. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 0.01, [1, 1, 3, -1]);
julia> trace(remove_mean(t))
4-element Array{Float64,1}:
0.0
0.0
2.0
-2.0Seis.remove_mean — Functionremove_mean!(t::Trace) -> t
remove_mean(t::Trace) -> t′Remove the mean of trace t. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 0.01, [1, 1, 3, -1]);
julia> trace(remove_mean(t))
4-element Array{Float64,1}:
0.0
0.0
2.0
-2.0Seis.remove_trend! — Functionremove_trend!(t::Trace) -> t
remove_trend(t::Trace) -> t′Remove the trend from t. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 0.2, [1, 2, 3, 4]);
julia> trace(remove_trend(t))
4-element Array{Float64,1}:
-2.220446049250313e-16
0.0
0.0
4.440892098500626e-16Seis.remove_trend — Functionremove_trend!(t::Trace) -> t
remove_trend(t::Trace) -> t′Remove the trend from t. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 0.2, [1, 2, 3, 4]);
julia> trace(remove_trend(t))
4-element Array{Float64,1}:
-2.220446049250313e-16
0.0
0.0
4.440892098500626e-16Seis.resample! — Functionresample!(t::AbstractTrace; delta, n) -> t
resample(t::AbstractTrace; delta, n) -> t′Resample the trace t so that either the sampling interval becomes delta s, or its sampling rate is increased n times. One of delta or n must be given.
In the first form, update the trace in place and return it. In the second form, return an updated copy (t′).
The functions uses DSP.resample to perform the operation, which applies an antialias filter and 'additional operations' to prevent aliasing and minimise other artifacts.
To perform decimation without antialiasing, use decimate or decimate! with antialias=false.
Example
julia> t = Trace(0, 0.5, 1:4);
julia> trace(resample(t, 3))DSP.Filters.resample — Functionresample!(t::AbstractTrace; delta, n) -> t
resample(t::AbstractTrace; delta, n) -> t′Resample the trace t so that either the sampling interval becomes delta s, or its sampling rate is increased n times. One of delta or n must be given.
In the first form, update the trace in place and return it. In the second form, return an updated copy (t′).
The functions uses DSP.resample to perform the operation, which applies an antialias filter and 'additional operations' to prevent aliasing and minimise other artifacts.
To perform decimation without antialiasing, use decimate or decimate! with antialias=false.
Example
julia> t = Trace(0, 0.5, 1:4);
julia> trace(resample(t, 3))DSP.Periodograms.spectrogram — Methodspectrogram(trace::AbstractTrace; length=(endtime(t) - starttime(t))/20, overlap=0.5, window=nothing, pad=nothing) -> specCalculate the spectrogram for the data in trace. Each segment is length s long, and overlaps with the next by a fraction of overlap (i.e., overlap must be 0 s or greater, and less than 1). Note that these values are rounded to an integer number of samples in both cases.
Windows are by default padded to the next length which allows for fast FFT computation. Setting pad to a number larger than 1 pads the trace with zeroes to the nearest integer length which is pad times the trace length. This allows for finer sampling in frequency space.
By default, no windowing of each segment (of length s) is performed; pass a windowing function or vector of amplitudes to window to window each segment before the periodogram is computed. See DSP.periodogram for more details of the kind of windowing which is possible. (The spectrogram calculation is performed by DSP.spectrogram and returns a DSP.Periodograms.Spectrogram object.)
Examples
julia> t = sample_data();
julia> spec = spectrogram(t);
julia> spec.time
52.90999984741211:0.25:62.40999984741211Seis.taper! — Functiontaper!(t::AbstractTrace, width=0.05; left=true, right=true, form=:hanning, time=nothing) -> t
taper(t::AbstractTrace, width=0.05; left=true, right=true, form=:hamming, time=nothing) -> t′Apply a taper to the ends of the data in trace t. form may be one of :hanning, :hamming or :cosine. width represents the fraction (at both ends) of the trace tapered, up to 0.5.
Optionally, specify time as an absolute length in time for the tapering period (at both ends), in which case width is ignored.
By default, tapering is applied to both ends. If left is false, then only the 'right' end (later in time part) of the trace is tapered; and vice versa.
In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [-1, 1, -1, 1, -1, 1]);
julia> trace(taper(t))
6-element Array{Float64,1}:
-0.0
0.49999999999999994
-1.0
1.0
-0.49999999999999994
0.0
julia> trace(taper(t; time=0.25))
6-element Vector{Float64}:
-0.0
0.49999999999999994
-1.0
1.0
-0.49999999999999994
0.0
julia> trace(taper(t; right=false))
6-element Vector{Float64}:
-0.0
0.49999999999999994
-1.0
1.0
-1.0
1.0Seis.taper — Functiontaper!(t::AbstractTrace, width=0.05; left=true, right=true, form=:hanning, time=nothing) -> t
taper(t::AbstractTrace, width=0.05; left=true, right=true, form=:hamming, time=nothing) -> t′Apply a taper to the ends of the data in trace t. form may be one of :hanning, :hamming or :cosine. width represents the fraction (at both ends) of the trace tapered, up to 0.5.
Optionally, specify time as an absolute length in time for the tapering period (at both ends), in which case width is ignored.
By default, tapering is applied to both ends. If left is false, then only the 'right' end (later in time part) of the trace is tapered; and vice versa.
In the first form, update the trace in place and return it. In the second form, return an updated copy.
Example
julia> t = Trace(0, 1, [-1, 1, -1, 1, -1, 1]);
julia> trace(taper(t))
6-element Array{Float64,1}:
-0.0
0.49999999999999994
-1.0
1.0
-0.49999999999999994
0.0
julia> trace(taper(t; time=0.25))
6-element Vector{Float64}:
-0.0
0.49999999999999994
-1.0
1.0
-0.49999999999999994
0.0
julia> trace(taper(t; right=false))
6-element Vector{Float64}:
-0.0
0.49999999999999994
-1.0
1.0
-1.0
1.0Filtering
Seis.bandstop! — Functionbandstop!(t::Trace, f1, f2; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
bandstop(t::Trace, f1, f2; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a bandreject filter to the trace t with stop band between frequencies f1 and f2 in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.bandstop — Functionbandstop!(t::Trace, f1, f2; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
bandstop(t::Trace, f1, f2; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a bandreject filter to the trace t with stop band between frequencies f1 and f2 in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.bandpass! — Functionbandpass!(t::Trace, f1, f2; poles=2, twopass=false) -> t
bandpass(t::Trace, f1, f2; poles=2, twopass=false) -> t′Apply a bandpass filter to the trace t between frequencies f1 and f2 in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.bandpass — Functionbandpass!(t::Trace, f1, f2; poles=2, twopass=false) -> t
bandpass(t::Trace, f1, f2; poles=2, twopass=false) -> t′Apply a bandpass filter to the trace t between frequencies f1 and f2 in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.highpass! — Functionhighpass!(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
highpass(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a highpass filter to the trace t with corner frequency f in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.highpass — Functionhighpass!(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
highpass(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a highpass filter to the trace t with corner frequency f in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.lowpass! — Functionlowpass!(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
lowpass(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a lowpass filter to the trace t with corner frequency f in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Seis.lowpass — Functionlowpass!(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t
lowpass(t::Trace, f; poles=2, twopass=false, kind=DSP.Butterworth(poles)) -> t′Apply a lowpass filter to the trace t with corner frequency f in Hz. In the first form, update the trace in place and return it. In the second form, return an updated copy.
Optionally specify the number of poles of the filter, and whether a two-pass filter should be applied. This doubles the effective number of poles, because both a forward and reverse pass occur. This has the advantage of preserving the phase.
Specify the kind of filter by providing a kind from the DSP.Filters module. If doing so, the poles keyword argument is not used and the number of poles, ripple power, etc., should be specified when providing the filter kind.
Trace rotation
Seis.rotate_through! — Functionrotate_through!(t1::Trace, t2::Trace, phi[; tol]) -> t1, t2For two traces t1 an t2 which are orthgonal, rotate them by phi° from t1 towards t2. Note therefore that the order of the arguments matters and opposite rotations can be achieved by swapping t1 and t2. Neither of the traces need to be horizontal.
This is a reference frame transformation (passive rotation) and hence particle motion will appear to rotate from t2 to t1.
Trace channel names are updated to contain the azimuth if both channels are horizontals.
The optional keyword argument tol specifies the angle in ° by which the traces must be orthogonal; see are_orthogonal.
Example
julia> e, n = sample_data(:local)[1:2];
julia> rotate_through!(n, e, 20); # Rotate 20° clockwise looking down
julia> n.sta.azi, e.sta.azi
(20.0f0, 110.0f0)
julia> rotate_through!(e, n, 20); # Rotate in opposite direction
julia> n.sta.azi, e.sta.azi
(6.5939315f-7, 90.0f0)See also: rotate_through, rotate_to_gcp!, rotate_to_azimuth_incidence!
Seis.rotate_through — Functionrotate_through!(t1::Trace, t2::Trace, phi[; tol]) -> t1, t2For two traces t1 an t2 which are orthgonal, rotate them by phi° from t1 towards t2. Note therefore that the order of the arguments matters and opposite rotations can be achieved by swapping t1 and t2. Neither of the traces need to be horizontal.
This is a reference frame transformation (passive rotation) and hence particle motion will appear to rotate from t2 to t1.
Trace channel names are updated to contain the azimuth if both channels are horizontals.
The optional keyword argument tol specifies the angle in ° by which the traces must be orthogonal; see are_orthogonal.
Example
julia> e, n = sample_data(:local)[1:2];
julia> rotate_through!(n, e, 20); # Rotate 20° clockwise looking down
julia> n.sta.azi, e.sta.azi
(20.0f0, 110.0f0)
julia> rotate_through!(e, n, 20); # Rotate in opposite direction
julia> n.sta.azi, e.sta.azi
(6.5939315f-7, 90.0f0)See also: rotate_through, rotate_to_gcp!, rotate_to_azimuth_incidence!
Seis.rotate_to_enz! — Functionrotate_to_enz!(t1, t2, t3[; tol]) -> e, n, zRotate three orthogonal traces t1, t2 and t3 in place so that they point east (e), north (n) and vertically (z).
e, n and z are bindings to the same data as t1, t2 and t3, but they may not be returned in the same order as passed in if the original set of traces are not given as a right-handed set.
See also: rotate_through!, rotate_to_gcp!, rotate_to_lqt!
Seis.rotate_to_enz — Functionrotate_to_enz(t1, t2, t3[; tol]) -> e, n, zCopying version of rotate_to_enz!.
Seis.rotate_to_gcp! — Functionrotate_to_gcp!(t1, t2; reverse=false, tol) -> t1, t2Rotate the pair of traces t1 and t2 in place so that t1 points along the radial direction (the backazimuth plus 180°), and t2 is 90° clockwise from that.
If reverse is true, then t2 is rotated to be 90° anticlockwise from t1, so that the polarity is reversed.
The component names of the radial and transverse traces are updated to be 'R', and either 'T' or '-T' respectively for normal and reverse polarity, unless the component code is a valid SEED identifier which seems rotatable and matches for the traces; then the correct component name is used. (E.g., "BHE" and "BHN" become "BHR" and "BHT".)
Traces must be orthogonal and horizontal. The optional keyword argument tol specifies the angle in ° by which the traces must be orthogonal; see are_orthogonal.
See also: rotate_to_lqt!, rotate_to_azimuth_incidence!, rotate_to_enz!
rotate_to_gcp!(t::AbstractArray{T}; kwargs...) -> tRotate pairs of traces in the array t so they are in the order [R1, T1, R2, T2, ...].
Seis.rotate_to_gcp — Functionrotate_to_gcp(t1, t2; reverse=false[, tol]) -> R, T
rotate_to_gcp(t::AbstractArray{<:AbstractTrace}; reverse=false[, tol]) -> t′Copying version of rotate_to_gcp! which returns the radial R and transverse T traces in the first form, or pairs of radial and transverse traces in the modified array t′
Seis.rotate_to_lqt! — Functionrotate_to_lqt!(t1, t2, t3; [tol]) -> L, Q, T
rotate_to_lqt!(t1, t2, t3, incidence; [tol]) -> L, Q, T
rotate_to_lqt!(t1, t2, t3, azimuth, incidence; [tol]) -> L, Q, TRotate the three traces t1, t2 and t3 in place, and return them in the order L, Q and T, forming a right-handed set.
The L trace records positive motion along the event-receiver direction, defined by the local azimuth at the receiver (i.e., backazimuth + 180°) and incidence angle (measured downwards away from the positive upwards direction).
The T direction is transverse to L, such that when looking along the direction towards the station, T is on the right and lies in the horizontal plane.
The Q direction is perpendicular to both, lying in the saggital plane, with some component in the vertical direction.
If azimuth and inclination are not passed in explicitly, then they are determined using the event-station geometry. This is only possible for both for Traces in Cartesian geometry, since inclination is not well-determined in a geographic system. Geographic-system traces (the default) must pass at least the inclination. For the Cartesian case, we assume straight-line paths between event and receiver.
tol specifies the angle in ° by which the traces must be orthogonal; see are_orthogonal
If incidence is 0° or 90° (the direction is vertical), then the choice of Q and T is arbitrary and simply chosen such that Q points along the local azimuth.
Diagram
Plan view
⋆ (event) North
` ↑
` |
` |
`
∇ (station)
⊙ `
- Q `
↙ ↘
T LSide view
Q
↑
Up |
↑ |
| | __ → L
| (station) ∇ ⊙__---
.__-- T
.__--
__--
⋆ (event)Examples
julia> e, n, z = sample_data(:regional)[1:3];
julia> azi = azimuth(e) + 180
216.85858118935954
julia> inc = 30; # Determined from other calculation
julia> l, q, t = rotate_to_lqt!(e, n, z, azi, inc)
(Seis.Trace(.ELK..1: delta=0.025, b=-5.000015, nsamples=12000), Seis.Trace(.ELK..2: delta=0.025, b=-5.000015, nsamples=12000), Seis.Trace(.ELK..T: delta=0.025, b=-5.000015, nsamples=12000))
julia> l.sta.azi, l.sta.inc, l.sta.cha
(216.85858f0, 30.0f0, "1")
julia> t.sta.cha
"T"
julia> l == e, q == n, t == z # Original traces are modified and returned in a possibly different order
(true, true, true)See also: rotate_through!, rotate_to_azimuth_incidence!, rotate_to_enz
Seis.rotate_to_lqt — Functionrotate_to_lqt(t1, t2, t3[, azimuth[, incidence]; tol) -> l, q, tCopying version of rotate_to_lqt!.
Seis.rotate_to_azimuth_incidence! — Functionrotate_to_azimuth_incidence!(t1, t2, t3, azimuth, incidence[; tol]) -> x, y, zRotate a mutually-orthogonal set of traces t1, t2 and t3 such that the trace x points along the direction defined by azimuth, y points perpendicular to x and has components only in the direction along azimuth and the vertical; z is perpendicular to both and lies in the horizontal plane. x, y and z form a right-handed set and are commonly known as L, Q and T respectively. (See rotate_to_lqt!.)
Note that in this form, the underlying data and metadata in the input traces is altered, and the returned traces point to the same data as the input traces, but possibly in a different order. Use rotate_to_azimuth_incidence to return copies of the traces and leave the original traces unmodified.
See also: rotate_to_azimuth_incidence, rotate_to_gcp!, rotate_to_lqt!, rotate_through!
Seis.rotate_to_azimuth_incidence — Functionrotate_to_azimuth_incidence(t1, t2, t3, azimuth, incidence[; tol]) -> x, y, zCopying version of rotate_to_azimuth_incidence.
Seis.sort_traces_right_handed — Functionsort_traces_right_handed(t1, t2, t3) -> x, y, z, permSort the traces t1, t2 and t3 such that they form a right-handed set; requiring the traces to be mutually orthogonal. The direction of x, y and z are arbitrary. perm is a length-three tuple containing the indices (from 1 to 3) of the new order of traces, such that x is (t1, t2, t3)[perm[1]] and so on.
Example
julia> e, n, z = sample_data(:regional)[1:3];
julia> e.sta.cha, n.sta.cha, z.sta.cha # Confirm the order
("e", "n", "z")
julia> u, v, w, perm = Seis.sort_traces_right_handed(n, e, z); # A left-handed arrangement
julia> [u, v, w].sta.cha
3-element Vector{String}:
"n"
"z"
"e"
julia> [n, e, z][[perm...]] # Indexing by perm gives us the new order
3-element Vector{Trace{Float32, Vector{Float32}, Seis.Geographic{Float32}}}:
Seis.Trace(.ELK..n: delta=0.025, b=-5.000015, nsamples=12000)
Seis.Trace(.ELK..z: delta=0.025, b=-5.000015, nsamples=12000)
Seis.Trace(.ELK..e: delta=0.025, b=-5.000015, nsamples=12000)IO
Seis.read_mseed — Functionread_mseed(file; kwargs...) -> traces
read_mseed(file, T; kwargs...) -> traces::Vector{T}Read a single miniseed file from disk and return a set of Traces.
The meta.mseed_file field of each trace contains the file name.
Optionally specify the type of trace T <: AbstractTrace to read. By default, T is Trace{Float64, Vector{Float32}, Seis.Geographic{Float64}}, since almost all seismic data stored in Miniseed format is single-precision, and because the sampling rate is stored at a 64-bit float in miniSEED files.
Example
Read a single file:
julia> read_mseed("data.mseed")Read a single file assuming a Cartesian geometry:
julia> read_mseed(CartTrace{Float64, Vector{Float32}}, "data.mseed")Handling gapped/overlapped data
When channels containing gaps or overlaps are encountered, they are split into multiple Traces as each Trace must be continuous and evenly sampled. However, data quite often contain single-sample offsets which are later corrected, and so these are ignored by default.
Use the keyword argument maximum_gap to control whether or not gaps cause new traces to be created. See below for more details.
Keyword arguments
The following keyword arguments can be passed to read_mseed:
headers_only = false: Iftrue, only read trace header information, leaving the returned traces empty. In this case, the following additional fields in.metaare set:mseed_nsamples: Number of samples in the tracemseed_enddate:DateTimeof the final samplemseed_endtime: Time of the final sample
maximum_gap: The maximum absolute gap length in s beyond which gaps are no longer tolerated in a single trace. By default this is the sampling interval of the trace being read.verbose = 0: An integer starting from 0 upwards indicating how much information about the reding process should be printed to the screen. The default (0) only produces output for errors and warnings.
read_mseed(data::Vector{UInt8}[, T]; kwargs...) -> tracesRead Miniseed data from memory, held as a set of bytes, optionally specifying the type T of traces to return. Keyword arguments are the same as for reading from a file on disk.
read_mseed(pattern, dir) -> ::Vector{<:Trace}
read_mseed(pattern, dir, T) -> Vector{T}Read all files matching pattern in directory dir.
See Glob.glob for details of pattern matching.
Optionally specify the type of trace T <: AbstractTrace to read.
Example
Read all files matching "TA.*.BHZ.mseed" in all directories within DATA which themselves match "Event_??":
julia> read_mseed("Event_??/TA.*.BHZ.mseed", "DATA")Seis.read_sac — Functionread_sac(file; terse=false, header_only=true) → ::TraceRead a single evenly-sampled SAC file and return a Trace. If terse is true, then warn when auto-byteswapping files.
Example
julia> file = joinpath(dirname(pathof(Seis)), "..", "data", "seis.sac");
julia> t = read_sac(file)
Seis.Trace{Float32,Vector{Float32},Seis.Geographic{Float32}}:
b: 52.66
delta: 0.01
GeogStation{Float32}:
sta.lon: -120.0
sta.lat: 48.0
sta.sta: CDV
sta.azi: 0.0
sta.inc: 0.0
sta.meta: Seis.SeisDict{Symbol, Any}()
GeogEvent{Float32}:
evt.lon: -125.0
evt.lat: 48.0
evt.dep: 0.0
evt.time: 1981-03-29T10:38:14
evt.id: K8108838
evt.meta: Seis.SeisDict{Symbol, Any}()
Trace:
picks: 2
meta: SAC_lpspol => true
SAC_nevid => 0
SAC_iftype => 1
file => "src/../data/seis.sac"
SAC_idep => 50
SAC_iztype => 9
SAC_lcalda => true
SAC_unused18 => false
SAC_lovrok => true
SAC_norid => 0
SAC_ievtyp => 42Reading only headers
To read only the headers from a SAC file, returning an empty trace, set header_only to true. In this case, the trace's meta dictionary contains a pair :SAC_npts => npts, where npts is the number of data points as held in the SAC file's header. Traces read from SAC files with header_only can used to overwrite the headers of files on disk, so long as npts is consistent.
read_sac(glob, dir; echo=false, header_only=false) → ::Vector{Trace}Read SAC files which match the patern glob in directory dir and return a set of Traces. Add the file names to t.meta.file. These are relative paths.
File names matching the pattern are shown if echo is true.
Example
julia> dir = joinpath(dirname(pathof(Seis)), "..", "data", "local");
julia> t = read_sac("*.z", dir)
9-element Vector{Trace{Float32, Vector{Float32}, Seis.Geographic{Float32}}}:
Seis.Trace(.CALZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CAOZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CDAZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CDVZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CMNZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CPSZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CVAZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CVLZ..: delta=0.01017683, b=-7.690632, nsamples=3933)
Seis.Trace(.CVYZ..: delta=0.01017683, b=-7.690632, nsamples=3933)SAC header conventions
When reading SAC files, the following conventions are observed:
- The event id is held in header
KEVNM - Channel ID is held in
KCMPNM - Location ID is held in
KHOLE - If
Oand the file origin time parameters are set,Ois shifted to 0 time, and all time picks are adjusted. This is similar to using the commandsch o gmt [date]; ch allt (0 - &1,o&)to set the origin in SAC. - Time picks are added to the
Tracepicks.
SAC headers which don't directly translate to Trace attributes are placed in the .meta field and have names prefixed by "SAC_".
Seis.write_mseed — Functionwrite_mseed(file, t; append=false, verbose=0, pubversion=1, record_length=nothing, version=2)Write the data contained in the trace(s) t to file on disk in miniSEED format.
t may be either a single AbstractTrace, or an array of AbstractTraces.
miniSEED files can contain data in (amongst others) in Float32, Float64 and Int32 format. This function will use whatever precision or type the data in t have and attempt to write. If for example you want to write a trace with a Float64 element type to a miniSEED file with element type Float32, you should first convert the trace using convert. (Note that since Seis does not support integer-valued trace data, it will not write 32-bit integer miniSEED files.)
If the trace does not have an origin time set, an error is thrown.
Keyword arguments
append::Bool: Iftrue, add the data intto the end of any data already existing infile. miniSEED files can contain multiples traces.verbose::Integer: Controls the verbosity of the miniSEED conversion and writing process. Larger values ofverbosecause more output to be produced.pubversion::Integer: The publication version of data describes whether a set of data has been updated since being initially published. Higher numbers correspond to records which supercede lower versions, which start at 1 (the default).record_length::Integer: The number of bytes used to write each miniSEED record.version: The miniSEED file version to write. Can be2(the default) or3.
Seis.write_sac — Functionwrite_sac(t, file; littleendian=false)
write_sac(t, io::IO; littleendian=false)Write the Trace t to a file on disk or an IO object in SAC format.
Keys in the t.meta field which begin with SAC_ have their values written to the corresponding SAC field (e.g., t.meta.SAC_kuser0 is written to the KUSER0 header). The user is responsible for ensuring that the values corresponding to these keys can be converted to the correct header type. Note also that SAC_ meta fields override the equivalent Trace headers (e.g., t.sta.sta is equivalent to SAC_kstnm) and so one way to override the values in Trace headers is to set the SAC_ fields. Note that the header is lowercase (i.e., SAC_kstnm not SAC_KSTNM).
Time picks with keys corresponding to SAC picks headers (A, F, and T0 to T9) are transferred, but other picks are not.
If t is in a Cartesian reference frame (i.e., its positions are given by CartEvent and CartStation), then the Cartesian station coordinates x, y and z are saved respectively to headers USER0, USER1 and USER2. Likewise, the event coordinates are saved respectively to USER3, USER4 and USER5. Any information in meta fields SAC_user0 to SAC_user5 will overwrite this data.
The convention on how non-geographic coordinates are written in SAC headers is not part of the API and may change at any time. Saving non-standard information in SAC headers should be done explicitly by the user if this information is important.
By default, files are written to disk in bigendian format (MacSAC or SAC/BRIS convention). Use littleendian=true to write in littleendian byte order (SAC/IRIS or SAC2000 convention).
See also: read_sac
Seis.write_sac_header — Functionwrite_sac_header(t, file; check=true, littleendian=false)Overwrite the equivalent SAC headers in the Trace t to file on disk or an IO object in SAC format. This is especially useful to update the headers of files which have been read with read_sac(file; header_only=true); see read_sac.
When check is true (the default), write_sac_header checks that file is an existing SAC trace with the correct number of points in the data trace, and will determine the file endianness in order to write the headers correctly. However, if check is false, then no checks are made. In this case, the header will be written in bigendian endianness (MacSAC or SAC/BRIS format) unless littleendian is true. littleendian has no effect if check is true.
This function is useful for updating headers for files on disk without having to read and write the entire trace from and to the disk.
With the option check=false, no check is made that the header written to disk matches the trace on disk in any way. Take care in particular to write a value of NPTS to the header which matches the number of points in the pre-existing SAC file.
overwrite_header will happily overwrite the first bytes of ANY file you point it at if check is false, making no check that file is actually a SAC file.
The number of points stated in the header is taken from t.meta.SAC_npts if it is set, in which case the length of the trace in memory is ignored. If t.meta does not contain a .SAC_npts entry, then the number of data points is used to fill the NPTS SAC header.
See write_sac for more information on how headers are transferred from Traces to SAC headers.
Example
julia> t = Trace(0, 1, [1, 2, 3]);
julia> file, _ = mktemp();
julia> write_sac(t, file);
julia> t.sta.lon, t.sta.lat = 15, 20; # Update coordindates
julia> trace(t2) .= 0; # Change data
julia> write_sac_header(t, file);
julia> t2 = read_sac(file);
julia> t2.sta
Seis.Station{Float32,Seis.Geographic{Float32}}:
lon: 15.0
lat: 20.0
dep: missing
net: missing
sta: missing
loc: missing
cha: missing
elev: missing
azi: missing
inc: missing
meta:
julia> trace(t2) # Data on disk are not touched
3-element Vector{Float32}:
1.0
2.0
3.0Seis.SAC.SACTrace — TypeSACTrace(delta, npts, b=0.) -> ::SACTraceConstruct a composite type holding an evenly-spaced SAC time-series trace, where the trace is accessed through the field name t. Supply the constant sampling interval delta in seconds, and the number of points in the trace t. Optionally, specify the trace start time b in seconds.
SACTrace(v::AbstractVector, delta, b=0.) -> ::SACTraceConstruct a SACTrace by supplying an array v, sampling interval delta and optionally the starting time.
SACTrace(d::Vector{UInt8}, file=""; swap=true, terse=false, check_npts=true) -> ::SACTraceConstruct a SACTrace from a raw array of bytes representing some data in SAC format. If swap is false, then non-native-endian files are not converted. If terse is true, then warnings about swapping are not written. If check_npts is false, then parts of files are read without error.
Example data sets
Seis.sample_data — Functionsample_data() -> ::Trace
sample_data(kind::Symbol) -> ::Array{Trace}Return some sample data.
With no arguments, sample gives one trace from a local earthquake recorded in California.
In the second form, a set of traces is returned according to the table below:
kind | Description |
|---|---|
:local | Livermore Valley, CA. 9 3-component stations |
:regional | Nevada. 4 3-component stations |
:teleseism | Mid-period recording of Eureka, CA event. 4 3-c stations |
:teleseisl | Long-period recording of Eureka, CA event. 4 3-c stations |
:array | Deep Fiji event. 60 vertical stations in the UK |