在matlab中使用每个for循环迭代减速

时间:2016-07-28 15:20:22

标签: matlab for-loop serial-communication

我在Matlab中编写了一个while循环,它应该使用Matlab中的tic toc延迟以指定的时间间隔将数组中的每个值从Matlab发送到arduino,然后读取值并将它们存储在变量中并将它们绘制成图形。

while循环的输出随着每次连续迭代而减慢。

我增加了缓冲区,这对它有很大帮助,但它仍然会减慢太多。是否有另一种方法来提高按时打印值的速度。我已经包含了另一个tic toc和图表来显示这里的执行速度是代码:

max = 80; min = 40; amp = (max-min)/2; offset = amp + min; btime = 5; bpm = 12; spb = 60/bpm; sapb = spb/.05; tosd = sapb*bpm*btime; time1 = btime*60; x = linspace(0,time1,tosd)'; x1 = amp*sin(x*(2*pi/20)) + offset; pause(1); fprintf(handles.UltraM,(['<P' num2str(offset) '>'])) pause(5); y = []; i = 1; figure(1); hold on; title('Pressure Data'); xlabel('Data Number'); ylabel('Analog Voltage (0-1023)'); t1 = []; figure(2); hold on; title('Time to execute task'); xlabel('iteration number'); ylabel('time taken'); while (i<=length(x)) t2 = tic; t = tic; fprintf(handles.UltraM,(['<P' num2str(x1(i)) '>'])); %disp((['<P' num2str(x1(i)) '>'])); y(i) = fscanf(handles.UltraM,'%d'); figure(1); hold on; plot(i, y(i), 'b*'); drawnow; hold off; while toc(t) < 0.05 continue end t1(i) = toc(t2); figure(2); hold on; plot(i,t1(i),'b*'); drawnow; hold off; i = i + 1; end

1 个答案:

答案 0 :(得分:1)

经过一番反复思考后,我想我知道你想要实现的目标以及阻碍你的方向。

我已经编辑了你的代码,使其更加快速和可读。大多数情况下,操作仅略高于0.05秒,并且在几个时间点可能比预期长约5毫秒。你的millage当然可能会有所不同。由于我没有arduino,我不知道那里是否有瓶颈。您还应该尝试使用内置的Matlab分析器(它非常有用)来分析您的代码,以查看究竟是什么减慢了代码的速度。

我发现减慢代码的主要原因是你使用plot函数一次向你的数字添加一个点。每次调用此函数时,它都会创建一个新的图形对象。几百个之后,事情变得缓慢。相反,您应该只更新已绘制的数据并使用drawnow重绘它。

简而言之,解决方案是:

1)使用单个点初始化绘图并保存图形句柄以供以后使用:

p1 = plot(0,0,'b*');

2)然后,在循环内部,一旦更新了数据阵列,用新阵列替换现有绘图中的数据。

set(p1, 'XData', 1:i, 'YData', y(1:i));

3)重绘图以反映最新更新。

drawnow;

drawnow最终会减慢您的代码速度,因为它必须在每次迭代时重绘越来越大的图。为了使工作更快,您可能希望在更长的间隔后刷新绘图。例如,以下内容将每10次迭代刷新一次:

if rem(i,10) == 0
    drawnow;
end

以下完整代码。如果您还有其他问题,请与我们联系。

max = 80;
min = 40;
amp = (max-min)/2;
offset = amp + min;
btime = 5;
bpm = 12;
spb = 60/bpm;
sapb = spb/.05;
tosd = sapb*bpm*btime;
time1 = btime*60;
x = linspace(0,time1,tosd)';
x1 = amp*sin(x*(2*pi/20)) + offset;
pause(1);
%fprintf(handles.UltraM,(['<P' num2str(offset) '>']))
disp(['<P' num2str(offset) '>']); % replacing with disp (I don't have an arduino)
pause(5);
%y = []; % unnecessary here, preallocated before loop
figure(1); 
p1 = plot(0,0,'b*'); % plotting one dot to create an object, data will be overwritten
hold on;
title('Pressure Data');
xlabel('Data Number');
ylabel('Analog Voltage (0-1023)');
%t1 = []; % unnecessary here, preallocated before loop
figure(2);
p2 = plot(0,0,'b*'); % plotting one dot to create an object, data will be overwritten
hold on;
title('Time to execute task');
xlabel('iteration number');
ylabel('time taken');

% preallocate t1 and y arrays for faster operation
t1 = zeros(size(x));
y  = zeros(size(x));
i = 1; % moved closer to loop beginning for better readability
while i <= length(x) % parentheses unnecessary in Matlab
    t2 = tic;
    t = tic;
    %fprintf(handles.UltraM,(['<P' num2str(x1(i)) '>']));
    disp((['<P' num2str(x1(i)) '>'])); % replacing with disp (I don't have an arduino)
    %y(i) = fscanf(handles.UltraM,'%d');
    y(i) = randn; % replacing with random number (I don't have an arduino)
    %figure(1); % unnecessary
    %hold on; % unnecessary
    %plot(i, y(i), 'b*');
    % replacing the above with a slightly faster version
    set(p1, 'XData', 1:i, 'YData', y(1:i));
    %drawnow; % first one is annecessary
    %hold off; % unnecessary
    while toc(t) < 0.05
        continue
    end
    t1(i) = toc(t2);
    %figure(2); % unnecessary
    %hold on; % unnecessary
    %plot(i,t1(i),'b*');
    % replacing the above with a slightly faster version
    set(p2, 'XData', 1:i, 'YData', t1(1:i));
    if rem(i,10) == 0 % refreshing every 10 iterations
        drawnow; 
    end
    %hold off; % unnecessary
    i = i + 1;
end

对以前版本的问题的回答

您可以通过使用以下两个语句完全替换它来对您的循环进行矢量化:

% vectorizing num-to-string conversion
y4 = cellstr(strcat('<P',num2str(x1), '>'));

% deleting all spaces
y4 = cellfun(@(u) u(~isspace(u)), y4, 'UniformOutput', false)

这个小调整使您的程序在我的电脑上运行x4更快。

显示/打印结果也可以使用cellfun迭代器完成:cellfun(@disp, y4)