Source code for stompy.tidal_datum

"""
Functions to take a time series of waterlevels and compute
tidal datums
"""

import numpy as np

# constants
TM2=12.4200*60 # M2 period in minutes. 12h25.2m 745.2 minutes
TLM=29.53059*24*60 # Lunar month in minutes 29d12h44m
T57M2=TM2*57 # 28.5 lunar days, 57 M2 periods, in minutes

[docs]def find_mllw(timeseries): """ Find MLLW from a month long tidal record timeseries: [N,2] array, [:,0] datenums, [:,1] water level samples Translated from Vitalii Sheremet's matlab code sh_tidemllw.m Only consumes the integer multiples of a lunar month of data """ return find_tidal_datum(timeseries,stat='min',daily=True)
[docs]def find_mlw(timeseries): return find_tidal_datum(timeseries,stat='min',daily=False)
[docs]def find_mhw(timeseries): return find_tidal_datum(timeseries,stat='max',daily=False)
[docs]def find_mhhw(timeseries): return find_tidal_datum(timeseries,stat='max',daily=True)
[docs]def find_tidal_datum(timeseries,stat,daily=False): """ generic workings for tidal extrema datums stat: 'min' or 'max' """ t = timeseries[:,0] h = timeseries[:,1] # median seems safer than mode with floating point data dt=np.median(np.diff(t)*24*60) # time step of the record in minutes nm2=TM2/dt # fractional samples per TM2 h1=h-h.mean() # height anomaly i0 = np.nonzero( h1[:-1]*h1[1:] < 0)[0][0] # first zero crossing Nmonths = int( (t[-1] - t[i0])*24*60 / T57M2 ) # Low Water find minimum in each TM2 segment jm=np.zeros(57*Nmonths,np.int32) # indices to low water within each M2 period for k in range(57*Nmonths): i1=int(i0+np.round(k * nm2)) # index of kth m2 i2=int(i0+np.round((k+1) * nm2)) if stat is 'min': jm[k] = i1 + np.argmin( h[i1:i2] ) elif stat is 'max': jm[k] = i1 + np.argmax( h[i1:i2] ) else: raise Exception("Stat %s not understodd"%stat) h_agg = h[jm] # h extrema aggregated per M2 period if not daily: return h_agg.mean() else: # [RH]: why compute the pairs two different ways? # This is a departure from V.S. code, and maybe # a departure from the 'correct' way - have to go # back to MLLW documentation... if len(h_agg)%2: h_agg = h_agg[:-1] # trim to even number of M2 periods h_agg_by_day = h_agg.reshape( (-1,2) ) if stat is 'min': daily_agg = h_agg_by_day.min(axis=1) else: daily_agg = h_agg_by_day.max(axis=1) return daily_agg.mean()