MATLAB离散元仿真视频生成代码运行过慢,如何优化及控制绘图速率?
代码加速优化方案
- 移除循环内冗余操作:原代码将壁面绘制、坐标轴设置、
hold on等逻辑写在了粒子遍历循环内部,粒子数量有多少就会重复执行多少次,完全属于无效计算。将这部分逻辑挪到粒子循环外,每个时间步仅执行1次即可。 - 预复用基础计算结果:圆的角度序列
th、对应三角函数值cos(th)/sin(th)是固定值,不需要每个时间步、每个粒子都重新计算,在仿真开始前计算一次存为变量即可,后续仅需要代入粒子半径和坐标生成圆形轮廓。 - 用句柄更新替代全量重绘:不要每次时间步都用
clf清空全图重绘所有元素,首次渲染时预创建所有粒子的填充对象、壁面线条对象、时间文本框对象,后续每个时间步仅修改对应对象的XData、YData、String属性即可,渲染效率可以提升10倍以上。 - 降低渲染额外开销:提前设置画布渲染器为OpenGL,开启双缓冲:
set(gcf, 'Renderer','opengl', 'DoubleBuffer','on');如果不需要实时预览绘制过程,可以把画布可见性关掉:set(gcf, 'Visible','off'),全部帧采集完成后再开启显示,能大幅提升采集速度。 - 调整取帧密度:如果对视频流畅度要求不高,可以调大帧间隔参数
INTMOVIE,比如从1改为2、5,减少总采集帧数。
绘制速率控制方法
- 若要控制生成视频的播放速率:直接修改
movie(FF,repeat,帧率)的第三个参数,数值越大播放越快,比如设置为20就是每秒播放20帧。 - 若要控制实时绘制的刷新速率:在每个时间步的帧采集代码前加
pause(间隔秒数),比如pause(0.05)就是每帧间隔50ms,数值越大绘制越慢。
优化后代码参考
%% Movie Output if SkipMovie == 1 % 预计算圆的基础坐标,仅计算1次 th = 0:pi/50:2*pi; cos_th = cos(th); sin_th = sin(th); NP = size(LPart,1); % 预创建所有图形对象 figure('Renderer','opengl','DoubleBuffer','on'); axis([xdim1,xdim2,ydim1,ydim2]); hold on; % 预创建壁面对象 for w=1:6 GW(w) = plot(LWall(w,1:2),LWall(w,3:4),['-',colorW],'LineWidth',2); end % 预创建粒子对象 for j=1:NP x_circle = R(j) * cos_th + LPart(j,1,1); y_circle = R(j) * sin_th + LPart(j,2,1); p_handle(j) = fill(x_circle, y_circle, colorP, 'EdgeColor','auto'); end % 预创建文本框 dim = [0.15,.95,.25,.06]; text_box = annotation('textbox', dim, 'BackgroundColor','w'); hold off; Start = 1; INTMOVIE = 1; End = NT; FF(End) = struct('cdata',[],'colormap',[]); % 预分配帧存储空间 for TimeStep = Start:INTMOVIE:End % 更新文本内容 text_box.String = sprintf('TimeStep = %3.2f',TimeStep); % 更新所有粒子坐标 for j = 1:NP x_circle = R(j) * cos_th + LPart(j,1,TimeStep); y_circle = R(j) * sin_th + LPart(j,2,TimeStep); p_handle(j).XData = x_circle; p_handle(j).YData = y_circle; end drawnow limitrate; % 限制刷新速率避免掉帧 FF(TimeStep) = getframe; % 采集当前帧 end set(gcf,'Visible','on'); movie(FF,repeat,20) % 20为播放帧率,可自行调整 end

内容的提问来源于stack exchange,提问作者Grady F. Mathews Iv
相关产品推荐
相关产品推荐

