
简介本资源是一份面向通信与信号处理方向本科生、研究生及工程实践者的自适应波束形成算法MATLAB实现包聚焦RLS递归最小二乘及其加权改进型WRLS算法在阵列信号处理中的核心应用。资源解决自适应滤波器快速收敛、干扰抑制与定向接收建模等关键问题适用于雷达、无线通信和声纳等场景下的波束方向图设计与性能分析。压缩包为RAR格式共含2个MATLAB源文件.m总大小仅2KB轻量精炼其中主控脚本实现波束形成全流程仿真函数文件封装RLS核心迭代逻辑涵盖协方差矩阵更新、权值向量递推、误差动态调整等关键步骤并支持波束方向图可视化输出。目前已有186人学习下载内容结构清晰、代码注释充分可直接运行调试是理解RLS/WRLS数学原理、掌握MATLAB工程实现、开展课程设计或算法对比实验的实用入门材料。 做了几年阵列信号处理手头一个 RLS 波束形成的仿真工程里我反复啃过不下三套不同版本的代码。说句实话包括不少标着“RLS.rar”的资源包里面的代码能直接跑通、方向图又能说明问题的很少。大部分人是把 RLS 当黑盒调跑出来什么波形就贴什么波形根本不知道中间那一堆递推公式在干什么。这篇文章就是我重新整理这套 RLS 波束形成仿真的一点心得从原理推导到 MATLAB 实现再到 WRLS 加权递归最小二乘的变体用法全部展开讲清楚适合刚接触自适应波束形成、或者在调参阶段被各种坑卡住的同学参考。在进入正文前先明确这里要解决的核心问题均匀线阵上接收信号混合了期望信号、干扰和噪声我们希望输出一个方向图让期望方向的增益最大干扰方向的增益尽量低而且这个“最优权值”要能根据接收数据在线更新。RLS 算法就是这类自适应波束形成器里非常实用的一种它比 LMS 收敛快得多在干扰强、信噪比不高的场景下优势尤其明显。WRLS 则是在 RLS 基础上对历史数据做加权处理的变体用来应对干扰方向快速变化的情形。1. 为什么波束形成器要用RLS从空间滤波到自适应权值1.1 波束形成到底在做什么先解决一个最基础的问题波束形成到底是干嘛的。你可以把阵列天线看成一组空间采样器。一个平面波从远处某个方向打过来到达各个阵元的时间不一样体现在复数基带信号上就是一个线性增长的相位差。所谓波束形成就是给每个阵元通道乘上一个复加权系数再求和输出。权值选得好期望方向的信号同相叠加信噪比大幅提升干扰方向由于相位不匹配输出被压低这就是“空间滤波”。常规的移相波束形成器只做一件事把方向图的主瓣掰到期望方向。它的问题在于旁瓣高度固定一旦强干扰落在旁瓣位置压低能力就非常有限。你可能会说“那我加窗、压低旁瓣不就行了”可以但这是被动的一旦干扰方向变化、阵元幅度相位误差变大、或者期望方向估计有偏差固定权值的方向图就会失效系统性能直接崩溃。自适应波束形成器恰恰是为解决这类问题而生的。它的本质是根据实时接收数据不断调整权值在约束期望方向增益的同时把输出功率最小化。这样干扰方向会被自动“挖”出零陷而且这个零陷会跟着干扰走。换句话说固定波束形成器只会“指”自适应波束形成器既会“指”又会“躲”。1.2 自适应算法的取舍为什么我不推荐直接用LMS做自适应波束形成最常接触的两种自适应算法是 LMS 和 RLS。LMS 思路很直观沿着误差平方的梯度方向往下走一步一更新。实现简单计算量也小但问题同样明显。LMS 的收敛速度严重依赖输入信号相关矩阵的特征值散布程度。阵列相关性矩阵的特征值一旦拉得很开LMS 收敛速度会慢到让人怀疑人生。我做过一个对比在 8 元阵、期望信号来自 0 度、干扰来自 30 度、干扰比信号强 20dB 的条件下LMS 用了五六百次迭代权值才基本稳定。而同样的条件RLS 在不到 100 次迭代就已经收敛了。为什么 RLS 能这么快因为它在迭代过程中显式维护了相关矩阵逆的估计相当于每一步都在做一个“近似精确”的最小二乘解而不是沿着梯度一点点爬。它的收敛速度对特征值分布的敏感度低得多这是 RLS 做自适应波束形成最大的优势。所以对于干扰强、响应要快的波束形成场景我优先推荐 RLS。计算量比 LMS 大一点但换来的是性能和稳定性。这篇文里所有仿真都是基于一套 8 元均匀线阵的 MATLAB 工程展开的下面逐步把 RLS 的数学原理和实现细节拆开讲。2. RLS递推的数学底子代价函数、正规方程与遗忘因子2.1 带遗忘因子的最小二乘代价函数RLS 不是一个凭空蹦出来的“智能算法”它本质上是带遗忘因子的最小二乘问题的递推解法。假设我们有 N 个阵元在时刻 n 收到一个快照向量 x(n)我们期望的输出是 d(n)实际输出是 w^H x(n)误差就是 e(n) d(n) - w^H x(n)。标准的最小二乘会从第一个快照到当前快照把所有误差的平方和最小化。但实际环境是时变的很久以前的数据对现在可能已经没有参考价值了。所以 RLS 引入遗忘因子 λ让过去的样本按指数规律衰减权重。代价函数写成J(w) Σ_{i1}^{n} λ^{n-i} |d(i) - w^H x(i)|²λ 的取值在 0 到 1 之间。λ 越接近 1历史记忆越长稳态性能越好但跟踪速度慢。λ 越小旧数据遗忘得越快对干扰变化的响应也越快但噪声引起的权值抖动会变大。工程里常用 λ0.99 到 0.999这个经验范围后面我会专门用一节来说。这里需要补一个细节d(n) 从哪来。如果系统里有训练序列或者导频信号d(n) 可以直接用参考信号。但波束形成场景中往往没有理想参考信号这时候可以把期望方向约束放进来让 d(n) 恒等于 1误差变成 e(n) 1 - w^H a(θ_0)a(θ_0) 是期望方向的导向矢量。等价地这相当于做了线性约束最小方差波束形成既保持期望方向增益为 1又让总输出功率最小。仿真里用第一种“有参考”的形式比较多因为实现起来直观后面讲代码时我会说明怎么处理参考信号。2.2 增益向量与权值更新RLS五条递推公式是怎么来的对代价函数求梯度并令它等于零可以得到正规方程Φ(n) w(n) r(n)其中Φ(n) Σ_{i1}^{n} λ^{n-i} x(i) x^H(i)r(n) Σ_{i1}^{n} λ^{n-i} x(i) d^*(i)Φ(n) 是加权相关矩阵r(n) 是互相关向量。如果每个时刻都从头重新算这个矩阵方程复杂度是 O(n³) 级别完全无法在线运行。RLS 厉害的地方在于它利用矩阵求逆引理把矩阵求逆过程转成逐快照递推复杂度降到 O(N²)N 是阵元数和快照数量无关。递推的核心五条公式我直接列出来这是整个算法的骨架(1) 增益向量k(n) \frac{λ^{-1} P(n-1) x(n)}{1 λ^{-1} x^H(n) P(n-1) x(n)}(2) 先验误差e(n) d(n) - w^H(n-1) x(n)(3) 权值更新w(n) w(n-1) k(n) e^*(n)(4) 逆相关矩阵更新P(n) λ^{-1} [P(n-1) - k(n) x^H(n) P(n-1)](5) 初值w(0) 0P(0) δ^{-1} I其中 P(n) 就是 Φ^{-1}(n) 的递推估计δ 是一个小的对角加载量作用是避免相关矩阵奇异同时给权值初始化提供一个正则化基础。理解这些公式的关键是看穿增益向量 k(n) 的含义。它的分子是 λ^{-1} P(n-1) x(n)你可以理解为“当前快照在逆相关矩阵空间里的映射”分母则是一个归一化项。k(n) 的幅度越大当前快照对权值更新的影响就越大。然后权值更新用先验误差 e(n) 做修正注意这里取共轭因为信号和权值都是复数这个细节在实际编程中特别容易出错。为什么叫“递归最小二乘”因为 P(n) 的递推式保证了每个时刻计算出来的 w(n)都能让时刻 n 的加权最小二乘代价函数取到最小值而不是“向最小值逼近”。这就是 RLS 和 LMS 本质的差异所在LMS 走的是随机梯度下降路线每一步只保证大致方向正确RLS 走的是精确递推路线每一步都保持对最优解的精确逼近。3. RLS波束形成器的MATLAB实现从初始化到方向图3.1 核心递归循环实现很多人拿到 RLS 代码最头疼的就是那堆矩阵更新和共轭操作。我在仿真里把核心循环整理成下面这样代码可以直接抄过去跑% 参数设置 N 8; % 阵元数 lambda 0.99; % 遗忘因子 delta 1e-3; % 初始对角加载量 P (1 / delta) * eye(N); % 初始逆相关矩阵 w zeros(N, 1); % 初始权值 % 假设已经准备好快照矩阵 snapshots 和参考信号 desired for n 1:Nsamples x snapshots(:, n); % 当前快照N x 1 的复数向量 d desired(n); % 当前参考信号 % 1. 计算增益向量 k (lambda^-1 * P * x) / (1 lambda^-1 * x * P * x); % 2. 计算先验误差 e d - w * x; % 3. 更新权值注意共轭 w w k * conj(e); % 4. 更新逆相关矩阵 P lambda^-1 * (P - k * x * P); end有几个地方必须强调。首先MATLAB 里 x 是共轭转置x. 才是普通转置。波束形成处理的都是复数基带信号如果这里用错整个算法会完全乱掉。其次权值更新那一步必须写成 k * conj(e)而不是 k * e。原因是误差 e 是复数权值修正量需要和 e 的共轭对齐这样才和代价函数对 w 的复梯度方向一致。很多新手在第一步就挂在这两个细节上。另外实际操作中我建议把快照矩阵预先生成好然后循环里面只做索引读取不要在循环里动态生成信号。MATLAB 对循环的优化不算好但 N8 这种规模根本不会成为瓶颈所以代码的可读性优先。如果你处理的是大规模阵列或者实时系统才需要考虑把 B 循环改写成矩阵运算或者 MEX 加速那是后话了。3.2 从权值到波束方向图验证算法是否收敛递归跑完之后w 就是最终的自适应权值。要验证它是否“学会了”不能只看权值本身要画方向图。方向图的公式是B(θ) |w^H a(θ)|²其中 a(θ) 是来波方向 θ 的导向矢量。对于阵元间距为 d、载波波长为 λ_c 的均匀线阵导向矢量是a(θ) [1, e^{-j2πd sinθ/λ_c}, ..., e^{-j2π(N-1)d sinθ/λ_c}]^T注意这里我用 λ_c 表示信号波长避免和遗忘因子 λ 混淆。画方向图的 MATLAB 代码可以这样写theta -90:0.5:90; steer zeros(N, length(theta)); for tt 1:length(theta) steer(:, tt) exp(-1j * 2 * pi * d * sin(deg2rad(theta(tt))) * (0:N-1) / lambda_c); end pattern abs(w * steer).^2; pattern_dB 10 * log10(pattern / max(pattern)); plot(theta, pattern_dB, LineWidth, 1.5); xlabel(方位角 / deg); ylabel(归一化增益 / dB); grid on;跑通这个代码后你会看到典型的自适应方向图期望方向 0 度附近增益最大干扰方向 30 度附近出现一个深凹陷。如果干扰较强这个凹陷可以达到 -30dB 甚至 -40dB 以下。看到这样的方向图才说明 RLS 真收敛了而不是把噪声当信号学进去了。这里有一个常见的调试技巧把方向图的纵轴用归一化增益来画最大值永远是 0dB干扰方向的凹陷深浅一眼就能看出来。如果你发现方向图在随机方向乱出谷底优先检查参考信号是否和期望信号对齐、P 矩阵是否出现数值发散、以及学步长是否过大。4. WRLS加权递归最小二乘变遗忘因子与样本加权4.1 WRLS到底加权加在哪儿WRLS 在标题里和 RLS 并列出现它其实是 Weighted RLS加权递归最小二乘。很多人看到“加权”两个字就懵不知道加在哪儿。实际上RLS 里本来就有指数遗忘因子 λ那已经是加权只不过这是一种固定的、均匀衰减的权。WRLS 做的是把这种固定加权改成更灵活的、可随数据变化的加权方式。第一种变体是变遗忘因子 RLS。标准 RLS 的 λ 是个标量全程不变。但在实际工程里有时候会希望初始阶段收敛快点进入稳态后平滑一点或者干扰突变了希望尽快丢掉旧数据。这时候可以让 λ 随时间变化。例如λ(n) 0.98 0.02 * exp(-|e(n)|² / σ²)误差 e(n) 大的时候说明当前模型可能已经失配λ(n) 自动变小算法快速响应新数据误差小的时候λ(n) 接近 1跟踪趋于平滑。这种基于误差能量调制遗忘因子的方案就是 WRLS 的一种经典实现。第二种变体是样本加权 RLS。在一些场景里并不是所有历史样本都同等可靠。比如某个时间段存在强脉冲干扰或者某个快照被瞬时饱和、丢失了很多信息这时候强行把这些样本平等地纳入最小二乘反而会把权值带偏。WRLS 的做法是在代价函数里给每个样本附加一个权重 α(i)J(w) Σ_{i1}^{n} α(i) λ^{n-i} |d(i) - w^H x(i)|²权重 α 可以根据误差大小、接收功率、干扰检测结果等指标设计。这个思路把 RLS 从“时间上的指数衰减”扩展成了“同时考虑样本可信度的加权”灵活性提高了一个量级。4.2 WRLS在快速干扰变化场景下的更新公式落实到代码我们可以把 WRLS 的递推写成一个“带门控的 RLS”。每个时刻先算一个临时误差再根据误差生成当前样本的权重系数 α(n)最后把它折叠进递推公式里。这里我用一个有效遗忘因子 β(n) λ · α(n) 来统一表达更新公式变为k(n) \frac{β^{-1}(n) P(n-1) x(n)}{1 β^{-1}(n) x^H(n) P(n-1) x(n)}e(n) d(n) - w^H(n-1) x(n)w(n) w(n-1) k(n) e^*(n)P(n) β^{-1}(n) [P(n-1) - k(n) x^H(n) P(n-1)]当 α(n) 1 时β(n) λ上式严格退化为标准 RLS当 α(n) 因异常干扰变小或变大时β(n) 相应变化实现样本权重调制。MATLAB 里的实现就是在循环里多算一步权重门% 计算当前快照的可信度权重 err_tmp d - w * x; alpha 1 / (1 abs(err_tmp)^2 / eta); % eta 是调节系数 beta lambda * alpha; % 等效遗忘因子 k (beta^-1 * P * x) / (1 beta^-1 * x * P * x); e d - w * x; w w k * conj(e); P beta^-1 * (P - k * x * P);eta 这个参数决定了“多大的误差算异常”一般根据信号功率量级设定比如 0.1 倍期望信号功率。我试过的经验是eta 太大会让门控失效等于退化成标准 RLSeta 太小会导致正常扰动也被当异常权值频繁大幅跳动稳态性能反而变差。这里必须提醒一点如果权重 α 是逐时变化的你在更新 P 的时候一定要用同样的 β(n)不能只在 k 里用了 βP 更新还按常数 λ 算。P 始终要保持为 Φ^{-1} 的递推估计只要前后公式不一致P 就会偏离真实值轻则收敛变慢重则数值发散。这套一致性问题我在实际调试中踩过很多次说出来都是泪。5. 仿真结果对比收敛速度、零陷深度与干扰跟踪5.1 仿真场景和评估指标为了把 RLS 和 WRLS 的性能差异说清楚我把仿真场景固定一下8 元均匀线阵阵元间距取半波长期望信号从 0 度方向入射信噪比 10dB一个强干扰从 30 度方向入射干噪比 30dB快照总数 200 个每个快照独立复高斯噪声。评估指标就三个方向图零陷深度、输出信干噪比的收敛曲线、以及干扰方向突变后的重新收敛时间。这个设定很常见但也很能说明问题。30dB 的干噪比意味着干扰功率是噪声的一千倍如果算法不够稳方向图很容易被干扰“带跑偏”。5.2 固定干扰下的RLS表现在固定干扰场景下标准 RLS 的表现已经很好了。我分别测试了 λ0.9、0.99 和 0.999 三组参数结果整理成下面的表格遗忘因子 λ收敛所需快照数稳态输出SINR约30度方向零陷深度0.9~259.5 dB-31 dB0.99~6010.2 dB-40 dB0.999~18010.3 dB-43 dB可以看到λ 越大稳态性能越好但收敛越慢。λ0.9 这个档位收敛很快但零陷只有 -31dB且权值抖动明显输出 SINR 波动也比较大。λ0.999 稳态 SINR 最高但需要 180 个快照才稳定如果干扰在几十个快照内变化一次它基本跟不上。实际工程里我一般把 λ 定在 0.99 附近兼顾速度和稳态。方向图上λ0.99 时 0 度期望方向增益归一化为 0dB30 度方向形成一个约 -40dB 的深零陷其他方向起伏很小。这个方向图形态就是 RLS 波束形成应该有的标准长相。5.3 干扰方向跳变时RLS与WRLS的跟踪差距固定干扰测不出 WRLS 的优势所以我把场景改成前 200 个快照干扰在 30 度第 201 个快照突然跳变到 -20 度。这种“干扰方向突变”在真实场景里很常见比如对方干扰源突然换了位置或者雷达平台转向导致干扰来向改变。标准 RLS 在这种突变面前的表现是短期内权值还停留在旧方向 30 度-20 度方向的干扰会大摇大摆从旁瓣进来大约需要再积累几十个快照新版权值才能把零陷搬过去。λ0.99 时重新收敛大概需要 50 到 80 个快照。这期间系统性能是明显下降的。而把 WRLS 的门控机制打开后干扰突变时误差会突增α(n) 自动变小β(n) 跟着变小算法立刻“忘掉”之前的旧信息把注意力集中在当前快照上。实测下来重新收敛时间压缩到 15 到 25 个快照左右比标准 RLS 快了两到三倍。这个差距在干扰快速跳频或者平台机动场景下是决定性的优势。代价自然也有。WRLS 稳态时的零陷深度略差于标准 RLS大概会少几个 dB 的性能因为它的权重一直在微调稳态没那么“稳”。所以实际使用时我倾向于在标准 RLS 和 WRLS 之间做一个开关检测到误差持续偏大时启动门控加权系统稳定后恢复正常 λ。这个混合模式既保留了 RLS 的稳态精度又能在突发情况下快速反应。6. 调参与改仿真代码时必踩的坑6.1 初始协方差δ和数值发散的关系δ 这个参数看起来不起眼却是很多人调 RLS 第一道坎。P(0) (1/δ)Iδ 太大意味着初始相关矩阵被估计得非常“小”P 的初始值非常大前几个快照的权值会被放大方向图到处乱跳甚至出现数值溢出δ 太小初始 P 很小权值更新缓慢算法收敛得很慢。我的一般经验是δ 取期望信号功率的 1/10 到 1/100 量级。比如信号归一化功率约 1那 δ 取 0.01 到 0.001 就比较稳妥。你也可以先跑一版画出权值模值的收敛曲线如果初始阶段权值明显超过稳态量级好几倍就把 δ 调大一些(也就是让初始 P 小一点)如果权值像乌龟爬一样半天不动就把 δ 调小。这个调参思路比死记硬背参数值可靠得多。数值稳定性的另一个隐患是 P 矩阵在长迭代后可能失去共轭对称性。由于浮点误差理论上应该保持 Hermitian 的 P 会慢慢出现不对称最终导致算法发散。稳妥的做法是每隔一定快照数把 P 重新对称化比如 P (P P) / 2。虽然 MATLAB 里这样做有点土但几百次迭代的仿真里非常有效。6.2 遗忘因子λ怎么选才不翻车遗忘因子是 RLS 里面最敏感的单个参数。一个直观的理解是λ 决定了算法的“记忆长度”。在统计意义上λ 对应的有效记忆长度大约是 1/(1-λ)。λ0.99 时记忆长度约 100 个快照λ0.9 时约 10 个快照λ0.999 时约 1000 个快照。所以说选择 λ 之前先问问自己我的系统环境变化有多快干扰可能在多少个快照内发生明显变化如果干扰几十个快照变一次λ0.999 就是自寻死路如果干扰全天候稳定只有噪声用 0.99 反而会因为权值抖动损失一部分稳态性能。我见过的翻车案例很多人把 λ 设成 1或者非常接近 1看似想追求最优稳态结果一个干扰突变就把权值带到沟里要花几百个快照才能爬回来。实践中我建议 λ 不要超过 0.999除非你有充分理由认为干扰永远不会变。还有一个容易忽略的点λ 影响的是整个 Φ 矩阵的加权不只是权值更新幅度。λ 调太小P 矩阵会变得非常大k(n) 也大权值更新剧烈稳态输出的 SINR 会明显下降。这不是 bug是算法的基本 trade-off。6.3 参考信号缺失时的替代方案不少做波束形成的同学拿到 RLS 代码第一反应是“d(n) 我没有啊”。这个问题很现实。没有训练序列时一个常用的替代方案是把 RLS 的误差定义改成约束形式也就是前面 2.1 节提到的把期望响应 d(n) 固定为 1以期望方向的导向矢量作为输入信号d 1; x_con steer(:, target_idx); % 期望方向的导向矢量这样的 RLS 更新实际上是在做“保目标方向、最小化其余方向输出功率”的约束自适应。注意此时输入快照不再是原始接收样本而是方向约束向量更新的含义也从“逼近期望响应”变成了“调节方向图零陷”。这样改出来的方向图和标准 MVDR 波束形成器很接近但通过 RLS 框架获得在线迭代能力。如果你的场景里没有准确的期望方向那问题就更深一层了需要先做到达角估计或者改用盲自适应算法。方向估计给得偏移 1 到 2 度自适应波束形成都可能把期望信号当成干扰消掉这是另一个大坑。6.4 复数共轭和各种转置的细节最后再强调一次复数问题。MATLAB 里 x 是共轭转置这在计算导向矢量、相关矩阵、增益向量时都是对的。但如果你手写代码到一半用 x. 去算相关矩阵得到的结果虽然维度对相位全错了方向图必然不对。类似的坑还出现在 e* 的共轭上权值更新漏掉 conj 会让算法完全不收敛误差却还一大一小不断变化很容易让人误以为是参数问题。我的调试建议是第一次写 RLS 代码时先用一段已知的平稳信号做测试比如让方向固定在 0 度没有干扰只有一个简单信源。这时 RLS 的权值应该趋近于该方向的共轭导向矢量。如果连这种最小场景都不能正确收敛问题大概率出在转置和共轭上而不是算法本身。还有一点MATLAB 里对复数数组求 . 会报错吗不会但结果就是普通转置不共轭很容易在方向图计算里埋雷。我的习惯是只在对纯实数数组操作时允许自己用 .复数域一概用 。写代码时养成这个习惯能省掉很多调 bug 的时间。RLS 这套东西从数学公式看不过五条递推但真正落到工程仿真里从初始化、共轭处理、遗忘因子选择到 WRLS 的门控加权每一环节都可能让结果面目全非。这套仿真工程我翻来覆去改了好几遍最大的体会就是不要把它当黑盒每一步递推都对应着一层数学含义调试的时候顺着 P、k、e 这三个量往下查大多数问题都能定位出来。希望这些踩坑经验能让你的 RLS 波束形成跑得比我当初顺利一些。本文还有配套的精品资源点击获取