11from __future__ import annotations
2+ from collections import deque
23
34import logging
45from copy import deepcopy
@@ -330,7 +331,8 @@ def follow_phase(
330331 window_size : int | tuple [int , int ] = 50 ,
331332 threshold : float = 5e-1 ,
332333 max_shift : int = 20 ,
333- stack_traces : int = 1 ,
334+ stack : bool = False ,
335+ no_of_stacks : int = 5 ,
334336 ) -> tuple [np .ndarray , list [datetime ], np .ndarray ]:
335337 """Follow a phase pick through a Blast.
336338
@@ -341,7 +343,7 @@ def follow_phase(
341343 2. Calculate normalized cross correlate with downwards neighbor.
342344 3. Evaluate maximum x-correlation in allowed window (max_shift).
343345 4. Update template trace and go to 2.
344-
346+ 4a. if stack=True: stack templates for correlation to stabilize
345347 5. Repeat for upward neighbors.
346348
347349 Args:
@@ -354,6 +356,12 @@ def follow_phase(
354356 Defaults to 5e-1.
355357 max_shift (int, optional): Maximum allowed shift in samples for
356358 neighboring picks. Defaults to 20.
359+ stack (bool): If True - (a default number of 5) templates will be stacked and used
360+ as correlation template. Stacking close to the initial template is limited to
361+ the distance to the initial tamplate. I.e. the correlation of a trace 3 traces
362+ next to the initial template will only use a stacked template of 3 traces
363+ (initial trace an trace 1 and 2 next to it), altough the no_of_stacks is set higher.
364+ no_of_stacks (int): Numbers of traces to stack to define the template.
357365
358366 Returns:
359367 tuple[np.ndarray, list[datetime], np.ndarray]: Tuple of channel number,
@@ -382,10 +390,15 @@ def prepare_template(data: np.ndarray) -> np.ndarray:
382390
383391 def correlate (data : np .ndarray , direction : Literal [1 , - 1 ] = 1 ) -> None :
384392 template = root_template .copy ()
385- index = root_idx
393+ template_deque = deque ([ np . array ( template )])
386394
395+ index = root_idx
387396 for ichannel , trace in enumerate (data ):
388397 template = prepare_template (template )
398+ # check if stacking is activated
399+ if stack and len (template_deque ) > 2 :
400+ template = prepare_template (template_stack )
401+
389402 norm = np .sqrt (np .sum (template ** 2 )) * np .sqrt (np .sum (trace ** 2 ))
390403 correlation = np .correlate (trace , template , mode = "same" )
391404 correlation = np .abs (correlation / norm )
@@ -400,7 +413,7 @@ def correlate(data: np.ndarray, direction: Literal[1, -1] = 1) -> None:
400413 phase_correlation = correlation [phase_idx ]
401414 phase_time = self ._sample_to_time (int (phase_idx ))
402415
403- if phase_correlation < threshold :
416+ if phase_correlation > threshold :
404417 continue
405418
406419 # Avoid the edges
@@ -414,15 +427,21 @@ def correlate(data: np.ndarray, direction: Literal[1, -1] = 1) -> None:
414427 template = trace [
415428 phase_idx - window_size [0 ] : phase_idx + window_size [1 ] + 1
416429 ].copy ()
430+
431+ # stacking
432+ if len (template_deque ) <= no_of_stacks :
433+ template_deque .append (template )
434+ if len (template_deque ) == no_of_stacks + 1 :
435+ template_deque .popleft ()
436+ template_stack = np .sum (template_deque , axis = 0 ) / len (template_deque )
437+
417438 index = phase_idx
418439
419440 correlate (self .data [pick_channel :])
420441 correlate (self .data [: pick_channel - 1 ][::- 1 ], direction = - 1 )
421442
422443 pick_channels = np .array (pick_channels ) + self .start_channel
423444 pick_correlations = np .array (pick_correlations )
424- print ("aa" )
425-
426445 return pick_channels , pick_times , pick_correlations
427446
428447 def taper (self , alpha : float = 0.05 ) -> None :
0 commit comments