@@ -92,36 +92,165 @@ def load_c3d_trial(
92
92
return trial
93
93
94
94
95
+ def get_event_detector (
96
+ method_hs : str ,
97
+ method_to : str ,
98
+ configs : mapping .MappingConfigs ,
99
+ offset : float = 0 ,
100
+ trial_ref = None ,
101
+ ) -> events .EventDetector :
102
+ """Builds an EventDetector object whose method is the same for all event types
103
+
104
+ Args:
105
+ method_hs: event detection method for heel strike
106
+ method_to: event detection method for toe off
107
+ - "Zen" will test the Zeni method
108
+ - "Des" will test the Desailly method
109
+ - "AC1" to "AC6" will test the Autocorrelation 1 to 6 methods
110
+ config: The mapping configurations
111
+ offset: offset to be applied to all event timings, default is 0
112
+ trial_ref: object of model.Trial, reference trial if the event detection requires a reference
113
+
114
+ Returns:
115
+ EventDetector object
116
+ """
117
+ if trial_ref is None :
118
+ return events .EventDetectorBuilder .get_event_detector_no_ref (
119
+ configs , method_hs , method_to , offset
120
+ )
121
+ else :
122
+ return events .EventDetectorBuilder .get_event_detector_with_ref (
123
+ configs , method_hs , method_to , trial_ref , offset
124
+ )
125
+
126
+
127
+ def get_GRF_event_detector (
128
+ configs : mapping .MappingConfigs , offset : float = 0
129
+ ) -> events .EventDetector :
130
+ """Builds an EventDetector object whose method is the same for all event types
131
+
132
+ Args:
133
+ config: The mapping configurations
134
+ offset: offset to be applied to all event timings, default is 0
135
+
136
+ Returns:
137
+ EventDetector object
138
+ """
139
+ return events .EventDetectorBuilder .get_event_detector_no_ref (
140
+ configs , "GRF" , "GRF" , offset
141
+ )
142
+
143
+
144
+ def get_mixed_event_detector (
145
+ method_hs_l : str ,
146
+ method_hs_r : str ,
147
+ method_to_l : str ,
148
+ method_to_r : str ,
149
+ configs : mapping .MappingConfigs ,
150
+ offset : float = 0 ,
151
+ trial = None ,
152
+ ) -> events .EventDetector :
153
+ """Builds an EventDetector object whose method is the same for all event type
154
+
155
+ Args:
156
+ method_to_l: event detection method for left toe off
157
+ method_to_r: event detection method for right toe off
158
+ method_hs_l: event detection method for left heel strike
159
+ method_hs_r: event detection method for right heel strike
160
+ - "Zen" will test the Zeni method
161
+ - "Des" will test the Desailly method
162
+ - "AC1" to "AC6" will test the Autocorrelation 1 to 6 methods
163
+ config: The mapping configurations
164
+ offset: offset to be applied to all event timings, default is 0
165
+ trial_ref: object of model.Trial, reference trial if the event detection requires a reference
166
+
167
+ Returns:
168
+ EventDetector object
169
+ """
170
+ return events .EventDetectorBuilder .get_mixed_event_detector (
171
+ configs , method_hs_l , method_hs_r , method_to_l , method_to_r , offset , trial
172
+ )
173
+
174
+
95
175
def detect_events (
96
176
trial : model .Trial ,
97
- config : mapping .MappingConfigs ,
98
- method : type [events .BaseEventDetection ] = events .MarkerEventDetection ,
99
- ** kwargs ,
177
+ event_detector : events .EventDetector ,
178
+ parameters : dict | None = None ,
100
179
) -> pd .DataFrame :
101
180
"""Detects the events in the trial.
102
181
103
182
Args:
104
183
trial: The trial to detect the events for.
105
- config: The mapping configurations
106
- method: The class to use for detecting the events.
107
- Currently, only "Marker" is supported, which implements
108
- the method from Zenis et al. 2008.
109
- Default is "Marker".
110
- **kwargs:
111
- - height: The height of peaks. Default = None
112
- - threshold: The threshold of peaks. Default = None
113
- - distance: The min distance in frames between events. Default = None
114
- - rel_height: The relative height of peak. Default = 0.5
184
+ event_detector: object containing detection methods (optimized or not) for each event type
185
+ parameters: dictionary of event detection parameters. Default None
115
186
116
187
Returns:
117
188
A DataFrame containing the detected events.
189
+ """
190
+ event_table = event_detector .detect_events (trial , parameters )
191
+ return event_table
118
192
193
+
194
+ def find_optimal_detectors (
195
+ trial_ref : model .Trial ,
196
+ config : mapping .MappingConfigs ,
197
+ method_list : list [str ] = ["Zen" , "Des" , "AC1" , "AC2" , "AC3" , "AC4" , "AC5" , "AC6" ],
198
+ ) -> tuple [events .EventDetector , dict ]:
199
+ """Finds the set of best methods that best detect all Gait Event types on a short labeled reference trial
200
+ Also returns feedback for user
201
+
202
+ Args:
203
+ trial_ref: The reference trial with some labeled gait events
204
+ config: The mapping configurations
205
+ method_list: list of methods it tests for
206
+ - "Zen" will test the Zeni method
207
+ - "Des" will test the Desailly method
208
+ - "AC1" to "AC6" will test the Autocorrelation 1 to 6 methods
209
+ Returns:
210
+ An EventDetector object with optimized detection methods for each gait event
211
+ user_show : dict containing the performance of all selected methods, as well as the parameters used to find the events
119
212
"""
213
+ method_list_mapping = [
214
+ events .EventDetectorBuilder .get_method (name ) for name in method_list
215
+ ]
216
+ auto_obj = events .AutoEventDetection (config , trial_ref , method_list_mapping )
217
+ event_detector , user_show = auto_obj .get_optimised_event_detectors ()
218
+ return event_detector , user_show
120
219
121
- method_obj = method (config , ** kwargs )
122
220
123
- event_table = method_obj .detect_events (trial )
124
- return event_table
221
+ def get_ref_from_GRF (
222
+ trial : model .Trial , config : mapping .MappingConfigs , gait_cycles_ref : int = 15
223
+ ) -> model .Trial :
224
+ """Creates a reference set of events detected with Ground Reaction Forces (if available) for the given trial.
225
+ The detected events meet the following set of conditions:
226
+ 1. Events are regularly spaced (not too close and not too far apart)
227
+ 2. Detected events should have a GRF value close to 0
228
+ 3. Event should be followed/preceded by a large slope
229
+ 4. Order of events is correct
230
+ If the required number of events is not found, an error is raised¨
231
+
232
+ Args:
233
+ trial: The trial whose events to be detected and used as reference
234
+ config: The mapping configurations
235
+ gait_cycles_ref: number of gait cycles to use as reference. Default is 15
236
+
237
+ Returns:
238
+ Trial: the same trial with detected events as attributes
239
+
240
+ Raises:
241
+ ValueError if no events have been selected to use as reference
242
+ """
243
+ event_detector = get_GRF_event_detector (config )
244
+ events_table = detect_events (trial , event_detector )
245
+
246
+ obj = events .ReferenceFromGrf (events_table , trial , config , gait_cycles_ref )
247
+ trial_ref = obj .get_reference ()
248
+ if trial_ref .events is not None and not trial_ref .events .empty :
249
+ return trial_ref
250
+ else :
251
+ raise ValueError (
252
+ "No valid events detected with GRF. Try manually labeling events to use as reference"
253
+ )
125
254
126
255
127
256
def check_events (event_table : pd .DataFrame , method : str = "sequence" ):
0 commit comments