简体   繁体   中英

Slowing Speed with each for loop iteration in matlab

I have written a while loop in Matlab that is supposed to send each value in an array from Matlab to arduino at a specified time interval using a tic toc delay in Matlab and then read values and store them in a variable and graph them.

The output of the while-loop slows down with each successive iteration.

I increased the buffersize which helped it a lot, but it still slows down too much. Is there another way to increase the speed to print the values on time. I have included another tic toc and graph to show the execution speed here is the 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

After a bit of back and forth I think I know what you're trying to achieve and what stands in your way.

I have edited your code to make it slightly more fast and readable. Most of the time the operations take just slightly above 0.05 seconds, and at several time points it can take about 5 milliseconds longer than expected. Your millage may vary of course. Since I do not have an arduino, I cannot know if there is a bottle neck there. You should also try profiling your code using the builtin Matlab profiler (it's very useful) to see what exactly slows your code down.

The main thing I found to slow your code is that you used the plot function to add one point at a time to your figure. Each time you call this function, it creates a new graphics object. After a few hundred of those, things get sluggish. Instead you should simply update the already plotted data and redraw it using drawnow .

In short, the solution is this:

1) Initialize you plot with a single point and save the graphics handle for later use:

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

2) Then, inside the loop, once your data arrays have been updated, replace the data in your existing plot with the new arrays.

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

3) Redraw the plots to reflect the latest update.

drawnow;

drawnow will eventually slow down your code also since it has to redraw increasingly large plots at every iteration. To make things work faster, you might want to refresh your plot after a longer interval. For example, the following will refresh every 10 iterations:

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

Full code below. Let me know if you have any more issues.

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 TO PREVIOUS VERSION OF QUESTION

You can vectorize your loop by replacing it entirely with the following two statements:

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

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

This small adjustment makes your program run x4 faster on my PC.

Displaying/printing the results could also be done using the cellfun iterator: cellfun(@disp, y4)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM