资讯动态

MATLAB contour函数绘制PIV流场流速云图实战详解

发布时间:2026/10/5 10:01:05 来源:尧图企业网站定制
做PIV实验的同学应该都体会过那种数据一大堆、图却拿不出手的感觉。粒子图像测速Particle Image VelocimetryPIV把流场的瞬时速度测出来了得到的是跟网格对应的u、v速度分量可这些原始数据如果不变成可视化云图就很难直观看到涡、剪切层、回流区这些结构。这篇文章就围绕“PIV实验流场流速云图”这件事重点讲清楚MATLAB的contour函数怎么用从数据整理、等值线设置到出图导出一整套细节都会覆盖。如果你正在做圆柱绕流、翼型、射流或者管道内流场实验手头已经有一份PIV数据却不知道怎么把图画得又准又好看那这篇内容应该能帮你省不少事。顺便说一句标题里的MALAB我理解是MATLAB的笔误下面统一按MATLAB讲。1. 先从流场说起PIV实验数据是怎么变成云图的1.1 一张云图背后的测量链条很多新手拿到PIV数据后第一反应是“直接画图”但如果不理解手里的数据是怎么来的画图时很容易被各种异常现象迷惑。PIV的基本原理其实不复杂在流场里撒入跟随性好的示踪粒子用激光片光照亮待测平面相机以极短的时间间隔连续拍两张粒子图像然后通过互相关算法算出每个小区域里粒子团的平均位移再除以两帧之间的时间间隔dt就得到了这个区域的速度。这里有一个关键点PIV软件最终给我们的不是每个粒子的速度而是一个均匀网格上的速度采样。比如你设置查询窗口interrogation window为32×32像素、重叠率50%那么输出的速度场就是在这个网格上排列的。每个网格点上有两个速度分量通常记为ux方向和vy方向。我们画流速云图本质就是把这里每个点的速度幅值sqrt(u^2v^2)映射成颜色。所以contour函数真正输入的东西不是粒子图像而是已经算好的速度场。你需要准备的是四个等尺寸的二维矩阵x坐标、y坐标、u速度分量、v速度分量。后面所有画图操作都是围绕这四个矩阵展开的。1.2 理解云图的横纵轴与颜色轴一张流速云图横向和纵向分别代表物理空间的两个方向颜色则表示当地速度大小。比如圆柱绕流实验上游来流速度是U0圆柱后面会出现回流区、剪切层和交替脱落的尾涡。把这些特征显示在云图上就是一片高亮的高速区、圆柱后方的低速深色区以及交替出现的涡结构。这里要特别提醒一点云图是流场的“快照”它显示的是某一瞬间或某个平均时间窗口内的速度大小分布。如果你做的是稳态流动那张图可以说明时间平均的流场结构如果做的是非定常流动比如卡门涡街那你需要看的是同一相位下的瞬时云图或者做相平均后再画。理解这个背景你就知道为什么contour这类等值线工具在流体力学后处理里这么常用——它能通过等值线的疏密变化清晰地表达速度梯度和流动结构的边界这是单纯的颜色填充图给不出来的信息。2. 把PIV数据收拾干净画图前的三个关键准备2.1 先搞清楚你手上的数据长什么样PIV软件不同导出的数据格式差异很大。PIVlab一般可以导出.mat文件里面通常有x、y、u、v这几个变量单位可能是像素/帧也可能是经过标定换算后的物理单位mm/s或m/s。OpenPIV这类开源工具则常常输出netCDF或CSV格式自己写的互相关代码导出的格式就更随意了。拿到数据的第一步先看变量维度。x、y、u、v都应该是二维矩阵比如150×120这代表沿着x方向有150个速度矢量节点y方向有120个。如果u、v是一维数组说明数据是散点形式你需要先用meshgrid把坐标网格化再用griddata或scatteredInterpolant插值成规整的网格。这一步很多人会忽略直接拿一维数据去画contourfMATLAB会报错或者画出完全错误的结果。我自己的习惯是不管从哪个软件出来先在MATLAB里用whos看一下变量的尺寸和类型再画一个最简单的quiver(x,y,u,v)检查矢量方向是否合理。如果这一步的速度方向都是乱的后面处理再花哨也没意义。2.2 剔除野点和不合理矢量PIV实验里因为粒子浓度不够、激光反光或者跨帧粒子丢失计算出来的速度矢量里偶尔会有个别离谱的值。这些“野点”如果不处理画到contourf上就是一团团的伪结构非常误导。判断野点的常用手段是中值滤波。对每个速度矢量观察它跟周围一圈邻居的差异如果偏差超过某个阈值比如3倍中值绝对偏差就认为这个点是野点。MATLAB里可以直接用medfilt2对u和v分别做一次中值滤波窗口取3×3或5×5。u_filt medfilt2(u, [3 3], symmetric); v_filt medfilt2(v, [3 3], symmetric);对于更严格的处理可以结合速度范围判断。比如你知道实验流速不会超过1.5 m/s那超过这个值的点就直接视为无效。关键是剔除野点时不要把无效点设成0而要设为NaN。因为0会被当成真实速度画出来后会产生一个不存在的低速区域误导性比野点本身还大。2.3 插值、平滑与物理单位换算处理完野点后速度场里常常会出现个别NaN空洞。如果这些空洞很小可以用周围有效点补上如果是模型遮挡或激光阴影造成的盲区就应该保留NaN画图时单独处理底色不能随便插值。补小洞时我比较推荐regionfillImage Processing Toolbox它可以按周围像素自然过渡地填充指定区域。用法很简单mask isnan(speed); if any(mask(:)) speed regionfill(speed, mask); end如果不想引入图像处理工具箱也可以用fillmissing沿行列各做一次线性插值。但要注意不要对大面积盲区做插值否则会造出本来不存在的“假涡”这在学术上是很危险的事。平滑方面可以适当对速度场做一次高斯滤波比如imgaussfilt(speed, 1)能把计算噪声压掉一些云图看起来更干净。但平滑过度会抹掉真实的细小涡结构一般我用一个像素左右的高斯核就够了而且我会先看一下原始云图确认平滑没有改变主结构再继续。单位换算也要在画图前确认。如果PIV软件里已经做过标定导出的坐标可能是mm、速度可能是m/s如果没有你的坐标可能是像素、速度可能是像素/帧。画图前统一转成物理单位不然色标上会出现令人困惑的数字。3. MATLAB contour函数怎么用从矢量场到完整云图3.1 contour和contourf根据需求二选一MATLAB里contour相关函数有两个常用变体contour画等值线contourf画填充云图。它们都接受大致相同的输入最核心的调用格式是contour(x, y, speed) contourf(x, y, speed)两者的区别在于呈现方式。contour只画线线条疏密直接反映梯度大小适合叠加在别的图上作为辅助信息也可以配合clabel在线上标注具体速度值。contourf则在等值线之间填充颜色视觉冲击力更强适合作为主云图展示。我的习惯是给课题组内部讨论或者快速检查数据用contourf往论文里放有时候会先用contourf做底色再叠加等高线或矢量箭头。还有一个实用细节contourf默认会在不同色块之间画出细白线如果你不想看到这些线就加上LineStyle, nonecontourf(x, y, speed, LineStyle, none);3.2 levels参数决定这张图的信息量contour函数里最容易被忽视但也最重要的是levels参数它控制画多少条等值线、在哪些值上画等值线。不同设置下同一组数据可以画成一张平平无奇的色块图也可以画成结构分明的流场图。如果直接写contourf(x, y, speed)MATLAB会自动选一组等值线层级大约是10到20条。这个默认值在大多数场景下偏少尾涡区和剪切层附近的细节会被糊掉。常用的做法是自己指定levels。一个直观的方法是传一个整数表示要画的等值线条数contourf(x, y, speed, 40, LineStyle, none);40条是一个比较保险的起点色带过渡细腻又不会因为太多而导致文件过大。如果想精确控制每条线的数值就传一个向量比如流速范围从0到1.2 m/s每隔0.05画一条levels 0:0.05:1.2; contourf(x, y, speed, levels, LineStyle, none);这样云图会按照你规定好的速度间隔来分层。多张图对比时尤其要做到所有图用同一组levels颜色才有可比性。回到等值线上看如果用的是contour而不是contourf这个levels向量直接决定了等值线的疏密。太密会黑压压一片太疏则信息量不足这个需要根据数据范围多试几次。3.3 坐标轴方向、颜色条与配色细节决定观感PIV数据经常来自图像处理结果而图像坐标系的y轴默认向下物理坐标系的y轴应该向上。如果直接画云图会出现上下颠倒的情况流动方向看着就别扭。解决办法是强制翻转y轴方向set(gca, YDir, normal);另一个常见问题是纵横比。如果x和y方向上每个点的物理间距相同但绘图时没有保持纵横比圆形的障碍物会被画成椭圆涡结构也会被压扁。用axis equal就能让坐标轴等比例显示axis equal;颜色条是云图的灵魂。colorbar加上之后会给色标加上标签比如单位是m/s就写ylabel(colorbar, Velocity (m/s))。配色方面MATLAB默认的parula已经不错但我个人更推荐turbo它在色彩变化上更均匀不容易在高亮处刺眼也不像jet那样在某些色带上产生视觉误导colormap(turbo);颜色范围的控制同样关键。如果不手动设置MATLAB会根据当前数据的最大最小值自动调色这就导致一个问题如果速度场里有几个异常高值整个云图的颜色都会被拉伸正常区域反而看不清。所以我会先算出合理的速度范围再用clim固定它clim([0 maxV]);需要提醒的是clim是R2022a之后引入的写法老版本里对应的函数是caxis([0 maxV])。写代码时要注意你所在环境的版本否则会报错。3.4 一个可以直接用的完整脚本圆柱绕流流速云图下面是一段我在实际项目里常用来处理PIV数据的脚本已经精简成一个可以照搬的版本。假设你已经从PIV软件导出了x、y、u、v四个变量单位都是物理单位%% 1. 加载数据 d load(piv_result.mat); x d.x; y d.y; u d.u; v d.v; % 如果暂时没有实验数据想先跑通流程可以用下面的合成流场 % [x, y] meshgrid(linspace(-10, 10, 200), linspace(-5, 5, 100)); % u 1.0 - 0.6 * exp(-(y.^2)./0.8) .* exp(-((x-2).^2)./4); % v 0.3 * sin(0.8*x) .* exp(-y.^2./1.2); %% 2. 粗处理 u medfilt2(u, [3 3], symmetric); v medfilt2(v, [3 3], symmetric); speed sqrt(u.^2 v.^2); %% 3. 计算速度范围并画图 maxV max(speed, [], all, omitnan); levels linspace(0, maxV, 40); figure(Color, w); contourf(x, y, speed, levels, LineStyle, none); colorbar; colormap(turbo); clim([0 maxV]); % 老版本MATLAB用 caxis([0 maxV]) axis equal; set(gca, YDir, normal, FontSize, 12); xlabel(x (mm)); ylabel(y (mm)); title(PIV Flow Velocity Contour); %% 4. 叠加矢量箭头可选 hold on; step 4; % 每隔4个点画一个箭头避免太密 quiver(x(1:step:end, 1:step:end), y(1:step:end, 1:step:end), ... u(1:step:end, 1:step:end), v(1:step:end, 1:step:end), ... 0.6, k, LineWidth, 0.6); hold off; %% 5. 导出高分辨率图 exportgraphics(gcf, piv_contourf.png, Resolution, 300);这段脚本第3步是整个流程的核心。先用max找出最大速度注意一定要加omitnan否则只要有NaNmax值就是NaN导致后面levels全部变成NaN。然后用linspace(0, maxV, 40)生成40条等值线层级保证云图颜色过渡均匀。第4步的quiver是叠加矢量箭头step4表示每四个网格点取一个箭头这样箭头不会把云图盖住。最后用exportgraphics导出300 DPI的PNG图足以应付大多数汇报和论文初稿。4. 云图进阶从能看变成好看又严谨4.1 叠加矢量箭头让云图更有说服力单独的流速云图只能看速度大小看不出流动方向。很多情况下比如判断回流区还是顺流区、判断涡的旋转方向都需要矢量箭头的配合。在contourf画完的图上直接叠加quiver是最省事的方式。关键问题是箭头密度。PIV数据网格动辄上百乘上百如果每个点都画箭头整张图会变成一片黑刺什么都看不清。我的经验是先用step抽取子网格再画quiver。通常step取3到6具体看你数据的网格密度和图幅大小。画完后如果能隐约看到箭头的分布模式和云图结构相互印证说明密度正合适。箭头颜色默认是蓝色但在彩色云图上辨识度不够一般用黑色或白色。黑色适合亮色底色白色适合深色底色这个要根据你的配色临时调。还有quiver的缩放因子0.6表示箭头长度自动缩放到网格间距的0.6倍这个值可以微调保证箭头不重叠又足够清晰。4.2 多工况对比时颜色尺度和levels必须统一做实验研究很少只拍一个工况。不同来流速度、不同攻角、不同雷诺数下的流场云图放在一起对比是论文里的常规操作。但这里有一个特别容易犯的错误每张图各自用各自的色标范围。结果是同一片蓝色在这张图里代表0.2 m/s在另一张图里却代表0.5 m/s读者一对比就懵了。正确的做法是先通盘看所有工况确定一个统一的速度上限然后让每张子图的clim和levels完全一致。用tiledlayout或subplot排版时可以这样写tiledlayout(1, 2); nexttile; contourf(x1, y1, speed1, levels, LineStyle, none); clim([0 maxV]); colorbar; axis equal; set(gca, YDir, normal); title(Case 1); nexttile; contourf(x2, y2, speed2, levels, LineStyle, none); clim([0 maxV]); colorbar; axis equal; set(gca, YDir, normal); title(Case 2);这里的levels、maxV都是提前算好的统一值。这样两张图放在一起哪个区域流速高、哪个区域流速低一眼就能比较出来不用来回看色标。4.3 导出既清晰又符合投稿要求的图画完图之后最后一个环节是导出。很多同学直接截图或者用菜单栏的“保存”这样出来的图分辨率不够放到论文里全是锯齿。正确的方式是用exportgraphics它支持直接指定分辨率还能导出矢量图exportgraphics(gcf, piv_contourf.png, Resolution, 300);如果要投期刊最好导出矢量格式这样无论放大多少倍都不会糊exportgraphics(gcf, piv_contourf.pdf, ContentType, vector);导出之前记得把字体调大。默认的坐标轴字号在论文里通常偏小我会先set(gca, FontSize, 12)如果图里有label或title再单独设置字号。另外图上所有元素都要在导出前确认位置合适不要出现颜色条和坐标轴重叠、标题被截断之类的情况这些返工其实很费时间。5. 常见问题与排查技巧实录5.1 画出来的图上下颠倒或比例不对这是新手最容易碰到的两个问题原因都很简单。上下颠倒是因为没有设置YDir图像数据默认y轴向下对PIV结果来说如果不设set(gca, YDir, normal)流动方向就反了。比例不对是因为坐标系没有等比例缩放比如实验区域在x方向实际长度是20 mm、y方向是10 mm但屏幕绘图区域的长宽比没与之对应图就会变形。解决方式是加axis equal。这里有一个小技巧加上axis equal之后如果图周围出现大片空白说明你的x、y坐标范围本身不成比例可以再用xlim、ylim手动裁到合理范围。5.2 contourf出现了很多白色线或裂纹白色裂纹通常有两种来源。第一种是等值线间隙contourf在每个色块之间默认画了一条细白线网格细密的时候看起来像裂纹。这种情况只需设置LineStyle, none就能解决。第二种是数据里有NaN。NaN所在的区域在contourf中会显示为空白如果空洞是细碎的看起来就像白色裂纹。这种时候要先判断NaN范围。如果只是个别野点留下的洞用regionfill或fillmissing补上如果是盲区就保留空白但为了美观可以给坐标轴设置一个浅灰底色set(gca, Color, [0.8 0.8 0.8]);千万别对大面积盲区做插值。我见过有人把圆柱后面的尾流盲区插出一片低速区结果涡街结构全歪了这种错误在审稿人那里基本一眼就能看出来。5.3 等值线太乱看不清主流动结构如果云图上有大量细碎的闭合圈、颜色分布像噪声通常由三个原因导致数据太噪、levels太密、色标范围太窄。解决思路也是从这三个方向逐一排查。先看原始数据噪声。PIV计算出来的瞬时速度场本身就有一定噪声尤其粒子浓度低或互相关窗口小的时候。此时先做一次中值滤波再对速度幅值做轻微高斯平滑大部分细碎结构就会消失。再看levels如果等值线数量超过60色块会密集到看不出层级我一般不超过50条。最后检查clim范围如果色标只覆盖速度变化很小的一段区间噪声会被放大适当扩大色标范围能有效减小视觉上的杂乱感。我在处理圆柱绕流数据时通常会先画一版默认参数的草图判断主结构是否清晰再决定要不要加强平滑。这样能避免一开始就过度处理把真实的小涡也抹掉。5.4 contourf和imagesc到底选哪个不少同学习惯用imagesc画云图因为一行代码就能出图速度也快。但imagesc本质是像素图它把矩阵的每个元素当成一个像素画出来x和y轴默认是索引号需要额外指定坐标范围。它适合快速预览但作为正式结果图有几个弱点不能画等值线、不能直接控制levels、多个图对比时色标处理比较别扭。我整理了一个简单的对比方便按场景选择对比维度contourfimagesc等值线支持可自定义levels和clabel不支持坐标对应直接使用x、y矩阵需要设置XData、YData且像素中心有偏移NaN处理留白可配合底色显示为背景色控制起来不如contourf灵活适用场景正式科研出图、多图对比快速预览、大规模数据扫描实际上还有一个pcolor它在处理非均匀网格时比contourf灵活但默认会有网格线通常要加shading interp才好看。如果你画的PIV数据是均匀网格contourf基本就是最合适的选择。自己做PIV处理这一年多我最大的体会是别把最后一步画图看轻了它其实是整个实验的“收货”环节。前面辛苦做实验、算互相关、处理数据都是为了在这张云图上把流动现象讲清楚。contour函数本身并不难难的是你愿不愿意在数据清洗、levels设置、配色和导出这些细节上多花功夫。同一份速度场随手一画和精心一画传达的信息量可以差很多。最后再分享一个建议保存结果时除了云图一定把x、y、u、v和没有剔除野点的原始数据一起存成.mat后面无论换配色、调levels还是做统计分析都能随时重来不用再翻原始粒子图像重新跑一遍PIV。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑