多用户MISO下行链路的波束成形问题中,目标函数常以SINR为基础来构建;这类分段求比值的目标,一旦在分母上出现其他用户的波束,求解就变得非常困难。梯度里耦合着所有波束,直接使用投影梯度会得到难以解释的结果,把它塞进通用凸优化工具又会反复返回“非凸、无法求解”。后来我把二次变换(Quadratic Transformation Method,QTM)用到这类问题上,才发现它真正的作用是重新拆分结构与变量之间的耦合关系,求解难度本身并不是重点。围绕QTM的二次变化原理以及它在MISO场景中的具体做法,下面把推导、实现和实操中的问题完整梳理一遍。
1. MISO场景里的比值目标始终难以求解的根源
1.1 一个多用户下行MISO的典型配置
先固定场景:一个基站配备Nt根天线,同时服务K个单天线用户,信道矢量记为h_k(Nt维列向量),波束矢量记为w_k。用户k的接收信号里,自己那一份是h_k^H w_k,其余K-1份是别人波束造成的干扰。于是信干噪比写成:
SINR_k = |h_k^H w_k|^2 / (Σ_{j≠k} |h_k^H w_j|^2 + σ^2)
发射端总功率约束为 Σ_k ||w_k||^2 ≤ P,通常再配一个最大功率P。这套模型是绝大部分波束成形仿真的起点:多用户MISO、单天线接收、相干检测,简单到可以手推,又足够暴露所有真实困难。
真正让人头疼的是目标函数。常见的几类写法里,几乎每一类都带比例结构:加权和速率 Σ_k ω_k log(1+SINR_k)、max-min 公平性 max min_k SINR_k、能量效率 Σ_k R_k / (Σ_k ||w_k||^2 + P_c)、以及各类“有用信号与泄漏/干扰之比”的工程指标。这些目标的共同点是:分子、分母都是关于w的二次型,而且分母里的二次型来自别的用户。
一个容易被忽略的事实是:MISO波束成形问题里没有秩约束的麻烦。因为接收端只有一根天线,波束就是向量,不存在半正定松弛那一套。换句话说,这个问题的全部难点都集中在“比值”这两个字上,一旦把比例结构拆开,剩下的就是一个带二次约束的凸问题,可以直接求解。
1.2 耦合的真正来源在分母中的其他用户波束
把SINR_k拆开看,分子只涉及w_k,分母涉及所有w_j(j≠k)。这意味着调整w_1时,用户1的SINR会上升,同时用户2、3、…、K的SINR会下降。任何基于梯度的做法,拿到的梯度里都混着这两股力,步长稍大就在用户之间反复摆动。
更麻烦的是非凸性。以max-min为例,可行域是功率球,目标min_k SINR_k在w上是若干个二次分式的最小值,既不是凸的也不是凹的。你甚至没法用“它离凸有多远”来判断,因为分式在分子取零附近会剧烈变化。工程上常见的现象是:仿真跑出来的SINR分布总是几家欢喜几家愁,最大的一直很大,最小的怎么都提不上去,交换用户的编号结果还会变。
我在早期仿真里试过最直接的办法:把目标写成加权和,用数值梯度做投影上升。结果非常不稳定,迭代次数上千次之后目标还在小幅振荡,换个初始点结果差好几个dB。这说明问题不在于“优化器不够强”,而在于建模时没有利用问题本身的结构。
1.3 几种常见做法及其代价
如果要在QTM之前找替代方案,大致有以下几条:
- Dinkelbach 型参数化:对单个比值 f/g,迭代时把比值固定成一个标量λ,转而去解 max f - λg。单比值问题这一步非常好用,收敛是超线性的。但目标一旦变成多个比值相加(比如加权和SINR),每个比值都需要一个λ,解出来的子问题依旧是非凸的差分结构,Dinkelbach 的优势会荡然无存。
- 交替优化:固定其他用户的波束,单独优化某一个w_k。这时用户k的SINR退化成一个瑞利商形式,分子是w_k的二次型、分母也是w_k的二次型加常数,能写出闭式解。做法简单,但收敛极慢,而且本质上只在坐标方向上走,用户一多就得跑几千轮。
- SCA / MM 一阶近似:在当前点对非凸部分做一阶泰勒展开或者构造上界,把问题变成一系列凸问题。这种方法通用性最好,任何目标都能套用,代价是每轮只是“近似最优”,收敛速度取决于近似的紧度,收敛后期步长越来越小,实际跑起来往往要上百轮才能稳定。
- WMMSE:和速率最大化的标准做法,把log(1+SINR)通过MSE加权重写,交替更新接收滤波器和权值。它在和速率上表现很好,但对max-min、能效这类不是“和速率”的目标,改写起来就没那么自然。
这几条路各有适用面,但它们都没有从根本上处理“分母里含有其他人波束”这个结构。QTM 的切入点正是在这里:它不近似,而是通过引入一组辅助变量,把分式等价地变成一个关于w的、可以求解的二次型表达。
2. 二次变换的代数结构:给每个比值配一个“可调权重”
2.1 单个比值:把分母改写成可调整的形式
先从最简单的单比值说起。考虑
max_x f(x) / g(x),其中 f(x) ≥ 0,g(x) > 0
引入一个实辅助变量 y ≥ 0,构造
q(x, y) = 2 y · sqrt(f(x)) − y^2 · g(x)
关键性质有两条。第一,固定x对y求极值:对y求导得 2sqrt(f) − 2y·g = 0,解出 y* = sqrt(f(x)) / g(x);把 y* 代回 q,得到
q(x, y*) = 2 · sqrt(f)/g · sqrt(f) − (f/g^2) · g = f/g
正好还原原来的比值。第二,q 关于 y 是一个开口向下的二次函数(系数 −g < 0),所以这次代换对y来说是精确的,不含任何近似。
于是原问题等价于 max_{x,y} q(x,y)。这个结论看起来只是换了个写法,但它在“结构”上完成了两件事:把原本固定在分母里的 g(x) 转移到了一个独立的变量系数上;把 sqrt(f) 从分式里提取出来,变成了一个线性乘子。当 f 是 |h^H w|^2 这种形式时,sqrt(f) 就是 |h^H w|,再配合相位对齐就变成了线性项;而 y^2 · g 里的 g 本来就是二次型,整体仍然是二次型。
2.2 多个比值:解耦比求解更重要
实际场景里几乎不会只有一个比值。加权和速率、多用户的max-min、能效问题里的多个分项,都是“多个比值同时存在”。如果对每一个比值单独引入辅助变量 y_k,目标变成
Q(w, y) = Σ_k [ 2 y_k · sqrt(f_k(w)) − y_k^2 · g_k(w) ]
这一步的价值远比单比值情形大。原因是:原来的 Σ f_k/g_k 中,每个分式内部的 f_k 与 g_k 都是关于同一个w的二次型,所有用户绞在一起;而变换之后,每个比值被拆成“一个线性项减一个带权二次项”,不同的 y_k 使用不同的权重 y_k^2。固定y看w时,整个目标是若干二次型之和,权重由y给定,耦合从“分式耦合”降级为“加权耦合”。
这就是QTM在工程上最吸引人的地方:它把一个求解困难的非凸分式问题,换成了一个“交替更新两组变量”的问题,而且每一组都有明确的求解路径。
2.3 从模值到实部:相位对齐是必要步骤
MISO场景里 f_k 的具体形式是 |h_k^H w_k|^2,开方之后是 |h_k^H w_k|,带绝对值。绝对值在复变量上不可导,直接对w求梯度会得到不光滑、难以处理的表达式。解决办法是相位对齐:
对任意一个波束w_k,把它整体乘上一个单位模的复数 e^{jθ},不会改变功率,也不会改变任何 |h_j^H w_k|(因为取模),但可以让 h_k^H w_k 变成实数非负。由于SINR只依赖模值,而功率约束对这种旋转不变,所以最优解一定可以取到这个相位对齐的形式。
完成相位对齐后,|h_k^H w_k| 可以写成 Re{h_k^H w_k},线性项就出来了。这一步是推导里最容易忽略、也是实现时最容易出错的地方:代码里如果忘记处理,优化出来的波束会带着随机相位,但只要比较SINR和功率,结果其实一样;而如果跳过对齐直接用 |·| 做梯度,就可能遇到收敛停滞或者来回抖动。
注意:相位对齐只对“分子里带模值”的情形成立。如果分母里也出现需要旋转的项,比如某些多小区场景的干扰项,就要重新检查这个论证是否还能成立,不能机械照搬。
2.4 矩阵形式的推广与适用边界
当接收端不是单天线、或者波束要成组处理时,比值会变成矩阵比值形式(分子分母都是 X^H A X 这类二次型)。此时二次变换的推广版本引入的是矩阵辅助变量,结论的形式和标量版类似:用一个矩阵Y去“夹”住原来的比值,固定Y后子问题仍是凸的。
我在实际使用中的体会是:矩阵版在推导上更整齐,但工程实现里要处理的数值细节(Y的初值、正定性、求逆的稳定性)比标量版多得多。MISO场景用标量版本就够了,没有必要为了形式统一引入矩阵变量。
还有一条边界要明确:QTM 处理的是比值。如果目标里出现了 log(1+SINR) 这样的结构,SINR本身可以被变换,但外层的对数无法一起被吸收掉,因为 log 是凹增函数,不能直接穿过变换。这种情况下常见做法是分两层处理:内层用QTM处理SINR,外层用MM或者一阶近似处理log,或者干脆换用WMMSE这类专门为和速率设计的方法。把目标写成“多个比值”而不是“对数值”的场景,才是QTM最顺手的场景。
3. 在MISO波束成形中的实现:两层交替与闭式解
3.1 辅助变量的更新式可以直接写出
把2.1的结论套到MISO上。对用户k,f_k = |h_k^H w_k|^2,g_k = Σ_{j≠k}|h_k^H w_j|^2 + σ^2。固定w时对y_k求极值,得
y_k = |h_k^H w_k| / (Σ_{j≠k}|h_k^H w_j|^2 + σ^2)
注意分母上少了一个开方。这一点容易搞混:f 的平方根提供了分子上的一个 |h_k^H w_k|,剩下的正好是分母。也就是说 y_k 的物理含义是“当前波束下用户k的信号幅度与干扰加噪声功率之比”,并不是SINR本身。代回后得到的目标值恰好等于SINR_k。
这给了我们一个极便宜的更新:把当前波束下的SINR算出来,乘上 sqrt(SINR) 的倒数关系,实际上就是每轮迭代里先统计一遍当前的干扰功率。复杂度是O(K^2 Nt)量级,在几千次迭代的仿真里几乎不占时间。
3.2 固定辅助变量后的子问题结构
固定y之后,把目标展开:
Q(w) = Σ_k 2 y_k Re{h_k^H w_k} − Σ_k y_k^2 (Σ_{j≠k}|h_k^H w_j|^2 + σ^2)
第二项里有一个求和可以交换次序。把“用户k受到的干扰”按“波束j造成的干扰”重新归类,于是
Σ_k y_k^2 Σ_{j≠k} |h_k^H w_j|^2 = Σ_j w_j^H A_j w_j,其中 A_j = Σ_{k≠j} y_k^2 h_k h_k^H
A_j 是一个Nt×Nt的厄米特半正定矩阵,由所有其他用户的信道外积加权而成,权重正是那些用户的辅助变量平方。于是子问题变成
max_w Σ_k [ 2 y_k Re{h_k^H w_k} − w_k^H A_k w_k ],s.t. Σ_k ||w_k||^2 ≤ P
这是一个凹二次目标(因为每一项的二次部分系数是负的)加一个二次约束,标准凸问题。到这一步,原来的非凸性已经不存在了,困扰我们的分式结构完全消失,剩下的只是一个带约束的二次规划。
这里有一个非常值得强调的结构性事实:目标对各个w_k是可分的,唯一的耦合来自总功率约束。也就是说,如果没有功率约束,每个w_k可以独立求解;有了功率约束,才需要通过一个拉格朗日乘子把它们连接起来。
3.3 拉格朗日乘子与闭式波束
写出拉格朗日函数,对w_k求导置零:
y_k h_k − A_k w_k − μ w_k = 0
得到闭式解
w_k = (A_k + μ I)^{-1} · y_k h_k
其中μ ≥ 0是对应总功率约束的乘子,由 Σ_k ||w_k(μ)||^2 = P 确定。由于 ||w_k(μ)||^2 关于μ单调递减(A_k半正定加上μI之后,逆的范数随μ增大而减小),可以直接用二分法求μ,几十次二分就能达到很高的精度。
这个闭式解的形式值得多看一眼:(A_k + μI)^{-1} h_k 是信道在“干扰加噪声加功率价格”构造出的协方差矩阵下的白化匹配滤波形式。A_k 里的权重 y_k^2 代表“用户k当前的相对重要程度”,μ 代表“功率的价格”。当某个用户的y_k很大时,他在其他用户的A_j里权重也大,相当于把干扰者的空间方向压制住。整个迭代就在“信号方向”和“压制干扰”之间反复寻找平衡。
我个人的观察是,这个闭式结构比WMMSE的等价形式更“干净”:没有MSE权值的迭代更新,没有需要额外维护的接收滤波器,只有一组y和一个标量μ。对于想在嵌入式或快速原型里实现波束成形的场景,这是个不小的优势。
3.4 完整迭代流程与代码骨架
把上面的推导串起来,算法是这样的:
- 初始化波束w_k(比如功率均分的匹配滤波);
- 由当前w计算各用户的SINR与干扰功率,更新 y_k;
- 构造 A_k(k = 1..K);
- 若 μ = 0 时已满足功率约束则取 μ = 0,否则二分求μ,使功率约束紧;
- 按闭式解更新 w_k;
- 检查目标函数相对变化,满足则停止,否则回到2。
Python 骨架(NumPy,复数信道)如下,去掉了加权系数,只保留最核心的迭代结构:
import numpy as np def qtm_miso(H, P, sigma2, iters=200, tol=1e-6): Nt, K = H.shape # 列 k 为 h_k W = np.zeros((Nt, K), dtype=complex) for k in range(K): # 匹配滤波初始化 W[:, k] = np.sqrt(P / K) * H[:, k] / np.linalg.norm(H[:, k]) def sinr_and_interf(W): s = np.zeros(K); d = np.zeros(K) for k in range(K): s[k] = abs(np.vdot(H[:, k], W[:, k])) ** 2 d[k] = sigma2 + sum(abs(np.vdot(H[:, k], W[:, j])) ** 2 for j in range(K) if j != k) return s, d for it in range(iters): # 第一步:辅助变量更新(用幅度除以干扰功率) s, d = sinr_and_interf(W) y = np.sqrt(s) / d # 第二步:构造每个用户的干扰协方差 A_k A = [] for k in range(K): M = np.zeros((Nt, Nt), dtype=complex) for j in range(K): if j != k: M += y[j] ** 2 * np.outer(H[:, j], H[:, j].conj()) A.append(M) # 第三步:对偶变量二分 def solve(mu): Wn = np.zeros_like(W) for k in range(K): Wn[:, k] = y[k] * np.linalg.solve(A[k] + mu * np.eye(Nt), H[:, k]) return Wn Wn = solve(0.0) if np.sum(np.abs(Wn) ** 2) > P: lo, hi = 0.0, 1.0 while np.sum(np.abs(solve(hi)) ** 2) > P: hi *= 2.0 for _ in range(60): mid = 0.5 * (lo + hi) if np.sum(np.abs(solve(mid)) ** 2) > P: lo = mid else: hi = mid Wn = solve(hi) if np.sum(np.abs(Wn - W) ** 2) < tol: W = Wn break W = Wn return W这段代码可以直接跑通并看到收敛,但要拿去比较不同算法的性能,还需要补上加权系数、目标值监控和初始化策略,这些后面会单独说。
4. 收敛性、初始化与数值实现细节
4.1 单调性从哪来,驻点保证到哪一步
QTM 的交替更新本质上是块坐标上升:固定y更新w是精确定位的最优解(子问题是凸的,闭式解就是全局最优),固定w更新y也是精确定位的最优解。每一步都不降低目标值,而目标有上界(在功率约束下SINR有有限上界),所以目标值单调不减且收敛。
收敛到什么点?常见的结论是:在子问题被全局求解、且目标函数满足一定正则性的前提下,这个迭代的不动点满足原问题的一阶最优性条件,也就是驻点。实测中我没有遇到过“收敛到明显劣于全局最优的解”的情况,但在极端信道(比如两个用户信道高度相关)下,不同初始点收敛到的SINR分布确实可能不同,这属于非凸问题本身的限制,不是算法缺陷。
实践中要注意的是“单调”只保证目标不下降,不保证每个用户的SINR都不下降。做max-min类目标时,如果直接监控最小SINR,会看到它在迭代初期有轻微波动,这是正常的,因为目标函数是“加权形式”,权重在每轮变化。
4.2 停止准则、变量缩放与初值选择
停止准则我一般用三条中的两条:目标的相对变化小于1e-4、辅助变量y的相对变化小于1e-4、以及迭代次数上限。单看波束的欧氏距离不太可靠,因为相位对齐之后波束的相位是任意的,两次迭代的w可能只差一个相位但范数差很多。
变量缩放是个容易被忽略的问题。y_k 的量纲是“幅度除以功率”,如果信道本身带很强的路损(|h|很小),y_k 会非常大或者非常小,导致 A_k 的元素在数值上跨度巨大,矩阵求逆的条件数会很差。稳妥的做法是在进入迭代前把信道矩阵按列做归一化,把路损因子提出来单独乘到功率约束上,这样 A_k 的量级始终在1附近。
初值方面,匹配滤波(每用户按最大比发送,功率均分)是最常用的起点,简单且不坏。但要注意:不要用全零初始化。如果w全零,则分子全零,y_k = 0,接着 A_k 全零,闭式解给出 w_k = 0,迭代就卡死在原点,目标恒为0,看起来像“收敛了”。这是新手最容易踩的一个坑,而且因为程序不报错,排查起来很费时间。
4.3 我在仿真中遇到的几个问题
坑一:忘记相位对齐,直接用模值算闭式解。推导里我们用的是 Re{h_k^H w_k},代码里 np.vdot(H[:,k], W[:,k]) 得到的是复数,直接取实部才对。如果直接拿复数去做线性项,解出来的w会带上一个与实际信道不匹配的相位,SINR会莫名低几个dB。
坑二:噪声项处理不一致。变换后的目标里有一项 −σ^2 Σ y_k^2,它是与w无关的常数,对w的求解没有影响,但如果你在用目标值做收敛监控或者和其他算法比目标值,这一项必须算进去,否则会看到目标值“不单调”,误以为是算法有问题。
坑三:对偶变量二分的上界。代码里从 hi = 1 开始倍增,这在信道归一化之后够用。如果没归一化,信道范数很小,正确的μ可能小到1e-12,二分60次也走不到,表现出来是“功率约束一直不紧”,波束功率远小于P。加一个基于 ||H||^2 的尺度估计,或者把二分次数提高到100,都能解决。
坑四:把每个天线的功率约束当成总功率约束。有些系统模型要求每根天线功率不超过P/Nt,这会破坏闭式解的结构(A_k + μI 变成一个对角矩阵加对角乘子,不再有简单的标量μ)。这时候子问题需要改用投影梯度或者SOCP求解,闭式解只是近似,不能直接套。
坑五:比较不同算法时对比w本身。相位任意的性质意味着两个算法可能得到SINR完全一样但w差一个相位的解。要比较就比SINR、比目标值、比功率占用,不要比波束矢量的范数差。
5. 与WMMSE、Dinkelbach、SCA的对照
5.1 每轮代价与收敛速度的实际观感
在Nt = 16、K = 8、总功率归一化的一组仿真里,我对比过几种方法的迭代行为(具体数值随场景变化很大,这里只说趋势):
| 方法 | 每轮主要运算 | 典型迭代轮数 | 收敛形态 |
|---|---|---|---|
| QTM | K次矩阵求逆 + 二分 | 20~60 | 前10轮目标值提升的幅度很大,之后平缓 |
| WMMSE | K次矩阵求逆 + MSE权更新 | 20~50 | 前期略慢,后期稳定 |
| 交替优化 | 每轮K个瑞利商闭式 | 几百到几千 | 每一步提升很小,曲线接近线性 |
| SCA/MM | 每轮解一个凸问题 | 50~150 | 前期平缓,后期步长衰减 |
| Dinkelbach(单比值) | 每轮解一次子问题 | 5~15 | 超线性,极快,但不适用于多比值 |
QTM 和 WMMSE 的每轮代价在同一量级,都是K次Nt×Nt矩阵求逆。QTM的优势在于辅助变量的更新只涉及标量,没有MSE权值那种需要解接收滤波器的额外步骤;劣势在于它不直接处理对数,所以做和速率时需要额外的一层处理。
5.2 目标函数类型与方法选择对照
选型这件事,我的经验是按目标函数的“形状”来分,不要只看方法是否出名:
| 目标形态 | 首选方法 | 原因 |
|---|---|---|
| max-min SINR | 相位对齐后转SOCP + 二分 | 约束可直接写成二阶锥,不需要额外变换 |
| 加权和SINR(SINR本身相加) | QTM | 多比值解耦,每轮闭式 |
| 任意多个比值的加权和 | QTM | 辅助变量解耦,是它的主要适用场景 |
| 和速率 Σ log(1+SINR) | WMMSE,或 QTM 内层 + MM 外层 | 对数需要专门处理 |
| 单比值(如能效) | Dinkelbach 或 QTM | Dinkelbach 收敛更快,QTM 实现更简单 |
| 带不确定集的鲁棒版本 | QTM 变换后接 SOCP | 变换后的子问题形态适合加锥约束 |
有一件事值得说清楚:max-min SINR这个经典问题其实不需要QTM。相位对齐之后,|h_k^H w_k|^2 ≥ t·D_k 可以改写成 Re{h_k^H w_k} ≥ sqrt(t)·||[h_k^H w_j]_{j≠k}, σ||,是标准二阶锥约束,对t做二分就能得到全局最优。这条路径比任何迭代方法都可靠。QTM 在max-min上的价值,主要体现在“想统一用一套代码框架同时处理多种目标”的工程需求上,而不是性能。
5.3 能效与鲁棒版本的适配性
能效最大化是QTM比较典型的使用场景(单比值)。目标写成 Σ_k R_k / (Σ_k ||w_k||^2 + P_c),引入一个标量y,得到 2y·sqrt(Σ R_k) − y^2·(总功率 + P_c)。问题在于 sqrt(Σ R_k) 里的R是对数,这个平方根并不好处理。
我的处理方式分两层:外层用QTM或者Dinkelbach引入标量,内层对每一个 log(1+SINR_k) 用一阶近似或者WMMSE展开。两层嵌套会让每轮代价翻倍,但收敛轮数通常反而下降,因为外层参数化把“能效”这个大比值先固定住了。相比之下,纯Dinkelbach的单层做法在能效问题上更简洁,如果只需要单比值,我会优先选它。
鲁棒版本的情况更微妙。如果信道存在有界误差,SINR的分母会多出一项与误差范数相关的干扰,分子变成 min 形式。二次变换本身仍然可以用,但变换后的子问题里的线性项变成了“在最坏信道下的实部”,需要引入二阶锥约束来表达。此时每轮子问题从“矩阵求逆”退化成“解一个SOCP”,速度会慢一个量级。这类场景我的建议是先用QTM把结构搭出来,跑通正确性,再考虑把内层换成更高效的定制求解器。
6. 把方法用到更复杂场景时的注意点
6.1 多小区与逐小区功率约束
多小区MISO里,每个小区的A_k会把其他小区用户的信道外积也加进来,结构完全一样,只是每个小区的波束闭式解里用的干扰协方差包含了邻区的贡献。真正的变化在功率约束:单小区是总功率,多小区是每个基站各有一条约束,于是拉格朗日乘子从一个标量变成每个小区一个,需要联合二分或者用对偶上升。
我在多小区仿真里试过最简单的做法:外层对每个小区的μ做坐标二分(固定其他小区的μ,调本小区的使本小区功率紧),内层更新波束。这种方法收敛不算快,但实现简单、不需要动主循环结构。如果小区数超过三四个,建议直接上对偶分解,把问题按小区拆开并行求解。
另一个多小区特有的细节:协方差矩阵A_k的规模随小区数增长,Nt = 64、小区数3时,矩阵求逆的开销开始明显。这时候可以用共轭梯度法代替直接求逆,因为 (A_k + μI) 是厄米特正定的,CG迭代十几次就能达到足够精度,总开销比求逆低。
6.2 不完美CSI下的子问题形态变化
信道带误差时,通常把真实信道写成估计值加误差,误差落在某个球或者椭球里。分子从 |h_k^H w_k|^2 变成最坏情况下的最小值,分母的干扰项也会增加一项与误差范数平方相关的上界。变换之后,固定y的子问题不再是纯二次型,而是在每个用户上多出一组二阶锥约束。
工程上的处理顺序是:先把QTM的框架搭好,用完美CSI验证收敛和最优性;再逐步加入误差模型,观察每次加入后子问题求解决的问题形态变化。我在做这一步时犯过一个错:一开始就把误差项和QTM混在一起推导,结果闭式解里出现了没法化简的项,花了很久才定位到问题出在“我误以为变换后的子问题仍然可以闭式求解”。实际上它不再有闭式解,必须交给锥规划求解器。
6.3 大规模天线下的运算量控制
Nt一旦上百,K次Nt×Nt矩阵求逆就变成了主要开销。几个实用的优化方向:
- 利用A_k的低秩结构。A_k = Σ_{k≠j} y_j^2 h_j h_j^H,秩最多是K−1。当K远小于Nt时,用Woodbury恒等式把 (A_k + μI)^{-1} h_k 的计算从O(Nt^3)降到O(Nt K^2)。
- 二分过程中复用矩阵分解。μ在二分时不断变化,但A_k不变,可以对A_k做一次特征分解,之后每次求逆只是在特征值上加μ,代价降到O(Nt^2)。
- 减少内层精度。二分不需要60次,功率约束的相对误差到1e-4就足够,通常20次以内。外层迭代次数比内层精度更重要。
这些优化在Nt较小时看不出效果,一旦上了大规模天线阵列,能带来数倍的加速。我的做法是先写正确版本,用profile确认矩阵求逆确实是瓶颈,再做上述优化,避免过早优化引入难以定位的数值问题。
最后分享一个我调试这类算法时常用的方法:把每一轮迭代的辅助变量y、对偶变量μ、以及还原出来的SINR都打印出来,看它们是否在你预期的范围内单调变化。y应该在迭代开始时快速上升然后趋于稳定,μ应该在功率紧约束时为正、否则为零。如果μ在某轮突然跳变,八成是功率约束的二分边界设错了;如果y在某轮变成零,八成是波束在那个方向上被压没了。这两个信号比任何收敛曲线都直观。