MATLAB : read data file in real time - matlab

I have an application, A, that writes to a File.
I want to use MATLAB to read N lines in realtime from this file.
My question is related to this stack post: How to plot real time data from text file in MATLAB
The author of one of the answers, mentions the following approach:
You can't plot using hard real time conditions, thus it can always happen that matlab misses a 10ms timeslot. You have to use option 2 to get all data.
To get started: Write a function which only reads the new data which was written since last call. To achieve this, do not close the file handle. It stores the position.
As such, here is my code:
myfile_fid=fopen(filePath, 'rt')
waitForFileToHaveData(filePath, 10);
for readingIdx = 1:10
fgetl(myfile_fid)
end
My waitForFileToHaveData function, is defined as follows:
function waitForFileToHaveData(filePath, desired_length)
if (getNumLinesOfFile(filePath) < desired_length)
disp('###### not enough data in the file');
pause(0.02);
waitForFileToHaveData(filePath, desired_length);
end
end
function num = getNumLinesOfFile(file_to_read)
[status, result] = system( ['wc -l ', file_to_read] );
if(status~=1)
scanCell = textscan(result,'%u %s');
num = scanCell{1} - 2;
else
num = 0;
end
end
Result:
When I get into the for loop, myfile_fid evaluates to 3, while fgetl(myfile_fid) evaluates to -1. If I print out the results of getNumLinesOfFile(filePath), I see 20. The odd part is that if I wait, say for the file to have 40 lines, and execute the code above, I do not get the error. I tried to look at the documentation to see why fgetl returns back -1, but I cannot seem to find it in 2018b MATLAB documentation. There is mention that the myfile_fid can return a -1, but that is only if the file cannot be opened. However, at runtime, myfile_id evaluates to 3.
Using MATLAB, is it possible to read N number of lines since last read in a file that is being written to by another application?

fgetl returns -1 when fileID reaches the end-of-file marker, See Matlab fgetl documentation. This means that if the first result from fgetl is -1 then the file is empty.
I'm not sure why you are getting -1 if getNumLinesOfFile returns 20, check the code carefully if you are reading the same file. Maybe the file has changed?
I wrote here MATLAB code that checks if 10 new lines were added and and then gets them with fgetl:
myfile_fid = fopen(filePath, 'rt');
newLines = 10;
linesRead = 0;
while(waitForFileToHaveData(filePath, linesRead + newLines))
linesRead = linesRead + newLines;
for readingIdx = 1:newLines
line = fgetl(myfile_fid)
end
end
fclose(myfile_fid);
I updated the waitForFileToHaveData function to return 1:
function ready = waitForFileToHaveData(filePath, desired_length)
while (getNumLinesOfFile(filePath) < desired_length)
disp('###### not enough data in the file');
pause(0.02);
end
ready = 1;
end
Note:
If the file had exactly 10 lines with no end-line marker at line 10, and you read them, then another 10 lines were added, fileID now points to the end-line of line 10 and the first line fgetl will return is the end-line at line 10, but since fgetl removes the end-line, it returns an empty array.
Side note:
the function waitForFileToHaveData uses recursion which is inefficient. You can easily use a while loop.

Related

Problems using Matlab function eps2pdf

I have a Matlab script where I produce a figure, and then create an eps file in my current directory using the command
print('myFile','-depsc'). Immediately following, I have: mypdf = eps2pdf('myFile').
I get the error message that 'Error while creating temporary eps file: ..... cannot be accessed or does not exist'.
Has anyone had a similar problem? Any suggestions what I might be doing wrong? I'm using Ubuntu and Matlab 2017a.
Here is an example code that I type into the command line. I get the error message which I stated above.
figure()
plot(linspace(1,100),linspace(1,100)) %Simple line
print('my_plot','-depsc') %Create eps file.
mypdf = eps2pdf('my_plot'); %Should produce mypdf in my current directory.
<error message prints>
This isn't a standard function. If you read the function you will see errStr that it returns for this.
function [ok,errStr] = read_epsfilecontent( epsFile )
% Reads the content of the eps file into epsFileContent
global epsFileContent
ok = 0;
errStr = [];
fh = fopen(epsFile,'r');
if fh == -1
errStr = ['File: ' epsFile ' cannot be accessed or does not exist'];
return
end
Then we figure out when fopen returns -1
fileID = fopen(filename) opens the file, filename, for binary read
access, and returns an integer file identifier equal to or greater
than 3. MATLABĀ® reserves file identifiers 0, 1, and 2 for standard
input, standard output (the screen), and standard error, respectively.
If fopen cannot open the file, then fileID is -1.
Which means please post some of your code so we can figure out why it cannot open your file.
Edit: After some work around and it wasn't necessary to download the code this is how I solved your problem. There is another implementation called eps2xxx
While running your code I received this error
Error while creating temporary eps file: *.eps - File:
C:\Users\Ryan\Documents\MATLAB*.eps cannot be accessed or does not
exist
Which lead me to the information in the documentation here.
% Create tmp file,...
[ok,errStr] = create_tmpepsfile(source,tmpFile,orientation);
if ~ok
status = ['Error while creating temporary eps file: ' epsFile ' - ' errStr];
if nargout, result = 1; end;
if nargout > 1, msg = status; else, disp(status); end;
And I read you needed GhostScript, I wasn't sure if I had this anyways. I downloaded it and gave the full pathway to GS like the following.
figure()
fullgspath = 'C:\Program Files\gs\gs9.23\bin\gswin64c.exe';
plot(linspace(1,100),linspace(1,100)); %Simple line
print('my_plot','-depsc');
eps2xxx('my_plot.eps',{'pdf'},fullgspath);
which created your nice little pdf here.

How to print and save result of a Table in a text format in a loop?

result 'output1' 'output2'
result1 [1.0000] [0.0182]
counter [ 2] [ 0]
percentage [ 4] [ 7]
I have an output stored in a table (T), I want to print all my 200 loop results in just one text file. I already tried with writetable function and always have a problem, the output overwrite the previous output.
fid = fopen(filename,'w');
for i = 1:200
writetable(T,'finalresult.txt','Delimiter','\t','WriteRowNames',true);
end
fclose(fid);
the output should be like this:
result 'output1' 'output2'
result1 [1.0000] [0.0182]
counter [ 2] [ 0]
percentage [ 4] [ 7]
result 'output1' 'output2'
result1 [0.0182] [1.0000]
counter [ 3] [ 0]
percentage [ 4] [ 7]
and so on for all the outputs i = 200
Per MATLAB's documentation for writetable, this is the default behavior.
If filename is the name of an existing text file, then writetable overwrites the file.
This gives you two options: create your own export routine or overload MATLAB's with the desired behavior. Let's look at the latter.
Warning: Modifying default MATLAB behavior can lead to unexpected results and errors. Take care to modify only copies of MATLAB's default files so you can revert MATLAB's state when you are finished.
Fortunately for us, the source code for table and its related methods are currently open so you can use open to read them and understand their behavior. We see that writetable is a thin wrapper for the undocumented table.write, which parses the input arguments and makes the determination whether or not to write to a text file or to a spreadsheet. For the text case MATLAB calls the writeTextFile function (again, undocumented) which handles writing table data to a text file.
If you look at line 25, you will see that MATLAB opens the file for writing as follows:
% Open the file for writing
[fid,errmsg] = fopen(file,'Wt'); % text mode: CRLF -> LF
Per the documentation for fopen this opens the file for writing ('W'), which will discard any existing contents. Saving a copy of writeTextFile and changing the fopen call to append data rather than overwrite it should give the desired behavior.
% Open the file for writing
fprintf('!!! Using overloaded writeTextFile D:\n%s\n', mfilename('fullpath'));
[fid,errmsg] = fopen(file,'At'); % text mode: CRLF -> LF
Per MATLAB's Function Precedence Order, Private or Object functions take precedence over functions in MATLAB's path, so we need to place this modified file in the same location as the original. You can find this location this using which -all:
>> which writeTextFile -all
C:\excaza\writeTextFile.m
C:\Program Files\MATLAB\R2016b\toolbox\matlab\datatypes\#tabular\writeTextFile.m % tabular method
You should see your saved copy and MATLAB's built-in version. You should now rename the built-in function (e.g. writeTextFile_builtin.m) and copy your modified version of the file into the folder. Run a clear all once to clear any memory cached version of the function.
We can now test to see if we've achieved the desired result:
filename = 'test.txt';
var1 = 1;
var2 = 2;
T1 = table(var1, 'RowNames', {'hi'});
T2 = table(var2, 'RowNames', {'hi'});
writetable(T1, filename)
writetable(T2, filename)
Which returns the following test.txt:
Row var1
hi 1
Row var2
hi 2
When you are done, be sure to revert the changes you made to the built-in.
a1=0.1;
a2=0.2;
opt =fopen('test.txt','a');
for i=1: size(t,1)
j=1;
if(i==1)
s=strcat('\n','result','\t',t(i,j),'\t',t(i,j+1),'\n');
s=s{1};
end
if (i==2)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','result1','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==3)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','counter','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==4)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','counter1','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==5)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','percentage','\t',num2str(s1),'\t',num2str(s1),'\n');
end
fprintf(opt,s);
end
the output will be like this
result output1 output2
result1 1.0000 0.0182
counter 1 1
counter1 0 0
percentage 0 0
I solved it without doing any function modification. #Brian thank you for the answer, and clear explanation.

How to fix error: "A(I): index out of bounds; value 1 out of bound 0"

So I made this function, but I don't know why I'm getting this error. How can I fix it?
error: LOADC: A(I): index out of bounds; value 1 out of bound 0
error: called from
LOADC at line 15 column 13
function res=LOADC(url)
[nomeFicheiro,sucesso]= urlwrite(url,'Composicoes.txt');
ficheiro=fopen(nomeFicheiro,'r');
fgetl(ficheiro);
nLinhas=0;
while (fgets(ficheiro) ~= -1)
nLinhas = nLinhas+1;
end
for i=2:nLinhas
linha=fgetl(ficheiro);
pontovirgula=findstr(linha,';');
Material=linha(1:pontovirgula(1)-1);
for n=1:2:length(pontovirgula)
ElemX=linha(pontovirgula(n)+1:pontovirgula(n+1)-1);
PercentX=linha(pontovirgula(n+1)+1:pontovirgula(n+2)-1);
end
end
fclose(ficheiro);
res=Composicoes;
end
The immediate is you're trying to access a value within an empty array (which has no values in it).
The reason that this is happening is that you read your entire file inside of your first while loop which places the file pointer at the end of the file. Then (without resetting the file pointer), you try to read it line by line in the for loop. Since the file pointer is at the end of the file already, fgetl will always return an empty array ([]) so when you start trying to work with it, you get the indexing error that you've shown.
The solution is one of two options:
Call frewind(ficheiro) before the for loop to reset the file pointer to the beginning of the file so that you can successfully read each line.
Come up with a better way to parse your file rather than looping through the whole file for the sole purpose of counting the number of lines in the file.
If you post some of the file contents we can likely provide you with a better way to parse the file in one or two lines of code.
Update
Also if you look at this line, n goes all the way to the end of pontovirgula.
for n = 1:2:length(pontovirgula)
But then you try to access 1 and 2 past the end of the array
pontovirgula(n+1)
pontovirgula(n+2)
This is going to cause issues for sure. Try only looping until 2 from the end instead.
for n = 1:2:(numel(pontovirgula) - 2)
Update 2
Given that you have posted the file contents, here is an alternate way to parse the file.
fid = fopen('filename.txt', 'rt');
lines = textscan(fid, '%s', 'HeaderLines', 1);
fclose(fid);
% For each line we want to get the reference off of the front
parts = regexp(lines{1}, ';', 'split');
materials = cell(1, numel(parts));
elements = cell(1, numel(parts));
percentages = cell(1, numel(parts));
for k = 1:numel(parts)
% Remove the last empty blank
parts{k}(end) = [];
% Get the material (the first element)
materials{k} = parts{k}{1};
% Get the elements
elements{k} = parts{k}(2:2:end);
% Get the percents
percents{k} = parts{k}(3:2:end);
end
Check the length of linha, and the values of pontovirgula that you are using to index into linha.

Trying to use fopen and fprintf with matlab, only writing once

I'm having trouble writing to a file here... I must be making a simple mistake but I can't find it. Anyways, here's the code:
ages = 1;
while (ages > 0)
fileID = fopen('age.txt', 'w'); %opens file
ages = input('Enter an age (negative to quit): '); %user input
if(ages > 0) %so it doesn't add on the break number
fprintf(fileID, '%d\r\n', ages);
end
end
fclose(fileID);
My problem is that it writes nothing to the file. If I remove the if statement it writes only -1 to the file (using -1 as the negative 'quit' number).
What am I missing?
Easy,
Your fopen command is inside the loop ... so each time "it opens file for writing and discard existing contents, if any" (w mode).
Put fopen outside while loop.

How can I read a simple txt file in Matlab in the fortran way (i.e. I want to keep reading after the newline)

I have to read the simple text file I write on the end of this post (it is just a sctructured grid). In fortran it is so easy to do this, you just have to do:
read(fileunit,*)
read(fileunit,*) mc,nc
do j = 1, nc
read (fileunit, *) dummy, dummy, (xcor(j,i), i=1,mc)
enddo
is there an equivalent function in matlab that reads element by element and keeps reading after the newline like in fortran? I could not find it, all the function as fscanf, textscan etc read line by line and then i have to parse each line. Here is the file. thanks for any help A.
Gridfile version 8.675.44
8 3
eta= 1 0.00000000000000000E+00 1.50000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 2 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 3 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
There are many ways to do this, but perhaps you will like the way fscanf works, as in this example. After the file is opened by something like fin = fopen('gridfile.txt') and the header swallowed, you can use fscanf(f, 'x= %d'), and then fscanf(f, '%f'), which will read the entire block. fscanf does not stop at the end of a line if not instructed to do so. Taken together, a solution could look like
fin = fopen('gridfile.txt');
fgetl(fin);
% read data counts
cnt = fscanf(fin, '%d %d', 2);
mc = cnt(1);
nc = cnt(2);
xcor = zeros(nc, mc);
% read blocks of data
for j = 1 : nc
fscanf(fin, '%s %s', 2);
xcor(j, :) = fscanf(fin, '%f', mc)';
end
fclose(fin);
fscanf keeps matching the format specifier as long as possible, and returns only when no further consecutive matches can be found. The above examples uses this in two places. First, to extract the dimensionality cnt, in your example (8, 3), and second, to read eight consecutive floating point values per record.