How to update app designer GUI in real time at high refresh rate without stutter/lag?
21 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Camile van der Heijden
am 31 Aug. 2017
Kommentiert: Camile van der Heijden
am 22 Feb. 2018
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 Kommentare
Antworten (1)
Jan
am 31 Aug. 2017
Bearbeitet: Jan
am 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 Kommentare
Siehe auch
Kategorien
Mehr zu Whos finden Sie in Help Center und File Exchange
Produkte
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!