From 2db6fde7090fd987fc7b9fd6e89d068f0460631e Mon Sep 17 00:00:00 2001 From: Darius Arnold <Darius.Arnold@ruhr-uni-bochum.de> Date: Sat, 26 Aug 2017 02:12:31 +0200 Subject: [PATCH] [add] check second maximum of HOS/AR-CF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the second maximum if it is larger than first maximum * minfactor. This helps when two onsets are close together (eg. S and SKS at 90°) and the second onset is stronger. --- pylot/core/io/default_parameters.py | 28 ++++++++++++++++++++++++++-- pylot/core/pick/autopick.py | 20 +++++++++++++------- pylot/core/pick/picker.py | 14 ++++++++++---- pylot/core/pick/utils.py | 24 ++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/pylot/core/io/default_parameters.py b/pylot/core/io/default_parameters.py index 945e0497..f0150112 100644 --- a/pylot/core/io/default_parameters.py +++ b/pylot/core/io/default_parameters.py @@ -273,6 +273,26 @@ defaults = {'rootpath': {'type': str, 'value': 1.5, 'namestring': 'Noise factor S'}, + 'checkwindowP': {'type': float, + 'tooltip': 'time window before HOS/AR-maximum to check for smaller maxima [s]', + 'value': 10.0, + 'namestring': 'Check Window P'}, + + 'minfactorP': {'type': float, + 'tooltip': 'Second maximum must be at least minfactor * first maximum [-]', + 'value': 0.7, + 'namestring': 'Minimum Factor P'}, + + 'checkwindowS': {'type': float, + 'tooltip': 'time window before AR-maximum to check for smaller maxima [s]', + 'value': 10.0, + 'namestring': 'Check Window S'}, + + 'minfactorS': {'type': float, + 'tooltip': 'Second maximum must be at least minfactor * first maximum [-]', + 'value': 0.7, + 'namestring': 'Minimum Factor S'}, + 'minfmweight': {'type': int, 'tooltip': 'minimum required P weight for first-motion determination', 'value': 1, @@ -450,7 +470,9 @@ settings_special_pick = { 'aictsmooth', 'tsmoothP', 'ausP', - 'nfacP'], + 'nfacP', + 'checkwindowP', + 'minfactorP'], 'h': [ 'algoS', 'tdet1h', @@ -464,7 +486,9 @@ settings_special_pick = { 'aictsmoothS', 'tsmoothS', 'ausS', - 'nfacS'], + 'nfacS', + 'checkwindowS', + 'minfactorS'], 'fm': [ 'minfmweight', 'minFMSNR', diff --git a/pylot/core/pick/autopick.py b/pylot/core/pick/autopick.py index 0b60f4f7..4d39075d 100644 --- a/pylot/core/pick/autopick.py +++ b/pylot/core/pick/autopick.py @@ -175,6 +175,10 @@ def autopickstation(wfstream, pickparam, verbose=False, # parameter to check for spuriously picked S onset zfac = pickparam.get('zfac') # path to inventory-, dataless- or resp-files + checkwindowP = pickparam.get('checkwindowP') + minfactorP = pickparam.get('minfactorP') + checkwindowS = pickparam.get('checkwindowS') + minfactorS = pickparam.get('minfactorS') # initialize output Pweight = 4 # weight for P onset @@ -322,7 +326,8 @@ def autopickstation(wfstream, pickparam, verbose=False, fig = fig_dict[key] else: fig = None - aicpick = AICPicker(aiccf, tsnrz, pickwinP, iplot, None, tsmoothP, fig=fig) + aicpick = AICPicker(aiccf, tsnrz, pickwinP, checkwindow=checkwindowP, minfactor=minfactorP, + iplot=iplot, Tsmooth=tsmoothP, fig=fig) # add pstart and pstop to aic plot if fig: for ax in fig.axes: @@ -442,8 +447,8 @@ def autopickstation(wfstream, pickparam, verbose=False, fig = fig_dict['refPpick'] else: fig = None - refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot, ausP, tsmoothP, - aicpick.getpick(), fig) + refPpick = PragPicker(cf2, tsnrz, pickwinP, iplot=iplot, aus=ausP, Tsmooth=tsmoothP, + Pick1 = aicpick.getpick(), fig=fig) mpickP = refPpick.getpick() ############################################################# if mpickP is not None: @@ -624,8 +629,9 @@ def autopickstation(wfstream, pickparam, verbose=False, fig = fig_dict['aicARHfig'] else: fig = None - aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, iplot, None, - aictsmoothS, fig=fig) + aicarhpick = AICPicker(haiccf, tsnrh, pickwinS, checkwindow=checkwindowS, + minfactor=minfactorS, iplot=iplot, Tsmooth=aictsmoothS, + fig=fig) ############################################################### # go on with processing if AIC onset passes quality control slope = aicarhpick.getSlope() @@ -686,8 +692,8 @@ def autopickstation(wfstream, pickparam, verbose=False, fig = fig_dict['refSpick'] else: fig = None - refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot, ausS, - tsmoothS, aicarhpick.getpick(), fig) + refSpick = PragPicker(arhcf2, tsnrh, pickwinS, iplot=iplot, aus=ausS, + Tsmooth=tsmoothS, Pick1=aicarhpick.getpick(), fig=fig) mpickS = refSpick.getpick() ############################################################# if mpickS is not None: diff --git a/pylot/core/pick/picker.py b/pylot/core/pick/picker.py index 1715746c..59bbf143 100644 --- a/pylot/core/pick/picker.py +++ b/pylot/core/pick/picker.py @@ -24,7 +24,7 @@ import warnings import matplotlib.pyplot as plt import numpy as np from pylot.core.pick.charfuns import CharacteristicFunction -from pylot.core.pick.utils import getnoisewin, getsignalwin +from pylot.core.pick.utils import getnoisewin, getsignalwin, get_maximum_index class AutoPicker(object): @@ -35,7 +35,7 @@ class AutoPicker(object): warnings.simplefilter('ignore') - def __init__(self, cf, TSNR, PickWindow, iplot=0, aus=None, Tsmooth=None, Pick1=None, fig=None): + def __init__(self, cf, TSNR, PickWindow, checkwindow=None, minfactor=None, iplot=0, aus=None, Tsmooth=None, Pick1=None, fig=None): ''' :param: cf, characteristic function, on which the picking algorithm is applied :type: `~pylot.core.pick.CharFuns.CharacteristicFunction` object @@ -74,6 +74,8 @@ class AutoPicker(object): self.setTsmooth(Tsmooth) self.setpick1(Pick1) self.fig = fig + self.setCheckWindow(checkwindow) + self.minfactor = minfactor self.calcPick() def __str__(self): @@ -89,6 +91,10 @@ class AutoPicker(object): aus=self.getaus(), Tsmooth=self.getTsmooth(), Pick1=self.getpick1()) + def setCheckWindow(self, checkwindow): + '''convert checkwindow to samples''' + if checkwindow: + self.checkwindow = int(checkwindow / self.Data[0].stats.delta) def getTSNR(self): return self.TSNR @@ -187,8 +193,8 @@ class AICPicker(AutoPicker): offset = abs(min(aic) - min(aicsmooth)) aicsmooth = aicsmooth - offset # get maximum of HOS/AR-CF as startimg point for searching - # minimum in AIC function - icfmax = np.argmax(self.Data[0].data) + # minimum in AIC function + icfmax = get_maximum_index(self.Data[0].data, self.checkwindow, self.minfactor) # find minimum in AIC-CF front of maximum of HOS/AR-CF lpickwindow = int(round(self.PickWindow / self.dt)) diff --git a/pylot/core/pick/utils.py b/pylot/core/pick/utils.py index 0dce76fd..33c3bbd5 100644 --- a/pylot/core/pick/utils.py +++ b/pylot/core/pick/utils.py @@ -13,6 +13,7 @@ import warnings import matplotlib.pyplot as plt import numpy as np from obspy.core import Stream, UTCDateTime +from scipy.signal import argrelextrema def earllatepicker(X, nfac, TSNR, Pick1, iplot=0, verbosity=1, fig=None): @@ -1171,6 +1172,29 @@ def removePicksAbove(pickDic, minWeight): newdic[eventKey][station].update({phasename: phaseinfo}) return newdic + +def get_maximum_index(data, checkwindow, minfactor): + '''get maximum of CF as starting point, then check for highest local maximum + in front of it. + return second maximum if its larger than first maximum * minfactor, else + return first maximum''' + icfmax1 = np.argmax(data) + imax_local = argrelextrema(data[icfmax1 - checkwindow:icfmax1], np.greater) # indices of local maxima + if (len(imax_local[0]) > 0): + imax_local = imax_local[0] + icfmax1 - checkwindow + local_maxima = (imax_local, data[imax_local]) + icfmax2 = local_maxima[0][np.where(local_maxima[1] == max(local_maxima[1]))][0] + if data[icfmax2] > data[icfmax1] * minfactor: + print("Found valid local maximum in front of first maximum") + return icfmax2 + else: + print("First maximum is the largest: {}>{}".format(data[icfmax1], + data[icfmax2])) + return icfmax1 + else: + print("No local maxima found in check window") + return icfmax1 + if __name__ == '__main__': import doctest