SGLOGENGMERGE Merge data from combined Seaglider log and eng data sets into a single data set. Syntax: [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG) [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPTIONS) [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPT1, VAL1, ...) Description: [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG) merges the data sets described by metadata structs META_LOG and META_ENG, and data arrays or structs DATA_LOG and DATA_ENG into a single data set described by metadata struct META and data array or struct DATA (see format option described below). Input metadata and data should be in the format returned by the functions SGLOGCAT and SGENGCAT. Log data referenced to the dive start time (GC, STATE and SM_CCo fields) is merged with eng data. See note on merging. META is a struct array combining the information in META_LOG and META_ENG. It has the following fields: LOGHEADERS: struct array of log headers. These are the log data headers in META_LOG. Entries corresponding to unmatched eng headers have all fields empty. ENGHEADERS: struct array of eng headers. These are the eng data headers from META_ENG. Entries corresponding to unmatched log headers have all fields empty. START_SECS: number with the reference time for timestamped data lines. This is the minimum of the START_SECS field in META_LOGG and META_ENG: start time of first dive as seconds since 1970 Janyuay 01 00:00:00 UTC. COLUMNS: string cell array with the names of the columns in output data. This are the column names in META_ENG. See note on data merging. PARAMS: struct with the names of the fields of non-scalar parameters. This is the PARAMS field in META_LOG. GCHEAD: string cell array with the names of the fields for the GC lines. This is the GCHEAD field in META_LOG. DEVICES: string cell array with the names of the fields for device lines. This is the DEVICES field in META_LOG. SENSORS: string cell array with the names of the fields for sensor lines. This is the SENSORS field in META_LIST. SOURCES: string cell array with the name of the source files. This is the concatenation the SOURCES field in META_LOG and META_ENG. [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPTIONS) and [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPT1, VAL1, ...) accept the following options given in key-value pairs OPT1, VAL1... or in a struct OPTIONS with field names as option keys and field values as option values: FORMAT: data output format. String setting the format of the output DATA. Valid values are: 'array': DATA is a struct with the following fields: LOG: array with log parameters in the column order specified by PARAMS metadata field. ENG: array or cell array with the eng columns and GC and SM_CCo log parameter columns in the column order specified by COLUMNS metadata field. GPSFIX: array or cell array with the GPS log columns in the order specified by the GPSFIX metadata field. See note on array format. 'merged': DATA is a struct with a column vector field for each parameter in log or gps data, and for each column in eng data. 'struct': DATA is a struct with a column vector field for each column in eng data and gps data, and for each scalar parameter in log data; and with a struct field for each non-scalar parameter in log data. Default value: 'array' PARAMS: log parameter filtering list. String cell array with the names of the log parameters of interest. If given, only parameters present in both the input data sets and this list will be present in output. For non-scalar parameters, the name of the identifier as it appears in the log line specifies including all of its fields. Individual parameter fields are selected with the identifier and the name of the field separated by underscore (e.g. 'FINISH_dens'). The string 'all' may also be given, in which case parameter filtering is not performed and all parameters in input list will be present in output. Default value: 'all' (do not perform log parameter filtering). COLUMNS: eng column filtering list. String cell array with the names of the eng data columns of interest. If given, only columns present in both the input data sets and this list will be present in output. The string 'all' may also be given, in which case column filtering is not performed and all columns in the list will be present in output. Default value: 'all' (do not perform eng column filtering). Notes: This function should be used to merge data from log and eng files concatenated by SGLOGCAT and SGENGCAT respectively. The log parameters GC, STATE and SM_CCo contain values produced during the dive and timestamped according to the start of it. Hence, they are merged with the data collected in the eng files. To avoid name clashes and duplications, the following fields of the log parameters are renamed: - 'st_secs' field of 'GC'/'STATE'/'SM_CCo' parameter maps to 'elaps_t' - 'depth' field of 'GC' parameter maps to 'GC_depth' - 'gcphase' field of 'GC' parameter maps to 'GC_phase' STATE lines ususally do not have a unique timestamp (the timestamp of consecutive end-begin lines is the same) and in that case only the last line appears in the output.ç Depth in 'GC' log lines and in eng columns is not merged because they come in different units (m and cm). Also, there seems to be some time mismatch. Output in 'array' format when there are both textual and numeric columns might require a large amount of memory because of the storage in a cell array. Examples: [meta, data] = sglogengmerge(meta_log, data_log, meta_eng, data_eng) See also: SGLOG2MAT SGLOGCAT SGENGCAT Authors: Joan Pau Beltran <joanpau.beltran@socib.cat>
0001 function [meta, data] = sglogengmerge(meta_log, data_log, meta_eng, data_eng, varargin) 0002 %SGLOGENGMERGE Merge data from combined Seaglider log and eng data sets into a single data set. 0003 % 0004 % Syntax: 0005 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG) 0006 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPTIONS) 0007 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPT1, VAL1, ...) 0008 % 0009 % Description: 0010 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG) 0011 % merges the data sets described by metadata structs META_LOG and META_ENG, 0012 % and data arrays or structs DATA_LOG and DATA_ENG into a single data set 0013 % described by metadata struct META and data array or struct DATA 0014 % (see format option described below). Input metadata and data should be 0015 % in the format returned by the functions SGLOGCAT and SGENGCAT. 0016 % Log data referenced to the dive start time (GC, STATE and SM_CCo fields) 0017 % is merged with eng data. See note on merging. 0018 % 0019 % META is a struct array combining the information in META_LOG and META_ENG. 0020 % It has the following fields: 0021 % LOGHEADERS: struct array of log headers. 0022 % These are the log data headers in META_LOG. Entries corresponding 0023 % to unmatched eng headers have all fields empty. 0024 % ENGHEADERS: struct array of eng headers. 0025 % These are the eng data headers from META_ENG. Entries corresponding 0026 % to unmatched log headers have all fields empty. 0027 % START_SECS: number with the reference time for timestamped data lines. 0028 % This is the minimum of the START_SECS field in META_LOGG and META_ENG: 0029 % start time of first dive as seconds since 1970 Janyuay 01 00:00:00 UTC. 0030 % COLUMNS: string cell array with the names of the columns in output data. 0031 % This are the column names in META_ENG. See note on data merging. 0032 % PARAMS: struct with the names of the fields of non-scalar parameters. 0033 % This is the PARAMS field in META_LOG. 0034 % GCHEAD: string cell array with the names of the fields for the GC lines. 0035 % This is the GCHEAD field in META_LOG. 0036 % DEVICES: string cell array with the names of the fields for device lines. 0037 % This is the DEVICES field in META_LOG. 0038 % SENSORS: string cell array with the names of the fields for sensor lines. 0039 % This is the SENSORS field in META_LIST. 0040 % SOURCES: string cell array with the name of the source files. 0041 % This is the concatenation the SOURCES field in META_LOG and META_ENG. 0042 % 0043 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPTIONS) and 0044 % [META, DATA] = SGLOGENGMERGE(META_LOG, DATA_LOG, META_ENG, DATA_ENG, OPT1, VAL1, ...) 0045 % accept the following options given in key-value pairs OPT1, VAL1... 0046 % or in a struct OPTIONS with field names as option keys and field values 0047 % as option values: 0048 % FORMAT: data output format. 0049 % String setting the format of the output DATA. Valid values are: 0050 % 'array': DATA is a struct with the following fields: 0051 % LOG: array with log parameters in the column order specified by 0052 % PARAMS metadata field. 0053 % ENG: array or cell array with the eng columns and GC and SM_CCo 0054 % log parameter columns in the column order specified by COLUMNS 0055 % metadata field. 0056 % GPSFIX: array or cell array with the GPS log columns in the order 0057 % specified by the GPSFIX metadata field. 0058 % See note on array format. 0059 % 'merged': DATA is a struct with a column vector field for each 0060 % parameter in log or gps data, and for each column in eng data. 0061 % 'struct': DATA is a struct with a column vector field for each column 0062 % in eng data and gps data, and for each scalar parameter in log data; 0063 % and with a struct field for each non-scalar parameter in log data. 0064 % Default value: 'array' 0065 % PARAMS: log parameter filtering list. 0066 % String cell array with the names of the log parameters of interest. 0067 % If given, only parameters present in both the input data sets and this 0068 % list will be present in output. For non-scalar parameters, the name 0069 % of the identifier as it appears in the log line specifies including 0070 % all of its fields. Individual parameter fields are selected 0071 % with the identifier and the name of the field separated by underscore 0072 % (e.g. 'FINISH_dens'). The string 'all' may also be given, in which case 0073 % parameter filtering is not performed and all parameters in input list 0074 % will be present in output. 0075 % Default value: 'all' (do not perform log parameter filtering). 0076 % COLUMNS: eng column filtering list. 0077 % String cell array with the names of the eng data columns of interest. 0078 % If given, only columns present in both the input data sets and this list 0079 % will be present in output. The string 'all' may also be given, 0080 % in which case column filtering is not performed and all columns 0081 % in the list will be present in output. 0082 % Default value: 'all' (do not perform eng column filtering). 0083 % 0084 % Notes: 0085 % This function should be used to merge data from log and eng files 0086 % concatenated by SGLOGCAT and SGENGCAT respectively. 0087 % 0088 % The log parameters GC, STATE and SM_CCo contain values produced during the 0089 % dive and timestamped according to the start of it. Hence, they are merged 0090 % with the data collected in the eng files. To avoid name clashes and 0091 % duplications, the following fields of the log parameters are renamed: 0092 % - 'st_secs' field of 'GC'/'STATE'/'SM_CCo' parameter maps to 'elaps_t' 0093 % - 'depth' field of 'GC' parameter maps to 'GC_depth' 0094 % - 'gcphase' field of 'GC' parameter maps to 'GC_phase' 0095 % STATE lines ususally do not have a unique timestamp (the timestamp of 0096 % consecutive end-begin lines is the same) and in that case only the last 0097 % line appears in the output.ç 0098 % 0099 % Depth in 'GC' log lines and in eng columns is not merged because they come 0100 % in different units (m and cm). Also, there seems to be some time mismatch. 0101 % 0102 % Output in 'array' format when there are both textual and numeric columns 0103 % might require a large amount of memory because of the storage in a cell 0104 % array. 0105 % 0106 % Examples: 0107 % [meta, data] = sglogengmerge(meta_log, data_log, meta_eng, data_eng) 0108 % 0109 % See also: 0110 % SGLOG2MAT 0111 % SGLOGCAT 0112 % SGENGCAT 0113 % 0114 % Authors: 0115 % Joan Pau Beltran <joanpau.beltran@socib.cat> 0116 0117 % Copyright (C) 2013-2016 0118 % ICTS SOCIB - Servei d'observacio i prediccio costaner de les Illes Balears 0119 % <http://www.socib.es> 0120 % 0121 % This program is free software: you can redistribute it and/or modify 0122 % it under the terms of the GNU General Public License as published by 0123 % the Free Software Foundation, either version 3 of the License, or 0124 % (at your option) any later version. 0125 % 0126 % This program is distributed in the hope that it will be useful, 0127 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0128 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0129 % GNU General Public License for more details. 0130 % 0131 % You should have received a copy of the GNU General Public License 0132 % along with this program. If not, see <http://www.gnu.org/licenses/>. 0133 0134 error(nargchk(4, 14, nargin, 'struct')); 0135 0136 0137 %% Set options and default values. 0138 options.format = 'array'; 0139 options.params = 'all'; 0140 options.columns = 'all'; 0141 options.period = 'all'; 0142 0143 0144 %% Parse optional arguments. 0145 % Get option key-value pairs in any accepted call signature. 0146 argopts = varargin; 0147 if isscalar(argopts) && isstruct(argopts{1}) 0148 % Options passed as a single option struct argument: 0149 % field names are option keys and field values are option values. 0150 opt_key_list = fieldnames(argopts{1}); 0151 opt_val_list = struct2cell(argopts{1}); 0152 elseif mod(numel(argopts), 2) == 0 0153 % Options passed as key-value argument pairs. 0154 opt_key_list = argopts(1:2:end); 0155 opt_val_list = argopts(2:2:end); 0156 else 0157 error('glider_toolbox:sglogengmerge:InvalidOptions', ... 0158 'Invalid optional arguments (neither key-value pairs nor struct).'); 0159 end 0160 % Overwrite default options with values given in extra arguments. 0161 for opt_idx = 1:numel(opt_key_list) 0162 opt = lower(opt_key_list{opt_idx}); 0163 val = opt_val_list{opt_idx}; 0164 if isfield(options, opt) 0165 options.(opt) = val; 0166 else 0167 error('glider_toolbox:sglogengmerge:InvalidOption', ... 0168 'Invalid option: %s.', opt); 0169 end 0170 end 0171 0172 0173 %% Set option flags and values. 0174 output_format = options.format; 0175 param_filter = true; 0176 param_filter_list = cellstr(options.params); 0177 column_filter = true; 0178 column_filter_list = cellstr(options.columns); 0179 if ischar(options.params) && strcmp(options.params, 'all') 0180 param_filter = false; 0181 end 0182 if ischar(options.columns) && strcmp(options.columns, 'all') 0183 column_filter = false; 0184 end 0185 0186 0187 %% GPS data goes on its own. 0188 % However, it is described in the PARAMS metadata field. 0189 0190 0191 %% Eng data merged with numeric timestamped log data. 0192 % Precompute timestamp column and column names, 0193 % and convert eng, GC and SM_CCo data to array if needed. 0194 min_start_secs = min([meta_log.start_secs; meta_eng.start_secs]); 0195 % Eng data: 0196 eng = data_eng; 0197 if isstruct(eng) 0198 eng = cell2mat(struct2cell(eng)'); 0199 end 0200 eng_column_list = meta_eng.columns; 0201 eng_secs_offset = meta_eng.start_secs - min_start_secs; 0202 eng_secs_select = strcmp('elaps_t', eng_column_list); 0203 eng(:, eng_secs_select) = eng(:, eng_secs_select) + eng_secs_offset; 0204 eng_secs = eng(:, eng_secs_select); 0205 if column_filter 0206 eng_column_filtering = ismember(eng_column_list, column_filter_list); 0207 eng_column_list = eng_column_list(eng_column_filtering); 0208 eng = eng(:, eng_column_filtering); 0209 if ~any(eng_column_filtering) 0210 eng_secs = zeros(0, 1); 0211 eng = []; 0212 end 0213 end 0214 % Log data to be merged with eng data: 0215 logeng_param_list = {'GC' 'SM_CCo' 'STATE'}'; 0216 logeng_param_numeric_list = [true true false]'; 0217 logeng_member_map = { 0218 'st_secs' 'elaps_t' 0219 'gcphase' 'GC_phase' 0220 'depth' 'GC_depth' 0221 }; 0222 logeng_param_list = ... 0223 intersect(fieldnames(meta_log.params), logeng_param_list); 0224 logeng_secs_offset = meta_log.start_secs - min_start_secs; 0225 logeng_stsecs_list = repmat({zeros(0, 1)}, size(logeng_param_list)); 0226 logeng_column_list = repmat({cell(0,1)}, size(logeng_param_list)); 0227 logeng_values_list = cell(size(logeng_param_list)); 0228 for logeng_param_idx = 1:numel(logeng_param_list) 0229 logeng_param = logeng_param_list{logeng_param_idx}; 0230 logeng_param_numeric = logeng_param_numeric_list(logeng_param_idx); 0231 logeng_members = meta_log.params.(logeng_param); 0232 logeng_columns = strcat(logeng_param, '_', logeng_members); 0233 if ~isfield(data_log, logeng_param) 0234 logeng_values = ... 0235 cellfun(@(f)(data_log.(f)), logeng_columns, 'UniformOutput', false); 0236 if ~logeng_param_numeric 0237 logeng_values_numeric = cellfun(@isnumeric, logeng_values); 0238 logeng_values(logeng_values_numeric) = ... 0239 cellfun(@num2cell, logeng_values(logeng_values_numeric), ... 0240 'UniformOutput', false); 0241 end 0242 logeng_values = horzcat(logeng_values{:}); 0243 elseif isstruct(data_log.(logeng_param)) 0244 logeng_values = struct2cell(data_log.(logeng_param))'; 0245 if logeng_param_numeric 0246 logeng_values = cell2mat(logeng_values); 0247 end 0248 else 0249 logeng_values = data_log.(logeng_param); 0250 end 0251 logeng_stsecs_column = strcmp('st_secs', logeng_members); 0252 if logeng_param_numeric 0253 logeng_stsecs = logeng_values(:, logeng_stsecs_column); 0254 logeng_stsecs = logeng_stsecs + logeng_secs_offset; 0255 logeng_values(:, logeng_stsecs_column) = logeng_stsecs; 0256 else 0257 logeng_stsecs = cell2mat(logeng_values(:, logeng_stsecs_column)); 0258 logeng_stsecs = logeng_stsecs + logeng_secs_offset; 0259 logeng_values(:, logeng_stsecs_column) = num2cell(logeng_stsecs); 0260 end 0261 [logeng_column_renaming, logeng_column_map] = ... 0262 ismember(logeng_members, logeng_member_map(:,1)); 0263 logeng_columns(logeng_column_renaming) = ... 0264 logeng_member_map(logeng_column_map(logeng_column_renaming), 2); 0265 logeng_member_filtering = true(size(logeng_members)); 0266 if param_filter && ~any(strcmp(logeng_param, param_filter_list)) 0267 logeng_member_filtering = ismember(logeng_members, param_filter_list); 0268 end 0269 if any(logeng_member_filtering) 0270 logeng_column_list{logeng_param_idx} = ... 0271 logeng_columns(logeng_member_filtering); 0272 logeng_values_list{logeng_param_idx} = ... 0273 logeng_values(:, logeng_member_filtering); 0274 logeng_stsecs_list{logeng_param_idx} = logeng_stsecs; 0275 end 0276 end 0277 % Merge timestamped data. 0278 logeng_data_list = vertcat({eng}, logeng_values_list(:)); 0279 logeng_secs_list = vertcat(eng_secs, logeng_stsecs_list{:}); 0280 logeng_cols_list = vertcat(eng_column_list, logeng_column_list{:}); 0281 column_list = unique(logeng_cols_list); 0282 [logeng_cols_present_list, logeng_cols_indices_list] = ... 0283 ismember(logeng_cols_list, column_list); 0284 [logeng_secs, ~, logeng_rows_indices_list] = unique(logeng_secs_list); 0285 [logeng_num_rows_list, logeng_num_cols_list] = ... 0286 cellfun(@size, logeng_data_list); 0287 logeng_rows_final_list = cumsum(logeng_num_rows_list); 0288 logeng_rows_start_list = 1 + [0; logeng_rows_final_list(1:end-1)]; 0289 logeng_cols_final_list = cumsum(logeng_num_cols_list); 0290 logeng_cols_start_list = 1 + [0; logeng_cols_final_list(1:end-1)]; 0291 logeng = struct(); 0292 logeng_rows_total = numel(logeng_secs); 0293 % logeng_cols_total = numel(column_list); 0294 % logeng = nan(logeng_rows_total, logeng_cols_total); 0295 for data_idx = 1:numel(logeng_data_list) 0296 logeng_rows_range = ... 0297 logeng_rows_start_list(data_idx):logeng_rows_final_list(data_idx); 0298 logeng_rows_indices = logeng_rows_indices_list(logeng_rows_range); 0299 logeng_cols_range = ... 0300 logeng_cols_start_list(data_idx):logeng_cols_final_list(data_idx); 0301 logeng_cols_present = logeng_cols_present_list(logeng_cols_range); 0302 logeng_cols_indices = logeng_cols_indices_list(logeng_cols_range); 0303 for logeng_col_idx = find(logeng_cols_present(:)') 0304 column_index = logeng_cols_indices(logeng_col_idx); 0305 column = column_list{column_index}; 0306 value = logeng_data_list{data_idx}(:,logeng_col_idx); 0307 if iscell(value) && ~iscellstr(value) 0308 value = cell2mat(value); 0309 end 0310 if ~isfield(logeng, column) 0311 if isnumeric(value) 0312 logeng.(column) = nan(logeng_rows_total, 1); 0313 else 0314 logeng.(column) = repmat({''}, logeng_rows_total, 1); 0315 end 0316 end 0317 logeng.(column)(logeng_rows_indices) = value; 0318 end 0319 end 0320 0321 0322 %% Log parameter data. 0323 log = struct(); 0324 param_list = struct(); 0325 log_param_list = setdiff(fieldnames(meta_log.params), logeng_param_list); 0326 log_param_filtering = true(size(log_param_list)); 0327 if param_filter 0328 log_param_filtering = ismember(log_param_list, param_filter_list); 0329 end 0330 for log_param_idx = 1:numel(log_param_list) 0331 log_field = log_param_list{log_param_idx}; 0332 log_member_list = meta_log.params.(log_field); 0333 log_field_member_list = strcat(log_field, '_', log_member_list); 0334 log_member_filtering = ismember(log_field_member_list, param_filter_list); 0335 log_values = []; 0336 if ~isfield(data_log, log_field) 0337 for log_member_idx = numel(log_field_member_list):-1:1 0338 log_field_member = log_field_member_list{log_member_idx}; 0339 if iscell(log_values) && isnumeric(data_log.(log_field_member)) 0340 log_values(:,log_member_idx) = num2cell(data_log.(log_field_member)); 0341 elseif isnumeric(log_values) && iscell(data_log.(log_field_member)) 0342 log_values = num2cell(log_values); 0343 log_values(:,log_member_idx) = data_log.(log_field_member); 0344 else 0345 log_values(:,log_member_idx) = data_log.(log_field_member); 0346 end 0347 end 0348 elseif isstruct(data_log.(log_field)) 0349 log_values = struct2cell(data_log.(log_field))'; 0350 if ~iscellstr(log_values) 0351 log_values = cell2mat(log_values); 0352 end 0353 else 0354 log_values = data_log.(log_field); 0355 end 0356 if log_param_filtering(log_param_idx) 0357 param_list.(log_field) = log_member_list; 0358 log.(log_field) = log_values; 0359 elseif any(log_member_filtering) 0360 param_list.(log_field) = log_member_list(log_member_filtering); 0361 log.(log_field) = log_values(:, log_member_filtering); 0362 end 0363 end 0364 0365 0366 %% Merge metadata. 0367 % Sort according mission and dive number (using a virtual rank index). 0368 num_log_headers = numel(meta_log.headers); 0369 num_eng_headers = numel(meta_eng.headers); 0370 all_miss_nums = vertcat(meta_log.headers.mission, meta_eng.headers.mission); 0371 all_dive_nums = vertcat(meta_log.headers.dive, meta_eng.headers.dive); 0372 [~, ~, miss_dive_sorting] = ... 0373 unique( (all_dive_nums - min(all_dive_nums)) ... 0374 + (all_miss_nums - min(all_miss_nums)) ... 0375 * (max(all_dive_nums) - min(all_dive_nums) + 1)); 0376 meta = struct(); 0377 meta.logheaders(miss_dive_sorting(1:num_log_headers)) = meta_log.headers; 0378 meta.engheaders(miss_dive_sorting(num_log_headers + (1:num_eng_headers))) = ... 0379 meta_eng.headers; 0380 meta.sources = vertcat(meta_log.sources, meta_eng.sources); 0381 meta.start_secs = min_start_secs; 0382 meta.GCHEAD = meta_log.GCHEAD; 0383 meta.SENSORS = meta_log.SENSORS; 0384 meta.DEVICES = meta_log.DEVICES; 0385 meta.params = param_list; 0386 meta.columns = column_list; 0387 0388 0389 %% Convert output data to struct format if needed. 0390 switch output_format 0391 case 'array' 0392 data = struct(); 0393 gps_field_list = {'GPSFIX'}'; 0394 odd_field_list = {'RECOV_CODE' 'RESTART_TIME'}'; 0395 field_list = intersect(fieldnames(meta.params), ... 0396 vertcat(gps_field_list, odd_field_list)); 0397 for field_idx = 1:numel(field_list) 0398 field = field_list{field_idx}; 0399 value_list = log.(field); 0400 data.(field) = value_list; 0401 end 0402 log = struct2cell(rmfield(log, vertcat(gps_field_list, odd_field_list))); 0403 log_num = cellfun(@isnumeric, log); 0404 if any(log_num) && ~all(log_num) 0405 log(log_num) = cellfun(@num2cell, log(log_num), 'UniformOutput', false); 0406 end 0407 log = horzcat(log{:}); 0408 data.log = log; 0409 logeng = struct2cell(logeng); 0410 logeng_num = cellfun(@isnumeric, logeng); 0411 if any(logeng_num) && ~all(logeng_num) 0412 logeng(logeng_num) = ... 0413 cellfun(@num2cell, logeng(logeng_num), 'UniformOutput', false); 0414 end 0415 logeng = horzcat(logeng{:}); 0416 data.eng = logeng; 0417 case 'merged' 0418 data = struct(); 0419 field_list = fieldnames(meta.params); 0420 for field_idx = 1:numel(field_list) 0421 field = field_list{field_idx}; 0422 member_list = meta.params.(field); 0423 value_list = log.(field); 0424 if isempty(member_list) 0425 data.(field) = value_list; 0426 else 0427 for member_idx = 1:numel(member_list) 0428 member = member_list{member_idx}; 0429 field_member = [field '_' member]; 0430 value = value_list(:, member_idx); 0431 if iscell(value) && ~iscellstr(value) 0432 value = vertcat(value{:}); 0433 end 0434 data.(field_member) = value; 0435 end 0436 end 0437 end 0438 field_list = meta.columns; 0439 for field_idx = 1:numel(field_list) 0440 field = field_list{field_idx}; 0441 value = logeng.(field); 0442 if iscell(value) && ~iscellstr(value) 0443 value = vertcat(value{:}); 0444 end 0445 data.(field) = value; 0446 end 0447 case 'struct' 0448 data = struct(); 0449 field_list = fieldnames(meta.params); 0450 for field_idx = 1:numel(field_list) 0451 field = field_list{field_idx}; 0452 member_list = meta.params.(field); 0453 value_list = log.(field); 0454 if isempty(member_list) 0455 data.(field) = value_list; 0456 else 0457 if isnumeric(value_list) 0458 value_list = num2cell(value_list); 0459 end 0460 data.(field) = cell2struct(value_list, member_list, 2); 0461 end 0462 end 0463 field_list = meta.columns; 0464 for field_idx = 1:numel(field_list) 0465 field = field_list{field_idx}; 0466 value = logeng.(field); 0467 if iscell(value) && ~iscellstr(value) 0468 value = vertcat(value{:}); 0469 end 0470 data.(field) = value; 0471 end 0472 otherwise 0473 error('glider_toolbox:sglogengmerge:InvalidFormat', ... 0474 'Invalid output format: %s.', output_format) 0475 end 0476 0477 end