首页 / 资讯中心 / 文章详情

大规模MIMO低复杂度混合预编码:算法解析与Matlab仿真实现

大规模MIMO低复杂度混合预编码:算法解析与Matlab仿真实现 ★ FEATURED ARTICLE
去年帮一个同学排查仿真失败的问题现象很有意思天线数从64根加到128根之后原本跑得飞快的全数字预编码算法内存直接爆掉仿真机风扇转得跟起飞一样。这不是个例。当基站的发射天线数进入大规模MIMO的量级全数字预编码方案在学术界和工程上都会逐渐站不住脚原因不是算法精度不够而是射频链路的数量和随之而来的硬件成本撑不住。混合预编码作为兼顾性能与可实现性的折衷方案这几年一直是物理层研究的热点也是很多同学做通信仿真时绕不开的一块硬骨头。这篇文章围绕大规模多用户MIMO系统中的低复杂度混合预编码展开重点讲清楚三件事混合预编码为什么非做不可低复杂度算法到底低在哪以及怎么用Matlab把仿真快速跑起来。内容适合正在做MIMO预编码方向课程设计、准备保研面试项目或者刚接触物理层算法仿真、想找一份能直接改着用的代码框架的读者。文中不会堆太多数学证明而是把建模、算法、代码和调参经验串成一条线尽量让你看完就能动手。1. 为什么大规模MIMO会让全数字预编码先出局1.1 射频链路数量与硬件成本的天平先明确一个概念预编码是在发端对信号做处理让信号经过信道之后在接收端更好被恢复。全数字预编码的“全数字”意味着每条天线都接一条完整的射频链路包括DAC、混频器、功放、滤波器这套东西不是芯片上画个框图就完事每一路都对应真实的硬件成本和功耗。大规模MIMO的基站天线数通常是64、128甚至256根。如果采用全数字架构射频链路数量就等于天线数量硬件成本随天线数线性增长。更麻烦的是每一路射频链路的功耗和散热都会成为工程问题部署在室外宏基站场景时几乎不可接受。学术界早期推 Massive MIMO 的时候隐含假设是射频链路可以低成本大规模集成但工程实现后发现这条路在成本账上很难走通。所以混合预编码的核心动机非常朴素把预编码拆成两级一级是低维数字预编码在基带完成一级是高维模拟预编码用移相器网络实现。移相器只调整相位、不调整幅度成本远低于完整射频链路这样可以用数量少得多的射频链路去驱动大量天线在性能和成本之间找一个可接受的平衡点。理解了这个动机后面看任何混合预编码算法第一反应都应该是“它在怎么分配数字域和模拟域的活儿”。1.2 算力和内存的双重挤压全数字预编码在仿真层面还有一个很容易被低估的问题算力和内存。假设发射天线Nt 128接收端用户总天线数假设也是几十根那么信道矩阵的维度就是几百乘几百。计算全数字预编码通常要做奇异值分解或者矩阵求逆这类操作的复杂度随矩阵维度呈三次方增长。天线数翻倍矩阵维度翻倍运算量可能涨了近一个数量级。我在帮同学排查那次问题的时候64天线跑一次蒙特卡洛仿真只要十几分钟128天线直接内存溢出。原因就是他把全数字预编码的最优矩阵、信道矩阵、各个中间变量全部以稠密矩阵形式存在工作区里再加上循环次数一多内存就扛不住了。这也是为什么很多论文里做混合预编码对比时基线算法只算到64或128天线很少往256以上跑——不是算法不支持而是全数字基线的仿真代价实在太高。这时混合预编码的低复杂度优势就体现出来了。模拟预编码矩阵虽然维度很大但它的元素全部是单位模长的相位值存储和计算上可以利用结构特性优化数字预编码矩阵维度很小只有射频链路数乘数据流数。两级联合起来实际上把一个大维度的矩阵分解问题拆成了两个小维度问题的交替求解复杂度下降非常明显。1.3 混合预编码用维度换成本的折衷思路有人可能会问既然全数字预编码性能最好那混合预编码的性能损失到底有多大答案是在合适的条件下差距很小尤其是在毫米波信道这种稀疏性很强的场景里。所谓稀疏性就是信道的大多数能量集中在少数几条路径上等效信道方向的数量有限。这时候用少量射频链路去匹配少数几条主要路径就足够逼近全数字预编码的性能。如果换到独立同分布瑞利信道这种能量分散的场景混合预编码的性能就会打折扣因为每条路径都贡献能量必须靠更多射频链路去覆盖。这也是为什么混合预编码的论文大多默认使用稀疏几何信道模型而不是简单的瑞利信道。这不是偷懒而是毫米波大规模MIMO的典型传播特征确实如此。我个人习惯把混合预编码理解成“用维度换成本”全数字方案用天线数倍的射频维度去追求极致性能混合方案用收缩后的射频维度去换可实现的硬件成本然后通过精心设计的算法把损失压到最低。理解了这条主线后面所有算法设计都是在回答同一个问题给定这么少的射频链路怎么让两级预编码配合得最好。2. 混合预编码建模中的三个关键约束2.1 发端到收端的信号链路怎么搭建模是仿真的第一步也是很多同学容易出问题的地方。考虑一个单小区多用户大规模MIMO系统基站配备Nt根发射天线、NRF条射频链路同时服务K个单天线用户数据流总数Ns K。发送信号向量s维度是Ns x 1先经过数字预编码矩阵F_BB维度NRF x Ns完成基带处理再经过模拟预编码矩阵F_RF维度Nt x NRF映射到天线阵列上。最终发射信号就是x F_RF * F_BB * s。接收端第k个用户收到的信号是y_k h_k * F_RF * F_BB * s n_k其中h_k是基站到第k个用户的下行信道向量维度1 x Ntn_k是高斯白噪声。这里要注意一个细节模拟预编码是宽带架构下的窄带近似也就是说我们假设信道在子载波上是平坦的所以可以省略子载波下标。做宽带OFDM仿真时每个子载波都要单独做一遍预编码计算计算量会成倍增长这是后话。等效预编码矩阵F F_RF * F_BB就是实际对数据流起作用的完整变换。混合预编码的设计目标很直接让F逼近全数字最优预编码矩阵F_opt比如基于信道SVD分解得到的主特征向量方向或者基于ZF准则得到的迫零方向。距离度量通常用Frobenius范数也就是让||F_opt - F_RF * F_BB||_F尽可能小。2.2 恒模约束为什么让问题突然变难如果只是上面这个逼近问题那太简单了直接把F_opt做矩阵分解就能得到一组解。真正让问题变难的是模拟预编码的硬件约束移相器只能调整相位不能调整幅度所以F_RF的每一个元素都必须满足模长等于1这就是恒模约束。恒模约束带来的数学后果是可行域不是一个凸集而是一个由多个单位圆乘积构成的流形。在一个非凸集合上做优化全局最优解很难求绝大多数算法只能保证收敛到局部最优或者接近最优的解。这也是为什么混合预编码领域有那么多算法文章——大家都在想方设法在这个非凸约束下逼近性能上界。更麻烦的是恒模约束把问题从“线性代数能直接解”变成了“需要迭代求解”。一旦引入迭代算法复杂度、收敛速度、初值敏感性就全都冒出来了。低复杂度设计本质上就是在这些因素之间做权衡要么减少迭代次数要么让每轮迭代的运算量更低要么找一个足够好的初值让收敛更快。2.3 功率归一化与多用户干扰的联动除了恒模约束建模时还容易忽略功率归一化。发射信号经过两级预编码之后总功率不能超过基站的最大发射功率所以一般要对数字预编码矩阵做归一化让||F_RF * F_BB||_F^2 Ns。这个看似不起眼的一步直接影响信噪比的计算是否准确。很多仿真结果对不上查到最后都是功率归一化写错了。多用户场景下还有一个绕不开的问题用户间干扰。每个用户只关心自己的数据流但基站发射的信号会串到其他用户那里。混合预编码要做的事情不仅仅是让每个用户的等效信道增益最大化还要抑制对其他用户的泄漏。最常见的设计思路是先算迫零或者MMSE形式的全数字预编码F_opt然后再用混合结构去逼近它这样用户间干扰的抑制能力基本继承自全数字方案。这部分建模的完整性很重要。我见过不少同学在仿真里只算单用户MIMO的谱效做出来的曲线很漂亮但一加多用户干扰就崩了。其实多用户的处理在代码上并不复杂就是在信道矩阵组织方式上多花点心思把每个用户的信道向量拼成一个大矩阵然后统一处理。后面的代码框架里我会给出具体做法。3. 低复杂度算法实测对比OMP、流形优化与相位提取3.1 稀疏重构思路把预编码当压缩感知做混合预编码算法里正交匹配追踪OMP是最容易理解的一种。思路来自压缩感知既然信道是稀疏的只有少数几个主要方向那么模拟预编码矩阵的每一列都可以从一组候选方向向量中挑选出来近似看成稀疏重构问题。具体做法是构造一个字典矩阵字典的每一列对应一个特定的发射方向响应向量通常是把到达角或离开角所在的空间离散化成若干网格。算法迭代做这么几件事找当前残差与字典列之间相关性最强的那一列把它选入支撑集更新模拟预编码矩阵然后用最小二乘更新数字预编码矩阵再重新计算残差。重复NRF次就得到整个模拟预编码矩阵。OMP的优点在于结构清晰、容易实现代码量不大。缺点也很明显字典的网格分辨率直接影响性能网格越细效果越好但计算量随之暴涨。而且OMP本质上是一种贪心算法每步只保证当前选择最优不保证全局最优。在射频链路数很少、网格不够细的时候性能损失会比较明显。适合做基线对比或者快速验证作为主推算法稍微有点不够看。3.2 相位提取法从全数字解逆推射频矩阵相位提取法PE-AltMin是我个人比较推荐的低复杂度方案思路非常直接全数字预编码矩阵F_opt既然是最优解那就想办法让两级混合结构尽量去贴合它。模拟预编码矩阵受恒模约束只能取相位那干脆直接取F_opt前NRF列的相位作为F_RF的初始值固定F_RF之后数字预编码矩阵的最优解就是最小二乘解用伪逆直接算出来。然后交替迭代每次迭代中先把F_RF * F_BB合并看成一个等效矩阵对这个等效矩阵重新做一次相位提取再重新算最小二乘。这个过程的每一步计算量都很小伪逆运算只涉及NRF维矩阵迭代几十次就能收敛。和OMP相比不需要构造字典也没有网格分辨率的问题实现起来反而更干净。相位提取法在信道稀疏性较强的场景下性能非常接近全数字预编码上界。原因也直观稀疏信道下F_opt的主要方向本来就不多提取相位相当于把主要方向的能量保留下来最小二乘再负责幅度修正和干扰抑制。两级配合得当损失就压得很低。3.3 复杂度的具体账要这么算对比算法复杂度不能只比迭代次数还要看每一轮的实际开销。矩阵乘法、伪逆、SVD这些基本运算的复杂度是不同的。SVD的复杂度大约是O(min(m*n^2, m^2*n))伪逆也类似而矩阵乘法的常数通常小很多。一个算法如果每轮都要做一次SVD哪怕只迭代10次也可能比另一个迭代100次但只做矩阵乘法的方案更慢。OMP的复杂度主要花在字典相关运算上。字典如果设了Nt根天线对应L个角度网格每轮要算一个L x 1的相关向量复杂度是O(L*Nt)迭代NRF轮。PE-AltMin每轮只有一次矩阵乘法和一次对NRF维矩阵的伪逆复杂度大概是O(Nt*NRF*Ns NRF^3)当Nt很大、NRF相对小的时候优势非常明显。从实测角度看我在64天线、4条射频链路的配置下跑过对比OMP大约需要几十毫秒完成一轮信道实现PE-AltMin只需要几毫秒性能却相差不大。对需要做上千次蒙特卡洛仿真的同学来说这个差距会直接决定你能不能按时跑完实验。低复杂度不是锦上添花而是实操中的硬需求。4. Matlab仿真框架与核心函数拆解4.1 仿真参数天线、射频链路、用户数要匹配写Matlab仿真前先把参数定清楚。参数之间是有匹配关系的乱设组合会让结果很难看。最基本的约束是射频链路数NRF必须不小于数据流数Ns否则数字预编码矩阵的维度就小于要服务的数据流数根本不可能完整消除用户间干扰。实际仿真中建议NRF比Ns大一点留出余量。我常用的一组配置是这样的可以直接当起点参数取值说明发射天线数 Nt64大规模MIMO典型规模射频链路数 NRF8大于等于用户数用户数 K4单天线用户数据流数 Ns4等于用户数信噪比范围-10dB 到 20dB步进5dB蒙特卡洛次数1000每次随机信道实现信道模型稀疏几何信道5条散射簇配比上要注意Nt/NRF的比值我试过64天线配4条射频链路性能和全数字方案差距明显拉大8条就从容很多。射频链路太少会让模拟预编码可调节的自由度不足性能上不去。后面调试的时候可以从“射频链路数翻倍谱效提升幅度”这个角度判断当前配置是否合理。4.2 主脚本流程与模块划分代码组织上我建议分四个模块主仿真脚本、信道生成函数、预编码函数、性能统计函数。这样每个模块可以独立调试验证不用每次从头跑。主脚本的逻辑大致是这样%% 参数初始化 Nt 64; NRF 8; K 4; Ns K; snr_dB_list -10:5:20; numMonte 1000; rng(2025); % 固定随机种子 %% 预分配结果矩阵 rate_hbf zeros(length(snr_dB_list), numMonte); rate_full zeros(length(snr_dB_list), numMonte); for s 1:length(snr_dB_list) snr 10^(snr_dB_list(s)/10); for mc 1:numMonte H generate_channel(Nt, K); F_opt full_digital_precoder(H, Ns, zf); [F_RF, F_BB] hybrid_precoder_pe_altmin(F_opt, Nt, NRF); F_hbf F_RF * F_BB; rate_hbf(s, mc) compute_rate(H, F_hbf, snr); rate_full(s, mc) compute_rate(H, F_opt, snr); end end这个流程里最关键的是rng(2025)这一行。通信仿真的随机信道必须用固定随机种子否则每次跑结果都不一样没法做对比实验。至于为什么用2025而不是别的数字就是个习惯问题固定下来就行。4.3 PE-AltMin核心函数代码逐行解释PE-AltMin的核心函数我简化过后大概长这样代码量不大但每一步都有讲究function [F_RF, F_BB] hybrid_precoder_pe_altmin(F_opt, Nt, NRF, maxIter) % F_opt: 全数字预编码矩阵, Nt x Ns % Nt: 发射天线数 % NRF: 射频链路数 % maxIter: 最大迭代次数, 默认设为20 F_BB pinv(F_opt * F_opt) * F_opt * F_opt(1:NRF, :); % 初始数字预编码 F_RF exp(1j * angle(F_opt(:, 1:NRF) * F_BB)); % 初值: 取等效矩阵的相位 for iter 1:maxIter % 固定F_RF, 更新F_BB: 最小二乘解 F_BB pinv(F_RF) * F_opt; % 固定F_BB, 更新F_RF: 取相位 F_RF exp(1j * angle(F_RF * F_BB * F_opt * pinv(F_BB * F_BB) )); % 功率归一化 F_BB F_BB / norm(F_RF * F_BB, fro) * sqrt(Ns); end end这里有个细节值得注意pinv比inv更稳健尤其在矩阵接近奇异的时候不会直接报错而是给出最小范数意义上的解。仿真里矩阵经常是秩亏的用inv会时不时让脚本中途挂掉。另外功率归一化必须在每次迭代的最后做否则后续迭代的数值尺度会乱掉。如果只是想要一个能跑通的版本上面的代码已经够用。但想要更好的性能可以把初值换成正交匹配追踪选出来的结果或者做两三次随机重启取最优这些都是后话。5. 仿真结果读法谱效、收敛曲线与误码率的联动5.1 频谱效率对比怎么判断算法好坏频谱效率Spectral Efficiency是衡量预编码性能最常用的指标单位是 bit/s/Hz。在多用户MIMO里用户k的速率可以写成R_k log2(1 SINR_k)其中SINR_k是用户k的信干噪比分子是期望信号功率分母是噪声功率加上其他用户的干扰功率。把用户谱效求和就得到总频谱效率。画图的时候横轴是SNR纵轴是总谱效画出两条曲线一条是全数字预编码的性能上界一条是混合预编码的实际性能。理想的混合预编码曲线应该紧贴全数字上界差距通常在1到2 dB以内。如果差距拉大到5 dB以上优先怀疑射频链路数是否太少或者信道稀疏度设置是否合理。我见过不少同学第一版仿真跑出来差距很大调整信道模型的路径数之后立刻改善问题不在算法而在信道配置。5.2 收敛迭代次数的工程意义PE-AltMin是迭代算法迭代次数直接影响仿真总耗时。收敛曲线的判断标准很简单相邻两次迭代的目标函数值变化小于一定阈值就可以认为收敛了。目标函数可以用||F_opt - F_RF * F_BB||_F^2来衡量。实测下来PE-AltMin在大多数信道实现中迭代10到15次就能收敛20次基本完全稳定。迭代太多没有意义因为每条新信道实现都要重新迭代蒙特卡洛实验次数一多总耗时就上去了。一个很实用的做法是先在少数几次信道实现上画一次收敛曲线确定合理的迭代次数再带着这个参数跑全量仿真省时省力。5.3 按基线配置复现的参考参数为了让初次上手的人不至于对着空白脚本发愁我给一组实测验证过的配置作为基线。这个配置跑出来的谱效曲线在10 dB信噪比附近混合预编码大概能到达全数字方案的90%左右差距看起来比较合理。信道参数建议值为什么这么设散射簇数量5簇太少信道太理想太多失去稀疏性每簇路径数10典型毫米波实测拟合值角度扩展10度过大会让信道趋于不稀疏收发端距离100米影响路径损耗但不影响算法对比如果收到的代码里信道生成函数的输入参数很多不要全都默认重点调散射簇数量和角度扩展这两个因为它们直接决定信道的稀疏程度进而决定混合预编码的性能表现。6. 我踩过的坑与调参心得6.1 天线数动辄翻倍带来的内存爆炸这是我最想强调的一个坑。很多同学拿到混合预编码代码第一步就是往大里改天线数64、128、256一路往上加。结果往往不是性能变差而是Matlab直接卡死或者内存溢出。原因在于蒙特卡洛仿真里每个信噪比点都要生成若干次信道矩阵每次信道实现都要计算预编码矩阵。如果你把所有中间结果都用变量存下来即使是最简单的Nt x Nt矩阵256根天线也会有相当可观的内存占用再加上循环叠加不死才怪。解决办法有几个。第一能用局部变量就不要用全局变量循环体内的中间量尽量覆盖而不是积累第二蒙特卡洛次数不要一开始就设几千先跑个100次确认流程无误再放大量第三如果只是验证算法性能不必每个信噪比点都跑满可以先跑几个代表点。这套思路能让我们在普通笔记本上完成大部分仿真任务。6.2 信道模型对算法排名的隐藏影响另一个容易忽视的问题是信道模型的选择会影响算法优劣排名。同样一个低复杂度算法在稀疏几何信道下可能表现很好在独立同分布瑞利信道下就可能明显变差。这不是算法本身的问题而是模型与算法适用范围的匹配问题。我建议在仿真报告里明确写上信道模型的假设并且在论文或报告里说明“本算法在稀疏信道假设下性能优势明显在富散射信道下性能会有所下降”。这样写反而显得专业因为审稿人或答辩老师会认可你对算法适用边界有清晰认知。千万不要把一种信道下的结果推广成所有场景都成立。6.3 随机性管理同一套代码两次结果不一样的原因通信仿真里最让人抓狂的问题之一就是同一套代码两次运行结果不一样。绝大多数情况是因为没有固定随机数种子。Matlab的rand、randn每次启动都会有不同的序列信道生成如果用到了这两者结果自然每次都不一样。解决方法是主脚本开头加一行rng(固定数字)。但这里还有一个进阶细节如果并行计算工具箱开启了多个工作进程每个进程的随机数流是独立的即使设了种子每次并行池启动也可能拿到不同的随机数分配。严谨的做法是在每次信道生成之前用RandStream给每个循环分配独立的子流但这属于进阶需求常规仿真固定种子就够了。我在实际做对比实验时还习惯把每一次蒙特卡洛实验的关键中间量保存成.mat文件这样后面对结果有疑问时可以直接回查而不是重新跑一遍。特别是论文数据需要可复现的时候这个习惯能省掉很多解释成本。这块内容做下来之后我最大的感受是混合预编码的算法创新固然重要但仿真框架的稳定性可能更决定一个项目能不能顺利完结。算法调试过程中有一半时间是花在排查变量作用域、矩阵维度、随机性控制这类基础问题上。反过来只要把建模、约束和复杂度账算清楚再配上一份结构清晰的代码骨架低复杂度混合预编码的复现和改良其实没有想象中那么难。希望这篇分享能帮你少走几步弯路把精力花在真正有意思的算法设计上。
阅读完成 · 觉得有帮助?
咨询建站