资讯详情

MATLAB天线方向图三维绘制:坐标转换与sph2cart实战

📅 2026/10/20 16:16:01 | 华诺云谱 👁 阅读
MATLAB天线方向图三维绘制:坐标转换与sph2cart实战
简介MATLAB没有直接提供三维极坐标绘图函数内置polarplot只能处理二维而surf、mesh等默认基于笛卡尔坐标直接绘制球坐标系下的天线方向图常会遇到数据映射和坐标轴设置困难。这份资源以天线三维方向图为例给出了一套从极坐标数据到笛卡尔坐标转换、再通过surf完成可视化的完整流程结果与HFSS仿真的方向图一致适合电磁场与天线课程设计、科研后处理以及需要快速绘制三维方向图的MATLAB用户参考。压缩包共2个文件、约320KB一个m脚本用于读取数据、坐标转换与绘图另一个csv表格保存方向图采样数据文件结构简单替换为自己的仿真数据即可复用。目前已有16174人学习下载说明这种处理方法在工程实践中具有较强的通用性。借助现成代码和数据模板读者能快速理解三维极坐标绘制的坐标变换思路同时掌握surf在非直角坐标系下的灵活应用。1. MATLAB 三维极坐标绘图为什么天线方向图总是画成一摊扁平的饼MATLAB 三维极坐标绘图这个需求十个里有八个是从天线三维方向图过来的。polarplot 这类函数只能解决二维极坐标而天线三维方向图是 θ、φ、r 三个量同时变化的数据直接扔给 surf 会得到一张摊在平面上的饼主瓣、旁瓣的位置关系全部丢失。真正的问题不在画图命令而在坐标转换和数据结构这两件事上。把它们理顺之后无论是仿真导出的 r(θ, φ) 矩阵还是实测的剖面数据都能在两三步内转成可旋转的三维球面图。这篇笔记适合正被方向图可视化卡住、需要出图做汇报的从业者尤其是研究场景下反复改图的人。2. 把 (θ, φ, r) 变成 (X, Y, Z)sph2cart 的维度陷阱与 meshgrid 用法2.1 方向图为什么不能直接画天线方向图是在球坐标系下采样的场强 r 对应某个俯角 θ 和方位角 φ 的方向。二维极坐标图本质上只画了一个剖面比如固定 φ 看 r(θ)或者固定 θ 看 r(φ)。一旦要表达「整个球面上每个方向的大小」就必须把球坐标映射到直角坐标否则 surf 没有合法的 X、Y、Z 三个矩阵可用。很多人第一次写三维方向图会下意识把 θ 当成 X、φ 当成 Y、r 当成 Z。这样画出来的图不是球面而是把角度当成平面坐标的扭曲面形状完全是错的。核心原因是 θ 和 φ 是角度量不是直角坐标空间里的长度量它们之间不存在直接的线性映射关系。所以所有三维方向图代码的第一步必须是坐标转换而不是画图。2.2 meshgrid 与矩阵维度R 必须是二维矩阵方向图数据的形态决定你能不能直接绘图。如果 r 是一维向量比如 r abs(cos(theta))它只描述了一个剖面的幅度变化缺少方位维度的信息。三维图需要的 R 是二维矩阵每一行对应一个方位角每一列对应一个俯角或者说 R(i,j) 表示在 (θj, φi) 方向的场强。用 meshgrid 生成网格矩阵是最常见的做法。meshgrid(theta, phi) 返回两个矩阵 Theta 和 Phi它们的尺寸相同行数等于 phi 的长度列数等于 theta 的长度。换句话说Theta 的每一行是同一个俯角序列的复制Phi 的每一列是同一个方位角序列的复制。R 必须和这两个矩阵同尺寸否则 surf 在下一步就会报维度不匹配的错误。theta linspace(0, pi, 91); % 俯角0 为 z 方向pi 为 -z 方向 phi linspace(0, 2*pi, 181); % 方位角绕 z 轴一整圈 [Theta, Phi] meshgrid(theta, phi); % 模拟数据主瓣指向 z实际替换为你的 r(theta, phi) 矩阵 R abs(cos(Theta)); R R / max(R(:)); % 线性归一化便于比较形状这里 linspace 的采样点数决定了绘图分辨率。91 个俯角、181 个方位角生成的网格是 181×91对出图来说已经足够细腻。如果仿真数据本身就是高分辨率的后续可以降采样这个我在第 5 章展开讲。R 的计算直接利用了 Theta 矩阵而不是一维的 theta这是初学者最容易漏掉的一步。2.3 最小可运行示例与 sph2cart 的角度约定MATLAB 的 sph2cart 函数签名是 [x, y, z] sph2cart(az, el, r)注意第二个参数是仰角不是俯角。天线方向图常用的 θ 是从 z 轴往下的俯角而仰角是从 x-y 平面往上算的两者相差 90 度转换关系是 el pi/2 - θ。这个细节一旦搞错方向图会上下颠倒或者被压到 x-y 平面附近属于高频翻车点。theta linspace(0, pi, 91); phi linspace(0, 2*pi, 181); [Theta, Phi] meshgrid(theta, phi); R abs(cos(Theta)); % 替换成你自己的方向图数据 % 球坐标转直角坐标theta 是俯角必须先转成仰角 [X, Y, Z] sph2cart(Phi, pi/2 - Theta, R); % 用 R 作为颜色数据可以同时体现幅度和形状 surf(X, Y, Z, R, EdgeColor, none); axis equal; % 三轴等比例否则球体会被拉变形 colormap(jet); colorbar;这段代码里有几个值得注意的地方。sph2cart 的输入和输出都要求同尺寸矩阵所以 Theta、Phi、R 三者必须都是 181×91否则这一行就会报错。surf 的第四个参数 R 用于颜色映射这样球面上的颜色能反映增益大小而形状本身由 X、Y、Z 决定。axis equal 在三维绘图里经常被忽略少了它 MATLAB 会把三个轴自动缩放到不同比例一个正球体会被显示成椭球方向图的旁瓣位置看起来全错。如果手头的数据是 dB 值而不是线性幅度可以直接拿来画形状但颜色轴的含义要清楚。线性幅度更利于观察主瓣和旁瓣的相对高度dB 值更利于观察小电平特征两者各有用途我在第 4 章会专门讲 dB 转换和颜色轴设置。3. 三条实现路线自写转换、第三方函数、单剖面扩展3.1 路线 A全手动自写出图完全可控自己写坐标转换是最推荐的默认路线整个流程只有三步生成网格、转直角坐标、surf 绘制。它的好处是每个环节都在你的掌控之中出问题能定位到具体一行。数据来源无论是从仿真软件导出、从仪器实测还是用公式解析计算最终都归结为构造 R 矩阵。theta linspace(0, pi, 181); phi linspace(0, 2*pi, 361); [Theta, Phi] meshgrid(theta, phi); % 模拟一个稍微复杂的方向图phi 方向有变化 R abs(cos(Theta)) .* (0.6 0.4 * sin(Phi).^2); R R / max(R(:)); [X, Y, Z] sph2cart(Phi, pi/2 - Theta, R); surf(X, Y, Z, R, EdgeColor, none, FaceAlpha, 0.9); axis equal; view(45, 30); % 从方位角 45 度、仰角 30 度观察这里用 abs(cos(Theta)) 模拟俯角剖面再乘一个随 Phi 变化的小因子来表示方位方向的不均匀性。实际工程中 R 来自仿真导出可能是一个 (91, 181) 的 CSV 矩阵读进来后直接替换就行。需要提醒的是如果数据文件的排布是「行对应 θ、列对应 φ」而 meshgrid 生成的矩阵是「行对应 φ、列对应 θ」要用转置 R. 对齐否则画出来的方向图会旋转 90 度。3.2 路线 B调用 polarplot3d 第三方函数如果你不想关心坐标转换细节MATLAB 交换社区上有现成的 polarplot3d 函数可以用。它接收的输入是一个二维矩阵内部完成极坐标到直角坐标的映射并输出转换后的网格坐标。这个函数不在 MATLAB 自带工具箱里需要单独下载下载后要确认文件在搜索路径中。这个函数对输入矩阵的排布有自己的约定每一行对应径向采样每一列对应角度采样。方向图数据通常是「行对应 θ、列对应 φ」直接喂进去可能方向不对遇到图形异常时先试一下转置这是最有效的排查手段。% Z 的每一行是一条径向剖面每一列是一个角度采样 Z your_r_matrix; % 尺寸为 91 x 181按 polarplot3d 的约定排布 % 生成坐标网格 [Xi, Yi, Zi] polarplot3d(Z, ... PlotType, surfn, ... PolarGrid, {6, 12}, ... RadialRange, [0, 1]); surf(Xi, Yi, Zi, EdgeColor, none); axis equal;PlotType 参数控制绘制类型surfn 表示带网格表面的曲面也可以改用 mesh 只画线框。PolarGrid 控制网格密度第一个数是径向网格数第二个数是角度网格数。RadialRange 控制半径映射范围如果你的数据归一化过用 [0, 1] 即可。这个函数的好处是代码量少坏处是它是一个黑匣子一旦图形不符合预期你不太容易判断是数据排布错了还是函数参数设置错了。我的建议是先用它自带的示例数据跑通再替换自己的数据。3.3 路线 C只有单个 θ 剖面时用 repmat 扩展成三维很多实测场景下你只有一条剖面数据比如在某个固定方位角上测了 r(θ)这时候要画三维方向图需要假设天线在这个方位角附近具有圆周对称性。把单剖面复制到所有方位角方向上就能得到一个近似的三维球面图。这套做法的前提是天线大致全向或者你明确知道要展示的是一个理想化的对称模型否则画出来会误导人。theta linspace(0, pi, 91); phi linspace(0, 2*pi, 181); % 只有一条剖面主瓣在 z旁瓣电平较低 r_one abs(cos(theta)) .* (1 0.2 * cos(3 * theta)); [Theta, Phi] meshgrid(theta, phi); % 把单剖面复制到所有方位角方向形成完整的 R 矩阵 R repmat(r_one(:), length(phi), 1); [X, Y, Z] sph2cart(Phi, pi/2 - Theta, R); surf(X, Y, Z, R, EdgeColor, none); axis equal;repmat 的作用是把 1×91 的剖面向量复制成 181×91 的矩阵每一行都是同一条剖面。这里的乘法运算要注意r_one 是列向量还是行向量会直接影响 repmat 的结果。我一般用 r_one(:) 强制转成行向量再参与复制避免维度方向写反。这种扩展方法在数据不足时是有效的近似手段但它真正的局限在于完全丢失了方位方向的细节。如果后续拿到多剖面实测数据应该直接升级为完整矩阵绘图而不是继续用对称假设。4. 参数调节与出图colorbar 基准、透明度、视角与坐标轴等比例4.1 dB 转换与 clim让主瓣在颜色轴上「跳」出来方向图最常用的展示方式是用线性幅值决定球面形状用 dB 值决定颜色。如果直接用线性幅度作颜色轴旁瓣电平可能只有主瓣的几十分之一颜色几乎全部集中在蓝色区域视觉上完全看不出旁瓣分布。相反用 dB 值作颜色轴能把小电平差异放大但要小心 dB 转换后最低值可能到 -100 以下颜色轴被拉得很宽主瓣反而不突出了。R_lin R / max(R(:)); % 归一化线性幅度 R_db 10 * log10(R_lin eps); % 转 dB加 eps 防止 log10(0) % 截断底部把低于 -30 dB 的值统一设为 -30 dB R_db(R_db -30) -30; % 线性幅度作为形状dB 值作为颜色 surf(X, Y, Z, R_lin, R_db, EdgeColor, none); clim([-30 0]); % 固定颜色轴范围 colormap(parula); colorbar;surf 的第五个参数是颜色数据它和 Z 坐标数据分离这样形状和颜色可以来自不同的物理量。这里 Z 坐标用的是 R_lin颜色数据用的是 R_db两者含义不同但可以共存。clim 命令在较老的 MATLAB 版本里写作 caxis功能等价都是固定颜色轴上下限。把下限设为 -30 dB 意味着低于主瓣 30 dB 的区域全部显示为最冷色这符合大多数方向图报告的习惯。4.2 透明度与叠加剖面多维度对比不靠猜三维曲面画出来之后内部结构往往被外层遮挡尤其是存在多个旁瓣时背面的信息完全看不见。两个办法可以解决一是调低曲面透明度二是把关键剖面的二维曲线叠加到三维图上。% 半透明曲面内部结构可见 surf(X, Y, Z, R_db, EdgeColor, none, FaceAlpha, 0.8); axis equal; hold on; % 在 phi 0 的剖面上叠加一条曲线 r_prof abs(cos(theta)); x_prof r_prof .* sin(theta); y_prof zeros(size(theta)); z_prof r_prof .* cos(theta); plot3(x_prof, y_prof, z_prof, k-, LineWidth, 1.5); hold off;叠加剖面线的原理是把 θ 剖面转换成直角坐标x r·sinθz r·cosθφ0 时 y 恒为 0所以曲线落在 x-z 平面内。黑色曲线在彩色的球面上很醒目可以直接读出主瓣宽度、零点位置这些指标。透明度我一般设在 0.8 左右太低会让曲面显得太空太高又挡视线具体看背景色和环境光。4.3 视角、网格与 axis equal三维方向图的最后一块拼图方向图的三维形状对坐标轴比例极其敏感。axis equal 这个命令保证三个轴的单位长度一致不加它的话 MATLAB 会把图形自动缩放进一个长方体里球体会被拉成椭球明明是对称的方向图看起来却不对称。我第一次画三维方向图就栽在这个上面当时还以为是数据错了折腾了半天才发现是坐标轴比例的问题。视角选择方面view(45, 30) 是比较通用的初始视角方位角 45 度、仰角 30 度能同时看到主瓣和大部分旁瓣。想要强调某个剖面时把方位角切到那个剖面的角度即可。网格线用 PolarGrid 或直接在 surf 里保留 EdgeColor 的默认值但网格过密会显得杂乱我通常直接用 EdgeColor, none依赖颜色映射来体现变化。下面是出图阶段最常用的参数速查表目的命令写法说明固定颜色轴clim([-30 0])老版本用 caxis二者等价半透明曲面surf(..., FaceAlpha, 0.8)0.50.85 适合观察内部设置视角view(45, 30)方位角 45仰角 30三轴等比例axis equal防止球体被拉伸成椭球关闭网格线surf(..., EdgeColor, none)网格密集时必用隐藏坐标轴axis off只保留球面形状聚焦图形本身这几个参数组合起来足以应付大多数汇报场景。颜色映射的选择也有讲究jet 色彩饱和、跨度大适合对比强弱的场合parula 更平缓适合长时间观看和印刷。方向图领域用 jet 的偏多因为主瓣和旁瓣的界限鲜明。5. 避坑与常见问题五个让方向图翻车的细节5.1 画出来是一张平饼而不是球面现象surf 执行后得到的图形是一个在 x-y 平面附近的扁平曲面完全看不出球面的隆起旋转视角后形状依旧不对。原因把 θ 和 φ 当成了平面的 X、Y 坐标直接 surf(Theta, Phi, R)。θ 和 φ 是角度量它们之间不存在直角坐标对应的空间关系画出来的只是角度平面的映射不是三维球面。解决所有绘图前必须先经过 sph2cart 坐标转换用转换后的 X、Y、Z 作为 surf 的前三个参数。检查代码里有没有 [X, Y, Z] sph2cart(...) 这一步没有的话补上即可。5.2 方向图上下颠倒或者侧翻 90 度现象主瓣明明应该在 z 轴方向画出来却指向 -z 轴或者整个图案旋转了 90 度怎么看都不对。原因sph2cart 的第二个参数要求的是仰角从 x-y 平面往上算而天线方向图行业里习惯用俯角 θ从 z 轴往下算。两者相差 90 度。把 θ 直接传给 sph2cart等于把俯角当作仰角用主瓣方向自然就错了。解决转换时写 sph2cart(Phi, pi/2 - Theta, R)把俯角先换算成仰角。这个 pi/2 - Theta 是整段代码里最容易被忽略但最关键的一行建议在注释里标清楚。5.3 颜色条最高点不在主瓣上现象colorbar 显示的最大值并没有出现在主瓣区域反而是一些小旁瓣或者背景噪声占据了红色区域主瓣在颜色上不突出。原因clim 默认取颜色数据的全局最小值和最大值。如果数据里有极低的噪声电平比如 -80 dB颜色轴就被拉宽到 -80 到 0主瓣附近的 -1 dB 和 -10 dB 在颜色上几乎分不开。解决先对线性幅值归一化转成 dB 后做底部截断再用 clim 固定范围。代码模式是 R_db(R_db -30) -30 加上 clim([-30 0])。这样颜色轴与主瓣电平的对应关系是确定的任何数据套进来都不会因为异常点而跑偏。5.4 调用 polarplot3d 报 Undefined function现象运行脚本时 MATLAB 报错提示 Undefined function or variable polarplot3d或者提示找不到对应文件。原因polarplot3d 是第三方函数不在 MATLAB 自带工具箱里。下载后如果文件放在某个子目录而 MATLAB 当前工作目录和搜索路径都不包含这个目录函数就调用不到。解决先运行 which polarplot3d 查看 MATLAB 是否找得到这个函数。找不到就执行 addpath(函数所在目录)或者直接把函数文件复制到当前工作目录。另外一个隐蔽问题是第三方函数有不同版本参数名不完全一致建议先跑它自带的 demo确认环境正常后再替换自己的数据。5.5 数据量大之后旋转卡顿现象图形能正常显示但一旦用鼠标拖动旋转视角反应非常慢画面掉帧严重缩放也卡顿。原因仿真数据常常是高分辨率的比如 2000×2000 的网格surf 需要绘制数百万个面片MATLAB 图形引擎扛不住尤其是打开颜色映射和透明度之后更明显。解决绘图用的分辨率不需要和仿真计算分辨率一致出图阶段降采样到 180×90 完全够用。对矩阵做间隔采样即可例如 X(1:4:end, 1:4:end) 代表每 4 个点取 1 个四个坐标矩阵同步采样再传给 surf 绘制。step 4; surf(X(1:step:end, 1:step:end), ... Y(1:step:end, 1:step:end), ... Z(1:step:end, 1:step:end), ... R_db(1:step:end, 1:step:end), ... EdgeColor, none);降采样的步长根据数据量调整如果还是卡就把 step 改大到 8。注意颜色矩阵 R_db 也要同步降采样否则 surf 会报颜色数据和坐标维度不匹配这属于降采样时最容易连带出来的批量报错。6. 封装成函数三分钟把任意数据套进三维方向图6.1 pattern3d 函数设计每次处理方向图都要重复坐标转换、dB 截断、颜色轴设置这几步写多了之后我干脆封装成一个函数。输入约定为theta 是俯角向量phi 是方位角向量r 可以是 length(theta)×length(phi) 的完整矩阵也可以是长度与 theta 相同的一维剖面向量。函数内自动区分两种输入向量按圆周对称扩展。function pattern3d(theta, phi, r, varargin) % 输入 % theta: 俯角向量范围 [0, pi]从 z 轴算起 % phi: 方位角向量范围 [0, 2*pi] % r: 幅度数据尺寸 length(theta) x length(phi) % 或长度等于 length(theta) 的一维向量按圆周对称扩展 p inputParser; addParameter(p, DBRange, [-30 0]); addParameter(p, FaceAlpha, 0.85); addParameter(p, ViewAngle, [45 30]); addParameter(p, ColorMap, jet); parse(p, varargin{:}); opt p.Results; if isvector(r) r repmat(r(:), length(phi), 1); % 单剖面扩展 else r r; % 对齐 meshgrid 排布 end [Theta, Phi] meshgrid(theta, phi); Rlin abs(r); Rlin Rlin / max(Rlin(:)); % 俯角转仰角后再转直角坐标 [X, Y, Z] sph2cart(Phi, pi/2 - Theta, Rlin); RdB 10 * log10(Rlin eps); RdB(RdB opt.DBRange(1)) opt.DBRange(1); RdB(RdB opt.DBRange(2)) opt.DBRange(2); surf(X, Y, Z, RdB, ... EdgeColor, none, ... FaceAlpha, opt.FaceAlpha); axis equal; view(opt.ViewAngle); colormap(opt.ColorMap); clim(opt.DBRange); colorbar; end这个函数把整套绘图流程收敛成一次调用输出参数暴露了最常用的四个调节项DBRange 控制颜色轴上下限FaceAlpha 控制透明度ViewAngle 控制视角ColorMap 控制色图。老版本 MATLAB 如果 inputParser 不兼容可以换成手动检查 varargin 的方式逻辑一样。函数内部把 r 的尺寸约定为「行对应 θ、列对应 φ」这是大多数仿真数据的默认排布方式内部转置是为了和 meshgrid 的输出格式对齐。6.2 调用示例与验证方法验证函数正确性的最快方式是先用理论模型跑一遍。abs(cos(theta)) 这种形状主瓣明确指向 z旁瓣完全对称任何坐标转换错误都会在它上面立刻暴露。theta linspace(0, pi, 91); phi linspace(0, 2*pi, 181); % 完整矩阵输入主瓣 zphi 方向有轻微起伏 [Theta, Phi] meshgrid(theta, phi); r abs(cos(Theta)) .* (0.7 0.3 * cos(2 * Phi)); pattern3d(theta, phi, r, DBRange, [-40 0], ViewAngle, [60 20]); % 单剖面输入假设圆周对称 r_prof abs(cos(theta)) .* (1 0.2 * cos(3 * theta)); pattern3d(theta, phi, r_prof, ColorMap, parula);用理论模型确认主瓣位置、旁瓣对称性、颜色轴范围都符合预期之后再把真实仿真数据替换进去。从那以后我每次处理方向图数据都强制走一遍这个流程先确认 θ 和 φ 的维度排布再检查俯角到仰角的转换然后固定颜色轴范围最后才考虑用什么视角和颜色映射。这套流程帮我挡掉了至少七八次汇报前的临时返工。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑