2016-07-28 22 views
0

Ich habe eine while-Schleife in Matlab geschrieben, die jeden Wert in einem Array von Matlab zu Arduino in einem bestimmten Zeitintervall mit einem Tic-Toc-Verzögerung in Matlab senden und dann Werte lesen soll und speichern Sie sie in einer Variablen und grafisch sie.Verlangsamung mit jedem für Schleife Iteration in Matlab

Die Ausgabe der while-Schleife wird mit jeder folgenden Iteration langsamer.

Ich habe die Puffergröße erhöht, was mir sehr geholfen hat, aber es verlangsamt sich immer noch zu sehr. Gibt es eine andere Möglichkeit, die Geschwindigkeit zu erhöhen, um die Werte rechtzeitig zu drucken? Ich habe eine andere Tic-Toc und Grafik hier enthält die Ausführungsgeschwindigkeit zu zeigen, ist der Code:

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

Ich bin nicht sicher, welches Problem Sie sehen, aber Sie können kurz Ihre 'for' Schleife:' für i = 1: Länge (x), disp (['']); Pause (.05); Ende, und es wird einige Zuordnungen speichern und es lesbarer machen. Beachten Sie, dass Sie nach dieser Änderung auch kein 'd' mehr benötigen. Ich habe auch versucht, dies zu reproduzieren, aber ich kann keine Änderung in der Laufzeit der for-Schleife (wie in meinem Vorschlag) über alle Iterationen sehen. – EBH

+0

Ich habe nur eine Antwort geschrieben, aber mir wurde klar, dass es zu früh gewesen sein könnte. Da Sie in Ihrer Schleife keinen wachsenden Vektor haben, sollte dieser in der Laufzeit nicht zunehmen. In jedem Fall, wenn es hilft, können Sie möglicherweise die Strings vor dem Senden vorverarbeiten, und dann wird jeder Verweis auf 'cellstr' 'O (1)' sein. –

+0

Ich konnte dieses Problem nicht auf meinem Computer reproduzieren. Ich habe versucht, es zu tun, aber ein Teil von einigen zufälligen Spikes, die erwartet wird, scheint, als sei die Zeit knapp über 0,05 Sekunden gehalten. Ich möchte jedoch darauf hinweisen, dass Sie viele Konstanten haben, die gleich oder teilweise gleich sind. Dies macht es schwer zu sehen, wie diese sich beziehen. Es ist zum Beispiel schwer zu erkennen, dass 'tosd' tatsächlich unabhängig von' bpm' ist. Um Maskierungsverhalten wie diese zu vermeiden, müssen Sie sich über Ihre Absichten im Klaren sein. Entweder durch Code oder durch Kommentare. – patrik

Antwort

0

Nach einigen hin und her glaube ich zu wissen, was Sie versuchen zu erreichen, und was steht in Ihrem Weg.

Ich habe Ihren Code bearbeitet, um es etwas schneller und lesbarer zu machen. Meistens nehmen die Operationen nur wenig über 0.05 Sekunden, und zu mehreren Zeitpunkten kann es etwa 5 Millisekunden länger als erwartet dauern. Ihre Millage kann natürlich variieren. Da ich kein Arduino habe, kann ich nicht wissen, ob da ein Flaschenhals ist. Sie sollten auch versuchen, Ihren Code mit dem eingebauten Matlab Profiler zu profilieren (es ist sehr nützlich), um zu sehen, was genau Ihren Code verlangsamt.

Die Hauptsache, die ich gefunden habe, um Ihren Code zu verlangsamen, ist, dass Sie die plot Funktion verwendet haben, um einen Punkt zu Ihrer Figur hinzuzufügen. Jedes Mal, wenn Sie diese Funktion aufrufen, wird ein neues Grafikobjekt erstellt. Nach ein paar hundert davon werden die Dinge träge. Stattdessen sollten Sie einfach die bereits geplotteten Daten aktualisieren und sie mit drawnow neu zeichnen.

Kurz gesagt, ist die Lösung dieses:

1) Initialisieren Sie mit einem einzigen Punkt plotten und speichern die Grafik für eine spätere Verwendung handhaben:

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

2) Dann in der Schleife, einmal Ihre Datenfelder wurden aktualisiert. Ersetzen Sie die Daten in Ihrem vorhandenen Diagramm durch die neuen Felder.

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

3) Zeichnen Sie die Plots neu, um das neueste Update wiederzugeben.

drawnow; 

drawnow wird schließlich der Code auch verlangsamen, da es bei jeder Iteration immer größere Parzellen neu zu ziehen hat. Um die Arbeit schneller zu machen, möchten Sie Ihren Plot möglicherweise nach einem längeren Intervall aktualisieren. Folgendes wird beispielsweise alle 10 Iterationen aktualisiert:

Vollständiger Code unten. Lassen Sie es mich wissen, wenn Sie weitere Probleme haben.

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 

ANTWORT AUF frühere Version FRAGE

Sie Ihre Schleife durch das Ersetzen es vollständig mit den beiden folgenden Anweisungen vektorisieren können:

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

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

Diese kleine Anpassung macht Ihr Programmlauf x4 schneller auf meinem PC.

/Anzeige der Ergebnisse Druck auch die cellfun Iterator getan werden könnte: cellfun(@disp, y4)

+0

Das Problem ist, dass ich über die Werte eins nach dem anderen so Index 1 Index 2 usw. senden muss, und ich sie an einigen senden muss uniform interval Ich habe versucht, den Code zu ändern, den du gabst, so dass es das tun würde, aber immer noch eine langsame Leistung hatte es etwa 1 Minute länger als es sollte, wenn ich es für eine 5 Minuten Zeit – emg184

+0

@ emg184 laufen wollte, bin ich ziemlich verwirrt in Bezug auf das, was Sie mit "senden Sie die Werte" meinen. Müssen die Werte auch spontan generiert werden oder können sie wie von mir vorgeschlagen vorverarbeitet werden? Sie können immer noch eine Schleife verwenden, um die Werte nacheinander zu drucken, nachdem die Zeichenfolgen generiert wurden. Das Generieren dauert weniger als eine Sekunde auf meinem nicht so heißen Laptop. Haben Sie versucht, Ihren Code zu profilieren, um zu sehen, was während der Laufzeit am meisten Zeit in Anspruch genommen hat? Wenn es die "disp" -Funktion ist, können Sie stattdessen 'fprintf' verwenden, das etwas schneller sein sollte. Schließlich, warum "pause (0,5)"? –

+0

@ emg184, wenn Ihr Ziel darin besteht, eine Zeichenfolge alle 0,05 Sekunden zu drucken, ist die Verwendung von "Pause" nicht korrekt. Stattdessen sollten Sie Folgendes verwenden (vorausgesetzt, Sie haben die Strings wie von mir vorgeschlagen vorverarbeitet): 'für i = 1: d, t = tic; fprintf ('% s \ n', y4 {i}), , während toc (t) <0,05, fortfahren; Ende, Ende '. Sorry für den One-Liner, Kommentare erlauben keine Einrückungen. Wenn Sie das brauchen, schreibe ich es in meine Antwort. In diesem Fall müssen Sie nicht einmal vorverarbeiten. –