fortran, read command - fortran90

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

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

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.

MATLAB Parse Data file

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

Read specific portions of an excel file based on string values in MATLAB

I have an excel file and I need to read it based on string values in the 4th column. I have written the following but it does not work properly:
[num,txt,raw] = xlsread('Coordinates','Centerville');
zn={};
ctr=0;
for i = 3:size(raw,1)
tf = strcmp(char(raw{i,4}),char(raw{i-1,4}));
if tf == 0
ctr = ctr+1;
end
zn{ctr}=raw{i,4};
end
data=zeros(1,10); % 10 corresponds to the number of columns I want to read (herein, columns 'J' to 'S')
ctr=0;
for j = 1:length(zn)
for i=3:size(raw,1)
tf=strcmp(char(raw{i,4}),char(zn{j}));
if tf==1
ctr=ctr+1;
data(ctr,:,j)=num(i-2,10:19);
end
end
end
It gives me a "15129x10x22 double" thing and when I try to open it I get the message "Cannot display summaries of variables with more than 524288 elements". It might be obvious but what I am trying to get as the output is 'N = length(zn)' number of matrices which represent the data for different strings in the 4th column (so I probably need a struct; I just don't know how to make it work). Any ideas on how I could fix this? Thanks!
Did not test it, but this should help you get going:
EDIT: corrected wrong indexing into raw vector. Also, depending on the format you might want to restrict also the rows of the raw matrix. From your question, I assume something like selector = raw(3:end,4); and data = raw(3:end,10:19); should be correct.
[~,~,raw] = xlsread('Coordinates','Centerville');
selector = raw(:,4);
data = raw(:,10:19);
[selector,~,grpidx] = unique(selector);
nGrp = numel(selector);
out = cell(nGrp,1);
for i=1:nGrp
idx = grpidx==i;
out{i} = cell2mat(data(idx,:));
end
out is the output variable. The key here is the variable grpidx that is an output of the unique function and allows you to trace back the unique values to their position in the original vector. Note that unique as I used it may change the order of the string values. If that is an issue for you, use the setOrderparameter of the unique function and set it to 'stable'

Struggling to vertically append a string ( csv file) to an existing matrix in Scilab/matlab

M=read_csv("Gradesheets\MECN2073_2014.csv")
disp(size(M,1))
for x=1:1:size(M,1)
StudNum=M(x,1)
Grd=M(x,2) // Grd is grade column in gradesheets hence x,2 (column 2 of Grd )
if find(StudNum==StudentNumbers)>0 then disp("Exists")
H = [StudNum]
StudentNumbers = [StudentNumbers;StudNum]
end
end
This is where i get error:
Undefined operation for the given operands.
check or define function %s_f_c for overloading.
at line 38 of exec file called by :
I assume that StudentNumbers is the vector containing all your existing students right? If so, try the code below and let me know what you get.
M=read_csv("Gradesheets\MECN2073_2014.csv")
storing = [];
for i=1:size(M,1)
StudNum=M(i,1)
if find(StudNum==StudentNumbers(i)) == 1
disp("Exists");
storing = [storing;StudNum];
end
end