passing a file to the timer function

7 vues (au cours des 30 derniers jours)
Patrick Lydon
Patrick Lydon le 2 Août 2017
Modifié(e) : Jan le 4 Août 2017
Hi, I am having trouble with my program. I am receiving data from 8 channels in one file. At the beginning of the program, I open up the file and parse through it, making an array for each of the channels. Then I plot these values on one graph. Every 100ms the data is updated. I would like for my graph to update as my data is updated. I am using a timer function to try to accomplish this. Everytime the timer function is called, it opens the updated file, parses through the data, makes the 8 arrays for the 8 channels, then updates the graphs and repeats repeats repeats.
The problem I am currently having is that after the first callback of the timer, the command window says "Reference to a cleared variable filetoRead." So obviously the file has been cleared and its trying to read a cleared file. How do I pass the "filetoRead" to the callback function. I tried using UserData but this didnt seem to work. Is there an easier way to refresh the file that i had once previously opened? I have asked this question two times before on the forum and no one answered it for me.
  3 commentaires
Patrick Lydon
Patrick Lydon le 2 Août 2017
Hi, I am writing it as a script. data is being appended on the file, from a different computer that is actually recording the data and then the file is spooled over to my computer. I will post my code, but here is a snippet of the beggining where i get the file then make a timer object.
filetoRead=varargin;
%Prompt for filename if blank
if isempty(filetoRead);
%Prompt the user for the file
[filetoRead,pathname]=uigetfile({'*.dat','All Files (*.dat)'},'Choose a Binary Data File');
if filetoRead==0;
return
end
filetoRead=fullfile(pathname,filetoRead);
end
%Get Filesize so it can be parsed correctly
fileInfo = dir(filetoRead);
FileSize = fileInfo.bytes;
%Openf File with fpopen(filetoRead,r,b) where r=readonly; b=BIG Endian
fid = fopen(filetoRead,'r','b');
TimerH = timer('Period', 0.1, 'ExecutionMode', 'fixedRate', ...
'TimerFcn', @TimerCallback, 'UserData', filetoRead);
here is the very beginning of my callback function
start(TimerH);
function TimerCallback(TimerH, EventData)
fid = fopen(filetoRead,'r','b');
Patrick Lydon
Patrick Lydon le 3 Août 2017
Anyone able to offer some assisitance? Please, any help will be much appreciated

Connectez-vous pour commenter.

Réponse acceptée

Jan
Jan le 3 Août 2017
Modifié(e) : Jan le 3 Août 2017
The shown code contains several problems:
  • You have some variables with an index hidden in the name. This requires to create a lot of redundant code, instead of using a smart loop with using a real indexed array:
assignin('base','channel1',channel1);
  • In addition the "remote controlled" creation of variables in the base workspace suffers from the same problems as global variables.
  • Both together decreases the readability of the code such massively, that I cannot see the intention anymore and would not dare to edit the code in consequence.
  • Some code parts can be massively simplified:
y2=zeros(1,NDataPoints);
ind=1;
for p=1:NDataPoints;
y2(1,ind)=channel2(1,p);
ind=ind+1;
end
What about:
y2 = channel2(1, 1:NDataPoints);
or even:
y2 = channel2; % Because channel2 is a [1 x NDataPoints] vector already
  • In the timer callback, the variable "filetoRead" does not exist at all. You should get an error message:
function TimerCallback(TimerH, EventData)
fid = fopen(filetoRead,'r','b');
...
Or is this a nested function? Then the darn clear all at the end of the main function would kill the contents. Note that clear all is junk at all, because it removes all functions loaded to memory and the reloading from disk wastes a lot of time. Simply omit this.
Then access the UserData of the timer, because you have defined it already:
TimerH = timer('Period', 0.1, 'ExecutionMode', 'fixedRate', ...
'TimerFcn', @TimerCallback, 'UserData', filetoRead);
% And then in the Timer's callback:
function TimerCallback(TimerH, EventData)
filetoRead = get(TimerH, 'UserData');
fid = fopen(filetoRead,'r','b');
  • Defining the Timer callback as nested function might have advantages, if shared variables are used. But here I do not see a reason for this. Better move the callback to an own function. Store the handles of the plot's either in the Timer's UserData, or by guidata in the figure.
  • If you import the complete file repeatedly, you will get timing problems: 0.1 seconds is short for reading a growing file. The import method looks quite confusing and due to the lack of comments, it is hard to guess the intention.
  • If you read a file simultaneously with another process writing to it, you cannot be sure to catch the correct end of file. This is a racing condition and it will fail from time to time.
  • Most of all: clean up the code and remove the hidden indices in the names.
  • Use a proper code intentation: Ctrl-a Ctrl-i
  • There are no semicolons behind for, end, case, switch, otherwise.
  4 commentaires
Patrick Lydon
Patrick Lydon le 4 Août 2017
I am also having troubles passing the handles of the plots through the user data. If I understand correctly, you can only pass one object throguh the user data. How do I send 8 plot handles AND the data file "filetoRead".
Jan
Jan le 4 Août 2017
Modifié(e) : Jan le 4 Août 2017
Do not use "a1", "a2", ... as set of variables, but a vector a with different indices a(1), a(2), ... In your case replace this:
channel1 = zeros (1,NDataPoints,'double');
channel2 = zeros (1,NDataPoints,'double');
channel3 = zeros (1,NDataPoints,'double');
channel4 = zeros (1,NDataPoints,'double');
channel5 = zeros (1,NDataPoints,'double');
channel6 = zeros (1,NDataPoints,'double');
channel7 = zeros (1,NDataPoints,'double');
channel8 = zeros (1,NDataPoints,'double');
by:
channel = zeros(NDataPoints, 8);
Then your old "channel7" is "channel(:, 7)", which can be processed in a loop easily. (Note that I have transposed the array, because Matlab stores arrays in columnwise order and processing neighboring elements is faster.)
Instead of
for k=1:NDataPoints;
channel8(1,k)=temp_dbl(k);
end
Write:
channel(:, 8) = temp_dbl;

Connectez-vous pour commenter.

Plus de réponses (1)

KL
KL le 3 Août 2017
You need to get the UserData from the timer object inside your timer function.
filetoRead = get(TimerH, 'UserData');

Catégories

En savoir plus sur Graphics Objects dans Help Center et File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by