Master Thesis Code
by Simon Moser
Loading...
Searching...
No Matches
jumpCheckData.m
Go to the documentation of this file.
1% =========================================================================== %
2%> @brief checks data structure
3%>
4%> @details this function checks the data structure of the provided data
5%> structure and returns a boolean indicating if the data structure is valid.
6%> Also, if only small, obvious errors are found, the function tries to correct
7%> them.
8%>
9%> @param data - data structure to check
10%>
11%> @retval valid - boolean indicating if the data structure is valid
12%> @retval corrected - boolean indicating if the data structure was corrected
13%> @retval data - corrected data structure
14%>
15%> @details the data structure must be a struct containing the following fields:
16%> - tt: timetable containing the sensor data
17%> - t: datetime vector
18%> - acc: acceleration data (m/s^2), Nx3 matrix
19%> - gyr: angular velocity data (°/s), Nx3 matrix
20%> - hig: high G acceleration data (m/s^2), Nx3 matrix
21%> - mag: magnetometer data (uT), Nx3 matrix
22%> - prs: pressure data (mbar), Nx1 vector
23%> - tmp: temperature data (°C), Nx1 vector
24%> - t_start: start time of the data
25%> - ID: sensor ID (string)
26%> - UID: sensor UID (string)
27%> - name: sensor name (string)
28%> - sw_version: sensor software version (string)
29%> - hw_version: sensor hardware version (string)
30%> - acc_range: accelerometer range (in g) (double)
31%> - gyro_range: gyroscope range (in °/s) (double)
32%> - mpu_cal: mpu calibration (double)
33%> - act_thrs: activity threshold (double)
34%> - inact_dur: inactivity duration (double)
35%> - mpu_rate: mpu rate (double)
36%> - adxl_rate: adxl rate (double)
37%> - pres_rate: pressure rate (double)
38%> - magn_en: magnetometer enable (254: off, 255: on) (double)
39%> - sync: sync mode (0: idle, 1: slave, 2: master) (double)
40%> - ble_address: ble address (string)
41%>
42%> @file jumpCheckData.m
43%>
44%> @copyright see the file @ref LICENSE in the root directory of the repository
45% =========================================================================== %
46
47function [valid, corrected, data] = jumpCheckData(data)
48
49arguments
50 data (1,1) struct
51end
52
53% initialize output
54valid = true;
55corrected = false;
56error_msg = "The following errors were found in the data structure:" + newline;
57
58%% check if all fields are present
59
60% define fields
61fields = [ ...
62 "tt", ...
63 "t_start", ...
64 "ID", ...
65 "UID", ...
66 "name", ...
67 "sw_version", ...
68 "hw_version", ...
69 "acc_range", ...
70 "gyro_range", ...
71 "mpu_cal", ...
72 "act_thrs", ...
73 "inact_dur", ...
74 "mpu_rate", ...
75 "adxl_rate", ...
76 "pres_rate", ...
77 "magn_en", ...
78 "sync", ...
79 "ble_address" ...
80 ];
81
82% provided fields in the provided data
83provided_fields = string(fieldnames(data));
84
85% check for missing and additional fields
86missing_fields = setdiff(fields, provided_fields);
87additional_fields = setdiff(provided_fields, fields);
88
89% check if all fields are present
90if ~isempty(missing_fields)
91 valid = false;
92 error_msg = error_msg + "Missing fields: " + strjoin(missing_fields, ", ") + newline;
93end
94
95% check if additional fields are present
96if ~isempty(additional_fields)
97 valid = true;
98 for i = 1:numel(additional_fields)
99 % remove additional fields
100 data.(additional_fields(i)) = [];
101 end
102end
103
104%% check fields for correct data types
105
106% check tt
107if ~istimetable(data.tt)
108 valid = false;
109 error_msg = error_msg + "Field tt is not a timetable." + newline;
110end
111
112% check t_start
113if ~isdatetime(data.t_start)
114 valid = false;
115 error_msg = error_msg + "Field t_start is not a datetime." + newline;
116end
117
118% check Strings
119string_fields = ["ID", "UID", "name", "sw_version", "hw_version", "ble_address"];
120for i = 1:numel(string_fields)
121 if ~isstring(data.(string_fields(i)))
122 if ischar(data.(string_fields(i)))
123 data.(string_fields(i)) = string(data.(string_fields(i)));
124 corrected = true;
125 else
126 valid = false;
127 error_msg = error_msg + "Field " + string_fields(i) + " is not a string." + newline;
128 end
129 end
130end
131
132% check numeric fields
133numeric_fields = ["acc_range", "gyro_range", "mpu_cal", "act_thrs", "inact_dur", "mpu_rate", "adxl_rate", "pres_rate", "magn_en", "sync"];
134for i = 1:numel(numeric_fields)
135 if ~isnumeric(data.(numeric_fields(i)))
136 valid = false;
137 error_msg = error_msg + "Field " + numeric_fields(i) + " is not numeric." + newline;
138 end
139end
140
141%% check content of timetable
142
143% check if all variables are present
144variables = ["acc", "gyr", "hig", "mag", "prs", "tmp"];
145provided_variables = string(data.tt.Properties.VariableNames);
146missing_variables = setdiff(variables, data.tt.Properties.VariableNames);
147if ~isempty(missing_variables)
148 valid = false;
149 error_msg = error_msg + "Missing variables in timetable: " + strjoin(missing_variables, ", ") + newline;
150end
151
152% check units of variables
153units = ["m/s^2", "°/s", "m/s^2", "uT", "mbar", "°C"];
154provided_units = string(data.tt.Properties.VariableUnits);
155mising_units = setdiff(units, provided_units);
156
157if ~isempty(mising_units)
158 new_units = string(zeros(numel(mising_units), 1));
159 for i = 1:numel(variables)
160 this_var_idx = cell2mat(strfind(provided_variables, variables(i)));
161 new_units(i) = units(this_var_idx);
162 end
163 data.tt.Properties.VariableUnits = new_units;
164 corrected = true;
165end
166
167% check if is datetime
168if ~isdatetime(data.tt.t)
169 if isduration(data.tt.t)
170 data.tt.t = data.t_start + data.tt.t;
171 corrected = true;
172 else
173 valid = false;
174 error_msg = error_msg + "Time variable is not a datetime." + newline;
175 end
176end
177
178% check if t is the time variable
179if ~strcmp(data.tt.Properties.DimensionNames{1}, "t")
180 data.tt.Properties.DimensionNames{1} = "t";
181 corrected = true;
182end
183
184
185
186% check if the time format is correct
187if ~strcmp(data.tt.t.Format, "dd.MM.uuuu HH:mm:ss.SSS")
188 data.tt.t.Format = "dd.MM.uuuu HH:mm:ss.SSS";
189 corrected = true;
190end
191
192% check if first time is correct
193if ~isequal(data.tt.t(1), data.t_start)
194 data.t_start = data.tt.t(1);
195 corrected = true;
196end
197
198%% output
199if ~valid
200 error(error_msg);
201end
202
203end % function
function jumpCheckData(in data)