【问题标题】:Real-time Matlab plot refresh rate is affected by plot size实时 Matlab 绘图刷新率受绘图大小的影响
【发布时间】:2017-09-30 04:00:54
【问题描述】:

我在 Matlab 中绘制实时数据(通过串行端口接收),我发现了一种影响刷新率的奇怪方法:改变绘图的大小。当情节“正常”时,它会得到〜35fps,当我缩小它时,它会超过120fps。但是,当我使用完全相同的绘图设置,但只是绘制为每个循环随机生成的数据时,刷新率不受绘图大小的影响。不幸的是,配置文件查看器(2017a)无法看到绘图内部,并且只是将所有等待时间归因于串行端口 - 这是不可能的,因为上面描述的可变刷新率(另外,我已经测试了一个裸-bones 串行调用和响应,Matlab 的往返时间低于 8ms (~120fps)。

这两个循环示例并不是要获得相同的帧速率,它们只是为了演示当一个更改绘图大小(只需手动抓取一个角并调整它,或使用位置参数)时,第一个示例(串行) 受大小的影响很大,而第二个示例(随机)则没有。

加法:

在玩了一个通过计时器回调更新绘图的修改版本后,我发现我可以使串行读取循环快速(~170Hz)或快速更新绘图(~170Hz)。然而,另一个总是受苦。如果我迭代地更改计时器周期以使两者都获得相同的更新率,毫不奇怪,它几乎与我在下面显示的循环中获得的速率完全相同。最好将绘图更新放在单独的线程上,而无需跳过调用单独的 Matlab 进程并在两者之间进行通信的麻烦。

情节设置:

figure_h = figure();
set(figure_h, 'KeyPressFcn', @key_press_function);
set(figure_h, 'WindowButtonDownFcn', {@click_callback, obj})

%some random things that drastically speed up the plotting
set(figure_h, 'Position', [100, 100, 350, 350]);    %the size has a huge effect on performance
set(figure_h, 'MenuBar', 'none');
set(figure_h, 'GraphicsSmoothing', 'Off');
set(figure_h, 'DockControls', 'Off');
set(figure_h, 'NumberTitle', 'Off');
set(figure_h, 'ToolBar', 'none');

%create plots
scatter_h = plot(number_array(:,1)*scale, number_array(:,2)*scale, 'r.');
set(scatter_h, 'MarkerSize',8);
set(scatter_h, 'Clipping','off');
hold on
axis square
grid on
ylim([min_value, max_value*scale]);  
xlim([min_value, max_value*scale]);
set(figure_h.CurrentAxes, 'xtick', [min_value:max_value/10:max_value]); %#ok<NBRAK>
set(figure_h.CurrentAxes, 'ytick', [min_value:max_value/10:max_value]); %#ok<NBRAK>
set(figure_h.CurrentAxes, 'XTickLabel',[]);
set(figure_h.CurrentAxes, 'YTickLabel',[]);
set(figure_h.CurrentAxes, 'ZTickLabel',[]);
set(figure_h.CurrentAxes, 'ZGrid', 'off');
set(figure_h.CurrentAxes, 'XLimMode', 'manual');
set(figure_h.CurrentAxes, 'YLimMode', 'manual');
set(figure_h.CurrentAxes, 'ZLimMode', 'manual');
set(figure_h.CurrentAxes, 'ALimMode', 'manual');
set(figure_h.CurrentAxes, 'CLimMode', 'manual');
set(figure_h.CurrentAxes, 'DataAspectRatioMode', 'manual');
set(figure_h.CurrentAxes, 'CameraPositionMode', 'manual');
set(figure_h.CurrentAxes, 'CameraPosition', [max_value/2,max_value/2,1]);
set(figure_h.CurrentAxes, 'CameraTargetMode', 'manual');
set(figure_h.CurrentAxes, 'CameraTarget', [max_value/2,max_value/2,0]);
set(figure_h.CurrentAxes, 'CameraUpVectorMode', 'manual');
set(figure_h.CurrentAxes, 'CameraUpVector', [0,1,0]);
set(figure_h.CurrentAxes, 'CameraViewAngleMode', 'manual');
set(figure_h.CurrentAxes, 'CameraViewAngle', 180);
set(figure_h.CurrentAxes, 'GridAlphaMode', 'manual');
set(figure_h.CurrentAxes, 'Clipping', 'off');
circle_h = line((radius*cos(theta) + center_x)*scale,(radius*sin(theta) + center_y)*scale);
hold off

串行的简化循环:

while keep_running

    %must wait for next packet to arrive
    bytes = obj.bytes_available;
    while keep_running && (bytes == 0)
        bytes = obj.bytes_available;  //function call actually directly uses the java serial objects for speed        
    end

    %send request for next packet
    obj.send_command(obj.cmd_id.cmd_history, true);  //sends synchronously, otherwise, with async, an additional wait loop is necessary to prevent an async call if serial is still transmitting (Matlab throws an error otherwise - why they can't be queued, I don't know)

    %grab the available buffer
    new_buffer = obj.buffer_available(bytes);

    %append new characters to running buffer
    char_buffer = strcat(char_buffer, new_buffer);

    %process buffer for all arrays
    while (~isempty(strfind(char_buffer, '[')) && ~isempty(strfind(char_buffer, ']'))) %#ok<STREMP>

        %extract a number array
        [number_array, char_buffer] = extract_hex_array(char_buffer,3,2);

        if ~isempty(number_array)
            %remove any duplicate points
            number_array = unique(number_array, 'rows', 'stable');

            frames = frames + 1;

            %update data
            set(scatter_h, 'xdata', number_array(:,1)*scale, 'ydata', number_array(:,2)*scale);

            %update header information (after stabilization, and every 10 frames)
            if frames > 25 && mod(frames, 10) == 0
                avg_framerate = frames/toc(total_time);
                set(figure_h, 'Name', strcat('rate: ', num2str(avg_framerate, '%.1f'), ' Hz  buffer: ',num2str(length(char_buffer), '%05d')));
            end

            %just a small delay, but not too small the callbacks stop working
            pause(0.005);
        end
    end
end

虚拟随机数据循环:

start_tic = tic;
for i=1:200
    array1 = 4095*rand(82,2);
    set(scatter_h, 'xdata', array1(:,1), 'ydata', array1(:,2));
    pause(0.005);
end
end_tic = toc(start_tic);
fprintf("fps: %f\n", i/end_tic);

【问题讨论】:

  • 只是关于设置属性的说明。您可以在set 函数中设置多个属性,尤其是当它们的值相同时:set(figure_h.CurrentAxes, {'XLimMode','YLimMode','ZLimMode',...'ALimMode','CLimMode','DataAspectRatioMode','CameraPositionMode',...'CameraTargetMode','CameraUpVectorMode', 'CameraViewAngleMode',...'GridAlphaMode'},repmat({'manual'},1,11));

标签: matlab performance plot serial-port frame-rate


【解决方案1】:

在向 Mathworks 提交服务请求后,官方的回答是 Matlab 2017a 及之前的版本不要在 Mac 上使用 OpenGL(即使“opengl info”命令表示支持)。因此,在他们修复绘图库之前,macOS 上的绘图不会像 Windows 那样快。

【讨论】:

    猜你喜欢
    • 2012-01-06
    • 2012-07-10
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多