MATLAB Parse Data file - matlab

I have a text file that contains many lines of header and overhead information. Then, following that, there are repetitive blocks of data that I am interested in capturing. However, the first block is a bit different then the ones that follow it. The file structure is as follows:
**Header and overhead:**
...
...
...
SPD -> PX: SS3Data[07]: Recv Data
Sync: 0xXXXXXXXX
Chan: N
ID: N
Seq: N
SS: N
Words: N
Time: 0xXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX
PX: SS3Data[07]: Recv Data
Sync: 0xXXXXXXXX
Chan: N
ID: N
Seq: N
SS: N
Words: N
Time: 0xXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX
PX: SS3Data[07]: Recv Data
Sync: 0xXXXXXXXX
Chan: N
ID: N
Seq: N
SS: N
Words: N
Time: 0xXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXX
I'd like to be able to capture the data in the said Blocks and store them in a structure such as the following:
S.Block1.Sync
S.Block1.Chan
S.Block1.Chan
S.Block1.ID
S.Block1.Seq
S.Block1.SS
S.Block1.Words
S.Block1.Time
S.Block1.Data
.
.
.
S.BlockN.Sync
S.BlockN.Chan
S.BlockN.Chan
S.BlockN.ID
S.BlockN.Seq
S.BlockN.SS
S.BlockN.Words
S.BlockN.Time
S.BlockN.Data
The X's following the Time field are HEX characters. There is 64 characters in the first line, and 32 in the second.

The best approach for this problem depends on the size of your files. If you can read it in all at once, I would suggest the following approach using textscan()
% read file => stored in "data.txt"
fID = fopen(fullfile(cd, 'data.txt'), 'r');
tmp = textscan(fID, '%s');
fclose(fID);
lines = tmp{1};
% find rows with data. You might want to add some additional checks, or
% check whether the labels are indeed always in this order
chan_row = find(strcmpi(lines, 'Chan:'))+1; % could add a check here that the distance between the rows is all the same
% save in a table
tbl = table();
tbl.Chan = lines(chan_row);
tbl.ID = lines(chan_row+2);
tbl.Seq = lines(chan_row+4);
tbl.SS = lines(chan_row+6);
tbl.Words = lines(chan_row+8);
tbl.Time = lines(chan_row+10);
tbl.Data = lines(chan_row+12);
Note that I store the results in a table. This is likely much easier to process than your struct with the id number in the name. Per field, you might want to do some additional transformations, such as converting particular fields to categoricals.
If that is not feasible because the file is very large, you could try fopen() in combination with fgetl() to read in line-by-line instead.

If this is only a one time data capture rather than something that's actually part of your code, just ctrl-c the data in notepad, then in Matlab click on your variable workspace and ctrl-v. It should bring up a window that will let you import that data easily enough

Related

Matlab: read multiple files

my matlab script read several wav files contained in a folder.
Each read signal is saved in cell "mat" and each signal is saved in array. For example,
I have 3 wav files, I read these files and these signals are saved in arrays "a,b and c".
I want apply another function that has as input each signal (a, b and c) and the name of corresponding
file.
dirMask = '\myfolder\*.wav';
fileRoot = fileparts(dirMask);
Files=dir(dirMask);
N = natsortfiles({Files.name});
C = cell(size(N));
D = cell(size(N));
for k = 1:numel(N)
str =fullfile(fileRoot, Files(k).name);
[C{k},D{k}] = audioread(str);
mat = [C(:)];
fs = [D(:)];
a=mat{1};
b=mat{2};
c=mat{3};
myfunction(a,Files(1).name);
myfunction(b,Files(2).name);
myfunction(c,Files(3).name);
end
My script doesn't work because myfunction considers only the last Wav file contained in the folder, although
arrays a, b and c cointain the three different signal.
If I read only one wav file, the script works well. What's wrong in the for loop?
Like Cris noticed, you have some issues with how you structured your for loop. You are trying to use 'b', and 'c' before they are even given any data (in the second and third times through the loop). Assuming that you have a reason for structuring your program the way you do (I would rewrite the loop so that you do not use 'a','b', or 'c'. And just send 'myfunction' the appropriate index of 'mat') The following should work:
dirMask = '\myfolder\*.wav';
fileRoot = fileparts(dirMask);
Files=dir(dirMask);
N = natsortfiles({Files.name});
C = cell(size(N));
D = cell(size(N));
a = {};
b = {};
c = {};
for k = 1:numel(N)
str =fullfile(fileRoot, Files(k).name);
[C{k},D{k}] = audioread(str);
mat = [C(:)];
fs = [D(:)];
a=mat{1};
b=mat{2};
c=mat{3};
end
myfunction(a,Files(1).name);
myfunction(b,Files(2).name);
myfunction(c,Files(3).name);
EDIT
I wanted to take a moment to clarify what I meant by saying that I would not use the a, b, or c variables. Please note that I could be missing something in what you were asking so I might be explaining things you already know.
In a certain scenarios like this it is possible to articulate exactly how many variables you will be using. In your case, you know that you have exactly 3 audio files that you are going to process. So, variables a, b, and c can come out. Great, but what if you have to throw another audio file in? Now you need to go back in and add a 'd' variable and another call to 'myfunction'. There is a better way, that not only reduces complexity but also extends functionality to the program. See the following code:
%same as your code
dirMask = '\myfolder\*.wav';
fileRoot = fileparts(dirMask);
Files = dir(dirMask);
%slight variable name change, k->idx, slightly more meaningful.
%also removed N, simplifying things a little.
for idx = 1:numel(Files)
%meaningful variable name change str -> filepath.
filepath = fullfile(fileRoot, Files(idx).name);
%It was unclear if you were actually using the Fs component returned
%from the 'audioread' call. I wanted to make sure that we kept access
%to that data. Note that we have removed 'mat' and 'fs'. We can hold
%all of that data inside one variable, 'audio', which simplifies the
%program.
[audio{idx}.('data'), audio{idx}.('rate')] = audioread(filepath);
%this function call sends exactly the same data that your version did
%but note that we have to unpack it a little by adding the .('data').
myfunction(audio{idx}.('data'), Files(idx).name);
end

Saving data to .mat file in MATLAB

I'm new to MATLAB, and I can't manage to make my function work in order to save my data into a .mat file.
The input:
A structure, with 5 fields:
data: 3D matrix of 19x1000x143
labels: 1x143 matrix with 1 or -1 in it
subject_number: an integer
sampling_rate: an integer, 500 Hz
channel_names: 1x19 matrix with text in it
name: a string for the name of the file
clean: a matrix 1x143 with 1 or 0 in it.
The idea is to save only the clean data, marked as 1 in the clean matrix.
If clean(i) is equal to 1:
save data(:,:,i) and labels(:,i)
This is the code I've tried to implement in the saving.m file:
function saving(EEG_struct, clean, name)
subject_number = EEG_struct.subject_number;
fs = EEG_struct.sampling_rate;
chan_names = EEG_struct.channel_names;
nb_epoch = size(EEG_struct.data, 3);
for j=1:nb_epoch
if clean(j) == 1
% Keep the epoch and label
data = cat(3, data, EEG_struct.data(:,:,j));
labels = cat(2, labels, EEG_struct.labels(:,j));
end
end
save(name, data, labels, subject_number, fs, chan_names)
As you can see, I would like to save the data as a structure with the same shape as the EEG_struct input.
Moreover, I would like to use a parfor instead of a for, but it raised me an error I didn't quite get:
An UndefinedFunction error was thrown on the workers for 'data'. This might be because the file containing 'data' is not accessible on the workers. Use addAttachedFiles(pool, files) to specify the required files to be attached. See the documentation for 'parallel.Pool/addAttachedFiles' for more details. Caused by: Undefined function or variable 'data'.
Thanks for the help !
You can use your clean variable as a logical index and parse out your data and labels at once. So there is no need for a loop.
Also the save command needs the "names" of the vars to save not the variables themselves. So I just put ' ' around each one.
function saving(EEG_struct, clean, name)
subject_number = EEG_struct.subject_number;
fs = EEG_struct.sampling_rate;
chan_names = EEG_struct.channel_names;
nb_epoch = size(EEG_struct.data, 3);
%No need for a loop at all
data = EEG_struct.data(:,:,logical(clean));
labels = EEG_struct.labels(logical(clean)); %This is a 1xN so I removed the extra colon operator
save(name, 'data', 'labels', 'subject_number', 'fs', 'chan_names');
EDIT:
Per you comment if you want to just leave everything in the structure. I gave you 2 options for how to save it.
function saving(EEG_struct, clean, name)
%Crop out ~clead data
EEG_struct.data = EEG_struct.data(:,:,logical(clean));
EEG_struct.labels = EEG_struct.labels(logical(clean)); %This is a 1xN so I removed the extra colon operator
% Option 1
save(name, 'EEG_struct');
% Option2
save(name, '-struct', 'EEG_struct');
Option 1 will directly save the struct to the MAT file. So if you were to load the data back like this:
test = load(name);
test =
EEG_struct: [1x1 struct]
You would get your structure placed inside another structure ... which might not be ideal or require an extra line to de-nest it. On the other hand just loading the MAT file with no outputs load(name) would put EEG_struct into your current workspace. But if in a function then it sort of springs into existence without every being declared which makes code a bit harder to follow.
Option 2 uses the '-struct' option which breaks out each field automatically into separate vars in the MAT file. So loading like this:
EEG_struct = load(name);
Will put all the fields back together again. To me at least this looks cleaner when done within a function but is probably just my preference
So comment out which ever you prefer. Also, not I did not include clean in the save. You could either append it to the MAT or add it to your structure.
To get a structure the same as EEG_struct but with only the data/labels corresponding with the clean variable, you can simply make a copy of the existing structure and remove the rows where clean=0
function saving(EEG_struct, clean, name)
newstruct = EEG_struct;
newstruct.data(:,:,logical(~clean)) = '';
newstruct.labels(logical(~clean)) = '';
save(name,'newstruct');

extracting numeric data from text in data files in Matlab

I have a .txt data file which has a few rows of text comments in the beginning, followed by the columns of actual data. It looks something like this:
lens (mm): 150
Power (uW): 24.4
Inner circle: 56x56
Outer Square: 256x320
remarks: this run looks good
2.450000E+1 6.802972E+7 1.086084E+6 1.055582E-5 1.012060E+0 1.036552E+0
2.400000E+1 6.866599E+7 1.088730E+6 1.055617E-5 1.021491E+0 1.039043E+0
2.350000E+1 6.858724E+7 1.086425E+6 1.055993E-5 1.019957E+0 1.036474E+0
2.300000E+1 6.848760E+7 1.084434E+6 1.056495E-5 1.017992E+0 1.034084E+0
By using importdata, Matlab automatically separates the text data and the actual data . But how do I extract those numeric data from the text (which is stored in cells format)? What I want to do to achieve:
extract those numbers (e.g. 150, 24.4)
If possible, extract the names ('lens', 'Power')
If possible, extract the units ('mm', 'uW')
1 is the most important and 2 or 3 is optional. I am also happy to change the format of the text comments if that simplifies the codes.
Let's say your sample data is saved as demo.txt, you can do the following:
function q47203382
%% Reading from file:
COMMENT_ROWS = 5;
% Read info rows:
fid = fopen('demo.txt','r'); % open for reading
txt = textscan(fid,'%s',COMMENT_ROWS,'delimiter', '\n'); txt = txt{1};
fclose(fid);
% Read data rows:
numData = dlmread('demo.txt',' ',COMMENT_ROWS,0);
%% Processing:
desc = cell(5,1);
unit = cell(2,1);
quant = cell(5,1);
for ind1 = 1:numel(txt)
if ind1 <= 2
[desc{ind1}, unit{ind1}, quant{ind1}] = readWithUnit(txt{ind1});
else
[desc{ind1}, quant{ind1}] = readWOUnit(txt{ind1});
end
end
%% Display:
disp(desc);
disp(unit);
disp(quant);
disp(mat2str(numData));
end
function [desc, unit, quant] = readWithUnit(str)
tmp = strsplit(str,{' ','(',')',':'});
[desc, unit, quant] = tmp{:};
end
function [desc, quant] = readWOUnit(str)
tmp = strtrim(strsplit(str,': '));
[desc, quant] = tmp{:};
end
We read the data in two stages: textscan for the comment rows in the beginning, and dlmread for the following numeric data. Then, it's a matter of splitting the text in order to obtain the various bits of information.
Here's the output of the above:
>> q47203382
'lens'
'Power'
'Inner circle'
'Outer Square'
'remarks'
'mm'
'uW'
'150'
'24.4'
'56x56'
'256x320'
'this run looks good'
[24.5 68029720 1086084 1.055582e-05 1.01206 1.036552;
24 68665990 1088730 1.055617e-05 1.021491 1.039043;
23.5 68587240 1086425 1.055993e-05 1.019957 1.036474;
23 68487600 1084434 1.056495e-05 1.017992 1.034084]
(I took the liberty to format the output a bit for easier viewing.)
See also: str2double.

fortran, read command

I have a .dat file that I want to read with a program in Fortran 90. The data file contains only one very long column of complex numbers. My problem is that I want to read only one part of the column, e.g., only from the nth up to the mth element including, and create an one-dimensional array from it. However, if I write something like
open(unit = 100, file = 'datafile.dat', status = 'old', action = 'read')
do j = n,m
read(100,*) vec(j-n+1)
end do
close(100)
the program reads the first m-n+1 elements from my file and not the ones from n to m including. Is there any way to do what I want?
Well, there is an obvious solution - you can simply execute n-1 dummy reads before reading actual data:
open(unit = 100, file = 'datafile.dat', status = 'old', action = 'read')
do j = 1,n-1
read(100,*)
end do
do j = n,m
read(100,*) vec(j-n+1)
end do
close(100)
You can also use the / edit descriptor and condense the first loop into a single read statement:
nm2 = n-2
read(100,'(<nm2>/)')
do j = n,m
read(100,*) vec(j-n+1)
end do
(this is n-2 records are being skipped because of the <nm2>/ edit descriptor and one record is skipped by the dummy read)
With compilers that do not support the <x> format extension, you can construct the format descriptor in an internal file:
character(len=20) :: fmt
write(fmt, "('(',I0,'/)')") n-2
read(100,fmt)
do j = n,m
read(100,*) vec(j-n+1)
end do

How to export data from Matlab to excel for a loop?

I have a code for "for loop"
for i=1:4
statement...
y=sim(net, I);
end
now i need to export the value of y to excel sheet. for that i used..
xlswrite('output_data.xls', y, 'output_data', 'A1')
but my problem is that the ID of excel i.e. "A1" should change according to each iteration... in my case for iteration 1-> A1, iteration-> A2 and so on..
anybody please help me out ..
thanks in advance. for any assistance.. or suggestion..
You can store sim outputs in a vector (y(ii)) and save in the sheet with a single write. This is also more efficient since you perform a single bulk-write instead of many small writes.
Specify the first cell and y will be written starting from there.
last = someNumber;
for i=1:last statement... y(i)=sim(net, I); end
xlswrite('output_data.xls', y', 'output_data', 'A1');
If you prefer specify the range write ['A1:A',num2str(last)] instead of A1.
If you really want to write within the loop try:
for ii=1:last
...
y=sim(net, I);
xlswrite('output_data.xls', y, 'output_data', sprintf('A%d',ii));
end
You can also do for yourself what xlswrite does internally, which is interact using COM. I prefer to do this when I have a frequently used excel template or data file, because it allows for more control (albeit with more lines of code).
Excel = actxserver('Excel.Application');
Workbook = Excel.Workbooks.Open('myExcelFile.xlsx');
MySheet = Excel.ActiveWorkBook.Sheets.Item(1);
set( get(MySheet,'Range','A1:A10'), 'Value', yourValues);
...
invoke(Workbook, 'Save');
invoke(Excel, 'Quit');
delete(Excel);
This would allow you to save new data to new ranges without re-opening excel each time.
Even better would be to define an oncleanup function (as does xlswrite) to prevent lost file locks (especially when you're doing things like exiting out of debug mode):
...
myWorkbook = Excel.Workbooks.Open(filename,0,true);
cleanUp = onCleanup(#()xlsCleanup(Excel, filename));
function xlsCleanup(Excel,filepath)
try
Excel.DisplayAlerts = 0; %// Turn off dialog boxes
[~,n,e] = fileparts(filepath); %// Excel API expects just the filename
fileName = [n,e];
Excel.Workbooks.Item(fileName).Close(false);
end
Excel.Quit;
end
You can put xlswrite after for loop.You just want to do is save you result in a matrix.This function can write a matrix.
also,you can use [] to combine string to change the range.
>> for i=1:4
Range=['A' num2str(i)]
end
Range =
A1
Range =
A2
Range =
A3
Range =
A4
But,this is a bad way.You should open and write Excel file every time.