MATLAB Answers

0

How do I apply unique names to structs created in a for loop?

Asked by Scooby921 on 19 Jul 2019
Latest activity Commented on by Scooby921 on 26 Jul 2019
I have this script and by the end of it I have variables in the workspace containing the quantity and names of vehicle performance modes to be tested, and I have the folder loacations of the data to be analyzed.
%% Initialize
close all
clear
clc
%% Select path and generate list of modes
% Prompt user to identify top level directory for the vehicle to be
% analyzed.
vehiclePath = uigetdir('','Select Vehicle Data Directory');
% Extract sub folder names which should identify the number and name of
% various performance modes tested in the selected vehicle. Ignore ., ..,
% and default folder names.
pathContents = dir(vehiclePath);
folders = pathContents(~ismember({pathContents.name},{'.','..','AWD-insert mode name with no spaces-'}));
dirFlags = [folders.isdir];
subFolders = folders(dirFlags);
modeList = {subFolders.name};
clearvars pathContents folders dirFlags
%% List Generation
% List of AWD hardware variants
variantList = {'Booster','Twinster'};
% List of all standardized test maneuvers used for validation. This list
% matches the sub folders contained within each performance mode (second
% level folders named in 'modeList' above).
testList = {'VVT_001 High Mu Path Deviation',...
'VVT_002 High Mu CRAM',...
'VVT_003 High Mu Acceleration',...
'VVT_004 Torque Steer Evaluation',...
'VVT_005 High Mu Sine Steer',...
'VVT_006 Low Mu Sine Steer',...
'VVT_007 High Mu AIT 90deg SWA',...
'VVT_008 High Mu AIT 45deg SWA',...
'VVT_009 Low Mu Acceleration',...
'VVT_010 Low Mu 50kph Tip-In',...
'VVT_011 Low Mu 100kph Tip-In',...
'VVT_012 AWD Response Time',...
'VVT_013 Level Mu Split',...
'VVT_014 Level Mu Step',...
'VVT_015 Mu Split 10pct Grade',...
'VVT_016 Mu Split 15pct Grade',...
'VVT_017 Mu Split 20pct Grade',...
'VVT_018 Mu Split 30pct Grade',...
'VVT_019 Micro Mu Split 50pct Tip-In',...
'VVT_020 Micro Mu Split WOT Tip-In',...
'VVT_021 Low Mu CRAM',...
'VVT_022 Small Ice AIT',...
'VVT_023 Small Ice DTIT',...
'VVT_024 Small Snow AIT',...
'VVT_025 Small Snow DTIT',...
'VVT_026 Large Ice AIT',...
'VVT_027 Large Ice DTIT',...
'VVT_028 Large Snow AIT',...
'VVT_029 Large Snow DTIT'};
%% Variant Selection
% Prompts user to identify which type of AWD system was equipped for
% testing. This impacts calculations and plots which execute in other
% scripts.
[variant,TF] = listdlg('ListString',variantList,'ListSize',[220,100],'Name','Select Variant','SelectionMode','Single');
if TF == 0
Err = errordlg('No Variant Selected','Analysis Canceled');
set(Err,'Position',[600 600 200 60]);
return
else
end
drivelineConfig = variantList{variant};
clearvars TF
%% User Selection
% Prompts user to idenfity which test is to be analyzed.
[test,tf] = listdlg('ListString',testList,'ListSize',[300 600],'Name','Select Comparison Maneuver','SelectionMode','Single');
if tf == 0
err = errordlg('No Analysis Selected','Analysis Canceled');
set(err,'Position',[600 600 200 60]);
return
else
end
selectedTest = testList{test};
clearvars tf
%% Create analysis path
analysisPath = cell(2,1);
for ii = 1:length(modeList)
analysisPath(ii) = fullfile(vehiclePath,modeList(ii),selectedTest,filesep);
end
clearvars ii
%% How to use analysisPath and modeList to name the structs, locate the data, and populate the structs in the workspace?
modeList is the quantity and names of the performance modes and these are the names I want to use to define my structs. In this case there are only two, "Fwd" and "Awd". In other vehicle applications there will be more. Other vehicles might have "AwdSport", "AwdOffroad", "AwdSand", "AwdMud", etc.
analysisPath is the file path location to where I need to grab the .mat files and populate the structs.
I'm struggling to sort out the next section of the script. I know I need to run this in a loop, but I can't figure out how to run a loop and output a unique struct name pulled from the values in modeList. I'm also struggling to access the specific data files that I need. This works to access the files contained within the paths defined by analysisPath, but it lists every file and not just the .mat files I'm looking for. Struggling to find the right search terms to find the results I need to push past this.
dir(analysisPath{i})
This is my older script for loading .mat files into a struct. Initialy my scripting was focused around only comparing Fwd and Awd data and didn't allow for additional Awd modes. In this case I could simply prompt the user to select specific data files and then load the Fwd data into a struct named D2 (Data 2WD). I used the same script with F4/P4/D4/etc. to load and store data for 4WD. I know I need to reuse the loop to get the data from the mat files into the structs. I'm not sure how to loop this such that I can populate the struct and then name it for the mode folder from which it populated data. I'd like it to be automated so the naming of folders by users is a bit more flexible. I'm sure it can be done and likely requires a couple nested for loops and maybe breaks and returns, but I'm having a hard time visualizing it before blindly starting to type.
[F2,P2] = uigetfile('*.mat','Select 2WD Data File','MultiSelect','on');
if isnumeric(F2)
error('User quit')
elseif ischar(F2)
F2 = {F2};
end
D2 = struct('filename',F2);
for ii = 1:numel(F2)
Tmp2 = load(fullfile(P2,F2{ii}));
L2 = [{'Time'};Tmp2.Data_Labels(1:end-1)]; % fix "Time" column mismatch
for jj = 1:numel(L2)
D2(ii).(L2{jj}) = Tmp2.Data(:,jj);
end
end

  18 Comments

I've already taken care of data channels having different names. One auto manufacturer to the next they will change, but I'm already setup to use calculated channels in the data acquisition tool to rename and convert units into whatever I need for the Matlab scripts to run. I would like to write a script / function to automatically search the data files for specific names and rename as needed to make things work, but that's something for another year...after I understand more about what I'm doing.
The issue in that linked older question / answer is that the data acquistion tool spits out one .mat file with two variables. One is a cell array with each cell being a different n x 1 vector of data, and the other is a character array with each row being a channel name. It's inconsistent in how it organizes the data upon export. That script works to realign the data with the channel name. For lack of knowing another way to do it successfully I've held onto that code and struct generation. Even before getting things into a potential table or struct array or any other variable type I first need to link the names from one variable to the data from another.
"The issue in that linked older question / answer is that the data acquistion tool spits out one .mat file with two variables. One is a cell array with each cell being a different n x 1 vector of data, and the other is a character array with each row being a channel name."
That could easily be converted to a structure using cell2stuct, or a table using cell2table. That does the "linking" for you, and make the "variable" order irrelevant. A table would probably be best.
Still struggling. I've spent a few days trying to understand tables. I don't understand them. I can't define the variablenames (column names) first and add data second. When I try to add data first and read from a file to populate the table the result is never what I want. Aside from visual organization I don't see the point of the table. If I can't create a table without first having all of my data in the workspace, then the mission is accomplished prior to creating the table. I just want to get all of my data into my workspace.
I've gone back to structs. Using all of my initial code, I've added the following:
%% Populate data struct with mode, filename, and filepath
dataAll = struct;
for ii = 1:length(modeList)
import = dir(fullfile(analysisPath{ii},'*.mat'));
for jj = 1:length(import)
dataAll(jj).mode = modeList{ii};
dataAll(jj).filename = import(jj).name;
dataAll(jj).filepath = import(jj).folder;
end
end
clearvars ii jj import
%% Populate data struct with channel names and recorded data
for ii = 1:length(dataAll)
Tmp = load(fullfile(dataAll(ii).filepath,dataAll(ii).filename));
L = [{'Time'};Tmp.Data_Labels(1:end-1)]; % fix "Time" column mismatch
for jj = 1:numel(L)
dataAll(ii).(L{jj}) = Tmp.Data(:,jj);
end
end
clearvars ii jj Tmp L
This works, except that first for loop is overwriting instead of appending. Instead of dataAll having 6 rows, 3 each for Awd and Fwd modes, it just has 3 for Fwd. I know why it is overwriting. It's a for loop and performing the same action twice without being told to index the starting row on the next loop. My brain is just riding the struggle bus this morning and I can't figure out how to fix it. Image attached of the dataAll struct and lack of Awd mode files.

Sign in to comment.

Products


Release

R2018b

1 Answer

Answer by Joel Handy on 22 Jul 2019
Edited by Joel Handy on 22 Jul 2019

Does this help at all? I'm not completely sure I understand the nuances of your question, but If I had a folder structure like you showed in your picture, I might arrange the data something like this. No dynamic variable naming but you can still clearly identify which folders each set came from. You also don't need to worry about folder names being valid matlab variable names.
modeList = {'AWD', 'FWD'};
testList = {'VVT_001 High Mu Path Deviation',...
'VVT_002 High Mu CRAM',...
'VVT_003 High Mu Acceleration',...
'VVT_004 Torque Steer Evaluation',...
'VVT_005 High Mu Sine Steer',...
'VVT_006 Low Mu Sine Steer',...
'VVT_007 High Mu AIT 90deg SWA',...
'VVT_008 High Mu AIT 45deg SWA',...
'VVT_009 Low Mu Acceleration',...
'VVT_010 Low Mu 50kph Tip-In',...
'VVT_011 Low Mu 100kph Tip-In',...
'VVT_012 AWD Response Time',...
'VVT_013 Level Mu Split',...
'VVT_014 Level Mu Step',...
'VVT_015 Mu Split 10pct Grade',...
'VVT_016 Mu Split 15pct Grade',...
'VVT_017 Mu Split 20pct Grade',...
'VVT_018 Mu Split 30pct Grade',...
'VVT_019 Micro Mu Split 50pct Tip-In',...
'VVT_020 Micro Mu Split WOT Tip-In',...
'VVT_021 Low Mu CRAM',...
'VVT_022 Small Ice AIT',...
'VVT_023 Small Ice DTIT',...
'VVT_024 Small Snow AIT',...
'VVT_025 Small Snow DTIT',...
'VVT_026 Large Ice AIT',...
'VVT_027 Large Ice DTIT',...
'VVT_028 Large Snow AIT',...
'VVT_029 Large Snow DTIT'};
testSets = struct('Mode', {}, 'TestID', {}, 'TestData', {})
for mode = modeList
testSets = [testSets struct('Mode', mode{:}, 'TestID', testList, 'TestData', [])];
end
for testIdx = 1:numel(testSets)
% testSets(testIdx).TestData = load(<build up filename based on mode and testID>);
end

  0 Comments

Sign in to comment.