BAYTAP-08 Demo

Uses earthscopestraintools library to

  • download strainmeter data and pressure data in miniseed format

  • convert raw data to units of strain

  • detrend and automatically estimate and remove offsets to create inputs for BAYTAP-08

  • use BAYTAP-08 to calculate the tidal constituents and pressure response coefficients

  • generate and remove trend, tidal (using SPOTL), pressure, and offset correction time series from original data

Not yet implemented here:

  • calculate signal-to-noise ratio for M2 and O1 tidal bands

  • containerized use of Cleanstrain+ for offset removal

[1]:
from earthscopestraintools.mseed_tools import ts_from_mseed
from earthscopestraintools.gtsm_metadata import GtsmMetadata
from earthscopestraintools.timeseries import plot_timeseries_comparison


import logging
logger = logging.getLogger()
logging.basicConfig(
        format="%(message)s", level=logging.INFO
    )

Download and prepare data

For BAYTAP, we want at least 3 months of continuous (non-gappy) strain and barometric pressure data

[2]:
#select a network, station, and time window
network = 'PB'
station = 'B073'
start="2015-07-01T00:00:00"
end = "2015-10-01T00:00:00"

#load the metadata for the station
meta = GtsmMetadata(network,station)

Uncorrected Strain data

[3]:
#load some 10 min data from miniseed, and view stats/plot
gauge_raw = ts_from_mseed(network=network, station=station, location='T0', channel='RS*', start=start, end=end)
gauge_raw.stats()
gauge_raw.plot()
PB B073 Loading T0 RS* from 2015-07-01T00:00:00 to 2015-10-01T00:00:00 from Earthscope DMC miniseed
    Trace 1. 2015-07-01T00:00:00.000000Z:2015-10-01T00:00:00.000000Z mapping RS1 to CH0
    Trace 2. 2015-07-01T00:00:00.000000Z:2015-10-01T00:00:00.000000Z mapping RS2 to CH1
    Trace 3. 2015-07-01T00:00:00.000000Z:2015-10-01T00:00:00.000000Z mapping RS3 to CH2
    Trace 4. 2015-07-01T00:00:00.000000Z:2015-10-01T00:00:00.000000Z mapping RS4 to CH3
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Converting missing data from 999999 to nan
  Converting 999999 values to nan
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
PB.B073.T0.RS*
    | Channels: ['CH0', 'CH1', 'CH2', 'CH3']
    | TimeRange: 2015-07-01 00:00:00 - 2015-10-01 00:00:00        | Period:           600s
    | Series:         raw| Units:        counts| Level:          0| Gaps:             0.0%
    | Epochs:       13249| Good:        13249.0| Missing:      0.0| Interpolated:      0.0
    | Samples:      52996| Good:          52996| Missing:        0| Interpolated:        0
../_images/notebooks_baytap_demo_5_1.png
[4]:
#apply a 2 hr lowpass butterworth filter to the data
name = f"{network}.{station}.gauge.filtered"
filt_cutoff_s = 2*60*60
gauge_filtered = gauge_raw.butterworth_filter(name=name,
                                              filter_type='lowpass',
                                              filter_order=5,
                                              filter_cutoff_s=filt_cutoff_s)
#gauge_filtered.stats()
#gauge_filtered.plot()
Applying Butterworth Filter
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
[5]:
#decimate to hourly data, as this is sufficiently sampled for BAYTAP tidal/pressure analysis
name = f"{network}.{station}.gauge.decimated"
gauge_decimated = gauge_filtered.decimate_to_hourly(name=name)
gauge_decimated.stats()
#gauge_decimated.plot()
Decimating to hourly
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
PB.B073.gauge.decimated
    | Channels: ['CH0', 'CH1', 'CH2', 'CH3']
    | TimeRange: 2015-07-01 00:00:00 - 2015-10-01 00:00:00        | Period:          3600s
    | Series:            | Units:        counts| Level:          1| Gaps:             0.0%
    | Epochs:        2209| Good:         2209.0| Missing:      0.0| Interpolated:      0.0
    | Samples:       8836| Good:           8836| Missing:        0| Interpolated:        0
[6]:
#convert digital counts to microstrain (Linearization) using some initial reference strains and physical information about the instrument
name = f"{network}.{station}.gauge.microstrain"
gauge_microstrain = gauge_decimated.linearize(reference_strains=meta.reference_strains, gap=meta.gap, name=name)
gauge_microstrain.stats()
gauge_microstrain.plot()
Converting raw counts to microstrain
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
PB.B073.gauge.microstrain
    | Channels: ['CH0', 'CH1', 'CH2', 'CH3']
    | TimeRange: 2015-07-01 00:00:00 - 2015-10-01 00:00:00        | Period:          3600s
    | Series: microstrain| Units:   microstrain| Level:          1| Gaps:             0.0%
    | Epochs:        2209| Good:         2209.0| Missing:      0.0| Interpolated:      0.0
    | Samples:       8836| Good:           8836| Missing:        0| Interpolated:        0
../_images/notebooks_baytap_demo_8_1.png

Initial trend correction

[7]:
name = f"{network}.{station}.gauge.trend_c"
trend_c = gauge_microstrain.linear_trend_correction(name=name)
trend_corrected = gauge_microstrain.apply_corrections([trend_c])
trend_corrected.plot()
Calculating linear trend correction
    Trend Start: 2015-07-01 00:00:00
    Trend End: 2015-10-01 00:00:00
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_10_1.png

Initial offset correction

Offsets in this section are automatically detected via a simple first differencing algorithm. The best approach is to first correct for other known changes (tides, pressure, trend), then to apply the calculate_offsets function. This function finds jumps between consecutive datapoints that are above a cutoff limit, which is assigned from a user-specified value multiplied by a user-specified percentile of all first differences calculated for the gauge. For example, if a multiplier of 10 and percentile of 75% are used on a dataset whose first difference 75th percentile is 2 nanostrain, any jump in the data above 20 nanostrain will be flagged as an offset. This method is not perfect, but works well for certain situations.

[8]:
name = f"{network}.{station}.gauge.offset_c"
offset_c = trend_corrected.calculate_offsets(limit_multiplier=10, cutoff_percentile=0.75, name=name)
trend_offset_corrected = trend_corrected.apply_corrections([offset_c])
#offset_c.plot()
plot_timeseries_comparison([trend_corrected, trend_offset_corrected],
                           names=['trend_corrected', 'trend_offset_corrected',],
                           zero=True)
Calculating offsets using cutoff percentile of 0.75 and limit multiplier of 10.
Using offset limits of [0.036702, 0.027049, 0.013494, 0.015453]
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_12_1.png

Barometric Pressure Data

[9]:
#download and prepare atmospheric pressure data, sampled at 30m by GTSM
atmp_raw = ts_from_mseed(network=network,
                         station=station,
                         location='TS',
                         channel='RDO',
                         period=1800,
                         start=start,
                         end=end,
                         scale_factor=0.001,
                         units='hPa')
atmp_raw.stats()
#atmp_raw.plot()
PB B073 Loading TS RDO from 2015-07-01T00:00:00 to 2015-10-01T00:00:00 from Earthscope DMC miniseed
    Trace 1. 2015-07-01T00:00:00.000000Z:2015-10-01T00:00:00.000000Z mapping RDO to atmp
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Converting missing data from 999999 to nan
  Converting 999999 values to nan
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
PB.B073.TS.RDO
    | Channels: ['atmp']
    | TimeRange: 2015-07-01 00:00:00 - 2015-10-01 00:00:00        | Period:          1800s
    | Series:         raw| Units:           hPa| Level:          0| Gaps:             0.0%
    | Epochs:        4417| Good:         4417.0| Missing:      0.0| Interpolated:      0.0
    | Samples:       4417| Good:           4417| Missing:        0| Interpolated:        0
[10]:
name = f"{network}.{station}.atmp.decimated"
atmp_decimated = atmp_raw.decimate_to_hourly(name=name, )
atmp_decimated.stats()
atmp_decimated.plot()
Decimating to hourly
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
PB.B073.atmp.decimated
    | Channels: ['atmp']
    | TimeRange: 2015-07-01 00:00:00 - 2015-10-01 00:00:00        | Period:          3600s
    | Series:         raw| Units:           hPa| Level:          1| Gaps:             0.0%
    | Epochs:        2209| Good:         2209.0| Missing:      0.0| Interpolated:      0.0
    | Samples:       2209| Good:           2209| Missing:        0| Interpolated:        0
../_images/notebooks_baytap_demo_15_1.png

Run BAYTAP to calculate tidal parameters and pressure response

[11]:
#Requires docker.  downloads and runs an image containing BAYTAP-08, and returns results as python dictionaries
#need to supply BAYTAP with strain data, pressure data, as well as lat/long/elev for station
results = trend_offset_corrected.baytap_analysis(atmp_ts=atmp_decimated,
                                                 latitude=meta.latitude,
                                                 longitude=meta.longitude,
                                                 elevation=meta.elevation
                                                 )
results
Please note, this method expects continuous data in microstrain and pressure in hPa.
4a85502584897919dd22518a0b688b748b994dc27586c592c9ee651ba33730ce
Docker container started.
Atmospheric pressure responses in microstrain/hPa and tidal parameters in degrees/nanostrain
baytap
Docker processes finished. Container removed.
[11]:
{'atmp_response': {'CH0': -0.010378,
  'CH1': -0.00841479,
  'CH2': -0.00692327,
  'CH3': -0.0067322},
 'tidal_params': {('CH0', 'M2', 'phz'): '-172.251',
  ('CH0', 'M2', 'amp'): '10.461',
  ('CH0', 'M2', 'doodson'): '2 0 0 0 0 0',
  ('CH0', 'O1', 'phz'): '-166.851',
  ('CH0', 'O1', 'amp'): '2.979',
  ('CH0', 'O1', 'doodson'): '1-1 0 0 0 0',
  ('CH0', 'P1', 'phz'): '-172.640',
  ('CH0', 'P1', 'amp'): '2.827',
  ('CH0', 'P1', 'doodson'): '1 1-2 0 0 0',
  ('CH0', 'K1', 'phz'): '153.528',
  ('CH0', 'K1', 'amp'): '1.513',
  ('CH0', 'K1', 'doodson'): '1 1 0 0 0 0',
  ('CH0', 'N2', 'phz'): '-178.805',
  ('CH0', 'N2', 'amp'): '0.372',
  ('CH0', 'N2', 'doodson'): '2-1 0 1 0 0',
  ('CH0', 'S2', 'phz'): '-168.576',
  ('CH0', 'S2', 'amp'): '6.374',
  ('CH0', 'S2', 'doodson'): '2 2-2 0 0 0',
  ('CH1', 'M2', 'phz'): '-148.400',
  ('CH1', 'M2', 'amp'): '7.158',
  ('CH1', 'M2', 'doodson'): '2 0 0 0 0 0',
  ('CH1', 'O1', 'phz'): '139.545',
  ('CH1', 'O1', 'amp'): '3.870',
  ('CH1', 'O1', 'doodson'): '1-1 0 0 0 0',
  ('CH1', 'P1', 'phz'): '167.507',
  ('CH1', 'P1', 'amp'): '2.929',
  ('CH1', 'P1', 'doodson'): '1 1-2 0 0 0',
  ('CH1', 'K1', 'phz'): '120.981',
  ('CH1', 'K1', 'amp'): '5.159',
  ('CH1', 'K1', 'doodson'): '1 1 0 0 0 0',
  ('CH1', 'N2', 'phz'): '-133.408',
  ('CH1', 'N2', 'amp'): '0.252',
  ('CH1', 'N2', 'doodson'): '2-1 0 1 0 0',
  ('CH1', 'S2', 'phz'): '-152.475',
  ('CH1', 'S2', 'amp'): '3.240',
  ('CH1', 'S2', 'doodson'): '2 2-2 0 0 0',
  ('CH2', 'M2', 'phz'): '112.936',
  ('CH2', 'M2', 'amp'): '1.230',
  ('CH2', 'M2', 'doodson'): '2 0 0 0 0 0',
  ('CH2', 'O1', 'phz'): '-165.629',
  ('CH2', 'O1', 'amp'): '2.976',
  ('CH2', 'O1', 'doodson'): '1-1 0 0 0 0',
  ('CH2', 'P1', 'phz'): '-170.864',
  ('CH2', 'P1', 'amp'): '2.269',
  ('CH2', 'P1', 'doodson'): '1 1-2 0 0 0',
  ('CH2', 'K1', 'phz'): '175.151',
  ('CH2', 'K1', 'amp'): '2.045',
  ('CH2', 'K1', 'doodson'): '1 1 0 0 0 0',
  ('CH2', 'N2', 'phz'): '14.300',
  ('CH2', 'N2', 'amp'): '0.152',
  ('CH2', 'N2', 'doodson'): '2-1 0 1 0 0',
  ('CH2', 'S2', 'phz'): '111.065',
  ('CH2', 'S2', 'amp'): '1.261',
  ('CH2', 'S2', 'doodson'): '2 2-2 0 0 0',
  ('CH3', 'M2', 'phz'): '148.610',
  ('CH3', 'M2', 'amp'): '2.970',
  ('CH3', 'M2', 'doodson'): '2 0 0 0 0 0',
  ('CH3', 'O1', 'phz'): '-135.304',
  ('CH3', 'O1', 'amp'): '2.210',
  ('CH3', 'O1', 'doodson'): '1-1 0 0 0 0',
  ('CH3', 'P1', 'phz'): '-157.251',
  ('CH3', 'P1', 'amp'): '1.693',
  ('CH3', 'P1', 'doodson'): '1 1-2 0 0 0',
  ('CH3', 'K1', 'phz'): '-111.030',
  ('CH3', 'K1', 'amp'): '0.838',
  ('CH3', 'K1', 'doodson'): '1 1 0 0 0 0',
  ('CH3', 'N2', 'phz'): '91.333',
  ('CH3', 'N2', 'amp'): '0.135',
  ('CH3', 'N2', 'doodson'): '2-1 0 1 0 0',
  ('CH3', 'S2', 'phz'): '165.026',
  ('CH3', 'S2', 'amp'): '2.174',
  ('CH3', 'S2', 'doodson'): '2 2-2 0 0 0'}}
[12]:
#Compare pressure response results to those in published metadata
#There will be some differences since this is only based on a small window of data
print("Calculated:", results['atmp_response'])
print("Published:", meta.atmp_response)
Calculated: {'CH0': -0.010378, 'CH1': -0.00841479, 'CH2': -0.00692327, 'CH3': -0.0067322}
Published: {'CH0': -0.012, 'CH1': -0.01, 'CH2': -0.0079, 'CH3': -0.0076}
[13]:
#Compare tidal parameter results to those in the published metadata
#There will be some differences since this is only based on a small window of data
print("Calculated:", results['tidal_params'])
print("Published:", meta.tidal_params)
Calculated: {('CH0', 'M2', 'phz'): '-172.251', ('CH0', 'M2', 'amp'): '10.461', ('CH0', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH0', 'O1', 'phz'): '-166.851', ('CH0', 'O1', 'amp'): '2.979', ('CH0', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH0', 'P1', 'phz'): '-172.640', ('CH0', 'P1', 'amp'): '2.827', ('CH0', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH0', 'K1', 'phz'): '153.528', ('CH0', 'K1', 'amp'): '1.513', ('CH0', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH0', 'N2', 'phz'): '-178.805', ('CH0', 'N2', 'amp'): '0.372', ('CH0', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH0', 'S2', 'phz'): '-168.576', ('CH0', 'S2', 'amp'): '6.374', ('CH0', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH1', 'M2', 'phz'): '-148.400', ('CH1', 'M2', 'amp'): '7.158', ('CH1', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH1', 'O1', 'phz'): '139.545', ('CH1', 'O1', 'amp'): '3.870', ('CH1', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH1', 'P1', 'phz'): '167.507', ('CH1', 'P1', 'amp'): '2.929', ('CH1', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH1', 'K1', 'phz'): '120.981', ('CH1', 'K1', 'amp'): '5.159', ('CH1', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH1', 'N2', 'phz'): '-133.408', ('CH1', 'N2', 'amp'): '0.252', ('CH1', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH1', 'S2', 'phz'): '-152.475', ('CH1', 'S2', 'amp'): '3.240', ('CH1', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH2', 'M2', 'phz'): '112.936', ('CH2', 'M2', 'amp'): '1.230', ('CH2', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH2', 'O1', 'phz'): '-165.629', ('CH2', 'O1', 'amp'): '2.976', ('CH2', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH2', 'P1', 'phz'): '-170.864', ('CH2', 'P1', 'amp'): '2.269', ('CH2', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH2', 'K1', 'phz'): '175.151', ('CH2', 'K1', 'amp'): '2.045', ('CH2', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH2', 'N2', 'phz'): '14.300', ('CH2', 'N2', 'amp'): '0.152', ('CH2', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH2', 'S2', 'phz'): '111.065', ('CH2', 'S2', 'amp'): '1.261', ('CH2', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH3', 'M2', 'phz'): '148.610', ('CH3', 'M2', 'amp'): '2.970', ('CH3', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH3', 'O1', 'phz'): '-135.304', ('CH3', 'O1', 'amp'): '2.210', ('CH3', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH3', 'P1', 'phz'): '-157.251', ('CH3', 'P1', 'amp'): '1.693', ('CH3', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH3', 'K1', 'phz'): '-111.030', ('CH3', 'K1', 'amp'): '0.838', ('CH3', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH3', 'N2', 'phz'): '91.333', ('CH3', 'N2', 'amp'): '0.135', ('CH3', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH3', 'S2', 'phz'): '165.026', ('CH3', 'S2', 'amp'): '2.174', ('CH3', 'S2', 'doodson'): '2 2-2 0 0 0'}
Published: {('CH0', 'M2', 'phz'): '-172.163', ('CH0', 'M2', 'amp'): '10.679', ('CH0', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH0', 'O1', 'phz'): '-167.318', ('CH0', 'O1', 'amp'): '2.925', ('CH0', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH0', 'P1', 'phz'): '-175.695', ('CH0', 'P1', 'amp'): '1.056', ('CH0', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH0', 'K1', 'phz'): '-160.382', ('CH0', 'K1', 'amp'): '2.704', ('CH0', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH0', 'N2', 'phz'): '179.368', ('CH0', 'N2', 'amp'): '1.958', ('CH0', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH0', 'S2', 'phz'): '-175.747', ('CH0', 'S2', 'amp'): '6.275', ('CH0', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH1', 'M2', 'phz'): '-148.679', ('CH1', 'M2', 'amp'): '7.809', ('CH1', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH1', 'O1', 'phz'): '143.932', ('CH1', 'O1', 'amp'): '4.237', ('CH1', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH1', 'P1', 'phz'): '139.121', ('CH1', 'P1', 'amp'): '1.976', ('CH1', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH1', 'K1', 'phz'): '140.482', ('CH1', 'K1', 'amp'): '5.156', ('CH1', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH1', 'N2', 'phz'): '-144.761', ('CH1', 'N2', 'amp'): '1.825', ('CH1', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH1', 'S2', 'phz'): '-167.968', ('CH1', 'S2', 'amp'): '3.057', ('CH1', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH2', 'M2', 'phz'): '109.445', ('CH2', 'M2', 'amp'): '1.133', ('CH2', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH2', 'O1', 'phz'): '-161.871', ('CH2', 'O1', 'amp'): '2.992', ('CH2', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH2', 'P1', 'phz'): '-169.262', ('CH2', 'P1', 'amp'): '0.921', ('CH2', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH2', 'K1', 'phz'): '-160.883', ('CH2', 'K1', 'amp'): '2.624', ('CH2', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH2', 'N2', 'phz'): '9.367', ('CH2', 'N2', 'amp'): '0.347', ('CH2', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH2', 'S2', 'phz'): '104.976', ('CH2', 'S2', 'amp'): '1.799', ('CH2', 'S2', 'doodson'): '2 2-2 0 0 0', ('CH3', 'M2', 'phz'): '151.372', ('CH3', 'M2', 'amp'): '2.959', ('CH3', 'M2', 'doodson'): '2 0 0 0 0 0', ('CH3', 'O1', 'phz'): '-135.281', ('CH3', 'O1', 'amp'): '2.413', ('CH3', 'O1', 'doodson'): '1-1 0 0 0 0', ('CH3', 'P1', 'phz'): '-127.049', ('CH3', 'P1', 'amp'): '0.682', ('CH3', 'P1', 'doodson'): '1 1-2 0 0 0', ('CH3', 'K1', 'phz'): '-118.362', ('CH3', 'K1', 'amp'): '2.351', ('CH3', 'K1', 'doodson'): '1 1 0 0 0 0', ('CH3', 'N2', 'phz'): '106.439', ('CH3', 'N2', 'amp'): '0.452', ('CH3', 'N2', 'doodson'): '2-1 0 1 0 0', ('CH3', 'S2', 'phz'): '152.039', ('CH3', 'S2', 'amp'): '2.334', ('CH3', 'S2', 'doodson'): '2 2-2 0 0 0'}

Calculate and plot corrections

Start from the original gauge microstrain

Calculate a simple linear trend correction

[14]:
name = f"{network}.{station}.gauge.trend_c"
trend_c = gauge_microstrain.linear_trend_correction(name=name)

trend_corrected = gauge_microstrain.apply_corrections([trend_c])
plot_timeseries_comparison([gauge_microstrain, trend_c, trend_corrected], names=['uncorrected', 'trend', 'corrected'], zero=True)
Calculating linear trend correction
    Trend Start: 2015-07-01 00:00:00
    Trend End: 2015-10-01 00:00:00
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_22_1.png

Calculate a pressure correction using the generated pressure responses

[15]:
name = f"{network}.{station}.gauge.atmp_c"
atmp_c = atmp_decimated.calculate_pressure_correction(results['atmp_response'], name=name)
trend_atmp_corrected = trend_corrected.apply_corrections([atmp_c])

plot_timeseries_comparison([trend_corrected, trend_atmp_corrected],
                            names=['trend_corrected', 'trend_atmp_corrected'],
                            zero=True)


Calculating pressure correction
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_24_1.png

Calculate a tidal correction using the generated tidal parameters

This function downloads and runs a SPOTL image, and uses the hartid program to generate a timeseries of predicted tides at this location

[16]:
name = f"{network}.{station}.gauge.tide_c"
tide_c = trend_atmp_corrected.calculate_tide_correction(tidal_parameters=results['tidal_params'], longitude=meta.longitude, name=name)
trend_atmp_tide_corrected = trend_atmp_corrected.apply_corrections([tide_c])

plot_timeseries_comparison([trend_atmp_corrected, trend_atmp_tide_corrected],
                           names=['trend_atmp_corrected', 'trend_atmp_tide_corrected',],
                           zero=True)
Calculating tide correction
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_26_1.png

Calculate offsets

Offsets in this section are automatically detected via a simple first differencing algorithm. The best approach is to first correct for other known changes (tides, pressure, trend), then to apply the calculate_offsets function. This function finds jumps between consecutive datapoints that are above a cutoff limit, which is assigned from a user-specified value multiplied by a user-specified percentile of all first differences calculated for the gauge. For example, if a multiplier of 10 and percentile of 75% are used on a dataset whose first difference 75th percentile is 2 nanostrain, any jump in the data above 20 nanostrain will be flagged as an offset. This method is not perfect, but works well for certain situations.

[17]:
name = f"{network}.{station}.gauge.offset_c"
offset_c = trend_atmp_tide_corrected.calculate_offsets(limit_multiplier=10, cutoff_percentile=0.75, name=name)
trend_atmp_tide_offset_corrected = trend_atmp_tide_corrected.apply_corrections([offset_c])
#offset_c.plot()
plot_timeseries_comparison([trend_atmp_tide_corrected, trend_atmp_tide_offset_corrected],
                           names=['trend_atmp_tide_corrected', 'trend_atmp_tide_offset_corrected',],
                           zero=True)
Calculating offsets using cutoff percentile of 0.75 and limit multiplier of 10.
Using offset limits of [0.005026, 0.004768, 0.002659, 0.002213]
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
Applying corrections
    Found 0 epochs with nans, 0.0 epochs with 999999s, and 0 missing epochs.
    Total missing data is 0.0%
../_images/notebooks_baytap_demo_28_1.png

Plot fully corrected vs trend corrected data

[18]:
title=f"{network}.{station}.gauge.strains"
plot_timeseries_comparison([trend_corrected, trend_atmp_tide_offset_corrected],
                           title=title, names=['trend_corrected', 'trend_atmp_tide_offset_corrected'],
                           zero=True)
../_images/notebooks_baytap_demo_30_0.png