2016-07-28 39 views
0

Matlabのtic toc delayを使用して、指定された時間間隔でMatlabからarduinoに配列の各値を送信し、値を読み取る予定のMatlabでwhileループを作成しましたそれらを変数に格納してグラフ化します。matlabのforループ繰り返しで遅くなる速度

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

+0

私はあなたが見る何をすべきか問題わからないんだけど、あなたは 'for'ループのショート缶に:' I = 1:長さ(x)、disp(['']);休止(.05);いくつかの割り当てを保存し、より読みやすくするでしょう。この変更の後、もはや 'd'は必要ないことに注意してください。また、私はこれを再現しようとしましたが、すべての反復でforループ(私の提案のように)の実行時間に変化は見られません。 – EBH

+0

ちょうど答えを書いたが、あまりに早すぎるかもしれないことに気付いた。あなたのループの中にベクトルが増えているわけではないので、実行時に増加するべきではありません。いずれにしても、文字列を送信する前に文字列を前処理することができ、 'cellstr'の各参照は' O(1) 'になります。 –

+0

私のマシンでこの問題を再現できませんでした。私はそれをクロックしようとしましたが、いくつかのランダムなスパイクの一部が予想されますが、時間は0.05秒を少し上回っているようです。しかし、私は同じ意味か同じか、あるいは部分的に同じ意味を持つ定数がたくさんあることを指摘したいと思います。これは、これらがどのように関連しているかを見るのが難しくなります。例えば、 'tosd'は実際には' bpm'から独立していることがわかりにくいです。このようなマスキング行動を避けるには、あなたの意図について明確にする必要があります。コードまたはコメントを通じて。 – patrik

答えて

0

前後に私はあなたが達成しようとしているものを知っていると思うと、何が中に立っているあなた方法。

私はあなたのコードを少し速くて読みやすくするために編集しました。ほとんどの場合、操作はちょうど0.05秒を上回り、いくつかの時点で約5ミリ秒かかることがあります。あなたの耕作物はもちろん変わることがあります。私はarduinoを持っていないので、そこにボトルネックがあるかどうかは分かりません。また、組み込みのMatlabプロファイラを使用してコードをプロファイリングしてみてください(非常に便利です)。

あなたのコードを遅くすることがわかった主なことは、plot関数を使用して一度に1つのポイントを数字に追加したことです。この関数を呼び出すたびに、新しいグラフィックスオブジェクトが作成されます。それらの数百の後、物事は低迷する。その代わりに、すでにプロットされたデータを更新し、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 

以下の完全なコードです。それ以上の問題がある場合はお知らせください。

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

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

この小さな調整はあなたのプログラムの実行x4が速くなります:あなたは、次の二つの文でそれを完全に置き換えることで、あなたのループをベクトル化することができますQUESTION

を以前のバージョンに

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 

ANSWER私のPCで。結果を印刷する/表示

cellfunイテレータを使用して行うことができますcellfun(@disp, y4)

+0

問題は私が一度に値を1つずつ送る必要があるのでインデックス1インデックス2など、私はあなたが与えたコードを修正しようとしましたが、それはそうするでしょうが、それでも5分の時間期間を実行しようとしていたときよりも約1分かかるパフォーマンスが遅かった – emg184

+0

@ emg184あなたは "値を送る"ことが何を意味するかについて、とても混乱しています。また、値はオンザフライで生成する必要がありますか、または私が示唆したように前処理することができますか?文字列が生成された後も、一度に1つずつ値を出力するループを作成できます。生成するには私のような暑いラップトップでは1秒未満です。実行時に何が最も時間がかかったかを見るためにコードをプロファイリングしてみましたか?それが 'disp'関数であれば、代わりに' fprintf'を使うことができます。これはやや速くなければなりません。最後に、なぜあなたは '(0.5)'を休止するのですか? –

+0

@ emg184、あなたの目標が '0.05秒'ごとに1つの文字列を出力することになっている場合、 'pause'を使うことは正確ではありません。代わりに、私は示唆したように文字列を前処理したと仮定して、以下を使用するべきです: 'for i = 1:d、 t = tic; fprintf( '%s \ n'、y4 {i})、 toc(t)<0.05, の間に続きます。 end、 end'。 1つのライナーには申し訳ありませんが、コメントではインデントが許されません。これがあなたが必要としているものなら、私は答えに書きます。この場合、前処理する必要はありません。 –

関連する問題