MATLAB: Initialise a table which contains a structure and a sub-structure

initialisationMATLABstructtable

I'm trying to initialise a structure to contain some EMG data. I've simplified the code, but have left in some of the complexity:
% create some variables which are needed later

varray = {'CvempBC_R'; 'OvempBC_R'; 'CvempAC_R'; 'CvempAC_L'; 'OvempAC_R'; 'OvempAC_L'};
maxsess = 28;
for pti = 1:10
pdat(pti).PiD = char('this is dummy data');
pdat(pti).canal = int8(15);
% create arrays to hold the raw data

for i = 1:6 % will iterate over varray, defined above

pdat(pti).(varray{i}) = table ( ... % will hold raw data and peaks for each condition tested
'Size', [maxsess,5], ... % need to set up column titles and data types in advance
'VariableNames', {'isAC', 'isCvemp', 'iteration', 'raw', 'peaks' }, ...
'VariableTypes', {'logical', 'logical', 'int8', 'struct', 'struct'} );
end
end
This is working fine – it will create the table I want.
The bit I'm having trouble with is the two 'struct' variable types in the lower right of the code sample above. These are initialised as 1×1 structures, but will ultimately be larger structures containing substructures.
To initialise them, I'd like to add something like this:
for k = 1:maxsess
pdat(pti).(varray{i}).raw(k) = struct( ...
'meta', struct(...
'fs', [0], ...
'nHL', int8([0]), ...
'nVperbit', [0], ...
'offset', [0], ...
'HPF', 'o', ...
'LPF', 'o', ...
'SweepsInBrick', int8([0]), ...
'nBricks', [0], ...
'nSamples', [0], ...
'nReps', int8([0]) ), ...
'data', zeros(20,467), ...
'avgALL', zeros(1,467), ...
'time', zeros(1,467) )
end
This creates the correct structure and sub-structure (I've tested by runnning it with a dummy structure name on the left hand side of the '='). However, if I try to combine my code like this:
% create some variables which are needed later
varray = {'CvempBC_R'; 'OvempBC_R'; 'CvempAC_R'; 'CvempAC_L'; 'OvempAC_R'; 'OvempAC_L'};
maxsess = 28;
for pti = 1:10
pdat(pti).PiD = char('this is dummy data');
pdat(pti).canal = int8(15);
% create arrays to hold the raw data
for i = 1:6 % will iterate over varray, defined above
pdat(pti).(varray{i}) = table ( ... % will hold raw data and peaks for each condition tested
'Size', [maxsess,5], ... % need to set up column titles and data types in advance
'VariableNames', {'isAC', 'isCvemp', 'iteration', 'raw', 'peaks' }, ...
'VariableTypes', {'logical', 'logical', 'int8', 'struct', 'struct'} );
for k = 1:maxsess
pdat(pti).(varray{i}).raw(k) = struct( ...
'meta', struct(...
'fs', [0], ...
'nHL', int8([0]), ...
'nVperbit', [0], ...
'offset', [0], ...
'HPF', 'o', ...
'LPF', 'o', ...
'SweepsInBrick', int8([0]), ...
'nBricks', [0], ...
'nSamples', [0], ...
'nReps', int8([0]) ), ...
'data', zeros(20,467), ...
'avgALL', zeros(1,467), ...
'time', zeros(1,467) )
end
end
end
I get the error "Subscripted assignment between dissimilar structures."
What I think is happening (please correct me if I'm wrong!) is that I initially created pdat.(varray).raw as a 1×1 structure. I then try to assign a much larger and more complex structure to pdat.(varray).raw. The mismatch between pdat.(varray).raw as initialised, and the form of data I'm trying to put into it, is at the root of the error.
The trouble is, I can't think of a way around the problem. There doesn't seem anything I can do when setting up the table to change how the structure it contains is set up. Here's what I've thought of:
  • Create dummy data containing everything I'd like to be in the table and the substructures, and then create the table as if the dummy data are the actual data. Then I can overwrite it. I did try this, but couldn't get it to work. Should I try again? It seemed a bit of a messy and clumsy solution.
  • I'm going to populate the table and substructures with data obtained from the Import Tool. When I use the Import Tool, I get a table/structure very similar to the table/structure I'm trying to recreate. So, I could simply use the Import Tool to create the structure for me. However, this is messier than I'd like, because I need to combine it with participant information which is unavailable to the Import Tool. Also, it makes troubleshooting more difficult. At the moment, I've got the Import Tool running in a function. I'd need to move the Import Tool inside a loop in my main script in order to have the Import Tool create a structure in the main script. And then any subsequent alteration or troubleshooting to the Import Tool is while it's embedded in a loop – ghastly!
  • Would it help if I stopped trying to use a table, and only used structures? I could do so. But the column headers in the table are actually quite useful – I'll be able to see all my participant metadata at a glance.
Any suggestions would be gratefully received 🙂

Best Answer

Subscripted assignment between dissimilar structures
This is because you're trying to change one element of a structure array to a different structure. If you changed the whole structure array instead you wouldn't get the error. Thus instead of your k loop:
initstruct = struct(... %your structure initialisation code that I'm not copying)
pdat(pti).(varray{i}).raw = repmat(initstruct, height(pdat(pti).(varray{i}), 1);
However, rather than preallocating the table with a default structure and then replacing it later on by a different structure, I'd just create the table directly with the right structure. That involves creating default arrays for all columns instead of using the 'Size', sz, 'VariableTypes', varTypes syntax, but I think it's cleaner:
initraw = struct(... %your structure initialisation code that I'm not copying)
initpeak = struct(... %some other structure)
pdat(pti).(varray{i}) = table(false(maxsess, 1), ...
false(maxsess, 1), ...
zeros(maxsess, 1, 'int8'), ...
repmat(initraw, maxsess, 1), ...
repmat(initpeak, maxsess, 1), ...
'VariableNames', {'isAC', 'isCvemp', 'iteration', 'raw', 'peaks'});