Boost refresh rate of App Designer UI elements
Asked Answered
R

4

7

I am currently trying to display data that I receive via serial port in a Matlab app designer application. I am suffering from abysmal refresh rate of the linear gauges (~1 Hz).

The gauges' values are updated by a fixed-rate timer which is set to 30Hz. A timestamp print in the timer callback shows me that it is called with the correct frequency. My computer is quite beefy and the Task Manager doesn't show any hints of high load - in fact, the MATLAB app consumes almost no CPU time at all. It's actually not just the gauges but all UI elements.

So my guess - or better: my hope - is that there must be some hard cap on the refresh rate. The official documentation doesn't give any hints about how to change this, though.

My MATLAB version is R2016b.

So my question(s):

  • Is this fixed with R2017a?

  • If not: can I do something about it, i.e. fiddling with MATLAB builtin files?

Here's a MCV example demonstrating the issue:

classdef testapp < matlab.apps.AppBase

% Properties that correspond to app components
properties (Access = public)
    UIFigure                  matlab.ui.Figure
    andwatchhowthisstartstospinsmoothlyGaugeLabel  matlab.ui.control.Label
    andwatchhowthisstartstospinsmoothlyGauge  matlab.ui.control.SemicircularGauge
    KeepturninghereKnobLabel  matlab.ui.control.Label
    KeepturninghereKnob       matlab.ui.control.Knob
end


properties (Access = private)
    tim_the_timer
    i = 0;
end

methods (Access = private)
    function app = refreshMeter(app, ~,~)
        % display timestamp
        datestr(now,'HH:MM:SS.FFF')

        % update the gauge
        app.andwatchhowthisstartstospinsmoothlyGauge.Value = app.i;
        app.i = app.i + 1;
        if app.i > 100
           app.i = 0;
        end
    end
end


methods (Access = private)

    % Code that executes after component creation
    function startupFcn(app)
       t = timer;
       t.TimerFcn = @app.refreshMeter;
       t.Period = 0.02;
       t.BusyMode = 'drop';
       t.ExecutionMode = 'fixedRate';
       start(t);
       app.tim_the_timer = t;
    end

    % Close request function: UIFigure
    function UIFigureCloseRequest(app, event)
        stop(app.tim_the_timer);
        delete(app.tim_the_timer);
        delete(app);
    end
end

% App initialization and construction
methods (Access = private)

    % Create UIFigure and components
    function createComponents(app)

        % Create UIFigure
        app.UIFigure = uifigure;
        app.UIFigure.Position = [100 100 640 480];
        app.UIFigure.Name = 'UI Figure';
        app.UIFigure.CloseRequestFcn = createCallbackFcn(app, @UIFigureCloseRequest, true);
        setAutoResize(app, app.UIFigure, true)

        % Create andwatchhowthisstartstospinsmoothlyGaugeLabel
        app.andwatchhowthisstartstospinsmoothlyGaugeLabel = uilabel(app.UIFigure);
        app.andwatchhowthisstartstospinsmoothlyGaugeLabel.HorizontalAlignment = 'center';
        app.andwatchhowthisstartstospinsmoothlyGaugeLabel.Position = [275 138 246 15];
        app.andwatchhowthisstartstospinsmoothlyGaugeLabel.Text = '... and watch how this starts to spin smoothly';

        % Create andwatchhowthisstartstospinsmoothlyGauge
        app.andwatchhowthisstartstospinsmoothlyGauge = uigauge(app.UIFigure, 'semicircular');
        app.andwatchhowthisstartstospinsmoothlyGauge.Position = [338 168 120 65];

        % Create KeepturninghereKnobLabel
        app.KeepturninghereKnobLabel = uilabel(app.UIFigure);
        app.KeepturninghereKnobLabel.HorizontalAlignment = 'center';
        app.KeepturninghereKnobLabel.Position = [119 265 112 15];
        app.KeepturninghereKnobLabel.Text = 'Keep turning here...';

        % Create KeepturninghereKnob
        app.KeepturninghereKnob = uiknob(app.UIFigure, 'continuous');
        app.KeepturninghereKnob.Position = [145 314 60 60];
    end
end

methods (Access = public)

    % Construct app
    function app = testapp()

        % Create and configure components
        createComponents(app)

        % Register the app with App Designer
        registerApp(app, app.UIFigure)

        % Execute the startup function
        runStartupFcn(app, @startupFcn)

        if nargout == 0
            clear app
        end
    end

    % Code that executes before app deletion
    function delete(app)

        % Delete UIFigure when app is deleted
        delete(app.UIFigure)
    end
end
end

Edit: I noticed that the gauge gets immediately updated when I turn a knob, slider, etc. So somehow the capability of a higher refresh rate is definitely there... but how to enable it without having to touch controls? Updated MCV accordingly.

Rustproof answered 6/7, 2017 at 23:47 Comment(1)
This is a very interesting problem! Actually, I think you're experiencing a mechanism known as "throttling". I noticed it only kicks in when updates are too frequent. As an example: if you set it to update every 0.16s (on my MATLAB 2017a) the motion is quite smooth. I'll try to investigate this further....Osmic
A
2

You should be able to force a refresh by calling the drawnow function in the refreshMeter callback.

Allerus answered 10/7, 2017 at 5:30 Comment(2)
Thanks for your answer. How would you suggest invoking drawnow? Just adding the word to the callback doesn't do anything for me, neither does drawnow update, nocallback, expose...Rustproof
In theory, it shouldn't matter where you put it, as long as it gets called regularly. I don't know why this isn't working for you, sorry.Allerus
G
2

I would suggest the following things to help with your problem:

  1. follow this very useful link which provides mathworks solution for low-level graphics issues. It may have to do with your graphics card.

  2. following @MrAzzamans suggestion, drawnow and refreshdata could help solve your problem (keep in mind they have different summoning options).

  3. If you're using GUIDE, try changing to App Designer and see if it solves your problem.

Iv'e encountered similar problems when building a "video-player" in GUIDE, the first suggestion fixed it for me.

Grammer answered 12/7, 2017 at 14:36 Comment(0)
R
0

So i got in touch with MathWorks support regarding this issue. Unfortunately, this seems to be a known issue prevalent in both R2016b and 2017a that might be fixed in future releases. Support couldn't provide me with a workaround either, so for the time being i just print the measurement data to the matlab command line.

Rustproof answered 16/7, 2017 at 8:23 Comment(0)
H
0

I found a way to force events triggering an update for a widget, for which drawnow was inoperate: try a sendkeys with a carriage return:

h = actxserver('WScript.shell'); h.SendKeys(newline);

Hooper answered 4/12, 2018 at 0:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.