1% =========================================================================== %
2%> @brief checks data structure
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
9%> @param data - data structure to check
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
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)
44%> @copyright see the file @ref LICENSE in the root directory of the repository
45% =========================================================================== %
56error_msg = "The following errors were found in the data structure:" + newline;
58%% check if all fields are present
82% provided fields in the provided data
83provided_fields = string(fieldnames(data));
85% check for missing and additional fields
86missing_fields = setdiff(fields, provided_fields);
87additional_fields = setdiff(provided_fields, fields);
89% check if all fields are present
90if ~isempty(missing_fields)
92 error_msg = error_msg + "Missing fields: " + strjoin(missing_fields, ", ") + newline;
95% check if additional fields are present
96if ~isempty(additional_fields)
98 for i = 1:numel(additional_fields)
99 % remove additional fields
100 data.(additional_fields(i)) = [];
104%% check fields for correct data types
107if ~istimetable(data.tt)
109 error_msg = error_msg + "Field tt is not a timetable." + newline;
113if ~isdatetime(data.t_start)
115 error_msg = error_msg + "Field t_start is not a datetime." + newline;
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)));
127 error_msg = error_msg + "Field " + string_fields(i) + " is not a string." + newline;
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)))
137 error_msg = error_msg + "Field " + numeric_fields(i) + " is not numeric." + newline;
141%% check content of timetable
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)
149 error_msg = error_msg + "Missing variables in timetable: " + strjoin(missing_variables, ", ") + newline;
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);
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);
163 data.tt.Properties.VariableUnits = new_units;
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;
174 error_msg = error_msg + "Time variable is not a datetime." + newline;
178% check if t is the time variable
179if ~strcmp(data.tt.Properties.DimensionNames{1}, "t")
180 data.tt.Properties.DimensionNames{1} =
"t";
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";
192% check if first time is correct
193if ~isequal(data.tt.t(1), data.t_start)
194 data.t_start = data.tt.t(1);
function jumpCheckData(in data)