matlab for循环太慢,Matlab中每个for循环迭代的速度降低

我在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,(['

']))

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,(['

']));

%disp((['

']));

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

我不确定您确实会遇到什么问题,但是可以将for循环缩短为:for i=1:length(x), disp([

]); pause(.05); end,它将保存一些分配并使其更具可读性。请注意,此更改之后,您也不再需要d。另外,我尝试重现此问题,但是在所有迭代中,我都看不到for循环的运行时间有任何变化(如我的建议)。

刚刚写了一个答案,但意识到可能还为时过早。由于您的循环中没有越来越多的向量,因此不应增加运行时间。无论如何,如果有帮助,您可以在发送字符串之前对其进行预处理,然后每个对cellstr的引用将为O(1)。

我无法在计算机上重现此问题。我尝试为其计时,但是部分随机峰值是正常的,时间似乎保持在0.05秒以上。但是,我要指出的是,您有很多常量,它们的含义相同或部分相同。这使得很难看到它们之间的关系。例如,很难看到tosd实际上独立于bpm。为避免掩盖此类行为,您需要清楚自己的意图。通过代码或注释。

在您的代码中未定义handles.UltraM。同样,您似乎打开了一个重复的问题。请注意,这对SO来说是一个很大的禁忌,最终并不能帮助您解决很多问题。

我没有列出串行端口的初始化信息,也没有给出参数,我不想包含一堆对试图解决@Alexander F的问题并不重要的代码。在重新制定这个问题之前,我打开了第二个问题,因为他们讨论了不同的主题,此后我将其删除

经过一番来回的思考,我想我知道您要达到的目标以及阻碍您前进的道路。

我已经对您的代码进行了编辑,以使其更快,更易读。大多数情况下,操作花费的时间略高于0.05秒,并且在几个时间点上,花费的时间可能比预期的时间长5毫秒。当然,您的年龄可能会有所不同。由于我没有arduino,所以我不知道那里是否有瓶颈。您还应该尝试使用内置的Matlab探查器对代码进行性能分析(这非常有用),以查看到底是什么导致代码变慢。

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

简而言之,解决方案是这样的:

1)用单点初始化绘图并保存图形手柄以备后用:

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

2)然后,在循环内部,一旦您的数据数组已更新,就用新数组替换现有绘图中的数据。

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

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

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,(['

']))

disp(['

']); % 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,(['

']));

disp((['

'])); % 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('

'));

% deleting all spaces

y4 = cellfun(@(u) u(~isspace(u)), y4, 'UniformOutput', false)

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

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

问题是我需要一次发送一个值,所以索引1索引2等等,并且我需要以某个统一的间隔发送它们,我尝试修改您提供的代码,以便这样做,但性能仍然很慢比我尝试运行5分钟的时间长了大约1分钟

@ emg184,我对您"发送值"的含义感到非常困惑。另外,这些值是否需要即时生成,还是可以像我建议的那样对其进行预处理?在生成字符串之后,您仍然可以有一个循环来一次打印一个值。在不太热的笔记本电脑上,生成时间不到一秒钟。您是否尝试对代码进行性能分析,以查看运行时花费了最多时间?如果它是disp函数,则可以尝试使用fprintf代替,它应该会更快一些。最后,为什么您pause(0.5)?

@ emg184,如果您的目标是每0.05秒打印一个字符串,则使用pause将不准确。相反,您应该使用以下内容(假设您按照我的建议对字符串进行了预处理):for i=1:d, t = tic; fprintf(%s

, y4{i}), while toc(t) < 0.05, continue; end, end。对不起,单线,注释不允许缩进。如果这是您需要的内容,我会在答案中写出来。在这种情况下,您甚至不需要进行预处理。

谢谢您的回应。很抱歉等待您的回复,我离开了一段时间。我做了你所说的,它的性能更好,但是我想做的是用fprintf将值发送到arduino,同时用fscanf读取来自arduino的数据,然后实时绘制它,得到了打印值但是我可以读取部分值,但是我似乎无法将它们存储在数组中以备后用。我可以实时绘图,但是当我实时绘图时,它不允许我正确读取数据。

@ emg184,阅读输入是您在问题或示例代码中未提到的全新问题。也许您应该重新设计问题,以适合您要达到的目标以及在哪些约束下。

我现在将重新制定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值