我在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,阅读输入是您在问题或示例代码中未提到的全新问题。也许您应该重新设计问题,以适合您要达到的目标以及在哪些约束下。
我现在将重新制定