@@ -454,54 +454,58 @@ def extract_angle_extremes(
454
454
The extracted angle extremes (peaks)
455
455
"""
456
456
# determine peaks
457
- df [f'{ angle_colname } _maxima' ] = df .apply (
458
- lambda row : find_peaks (row [angle_colname ],
459
- distance = sampling_frequency * 0.6 / row [dominant_frequency_colname ],
460
- prominence = 2 )[0 ], axis = 1
461
- )
462
- df [f'{ angle_colname } _minima' ] = df .apply (
463
- lambda row : find_peaks ([- x for x in row [angle_colname ]],
464
- distance = sampling_frequency * 0.6 / row [dominant_frequency_colname ],
465
- prominence = 2 )[0 ], axis = 1
466
- )
457
+ df [f'{ angle_colname } _maxima' ] = df .apply (lambda x : signal .find_peaks (x [angle_colname ], distance = sampling_frequency * 0.6 / x [dominant_frequency_colname ], prominence = 0.5 )[0 ], axis = 1 )
458
+ df [f'{ angle_colname } _minima' ] = df .apply (lambda x : signal .find_peaks ([- x for x in x [angle_colname ]], distance = sampling_frequency * 0.6 / x [dominant_frequency_colname ], prominence = 0.5 )[0 ], axis = 1 )
467
459
468
460
df [f'{ angle_colname } _new_minima' ] = df [f'{ angle_colname } _minima' ].copy ()
469
461
df [f'{ angle_colname } _new_maxima' ] = df [f'{ angle_colname } _maxima' ].copy ()
470
462
471
- def refine_extrema (minima , maxima , angle_values ):
472
- """Refine the minima and maxima by removing consecutive points that don't adhere to the rules."""
473
- i_pks = 0
474
- while i_pks < len (minima ) - 1 and i_pks < len (maxima ):
475
- # Min-min or max-max sequences handling
476
- if minima [i_pks + 1 ] < maxima [i_pks ]:
477
- if angle_values [minima [i_pks + 1 ]] < angle_values [minima [i_pks ]]:
478
- minima = np .delete (minima , i_pks )
479
- else :
480
- minima = np .delete (minima , i_pks + 1 )
481
- i_pks -= 1
482
- elif maxima [i_pks ] < minima [i_pks ]:
483
- if angle_values [maxima [i_pks ]] < angle_values [maxima [i_pks - 1 ]]:
484
- maxima = np .delete (maxima , i_pks )
485
- else :
486
- maxima = np .delete (maxima , i_pks - 1 )
487
- i_pks -= 1
488
- i_pks += 1
489
- return minima , maxima
490
-
491
- # Apply refinement to each row
492
- for index , row in df .iterrows ():
493
- minima , maxima = refine_extrema (row [f'{ angle_colname } _new_minima' ], row [f'{ angle_colname } _new_maxima' ], row [angle_colname ])
494
- df .loc [index , f'{ angle_colname } _new_minima' ] = minima
495
- df .loc [index , f'{ angle_colname } _new_maxima' ] = maxima
496
-
497
- # Ensure scalar values are converted to lists
498
- df [f'{ angle_colname } _new_minima' ] = df [f'{ angle_colname } _new_minima' ].apply (lambda x : [x ] if isinstance (x , int ) else x )
499
- df [f'{ angle_colname } _new_maxima' ] = df [f'{ angle_colname } _new_maxima' ].apply (lambda x : [x ] if isinstance (x , int ) else x )
500
-
501
- # Combine and sort minima and maxima
502
- df [f'{ angle_colname } _extrema_values' ] = df .apply (
503
- lambda row : [row [angle_colname ][i ] for i in sorted (np .concatenate ([row [f'{ angle_colname } _new_minima' ], row [f'{ angle_colname } new_maxima' ]]))], axis = 1
504
- )
463
+ for index , _ in df .iterrows ():
464
+ i_pks = 0 # iterable to keep track of consecutive min-min and max-max versus min-max
465
+ n_min = df .loc [index , f'{ angle_colname } _new_minima' ].size # number of minima in window
466
+ n_max = df .loc [index , f'{ angle_colname } _new_maxima' ].size # number of maxima in window
467
+
468
+ if n_min > 0 and n_max > 0 :
469
+ if df .loc [index , f'{ angle_colname } _new_maxima' ][0 ] > df .loc [index , f'{ angle_colname } _new_minima' ][0 ]: # if first minimum occurs before first maximum, start with minimum
470
+ while i_pks < df .loc [index , f'{ angle_colname } _new_minima' ].size - 1 and i_pks < df .loc [index , f'{ angle_colname } _new_maxima' ].size : # only continue if there's enough minima and maxima to perform operations
471
+ if df .loc [index , f'{ angle_colname } _new_minima' ][i_pks + 1 ] < df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks ]: # if angle of next minimum comes before the current maxima, we have two minima in a row
472
+ if df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_minima' ][i_pks + 1 ]] < df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_minima' ][i_pks ]]: # if second minimum if smaller than first, keep second
473
+ df .at [index , f'{ angle_colname } _new_minima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_minima' ], i_pks )
474
+ else : # otherwise keep the first
475
+ df .at [index , f'{ angle_colname } _new_minima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_minima' ], i_pks + 1 )
476
+ i_pks -= 1
477
+ if i_pks >= 0 and df .loc [index , f'{ angle_colname } _new_minima' ][i_pks ] > df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks ]:
478
+ if df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks ]] < df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks - 1 ]]:
479
+ df .at [index , f'{ angle_colname } _new_maxima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_maxima' ], i_pks )
480
+ else :
481
+ df .at [index , f'{ angle_colname } _new_maxima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_maxima' ], i_pks - 1 )
482
+ i_pks -= 1
483
+ i_pks += 1
484
+
485
+ elif df .loc [index , f'{ angle_colname } _new_maxima' ][0 ] < df .loc [index , f'{ angle_colname } _new_minima' ][0 ]: # if the first maximum occurs before the first minimum, start with the maximum
486
+ while i_pks < df .loc [index , f'{ angle_colname } _new_minima' ].size and i_pks < df .loc [index , f'{ angle_colname } _new_maxima' ].size - 1 :
487
+ if df .loc [index , f'{ angle_colname } _new_minima' ][i_pks ] > df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks + 1 ]:
488
+ if df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks + 1 ]] > df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks ]]:
489
+ df .at [index , f'{ angle_colname } _new_maxima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_maxima' ], i_pks )
490
+ else :
491
+ df .at [index , f'{ angle_colname } _new_maxima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_maxima' ], i_pks + 1 )
492
+ i_pks -= 1
493
+ if i_pks > 0 and df .loc [index , f'{ angle_colname } _new_minima' ][i_pks ] < df .loc [index , f'{ angle_colname } _new_maxima' ][i_pks ]:
494
+ if df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_minima' ][i_pks ]] < df .loc [index , angle_colname ][df .loc [index , f'{ angle_colname } _new_minima' ][i_pks - 1 ]]:
495
+ df .at [index , f'{ angle_colname } _new_minima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_minima' ], i_pks - 1 )
496
+
497
+ else :
498
+ df .at [index , f'{ angle_colname } _new_minima' ] = np .delete (df .loc [index , f'{ angle_colname } _new_minima' ], i_pks )
499
+ i_pks -= 1
500
+ i_pks += 1
501
+
502
+ # for some peculiar reason, if a single item remains in the row for {angle_colname}_new_minima or
503
+ # angle_new_maxima, it could be either a scalar or a vector.
504
+ for col in [f'{ angle_colname } _new_minima' , f'{ angle_colname } _new_maxima' ]:
505
+ df .loc [df .apply (lambda x : type (x [col ].tolist ())== int , axis = 1 ), col ] = df .loc [df .apply (lambda x : type (x [col ].tolist ())== int , axis = 1 ), col ].apply (lambda x : [x ])
506
+
507
+ # extract amplitude
508
+ df [f'{ angle_colname } _extrema_values' ] = df .apply (lambda x : [x [angle_colname ][i ] for i in sorted (np .concatenate ([x [f'{ angle_colname } _new_minima' ], x [f'{ angle_colname } _new_maxima' ]]))], axis = 1 )
505
509
506
510
return df [f'{ angle_colname } _extrema_values' ]
507
511
0 commit comments