26
26
27
27
28
28
class ImpulseDetector :
29
- def __init__ (self , min_separation , max_duration , band , threshold = 150 , dt = None ):
29
+ def __init__ (self , min_separation , max_duration , detection_band , analysis_band , threshold = 150 , dt = None ):
30
30
"""
31
31
Impulse events detector
32
32
@@ -36,6 +36,10 @@ def __init__(self, min_separation, max_duration, band, threshold=150, dt=None):
36
36
Minimum separation of the event, in seconds
37
37
max_duration : float
38
38
Maxium duration of the event, in seconds
39
+ detection_band : list
40
+ List or tuple of (min_freq, max_freq) of the frequency band used to detect the signals
41
+ analysis_band : list
42
+ List or tuple of (min_freq, max_freq) of the frequency band used to characterize the impulses
39
43
threshold : float
40
44
Threshold above ref value which one it is considered piling, in db
41
45
dt : float
@@ -46,7 +50,8 @@ def __init__(self, min_separation, max_duration, band, threshold=150, dt=None):
46
50
self .max_duration = max_duration
47
51
self .threshold = threshold
48
52
self .dt = dt
49
- self .band = band
53
+ self .detection_band = detection_band
54
+ self .analysis_band = analysis_band
50
55
51
56
def detect_events (self , signal , method = 'dt' , verbose = False , save_path = None ):
52
57
"""
@@ -89,7 +94,7 @@ def detect_events_dt(self, signal, verbose=False, save_path=None):
89
94
save_path : string or Path
90
95
Where to save the image. Set to None if it should not be saved
91
96
"""
92
- signal .set_band (self .band )
97
+ signal .set_band (self .detection_band )
93
98
levels = []
94
99
blocksize = int (self .dt * signal .fs )
95
100
for block in signal .Blocks (blocksize = blocksize ):
@@ -116,10 +121,8 @@ def detect_events_envelope(self, signal, verbose=False, save_path=None):
116
121
save_path : string or Path
117
122
Where to save the image. Set to None if it should not be saved
118
123
"""
119
- signal .set_band (band = self .band )
124
+ signal .set_band (band = self .detection_band )
120
125
envelope = signal .envelope ()
121
- envelope = utils .to_db (envelope , ref = 1.0 , square = True )
122
-
123
126
times_events = events_times_diff (signal = envelope , fs = signal .fs , threshold = self .threshold ,
124
127
max_duration = self .max_duration ,
125
128
min_separation = self .min_separation )
@@ -144,12 +147,12 @@ def detect_events_snr(self, signal, verbose=False, save_path=None):
144
147
Where to save the image. Set to None if it should not be saved
145
148
"""
146
149
blocksize = int (self .dt * signal .fs )
147
- signal .set_band (band = self .band )
150
+ signal .set_band (band = self .detection_band )
148
151
envelope = signal .envelope ()
149
- envelope = utils .to_db (envelope , ref = 1.0 , square = True )
150
152
times_events = events_times_snr (signal = envelope , blocksize = blocksize , fs = signal .fs ,
151
153
threshold = self .threshold , max_duration = self .max_duration ,
152
- min_separation = self .min_separation )
154
+ min_separation = self .min_separation , original_sig = signal .signal )
155
+
153
156
events_df = self .load_all_times_events (times_events , signal , verbose = verbose )
154
157
155
158
if verbose :
@@ -183,10 +186,11 @@ def load_event(self, s, t, duration, removenoise=True, verbose=False):
183
186
n2 = min (int ((t + duration + self .min_separation ) * s .fs ), s .signal .shape [0 ])
184
187
event = Event (s .signal [n1 :n2 ], s .fs )
185
188
noise_clip = np .concatenate ((s .signal [n1 :start_n ], s .signal [end_n :n2 ]))
186
- event .reduce_noise (noise_clip = noise_clip , nfft = 512 , verbose = verbose )
189
+ event .reduce_noise (noise_clip = noise_clip , nfft = 512 , verbose = False )
187
190
event .signal = event .signal [start_n - n1 :end_n - n1 ]
188
191
else :
189
192
event = Event (s .signal [start_n :end_n ], s .fs )
193
+
190
194
return event
191
195
192
196
def load_all_times_events (self , times_events , signal , verbose = False ):
@@ -202,10 +206,10 @@ def load_all_times_events(self, times_events, signal, verbose=False):
202
206
verbose : bool
203
207
Set to True to plot all the events of the signal
204
208
"""
205
- signal .set_band ([ 10 , 20000 ] )
209
+ signal .set_band (self . analysis_band )
206
210
columns_temp = ['start_seconds' , 'end_seconds' , 'duration' , 'rms' , 'sel' , 'peak' ]
207
211
columns_df = pd .DataFrame ({'variable' : 'temporal' , 'value' : columns_temp })
208
- freq = sci .fft .rfftfreq (128 ) * 40000
212
+ freq = sci .fft .rfftfreq (128 ) * signal . fs
209
213
columns_df = pd .concat ([columns_df , pd .DataFrame ({'variable' : 'psd' , 'value' : freq })])
210
214
columns = pd .MultiIndex .from_frame (columns_df )
211
215
events_df = pd .DataFrame (columns = columns )
@@ -231,7 +235,7 @@ def plot_all_events(self, signal, events_df, save_path=None):
231
235
save_path : string or Path
232
236
Where to save the image. Set to None if it should not be saved
233
237
"""
234
- signal .set_band (band = self .band )
238
+ signal .set_band (band = self .detection_band )
235
239
fbands , t , sxx = signal .spectrogram (nfft = 512 , scaling = 'spectrum' , db = True , mode = 'fast' )
236
240
fig , ax = plt .subplots (3 , 1 , sharex = 'col' )
237
241
im = ax [0 ].pcolormesh (t , fbands , sxx , shading = 'auto' )
@@ -275,9 +279,13 @@ def plot_all_events(self, signal, events_df, save_path=None):
275
279
276
280
277
281
class PilingDetector (ImpulseDetector ):
278
- def __init__ (self , min_separation , max_duration , threshold , dt ):
282
+ def __init__ (self , min_separation , max_duration , threshold , dt , detection_band = None , analysis_band = None ):
283
+ if detection_band is None :
284
+ detection_band = [500 , 1000 ]
285
+ if analysis_band is None :
286
+ analysis_band = [100 , 20000 ]
279
287
super ().__init__ (min_separation = min_separation , max_duration = max_duration ,
280
- band = [ 5000 , 10000 ] , threshold = threshold , dt = dt )
288
+ detection_band = detection_band , analysis_band = analysis_band , threshold = threshold , dt = dt )
281
289
282
290
283
291
@nb .jit
@@ -304,21 +312,30 @@ def events_times_diff(signal, fs, threshold, max_duration, min_separation):
304
312
event_max_val = 0
305
313
last_xi = 0
306
314
i = 0
315
+ threshold_upa = 10 ** (threshold / 20.0 )
307
316
while i < len (signal ):
308
317
xi = signal [i ]
318
+
309
319
if event_on :
310
320
duration = (i - event_start ) / fs
311
- if duration >= max_duration or xi < (event_max_val - threshold ) :
312
- # Event finished, too long! Or event detected!
321
+ if duration >= max_duration or (event_max_val - xi ) >= threshold_upa :
322
+ # Event finished, too long! Or event end detected
313
323
event_on = False
314
324
event_end = i
315
325
times_events .append ([event_start / fs , duration , event_end / fs ])
316
326
i += min_separation_samples
317
327
event_max_val = 0
328
+ # plt.Figure()
329
+ # plt.plot(signal[event_start - min_separation_samples:event_end + min_separation_samples])
330
+ # plt.axvline(min_separation_samples, color='green', label='Start')
331
+ # plt.axvline(min_separation_samples + event_end - event_start, color='red', label='End')
332
+ # plt.show()
333
+ # plt.close()
318
334
elif xi > event_max_val :
319
335
event_max_val = xi
320
336
else :
321
- if i != 0 and (xi - last_xi ) >= threshold :
337
+ if i != 0 and (xi - last_xi ) >= threshold_upa :
338
+ # There is a big jump, start event!
322
339
event_on = True
323
340
event_start = i
324
341
event_max_val = xi
@@ -328,31 +345,47 @@ def events_times_diff(signal, fs, threshold, max_duration, min_separation):
328
345
329
346
330
347
@nb .jit
331
- def events_times_snr (signal , fs , blocksize , threshold , max_duration , min_separation ):
348
+ def events_times_snr (signal , fs , blocksize , threshold , max_duration , min_separation , original_sig ):
332
349
times_events = []
333
350
min_separation_samples = int (min_separation * fs )
334
351
event_on = False
335
352
event_start = 0
336
353
event_end = 0
337
354
j = 0
355
+ threshold_upa = 10 ** (threshold / 20.0 )
338
356
while j < len (signal ):
339
357
if j + blocksize > len (signal ):
340
358
blocksize = len (signal ) - j
341
- noise = np .mean (signal [j :j + blocksize ])
359
+ noise = np .sqrt (np .mean (signal [j :j + blocksize ]** 2 ))
360
+ max_value = noise
342
361
for i in np .arange (blocksize - 1 ) + j :
343
362
xi = signal [i ]
344
- snr = xi - noise
345
363
if event_on :
346
364
duration = (i - event_start ) / fs
347
- if duration >= max_duration or snr < threshold :
365
+ if duration >= max_duration or ( xi - noise ) < 10 ** ( 6.0 / 20.0 ) :
348
366
# Event finished, too long! Or event detected!
349
367
event_on = False
350
368
event_end = i
351
369
times_events .append ([event_start / fs , duration , event_end / fs ])
370
+ # plt.Figure()
371
+ # plt.plot(original_sig[event_start-min_separation_samples:event_end+min_separation_samples],
372
+ # label='Signal')
373
+ # plt.plot(signal[event_start-min_separation_samples:event_end+min_separation_samples],
374
+ # label='Envelope')
375
+ # plt.axhline(noise + threshold_upa, label='Threshold')
376
+ # plt.axhline(noise + threshold_upa/2.0, label='Threshold')
377
+ # plt.axvline(min_separation_samples, color='green', label='Start')
378
+ # plt.axvline(min_separation_samples+event_end-event_start, color='red', label='End')
379
+ # plt.show()
380
+ # plt.close()
381
+ if xi > max_value :
382
+ max_value = xi
352
383
else :
353
- if snr >= threshold :
384
+ if ( xi - noise ) >= threshold_upa :
354
385
if len (times_events ) == 0 or (i - event_end ) >= min_separation_samples :
355
386
event_on = True
356
387
event_start = i
388
+ max_value = xi
357
389
j += blocksize
390
+
358
391
return times_events
0 commit comments