☰
毫米波大规模MIMO混合波束成形仿真:最小相差算法与Matlab实现
2026/10/20 11:24:21 网站建设 项目流程

如果你做过毫米波大规模MIMO的链路级仿真,一定对“混合波束成形”四个字又爱又恨。爱的是它能让频谱效率逼近全数字方案,恨的是模拟域的恒模约束——移相器只能改变相位,不能改变幅度——让预编码设计从单纯的线性代数问题变成了带约束的优化问题。我最近整理了一套多用户毫米波大规模MIMO系统混合波束成形Matlab仿真,核心思路是“最小相差”:让混合预编码矩阵与理想全数字预编码矩阵之间的距离最小化。整套代码跑通之后,频谱效率和误差收敛曲线都能稳定复现,这篇就把背后的原理、交替迭代实现、Matlab代码结构以及几个容易翻车的细节一次聊透。

1. 为什么非要用混合波束成形:成本、功耗与恒模约束

1.1 全数字架构在毫米波频段的尴尬

大规模MIMO的理论基础很漂亮:天线数量翻倍,阵列增益和空间自由度跟着涨,频谱效率能线性提升。但落到毫米波频段,问题就来了——波长只有毫米级,天线间距小,塞几十上百根天线不难,难的是每一根天线后面都得跟着一条完整的射频链路,包含DAC、混频器、功放、滤波器。这套全数字架构在30GHz以上频段的功耗和成本,放到工程项目里根本压不住。

我最早仿真的版本就是全数字预编码,把所有天线都接在独立射频链上,配置128根天线、8个用户,基站侧射频链也设成128条。跑出来的性能曲线确实漂亮,但功耗表和硬件成本表一摆出来,谁都知道这不现实。所以业界才退一步:用少量射频链支撑大量天线,射频链数量降到8甚至4,其余天线通过移相器网络连接,这就是混合波束成形的出发点。

1.2 混合架构的基本分工

混合架构里,模拟域和数字域的分工很明确。数字预编码器在基带处理,负责调整每个数据流在射频链之间的幅度和相位,主要用来消除多用户之间的干扰;模拟预编码器由一组移相器组成,只改变相位不改变幅度,每条射频链通过移相器网络连到所有天线上,负责把波束指向目标用户的方向。

这种分工直接带出一个约束:模拟预编码矩阵FRF的每个元素幅度必须是1,也就是恒模约束。恒模约束看着简单,实际上把设计问题变得很棘手。直接用SVD分解取前几个奇异向量,得到的结果大概率不满足恒模条件,硬把幅度归一化掉又会损失性能。所以混合预编码从来不是单纯求一个最优解,而是在一系列工程约束下,找到尽量逼近理想解的办法。这套代码里所有迭代操作,本质上都在跟这个约束较劲。

1.3 “最小相差”到底在说什么

这套代码标题里提到的“最小相差”,我第一次看到时也琢磨了一下,后来把它明确实现成一种优化准则:设计混合预编码矩阵FRF和FBB,让两者的乘积尽可能接近某个理想预编码矩阵Fopt。用数学语言写就是

|| Fopt - FRF·FBB ||_F² → min

约束是FRF每个元素都落在恒模集合里。Fopt一般取全数字无约束方案下的最优解,比如对等效信道做奇异值分解后,取对应主奇异值的右奇异向量方向。这个准则的物理含义很直观:既然全数字方案性能最好但硬件做不到,那就退一步,让硬件能做到的混合方案与理想方案之间的“差距”最小。这个差距在信号空间里体现为波束方向的偏差和功率分配的偏差,所以叫最小相差,本质上是最小误差逼近。

这种思路的好处是,不再需要针对每个信道做复杂闭式推导,只要反复用交替最小化逼近Fopt,就能拿到一组性能良好的FRF和FBB。后面要做的所有事情,都围绕这个目标函数展开。

2. 系统模型与信道生成:先把仿真地基打牢

2.1 基站、用户与射频链参数

我这次搭建的系统配置如下:基站侧用均匀线阵,天线数Nt=128,射频链数量NRF=8;同时服务K=4个单天线用户,每个用户配一根接收天线。数据流数Ns=K=4,也就是说每个用户分配一路独立数据流。射频链数量满足工程常见条件NRF≥Ns,这里8条射频链留出了一定冗余。

载频取28GHz,系统带宽20MHz。为了先把核心算法跑通,我用了窄带信道建模,不做OFDM子载波扩展。这种单载波假设在毫米波场景里偏理想,但作为算法验证完全够用,很多论文的第一步也是这么做的。参数层面有几个点需要提前说清楚:第一,移相器精度会影响模拟预编码的码本设计,源码里默认用均匀量化,移相器位数取4比特,也就是每个移相器有16个可选相位;第二,信噪比范围取-10dB到20dB,每隔2dB采一个点,多用户场景下这个范围能看到从噪声主导到干扰主导的完整变化。

2.2 毫米波信道的稀疏多径模型

毫米波信道和传统低频信道最大的区别是稀疏性。28GHz频段有效散射体数量少,信道能量集中在少数几条路径上。我这里用的是常用的S-V集群信道模型,每个用户包含Ncl=4个散射簇,每个簇Nray=8条射线,总共L=32条路径。每条路径都有自己的离开角和到达角,由于基站侧是均匀线阵,只需要考虑离开角一个维度的正弦值。

信道矩阵的生成逻辑是:每个用户对应的信道行向量,等于所有路径增益乘以阵列响应向量的加权和。阵列响应向量对第l条路径离开角θ_l可以写成

a(θ_l) = [1, e^{j·2π·d·sin(θ_l)/λ}, ..., e^{j·2π·(Nt-1)·d·sin(θ_l)/λ}]^T

其中d是天线间距,取半波长,λ是载波波长。角度在[-60°, 60°]内服从拉普拉斯分布,路径增益服从复高斯分布,簇间功率按指数衰减。这套模型跑出来的信道矩阵通常只有少数几个较大的奇异值,低秩特性非常明显,恰好是混合波束成形能发挥优势的场景。

2.3 优化目标在程序里的落地

“最小相差”准则落到程序里,就是写一个目标函数,然后交替优化FRF和FBB。具体实现时,第一步先计算全数字基准Fopt。这里Fopt的选择有讲究:如果直接对信道矩阵H做SVD,取V的前Ns列,得到的是无约束下最大化频谱效率的方向,但这样得到的Fopt会包含许多幅度很小的分量,混合方案很难逼近。

我沿用了文献里的常规做法:对信道矩阵H做SVD,取前Ns个右奇异向量作为Fopt。然后交替执行两步:固定FRF时更新FBB,固定FBB时更新FRF。每一步都让差值范数单调不增,迭代十来次就能收敛到稳定值。

3. 交替最小化:模拟域和数字域轮流修正

3.1 固定数字域,模拟预编码怎么求

模拟预编码矩阵FRF的每个元素必须满足恒模条件,这是整个设计里最硬的一条约束。固定FBB之后,问题变成一个带恒模约束的最小二乘问题。最简单的解法是相位提取:直接取Fopt的相位作为FRF的相位,幅度强制归一化。这个方法复杂度低,但坏处是在多用户场景下会残余比较明显的用户间干扰。

我实际测试下来,直接相位提取在4用户、SNR大于5dB时,频谱效率比理想全数字方案低2~3dB,不算差,但还有提升空间。于是我在代码里多走了一步:先做相位提取,再用码本搜索把所有候选移相器组合过一遍,选出差值范数最小的一组。码本大小取决于移相器位数,4比特就是16个候选相位,128×8的FRF矩阵如果做全局搜索,复杂度会爆炸,所以实际的搜索方法是逐列替换:每次固定其他列,对当前列的每个候选相位计算目标函数,选最小的更新进去,扫完所有列算一轮,迭代几轮。

这个方法在工程上叫坐标下降法,相当于把全局搜索拆成多次局部搜索,每次只动一列,复杂度从指数级降到线性级,性能损失很小。我试过把候选相位从16提高到64,频谱效率只提升了不到0.3dB,算法运行时间却翻了4倍,性价比很低,所以4比特足够。

3.2 固定模拟域,数字预编码怎么求

FRF定下来之后,FBB的问题就友好很多了。此时等效信道是Heq = H·FRF,维度是K×NRF,而FBB是NRF×Ns。如果目标是追着Fopt跑,直接用最小二乘解

FBB = (FRF^H·H^H·H·FRF)^(-1)·FRF^H·H^H·Fopt

这个解能最小化||Fopt - FRF·FBB||_F²,但它是普通最小二乘,没有考虑用户间干扰的结构。我在多用户场景里更倾向于加一步线性迫零:把等效信道Heq直接求伪逆,再把结果映射到Fopt对应的行空间上,这样既保证混合预编码尽量接近Fopt,又能把多用户干扰压到很低。

需要注意,FBB解出来之后要配合模拟预编码做功率规范化。发送端总功率固定,我习惯让||FRF·FBB||_F²等于Ns。这个规范化看起来简单,但放的位置不对,所有性能曲线都会整体偏移,后面专门讲这个坑。

3.3 迭代流程与收敛判据

整个交替最小化循环结构很清晰:初始化FRF为单位恒模矩阵,FBB先给一个合法解;循环里先更新FRF,再更新FBB,计算当前差值范数error;如果error相对上一次的变化小于阈值,或者迭代次数到达上限,就跳出。我在代码里设阈值1e-4,上限15次,实测8到12次就能收敛。

有一点值得提醒:交替最小化只能保证迭代过程中目标函数单调下降,不能保证全局最优。好消息是毫米波信道低秩,初始点选得不算离谱的情况下,最终结果和全数字方案的差距基本能维持在1dB以内。如果你想要更稳妥,可以把初始化重复几次,取差值范数最小的一次作为最终结果。我测试下来,重复3次初始化能再榨出0.2dB左右的性能。

4. Matlab代码结构与关键实现

4.1 文件划分与主脚本流程

这套仿真我把代码拆成几个模块,避免一个上千行的脚本让人看晕。首先是参数配置文件,集中设置天线数、射频链数、用户数、信噪比范围和移相器位数;然后是信道生成函数,输入用户数量和路径参数,输出信道矩阵H和阵列响应;再是核心预编码函数,输入H、FRF初值、Fopt和迭代参数,输出优化后的FRF和FBB;最后是主脚本,负责循环不同SNR做蒙特卡洛仿真,收集频谱效率和误差范数,并输出对比图。

主脚本的流程骨架如下:

% 主仿真脚本骨架 clear; clc; config = loadConfig(); % 加载参数 rng(2025); snr_list = -10:2:20; se_hybrid = zeros(size(snr_list)); error_norm = zeros(size(snr_list)); for s = 1:length(snr_list) for monte = 1:config.numMonte H = generateChannel(config); Fopt = computeFopt(H, config); [FRF, FBB, err] = hybridBeamforming(H, Fopt, config); se = computeSpectralEfficiency(H, FRF, FBB, config, snr_list(s)); se_hybrid(s) = se_hybrid(s) + se; error_norm(s) = error_norm(s) + err; end se_hybrid(s) = se_hybrid(s) / config.numMonte; end

蒙特卡洛次数我取100次。这个次数在算法验证阶段够用,曲线已经比较平滑,再多跑收益有限。

4.2 信道生成与阵列响应

信道生成函数的实现要点,是把S-V模型的累加过程写清楚。每个用户的行向量等于所有路径增益与阵列响应向量相乘后求和。路径增益里包含路径损耗和衰落,幅度服从瑞利分布,相位均匀分布。离开角在簇中心角度附近服从拉普拉斯分布,簇中心角度服从均匀分布。

这里最容易出bug的是角度和阵列响应对不上。我用的是正弦域均匀线阵,表达式里只出现sin(θ_l),如果直接拿角度算相位,记得统一用sin形式,否则旁瓣方向会算错。另一个容易忽略的是天线间距d与波长λ的比值,取半波长时相位增量为π·sin(θ_l),代码里写清楚就不会乱。

4.3 核心预编码函数

混合预编码函数是整个仿真的核心。我用坐标下降法替代直接相位提取,同时保留了一个开关参数,允许对比两种做法的效果。核心代码逻辑如下:

function [FRF, FBB, error_seq] = hybridBeamforming(H, Fopt, config) Nt = config.Nt; NRF = config.NRF; FRF = exp(1j * 2 * pi * rand(Nt, NRF)); FRF = FRF ./ abs(FRF); % 恒模初始化 FBB = zeros(NRF, size(Fopt, 2)); for iter = 1:config.maxIter % 坐标下降更新FRF for col = 1:NRF for phase = 1:config.codebookSize cand = FRF; cand(:, col) = codebook(:, phase); err(phase) = norm(Fopt - cand * FBB, 'fro'); end [~, best] = min(err); FRF(:, col) = codebook(:, best); end % 更新FBB,最小二乘加规范化 FBB = (FRF' * FRF) \ (FRF' * Fopt); FBB = FBB * sqrt(Ns) / norm(FRF * FBB, 'fro'); error_seq(iter) = norm(Fopt - FRF * FBB, 'fro'); if iter > 1 && abs(error_seq(iter-1) - error_seq(iter)) < 1e-4 break; end end end

这里FBB规范化用的系数要根据发射功率基准来定,这一点下面详细说。

4.4 对比基线与绘图

有对照才有说服力。我在仿真里同时算了三个基线:全数字无约束预编码,作为性能上限;纯模拟波束成形,不经过数字域,直接把波束对准最强路径方向;以及随机相位初始化的混合方案,用来体现交替优化的增益。

绘图时把频谱效率随SNR的变化画成一张图,三条线分别是全数字、混合、纯模拟。另外画一张误差范数随迭代次数下降的曲线,直观展示交替最小化每一步的收敛情况。这两张图足以支撑一篇仿真类项目的主要结论。

5. 复现这套代码时最容易踩的四个坑

5.1 发送功率规范化:位置不对性能整体漂移

我最早一版代码里,数字预编码的规范化写错了,把||FRF·FBB||_F²直接缩放成Ns,结果低SNR段没什么感觉,到高SNR段频谱效率曲线明显低于正常值,看起来就像混合波束成形比纯模拟还差。查了半天发现是功率基准搞混了。

规范化要看你想约束的是总发射功率还是每流功率。如果总发射功率等于Ns,那就让||FRF·FBB||_F² = Ns;如果想约束每根天线的平均功率一致,得除以Nt再开方。我最终统一用总发射功率约束:FBB乘以sqrt(Ns)/norm(FRF·FBB, 'fro')。这个细节通常不写在文档里,但它直接决定所有曲线能否对上。

5.2 移相器码本分辨率和角度量化

码本分辨率直接决定模拟预编码的逼近能力。4比特只有16个相位,我一开始也怀疑不够,专门测试过8比特,结果性能提升微乎其微,但计算量翻了4倍。原因在于毫米波信道的低秩性,主路径就那么几条,角度域稍微偏一点,数字域的线性调整也能补回来。

真正需要注意的是码本覆盖范围。如果覆盖范围写成[-90°, 90°],但系统设定用户在[-60°, 60°],码本里一半候选角度是空闲的;反过来,如果用户角度超出覆盖范围,高频段频谱效率会明显下降。我建议码本范围跟系统角度范围保持一致,不要图省事直接用全角度。

5.3 多用户流数与射频链的约束关系

射频链数量NRF决定数字域最多能支撑几路数据流。我第一次扩展多用户时,直接设K=8用户、每用户1流,NRF也设成8,一路跑通后发现迭代误差范数死活降不下去。后来意识到问题在于模拟域只有8条射频链,但每列FRF要同时服务8个用户,自由度被严重透支,必须把NRF增加到至少K+2才有余量做干扰抑制。

实际工程里NRF一般取2K到4K,既要满足流数需求,又要留出空间给迫零矩阵做干扰消除。如果要压缩射频链数量,就得在用户调度上做文章,不能指望算法自己变魔术。

5.4 交替最小化不收敛的排查思路

如果误差范数曲线出现反复震荡,或者收敛到明显高于正常水平的值,我的排查顺序是:先看FRF初值是不是恒模,再看候选码本里是否有无效相位,然后检查FBB更新时伪逆是否稳定。这三个环节里最容易出问题的是伪逆,当NRF和流数相等时,FRF'*FRF可能接近奇异,数值溢出会让FBB突然变大,把误差范数顶上去。

解决方法有两个:一个是用pinv代替inv求伪逆,另一个是在FBB更新后做一步规范化,再进下一轮坐标下降。我实测用pinv之后,迭代曲线稳定了很多,再也没有出现误差范数突然反弹的情况。

6. 结果怎么看:频谱效率曲线、收敛曲线与扩展方向

6.1 频谱效率曲线的解读

当SNR从-10dB升到20dB,混合波束成形的频谱效率曲线稳步上升,在低SNR段几乎贴着全数字方案走,高SNR段由于多用户干扰和量化误差,逐渐拉开约1dB差距。纯模拟方案在SNR超过0dB后增速放缓,说明它只靠方向增益无法消除用户间干扰,高频段被干扰拖住是必然的。

实际复现中,如果你看到混合方案在低SNR和高SNR都低于纯模拟,不用怀疑算法方向,大概率是数字预编码或功率规范化写错了。正确实现下,混合方案应当在全SNR范围内都明显优于纯模拟。

6.2 迭代收敛曲线

误差范数随迭代次数的曲线通常在前3到5次迭代快速下降,之后趋于平缓。我设置的阈值1e-4,在大部分信道实现下不到10次收敛。偶尔在信道相关性较强的场景会多跑几轮,但不会超过15次的设置上限。

这个收敛行为还有一个实用价值:如果想降低实时处理时延,可以把迭代次数设成5,性能损失通常不超过0.5dB,计算量减少一半。工程上这个权衡很常用。

6.3 代码还能怎么扩展

这套代码基础版本跑通后,下一步有几个很自然的扩展方向。第一,把窄带信道换成多径OFDM,每个子载波分别做数字预编码,模拟部分整段频带共享,这会带来新的复杂度,但更接近真实系统。第二,加入信道估计环节,用导频和最小二乘估计出瞬时信道,替代理想的信道已知假设。第三,把发射端单边波束成形扩展到收发端联合设计,也就是收发两端都采用混合架构,此时需要同时对发射端FRF和接收端WRF做交替优化。

我目前已经做了OFDM扩展的第一版,数字预编码按子载波分别计算,模拟预编码用所有子载波的平均信道来设计,效果比我预期好,后面有机会单独写一篇分享。

整套源码跑通之后,我最大的感受是:混合波束成形的核心难点不在算法推导,而在恒模约束和功率规范化的实现细节上。坐标下降和最小二乘交替迭代的原理,十分钟就能讲完,但真正让仿真曲线对得上理论预期,靠的是把每一个矩阵维度、每一个规范化因子都抠清楚。如果你复现时发现曲线对不上,建议从第5章的四个坑开始排查,尤其注意规范化那一步。代码里还剩几个参数可以调,包括移相器位数、迭代次数和初始化次数,调参的过程往往比跑通本身更有收获。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询