Master Thesis Code
by Simon Moser
Loading...
Searching...
No Matches
exp_SonEMS_3.m
Go to the documentation of this file.
1% =========================================================================== %
2%> @brief final analysis script for the SonEMS data
3%>
4%> this script filters the data of the feet and compares certain gait
5%> parameters with the VICON data. the data is from the SonEMS experiments.
6%>
7%> @file exp_SonEMS_3.m
8%>
9%> @note this script is written to use the parallel processing toolbox. it
10%> works only with the "Processes" pool. The script is very memory intensive,
11%> therefore the number of workers should be set accordingly.
12%>
13%> @copyright see the file @ref LICENSE in the root directory of the repository
14% =========================================================================== %
15
16clear;
17close all;
18clc;
19
20pause(2); % give the system some time to close the figures
21
22%%> TASKS TO DO
23%> here the tasks that need to be done again can be marked. if a task is not done
24%> yet OR is marked as true, it will be executed. if a task is marked as false,
25%> it will be skipped (if it has be done before).
26
27%% base folder, participant list and ekf tuning parameters
28basepath = "D:/ETH_Data/";
29info_sheet = readtable(fullfile(basepath, "participant_info.xlsx"), ...
30 FileType = "spreadsheet", ...
31 TextType = "string", ...
32 DatetimeType = "datetime", ...
33 VariableNamingRule = "modify", ...
34 ReadVariableNames = true, ...
35 Range = "A1:I38");
36
37% get the participants
38current_run = "Test"; % "Tuning" or "Test"
39ptps = unique(info_sheet.ID(info_sheet.(current_run) == 1));
40
41% ekf tuning parameters file
42if strcmp(current_run, "Test")
43 tuning_files = "C:\Users\moss\Code\MT_moss_IMU_sensor_fusion\experiments\ekf_tuning.json"; % Test
44elseif strcmp(current_run, "Tuning")
45 tuning_files = dir(fullfile(basepath, "Tuning", "Trial_14", "*.json"));
46 tuning_files = string(fullfile({tuning_files.folder}, {tuning_files.name}))';
47 tuning_files = "C:\Users\moss\Code\MT_moss_IMU_sensor_fusion\experiments\ekf_tuning.json"; % Test
48else
49 error("Unknown Dataset.")
50end
51
52% log file
53diary(fullfile(basepath, "exp_SonEMS_3.log"))
54fprintf("\n\nThis is the beginning of a new log file.\n\nThe column headers are:\n")
55fprintf("Time; Log Level; Participant; Message\n\n")
56
57log_entry("Start processing SonEMS data")
58log_entry("Running " + current_run + " set", 0, 4)
59
60% Select the processes pool to use (not the thread pool)
61num_workers = 16; % change this value, if you want to use more or less workers
62num_workers = min(num_workers, numel(ptps)); % limit the number of workers to the number of participants
63currentPool = gcp("nocreate");
64if ~isempty(currentPool)
65 if ~strcmp(class(currentPool), "parallel.ProcessPool")
66 delete(currentPool);
67 parpool("Processes", num_workers);
68 log_entry("Changed the pool to Processes", 0, 5)
69 elseif currentPool.NumWorkers ~= num_workers
70 delete(currentPool);
71 parpool("Processes", num_workers);
72 log_entry("Changed the pool to Processes with " + num_workers + " workers", 0, 5)
73 else
74 log_entry("Using the existing pool of Processes", 0, 5)
75 end
76else
77 parpool("Processes", num_workers);
78 log_entry("Created a new pool of Processes", 0, 5)
79end
80
81% define a vartiabel to store the time of the last log entry of the RAM usage
82ram_last_logged = datetime(1970, 1, 1); % preinitialize to a long time ago
83
84% loop over the tuning files
85wb = waitbar(0, "Processing participants", "Name", "Processing participants");
86
87% allocate the grid search results table
88grid_search_results = table('Size', [numel(tuning_files), 20], ...
89 'VariableTypes', ["string", "datetime", repmat("double", 1, 18)], ...
90 'VariableNames', [...
91 "TuningFile", ...
92 "time", ...
93 "StrideLengthMu", ...
94 "StrideLengthDiffMu", ...
95 "StepLengthMu", ...
96 "StepLengthDiffMu", ...
97 "StepWidthMu", ...
98 "StepWidthDiffMu", ...
99 "StrideLengthStd", ...
100 "StrideLengthDiffStd", ...
101 "StepLengthStd", ...
102 "StepLengthDiffStd", ...
103 "StepWidthStd", ...
104 "StepWidthDiffStd", ...
105 "StrideLengthMSE", ...
106 "StrideLengthDiffMSE", ...
107 "StepLengthMSE", ...
108 "StepLengthDiffMSE", ...
109 "StepWidthMSE", ...
110 "StepWidthDiffMSE"
111 ]);
112
113for i_tf = 1:numel(tuning_files)
114
115 % get the tuning file
116 tuning_file = tuning_files(i_tf);
117
118 % save the tuning file
119 grid_search_results.TuningFile(i_tf) = tuning_file;
120
121 if numel(tuning_files) > 1
122 log_entry("Start processing with tuning file " + tuning_file, 0, 4)
123 end
124
125 % preallocate the futures
126 f_filter(1:numel(ptps)) = parallel.FevalFuture;
127 f_gait_parameters(1:numel(ptps)) = parallel.FevalFuture;
128
129 % queue all participants for filter processing
130 for ptp = 1:numel(ptps)
131
132 f_filter(ptp) = parfeval(...
133 @process_participant, ... % function to execute
134 0, ... % number of output arguments
135 basepath, ...
136 ptps(ptp), ...
137 ekf_tuning_file = tuning_file, ...
138 GT_POS = false, ...
139 FIND_WALKING_AXES = false, ...
140 FIND_WALKING_SPEED = false, ...
141 ACCUMULATE_DIST = false, ...
142 ALIGN_IMU_VICON = false, ...
143 FIND_YAW = true, ...
144 FILTER = true);
145
146 log_entry("Participant " + ptps(ptp) + " queued")
147
148 end
149
150 % wait for all futures to finish, show intermediate results in waitbar
151 filter_finished = false;
152 error_occured = 0;
153 while ~filter_finished
154 finished = sum(string({f_filter.State}) == "finished");
155 queued = sum(string({f_filter.State}) == "queued");
156 running = sum(string({f_filter.State}) == "running");
157 failed = sum(string({f_filter.State}) == "failed") + error_occured;
158
159 waitbar(finished / numel(f_filter), wb, sprintf("Filtering (%i/%i) ...\nFinished: %d, Queued: %d, Running: %d, Failed: %d", i_tf, numel(tuning_files), finished, queued, running, failed))
160
161 if finished + failed >= numel(f_filter)
162 filter_finished = true;
163 end
164
165 % log RAM usage every 1 minute
166 if seconds(datetime("now") - ram_last_logged) > 60
167 [~, curr_ram] = memory;
168
169 log_entry(sprintf("RAM: %.1f GB of %.1f GB remaining.", curr_ram.PhysicalMemory.Available / 1e9, curr_ram.PhysicalMemory.Total / 1e9), 0, 5)
170
171 ram_last_logged = datetime("now");
172 end
173
174 pause(1)
175
176 % check the state of the futures
177 for ptp = 1:numel(f_filter)
178
179 % check if future is already read
180 if f_filter(ptp).Read == 1
181 continue
182 end
183
184 % check for errors
185 if ~isempty(f_filter(ptp).Error)
186
187 % get the SonEMS String
188 err_ptp = f_filter(ptp).InputArguments{2};
189
190 % stop the future
191 f_filter(ptp).cancel
192
193 % log the error
194 log_entry("Unhandled error in participant " + err_ptp, 0, 1)
195 log_entry(f_filter(ptp).Error.message, 0, 2)
196 log_entry("Stack trace:", 0, 2)
197 for i = 1:numel(f_filter(ptp).Error.stack)
198 log_entry(f_filter(ptp).Error.stack(i).name + " (Line: " + string(f_filter(ptp).Error.stack(i).line) + ")", 0, 2)
199 end
200
201 % read the future (this will throw an exeption but will mark it as read)
202 try
203 fetchOutputs(f_filter(ptp));
204 catch
205 % do nothing
206 end
207
208 error_occured = error_occured + 1;
209
210 continue
211 end
212
213 % check if the future is finished
214 if strcmp(f_filter(ptp).State, "finished")
215
216 % read the future (this can throw an exeption but will mark it as read)
217 try
218 fetchOutputs(f_filter(ptp));
219 catch
220 % do nothing
221 end
222
223 % log the finished participant
224 log_entry("Participant " + ptps(ptp) + " finished with filter processing", 0, 4)
225
226 % start the future for the gait parameters
227 f_gait_parameters(ptp) = parfeval(...
228 @calculate_gait_parameters, ... % function to execute
229 0, ... % number of output arguments
230 basepath, ...
231 ptps(ptp), ...
232 RECALCULATE = true, ...
233 create_plots = true);
234
235 % log the queued participant
236 log_entry("Participant " + ptps(ptp) + " queued for gait parameter calculation", 0, 4)
237
238 end
239 end
240 end
241
242 log_entry("All participants processed (filtered)")
243
244 % wait for all gait parameters to finish, show intermediate results in waitbar
245 gait_parameters_finished = false;
246 while ~gait_parameters_finished
247 finished = sum(string({f_gait_parameters.State}) == "finished");
248 queued = sum(string({f_gait_parameters.State}) == "queued");
249 running = sum(string({f_gait_parameters.State}) == "running");
250 failed = sum(string({f_gait_parameters.State}) == "failed");
251 unavailable = sum(string({f_gait_parameters.State}) == "unavailable");
252
253 waitbar(finished / numel(f_filter), wb, sprintf("Gait Parameters (%i/%i) ...\nFinished: %d, Queued: %d, Running: %d, Failed: %d", i_tf, numel(tuning_files), finished, queued, running, failed))
254
255 if finished + failed + unavailable >= numel(f_gait_parameters)
256 gait_parameters_finished = true;
257 end
258
259 pause(1)
260
261 % check the state of the futures
262 for ptp = 1:numel(f_gait_parameters)
263
264 % check if future is already read
265 if f_gait_parameters(ptp).Read == 1
266 continue
267 end
268
269 % check if the future is finished
270 if strcmp(f_gait_parameters(ptp).State, "finished")
271
272 % read the future (this can throw an exeption but will mark it as read)
273 try
274 fetchOutputs(f_gait_parameters(ptp));
275 catch
276 % do nothing
277 end
278
279 % log the finished participant
280 log_entry("Participant " + ptps(ptp) + " finished with gait parameter calculation")
281
282 end
283
284 % check for errors
285 if ~isempty(f_gait_parameters(ptp).Error)
286
287 % get the SonEMS String
288 err_ptp = f_gait_parameters(ptp).InputArguments{2};
289
290 % stop the future
291 f_gait_parameters(ptp).cancel
292
293 % log the error
294 log_entry("Unhandled eror in participant " + err_ptp, 0, 1)
295 log_entry(f_gait_parameters(ptp).Error.message, 0, 2)
296 log_entry("Stack trace:", 0, 2)
297 for i = 1:numel(f_gait_parameters(ptp).Error.stack)
298 log_entry(f_gait_parameters(ptp).Error.stack(i).name + " (Line: " + string(f_gait_parameters(ptp).Error.stack(i).line) + ")", 0, 2)
299 end
300
301 % read the future (this will throw an exeption but will mark it as read)
302 try
303 fetchOutputs(f_gait_parameters(ptp));
304 catch
305 % do nothing
306 end
307 end
308
309 end
310
311 end
312
313 %% create a summary of the gait parameters
314 log_entry("Start creating gait parameter summary")
315 results = create_gait_parameter_summary(basepath, ptps, tuning_file, current_run);
316
317 % save the results
318 grid_search_results.time(i_tf) = datetime("now");
319 grid_search_results.StrideLengthMu(i_tf) = results.mu_stride;
320 grid_search_results.StepLengthMu(i_tf) = results.mu_step;
321 grid_search_results.StepWidthMu(i_tf) = results.mu_width;
322 grid_search_results.StrideLengthDiffMu(i_tf) = results.mu_stride_d;
323 grid_search_results.StepLengthDiffMu(i_tf) = results.mu_step_d;
324 grid_search_results.StepWidthDiffMu(i_tf) = results.mu_width_d;
325 grid_search_results.StrideLengthStd(i_tf) = results.std_stride;
326 grid_search_results.StepLengthStd(i_tf) = results.std_step;
327 grid_search_results.StepWidthStd(i_tf) = results.std_width;
328 grid_search_results.StrideLengthDiffStd(i_tf) = results.std_stride_d;
329 grid_search_results.StepLengthDiffStd(i_tf) = results.std_step_d;
330 grid_search_results.StepWidthDiffStd(i_tf) = results.std_width_d;
331 grid_search_results.StrideLengthMSE(i_tf) = results.mse_stride;
332 grid_search_results.StepLengthMSE(i_tf) = results.mse_step;
333 grid_search_results.StepWidthMSE(i_tf) = results.mse_width;
334 grid_search_results.StrideLengthDiffMSE(i_tf) = results.mse_stride_d;
335 grid_search_results.StepLengthDiffMSE(i_tf) = results.mse_step_d;
336 grid_search_results.StepWidthDiffMSE(i_tf) = results.mse_width_d;
337
338 if current_run == "Tuning"
339 save(fullfile(basepath, "Tuning", "grid_search_results.mat"), "grid_search_results");
340 copyfile(fullfile(basepath, "Tuning", "grid_search_results.mat"), fullfile(basepath, "Tuning", string(datetime("now", "Format", "yy-MM-dd_HH-mm-ss")) + "_grid_search_results.mat"));
341 end
342
343 % log the end of the processing
344 log_entry("All participants processed (gait parameters calculated)")
345
346end
347
348% close the waitbar
349close(wb)