API Reference
This page gives all the exported functions and types, in groups by their purpose.
Contents
Data model
Timekeepers.TimekeeperChannel Type
TimekeeperChannelOne component of a recording. It holds the samples and all the data that you need to put them in time and to interpret them.
Fields
component::Symbol– the standard component name (:bx,:by,:bz,:e1,:e2, ...).data::Vector{Float64}– the samples, inunits.sample_rate::Float64– samples per second.start::DateTime– timestamp ofdata[1].units::String– physical units, e.g."nT"or"mV/km".source_file::String– the file that the samples came from (empty for synthetic data).header::Dict{String, Any}– the header fields of the format, kept for the writer.
See also TimekeeperRun, end_time.
Timekeepers.TimekeeperRun Type
TimekeeperRunOne continuous recording. It is a set of TimekeeperChannels with the same sample rate and start time. It also holds the run metadata that a writer needs to make the original file again.
Fields
site::String– site name, usually from the file or directory name.instrument::String– instrument description, e.g."Metronix ADU".source_format::Symbol–:lemi424,:geomagor:metronix.channels::Dict{Symbol, TimekeeperChannel}– channels, with the component as key.metadata::Dict{Symbol, Any}– run metadata: position, sample rate, header values and, for Metronix, the paths of the XML templates for the writer.
The readers (read_timekeeper, read_lemi424, read_geomag, read_metronix) return a run. The writers use it. Use to_timearray to change it to a TimeSeries.TimeArray.
Timekeepers.components Function
components(run::TimekeeperRun) -> Vector{Symbol}All the component names in run, in alphabetical order.
See also default_components.
Timekeepers.default_components Function
default_components(run::TimekeeperRun) -> Vector{Symbol}The components of run in the usual magnetotelluric plot order (bx, by, bz, e1, e2). Components that are not in the run are not in the list. If the run has none of these names, the function returns components.
Timekeepers.sampling_rate Function
sampling_rate(run::TimekeeperRun) -> Float64The sample rate of run in Hz. If the channels have different rates, the function gives an error, because a TimekeeperRun holds one rate. To separate a Metronix site with more than one rate, use metronix_site_rates and the procedure that splits a site by rate.
Timekeepers.start_time Function
start_time(run::TimekeeperRun) -> Union{DateTime, Nothing}The earliest start of the channels in run, or nothing if the run has no channels.
Timekeepers.end_time Function
end_time(ch::TimekeeperChannel) -> DateTime
end_time(run::TimekeeperRun) -> Union{DateTime, Nothing}The timestamp of the last sample. The function calculates it from the start, the number of samples and the sample rate. For a run, it is the latest end of its channels.
sourceTimekeepers.duration_seconds Function
duration_seconds(run::TimekeeperRun) -> Float64The length of run in seconds (nsamples / sample_rate), or 0.0 if the run is empty.
TimeArray interop
Timekeepers.to_timearray Function
to_timearray(run::TimekeeperRun; components = default_components(run), axis = :auto) -> TimeArrayPut the selected channels of run into a TimeSeries.TimeArray. Each component is one column, in the order that you give.
axis sets the timestamp type:
:datetimegivesDateTimestamps with millisecond resolution.:timegivesTimestamps with nanosecond resolution (necessary above 1 kHz).:autoselects:timeif the rate is more than 1 kHz.
If the channels have different lengths, the function cuts them to the shortest length and gives a warning.
The metadata holds the site, the instrument, the source format, the sample rate, the start time and the units of each component. These values replace the same keys in run.metadata.
Timekeepers.from_timearray Function
from_timearray(ta::TimeArray; site, instrument, source_format, units, metadata) -> TimekeeperRunThe opposite of to_timearray. It wraps each column of ta as a TimekeeperChannel. The sample rate and the start time come from the metadata of ta. If the metadata does not have them, the function calculates them from the timestamps. The default unit is the standard unit for each component name.
Format-agnostic I/O
Timekeepers.read_timekeeper Function
read_timekeeper(path; format = :auto, kwargs...) -> TimekeeperRunRead a supported format into a TimekeeperRun. The function calls read_lemi424, read_geomag or read_metronix.
With format = :auto, the function finds the format:
A
.atsfile, or a directory that contains one, is Metronix.A
.txtfile with aGEOMAGheader is GEOMAG. Other.txtfiles are LEMI-424.
To skip the detection, give format = :lemi424, :geomag or :metronix. The function gives the other keywords to the selected reader.
Timekeepers.write_timekeeper Function
write_timekeeper(path, run::TimekeeperRun; format = :auto) -> StringWrite run in its native format. The function calls write_lemi424, write_geomag or write_metronix.
With format = :auto, the source_format of the run selects the writer. Thus, you can write a file that you read with read_timekeeper without more arguments.
Timekeepers.default_data_dir Function
default_data_dir() -> StringThe path that the app and the examples use if you do not give a data directory. It is data/ next to the package root if that directory exists. If not, it is examples/data/. The path that the function returns possibly does not exist.
LEMI-424
Timekeepers.LEMI424_COLUMNS Constant
LEMI424_COLUMNSThe names of the 24 fields of a LEMI-424 record, in the file order. The fields are separated by whitespace. There are six date and time fields, then the magnetic, electric, temperature, GPS and housekeeping columns. The reader uses the names to find the tokens. The writer uses them to make the original layout again.
sourceTimekeepers.read_lemi424 Function
read_lemi424(path; site, include_aux=true) -> TimekeeperRunRead a LEMI-424 text file into a run with one channel for each component. The function accepts the file path, an optional site name and a flag for the auxiliary channels (temperatures, GPS, battery). It returns a TimekeeperRun at 1 Hz. It makes a channel for each known data column. If the file does not have the column, the channel contains NaN.
Timekeepers.load_lemi424 Function
load_lemi424(path; components, site, include_aux=true) -> TimeArrayLoad a LEMI-424 text file as a TimeArray. The function accepts:
the file path;
the components to keep (from
LEMI424_DEFAULT_COMPONENTS);an optional site name;
a flag to add the auxiliary columns to the metadata.
It returns a TimeArray at 1 Hz. If include_aux is set, the metadata holds :aux_columns.
Timekeepers.write_lemi424 Function
write_lemi424(path, run; timestamps=nothing, aux=nothing) -> StringWrite a run as a LEMI-424 text file. The function accepts the destination path, the run, an optional timestamp vector and optional auxiliary columns. If you do not give the timestamps, the function makes them at 1 Hz. It returns the path. If the run is not at 1 Hz, it gives an error. The number of records is the length of the shortest channel.
sourcewrite_lemi424(path, ta; kwargs...) -> StringWrite a TimeArray as a LEMI-424 text file. The function accepts the destination path and the array. It gives kwargs to from_timearray, and it returns the path. It uses the auxiliary columns in the metadata again. Thus, a cycle of read and write keeps the original GPS and housekeeping fields.
GEOMAG
Timekeepers.read_geomag Function
read_geomag(path; site, include_aux=true) -> TimekeeperRunRead a GEOMAG text file into a run with one channel for each component. The function accepts the file path, an optional site name and a flag for the temperature channels. It returns a TimekeeperRun.
Timekeepers.load_geomag Function
load_geomag(path; components, site, include_aux=true) -> TimeArrayLoad a GEOMAG text file as a TimeArray. The function accepts:
the file path;
the components to read (keys of
GEOMAG_COLUMN_INDEX);an optional site name;
a flag to add the other temperature columns to the metadata as
:aux_columns.
It returns the array. The sample rate comes from the header. If the header does not give it, the rate comes from the first gap between timestamps.
sourceTimekeepers.write_geomag Function
write_geomag(path, ta) -> StringWrite a TimeArray as a GEOMAG text file. The function accepts the destination path and the array, and returns the path. If the array does not have one of :bx, :by, :bz, :e1 and :e2, the function writes 0 for it. Thus, the fixed column layout of the format stays the same. The temperatures come from the metadata :aux_columns. If the metadata does not have them, they are NaN.
write_geomag(path, run) -> StringWrite a run as a GEOMAG text file. The function accepts the destination path and the run, and returns the path. It first keeps only the GEOMAG_DEFAULT_COMPONENTS of the run.
Metronix ATS
Timekeepers.METRONIX_CHANNEL_MAP Constant
METRONIX_CHANNEL_MAPThe map from Metronix ATS channel types to Timekeepers component names: "Ex" => :e1, "Ey" => :e2, "Hx" => :bx, "Hy" => :by, "Hz" => :bz. A channel type that is not in this table stays as a symbol with the same name.
Timekeepers.read_metronix Function
read_metronix(path; site, components = nothing, include_aux = true) -> TimekeeperRunRead one Metronix ADU run (its .ats binary files and their .xml sidecar) into a TimekeeperRun. The XML is optional. All the data that the function reads comes from the .ats headers. Thus, the function can read a run without its XML. It then gives a warning, and write_metronix writes only the .ats files of the run.
A meas_* directory can hold more than one run, for example a 128 Hz run and 4096 Hz bursts. The run number and the rate in the filenames identify each run. path selects one run: the .xml of the run, one of its .ats files, or a meas_* directory that holds one run. metronix_site_runs gives the runs of a site.
The function multiplies the samples by the LSB value of each file. It changes the channel types with METRONIX_CHANNEL_MAP. To read only some components, give components. The default site is the name of the directory above the meas_* directory.
The metadata keeps the XML path and the filename tokens. Thus, write_metronix can use the original names again.
Timekeepers.load_metronix Function
load_metronix(meas_dir; components = nothing, kwargs...) -> TimeArrayread_metronix and then to_timearray. Use this function to get a TimeArray in one step, not a run.
Timekeepers.write_metronix Function
write_metronix(dest_meas_dir, run::TimekeeperRun) -> StringWrite run as a Metronix measurement directory. The directory gets one .ats file for each channel and an .xml sidecar. The sidecar comes from the template that the reader used. The run must come from read_metronix. If the run has no XML, the function writes it without an XML and gives a warning. The function returns dest_meas_dir.
Timekeepers.is_metronix_site Function
is_metronix_site(dir) -> BoolTells if dir holds Metronix data: its own .ats files, or meas_* directories with .ats files.
Timekeepers.metronix_site_rates Function
metronix_site_rates(dir) -> Vector{Float64}The different sampling rates in a Metronix site, in increasing order. The list is empty if dir is not a site.
Timekeepers.load_metronix_site Function
load_metronix_site(site_dir; rate = nothing) -> TimeArrayRead the runs of one sampling rate from a Metronix site, or from one meas_* directory (which can hold runs at more than one rate). The function reads them in time order, as one record.
Up to 1 kHz, the runs use one time grid, and
NaNfills the gaps between them.Above 1 kHz, the function joins the runs end to end. The gaps stay as jumps in time.
A site with one rate does not need rate. For a site with more than one rate, you must give rate. metronix_site_rates gives the rates and reads no samples.
The function reads the runs of the selected rate from the meas_* directories of the site, and writes nothing. If the site has directories for each rate next to it (DF002.128, made by a masked write), it reads from those, so that the cuts show.
Timekeepers.metronix_site_runs Function
metronix_site_runs(dir) -> Dict{Float64, Vector{String}}All the runs in a Metronix site, in groups by sampling rate, in order of start time. The name of each run is the path of its .xml, which read_metronix accepts.
A run is one run number at one rate. It is not one meas_* directory: an ADU can write a long 128 Hz run and some 4096 Hz bursts into the same directory. The result does not include XMLs without recorded .ats data. dir is a site of meas_* directories or one meas_* directory. The function reads only the .ats headers.
Timekeepers.write_metronix_site Function
write_metronix_site(run; mask = nothing, dest = nothing, min_samples = 1) -> (String, Vector{String})Cut run at the masked intervals. Write the parts into dest, a meas_* directory, in place of the files of the run there.
The default
destis themeas_*directory of the run in its rate directory. For example, it isDF002.128/meas_2021-09-25_14-02-01for a 128 Hz run ofDF002. A run that the reader read from there is replaced in the same location.The first good part keeps the run number. Each subsequent part gets the next free run number at the rate of the run in
dest.If the rate needs it, the function moves the start of a segment to a whole second.
Some segments are too short to keep as a run: shorter than one whole second (the ATS header and the XML cannot describe them), or shorter than
min_samples. The function ignores such a segment and gives a warning.With
mask = nothing, the function writes the full run.
The function returns dest and the runs that it wrote. The name of each run is a name that read_metronix accepts. For a full site, use write_metronix_site_masked.
Timekeepers.write_metronix_site_masked Function
write_metronix_site_masked(site_dir; intervals=[], rate_intervals=Dict(), min_samples=1, only=nothing, format=:default) -> Vector{String}Cut the masked intervals out of a Metronix site. The cuts occur in the rate directories of the site, <site>.128, <site>.4096, ... next to it. If these directories are missing, split_metronix_site first makes them. The site itself never changes. site_dir is the site or one of its rate directories. A rate directory stands for the full site.
The intervals are DateTime tuples, usually the mask intervals from the app. rate_intervals is a map from a sampling rate to the intervals for its runs. intervals cuts the runs at all the other rates. Keep the intervals for each rate if you drew the masks at one rate. For example, a 128 Hz run that recorded in the same hours as 4096 Hz bursts must not lose the parts that you masked on the bursts.
If no interval touches a run, the run stays as it is. If an interval touches a run, the good parts of the run replace it in its meas_* directory. The first part keeps the run number. Each subsequent part gets the next free run number at that rate in that directory, after all the runs and scheduled jobs there. Thus, the function does not rename other files:
DF002.4096/meas_2021-09-26_00-00-00/ R000 up to the cut, R002 after it,
R001 untouched, the .kmlThe function cuts the .ats files of a part from the run. The XML of the part is the XML of the run. Only the start, the stop, the numbers of samples and the file size change, and the .ats names when the part gets a new number. Each .ats header that gives the name of its XML changes to the new XML. The .kml stays. The masked time is not in the data, and nothing fills it.
Some parts are too short to keep as a run: shorter than one whole second, or shorter than min_samples. The function ignores such a part and gives a warning. If no run stays in a meas_* directory, the function removes the directory. If a run had no XML, the function writes it without an XML. The function returns the rate directories that it cut.
Each rate directory with a cut gets a mask.csv. The file gives each removed part, one row for each part. The rows of all the writes stay in the file, in time order:
start_sample,end_sample,start_time,end_time
17,40,2025-04-01T07:00:08.000,2025-04-01T07:00:10.875The samples have numbers from 1 at the start of the run, as the site recorded it. The two ends are included. Thus, the numbers stay the same after more cuts. The times are the times of the first and the last removed sample. The file includes the parts moved to a whole second and the parts that were too short. Thus, the file describes the data as written. A short README.md next to the file tells where the directory came from.
format = :default gives the layout above. :MTH5 is reserved for MTH5 output, which is not available yet. To cut only some runs, give only: run names from metronix_site_runs, or meas_* directories, in the rate directories.
Timekeepers.split_metronix_site Function
split_metronix_site(site_dir; dest = nothing, on_run = nothing) -> Vector{String}Copy a Metronix site into one directory for each sampling rate. The name of each directory is <site>.<rate>, and it is in dest (default: next to the site). Each directory is a usual site of meas_* directories with the runs at that rate:
DF002/meas_2021-09-25_14-02-01/ -> DF002.128/meas_2021-09-25_14-02-01/
DF002.4096/meas_2021-09-25_14-02-01/The .ats files and the .xml of each run go to its rate. The XML of a job that did not record goes to the rate in its filename. Each other file of a meas_* directory (the .kml) goes to each rate that the directory holds. The function copies the files byte for byte and does not change the source.
write_metronix_site_masked cuts the masked intervals in the rate directories. Thus, the function never copies over a rate directory that exists. It makes only the missing rates. It copies each rate directory fully under a temporary name and then renames it. Thus, a split that stops before the end leaves no partial rate directory. To start a rate again from the site, delete its rate directory. The function calls on_run(i, n, run_name) before it copies each run. It returns the rate directories, the lowest rate first.
Timekeepers.metronix_site_is_split Function
metronix_site_is_split(site_dir; dest = nothing) -> BoolTells if site_dir is already split by rate: each rate of the site has its rate directory in dest (default: next to the site). The function makes a rate directory only as a full directory. Thus, a rate directory that exists is complete.
Masking and cleaning
Timekeepers.TimekeeperMask Type
TimekeeperMask(ta::TimeArray)
TimekeeperMask(timestamps, masked, intervals)A good or bad flag for each sample of a time series, with the list of the contiguous bad intervals.
A mask that you make from a TimeArray has all its samples good. Edit it with mask_interval!, unmask_interval! and clear_mask!. The intervals field always agrees with the flags.
Fields
timestamps::Vector{T}– the time axis of the mask.masked::BitVector–truemarks a bad sample.intervals::Vector{Tuple{T, T}}– the contiguous masked spans.
To make outputs, use cleaned_timearray, good_segments and sample_weights. To save the mask and read it again, use write_mask and read_mask.
Timekeepers.mask_interval! Function
mask_interval!(mask, start_time, end_time) -> TimekeeperMaskMark each sample with a timestamp in [start_time, end_time] as bad. You can give the two limits in either order. The function changes mask and returns it.
mask = TimekeeperMask(ta)
mask_interval!(mask, DateTime(2020, 10, 4, 0, 10), DateTime(2020, 10, 4, 0, 20))Timekeepers.unmask_interval! Function
unmask_interval!(mask, start_time, end_time) -> TimekeeperMaskThe opposite of mask_interval!. Mark each sample in the closed interval as good again. The function changes mask and returns it.
Timekeepers.clear_mask! Function
clear_mask!(mask::TimekeeperMask) -> TimekeeperMaskMark all the samples as good and remove all the intervals. The function changes mask and returns it.
Timekeepers.masked_samples Function
masked_samples(mask::TimekeeperMask) -> IntThe number of samples that are bad now.
sourceTimekeepers.combine_masks Function
combine_masks(first_mask, masks...) -> TimekeeperMaskThe union of masks on the same time axis. A sample is bad if it is bad in one or more inputs. All the masks must have the same length. The function returns a new mask and does not change the inputs.
sourceTimekeepers.cleaned_timearray Function
cleaned_timearray(ta::TimeArray, mask::TimekeeperMask; mode = :nan) -> TimeArray
cleaned_timearray(app::TKApp; mode = :nan) -> TimeArrayApply mask to ta.
mode = :nan(the default) keeps the full time axis and writesNaNin the masked rows. Thus, the gaps stay visible and the interval between samples stays the same.mode = :dropremoves the masked rows. The time axis is then not uniform.
The metadata of the result holds :mask_intervals, :masked_samples and :cleaning_mode. If the length of the mask is not the length of ta, the function gives an error.
Timekeepers.good_segments Function
good_segments(ta::TimeArray, mask::TimekeeperMask; min_samples = 1) -> Vector{TimeArray}
good_segments(app::TKApp; min_samples = 1) -> Vector{TimeArray}Cut ta into the contiguous parts without a mask. The function removes each part that is shorter than min_samples. Use this function to give clean data to a processing step that needs windows without interruptions. For example, use min_samples = 256 for an FFT of 256 points.
Timekeepers.sample_weights Function
sample_weights(mask::TimekeeperMask; good = 1.0, bad = 0.0) -> Vector
sample_weights(app::TKApp; good = 1.0, bad = 0.0) -> VectorA weight for each sample, for robust processing. The weight is good where the mask is clear and bad where the mask is set. Use the weights to give a mask to a weighted regression without removing samples.
Timekeepers.write_cleaned Function
write_cleaned(path, ta::TimeArray, mask::TimekeeperMask; mode = :nan, delimiter = ',') -> String
write_cleaned(path, app::TKApp; mode = :nan, delimiter = ',') -> StringWrite cleaned_timearray to a delimited text file. The file has a timestamp column, then one column for each component. The function returns path.
To keep the format of the instrument, use write_timekeeper or the writer of the format.
Timekeepers.write_mask Function
write_mask(path, mask::TimekeeperMask; delimiter = ',') -> String
write_mask(path, app::TKApp; delimiter = ',') -> StringWrite the masked intervals to a file with the two columns start,stop and a header row. The function returns path. To read the file, use read_mask.
Timekeepers.read_mask Function
read_mask(path, ta::TimeArray; delimiter = ',') -> TimekeeperMaskMake a mask on the time axis of ta from an interval file that write_mask wrote. The function applies the intervals with mask_interval!. Thus, you can apply a mask that you saved for one series to a different series that covers the same times.
Interactive explorer
Timekeepers.TKApp Type
TKApp(; size = (1600, 900))
TKApp(path::AbstractString; kwargs...)
TKApp(ta::TimeArray; size = (1600, 900), source_format = :lemi424, source_path = "")Make the interactive Timekeepers explorer for a time series. The function does not open a window. If you give a path, the function first loads the data: one file, or a site directory. For a site directory, it joins the runs and fills the gaps. If you give nothing, the app starts empty and waits for Load.
The app owns the data, a TimekeeperMask and the GLMakie figure. To get the results, use cleaned_timearray, good_segments, sample_weights, write_cleaned and write_mask. Each of these functions accepts a TKApp directly.
Use run_tkapp to make and show the app in one step. display(app) opens the window and does not wait.
The app needs a desktop session with OpenGL 3.3 or newer.
sourceTimekeepers.run_tkapp Function
run_tkapp(; kwargs...)
run_tkapp(path::AbstractString; kwargs...)
run_tkapp(ta::TimeArray; kwargs...)
run_tkapp(app::TKApp)Open the Timekeepers explorer window and wait until you close it. Then return the TKApp. Thus, you keep the mask after the session.
using Timekeepers
app = run_tkapp("data/LEMI090.txt")
segments = good_segments(app; min_samples = 256)In the window:
Use Load Run… or Load Site… to open data.
Use the Window menu and the slider to scroll the record.
Left-drag to select an interval.
Use Mask, Unmask or Clear to edit the interval.
Use Write to export in the source format.
The View menu adds a PSD panel for each channel.
The app needs a desktop session with OpenGL 3.3 or newer. To make the app without showing it, refer to TKApp.
Survey dashboard
Timekeepers.SurveyRun Type
SurveyRunOne continuous recording that scan_survey found. The scan reads only the headers.
Fields
path::String– the XML (Metronix) or the data file of the run.sample_rate::Float64– samples per second.start::DateTime– time of the first sample.stop::DateTime– time immediately after the last sample.n_samples::Int– samples for each channel.components::Vector{Symbol}– the recorded channels (:e1,:e2,:bx,:by,:bz). For a Metronix run, these are all its.atsfiles. For LEMI-424 and GEOMAG, these are the columns that are not zero orNaNat the two ends of the file.
Timekeepers.SurveySite Type
SurveySiteA site that scan_survey found: its runs and its position.
Fields
name::String– the name of the site directory.path::String– the site directory.format::Symbol–:metronix,:lemi424or:geomag.latitude::Float64,longitude::Float64– decimal degrees,NaNif the headers give no position.elevation::Float64– metres,NaNif not known.runs::Vector{SurveyRun}– in order of start time.
Timekeepers.Survey Type
SurveyAll the sites in a survey directory, as scan_survey returns them. Use a position or a site name as the index: survey["site004"].
Timekeepers.scan_survey Function
scan_survey(root; include_split = false, maxdepth = 4, progress = nothing) -> SurveyFind all the sites in root and make an index of their runs. The function reads only the headers. It does not read the samples.
A site is a directory that holds Metronix
meas_*directories (or.atsfiles), or LEMI-424 or GEOMAG files.The function looks into the directories that are not sites, down to
maxdepthlevels.The position of each site comes from its headers: the
.atsheader of a Metronix run, the GPS columns of a LEMI-424 record, or the header block of a GEOMAG file.
The function ignores the rate directories that a split of a Metronix site makes (site002.128 next to site002). Thus, it does not count a site two times. To make an index of them as separate sites, give include_split = true.
The function uses the first and the last line of a LEMI-424 or GEOMAG file as the start and the end of the recording. Thus, it does not see gaps in one file.
progress, when given, is a function that receives a line of text for each directory that the function looks into and for each site that it finds.
See also site_references, reference_plan, run_tkdash.
Timekeepers.site_rates Function
site_rates(site) -> Vector{Float64}The different sampling rates of a SurveySite, in increasing order.
Timekeepers.site_components Function
site_components(site) -> Vector{Symbol}All the channels that a run of a SurveySite recorded, with the electric channels first.
Timekeepers.has_magnetic Function
has_magnetic(site) -> BoolTells if a SurveySite recorded the two horizontal magnetic channels, Hx and Hy. A base or remote site must supply these channels. A site with only electric channels (a telluric site) can have base and remote sites, but it can never be one.
Timekeepers.survey_rates Function
survey_rates(survey) -> Vector{Float64}The different sampling rates of all the sites of a Survey, in increasing order.
Timekeepers.recording_intervals Function
recording_intervals(site; rate = nothing) -> Vector{Tuple{DateTime, DateTime}}The spans that site recorded, at rate, or at all rates if rate is nothing or :all. Runs that touch become one span.
Timekeepers.recording_seconds Function
recording_seconds(site; rate = nothing) -> Float64The total time that site recorded, at rate, or at all rates if rate is nothing or :all.
Timekeepers.overlap_intervals Function
overlap_intervals(a, b; rate = nothing) -> Vector{Tuple{DateTime, DateTime}}The spans in which the sites a and b both recorded. rate sets which recordings make a pair:
a number – the two sites at that sampling rate;
nothing(the default) – the two sites at the same rate, at a rate that they share;:all– at all rates. Use it for a survey with different instruments (for example, a LEMI-424 at 1 Hz and a Metronix at 128 Hz). The processing will resample these records.
Timekeepers.overlap_seconds Function
overlap_seconds(a, b; rate = nothing) -> Float64The total length of overlap_intervals(a, b; rate).
Timekeepers.overlap_matrix Function
overlap_matrix(survey; rate = nothing) -> Matrix{Float64}The hours that each pair of sites recorded together, in the order of survey.sites. The diagonal holds the recording hours of each site.
Timekeepers.site_distance Function
site_distance(a, b) -> Float64The great-circle distance between two sites, in kilometres. NaN if one of the sites has no position.
Timekeepers.site_references Function
site_references(survey, site; rate = nothing, base_km = 5.0, remote_km = 0.1,
min_overlap_hours = 1.0, exclude = ()) -> (base, remote)The sites that recorded together with site (a SurveySite, its name or its index) for min_overlap_hours or more, at a common rate (refer to overlap_intervals):
base sites: within
base_kmof the site;remote sites:
remote_kmor more from the site.
The two lists are independent: with the defaults, a site 2 km away is in both. A remote site as near as 100 m is useful in a test array or a dense survey; for a remote reference that is free of local noise, select a site far away, or give a larger remote_km.
rate has the same meaning as for overlap_intervals. Base and remote sites supply their magnetic field. Thus, only sites that recorded Hx and Hy count (refer to has_magnetic). These sites are in neither list: sites beyond base_km and nearer than remote_km (when remote_km > base_km), sites without a position in their headers, and sites with only electric channels.
Each list is in order of the time recorded together, longest first. If two sites have the same time, the nearer site comes first. An entry is a NamedTuple:
site– the name of the sitedistance_km– the great-circle distance fromsiteoverlap_hours– the time recorded togetheroverlap_fraction– that time as a fraction of the recording ofsitewindows– the overlap spans, as(start, stop)pairsexcluded– tells if its name is inexclude. Excluded sites stay in the lists with this flag. Thus, a window can show them.reference_plandoes not include them
Timekeepers.common_window Function
common_window(survey, site, others; rate = nothing) -> Vector{Tuple{DateTime, DateTime}}The spans in which site and all the sites in others (sites or names) recorded together: at rate, at one rate that they all share (nothing), or at all rates (:all). Processing can use this part of the data when it uses site with all of others at the same time. The result is empty if others is empty or if the sites never recorded together.
Timekeepers.reference_plan Function
reference_plan(survey; rate = nothing, base_km = 5.0, remote_km = 0.1,
min_overlap_hours = 1.0, exclude = Dict()) -> Vector{NamedTuple}All the sites of survey with their base and remote sites from site_references. The result has one NamedTuple for each site: (site, base, base_hours, remote, remote_hours, common).
baseandremoteare vectors of site names, with the longest overlap first.base_hoursandremote_hoursare the hours that each of these sites recorded with the site, in the same order.commonis thecommon_windowof the site with all of them.
exclude[site] is a set of names that the lists of that site must not include.
See also write_reference_plan, read_reference_plan.
Timekeepers.write_reference_plan Function
write_reference_plan(path, survey; kwargs...) -> String
write_reference_plan(path, plan) -> StringWrite a reference_plan as a plain text table. The table has one header line and one row for each site. The columns are aligned:
site base overlap (h) remote overlap (h)
site002 site004, site006 11.77, 9.00 site099, site100 11.77, 11.77
site099 - - site100, site004 22.98, 12.00The base and remote sites are in order of longest overlap first. The overlaps below overlap (h) are in the same order. A - shows an empty list. The keywords are the same as for reference_plan. Use read_reference_plan to read the table. The function returns path.
Timekeepers.read_reference_plan Function
read_reference_plan(path) -> Vector{NamedTuple}Read a table that write_reference_plan (or Export in TKDash) wrote. The result has one (site, base, base_hours, remote, remote_hours) for each row. The sites are vectors of names, and the hours are vectors of numbers, in the order of the table.
Timekeepers.TKDash Type
TKDashThe survey dashboard. It holds:
a
Survey;the site in focus (
0for the overview);the rate and the limits on the screen;
the base and remote sites that you dropped by hand;
the GLMakie figure.
To make one, use TKDash(root) and display it. Or use run_tkdash, which opens it and waits.
After you close the window, your choices stay. reference_plan(dash) returns the plan as the window shows it, and write_reference_plan(path, dash) writes it.
Timekeepers.run_tkdash Function
run_tkdash(root; kwargs...) -> TKDash
run_tkdash(survey::Survey; kwargs...) -> TKDash
run_tkdash(; kwargs...) -> TKDashOpen the survey dashboard and wait until you close its window. Then return the TKDash with the choices that you made in it. The function scans root with scan_survey. It gives the keywords to TKDash. If you do not give root, a folder dialog asks for it.
dash = run_tkdash("data/survey") # pick sites, drop references, close the window
write_reference_plan("plan.txt", dash)Calibration
Timekeepers.SensorCalibration Type
SensorCalibrationThe calibration of one induction coil. A Metronix table gives the response normalized by frequency: magnitude in V/(nT·Hz) and phase in degrees. Thus, the response of the coil is magnitude · f · exp(i·phase) in V/nT. The file has one table with the chopper on and one with the chopper off.
Fields
sensor::String– the sensor type, e.g."MFS07e".serial::Int– the serial number.path::String– the calibration file.on,off–(f, magnitude, phase)tables in increasing frequency, empty if the file has no table for that state.
See also read_calibration, sensor_response.
Timekeepers.read_calibration Function
read_calibration(path; sensor = "", serial = 0) -> SensorCalibrationRead a Metronix calibration text file. It has a Chopper On and a Chopper Off block, each with rows of frequency, magnitude and phase.
The function examines each table. A coil has a smooth response. Thus, a jump by a factor of more than 5 in the normalized magnitude from one row to the next is a part of a table that does not belong to the coil (some files hold rows of a different model at their low end). The function keeps the longest smooth part of each table and gives a warning about the rows that it removed.
sourceTimekeepers.find_calibration Function
find_calibration(dirs, sensor, serial) -> Union{String, Nothing}The calibration file of a coil in dirs. The name of a Metronix file is the sensor type and the serial number in three digits, e.g. MFS07e160.txt. If no file has that name, a file with the same serial number and a sensor family that agrees (the type of an unknown sensor agrees with each family) is the file, but only if it is the only one.
Timekeepers.read_dipoles Function
read_dipoles(path) -> Dict{String, NTuple{4, Float64}}Read a dipole table, d/dipoles.dat of a survey. The first line is the header. Each other line holds a site name and the distances in metres from the centre of the site to the N, S, E and W electrodes:
site N S E W
site002 24.5 48.5 50.9 51.5Ex is N + S long and Ey is E + W. - is a distance that is not known. The result maps a site name to (N, S, E, W), with NaN for -.
Timekeepers.sensor_response Function
sensor_response(cal::SensorCalibration, f; chopper = true) -> ComplexF64The response of the coil at the frequency f in Hz, in V/nT. The function uses the table for the chopper state. If that table does not cover f but the other table does, the function uses the other table. Out of both tables, the normalized response keeps its value at the nearest end. That is the response of a coil far below its corner frequency, where its output is proportional to f.
Declination
Timekeepers.igrf_field Function
igrf_field(latitude, longitude, t; altitude_km = 0.0) -> NamedTupleThe main geomagnetic field of IGRF-14 at a geodetic (WGS84) position and time t (a DateTime, a Date or a decimal year, 1900-2030). The result has the north, east and down components (nT), declination (degrees east of true north), inclination (degrees, down positive) and intensity (nT).
See also igrf_declination, survey_declination.
Timekeepers.igrf_declination Function
igrf_declination(latitude, longitude, t; altitude_km = 0.0) -> Float64The declination of IGRF-14 (degrees east of true north) at a geodetic position and time. Refer to igrf_field.
Timekeepers.survey_declination Function
survey_declination(survey) -> NamedTupleThe declination that IGRF-14 gives for a survey: at the median position of its sites with a position, at the middle of its recordings. The result has declination (degrees east), latitude, longitude and time, or declination = NaN if no site has a position.
Sensor orientation
Timekeepers.read_orientations Function
read_orientations(path) -> (declination, rows)Read the orientation table of a survey, d/orientations.dat: the declination, and for each site the polarity of each channel.
# comments start with #
declination 10.49
site Ex Ey Hx Hy
1 +1 +1 +1 +1
2 +1 -1 +1 +1+1is a channel wired as planned,-1a channel wired the other way round in the field: the processing reverses it.flip_channel!changes the sign.-is+1.Ex is the N-S line (red at geographic north), Ey the E-W line (red at east).
The x axis of a fluxgate (LEMI-424, GEOMAG) comes from its static field:
declination − atan2(By, Bx); y is 90° more and z is down. Metronix coils are taken as Hx north and Hy east, and Metronix electric lines in the directions of the electrode positions of their .ats headers.
The result is the declination (NaN if the file has none; the processing then takes IGRF-14 at the position of the run) and a Dict from a site name to its row as text (Dict{Symbol, String} keyed by the channels :e1 (Ex), :e2 (Ey), :bx (Hx), :by (Hy)). Hz has no column: a vertical sensor cannot be wired the other way round. See also write_orientations, flip_channel!.
Timekeepers.write_orientations Function
write_orientations(path, declination, rows)Write an orientation table (see read_orientations), with the sites in the order of their names. declination can be NaN (no line).
Timekeepers.orientation_file Function
orientation_file(site_dir) -> Union{String, Nothing}d/orientations.dat in site_dir or in up to three directories above it.
Timekeepers.site_orientation Function
site_orientation(run; site_dir) -> NamedTupleThe orientation of the channels of run: (e1, e2, bx, by, signs, notes, file). The azimuths are in degrees east of true north: for a fluxgate the x axis from its static field and the declination (NaN keeps the header or nominal direction). signs[c] is the polarity of each channel from the orientation table of the survey (refer to read_orientations), notes a short note for each channel and file the table ("" if none).
Timekeepers.flip_channel! Function
flip_channel!(path, site, comp) -> Dict{Symbol, String}Change the polarity of one channel (:e1 Ex, :e2 Ey, :bx Hx or :by Hy) of site in the orientation table path (made if it is not there), +1 ↔ -1, and return the new row.
Transfer functions
Timekeepers.TransferFunction Type
TransferFunctionThe impedance and the tipper of one site, with their errors, as estimate_tf returns them.
The fields are in geographic coordinates: x is north and y is east. Z is in (mV/km)/nT and has the time dependence exp(+iωt). Thus, the phase of Zxy over a uniform half-space is +45°.
Fields
site::String– the site.mode::Symbol–:single,:base,:remoteor:base_remote.base::String– the site that gave the inputs Hx, Hy (""for the site itself).remote::Vector{String}– the reference sites.latitude,longitude,elevation– the position of the site.periods::Vector{Float64}– seconds, increasing.Z::Array{ComplexF64, 3}–2 × 2 × nperiods.NaNwhere there is no estimate.Z_var::Array{Float64, 3}– the varianceE|δZ|²of each element.T::Matrix{ComplexF64}–2 × nperiods:Tzx,Tzy.T_var::Matrix{Float64}– the variance of each tipper element.coherence::Matrix{Float64}–3 × nperiods: the multiple coherence of Ex, Ey and Hz with the inputs, with the robust weights.ref_coherence::Matrix{Float64}–2 × nperiods: the coherence of the inputs Hx, Hy with the reference (NaNwithout a reference).n_windows::Vector{Int}– the windows in each band.n_obs::Vector{Int}– the Fourier coefficients in each band.sample_rate::Vector{Float64}– the rate that gave each period.metadata::Dict{Symbol, Any}– the options, the sensors and the data spans.
See also apparent_resistivity, impedance_phase, write_modem.
Timekeepers.estimate_tf Function
estimate_tf(site; base = nothing, remote = nothing, rate = :all, kwargs...) -> TransferFunction
estimate_tf(survey::Survey, site; base = nothing, remote = nothing, kwargs...) -> TransferFunctionEstimate the impedance and the tipper of site. A site is a site directory (Metronix, LEMI-424 or GEOMAG), a data file, a SurveySite, a TimekeeperRun or a vector of runs. With a Survey, give the sites by their names; :auto then selects the base or the remote site with the longest overlap (refer to site_references).
The set-up:
no
base, noremote– single site: the inputs are Hx, Hy of the site;base– the inputs are Hx, Hy of the base site. Use it for a site without magnetic channels, or with poor ones;remote– one site or a vector of sites. Their Hx, Hy are the reference. In a vector of runs, the runs of each site name are one remote site. With more than one remote site, the reference has all their channels (a two-stage least squares fit);baseandremotetogether.
The method is in the header of Processing.jl. The keywords:
rate– the sampling rate in Hz, or:all(each rate that all the sites recorded, then the best estimate at each period).window = 256– the section length: samples in each data section (Chave & Thomson 2004), at each decimation level.overlap = 0.5– the section overlap.bands_per_decade = 8– the bands at the periods10^(j/8)s.prewhiten = 3– the terms of the least-squares AR pre-whitening filter (0: none).min_windows = 8– the data sections that a level needs. Fewer gives longer periods with larger errors.min_harmonic = 4– the lowest frequency index of a section at the last level. A lower one gives longer periods, closer to the trend of each section.nyquist_fraction = :auto– the highest frequency as a fraction of the Nyquist frequency of the record (0.5 is a quarter of the rate).:autofinds where the anti-alias filter of the recorder ends the signal: the lowest frequency above half the Nyquist frequency where the coherence of E with H falls below 0.5. The top is 5 % below it, from 0.5 to 0.9. A number sets it. A higher one gives shorter periods, closer to the filter.max_levels = 12– the most decimation levels.min_period = 0,max_period = Inf– the periods to estimate.method = :ct2004–:ct2004(two stages with bounded influence, after Chave & Thomson 2004) or:eb1986(one robust M-estimate with Huber weights, after Egbert & Booker 1986). Step 5 of the header of Processing.jl compares them.huber = 1.5– the parameter a of the Huber weights (Chave & Thomson 2004, eq. 7).leverage = true– the leverage weights of the bounded influence estimator (Chave & Thomson 2004, eq. 26;:ct2004only).jackknife_groups = 50– the blocks of data sections that the jackknife deletes one at a time.calibration– a directory (or a vector of directories) with the coil calibration files. If you do not give it, the function looks in the site directory and up to three directories above it, ins(the calibration directory of a survey) and in directories with "cal" in their names.dipole–Dict(:e1 => L1, :e2 => L2)in metres. If you do not give it, the lengths come from the row of the site ind/dipoles.datof the survey (refer toread_dipoles), then from the electrode positions in the.atsheaders. Without either, each electrode is 50 m from the centre.azimuths–Dict(component => degrees east of north)to replace the directions of the sensors.masks–Dict(site name => [(start, stop), …]): intervals to leave out.span–(start, stop): use only this time span.progress– a function that receives a line of text at each step. The function can call it from more than one thread.
Timekeepers.default_references Function
default_references(survey, site; base_km = 5.0, remote_km = 0.1) -> (base, remote)The set-up that TKProc selects when it loads site: names or nothing.
A site with Hx and Hy: no base site, and the remote site (none if no site is far enough).
A site without them: the base site with the longest overlap, and the remote site.
The remote site is the farthest of the sites that recorded with site at least 90 % as long as the best one: its local noise is the least like that of the site.
Timekeepers.apparent_resistivity Function
apparent_resistivity(tf::TransferFunction) -> (rho, rho_err)The apparent resistivity ρ = 0.2 T |Z|² of each element in Ω·m, and its error, both 2 × 2 × nperiods. The error comes from the standard deviation of Z along one axis, σ = √(var/2): δρ = 2ρσ/|Z|.
Timekeepers.impedance_phase Function
impedance_phase(tf::TransferFunction) -> (phi, phi_err)The phase of each element of Z in degrees, in (-180°, 180°], and its error δφ = σ/|Z| in degrees, both 2 × 2 × nperiods. Refer to apparent_resistivity for σ.
Timekeepers.rotate_tf Function
rotate_tf(tf::TransferFunction, angle) -> TransferFunctionThe transfer function in axes that are turned clockwise by angle degrees (east of north): Z' = R Z Rᵀ and T' = T Rᵀ. The variances turn with the same rule, for independent elements.
Transfer function I/O
Timekeepers.write_edi Function
write_edi(path, tf::TransferFunction) -> StringWrite tf to a SEG EDI file. The frequencies are in decreasing order. The file holds Z (ZXX … ZYY: real, imaginary, variance), the tipper (TX, TY: real, imaginary, variance) if the site has Hz, and the coherences of Ex, Ey and Hz with the inputs. The >INFO block lists the set-up (base and remote sites), the sensors and the options of the estimate. A missing value is 1.0E+32. The function returns path.
Timekeepers.read_edi Function
read_edi(path) -> TransferFunctionRead the impedance and the tipper of a SEG EDI file (the blocks that write_edi writes, and the same blocks from other programs). The values equal to the EMPTY value of the file are NaN.
Timekeepers.write_modem Function
write_modem(path, tfs; components = :full, units = :field, sign = :plus, origin = nothing,
elevation = false, description = "") -> StringWrite TransferFunctions (one or a vector) to a ModEM data file.
components–:full(the four elements ofZand the tipper),:offdiagonal(onlyZxy,Zyxand the tipper) or:impedance(no tipper).units–:fieldwrites[mV/km]/[nT].:ohmwritesZin Ω ([V/m]/[A/m]).sign–:pluswritesexp(+i\omega t), the convention of the estimate.:minuswrites the complex conjugate withexp(-i\omega t).origin–(lat, lon)of the grid origin. The default is the centre of the sites.elevation–truewritesz = -elevation. Withfalse(the default),z = 0, and the mesh puts the sites on its surface.
The error of an element is its estimated standard deviation along one axis, √(var/2), with no floor: set the error floors of an inversion in its own set-up. The file leaves out the elements without an estimate or with an error that is not finite. The function returns path.
Timekeepers.read_modem Function
read_modem(path) -> Vector{TransferFunction}Read the Full_Impedance, Off_Diagonal_Impedance and Full_Vertical_Components blocks of a ModEM data file. The result has one TransferFunction for each site, in the order of the file, in (mV/km)/nT with the convention exp(+iωt). The variance of each element is 2·error². The fields that a data file does not hold (coherences, counts) are NaN or zero.
Timekeepers.plot_tf Function
plot_tf(tf::TransferFunction; full_tensor = false, errors = true, wrap_phase = false,
size = (1300, 800)) -> FigureA figure of tf: the apparent resistivity above the phase on the left, the tipper Tzx above Tzy on the right, against the period, with the error bars. Zxy is red and Zyx blue. With full_tensor, Zxx (green) and Zyy (lilac) are there too. With errors = false, no error bars. With wrap_phase, the phases are wrapped to 0°-90° (modulo 180°). The real tipper is red and the imaginary tipper is blue. Save it with save("site.png", plot_tf(tf)).
Timekeepers.export_tf Function
export_tf(dir, tf::TransferFunction; full_tensor = false, errors = true, wrap_phase = false,
rotate = 0) -> Vector{String}Write the estimate of one site into dir as <name>.edi (write_edi) and <name>.png (plot_tf, with or without Zxx and Zyy and the error bars). <name> is tf_filename: the site, its base and remote sites and the values of the options. The INFO block of the EDI file holds each sensor with its calibration file or its dipole length and where the length came from. The errors are the estimated errors, with no floor. With rotate (degrees east of north), the plot shows the tensor turned by that angle; the EDI file stays in geographic axes. The function returns the paths.
Timekeepers.tf_filename Function
tf_filename(tf::TransferFunction) -> StringThe name (without extension) of the export of tf: the site, the base site, the remote sites, the rate and the values of the options, joined by -:
site-base-remote-rate-window-overlap-bands-prewhiten-top-harmonic-windows-levels-method-huber-leverage-jackknifee.g. site002-site002-site099-all-256-0.5-8-3-auto-4-8-12-ct2004-1.5-1-50. The base is the site itself when the site gives its own Hx, Hy; the remote is none without a remote site, and remote sites join with +. rate is all or the rate that was processed (128Hz, 16s); top is auto or the fraction of Nyquist; leverage is 1 or 0. The name holds all you need to give estimate_tf to make the estimate again. A period range other than all periods adds minperiod-maxperiod at the end.
Timekeepers.write_tf_report Function
write_tf_report(path, tf::TransferFunction; files = String[]) -> StringWrite a Markdown record of how tf was made: the site and its set-up (base and remote sites), the data of each rate (hours, spans, start and end, the decimation levels), each sensor with its calibration file or its dipole length and where the length came from (d/dipoles.dat, the header or the default), the calibration files and dipole tables that the estimate used, all the processing options, the files of the export and a table of the estimates (apparent resistivity and phase with their errors, the tipper, the coherences and the windows at each period). A PNG among files shows in the record. The function returns path.
Site processing
Timekeepers.parse_span Function
parse_span(s) -> Union{Tuple{DateTime, DateTime}, Nothing}A time span from the two date-times in s, as "2026-10-20 14:00 to 2026-10-21 07:20" (also with T, with seconds, or with -, – or / between them). nothing for "all", an empty text, or a text without two date-times in order.
Timekeepers.read_procset Function
read_procset(path) -> Dict{Symbol, String}
write_procset(path, settings; site = "")The processing set-up of one site, as TKProc saves it (Save set-up) and reads it when you select the site. One key value line each; # starts a comment:
base -
remote 10
section_length 256
method eb1986
bands_per_decade 6
min_period 8
max_period 3000
span 2026-10-20 14:00 to 2026-10-21 07:20The keys: base, remote, min_distance, rate, section_length, section_overlap, method, bands_per_decade, ar_terms, top_nyquist, min_frequency_index, min_sections, decimation_levels, huber_a, jackknife_blocks, leverage_weights, min_period, max_period, span and rotate. Their names are the terms of Chave & Thomson (2004). A key that the file leaves out keeps the default of a new TKProc window, and so does every key of a site without the file. write_procset writes the keys of settings in that order.
Timekeepers.procset_file Function
procset_file(site_dir) -> StringThe set-up file of a site: procset.dat in its directory. For the card folder of a logger (DATA0247) or a corrected copy, it is in the folder of the site above it. The file need not be there.
Timekeepers.procset_options Function
procset_options(settings) -> NamedTupleThe keywords of estimate_tf from the text values of procset.dat (read_procset). A key that settings leaves out takes the default of a new TKProc window. base, remote, min_distance and rotate are not keywords of the estimate: refer to procset_references.
Timekeepers.procset_references Function
procset_references(survey, site, settings) -> (base, remote)The base site and the remote sites of procset.dat: - is none (for the base, the site itself), all is remote_sites at min_distance metres (100 if the file has none), and other values are site names (remote sites joined with + or ,).
Timekeepers.remote_sites Function
remote_sites(survey, site; min_distance = 100.0, min_overlap = 0.75) -> Vector{String}The sites with Hx and Hy at min_distance metres or farther that recorded with site for min_overlap (a fraction) or more of its recording, nearest first: "all ≥ …" of the Remote menu of TKProc, and remote all in procset.dat. An estimate with several remote sites uses only the time that all of them recorded: a site that recorded a short part of the time would cut the data of the others, so it is left out (select it by itself to use it). A site without a position is never in the list.
Timekeepers.process_site Function
process_site(survey, site; procset = procset_file(site.path), progress = nothing) -> TransferFunctionThe transfer function of site (a name, an index or a SurveySite) with its set-up in procset.dat: the same estimate as Process in TKProc with that set-up. procset can also be a Dict of the values. The result keeps the values in tf.metadata[:procset] and the file in tf.metadata[:procset_file].
See also export_site, read_procset.
Timekeepers.export_site Function
export_site(survey, tf; dir = joinpath(site.path, "proc"), full_tensor = false, errors = true,
wrap_phase = false, rotate = nothing) -> Vector{String}Write the estimate tf of a site of survey into dir, the proc folder of the site (made new: the files of an earlier export there are removed):
<site>.edi– the transfer function in geographic axes;<site>_tf.png–paper_tf, turned byrotatedegrees (therotateof its procset.dat ifnothing);<site>_qc.png–paper_qc;procnotes.md– how the estimate was made (write_tf_report), with the set-up of procset.dat and the steps that make it again in TKProc.
The function returns the paths.
sourceTimekeepers.paper_tf Function
paper_tf(tf; full_tensor = false, errors = true, wrap_phase = false, rotate = 0.0,
size = (1100, 720)) -> FigureThe figure of plot_tf for a paper: thick axes without a grid, panel labels (a)-(d), the set-up in the title. rotate turns tf first (degrees). Save it as a PNG with save(path, fig; px_per_unit = 4).
Timekeepers.paper_qc Function
paper_qc(tf; size = (1100, 820)) -> FigureThe check of an estimate for a paper: (a) the relative error of Zxy and Zyx, (b) the coherence of Ex, Ey (and Hz) with the inputs and of the inputs with the reference, (c) the windows in each band, (d) the data that each rate used.
sourceTransfer function window
Timekeepers.TKProc Type
TKProcThe transfer function window. It holds:
the loaded
Survey;the selected site;
the
TransferFunctionof each site that you processed, inresults;the GLMakie figure.
To make one, use TKProc(survey_dir) and display it, or use run_tkproc. After you close the window, proc.results holds the estimates.
Timekeepers.run_tkproc Function
run_tkproc(survey_dir, site = nothing; kwargs...) -> TKProc
run_tkproc(survey::Survey, site; kwargs...) -> TKProc
run_tkproc(; kwargs...) -> TKProcOpen the transfer function window and wait until you close it. Then return the TKProc with the estimates that you made in it (proc.results). With survey_dir, the window opens on that survey with site (or its first site) and its base and remote sites selected (refer to TKProc). Select the other sites in the Site menu. Without it, the window opens empty: use Survey…. Start Julia with more than one thread (julia -t auto). Thus, the window stays live while a site is processed.
proc = run_tkproc("data/survey", "site004") # process, export, close the window
export_tf("out", proc.results["site004"])Index
Timekeepers.LEMI424_COLUMNSTimekeepers.METRONIX_CHANNEL_MAPTimekeepers.SensorCalibrationTimekeepers.SurveyTimekeepers.SurveyRunTimekeepers.SurveySiteTimekeepers.TKAppTimekeepers.TKDashTimekeepers.TKProcTimekeepers.TimekeeperChannelTimekeepers.TimekeeperMaskTimekeepers.TimekeeperRunTimekeepers.TransferFunctionTimekeepers.apparent_resistivityTimekeepers.cleaned_timearrayTimekeepers.clear_mask!Timekeepers.combine_masksTimekeepers.common_windowTimekeepers.componentsTimekeepers.default_componentsTimekeepers.default_data_dirTimekeepers.default_referencesTimekeepers.duration_secondsTimekeepers.end_timeTimekeepers.estimate_tfTimekeepers.export_siteTimekeepers.export_tfTimekeepers.find_calibrationTimekeepers.flip_channel!Timekeepers.from_timearrayTimekeepers.good_segmentsTimekeepers.has_magneticTimekeepers.igrf_declinationTimekeepers.igrf_fieldTimekeepers.impedance_phaseTimekeepers.is_metronix_siteTimekeepers.load_geomagTimekeepers.load_lemi424Timekeepers.load_metronixTimekeepers.load_metronix_siteTimekeepers.mask_interval!Timekeepers.masked_samplesTimekeepers.metronix_site_is_splitTimekeepers.metronix_site_ratesTimekeepers.metronix_site_runsTimekeepers.orientation_fileTimekeepers.overlap_intervalsTimekeepers.overlap_matrixTimekeepers.overlap_secondsTimekeepers.paper_qcTimekeepers.paper_tfTimekeepers.parse_spanTimekeepers.plot_tfTimekeepers.process_siteTimekeepers.procset_fileTimekeepers.procset_optionsTimekeepers.procset_referencesTimekeepers.read_calibrationTimekeepers.read_dipolesTimekeepers.read_ediTimekeepers.read_geomagTimekeepers.read_lemi424Timekeepers.read_maskTimekeepers.read_metronixTimekeepers.read_modemTimekeepers.read_orientationsTimekeepers.read_procsetTimekeepers.read_reference_planTimekeepers.read_timekeeperTimekeepers.recording_intervalsTimekeepers.recording_secondsTimekeepers.reference_planTimekeepers.remote_sitesTimekeepers.rotate_tfTimekeepers.run_tkappTimekeepers.run_tkdashTimekeepers.run_tkprocTimekeepers.sample_weightsTimekeepers.sampling_rateTimekeepers.scan_surveyTimekeepers.sensor_responseTimekeepers.site_componentsTimekeepers.site_distanceTimekeepers.site_orientationTimekeepers.site_ratesTimekeepers.site_referencesTimekeepers.split_metronix_siteTimekeepers.start_timeTimekeepers.survey_declinationTimekeepers.survey_ratesTimekeepers.tf_filenameTimekeepers.to_timearrayTimekeepers.unmask_interval!Timekeepers.write_cleanedTimekeepers.write_ediTimekeepers.write_geomagTimekeepers.write_lemi424Timekeepers.write_maskTimekeepers.write_metronixTimekeepers.write_metronix_siteTimekeepers.write_metronix_site_maskedTimekeepers.write_modemTimekeepers.write_orientationsTimekeepers.write_reference_planTimekeepers.write_tf_reportTimekeepers.write_timekeeper