【发布时间】: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