How to update app designer GUI in real time at high refresh rate without stutter/lag?
22 views (last 30 days)
Show older comments
I'm currently working on an application that simulates a medical monitor. I designed a GUI in matlab's app designer which 1) shows the 6 graphs/signals and 2) provides the controls to adjust those signals. A few simple functions have been implemented to simulate e.g. an ECG signal. I use a timer object within the app to call a function that 1) refreshes the current signal values and 2) plots the new signals in the GUI axes. It is currently working at a refresh rate of 20 Hz (way too low) and a physiological model to be used to replace the current 'simple functions' is yet to be implemented.
However, I'm already running into a problem that the application becomes too slow, shortly after starting up. The timer seems unable to maintain the desired refresh rate, resulting in stuttering or 'lag' in the displaying of the signals. The controls become slow to respond as well or even stop responding altogether.
The problem is so bad I'm currently debating rewriting everything in another language (maybe Java or C++), even though I have virtually no experience with those.
If anyone has an idea of how to solve this, I'd be very grateful to hear it.
To give an idea of what the (simplified) code for the primary function looks like:
function Timer = timed_dash(app)
% Function to create and start the main timer needed for real-time simulation
Timer = timer('ExecutionMode','fixedRate','Period',app.period);
Timer.TimerFcn = {@app.myfun};
% <snip>...lots of one time variable creation...<snip>
start(Timer);
end
function myfun(app, ~, ~)
% Main Function called by timer to run / plot everything
% Is ECG connected?
if app.ConnectECGButton.Value % Yes
app.ECGplot(app.shortcounter)=func_ECG(app.t(app.longcounter));
app.HRplot(app.longcounter)=app.HR+random('Normal', 0,.3);%+2*sin(app.t(app.longcounter)*pi);
app.RFplot(app.longcounter)=app.RF+2*random('Normal', 0,.1);
app.Respplot(app.medcounter)=.6*sin(2*pi*app.RF/60*app.t(app.longcounter)); % temporary demo func
% Adjust current value for numeric display of monitor data
app.RFText.Value = sprintf('%d',round(app.RFplot(app.longcounter)));
app.HRText.Value = sprintf('%d',round(app.HRplot(app.longcounter)));
else % No
app.ECGplot(app.shortcounter)=0;
app.Respplot(app.medcounter)=0;
app.HRplot(app.longcounter)=0;
app.RFplot(app.longcounter)=0;
% Adjust current value for numeric display of monitor data
app.RFText.Value = '0';
app.HRText.Value = '0';
end
if app.loopshortcounter
plot(app.ECGAxes,app.t(1:app.shortcounter),app.ECGplot(1:app.shortcounter),'-g','LineWidth',2)
plot(app.PlethAxes,app.t(1:app.shortcounter),app.Plethplot(1:app.shortcounter),'-c','LineWidth',2)
else
plot(app.ECGAxes,app.t(1:app.shortcounter),app.ECGplot(1:app.shortcounter), '-g',app.t(app.shortcounter+3:app.endshortcounter+3),app.ECGplot(app.shortcounter+3:end),'-g','LineWidth',2)
plot(app.PlethAxes,app.t(1:app.shortcounter),app.Plethplot(1:app.shortcounter),'-c',app.t(app.shortcounter+3:app.endshortcounter+3),app.Plethplot(app.shortcounter+3:end),'-c','LineWidth',2)
end
if app.loopmedcounter % Resp loop
plot(app.RespAxes,app.t(1:app.medcounter),app.Respplot(1:app.medcounter),'-y','LineWidth',2)
else
plot(app.RespAxes,app.t(1:app.medcounter),app.Respplot(1:app.medcounter),'-y',app.t(app.medcounter+3:app.endmedcounter+3),app.Respplot(app.medcounter+3:end),'-y','LineWidth',2)
end
if app.looplongcounter
plot(app.RFAxes,app.t(1:app.longcounter)./60-10,app.RFplot(1:app.longcounter),'-y','LineWidth', 2)
plot(app.SpO2Axes,app.t(1:app.longcounter)./60-10,app.SpO2plot(1:app.longcounter),'-c','LineWidth', 2)
plot(app.HRAxes,app.t(1:app.longcounter)./60-10,app.HRplot(1:app.longcounter),'-g','LineWidth', 2)
else
plot(app.RFAxes,app.t(1:app.longcounter)./60-10,app.RFplot(1:app.longcounter), '-y',app.t(app.longcounter+3:end),app.RFplot(app.longcounter+3:end),'-c', 'LineWidth',2)
plot(app.SpO2Axes,app.t(1:app.longcounter)./60-10,app.SpO2plot(1:app.longcounter), '-c',app.t(app.longcounter+3:end),app.SpO2plot(app.longcounter+3:end),'-y', 'LineWidth',2)
plot(app.HRAxes,app.t(1:app.longcounter)./60-10,app.HRplot(1:app.longcounter), '-g',app.t(app.longcounter+3:end),app.HRplot(app.longcounter+3:end),'-c', 'LineWidth',2)
end
% Update counters & reset when necessary.
if app.shortcounter==app.endshortcounter
app.shortcounter=1;
if app.loopshortcounter
app.loopshortcounter=false;
end
else
app.shortcounter=app.shortcounter+1;
end
if app.medcounter==app.endmedcounter
app.medcounter=1;
if app.loopmedcounter
app.loopmedcounter=false;
end
else
app.medcounter=app.medcounter+1;
end
if app.longcounter==app.endlongcounter
app.longcounter=1;
if app.looplongcounter
app.looplongcounter=false;
end
else
app.longcounter=app.longcounter+1;
end
end
0 Comments
Answers (1)
Jan
on 31 Aug 2017
Edited: Jan
on 31 Aug 2017
Do I see correctly that you create a new set of plot's in each timer callback? This is rather inefficient. Prefer to create the line object once and update the XData and YData afterwards.
Search for "XData" or "animation" in this forum or in the net to see many examples.
3 Comments
See Also
Categories
Find more on Whos in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!