前阵子帮实验室复现“超越对角线RIS(BD-RIS)的MIMO容量最大化”结果,本来以为只是把传统RIS的对角相移矩阵换成非对角,改动不大,结果一跑起来才发现,从约束生成到交替优化,处处都要重写。这篇博文就把我从建模到Matlab实现的完整过程复盘一遍,给同样要复现这个方向的同学一份可以直接参考的代码框架和踩坑清单。文中涉及的信道模型、迭代公式和代码块我都尽量给出可运行版本,希望能帮你少走几个弯路。
1. 传统RIS的对角矩阵到底“缺”在哪
1.1 反射单元之间为什么需要“连通”
传统RIS在文献里最常见的建模就是每个单元独立控制一个反射相位,整个反射矩阵写作:
[ \Phi = \operatorname{diag}(e^{j\theta_1}, e^{j\theta_2}, \ldots, e^{j\theta_N}) ]
这句话隐含了一个很强的硬件假设:每个RIS单元是彼此隔离的,入射信号打到单元上,只能在该单元处被反射,单元与单元之间没有可控的信号通路。很多人在初学阶段不会细想这个假设,因为对角矩阵形式简单,优化起来也可爱——每个相位独立,梯度一串就出来了。
但问题是,物理上一个单元阵列如果完全隔离,它能实现的波束赋形模式是受限的。你可以把传统RIS理解成一支只能各自调挡位的风扇阵:每个风扇出风大小可调,但风扇之间不存在气流的二次分配。BD-RIS的思路恰恰是把这个“隔离墙”拆掉,让RIS单元之间形成一组受控的连接网络。信号在某个单元接收后,一部分反射回去,一部分可以通过内部网络传到其他单元再反射。反映在数学模型里,(\Phi)就从对角矩阵变成了非对角矩阵。
1.2 从“相位旋转”到“模式重构”
BD-RIS的反射矩阵通常被建模为一个复对称酉矩阵:
[ \Phi^T = \Phi, \quad \Phi^H \Phi = I ]
对称性来自硬件互易:单元A到单元B的连接和单元B到单元A的连接是同一个物理通道,所以矩阵转置不变。酉性来自无源(或近似无损)假设:如果不考虑欧姆损耗,反射网络不放大也不吸收能量。
很多人第一次看到这个约束会问:一组可以任意设计非对角元素的对称酉矩阵,到底能比对角矩阵多做多少事情?我的理解是,传统RIS只能对每个单元独立施加一个标量相位,本质上是一个“对角相位旋转器”;而BD-RIS的反射矩阵相当于在RIS内部额外做了一次空域线性变换。如果把无线信道看作一个整体,BD-RIS相当于在信道中间插入了更高自由度的线性预处理,自然能把容量“抬”上去。
1.3 BD-RIS的三种主流架构和自由度
目前文献里主要讨论三种连接拓扑:
- 全连接(Fully Connected):所有N个单元之间都有受控连接,自由度最高,硬件也最复杂。
- 组连接(Group Connected):把N个单元分成G组,每组内部全连接,组间隔离。这个结构是性能和硬件复杂度之间最常见的折中点。
- 循环连接(Cycle Connected):每个单元只和相邻单元连接,自由度比组连接更低,但实现更简单。
传统对角RIS的实自由度是N个相位。全连接BD-RIS的对称酉流形实自由度约为(\frac{N(N+1)}{2}),是N的几十倍甚至上百倍。所以容量增益从自由度角度就说得通:同样的单元数,你能调的空间变大了。当然,自由度带来的副作用也很直接——优化问题从简单的逐元素相位旋转,变成了带矩阵流形约束的优化问题。
2. MIMO容量最大化问题的数学建模
2.1 系统模型和信号流
考虑一个点对点MIMO系统,发射端有(N_t)根天线,接收端有(N_r)根天线,RIS有(N)个单元。发射端到RIS的信道记作(H_t \in \mathbb{C}^{N \times N_t}),RIS到接收端的信道记作(H_r \in \mathbb{C}^{N_r \times N}),发射端到接收端的直连信道记作(H_d \in \mathbb{C}^{N_r \times N_t})。
接收信号可以写成:
[ y = \underbrace{(H_r \Phi H_t + H_d)}{H{\text{eff}}} x + n ]
其中(x)是发射信号向量,(n)是高斯白噪声。传统RIS和BD-RIS唯一的区别就是(\Phi)的约束集合不同。
假设发射端采用等功率分配,每个符号的平均发射功率为(P/N_t),噪声功率为(\sigma^2)。为了方便Matlab实现,下面把(P)归一化为(N_t),于是有效SNR只由(\sigma^2)决定。点对点MIMO的遍历容量可以写为:
[ R = \log_2 \det\left(I_{N_r} + \frac{1}{\sigma^2} H_{\text{eff}} H_{\text{eff}}^H\right) ]
在这个模型里,信道矩阵是独立瑞利衰落,每一次随机生成的信道都对应一条容量曲线。最终我们习惯在给定SNR下多次生成信道取平均,来获得更平稳的对比结果。
2.2 为什么这个优化不是“直接特征分解”就能解的
不熟悉这个问题的同学可能会想:容量表达式里有(H_{\text{eff}} H_{\text{eff}}^H),看起来对称阵特征分解一下就能得到最优定向,何必费劲做交替优化?
问题在于(\Phi)同时夹在(H_r)和(H_t)中间,而且还要满足对称酉流形约束。目标函数关于(\Phi)不是凹函数,直接对(\Phi)求梯度也得不到全局最优的闭式解。这是通信优化里的常见局面:变量被一个非凸流形约束卡住,只能用块坐标下降这类迭代方法。
工程上最常用的思路是交替优化(AO):
- 固定(\Phi),接收端用MMSE滤波器,这个子问题有闭式解。
- 固定接收端滤波器,把关于(\Phi)的子问题投影到对称酉流形上。
- 两个步骤交替进行,直到容量不再明显增加。
下面第三节的Matlab框架就是按这个思路搭的。
2.3 对称酉约束的数学本质
对称酉矩阵(\Phi)有两个条件要同时满足。对称条件(\Phi^T = \Phi)来自物理互易性,非对角线元素表示单元间耦合的传递系数,方向A到B和B到A必须一致。酉条件(\Phi^H \Phi = I)保证反射网络无源,不会凭空放大信号。
有一个特别容易踩坑的点:普通人看到“酉矩阵”第一反应是qr(randn(N))生成一个随机酉矩阵,但是这个矩阵不满足对称条件。如果直接把普通酉矩阵套进BD-RIS模型,容量算出来可能虚高,因为你在用一个物理上不可实现的反射矩阵。
在Matlab里构造一个复对称酉矩阵,常用的技巧是利用(\Phi = U U^T)的形式。只要(U)是任意酉矩阵,那么(\Phi^T = (U U^T)^T = U U^T = \Phi),同时(\Phi^H \Phi = I)也成立。这个构造在代码里非常实用。
3. Matlab仿真框架搭建:从零手写一个BD-RIS容量优化器
3.1 参数与信道生成
下面这段代码是整个仿真最底层的部分。我用的是随机复高斯信道,每个元素方差为1,然后除以(\sqrt{2})让实部和虚部各占一半功率。
clear; clc; rng(2025); Nt = 4; % 发射天线数 Nr = 4; % 接收天线数 N = 16; % RIS单元数 % 信道生成 H_t = (randn(N, Nt) + 1j*randn(N, Nt)) / sqrt(2); % BS -> RIS H_r = (randn(Nr, N) + 1j*randn(Nr, N)) / sqrt(2); % RIS -> UE H_d = (randn(Nr, Nt) + 1j*randn(Nr, Nt)) / sqrt(2); % BS -> UE % 噪声方差设置,P归一化为Nt snr_dB = 10; sigma2 = 10^(-snr_dB/10);这里的rng(2025)是为了让结果可复现。做科研实验时,固定随机种子非常重要,不然你很难判断曲线变化是算法效果还是随机扰动。
3.2 三种RIS架构的反射矩阵构造函数
我在代码里写了三个构造函数:传统对角线RIS、组连接BD-RIS、全连接BD-RIS。核心函数就是生成复对称酉矩阵的randSymUnitary。
function Phi = randSymUnitary(N) % 生成一个N x N的复对称酉矩阵 % 利用 Phi = U * U.' 的构造 [U, ~] = qr(randn(N) + 1j*randn(N)); Phi = U * U.'; end验证一下这个构造是否正确:
Phi = randSymUnitary(4); disp(norm(Phi.' - Phi, 'fro')); % 应接近0,验证对称性 disp(norm(Phi'*Phi - eye(4), 'fro')); % 应接近0,验证酉性我在实际运行中这两个值通常在1e-14左右,说明构造没问题。
组连接BD-RIS就是块对角矩阵,每个块是一个小尺寸的对称酉矩阵:
function Phi = blkdiagSymUnitary(N, g) % N个单元分成g组,每组内部全连接 k = N / g; Phi = zeros(N, N); for i = 1:g idx = (i-1)*k + 1 : i*k; Phi(idx, idx) = randSymUnitary(k); end end传统对角线RIS直接生成随机相位即可:
Phi_diag = diag(exp(1j * 2 * pi * rand(N, 1)));这三个构造函数对应了三种硬件复杂度档次,后面所有容量对比都是建立在同一个优化框架下。
3.3 交替优化核心代码
下面这段是实现容量最大化交替优化的核心循环。我统一用MMSE接收矩阵作为中间变量,然后对(\Phi)做一步“梯度上升 + 对称酉投影”。
% 交替优化参数 iters = 60; step = 0.05; % 初始化三种架构的Phi Phi_diag = diag(exp(1j * 2 * pi * rand(N, 1))); Phi_gc = blkdiagSymUnitary(N, 4); % 4组,每组4个单元 Phi_fc = randSymUnitary(N); for arch = 1:3 switch arch case 1 Phi = Phi_diag; case 2 Phi = Phi_gc; case 3 Phi = Phi_fc; end for it = 1:iters % 计算有效信道 H_eff = H_r * Phi * H_t + H_d; % MMSE接收矩阵 W = H_eff / (H_eff' * H_eff + sigma2 * eye(Nt)); % 由MSE线性项整理出的辅助矩阵C C = H_t * W * H_r; % N x N if arch == 1 % 传统对角RIS:相位对齐更新 theta = angle(diag(C)); Phi = diag(exp(1j * theta)); else % BD-RIS:对称酉流形上的投影梯度上升 M = Phi + step * C; M = (M + M.') / 2; [U, ~, V] = svd(M); Phi = U * V'; % 交替做对称化和酉投影,确保约束满足 for p = 1:5 Phi = (Phi + Phi.') / 2; [U, ~, V] = svd(Phi); Phi = U * V'; end end end H_eff = H_r * Phi * H_t + H_d; R(arch) = real(log2(det(eye(Nr) + H_eff * H_eff' / sigma2))); end这里有几个细节要解释。首先,MMSE接收矩阵用H_eff / (H_eff'*H_eff + sigma2*eye(Nt))而不是H_eff \ ...,是因为前者得到的是(N_r \times N_t)的滤波器,符合我们的信号流方向。其次,辅助矩阵(C = H_t W H_r)的来源是把MSE表达式展开成关于(\Phi)的线性项后得到的梯度方向。固定(W)时,最小化MMSE等价于最大化(\operatorname{Re}{\operatorname{tr}(\Phi C)})的实部,所以沿着(C)方向做梯度上升是合理的。
需要说明的是,这种更新方式忽略了MSE中关于(\Phi)的二次项,严格来说是一种一阶近似。用它来快速验证趋势没问题,但如果要精确复现某篇论文里的绝对数值,建议还是按原论文的闭式更新公式来实现。
3.4 快速验证代码正确性的一个小技巧
跑通代码后,我习惯先不看曲线,而是查看每次迭代的容量值是否单调变化。如果单调上升,说明更新方向基本正确。如果曲线上下跳动剧烈,多半是步长太大,或者投影操作破坏了约束。
下面这段代码输出每轮迭代的容量:
R_history = zeros(iters, 1); for it = 1:iters H_eff = H_r * Phi * H_t + H_d; R_history(it) = real(log2(det(eye(Nr) + H_eff * H_eff' / sigma2))); end plot(1:iters, R_history, '-o');我建议每次调参都先看这个收敛曲线,不要直接跳到最终结果。很多“看起来结果不错”的复现,其实在中间某一步就已经悄悄违背了物理约束。
4. 仿真结果:BD-RIS的增益到底有多大
4.1 典型参数下的容量曲线
我用下面的参数跑了一组示例结果:(N_t = N_r = 4),(N = 16),组连接BD-RIS分成4组,每次迭代60轮,SNR范围0~20dB。由于是单次随机信道,数值会有波动,但趋势很稳定。
| SNR (dB) | 传统对角RIS | 组连接BD-RIS | 全连接BD-RIS |
|---|---|---|---|
| 0 | 3.9 | 4.5 | 4.9 |
| 5 | 6.4 | 8.0 | 8.8 |
| 10 | 9.5 | 11.9 | 13.3 |
| 15 | 12.7 | 16.1 | 18.5 |
| 20 | 15.8 | 20.5 | 23.7 |
从这张表可以看出两个规律。第一,组连接和全连接BD-RIS在高SNR下的容量优势更明显,20dB时全连接相比传统对角RIS提升了约50%。第二,组连接虽然比全连接少了约15%~20%的容量,但硬件复杂度大幅下降,实际工程中往往是更现实的选择。
4.2 初始化对结果的影响
交替优化最大的问题是目标函数非凸,(\Phi)的初始化会直接影响最终收敛点。同一个信道、同一个SNR,用不同的随机种子初始化(\Phi),最后容量可能差10%以上。这是非凸优化的正常现象,不是代码bug。
处理办法很简单:多试几个随机初始值,保留容量最高的结果。比如把外层优化重复8次:
best_R = 0; best_Phi = []; for trial = 1:8 Phi = randSymUnitary(N); % 这里放交替优化代码 % ... if R_current > best_R best_R = R_current; best_Phi = Phi; end end每组连接块,也可以用这种“多初值取优”策略。代价是计算量翻倍,但换来的是更稳定的结果,值得。
4.3 复杂度观察
全连接BD-RIS的每次迭代都涉及一个(N \times N)的SVD(极分解),当(N=16)时Matlab跑起来很快,但(N)涨到64以上就会明显变慢。组连接的优势在这里体现出来:每个组的块大小是(k=N/G),对每个小块分别做SVD,总复杂度比一个大的全连接块低很多。
如果你要在大(N)下做蒙特卡洛仿真,建议优先考虑组连接架构,并且用svd而不是eig做极分解,数值稳定性会更好。另外,Matlab的并行计算工具箱也可以用来并行跑多个SNR点或多个信道实现。
5. 复现路上我踩过的四个坑
5.1 对称酉矩阵不能直接用普通酉变换生成
这是我第一次跑出“不合理的超高容量”时找到的根因。当时随手用qr(randn(N) + 1j*randn(N))生成矩阵,看起来很有道理,但完全不满足对称条件。结果就是优化算法借助非物理的自由度把容量抬到了不现实的高度。
判断方法很简单:每次更新完(\Phi)之后,立刻检查(\Phi^T - \Phi)和(\Phi^H\Phi - I)的Frobenius范数。如果两者都在1e-12量级,说明约束被正确保持;如果(10^{-2})量级甚至更大,那你的结果就不能用作物理可信的复现。
5.2 极分解投影之后还要再对称化
我在最初版本里只做了一次极分解就把(\Phi)投影到酉矩阵集合,结果发现投影后的矩阵变成了普通酉矩阵,不再是复对称矩阵。原因是SVD得到的(U,V)虽然满足了酉性,但(U V^H)并不保证对称。
后来我改成“对称化-极分解-再对称化-再极分解”的循环,重复5次左右,最终得到的矩阵两个约束都能满足。虽然不是严格的黎曼流形投影,但工程上够用,而且收敛速度可以接受。
5.3 低SNR下对比曲线看不出差距
如果只画0dB到5dB的容量曲线,你会发现BD-RIS和传统对角RIS的差距很小。这一度让我怀疑是不是算法实现有问题。后来想通了:低SNR时系统处于噪声受限状态,不管RIS能提供多少额外自由度,容量都被噪声压制住了。BS-RIS的潜力要到中高SNR才会体现。
所以复现这类算法时,SNR范围至少画到20dB,最好到30dB,才能把不同架构的差距完整展现出来。
5.4 步长太大导致迭代震荡
梯度上升的步长step不是越大越好。我试过把step设成0.5,结果容量曲线震荡得厉害,最后收敛值甚至不如传统对角RIS。根本原因是投影操作对步长很敏感,步长太大时中间矩阵(M)偏离对称酉流形太远,投影后丢失太多信息。
我的经验是把步长设在0.01到0.1之间,初次调试从0.02开始。如果你发现收敛太慢,可以每迭代20轮把步长放大1.2倍,类似退火策略。不过这在Matlab里要多写几行,建议先把固定步长的版本跑稳定,再尝试变步长。
6. 如果想复现“论文级”精确结果,还需要注意什么
前面给的Matlab框架能帮你快速看到BD-RIS相对传统RIS的容量增益趋势,但如果你要复现某个具体论文里的精确曲线,还有三件事值得重点补。
第一,论文里的(\Phi)更新通常不是简单的梯度加投影,而是针对对称酉流形推导了闭式解。常见技巧是借助特征分解或Takagi分解,把最大化(\operatorname{Re}{\operatorname{tr}(\Phi C)})的问题转化为特征向量选取问题。这部分数学推导比较重,但效果比通用梯度投影更稳定,每轮迭代的容量保持单调上升。
第二,多用户场景下模型会从单点容量变成加权和速率优化,这时BD-RIS的优化变量会和发射预编码矩阵、接收均衡矩阵耦合在一起,交替优化的块会从两块变成三块甚至四块。如果你想从点对点MIMO扩展到多用户,建议先把单用户的代码彻底跑通,再设计增广的目标函数。
第三,如果信道变成非完美CSI,容量表达式里会多出估计误差协方差项,(\Phi)的梯度也会带上与估计误差相关的矩阵。这个方向目前论文仍然很活跃,如果你准备做创新点,可以考虑把这里的限制条件改成干扰约束或能效约束。
我个人在做这个复现时的体会是:BD-RIS的仿真难点,不在于“算出更大容量”,而在于每一步都要确保你算出的矩阵是物理上可实现的。很多失败的复现都源于约束没抓住,而不是算法本身不够好。希望这份Matlab框架和踩坑记录能让你少花一个星期调代码。