简介:这是一份基于MATLAB实现的自适应波束形成算法项目源码,主要包含LMS(最小均方)与RLS(递归最小二乘)两种经典算法,并配套独立的波束形成仿真文件。资源面向信号处理、阵列信号处理及通信工程方向的新手和有一定经验的开发人员,可帮助理解无约束自适应波束形成的基本原理、参数设置与性能对比。压缩包内共有3个文件,其中2个为可直接运行的.m脚本,分别对应LMS与RLS算法的波束形成实现,可快速产出方向图并观察收敛效果;另1个为docx格式的算法说明文档,便于对照原理梳理代码流程。整个资源包仅14KB,轻量便携,适合课堂实验、课程设计或入门自学。当前已有665人学习下载,代码均经过测试校正,下载后可在MATLAB环境中直接运行,若遇问题还可联系作者获得指导。学习本资源可以掌握完整的波束形成仿真流程,节省自行查找与调试时间,是快速上手自适应阵列算法的实用工具。
1. 波束形成为什么要用 LMS 和 RLS 这类自适应算法
一个 8 元均匀线阵摆在桌面上,期望信号从 0° 方向来,一个强干扰从 30° 方向来。普通相移波束形成的波束图是固定的,主瓣对准 0° 之后,30° 方向通常只剩 -13dB 左右的副瓣,干扰功率一高就把期望信号淹没了。自适应波束形成的思路是让权向量随接收数据实时更新,在干扰方向自动挖出数十 dB 深的零陷,这正是 LMS 算法和 RLS 算法在阵列信号处理里的核心用途。LMS 用瞬时梯度做最陡下降,每步只做一次乘加,简单稳定;RLS 递归估计输入协方差矩阵的逆,收敛快一个数量级,适合快拍有限的场景。下面从信号模型开始,把公式推导、MATLAB 实现和调参坑点一次讲完,新手能照着跑通,熟手可以对照自己的工程实现检查边界。
2. LMS 与 RLS 的数学基础:导向矢量、代价函数和递推式
2.1 均匀线阵的信号模型:从快拍到导向矢量
M 个阵元沿直线等间距排列,阵元间距 d 与载波波长 λ 的比值通常取 0.5,这是把空间采样率卡在奈奎斯特边界上,避免角度域出现栅瓣。以第一个阵元为参考点,某个远场平面波以 θ 角入射时,第 m 个阵元相对参考点的传播延迟是 md sinθ / c,折算成相位就是 2πmd sinθ / λ,于是来波方向 θ 的导向矢量写成
a(θ) = [1, e^{j2πd sinθ/λ}, ..., e^{j2π(M-1)d sinθ/λ}]^T把某一时刻所有阵元的采样值拼成一个 M 维复向量 x(n),就是一个快拍。期望信号 s(n)、P 个干扰 j_i(n) 和加性白噪声 v(n) 叠加后,第 n 次快拍的接收向量是
x(n) = a(θs)s(n) + Σ a(θi)j_i(n) + v(n)波束形成的输出是 y(n) = w^H x(n),w 是 M×1 复权向量,上标 H 表示共轭转置,MATLAB 里对应 w'。而 w.' 是不取共轭的转置,初学者最容易在这里写错,后面验证波束图时会出现零陷左右镜像的怪现象。自适应波束形成要做的事,就是根据 x(n) 的统计特性迭代调整 w,让期望信号尽量保留、干扰和噪声被压下去。
2.2 LMS 算法:用瞬时梯度逼近维纳解
LMS 的最小化目标是均方误差 J(w) = E|d(n) − w^H x(n)|^2,其中 d(n) 是期望响应。对 w 求梯度得到 −2E[x(n)e*(n)],但真实统计量拿不到,LMS 直接用单次快拍的瞬时值替换梯度,得到递推式
w(n+1) = w(n) + μ e*(n) x(n), e(n) = d(n) − w^H(n)x(n)μ 是步长。收敛条件理论上是 0 < μ < 2/λmax,λmax 是输入协方差矩阵 R 的最大特征值;工程上算特征值太贵,一般以 μ < 1/tr(R) 为起点,tr(R) 就是阵列总输入功率的量级。LMS 每步复杂度只有 O(M),但收敛速度受 R 的特征值散布 λmax/λmin 影响很大:期望信号和干扰功率相差 30dB 时,特征值散布上千,LMS 需要上万快拍才能收敛,学习曲线拖出长长的尾巴,这是它先天性的短板。
2.3 RLS 算法:递归估计协方差逆矩阵
RLS 的代价函数换成带遗忘因子的加权最小二乘 J(w) = Σ λ^(n−i) |e(i)|^2,λ 越接近 1,历史数据权重越大。它不直接求 R,而是用 P(n) 递推估计 R^−1,增益向量和权更新式为
k(n) = P(n−1)x(n) / (λ + x^H(n)P(n−1)x(n)) α(n) = d(n) − w^H(n−1)x(n) w(n) = w(n−1) + k(n)α*(n) P(n) = (P(n−1) − k(n)x^H(n)P(n−1)) / λ从形式上看,增益向量里乘了 P(n−1),相当于对输入先做白化,使各特征方向的收敛速度趋于一致,所以 RLS 的收敛速度基本不受特征值散布影响,快拍 100 以内就能看到零陷成型。代价是每步 O(M^2) 的复杂度,以及 P 矩阵长时运行中的数值漂移,后者要靠正则化系数 δ 和周期性重建 P 来控制。
2.4 选型判据:快拍数、非平稳度与算力约束
选 LMS 还是 RLS,先数快拍。一次实验只有 200 个快拍,LMS 可能还没收敛就结束了,RLS 在短数据下的优势是压倒性的;跑几万快拍、要求低算力的在线系统,LMS 更合适。再看环境平稳性:干扰方向快速变化时,RLS 的遗忘因子能较快重建零陷,但 λ 取得太小会让稳态权抖动;LMS 结构简单,在 DSP 或 FPGA 上容易流水化,实时性反而更好。两类算法的典型定位如下。
| 对比项 | LMS | RLS |
|---|---|---|
| 迭代公式 | w(n+1) = w(n) + μe*(n)x(n) | w(n) = w(n−1) + k(n)α*(n) |
| 单步复杂度 | O(M) | O(M^2) |
| 收敛速度 | 慢,受特征值散布影响 | 快,接近牛顿方向 |
| 稳态失调 | 与 μ 成正比 | 与 1−λ 成正比 |
| 主要参数 | 步长 μ | 遗忘因子 λ、正则化 δ |
| 适用场景 | 长数据、低算力实时系统 | 短快拍、强非平稳环境 |
3. 在 MATLAB 里跑通 LMS 和 RLS 波束形成的最小代码
3.1 仿真参数与接收数据生成
先把数组和信号参数写清楚。下面的代码生成 8 阵元的均匀线阵,期望信号在 0°,两个干扰分别在 20° 和 −30°,信噪比 10dB、干噪比 30dB,共 1000 个快拍。设随机数种子是为了让每次运行结果可复现,排错时这一点很重要。
M = 8; % 阵元数 thetaS = 0; % 期望信号方向(度) thetaJ = [20, -30]; % 干扰方向(度) N = 1000; % 快拍数 SNRdB = 10; INRdB = 30; dlam = 0.5; % 阵元间距/波长 = 0.5 thetaGrid = linspace(-90, 90, 181); % 导向矢量函数,theta 直接给度数 steer = @(theta) exp(1j*2*pi*dlam*(0:M-1).'*sind(theta)); aS = steer(thetaS); aI = steer(thetaJ); rng(2024); s = sqrt(10^(SNRdB/10)) * (randn(1,N) + 1j*randn(1,N))/sqrt(2); j1 = sqrt(10^(INRdB/10)) * (randn(1,N) + 1j*randn(1,N))/sqrt(2); j2 = sqrt(10^(INRdB/10)) * (randn(1,N) + 1j*randn(1,N))/sqrt(2); v = (randn(M,N) + 1j*randn(M,N))/sqrt(2); % 单位功率噪声 X = aS*s + aI(:,1)*j1 + aI(:,2)*j2 + v; % M x N 接收矩阵匿名函数steer里用sind直接吃角度,省掉 deg2rad 转换;(0:M-1).'把行向量转成列向量,保证导向矢量是 M×1。干扰和噪声按实部、虚部各 0.5 功率构造复信号,总功率为 1。X 的每一列是一个快拍,后面所有算法都按列处理。
3.2 LMS 波束形成主循环
期望响应 d(n) 取期望信号本身 s(n),这样一来算法学会在保持期望信号的同时抑制干扰。权向量初值取常规波束形成的导向矢量 aS/M,让主瓣从 0° 起步,而不是从全零向量起跑,收敛速度会快不少。
mu = 0.002; % 步长,按 1/trace(R) 量级估算后缩小 wLMS = aS / M; % 初始权:常规延时求和 eLMS = zeros(1,N); for n = 1:N x = X(:,n); y = wLMS' * x; e = s(n) - y; % 期望响应是期望信号 wLMS = wLMS + mu * conj(e) * x; eLMS(n) = abs(e)^2; end % 输出 SINR 估计:信号功率 / (干扰功率 + 噪声功率) Ps = 10^(SNRdB/10); Pi = 10^(INRdB/10); sinrLMS = (abs(wLMS'*aS).^2 * Ps) / (sum(abs(wLMS'*aI).^2) * Pi + wLMS'*wLMS);注意:
conj(e)对应推导里的 e*(n)。把共轭漏掉时 LMS 不会立刻发散,但更新方向偏了,收敛后的零陷明显变浅,这是最常见的实现错误。
步长 μ 的估算做法是先算1/trace(X*X'/N)得到参考值,再缩小 5~10 倍使用,避免接近发散边界。最后三行算的是输出信干噪比,信号和干扰功率都做了线性化折算,噪声功率就是 ||w||^2,因为每阵元噪声功率为 1。
3.3 RLS 波束形成主循环
RLS 初始化时给 P 乘一个较大的正则化系数 δ,防止前几个快拍矩阵奇异。δ 一般取 0.01~1,和输入功率同量级即可。
lambda = 0.995; % 遗忘因子 delta = 0.1; wRLS = aS / M; Pmat = delta * eye(M); % 逆相关矩阵初值 eRLS = zeros(1,N); for n = 1:N x = X(:,n); k = Pmat * x / (lambda + x' * Pmat * x); % 增益向量 alpha = s(n) - wRLS' * x; % 先验误差 wRLS = wRLS + k * conj(alpha); Pmat = (Pmat - k * x' * Pmat) / lambda; eRLS(n) = abs(alpha)^2; end sinrRLS = (abs(wRLS'*aS).^2 * Ps) / (sum(abs(wRLS'*aI).^2) * Pi + wRLS'*wRLS);RLS 的误差 α(n) 用的是更新前的权向量计算,所以叫先验误差,和 LMS 里 e(n) 的时序略有差别,但对比收敛曲线时不影响结论。P 矩阵每轮都要除以 λ,漏掉这一步会让 P 越滚越大,最终权向量漂移甚至溢出。
3.4 画波束图与学习曲线
波束图用最后一个权向量扫角度,画 20log10 归一化幅度;学习曲线用平方误差的 50 点滑动平均,两条曲线叠在一起,收敛速度一眼可见。
pat = @(w) 20*log10(abs(w' * steer(thetaGrid)) / max(abs(w' * steer(thetaGrid)))); figure; subplot(2,1,1); plot(thetaGrid, pat(wLMS), 'b', thetaGrid, pat(wRLS), 'r', ... [thetaJ(1) thetaJ(1)], [-60 0], 'k--', [thetaJ(2) thetaJ(2)], [-60 0], 'k--'); legend('LMS', 'RLS', '干扰1', '干扰2'); xlabel('角度 (deg)'); ylabel('归一化幅度 (dB)'); grid on; subplot(2,1,2); plot(1:N, movmean(10*log10(eLMS), 50), 'b', ... 1:N, movmean(10*log10(eRLS), 50), 'r'); legend('LMS', 'RLS'); xlabel('快拍'); ylabel('平方误差 (dB)'); grid on;movmean(...,50)是 50 点滑动平均,不平均的话误差曲线抖动太大,看不出趋势。两个虚线标在干扰方向,方便对波束图上的零陷位置。
4. 步长 μ、遗忘因子 λ 与阵元数的调参实验
4.1 步长 μ 的三档取值与发散边界
μ 是 LMS 里唯一要调的参数。低于 5e-4 时收敛太慢,1000 快拍内零陷还没成形;2e-3 附近是 8 阵元、10dB 信噪比仿真的常用起点;超过 1e-2 后,误差曲线会在某一快拍突然冲到 60dB 以上,这是发散——原因是 μ 冲破了 2/λmax 上界。判定发散不需要算特征值,直接看eLMS里是否出现比初始误差高 20dB 的尖峰即可。
4.2 遗忘因子 λ:越小跟得越快,稳态越抖
λ 决定 RLS 的有效记忆长度,约为 1/(1−λ) 个快拍。λ=0.999 时相当于用最近 1000 个快拍的统计量,适合平稳环境;λ=0.99 时有效记忆只有 100 快拍,干扰方向突变时零陷能在几十个快拍内重新生成,但稳态权噪声明显变大。实际做法是平稳实验用 0.995~0.999,非平稳实验用 0.98~0.99,并配合稍大的 δ 抑制抖动。
4.3 阵元数、自由度与零陷容量
M 个阵元的自由度理论上是 M−1 个,因为主瓣约束已经占用一个。也就是说 8 元阵最多挖 7 个独立零陷。把干扰数量加到接近 M−1,LMS 和 RLS 的稳态 SINR 都会明显下降;两个干扰角度间隔小于主瓣半宽时,零陷会合并成一个宽零陷,此时靠增加阵元数比靠调参数更有效。阵元间距 d/λ 固定在 0.5 后,主瓣宽度随 M 增大而变窄,干扰落在主瓣内时无法通过置零区分,只能提高角度分辨率。
4.4 用参数扫描验证收敛速度与稳态误差的取舍
下面这段代码对 μ 做对数扫描,把每种步长下的稳态误差打出来。收敛快拍定义为滑动平均误差第一次低于稳态值 +1dB 的位置。
mus = [2e-4, 1e-3, 2e-3, 5e-3]; for i = 1:numel(mus) w = aS/M; err = zeros(1,N); for n = 1:N x = X(:,n); e = s(n) - w'*x; w = w + mus(i)*conj(e)*x; err(n) = abs(e)^2; end sem = movmean(10*log10(err), 50); idx = find(sem < min(sem)+1, 1); fprintf('mu=%.1e 收敛快拍=%d 稳态误差=%.2fdB\n', mus(i), idx, min(sem)); end| μ | 收敛快拍 | 稳态误差 | 现象 |
|---|---|---|---|
| 2e-4 | 900 以上 | 最低 | 收敛慢,零陷浅 |
| 1e-3 | 约 300 | 次低 | 均衡 |
| 2e-3 | 约 150 | 偏高 | 常用折中 |
| 5e-3 | 约 80 | 明显高 | 接近发散 |
这个表对应上面的扫描结果,μ 每放大 2~5 倍,收敛速度上去了,稳态误差也抬上去,验证了 LMS 收敛速度与失调之间的固有矛盾。RLS 同理,把 lambda 从 0.999 改成 0.99 重跑一遍,会看到同样的取舍。
5. 用零陷位置和收敛曲线验证你的 MATLAB 仿真
验证仿真不能只看波束图好看。第一步核对零陷角度:把pat(wRLS)的局部极小值打印出来,如果 20° 和 −30° 方向附近各出现一个低于 −40dB 的谷,说明权向量收敛到了干扰置零解。零陷偏了 2° 以上,优先怀疑导向矢量里的sind或共轭转置写错——把w'*steer(theta)写成w.'*steer(theta)是最典型的错误,波束图会左右颠倒。
第二步做对照实验:把干扰功率改成和期望信号相同,即 INR=SNR=10dB。RLS 仍然正常收敛,LMS 的收敛时间会明显变长,这是特征值散布效应最直观的展示。第三步检查收敛曲线末段的波动幅度:RLS 的平方误差曲线稳定后应在 ±1dB 内抖动,抖动超过 3dB 就把 λ 调大 0.002 再跑,直到曲线尾部平稳。
最后是一个稳定性技巧:打印cond(Pmat),当条件数超过 1e6 时,说明 δ 初始值太小或输入近似奇异。把 δ 从 0.1 提高到 1,并在每 200 快拍对 P 做一次对称化重建Pmat = (Pmat + Pmat')/2,能消除浮点舍入累积的不对称漂移。整套代码在近两年的 MATLAB 版本上直接运行,不需要额外工具箱,作为阵列信号处理仿真的基线实现足够干净,后面接 MVDR 或字典学习类方法时,这套数据生成和验证流程可以原样复用。
本文还有配套的精品资源,点击获取