ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于MATLAB的三维波束形成仿真:从阵列模型到波束扫描图谱

2026/9/14 3:29:23 拓冰建站 浏览量
基于MATLAB的三维波束形成仿真:从阵列模型到波束扫描图谱 简介基于MATLAB的波束形成仿真资源面向通信、雷达及信号处理方向的本科生或工程师用于理解俯仰角、方位角与波束形成幅度之间的三维映射关系。压缩包共4个文件内含核心m源程序、两张效果图以及一段avi操作录像程序基于MATLAB 2021a编写录像演示了如何将当前文件夹切换至程序所在路径并运行仿真能有效规避新手常见的路径错误。资源已有505人学习适合课程设计、课题入门或阵列信号处理实验复现。通过运行m程序即可输出三维关系图结合效果图和录像可对照结果、理清参数影响快速掌握波束形成的基本仿真流程。1. 从一维方向图到三维波束扫描图谱大多数教材讲波束形成时先画水平面或者垂直面的一维方向图切片实际调试相控阵或声学阵列时最容易被忽略的副瓣和栅瓣往往就藏在你没看的那条切线上。这份基于 MATLAB 的波束形成仿真用 Runme.m 直接把俯仰角、方位角与波束形成幅度画成三维关系图把整个可见空域的响应摊开在眼前主瓣偏移、副瓣抬升、阵列布阵错误都能一眼定位。matlab2021a 可直接运行包里还带着操作录像对刚接触阵列信号处理的人以及想快速验证权重方案的老手都合适。下面从数学模型拆起再到代码、参数和排错最后给出把固定波束改成扫描波束的扩展思路。2. 阵列模型、导向矢量与波束形成幅度计算2.1 从线阵到面阵为什么要用俯仰角和方位角两个维度均匀线阵只有一个维度的相位差方向图通常只随方位角变化画成三维图时会发现另一个维度根本没有信息。要真正做出俯仰角、方位角和幅度三个维度的关系图阵元必须分布在平面上最常见的是均匀矩形阵列URA或规则圆环阵列。这个仿真资源里虽然没有强制指定具体阵形但三维图对坐标建模的要求是一致的每个阵元必须给出 (x, y) 平面坐标然后对每一个扫描方向计算所有阵元之间的相位差。常见做法是取 8×8 或 12×12 的矩形栅格阵元间距取半波长。半波长是防止栅瓣出现的经验值间距再大会在可见空域复制出额外的栅瓣间距再小则阵列孔径不足主瓣明显变宽。下面这张表给出一组能跑通整个流程的默认参数不是资源里写死的数字换成其他频率和阵列规模也一样能跑通。参数典型值作用阵元行数8决定俯仰方向孔径阵元列数8决定方位方向孔径阵元间距 d半个波长避免栅瓣工作频率 f02.4 GHz计算波数俯仰角范围0°90°通常从阵列法线开始扫方位角范围0°360°绕阵列平面整个扫一圈这里的俯仰角如果按从 z 轴正方向往下计算那 0° 对应阵列法线90° 落在阵面内如果按从 xy 平面起算角度含义则完全相反。MATLAB 绘图代码里常用meshgrid生成扫描网格跑图之前先确认角度起点定义不然你把波束指向设为 30°出来主瓣却出现在 60°很容易误判成代码 bug。2.2 导向矢量的复指数模型假设第 n 个阵元的坐标是 (x_n, y_n)入射信号从俯仰角 θ、方位角 φ 到达阵列。以坐标原点为参考点第 n 个阵元的空间相位差可以写成 k 乘以 (x_n·sinθ·cosφ y_n·sinθ·sinφ)其中 k 2π/λ 是波数。把这些阵元的复指数排成一列就得到该方向对应的导向矢量 a。波束形成的核心逻辑是选取复权重向量 w让期望方向信号同相叠加其他方向尽量被抑制。最常见也最容易实现的权重是直接取期望方向 (θ0, φ0) 的导向矢量也就是相位对齐权。分享一段常用的方形阵列导向矢量生成代码。Runme.m 在做三维曲面图之前核心一定也是这一步只是原始脚本可能用exp(1j*...)展开写而不是封装成函数% 参数定义 f 2.4e9; % 工作频率单位 Hz c 3e8; % 光速 lambda c / f; d lambda / 2; % 阵元间距按半波长设置 Nx 8; Ny 8; x (0:Nx-1) * d; % 建立 x 方向阵元坐标 y (0:Ny-1) * d; [X, Y] meshgrid(x, y); % 二维网格不用循环生成 % 计算导向矢量输入俯仰角 theta、方位角 phi k 2*pi / lambda; theta_t 30 * pi/180; % 波束指向俯仰角转弧度 phi_t 45 * pi/180; % 波束指向方位角转弧度 steer exp(1j * k * ( X(:) * sin(theta_t)*cos(phi_t) ... Y(:) * sin(theta_t)*sin(phi_t) )); steer steer / sqrt(Nx*Ny); % 归一化保证能量不变代码里X(:)和Y(:)把 8×8 网格拉成 64 个坐标点和导向矢量的 64 个元素一一对应。sin(theta_t)把俯仰角投影到 xy 平面的方向余弦cos(phi_t)和sin(phi_t)再把这个投影分解到 x、y 两个坐标轴。注意所有角度必须从度转成弧度MATLAB 的三角函数默认按弧度计算忘记转换是本仿真里最常见的主瓣错位原因。steer中每个元素的幅度都是 1相位由阵元位置和入射方向唯一确定。2.3 输出幅度计算与归一化有了导向矢量和固定权重后波束形成输出就是对每个扫描方向计算abs(w * a)。w 固定为期望方向上的导向矢量a 则随扫描角度变化。这份资源里的“幅度”多数情况是电压幅度所以画出来的 z 轴范围在 0 到 1 之间峰值对应波束指向方向。下面这段代码可以看成 Runme.m 的中间计算主体和上面的steer直接衔接theta_scan 0:1:90; % 俯仰扫描范围单位度 phi_scan 0:1:360; % 方位扫描范围单位度 [TH, PH] meshgrid(theta_scan, phi_scan); beam zeros(size(TH)); for idx 1:numel(TH) t TH(idx) * pi/180; p PH(idx) * pi/180; a exp(1j * k * ( X(:) * sin(t)*cos(p) ... Y(:) * sin(t)*sin(p) )); a a / sqrt(Nx*Ny); beam(idx) abs(steer * a); % 复内积取模 end beam beam / max(beam(:)); % 归一化让最高点等于 1这里的循环一共算了 91×361 32851 个方向每个方向做一次 64 维复内积在 matlab2021a 上大概一两秒跑完属于可接受的仿真规模。如果要扫 0.1° 步长循环次数会膨胀到 300 万次必须改成矩阵乘法这个在第 5 章会给出替代写法。steer是共轭转置不能写成steer.否则复数相位相加会变成相减波束形成结果完全错误。这是初级用户最常踩的坑之一三维图上会表现为乱纹或主瓣消失。3. Runme.m 的三维波束形成仿真流程与路径坑3.1 主脚本的四个模块读懂这份仿真包不需要从头到尾逐行看Runme.m 做的事情可以分成四个模块清空环境并设置仿真参数建立阵元网格和波束指向权重在俯仰角、方位角网格上计算波束形成幅度用surf或mesh绘制三维关系图并添加坐标标签。包里的操作录像就是用 Windows Media Player 播放的视频里能看到第 4 步生成了三维曲面图并且拖动视角观察主瓣和副瓣。很多初学者第一次打开 Runme.m 直接按 F5结果报Undefined function or variable问题基本出在模块 1MATLAB 左侧“当前文件夹”没有切换到脚本所在目录。录像特意录下了那个切换动作就是提醒你路径必须先设对。你可以在 MATLAB 编辑器里点 Run 按钮旁边的向下箭头选择“更改文件夹”或者直接执行cd到解压目录。注意如果当前文件夹不是 Runme.m 所在目录即使文件在编辑器里打开着脚本里依赖的同目录数据文件或子函数也可能加载不到这是下载资源类项目最常见的启动失败原因。3.2 三维绘图时的坐标映射计算完beam矩阵后绘图代码建议写成下面这种形式和仿真包的输出风格保持一致figure; surf(phi_scan, theta_scan, beam); xlabel(方位角 (deg)); ylabel(俯仰角 (deg)); zlabel(归一化幅度); colormap(jet); colorbar; view(45, 30); % 调整初始视角方便看到主瓣和副瓣 shading interp; % 平滑曲面颜色避免黑色网格线干扰视线surf的第一个参数对应 x 轴第二个对应 y 轴第三个是高度。这里phi_scan和theta_scan是长度不等的向量surf会自动把它们整合成网格坐标前提是beam的行数等于length(theta_scan)列数等于length(phi_scan)。如果把beam的尺寸写反会出现矩阵维度不匹配报错或者图形整体转置 90°。更保险的写法是surf(TH, PH, beam)因为TH、PH已经是meshgrid生成的完整矩阵尺寸关系一目了然。仿真包里如果画成环状极坐标样式说明代码把角度转成了弧度用surf(phi_scan.*pi/180, theta_scan.*pi/180, beam)绘制。这种风格更接近雷达显示习惯视觉上方位角 0° 到 360° 会变成一个圆环平面但不影响计算结果。我一般先用直角坐标确认主瓣位置出汇报图时再切成球坐标风格。3.3 对照录像复现的完整步骤步骤操作验证结果1解压到纯英文目录路径不要带中文和空格ls能看到 Runme.m 和 avi 文件2打开 MATLAB切换当前文件夹到解压目录编辑器标题栏显示当前目录与脚本路径一致3双击 Runme.m点击运行命令行无红色报错4等待角度循环跑完弹出三维曲面图最高点颜色最亮5用工具栏旋转图形主瓣峰值位置不随视角变化操作录像在 Windows Media Player 里播放注意录像里演示的界面大概率是 matlab2021a如果你的版本是 R2018b 或 R2023b算法代码仍然兼容只是个别绘图函数默认配色稍有差异。如果打开 Runme.m 后看到变量名以下划线结尾不需要担心那只是打包者为了区分参数区和计算区养成的命名习惯。命令行报错时优先看第一处红色高亮行后面跟的往往是连锁错误提示。3.4 为什么固定波束指向下三维图仍然有形状有些读者会问波束指向已经固定扫描全空域得到的不就是方向图吗方向图形状由阵列几何和权重共同决定。8×8 阵列在 30° 俯仰、45° 方位指向时主瓣会出现在该方向但副瓣分布并不对称因为矩形阵列在 x、y 两个方向上的孔径投影不同。三维图把这种不对称直观暴露出来设计者能马上看出副瓣集中在哪个方位角区间而不是只看到一维指标里写的“最大副瓣 -13.5 dB”。这份资源最有价值的地方就在于此先用三维图做全局判断再回到一维切片做定量分析。4. 三维图参数、读取方式与调试技巧4.1 角度分辨率与阵元数量的取舍角度扫描步长直接决定计算量和图形精细度。步长 5° 时曲面边缘有明显锯齿步长 1° 时主瓣轮廓平滑仿真时间从几十毫秒涨到几秒步长 0.1° 时单循环跑起来非常慢建议直接用向量化矩阵计算。阵元数的影响是另一个维度8×8 和 12×12 的主瓣宽度不同但扫描网格维度不变运算量主要由角度网格数量决定所以增加阵元数不会显著拉长仿真时间。阵列规模主瓣 3dB 宽度估首副瓣电平对三维图视觉影响推荐扫描步长8×812° 左右约 -13.2 dB主瓣圆润容易观察2°12×128° 左右约 -13.2 dB峰值尖锐需要更细网格1°均匀加权下首副瓣电平在两种阵列上相差不多因为这是由阵列孔径的傅里叶变换旁瓣特性决定的对应 sinc 函数的首瓣 -13.26 dB。如果三维图里看到的副瓣明显高于这个水平就要怀疑阵元间距是否超过半波长或者当前角度范围内出现了栅瓣。均匀阵列的副瓣在三维图上表现为围绕主瓣的一圈圈波纹颜色从红色渐变到蓝色整体分布比较规则。4.2 用绘图设置提升可读性直接用surf画出来的图默认带黑色网格线在密集角度下会干扰主瓣判断。加上shading interp后再用colorbar看幅度刻度图形会干净很多。如果只想快速定位峰值方向把视角切到正上方即view(0, 90)主瓣会变成亮红色区域方位角和俯仰角坐标轴直接读出figure; surf(phi_scan, theta_scan, beam); shading interp; colorbar; clim([0 1]); % 只显示 01 的线性幅度适合看归一化主瓣 view(0, 90); % 从 z 轴正上方往下看 xlabel(方位角 (deg)); ylabel(俯仰角 (deg));clim([0 1])在 R2022a 之后用于替代旧的caxis作用是限定颜色映射范围。如果更关心副瓣结构可以把显示量切换成 dBbeam_db 20*log10(beam 1e-12);然后把clim设为[-40 0]。低于 -40 dB 的区域全部显示为深蓝色副瓣波纹会比线性幅度清楚得多。线性显示适合看主瓣dB 显示适合挑副瓣两者配合才能把三维图真正读透。4.3 常见错误和排查顺序运行这套仿真如果结果不对从三个地方按顺序检查。第一检查角度单位。sin(theta)默认要求弧度如果直接把0:90喂进去方向图峰值不会落在期望角度。建议在参数区定义deg2rad pi/180所有角度变量乘上它再参与计算。第二检查矩阵尺寸和索引顺序。[TH, PH] meshgrid(theta_scan, phi_scan)返回的行对应phi_scan列对应theta_scan而surf(theta_scan, phi_scan, beam)要求beam是length(phi_scan)×length(theta_scan)稍不注意就会画成转置曲面。第三检查权重向量的转置方式。steer是共轭转置如果误用steer.相位叠加会变成相位相减三维图变成对称乱纹主瓣幅度也不再归一化。如果代码层面都没问题主瓣仍然偏移固定角度那大概率是坐标轴定义和角度参考不一致。有些代码的方位角从 x 轴起算有些从 y 轴起算两者相差 90°。排查时打印导向矢量前几个元素的相位取 θ30°、φ0° 的理论值x 方向相邻阵元的相位差应该等于2π/λ * d * sin(30°)也就是 90°。如果打印结果不是这个值说明坐标定义里 x 和 y 可能对调了或者俯仰角参考轴选错。4.4 截取一维切片验证三维图三维图适合全局观察但做定量分析必须回到一维切片。可以在 Runme.m 后面追加一段代码提取某个方位角上的俯仰向切片和理论方向图做对比phi_fixed 45; % 想要观察的方位角单位度 [~, phi_idx] min(abs(phi_scan - phi_fixed)); beam_slice beam(:, phi_idx); % 取出该方位上的俯仰切片 figure; plot(theta_scan, beam_slice, LineWidth, 1.5); xlabel(俯仰角 (deg)); ylabel(归一化幅度); title(sprintf(方位角 %d° 处的切片, phi_fixed));min(abs(phi_scan - phi_fixed))的好处是即使phi_fixed不在phi_scan数组里也能自动找到最近点比直接用find(phi_scan phi_fixed)更健壮。切片验证能让主瓣位置精确到 1° 以内。配合findpeaks(beam_slice)还能自动列出所有副瓣位置和电平再对照三维图决定是否加窗修正。5. 从固定波束到角度扫描进一步榨干这份仿真5.1 把固定波束改成全空域扫描Runme.m 里的steer固定只有一个指向三维图描述的是这个指向下全空域的方向图响应。实际做目标捕获时需要让波束在俯仰和方位上逐步挪动每挪一次记录一个响应值。这个改造不需要重写整个脚本只需把steer放进指向角度循环里再保存每次扫描的峰值theta_0s 10:10:80; % 波束指向俯仰角列表 phi_0s 0:30:330; % 波束指向方位角列表 peak_matrix zeros(length(theta_0s), length(phi_0s)); for i 1:length(theta_0s) for j 1:length(phi_0s) t0 theta_0s(i) * pi/180; p0 phi_0s(j) * pi/180; steer exp(1j * k * ( X(:) * sin(t0)*cos(p0) ... Y(:) * sin(t0)*sin(p0) )); steer steer / sqrt(Nx*Ny); response abs(steer * a_full); peak_matrix(i, j) max(response); end end这里的a_full是某个真实来波方向对应的导向矢量相当于把原仿真从“画固定波束方向图”变成了“用一组波束覆盖整个空域”。peak_matrix最大值出现的位置就是对来波方向的粗略估计这就是数字波束测向的基础思路。改造后你可以把peak_matrix画成热力图比单张三维图更接近工程产品里的角度-角度输出界面。5.2 快速验证改动是否正确改完固定波束为扫描波束后最简单的验证方法是让来波方向等于某个波束指向比如 θ40°、φ120°然后检查peak_matrix最大值是否落在theta_0s 40和phi_0s 120对应的格子附近。如果偏移超过一个波束步进说明波束权重的相位参考点选错了。还有一种常见调整是把 8×8 换成 4×8这时 x 和 y 方向阵元数不等导向矢量里的X(:)和Y(:)必须重新生成否则会出现维度错误或者三维图上只在方位方向变宽、俯仰方向不变化。换阵列尺寸前用size(unique(X(:)))确认 x 坐标有 Nx 个不同值y 坐标有 Ny 个不同值再跑仿真就稳了。5.3 把循环改成矩阵运算如果角度扫描步长要小于 1°前面的 for 循环会慢到难以接受。把循环合并成矩阵乘法是最常用的提速手段Runme.m 也可以直接照这个思路改TH_all reshape(TH, 1, []) * pi/180; PH_all reshape(PH, 1, []) * pi/180; A_all exp(1j * k * ( X(:) * sin(TH_all).*cos(PH_all) ... Y(:) * sin(TH_all).*sin(PH_all) )); beam abs(steer * A_all); beam reshape(beam, size(TH));X(:) * sin(TH_all)形成 64×32851 的相位矩阵左侧行是阵元右侧列是角度网格矩阵乘法的结果就是所有方向上的波束形成响应。这段代码在 matlab2021a 上只需要零点几秒比原来的循环快几十倍。改完后建议先用原来的循环版本对比一个固定方位切面确认两种写法的数值完全一致再把旧代码注释掉。这也是把这份三维波束形成仿真从演示级别推进到实用级别最值得做的一次重构。本文还有配套的精品资源点击获取