
简介毫米波系统中混合预编码的交替最小化MATLAB实现面向通信工程方向本科生、研究生及预编码算法研发者可用于大规模MIMO场景下模拟/数字预编码联合优化的算法验证与性能分析以解决全数字预编码硬件成本高昂、混合预编码求解困难等实际问题。压缩包共12个文件包含11个.m源码与1张结果示意图总大小仅24KB代码涵盖交替最小化主程序、OMP正交匹配追踪、信道生成、阵列响应及SNR扫描等模块结构紧凑便于定位与复用。目前已有81人学习下载适合课程设计、毕业设计及科研初期探索。运行main_SNR等脚本可复现不同信噪比下的频谱效率曲线调节Nc参数可观察子载波数对性能的影响对照非并行版本可进一步理解交替最小化的收敛特性与复杂度权衡帮助读者完整掌握从算法原理到代码实现的映射关系。1. 毫米波系统的混合预编码为什么最后收敛到交替最小化5G 毫米波基站端的天线阵列动辄 64 元、128 元起步射频链路却只给到 4~8 条。相位要由移相器在射频域完成多流数据要靠数字域的低维矩阵叠加于是每个符号都要经过“模拟预编码 × 数字预编码”两级变换。两级矩阵合起来逼近理想全数字预编码这就是混合预编码。直接联立求解这两个矩阵是非凸的工程上最常见的做法就是把它拆成两个子问题交替处理先固定模拟域矩阵用最小二乘解出数字域再固定数字域用码本搜索或相位提取更新模拟域。这样每个子问题都有闭式解迭代十几轮就能收敛到稳定点。下面从毫米波信道建模讲起直接给出一套能跑的 MATLAB 实现和参数调整方法最后再落到宽带 OFDM 场景的扩展上。2. 混合预编码问题建模与交替最小化的推导2.1 毫米波信道模型与混合预编码结构毫米波系统里的信道常用几何信道模型Saleh-Valenzuela 型描述。假设发射端 Nt 根天线、接收端 Nr 根天线信道 H 是 L 条路径叠加的结果H Σ(l1..L) α_l · a_R(φ_l) · a_T^H(θ_l)α_l 是第 l 条路径的复增益φ_l 和 θ_l 分别是对应的到达角AoA和离开角AoD。a_T(θ) 是均匀线阵响应常用向量形式是 [1, e^{jπ sinθ}, e^{j2π sinθ}, …, e^{j(Nt−1)π sinθ}]^T这里已经假设阵元间距为半波长。毫米波环境里 L 通常只有 3~8 条有效路径这正是混合预编码能工作的前提信道在角度域稀疏少数几条强路径就能代表大部分能量。设数据流数为 Ns发射端有 NtRF 条射频链NtRF 远小于 Nt一般取 Ns 的 1~2 倍。发射信号经过基带预编码 F_BBNtRF×Ns 矩阵和模拟预编码 F_RFNt×NtRF 矩阵后送入天线阵列。模拟部分通常由移相器网络实现每个元素的模恒为 1/√Nt相位只能取量化后的离散值数字部分不受约束可以是任意复矩阵。整个发射预编码就是 F F_RF F_BB。为什么不用全数字预编码也不单纯用模拟波束成形成本和自由度的差异很明显我习惯用这张表快速对齐方案射频链数量阵列增益多流能力矩阵自由度典型实现难度全数字预编码Nt高最多 Ns 路完全自由硬件成本高、功耗高纯模拟波束成形1高仅单流只有相位只能扫方向不能同时多流混合预编码Ns~2Ns高多流恒模低维复矩阵需联合设计两个矩阵混合预编码本质上是用尽量少的射频链换接近全数字的性能。目标也很直白让 F_RF F_BB 尽可能逼近某个“理想的全数字预编码矩阵 F_opt”。单用户点对点场景F_opt 通常取信道 H 的右奇异向量里对应最大奇异值的前 Ns 列多用户场景则换成 ZF 或块对角化得到的结果。2.2 以全数字预编码为目标的优化问题把预编码设计写成优化问题minimize ||F_opt − F_RF F_BB||_F^2subject to F_RF ∈ W, ||F_RF F_BB||_F^2 Ns第一个约束表示模拟矩阵的每一列都从预置的移相器码本 W 中选取第二个约束是总发射功率限制让 F_RF F_BB 的 Frobenius 范数等于 Ns。这两个约束加在一起问题立刻变成非凸的不能用一次 SVD 或一次最小二乘解决。一个常见的疑问是为什么不直接最大化可达频谱效率 log2 det(I …)因为频谱效率表达式里有 log-det 项对 F_RF 的恒模离散约束求导很困难也没有闭式解。用 ||F_opt − F_RF F_BB||_F 作为设计目标一方面和频谱效率呈强相关另一方面允许把问题拆成两个可解析的子问题。最终验证阶段再用频谱效率曲线验收设计阶段只看 Frobenius 范数距离这是我做仿真时常用的分工。2.3 交替最小化的三步迭代与收敛性交替最小化的思路是别一次求两个变量先固定一个解另一个。先固定 F_RF。此时 F_BB 是无约束最小二乘问题直接对 F_BB 求导并令导数为零F_BB (F_RF^H F_RF)^{-1} F_RF^H F_opt当 NtRF 较小或 F_RF 的列相关性较高时Gram 矩阵 F_RF^H F_RF 可能病态我会在括号里加一个 1e-6 量级的正则项 εI。得到 F_BB 后还需要做功率归一化把 F_RF F_BB 的总功率拉到 Ns。再固定 F_BB更新 F_RF。由于 F_RF 的候选数量有限码本大小 M这一步本质上是“从 M 个候选方向里选出 NtRF 个去解释残差矩阵 F_opt − F_RF F_BB”。常见做法是用类似 OMP 的逐列选择每次找与残差能量最匹配的码本列选完从残差里减掉这列的贡献再选下一列。这个更新天然保证恒模约束始终成立。整套交替过程可以写成下面的 MATLAB 风格伪代码% F_RF 初始化OMP 式从码本中选列 R Fopt; for k 1:NtRF [~, idx] max(sum(abs(W * R), 2)); F_RF(:, k) W(:, idx); R R - F_RF(:, k) * (F_RF(:, k) * R); end % 主迭代 for it 1:maxIter F_BB (F_RF * F_RF 1e-6 * eye(NtRF)) \ (F_RF * Fopt); F_BB sqrt(Ns) * F_BB / norm(F_RF * F_BB, fro); obj(it) norm(Fopt - F_RF * F_BB, fro)^2; if it 1 abs(obj(it-1) - obj(it)) tol, break; end R Fopt - F_RF * F_BB; for k 1:NtRF [~, idx] max(sum(abs(W * R), 2)); F_RF(:, k) W(:, idx); R R - F_RF(:, k) * (F_RF(:, k) * R); end end每次迭代里F_BB 子问题取到了当前 F_RF 下的全局最优F_RF 子问题也保证目标不增因此目标值单调下降。但要注意离散码本和恒模约束会让问题停在一个局部驻点不能保证全局最优。实际执行时我习惯用一组“随机初始化跑 3~5 次、取 NDF 最小”的结果作为最终输出能明显减少坏初值带来的性能抖动。3. 用 MATLAB 实现交替最小化信道、码本与核心函数3.1 生成毫米波稀疏信道的 mmwave_channel 函数先写信道生成函数。这样后续脚本不用依赖任何通信工具箱纯矩阵运算就能跑。array_response单独保存为array_response.m其他函数放同一目录即可互相调用。function H mmwave_channel(Nt, Nr, L) % 生成毫米波稀疏信道返回 Nr x Nt 复数矩阵 % Nt, Nr: 发射/接收天线数L: 有效路径数 alpha (randn(1, L) 1i * randn(1, L)) / sqrt(2); % 每条路径复增益 H zeros(Nr, Nt); for l 1:L aod -60 120 * rand; % 离开角 AoD单位度 aoa -60 120 * rand; % 到达角 AoA单位度 H H alpha(l) * array_response(Nr, aoa) * array_response(Nt, aod); end H H / sqrt(L); % 让信道F范数期望为 sqrt(Nt*Nr) end function a array_response(N, phi_deg) % 半波长均匀线阵响应向量N 元 n (0:N-1).; a exp(1j * pi * sin(deg2rad(phi_deg)) * n); end逻辑说明alpha用复高斯分布产生功率期望为 1array_response里exp(1j * pi * sin(...) * n)隐含了 d/λ 0.5 的阵元间距。路径数 L 取 8 左右既能体现毫米波稀疏性又不会让信道退化成满秩瑞利信道。最后除以sqrt(L)很关键如果不做这一步H 的范数会随路径数线性膨胀后面频谱效率数值会整体漂移很多复现结果对不上都是这里少了一除。参数说明如果模拟的是室内毫米波场景角度范围可以压缩到 ±45°如果是宏站覆盖±60° 仍然偏小建议把角度按实际小区扇区范围改成 ±80°并同步调整码本的覆盖。路径数 L 越大信道越接近满秩菲涅尔信道混合预编码的增益会被稀释。3.2 生成模拟预编码码本的 codebook 函数码本可以理解为“移相器可调相位的候选集合”。用均匀网格码本最简单function W codebook(Nt, M) % 生成 Nt x M 的码本M个候选方向覆盖[-90, 90)度 W zeros(Nt, M); for m 1:M phi -90 180 * (m - 1) / M; W(:, m) array_response(Nt, phi); end endM 是候选方向数。M64、Nt64 时相邻波束的间隔约 2.8°波束主瓣宽度约 2/Nt 弧度约 1.8°网格基本够用如果模拟移相器是 2 bit 量化M 就取 4那是另一套约束。码本列是单位范数的这个性质会直接用在后面交替最小化的模拟更新里。所有候选列都满足恒模约束因此从码本里选出来的 F_RF 天然合法。3.3 hybrid_altmin 主函数与迭代逻辑核心函数采用 OMP 初始化加数字/模拟交替更新的结构。初始化阶段直接把 F_opt 当作待解释对象从码本里挑出贡献最大的 NtRF 列主循环里每轮先解 F_BB再基于残差做一轮码本搜索。函数输入输出作用mmwave_channelNt, Nr, LH生成毫米波稀疏信道array_responseN, phi_dega生成 ULA 响应向量codebookNt, MW生成网格模拟码本hybrid_altminH, Ns, NtRF, W, maxIter, tolFRF, FBB, obj交替最小化主函数function [FRF, FBB, obj] hybrid_altmin(H, Ns, NtRF, W, maxIter, tol) % 混合预编码交替最小化主函数 % 输入: H Nr x Nt 信道矩阵 % Ns 数据流数 % NtRF 发射端射频链数量 % W Nt x M 模拟码本 % maxIter 最大迭代次数 % tol 目标值变化阈值 % 输出: FRF Nt x NtRF 模拟预编码 % FBB NtRF x Ns 数字预编码 % obj 每轮目标值用于画收敛曲线 [~, ~, V] svd(H, econ); Fopt V(:, 1:Ns); % 全数字预编码基准 M size(W, 2); used false(M, 1); % ---- OMP初始化 ---- R Fopt; FRF zeros(size(W, 1), NtRF); for k 1:NtRF scores sum(abs(W * R), 2); scores(used) -inf; % 同一波束方向不重复占用 [~, idx] max(scores); FRF(:, k) W(:, idx); used(idx) true; R R - FRF(:, k) * (FRF(:, k) * R); end % ---- 交替主循环 ---- FBB zeros(NtRF, Ns); obj zeros(maxIter, 1); for it 1:maxIter % 数字子问题正则化最小二乘 FBB (FRF * FRF 1e-6 * eye(NtRF)) \ (FRF * Fopt); % 功率归一化让发射总功率等于 Ns FBB sqrt(Ns) * FBB / norm(FRF * FBB, fro); obj(it) norm(Fopt - FRF * FBB, fro)^2; if it 1 abs(obj(it-1) - obj(it)) tol break; end % 模拟子问题逐列码本搜索 R Fopt - FRF * FBB; used(:) false; for k 1:NtRF scores sum(abs(W * R), 2); scores(used) -inf; [~, idx] max(scores); FRF(:, k) W(:, idx); used(idx) true; R R - FRF(:, k) * (FRF(:, k) * R); end end obj obj(1:it); end几个容易写错的地方需要实际动手时注意。数字子问题的(FRF*FRF 1e-6*eye(NtRF))正则项不能省当 NtRF 稍大或码本列之间角度接近时Gram 矩阵的条件数很容易到 1e3 以上不加正则时 F_BB 会出现大范数再叠加后面的功率归一化会直接把 NDF 曲线顶出一个尖峰。功率归一化要放在最小二乘之后、记录 obj 之前顺序反了收敛曲线就会不单调。模拟更新里的used数组防止同一波束重复占用射频链这在纯交替里不是严格必需但能显著降低局部收敛的概率。3.4 最小可运行主脚本与归一化处理把上述函数放进同一目录复制下面脚本运行Nt 64; Nr 16; % 发射/接收天线数 Ns 2; NtRF 4; % 数据流/发射射频链 L 8; M 128; % 信道路径数/码本大小 H mmwave_channel(Nt, Nr, L); W codebook(Nt, M); [FRF, FBB, obj] hybrid_altmin(H, Ns, NtRF, W, 100, 1e-4); % 发射端整体功率归一化保证和全数字基准公平比较 Fn FRF * FBB; Fn sqrt(Ns) * Fn / norm(Fn, fro); % 10 dB 线性信噪比 snr_lin 10^(10 / 10); % 可达频谱效率 R_mix real(log2(det(eye(Ns) (snr_lin / Ns) * (Fn * H * H * Fn)))); % 全数字基准 [~, ~, V] svd(H, econ); F_full V(:, 1:Ns); F_full sqrt(Ns) * F_full / norm(F_full, fro); R_full real(log2(det(eye(Ns) (snr_lin / Ns) * (F_full * H * H * F_full)))); fprintf(全数字频谱效率: %.2f bit/s/Hz\n, R_full); fprintf(混合预编码频谱效率: %.2f bit/s/Hz\n, R_mix); fprintf(归一化NDF: %.4f\n, norm(F_full - FRF * FBB, fro)^2 / norm(F_full, fro)^2); figure; plot(obj, -o); xlabel(迭代次数); ylabel(||F_{opt} - F_{RF}F_{BB}||_F^2); grid on;这里对 H 没有单独做归一化因为 mmwave_channel 里已经除以sqrt(L)信噪比的基准是总发射功率 Ns、噪声功率 1。频谱效率公式里的snr_lin / Ns是每个数据流分配的功率和发射天线数无关。这个模型没有加路径损耗绝对频谱效率数值会偏高验证实现正确性主要看全数字和混合之间的差距是否在 1 bit/s/Hz 以内、NDF 是否在 0.1 上下差距太大优先怀疑码本覆盖角度和 H 的 AoD/AoA 范围不匹配。4. 交替最小化的参数设定、性能评估与四个典型坑4.1 关键仿真参数表与调整方向写交替最小化仿真有一组参数几乎每次都要定。下表是我默认的开始值以及它们各自的调整语义参数常用起始值调大之后调小之后天线数 Nt64 或 128波束更窄、阵列增益高码本搜索变慢角度分辨率下降射频链 NtRFNs~2Ns数字自由度提升NDF降低硬件开销大接近Ns时会退化为纯波束对准数据流 Ns2 或 4单流信噪比下降数字矩阵更病态浪费射频链和信道自由度路径数 L6~8信道变满秩混合优势减弱过于理想可能掩盖算法问题码本大小 M2Nt~4Nt波束量化误差减小搜索成本线性涨量化误差成为性能瓶颈迭代次数 maxIter50~100对已收敛问题无收益容易停在未收敛点收敛阈值 tol1e-4会更早停止代价是精度迭代次数增加正则系数 ε1e-6数字预编码偏斜NDF抬升Gram病态时FBB爆炸几个容易被忽略的联动点。第一M 和 Nt 的比值决定了角度网格的量化误差毫米波系统里 AoD 大概率不会恰好落在网格上这种 off-grid 误差在高频段会直接变成频谱效率损失不能靠增大迭代次数弥补只能加大 M 或改用相位提取类算法。第二NtRF 从 Ns 加到 2Ns 带来的增益并不线性第一个额外射频链带来的增益最大第三个开始基本是边际效果仿真对比 NtRF 时应该一组一组跑而不是只改一个点。第三如果做的是宽带仿真的初期验证先把码本 M 设大一点确定算法上限再退回量化码本排错顺序更清晰。4.2 用收敛曲线和频谱效率验证实现跑通主脚本后不要直接看频谱效率就收工。我一般先看两样东西收敛曲线是否单调以及混合预编码与全数字基准的差距是否随迭代缩小。% 复用 3.4 节得到的 obj 与 H [~, ~, V] svd(H, econ); Fopt V(:, 1:Ns); % 用不同迭代轮数对比NDF rounds [5, 10, 20, 40, 80]; ndf_vals zeros(size(rounds)); for i 1:length(rounds) [FRF_i, FBB_i] hybrid_altmin(H, Ns, NtRF, W, rounds(i), 1e-6); Fn_i FRF_i * FBB_i; Fn_i sqrt(Ns) * Fn_i / norm(Fn_i, fro); ndf_vals(i) norm(Fopt - Fn_i, fro)^2 / norm(Fopt, fro)^2; end semilogx(rounds, ndf_vals, -*); xlabel(迭代次数); ylabel(归一化NDF); grid on;收敛曲线如果出现“前两轮下降明显、后面缓慢下台阶”的形状是交替最小化的正常表现不要为了提高收敛精度盲目把迭代加到 500 次。台阶通常是码本量化误差造成的继续迭代也降不下去。如果第一轮结束 NDF 反而高于 OMP 初始化值大概率是 F_BB 功率归一化里的 norm 写法有误或者正则系数过大。4.3 四个典型坑第一个坑是直接用exp(1j*angle(R))这种相位提取方式更新 F_RF忽略了码本。无码本约束下这样做每列都恒模看起来没问题但硬件移相器只支持有限个相位状态直接量化后性能掉得很快。仿真模型如果最终要落到硬件从一开始就带码本约束比后期再改省事得多。第二个坑是数字预编码做完最小二乘后没有做总功率归一化就进入下一轮模拟更新。这样会让残差 R 的范数被 F_BB 的尺度带偏下一轮码本选择也会跟着偏。代码里把FBB除以norm(FRF*FBB, fro)再乘sqrt(Ns)这个顺序不要改。第三个坑是 F_opt 的列没有和信道奇异值对齐。用svd(H, econ)时V 的列顺序和奇异值自动对齐但有人喜欢用eig(H*H)再自己排序排序一错整段交替都在解释错误的方向。统一用 SVD 拿 F_opt少一步出错机会。第四个坑出现在初始化。如果直接拿随机的码本列当 F_RF 起点交替很容易停在一个差的驻点。用 3.3 节里的 OMP 初始化先把信道主导方向选出来比随机初始化稳定得多。也可以从 OMP 初始化的结果出发再跑几个不同的随机种子取 NDF 最小的结果。提示如果频谱效率曲线在某个 SNR 点突然塌陷先看是不是码本覆盖角度没有覆盖到信道的 AoD/AoA。信号方向跑到码本边缘时交替最小化会表现出“怎么迭代都不动”的假收敛这是覆盖问题不是收敛问题。5. 把交替最小化扩展到宽带 OFDM 场景的实用技巧5.1 跨子载波拼接目标函数的做法OFDM 毫米波系统里每个子载波上的信道都不同数字预编码可以逐子载波设计但模拟预编码因为移相器无法随频率变化而共用一套。常见做法是构造拼接矩阵把窄带目标扩展成跨子载波的单一目标。记 H[k]、Fopt[k]、FBB[k] 分别为第 k 个子载波的信道、全数字预编码和数字预编码。定义Fopt_all [Fopt[1], Fopt[2], …, Fopt[K]]FBB_all [FBB[1], FBB[2], …, FBB[K]]目标函数从单载波的 ||Fopt − FRF FBB||_F^2 变成对全部 K 个子载波求和min Σₖ ||Fopt[k] − FRF FBB[k]||_F^2 ||Fopt_all − FRF FBB_all||_F^2这样模拟预编码更新逻辑和窄带版几乎一致只是残差矩阵从 Nt×Ns 变成了 Nt×(K·Ns)。数字更新在拼接矩阵上统一做一次最小二乘再按子载波块分别做功率归一化。5.2 两步修正先稀疏初始化再做拼接矩阵上的码本搜索我常用的落地技巧是两步走。第一步只用信道带宽中心的几个子载波做一次 OMP 初始化得到 F_RF 的初值第二步把所有子载波拼起来在拼接矩阵上做交替。第二步的模拟更新不能用“每个子载波各自选方向再投票”的方式那样不同子载波会选出互相冲突的方向收敛后模拟矩阵在两个方向之间摇摆。正确的做法是在拼接残差上直接算 scoresR_all Fopt_all - FRF * FBB_all; scores sum(abs(W * R_all), 2); % 统计全部子载波的总匹配能量 [~, idx] max(scores); FRF(:, k) W(:, idx);这里的scores已经把 K 个子载波的残差能量聚合成一个 M×1 向量选出的方向是对整个带宽整体贡献最大的方向而不是某一个子载波的最优方向。数字部分每轮按子载波块单独归一化模拟部分只在拼接残差上更新两边的目标一致交替不会互相拉扯。验证第二阶段是否有效可以对比“只做第一步固定模拟矩阵”和“第二步完整交替”两个版本的宽带频谱效率。第一步已经能拿到大部分阵列增益第二步通常还能在边缘子载波上再捞回约 20% 的 NDF 下降。如果观察某个边缘子载波的 NDF 始终不掉不要增加迭代次数先检查该子载波的功率归一化是否写在了子载波块内。提示均匀线阵换成均匀面阵时码本从一维角度网格换成二维 (azimuth, elevation) 网格scores 的计算形状不变只是 W 的列变为二维响应向量的展开。交替最小化的主循环一行都不用改。把一次窄带码本搜索换成跨子载波拼接矩阵上的码本搜索宽带 OFDM 的混合预编码实现就和窄带共用了同一套交替框架代码里唯一要警惕的是 FBB_all 按子载波块归一化时不要误写成按拼接矩阵整体归一化。本文还有配套的精品资源点击获取