Plotting in a parallel while reading serial
Mostrar comentarios más antiguos
Hi there,
I have the following code (which I have simplified a bit to post).
It captures the position and force from a test rig, which I am printing out over serial as fast as possible and reading into matlab.
It grabs the most recent reading from each serial device and stores it along with the current time (using tic toc).
I then plot this data on a graph.
My problem is that while matlab is executing the plot I miss some new incoming serial data and build up a back log.
I have improved the situation by only plotting every 50 times i collect data, but this still allows a buildup to occur during plotting. Can i carry out the plot in a parallel thread to avoid affecting the serial reads? How would i structure this?
Thanks!
positioncounter=0;
forcecounter=0;
tic
while running==1
if rig.bytesavailable>0 %grab rig position and time
positioncounter=positioncounter+1;
position = fscanf(rig);
ResultsPosition(positioncounter,1)= toc;
ResultsPosition(positioncounter,2)=str2double(position(1:end-2));
end
if s.bytesavailable>0 %grab force and time
forcecounter=forcecounter+1;
force = fscanf(s);
ResultsForce(forcecounter,2)=9.81*str2double(force(1:end-2));
ResultsForce(forcecounter,1)= toc;
end
try
yyaxis left
plot(ResultsForce(:,1),ResultsForce(:,2));
yyaxis right
plot(ResultsPosition(:,1),ResultsPosition(:,2));
end
running =get(handles.BTN_CAPTURE,'Value'); %is button still toggled on
drawnow();
end
8 comentarios
Walter Roberson
el 7 de Jun. de 2019
No. The graphic display cannot be affected by any parallel thread.
You would have to do the plotting in the client, but you could potentially do the data collection in a parallel thread. However, there will be overhead in making the data available between processes, and so there is risk of similar build-up.
You shoud look in the File Exchange for "shared array": it can be used to share data between processes.
If you have the Parallel Computing Toolbox then
doc batch
may help, though it is one of those things I have often wanted to look into to see where it could be useful but have never had the time. Theoretically it lets you run a Matlab script or function on a worker, but plotting is not generally possible in parallel. I'm not sure if it would work in this case or not though or what the syntax would be. Maybe you can run the code that collects the data in this way and keep the plotting in the main thread, but I don't know.
Walter Roberson
el 7 de Jun. de 2019
Communication back to the thread doing the plotting becomes an issue at high speed.
The problem can be reduced by using a BytesAvailableFcn callback to read available data instead of doing polling, and possibly adjusting the buffer size.
Steven Brace
el 7 de Jun. de 2019
Walter Roberson
el 7 de Jun. de 2019
You need to be able to plot with accurate timestamps, but you do not need to compute with them in real-time.
This suggests that you should consider doing data collection with an NI chassis that will timestamp samples for you, or else that you should consider doing data collection with an Arduino or Raspberry Pi and have those add timestamps before sending the data on to MATLAB.
Steven Brace
el 8 de Jun. de 2019
Walter Roberson
el 8 de Jun. de 2019
Are you using true serial, or are you using serial over USB ?
There is an arduino-like device that sends data direct to USB instead of buffering it, and so can achieve higher data rates. Unfortunately I keep losing track of which device it is.
Adam
el 10 de Jun. de 2019
Do you need or want every point to be its own plot, as is in your code included in the question? This is, in general, an expensive way to plot data. Much more efficient is to create one plot and then edit its XData and YData properties to add your new data.
e.g.
yyaxis left
hPlotForce = plot(ResultsForce(:,1),ResultsForce(:,2));
yyaxis right
hPlotPosition = plot(ResultsPosition(:,1),ResultsPosition(:,2));
for the first point, then
set( hPlotForce, 'XData', [ hPlotForce.XData, ResultsForce(:,1) ], 'YData', [ hPlotForce.YData, ResultsForce(:,2) ] );
set( hPlotPosition, 'XData', [ hPlotPosition.XData, ResultsPosition(:,1) ], 'YData', [ hPlotPosition.YData, ResultsPosition(:,2) ] );
on each subsequent pass.
Normally I do this by storing a handle to the initially empty plot e.g.
hPlotForce = [];
then in my code I have an if else
if isempty( hPlotForce )
...
else
...
end
where the first code above goes in the if and the second block of code in the else - i.e. if the plot hasn't been created yet then call plot, if it has then edit the existing plot.
Sometimes simply speeding up the way you plot solves the problems itself without you needing to come up with complex parallelisation. It may not in this case, I don't know, but calls to plot are expensive and create a new graphics object every time and the more individual graphics objects you have the slower your code is generally.
Respuestas (0)
Categorías
Más información sobre Graphics Performance en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!