Source code for vtools.functions.separate_species

"""Separation of tidal data into species
The key function in this module is separate_species, which decomposes
tides into subtidal, diurnal, semidiurnal and noise components.

The fileters are long, so the time resolution of the amplitude may be limited.
A demo function is also provided that reads tide series (6min intervl)
from input files, seperates  the species, writes results and optionally plots
an example
"""

import argparse
from vtools.datastore.read_ts import read_ts
import datetime as dtm
from vtools.functions.filter import cosine_lanczos
from vtools.data.vtime import hours, minutes


[docs] def separate_species(ts, noise_thresh_min=40): """Separate species into subtidal, diurnal, semidiurnal and noise components Input: ts: timeseries to be decomposed into species, assumed to be at six minute intervals. The filters used have long lenghts, so avoid missing data and allow for four extra days worth of data on each end. Output: four regular time series, representing subtidal, diurnal, semi-diurnal and noise """ # the first filter eliminates noise ts_denoise = cosine_lanczos(ts, cutoff_period=minutes(noise_thresh_min)) ts_noise = ts - ts_denoise # this is the residual, the part that IS noise # the filter length assumes 6 minute data. The resulting filter is 90 hours # long which is MUCH longer than the default because this filter has to be # really sharp assert ts.index.freq == minutes(6) # 14.5 hours = 870min ts_diurnal_and_low = cosine_lanczos( ts_denoise, cutoff_period=minutes(870), filter_len=900 ) ts_semidiurnal_and_high = ts_denoise - ts_diurnal_and_low # The resulting filter is again 90 hours # long which is still a bit longer than the default. Again, # we want this filter to be pretty sharp. # ts_sub_tide=cosine_lanczos(ts_diurnal_and_low,cutoff_period=hours(40), # filter_len=900) ts_sub_tide = cosine_lanczos(ts_denoise, cutoff_period=hours(40), filter_len=900) ts_diurnal = ts_diurnal_and_low - ts_sub_tide return ts_sub_tide, ts_diurnal, ts_semidiurnal_and_high, ts_noise
[docs] def write_th(filename, ts_output): """This works fine for fairly big series""" fout = open(filename, "w") st = ts_output.ticks[0] for el in ts_output: tck = float(el.ticks - st) fout.write("%-12.1f %6.4f\n" % (tck, el.value)) fout.close()
[docs] def plot_result(ts, ts_semi, ts_diurnal, ts_sub_tide, station): import matplotlib.pyplot as plt fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True) ax1.plot(ts.times, ts.data, color="black", linewidth=1, label="Original data") ax1.legend(loc="lower right") # ,prop=legend_font) ax1.set_ylabel("Elev (m)") ax1.grid(b=True, which="both", color="0.9", linestyle="-", linewidth=0.5) ax2.plot( ts_semi.times, ts_semi.data, color="black", linewidth=1, label="Semidiurnal" ) ax2.legend(loc="lower right") ax2.set_ylabel("Elev (m)") ax2.grid(b=True, which="both", color="0.9", linestyle="-", linewidth=0.5) ax3.plot( ts_diurnal.times, ts_diurnal.data, color="black", linewidth=1, label="Diurnal" ) ax3.legend(loc="lower right") ax3.set_ylabel("Elev (m)") ax3.grid(b=True, which="both", color="0.9", linestyle="-", linewidth=0.5) ax4.plot( ts_sub_tide.times, ts_sub_tide.data, color="black", linewidth=1, label="Subtidal", ) ax4.legend(loc="lower right") ax4.set_ylabel("Elev (m)") ax4.grid(b=True, which="both", color="0.9", linestyle="-", linewidth=0.5) fig.tight_layout() fig.autofmt_xdate() plt.show() # plt.savefig('tidal_species_%s.png'%station,bbox_inches=0) plt.close(fig)
################# command line application #####################
[docs] def create_arg_parser(): import textwrap parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, epilog=textwrap.dedent( """ ============== Example ================== > separate_species.py --stime=2009-03-12 --etime=2010-01-01 --label="San Francisco" --outprefix=sf --plot 9414290_gageheight.csv """ ), description="""Script to filter a tide into its subtidal, diurnal and semidiurnal components (and residual noise""", ) parser.add_argument( "--stime", default=None, required=False, help="Start time in ISO-like format 2009-03-12T00:00:00. Time part and 'T' are optional.", ) parser.add_argument("--etime", default=None, required=False, help="End time.") parser.add_argument( "--plot", default=False, required=False, action="store_true", help="Plot time series in matplotlib", ) parser.add_argument( "--label", default="Tide", required=False, help="Label for station in plots" ) parser.add_argument( "--outprefix", default=None, help="Output file prefix (species name will be added). If omitted, the label will be used", ) parser.add_argument("infile", help="Input file.") return parser
[docs] def main(): parser = create_arg_parser() args = parser.parse_args() if args.stime: sdate = dtm.datetime( *list(map(int, re.split(r"[^\d]", args.stime))) ) # convert start time string input to datetime else: sdate = None if args.etime: edate = dtm.datetime( *list(map(int, re.split(r"[^\d]", args.etime))) ) # convert start time string input to datetime else: edate = None data_file = args.infile station_name = args.label outprefix = args.outprefix if not outprefix: outprefix = station_name.replace(" ", "_") do_plot = args.plot ts = read_ts(data_file, None, None) astart = max(ts.start, sdate - days(5)) if sdate else ts.start aend = min(ts.end, edate + days(5)) if edate else ts.end ts_sub, ts_diurnal, ts_semi, ts_noise = separate_species(ts.window(astart, aend)) comps = [ (ts_noise, "noise"), (ts_semi, "semi_over"), (ts_diurnal, "diurnal"), (ts_sub, "subtidal"), ] for comp in comps: ts_output = comp[0].window(sdate, edate) output_file = outprefix + "_" + comp[1] + ".th" write_th(output_file, ts_output) if do_plot: plot_result( ts.window(sdate, edate), ts_semi.window(sdate, edate), ts_diurnal.window(sdate, edate), ts_sub.window(sdate, edate), station_name, )
[docs] def run_example(): """This is the data for the example. Note that you want the data to be at least 4 days longer than the desired output """ start = dtm.datetime(2009, 2, 18) end = dtm.datetime(2010, 11, 24) out_st = dtm.datetime(2009, 3, 12) out_end = dtm.datetime(2010, 11, 2) sf_path = "../9415020_gageheight.csv" ts = read_ts(sf_path, start, end) print("separating reys...") separate_species(ts, "rey", out_st, out_end, do_plot=True) print("all done")
if __name__ == "__main__": main() # run_example()