2525from eqcorrscan .core .match_filter .template import Template
2626from eqcorrscan .utils .plotting import plot_repicked
2727
28+ show_interp_deprec_warning = True
2829
2930Logger = logging .getLogger (__name__ )
3031
@@ -43,14 +44,19 @@ def __str__(self):
4344 return 'LagCalcError: ' + self .value
4445
4546
46- def _xcorr_interp (ccc , dt ):
47+ def _xcorr_interp (ccc , dt , resample_factor = 10 , use_new_resamp_method = False ,
48+ ** kwargs ):
4749 """
48- Interpolate around the maximum correlation value for sub-sample precision.
50+ Resample correlation-trace and check if there is a better CCC peak for
51+ sub-sample precision.
4952
5053 :param ccc: Cross-correlation array
5154 :type ccc: numpy.ndarray
5255 :param dt: sample interval
5356 :type dt: float
57+ :param resample_factor:
58+ Factor for upsampling CC-values (only for use_new_resamp_method=True)
59+ :type resample_factor: int
5460
5561 :return: Position of interpolated maximum in seconds from start of ccc
5662 :rtype: float
@@ -59,6 +65,32 @@ def _xcorr_interp(ccc, dt):
5965 cc = ccc [0 ]
6066 else :
6167 cc = ccc
68+
69+ # New method with resampling - make this the default in a future version
70+ if use_new_resamp_method :
71+ cc_resampled = scipy .signal .resample (cc , len (cc ) * resample_factor + 1 )
72+ dt_resampled = dt / resample_factor
73+ cc_t = np .arange (0 , len (cc_resampled ) * dt_resampled , dt_resampled )
74+ peak_index = cc_resampled .argmax ()
75+ cc_peak = max (cc_resampled )
76+
77+ shift = cc_t [peak_index ]
78+ if (cc_peak < np .amax (cc ) or cc_peak > 1.0 or
79+ not 0 < shift < len (ccc ) * dt ):
80+ # Sometimes the interpolation returns a worse result.
81+ Logger .warning ("Interpolation did not give an accurate result, "
82+ "returning maximum in data" )
83+ return np .argmax (ccc ) * dt , np .amax (ccc )
84+ return shift , cc_peak
85+
86+ # Otherwise use old interpolation method, but warn with deprcation message
87+ # (but show it only once):
88+ global show_interp_deprec_warning
89+ if show_interp_deprec_warning :
90+ Logger .warning (
91+ 'This method for interpolating cross-correlations is deprecated, '
92+ 'use a more robust method with use_new_resamp_method=True' )
93+ show_interp_deprec_warning = False
6294 # Code borrowed from obspy.signal.cross_correlation.xcorr_pick_correction
6395 cc_curvature = np .concatenate ((np .zeros (1 ), np .diff (cc , 2 ), np .zeros (1 )))
6496 cc_t = np .arange (0 , len (cc ) * dt , dt )
@@ -191,7 +223,8 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4,
191223 min_cc_from_mean_cc_factor = None ,
192224 horizontal_chans = ['E' , 'N' , '1' , '2' ],
193225 vertical_chans = ['Z' ], cores = 1 , interpolate = False ,
194- plot = False , plotdir = None , export_cc = False , cc_dir = None ):
226+ plot = False , plotdir = None , export_cc = False , cc_dir = None ,
227+ ** kwargs ):
195228 """
196229 Compute cross-correlation picks for detections in a family.
197230
@@ -273,8 +306,9 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4,
273306 checksum , cccsum , used_chans = 0.0 , 0.0 , 0
274307 event = Event ()
275308 if min_cc_from_mean_cc_factor is not None :
276- cc_thresh = min (detection .detect_val / detection .no_chans
277- * min_cc_from_mean_cc_factor , min_cc )
309+ cc_thresh = min (abs (detection .detect_val / detection .no_chans
310+ * min_cc_from_mean_cc_factor ),
311+ min_cc )
278312 Logger .info ('Setting minimum cc-threshold for detection %s to %s' ,
279313 detection .id , str (cc_thresh ))
280314 else :
@@ -285,7 +319,7 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4,
285319 tr = detect_stream .select (
286320 station = stachan .channel [0 ], channel = stachan .channel [1 ])[0 ]
287321 if interpolate :
288- shift , cc_max = _xcorr_interp (correlation , dt = delta )
322+ shift , cc_max = _xcorr_interp (correlation , dt = delta , ** kwargs )
289323 else :
290324 cc_max = np .amax (correlation )
291325 shift = np .argmax (correlation ) * delta
@@ -387,7 +421,7 @@ def _prepare_data(family, detect_data, shift_len):
387421 length = round (length_samples ) / family .template .samp_rate
388422 Logger .info ("Setting length to {0}s to give an integer number of "
389423 "samples" .format (length ))
390- prepick = shift_len
424+ prepick = shift_len + family . template . prepick
391425 detect_streams_dict = family .extract_streams (
392426 stream = detect_data , length = length , prepick = prepick )
393427 for key , detect_stream in detect_streams_dict .items ():
@@ -419,7 +453,7 @@ def lag_calc(detections, detect_data, template_names, templates,
419453 shift_len = 0.2 , min_cc = 0.4 , min_cc_from_mean_cc_factor = None ,
420454 horizontal_chans = ['E' , 'N' , '1' , '2' ],
421455 vertical_chans = ['Z' ], cores = 1 , interpolate = False ,
422- plot = False , plotdir = None , export_cc = False , cc_dir = None ):
456+ plot = False , plotdir = None , export_cc = False , cc_dir = None , ** kwargs ):
423457 """
424458 Cross-correlation derived picking of seismic events.
425459
@@ -557,7 +591,7 @@ def lag_calc(detections, detect_data, template_names, templates,
557591 detections = template_detections ,
558592 template = Template (
559593 name = template_name , st = template ,
560- samp_rate = template [0 ].stats .sampling_rate ))
594+ samp_rate = template [0 ].stats .sampling_rate , prepick = 0.0 ))
561595 # Make a sparse template
562596 if len (template_detections ) > 0 :
563597 template_dict = xcorr_pick_family (
@@ -566,7 +600,7 @@ def lag_calc(detections, detect_data, template_names, templates,
566600 horizontal_chans = horizontal_chans ,
567601 vertical_chans = vertical_chans , interpolate = interpolate ,
568602 cores = cores , shift_len = shift_len , plot = plot , plotdir = plotdir ,
569- export_cc = export_cc , cc_dir = cc_dir )
603+ export_cc = export_cc , cc_dir = cc_dir , ** kwargs )
570604 initial_cat .update (template_dict )
571605 # Order the catalogue to match the input
572606 output_cat = Catalog ()
0 commit comments