1
1
from __future__ import annotations
2
+ from collections import deque
2
3
3
4
import logging
4
5
from copy import deepcopy
@@ -330,6 +331,8 @@ def follow_phase(
330
331
window_size : int | tuple [int , int ] = 50 ,
331
332
threshold : float = 5e-1 ,
332
333
max_shift : int = 20 ,
334
+ stack : bool = False ,
335
+ no_of_stacks : int = 5 ,
333
336
) -> tuple [np .ndarray , list [datetime ], np .ndarray ]:
334
337
"""Follow a phase pick through a Blast.
335
338
@@ -340,7 +343,7 @@ def follow_phase(
340
343
2. Calculate normalized cross correlate with downwards neighbor.
341
344
3. Evaluate maximum x-correlation in allowed window (max_shift).
342
345
4. Update template trace and go to 2.
343
-
346
+ 4a. if stack=True: stack templates for correlation to stabilize
344
347
5. Repeat for upward neighbors.
345
348
346
349
Args:
@@ -353,6 +356,12 @@ def follow_phase(
353
356
Defaults to 5e-1.
354
357
max_shift (int, optional): Maximum allowed shift in samples for
355
358
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.
356
365
357
366
Returns:
358
367
tuple[np.ndarray, list[datetime], np.ndarray]: Tuple of channel number,
@@ -375,12 +384,21 @@ def follow_phase(
375
384
def prepare_template (data : np .ndarray ) -> np .ndarray :
376
385
return data * template_taper
377
386
387
+ # def stack_n_straces(data: np.ndarray,stack_traces) -> np.ndarray:
388
+
389
+ # return stacked_data
390
+
378
391
def correlate (data : np .ndarray , direction : Literal [1 , - 1 ] = 1 ) -> None :
379
392
template = root_template .copy ()
380
- index = root_idx
393
+ template_deque = deque ([ np . array ( template )])
381
394
395
+ index = root_idx
382
396
for ichannel , trace in enumerate (data ):
383
397
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
+
384
402
norm = np .sqrt (np .sum (template ** 2 )) * np .sqrt (np .sum (trace ** 2 ))
385
403
correlation = np .correlate (trace , template , mode = "same" )
386
404
correlation = np .abs (correlation / norm )
@@ -395,7 +413,7 @@ def correlate(data: np.ndarray, direction: Literal[1, -1] = 1) -> None:
395
413
phase_correlation = correlation [phase_idx ]
396
414
phase_time = self ._sample_to_time (int (phase_idx ))
397
415
398
- if phase_correlation < threshold :
416
+ if phase_correlation > threshold :
399
417
continue
400
418
401
419
# Avoid the edges
@@ -409,14 +427,21 @@ def correlate(data: np.ndarray, direction: Literal[1, -1] = 1) -> None:
409
427
template = trace [
410
428
phase_idx - window_size [0 ] : phase_idx + window_size [1 ] + 1
411
429
].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
+
412
438
index = phase_idx
413
439
414
440
correlate (self .data [pick_channel :])
415
441
correlate (self .data [: pick_channel - 1 ][::- 1 ], direction = - 1 )
416
442
417
443
pick_channels = np .array (pick_channels ) + self .start_channel
418
444
pick_correlations = np .array (pick_correlations )
419
-
420
445
return pick_channels , pick_times , pick_correlations
421
446
422
447
def taper (self , alpha : float = 0.05 ) -> None :
0 commit comments