@@ -631,47 +631,31 @@ def __init__(
631631 self .conv_margin = prototype .shape [0 ]
632632
633633 assert peak_sign in ("both" , "neg" , "pos" )
634- idx = np . argmax ( np . abs ( prototype ) )
634+ self . nbefore = int ( ms_before * recording . sampling_frequency / 1000 )
635635 if peak_sign == "neg" :
636- assert prototype [idx ] < 0 , "Prototype should have a negative peak"
636+ assert prototype [self . nbefore ] < 0 , "Prototype should have a negative peak"
637637 peak_sign = "pos"
638638 elif peak_sign == "pos" :
639- assert prototype [idx ] > 0 , "Prototype should have a positive peak"
640- elif peak_sign == "both" :
641- raise NotImplementedError ("Matched filtering not working with peak_sign=both yet!" )
639+ assert prototype [self .nbefore ] > 0 , "Prototype should have a positive peak"
642640
643641 self .peak_sign = peak_sign
644- self .nbefore = int (ms_before * recording .sampling_frequency / 1000 )
642+ self .prototype = np .flip (prototype ) / np .linalg .norm (prototype )
643+
645644 contact_locations = recording .get_channel_locations ()
646645 dist = np .linalg .norm (contact_locations [:, np .newaxis ] - contact_locations [np .newaxis , :], axis = 2 )
647- weights , self .z_factors = get_convolution_weights (dist , ** weight_method )
646+ self .weights , self .z_factors = get_convolution_weights (dist , ** weight_method )
647+ self .num_z_factors = len (self .z_factors )
648+ self .num_channels = recording .get_num_channels ()
649+ self .num_templates = self .num_channels
650+ if peak_sign == "both" :
651+ self .weights = np .hstack ((self .weights , self .weights ))
652+ self .weights [:, self .num_templates :, :] *= - 1
653+ self .num_templates *= 2
648654
649- num_channels = recording .get_num_channels ()
650- num_templates = num_channels * len (self .z_factors )
651- weights = weights .reshape (num_templates , - 1 )
652-
653- templates = weights [:, None , :] * prototype [None , :, None ]
654- templates -= templates .mean (axis = (1 , 2 ))[:, None , None ]
655- temporal , singular , spatial = np .linalg .svd (templates , full_matrices = False )
656- temporal = temporal [:, :, :rank ]
657- singular = singular [:, :rank ]
658- spatial = spatial [:, :rank , :]
659- templates = np .matmul (temporal * singular [:, np .newaxis , :], spatial )
660- norms = np .linalg .norm (templates , axis = (1 , 2 ))
661- del templates
662-
663- temporal /= norms [:, np .newaxis , np .newaxis ]
664- temporal = np .flip (temporal , axis = 1 )
665- spatial = np .moveaxis (spatial , [0 , 1 , 2 ], [1 , 0 , 2 ])
666- temporal = np .moveaxis (temporal , [0 , 1 , 2 ], [1 , 2 , 0 ])
667- singular = singular .T [:, :, np .newaxis ]
668-
669- self .temporal = temporal
670- self .spatial = spatial
671- self .singular = singular
655+ self .weights = self .weights .reshape (self .num_templates * self .num_z_factors , - 1 )
672656
673657 random_data = get_random_data_chunks (recording , return_scaled = False , ** random_chunk_kwargs )
674- conv_random_data = self .get_convolved_traces (random_data , temporal , spatial , singular )
658+ conv_random_data = self .get_convolved_traces (random_data )
675659 medians = np .median (conv_random_data , axis = 1 )
676660 medians = medians [:, None ]
677661 noise_levels = np .median (np .abs (conv_random_data - medians ), axis = 1 ) / 0.6744897501960817
@@ -688,16 +672,13 @@ def get_trace_margin(self):
688672 def compute (self , traces , start_frame , end_frame , segment_index , max_margin ):
689673
690674 assert HAVE_NUMBA , "You need to install numba"
691- conv_traces = self .get_convolved_traces (traces , self . temporal , self . spatial , self . singular )
675+ conv_traces = self .get_convolved_traces (traces )
692676 conv_traces /= self .abs_thresholds [:, None ]
693677 conv_traces = conv_traces [:, self .conv_margin : - self .conv_margin ]
694678 traces_center = conv_traces [:, self .exclude_sweep_size : - self .exclude_sweep_size ]
695679
696- num_z_factors = len (self .z_factors )
697- num_templates = traces .shape [1 ]
698-
699- traces_center = traces_center .reshape (num_z_factors , num_templates , traces_center .shape [1 ])
700- conv_traces = conv_traces .reshape (num_z_factors , num_templates , conv_traces .shape [1 ])
680+ traces_center = traces_center .reshape (self .num_z_factors , self .num_templates , traces_center .shape [1 ])
681+ conv_traces = conv_traces .reshape (self .num_z_factors , self .num_templates , conv_traces .shape [1 ])
701682 peak_mask = traces_center > 1
702683
703684 peak_mask = _numba_detect_peak_matched_filtering (
@@ -708,11 +689,13 @@ def compute(self, traces, start_frame, end_frame, segment_index, max_margin):
708689 self .abs_thresholds ,
709690 self .peak_sign ,
710691 self .neighbours_mask ,
711- num_templates ,
692+ self . num_channels ,
712693 )
713694
714695 # Find peaks and correct for time shift
715696 z_ind , peak_chan_ind , peak_sample_ind = np .nonzero (peak_mask )
697+ if self .peak_sign == "both" :
698+ peak_chan_ind = peak_chan_ind % self .num_channels
716699
717700 # If we want to estimate z
718701 # peak_chan_ind = peak_chan_ind % num_channels
@@ -739,16 +722,11 @@ def compute(self, traces, start_frame, end_frame, segment_index, max_margin):
739722 # return is always a tuple
740723 return (local_peaks ,)
741724
742- def get_convolved_traces (self , traces , temporal , spatial , singular ):
725+ def get_convolved_traces (self , traces ):
743726 import scipy .signal
744727
745- num_timesteps , num_templates = len (traces ), temporal .shape [1 ]
746- num_peaks = num_timesteps - self .conv_margin + 1
747- scalar_products = np .zeros ((num_templates , num_peaks ), dtype = np .float32 )
748- spatially_filtered_data = np .matmul (spatial , traces .T [np .newaxis , :, :])
749- scaled_filtered_data = spatially_filtered_data * singular
750- objective_by_rank = scipy .signal .oaconvolve (scaled_filtered_data , temporal , axes = 2 , mode = "valid" )
751- scalar_products += np .sum (objective_by_rank , axis = 0 )
728+ tmp = scipy .signal .oaconvolve (self .prototype [None , :], traces .T , axes = 1 , mode = "valid" )
729+ scalar_products = np .dot (self .weights , tmp )
752730 return scalar_products
753731
754732
@@ -873,37 +851,28 @@ def _numba_detect_peak_neg(
873851
874852 @numba .jit (nopython = True , parallel = False )
875853 def _numba_detect_peak_matched_filtering (
876- traces , traces_center , peak_mask , exclude_sweep_size , abs_thresholds , peak_sign , neighbours_mask , num_templates
854+ traces , traces_center , peak_mask , exclude_sweep_size , abs_thresholds , peak_sign , neighbours_mask , num_channels
877855 ):
878856 num_z = traces_center .shape [0 ]
857+ num_templates = traces_center .shape [1 ]
879858 for template_ind in range (num_templates ):
880859 for z in range (num_z ):
881860 for s in range (peak_mask .shape [2 ]):
882861 if not peak_mask [z , template_ind , s ]:
883862 continue
884863 for neighbour in range (num_templates ):
885- if not neighbours_mask [template_ind , neighbour ]:
886- continue
887864 for j in range (num_z ):
865+ if not neighbours_mask [template_ind % num_channels , neighbour % num_channels ]:
866+ continue
888867 for i in range (exclude_sweep_size ):
889- if template_ind >= neighbour :
890- if z >= j :
891- peak_mask [z , template_ind , s ] &= (
892- traces_center [z , template_ind , s ] >= traces_center [j , neighbour , s ]
893- )
894- else :
895- peak_mask [z , template_ind , s ] &= (
896- traces_center [z , template_ind , s ] > traces_center [j , neighbour , s ]
897- )
898- elif template_ind < neighbour :
899- if z > j :
900- peak_mask [z , template_ind , s ] &= (
901- traces_center [z , template_ind , s ] > traces_center [j , neighbour , s ]
902- )
903- else :
904- peak_mask [z , template_ind , s ] &= (
905- traces_center [z , template_ind , s ] > traces_center [j , neighbour , s ]
906- )
868+ if template_ind >= neighbour and z >= j :
869+ peak_mask [z , template_ind , s ] &= (
870+ traces_center [z , template_ind , s ] >= traces_center [j , neighbour , s ]
871+ )
872+ else :
873+ peak_mask [z , template_ind , s ] &= (
874+ traces_center [z , template_ind , s ] > traces_center [j , neighbour , s ]
875+ )
907876 peak_mask [z , template_ind , s ] &= (
908877 traces_center [z , template_ind , s ] > traces [j , neighbour , s + i ]
909878 )
0 commit comments