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,閱讀輸入是您在問題或示例代碼中未提到的全新問題。也許您應該重新設計問題,以適合您要達到的目標以及在哪些約束下。
我現在將重新制定
總結
以上是生活随笔為你收集整理的matlab for循环太慢,Matlab中每个for循环迭代的速度降低的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手把手带你玩转Tensorflow 物体
- 下一篇: matlab人脸追踪,求大神帮助我这个菜