Trouble with looping function into structure index - matlab

I'm relatively new to matlab and would really appreciate any help.
Currently, I have a function (we'll call it readf) that reads in data from a single ascii file into a struct of multiple fields (we'll call it cdata).
names = cellstr(char('A','B','C','D','E','F','G'));
cdata = readf('filestring','dataNames',names);
The function works fine and gives me the correct output of a struct with these field names, with the value of each field name being a cell array of the corresponding data.
My task is to create a for loop that uses this readf function to read in a folder of these ascii files at once. I'm trying to work it so that the for loop creates a struct with an index of the different cdata structs. After trying a few different methods, I am stumped.
This is what I have so far.
files = struct2cell(dir('folderstring')); %creates a cell array of the names of the files withing the folder
for ii=length(files);
cdata(ii) = readf([folderstring,files(1,1:ii),names],'dataName',names);
end;
This is currently giving me the following error.
"Error using horzcat
Dimensions of matrices being concatenated are not consistent."
I am not sure what is wrong. How can I fix this code so i can read in all the data from a folder at once??? Is there a better and more efficient way to do this than making an index to this struct? Perhaps a cell array of different structures or even a structure of nested structures? Thanks!

Change:
for ii=length(files);
cdata(ii) = readf([folderstring,files(1,1:ii),names],'dataName',names);
end;
To:
for ii=1:length(files); % CHECK to make sure length(files) is giving you the right number
cdata(ii) = readf([folderstring,files{ii},names],'dataName',names);
end;
% CHECK files{ii}, with 1,2,3 etc. is giving you the correct file name.

Related

Synchronize timetables stored in a structure

I am dynamically storing data from different data recorders in timetables, nested in a structure DATA, such as DATA.Motor (timetable with motor data), DATA.Actuators (timetable with actuators data) and so on.
My objective is to have a function that synchronizes and merges these timetables so I can work with one big timetable.
I am trying to use synchronize to merge and synchronize those timetables:
fields = fieldnames(DATA);
TT = synchronize(DATA.(fields{1:end}));
but get the following error:
Expected one output from a curly brace or dot indexing expression, but there were 3 results.
This confuses me because DATA.(fields{1}) return the timetable of the first field name of the DATA structure.
Any thought on how I can solve this is greatly appreciated.
The problem here is that fields{1:end} is returning a "comma-separated list", and you're not allowed to use one of those as a struct dot-index expression. I.e. it's as if you tried the following, which is not legal:
DATA.('Motor','Actuators')
One way to fix this is to pull out the values from DATA into a cell array, and then you can use {:} indexing to generate the comma-separated list as input to synchronize, like this:
DATA = struct('Motor', timetable(datetime, rand), ...
'Actuators', timetable(datetime, rand));
DATA_c = struct2cell(DATA);
TT = synchronize(DATA_c{:});

Sequential import of datafiles according to rule in Matlab

I have a list of .txt datafiles to import. Suppose they are called like that
file100data.txt file101data.txt ... file109data.txt I want to import them all using readtable.
I tried using the for to specify a vector a = [0:9] through which matlab could loop the readtable command but I cannot make it work.
for a = [0:9]
T_a_ = readtable('file10_a_data.txt')
end
I know I cannot just put _a_ where I want the vector to loop through, so my question is how can I actually do it?
Thank you in advance!
Here is a solution that should work even if you have missing files in your folder (e.g. you have file100data.txt to file107data.txt, but you are missing file file108data.txt and file109data.txt):
files=dir('file10*data.txt'); %list all data files in your folder
nof=size(files,1); %number of files
for i=1:nof %loop over the number of files
table_index=files(i).name(7) %recover table index from data filename
eval(sprintf('T%s = readtable(files(i).name)', table_index)); %read table
end
Now, please note that is it generally regarded as poor practice to dynamically name variables in Matlab (see this post for example). You may want to resort to structures or cells to store your data.
You need to convert the value of a into a string and combine strings together, like this:
Tables = struct();
for a = 0:9
% note: using dynamic structure field names to store the imported tables
fname = ['file10_' num2str(a) '_data'];
Tables.(fname) = readtable([fname '.txt']);
end

Matlab save sequence of mat files from convertTDMS stored in cell array to sequence of mat files

I have data stored in the .tdms format, gathering the data of many sensors, measured every second, every day. A new tdms file is created every day, and stored in a folder per month. Using the convertTDMS function, I have converted these tdms files to mat files.
As there are some errors in some of the measurements(e.g. negative values which can not physically occur), I have performed some corrections by loading one mat file at a time, do the calculations and then save the data into the original .mat file.
However, when I try to do what I described above in a loop (so: load .mat in folder, do calculations on one mat file (or channel therein), save mat file, repeat until all files in the folder have been done), I end up running into trouble with the limitations of the save function: so far I save all variables (or am unable to save) in the workspace when using the code below.
for k = 1:nFiles
w{k,1} = load(wMAT{k,1});
len = length(w{k,1}.(x).(y).(z));
pos = find(w{k,1}.(x).(y).(z)(1,len).(y)<0); %Wind speed must be >0 m/s
for n = 1:length(pos)
w{k,1}.(x).(y).(z)(1,len).(y)(pos(n)) = mean([w{k,1}.(x).(y).(z)(1,len).(y)(pos(n)+1),...
w{k,1}.(x).(y).(z)(1,len).(y)(pos(n)-1)],2);
end
save( name{k,1});
%save(wMAT{k,1},w{k,1}.(x),w{k,1}.ConvertVer,w{k,1}.ChanNames);
end
A bit of background information: the file names are stored in a cell array wMAT of length nFiles in the folder. Each cell in the cell array wMAT stores the fullfile path to the mat files.
The data of the files is loaded and saved into the cell array w, also of length nFiles.
Each cell in "w" has all the data stored from the tdms to mat conversion, in the format described in the convertTDMS description.
This means: to get at the actual data, I need to go from the
cell in the cell array w{k,1} (my addition)
to the struct array "ConvertedData" (Structure of all of the data objects - part of convertTDMS)
to the struct array below called "Data" (convertTDMS)
to the struct array below called "MeasuredData" (convertTDMS) -> at this level, I can access the channels which store the data.
to finally access/manipulate the values stored, I have to select a channel, e.g. (1,len), and then go via the struct array to the actual values (="Data"). (convertTDMS)
In Matlab format, this looks like "w{1, 1}.ConvertedData.Data.MeasuredData(1, len).Data(1:end)" or "w{1, 1}.ConvertedData.Data.MeasuredData(1, len).Data".
To make typing easier, I took
x = 'ConvertedData';
y = 'Data';
z = 'MeasuredData';
allowing me to write instead:
w{k,1}.(x).(y).(z)(1,len).(y)
using the dot notation.
My goal/question: I want to load the values stored in a .mat file from the original .tdms files in a loop to a cell array (or if I can do better than a cell array: please tell me), do the necessary calculations, and then save each 'corrected' .mat file using the original name.
So far, I have gotten a multitude of errors from trying a variety of solutions, going from "getfieldnames", trying to pass the name of the (dynamically changing) variable(s), etc.
Similar questions which have helped me get in the right direction include Saving matlab files with a name having a variable input, Dynamically Assign Variables in Matlab and http://www.mathworks.com/matlabcentral/answers/4042-load-files-containing-part-of-a-string-in-the-file-name-and-the-load-that-file , yet the result is that I am still no closer than doing manual labour in this case.
Any help would be appreciated.
If I understand your ultimate goal correctly, I think you're pretty much there. I think you're trying to process your .mat files and that the loading of all of the files into a cell array is not a requirement, but just part of your solution? Assuming this is the case, you could just load the data from one file, process it, save it and then repeat. This way you only ever have one file loaded at a time and shouldn't hit any limits.
Edit
You could certainly make a function out of your code and then call that in a loop, passing in the file name to modify. Personally I'd probably do that as I think it's neater solution. If you don't want to do that though, you could just replace w{k,1} with w then each time you load a file w would be overwritten. If you wanted to explicitly clear variables you can use the clear command with a space separated list of variables e.g. clear w len pos, but I don't think that this is necessary.

Matlab bad cell reference operation when if statement

I have a <850x1> cell called x. Each of the individual structures has a 'Tag' name and 'Data' cell with <7168x1 double> data values.
(i.e.
x{1,1}.Tag = 'Channel1', x{1,1}.Data= <7168x1 double>)
So, I want to go through the x cell, identify the structures with 'Channel1' Tag names and pull out that structure's data. Then, combine the data into a cell called Ch1. Here is my approach so far:
n=1:850
if x{n,1}.Tag == 'Channel1'
Ch1{:,n} = x{n,1}.Data;
end
However, this gives an error: Bad cell reference operation.
Any ideas what may be going wrong?
There are 2 issues here. First, your if statement will compare each entry in the string x{n,1}.Tag to each entry in the string 'Channel1'. If the dimensions are not the same, you will get an error. To fix this, you could use the string compare function, strcmp. The other issue is that you are assigning n to all values between 1 and 850 at once. This is the issue that is producing the actual error you are seeing. Instead, you want to step through each of these values one at a time with a for loop. I would suggest trying the following code:
for n=1:850
if strcmp(x{n,1}.Tag, 'Channel1')
Ch1{:,n} = x{n,1}.Data;
end
end

Matlab: how to rename a sub-field

Let me describe the question in this way. I have a .mat file, and if I open it, it contains a 1x10 struct data. In each data, it has a 1x5 struct (or field) called res. In res, it has a 1x1 struct (or field) called, let's say, foo. Thus, I have ixj copies of data(i).res(j).foo .
Is there anyway I can change the name of this foo? say I want all data(i).res(j).foo to become data(i).res(j).bar
I did search on the internet, and tried a few ways (add field and delete, create a temp field, use cell2field or fieldtofile, etc.) and all of them didn't work. The most frequent returned error is "Subscripted Assignment between dissimilar structures."
Please help, thanks in advance!
The safest way is probably by looping over data twice, the first pass creating a new field bar for each subfield like data(i).res(j).bar=data(i).res(j).foo, then the second pass deletes the old fields like data(i).res(j) = rmfield(data(i).res(j),'foo').
Thanks caoy and NotLikeThat. I finally came to an conclusion.
data2 = data
for i=1:10
for j = 1:5
data(i).res(j).bar = data2(i).res(j).foo;
end
data(i).res = rmfield(data(i).res, 'foo');
end
I probably need to removed i, j, and data2 after running this script.