1. 从对角线到“超越对角线”:RIS模型发生了哪些变化
我最初接触RIS辅助通信仿真时,和大家一样,用的是最经典的那套假设:可重构智能表面每个单元独立控制反射相位,等效相移矩阵是个对角阵,
Φ = diag(e^{jφ₁}, e^{jφ₂}, ..., e^{jφ_L})。这种模型的好处是物理直观,每个单元就是一个可调负载,反射信号只改变相位,不改变单元之间的耦合关系。优化起来也简单,因为变量就是L个相位角,随便用坐标下降或者流形上的梯度上升都能跑。
但最近两年频繁出现在论文里的BD-RIS(Beyond Diagonal RIS,超越对角线RIS)把这一步推得更远了。它不再假设相移矩阵必须是对角的,而是允许RIS单元之间存在受控互连,等效成一个可重构的散射网络。换句话说,相移矩阵Φ不再只是对角阵,它可以有非对角元素,这些非对角元素代表单元之间的能量交换路径。
这个看起来不大的模型改动,实际上把整个问题从“调L个旋钮”变成了“调一个L×L维可重构网络”,优化自由度从L一下子提到了L²量级。代价也很明显:容量最大化问题从相对简单的对角相移优化,变成了带有酉对称约束的矩阵优化。很多第一次做复现的人,拿到代码会发现优化的对象从向量变成了矩阵,梯度公式也一下子变得复杂,这是最大的门槛。
那标题里“容量最大化”这个目标具体是什么?在MIMO通信里,容量最大化通常是指:给定发射总功率约束,设计发射协方差矩阵和RIS相移参数,使得等效信道H = H_r Φ H_t(在有直射链路时还要加上H_d)对应的香农容量最大。传统RIS用对角Φ能做的本质上是“相位对齐”加“阵列增益”,而BD-RIS的散射网络还可以在RIS端口之间重新分配能量,实现类似空间复用和模式调制的效果,这是对角结构做不到的。
这篇文章我会从系统模型、优化算法、Matlab实现、公平对比、常见坑这五个方面,把BD-RIS容量最大化的完整复现思路讲清楚。适合已经有传统RIS或MIMO仿真基础、想要快速上手BD-RIS的读者;如果你只是刚接触通信仿真,前半部分模型推导也能帮你建立一个清晰的数学框架。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 容量最大化问题怎么建模,先推公式再谈代码
2.1 点对点RIS辅助MIMO的系统模型
为了方便复现,我们考虑一个经典的点对点MIMO系统,发射端有M_t根天线,接收端有M_r根天线,RIS布置在两者之间,共L个反射单元。假设直射链路被遮挡,信号只能通过RIS反射链路到达接收端,这是很多RIS论文里常用的简化模型,也是验证BD-RIS增益最干净的场景。
令H₁表示L×M_t的发射端到RIS信道,H₂表示M_r×L的RIS到接收端信道。接收信号可以写成:
y = H₂ Φ H₁ x + n
其中x是M_t维发射向量,n服从独立复高斯分布,均值为零,协方差为σ² I。这里Φ就是L×L的可重构相移矩阵。传统模型里Φ = diag(e^{jφ₁},...,e^{jφ_L}),BD-RIS模型里Φ是带约束的满矩阵。
等效信道可以写成H = H₂ Φ H₁。若发射端采用零均值高斯输入,协方差矩阵为Q,且功率约束为tr(Q) ≤ P,那么系统的可达速率(也就是容量,在已知CSI且高斯输入条件下)为:
R(Φ, Q) = log₂ det( I_{M_r} + σ⁻² H Q Hᴴ )
如果进一步假设采用等功率分配,Q = (P/M_t) I,则速率简化为:
R(Φ) = log₂ det( I_{M_r} + (ρ/M_t) H₂ Φ H₁ H₁ᴴ Φᴴ H₂ᴴ )
其中ρ = P/σ² 是发射信噪比。这个等功率版本虽然在实际容量意义上略微保守,但它在数学上更利于让Φ做梯度优化,仿真时特别方便。后面在讨论注水算法时,我再补充如何升级成真正的容量最大化。
2.2 超越对角线RIS的约束是什么
BD-RIS之所以叫“超越对角线”,是因为相移矩阵不再要求对角线结构,但它也不是任意满矩阵。从电路理论看,RIS单元之间通过可重构阻抗网络互联,需要满足无源约束;若考虑无损网络,则等效相移矩阵还存在酉对称性。
最常用的建模方式是引入散射矩阵S,这个S是酉矩阵,且对于互易网络,S = Sᵀ。BD-RIS的等效相移矩阵一般通过Cayley变换与S关联。不过在实际复现时,我发现更省事的做法是:直接把优化变量设成S,并用它构造等效信道,也就是令:
Φ = S 或 Φ = j(2(I + S)⁻¹ − I)
前一种更直观,直接让S充当相移矩阵;后一种严格对应阻抗网络的散射参数关系。两种选择在容量趋势上基本一致,但后一种在I+S接近奇异时数值上不稳定。为了把精力集中在容量最大化的核心逻辑上,下面代码统一用S作为相移矩阵,然后根据架构加约束。
BD-RIS的典型架构有三种:
- 单连接(Single-connected):S是对角酉矩阵,等价于传统RIS。
- 全连接(Fully-connected):S是没有块状限制的对称酉矩阵,单元之间全部互联。
- 分组连接(Group-connected):把L个单元分成B组,每组内部全连接,组间无连接。此时S是块对角对称酉矩阵。
分组连接是最实用的一种,因为它兼顾性能和硬件复杂度。复现代码时,分组连接的优化可以拆成多个小块独立做,计算效率高,也是我下面会用主要篇幅讲的场景。
2.3 目标函数和梯度公式
假设采用等功率分配,令A = (ρ/M_t) H₁ H₁ᴴ,那么容量可以写成:
R(S) = log₂ det( I_{M_r} + H₂ S A Sᴴ H₂ᴴ )
优化变量S满足分组约束。这个形式看起来很平滑,我们可以直接求它关于S的梯度。经过Wirtinger微分,定义为欧几里得梯度矩阵G,使得关于dS的微小变化的实部为Re tr(Gᴴ dS),则:
G = (1/ln2) · H₂ᴴ ( I + H₂ S A Sᴴ H₂ᴴ )⁻¹ H₂ S A
这里有个细节容易踩坑:在复数矩阵微分里,梯度方向到底是关于S还是关于S的共轭,不同资料写法不一样。我自己验证过,manopt框架里egrad字段通常要求的就是这个G,也就是和dS做内积得到方向导数的那个矩阵。如果你在复现时不确定,最好用manopt自带的checkgradient函数验证,或者用有限差分自己算一遍,否则梯度方向反了,容量曲线会直接往下掉。
3. 基于流形优化的Matlab实现:从理论到可跑代码
3.1 为什么选流形优化而不是朴素投影梯度
拿到这个优化问题,第一反应可能是:直接对S做梯度上升,然后投影到酉矩阵集合上。这个思路没错,但实际效果往往不好,原因是步长不好选,而且投影到“对称酉”集合这一步做不干净。传统投影到酉矩阵可以用极分解,但投影到对称酉矩阵需要额外处理,数值偏差会累积。
更规范的做法是把可行集本身看成一个黎曼流形,直接在流形上做优化。MATLAB里现有manopt工具箱,把度量、梯度、投影都封装好了,我们能少写很多底层代码。以全连接BD-RIS为例,可行集可以建模为Stiefel流形:
M = {S ∈ C^{L×L} : Sᴴ S = I_L}
如果还要对称性,可以进一步施加S = Sᵀ。manopt对复Stiefel流形支持很好。对分组连接,可以用多个小Stiefel流形的乘积构造,这一点在代码里用起来特别舒服。
manopt的最新版本在获取方式上很简单,直接GitHub克隆或者官网下载,加进MATLAB路径就能用,不依赖其他工具箱。这也是我推荐复现BD-RIS优先选择manopt的原因。
3.2 全连接BD-RIS的流形优化主循环
下面给出一个简化但可直接运行的框架,注意我为了突出核心逻辑,省略了天线数、SNR等参数的输入校验,你在实际使用的时候可以自己封装成函数。
matlab复制% 参数配置
Mt = 4; % 发射天线数
Mr = 4; % 接收天线数
L = 16; % RIS单元数
SNR_dB = 10;
rho = 10^(SNR_dB/10);
P = 1;
% 信道生成
H1 = (randn(L, Mt) + 1j*randn(L, Mt)) / sqrt(2);
H2 = (randn(Mr, L) + 1j*randn(Mr, L)) / sqrt(2);
A = (rho / Mt) * (H1 * H1');
% 基于manopt的流形
problem.M = stiefelfactory(L, L); % 可以先跑无对称版本
problem.cost = @(S) -capacity_BD(S, H2, A);
problem.egrad = @(S) -grad_BD(S, H2, A);
% 初始化,取一个对称酉矩阵
S0 = init_symmetric_unitary(L);
problem.x0 = S0;
% 梯度校验,第一次运行务必打开
% checkgradient(problem);
S_opt = conjugategradient(problem, S0);
R_opt = -problem.cost(S_opt);
这里有两个辅助函数需要定义。容量函数很简单:
matlab复制function R = capacity_BD(S, H2, A)
N = Mr;
B = eye(N) + H2 * S * A * S' * H2';
R = real(log2(det(B)));
end
梯度函数按照上面推导的公式写:
matlab复制function G = grad_BD(S, H2, A)
B = eye(size(H2,1)) + H2 * S * A * S' * H2';
G = H2' * (B \ (H2 * S * A)) / log(2);
end
注意,我在容量函数里取了real,因为数值上行列式可能带非常小的虚部,但不影响最终结果;梯度函数里的B\ 实际上是求解线性方程组,比直接inv(B)更稳定,L和M_r都不大时可以放心用。
初始化函数我习惯用S = U Uᵀ的方式生成对称酉矩阵:
matlab复制function S = init_symmetric_unitary(L)
U = (randn(L, L) + 1j*randn(L, L)) / sqrt(2);
[Q, ~] = qr(U);
S = Q * Q.'; % 对称酉矩阵
end
这个技巧很好用:任意酉矩阵Q,Q Qᵀ一定是对称酉矩阵。因为(Q Qᵀ)ᵀ = Q Qᵀ,且(Q Qᵀ)ᴴ (Q Qᵀ) = Q̄ Q^T Q Qᵀ = I。当然它覆盖的对称酉矩阵不是整个流形满射,但作为初始点已经足够。
3.3 分组连接BD-RIS怎么用Manopt实现
分组连接是更贴近实际硬件的架构。假设L=16,分成B=4组,每组g=4个单元,那么S是4个4×4对称酉矩阵的块对角拼接。在manopt里,可以用productmanifold:
matlab复制g = 4;
B = L / g;
manifold_cell = cell(1, B);
for b = 1:B
manifold_cell{b} = stiefelfactory(g, g);
end
problem.M = productmanifold(manifold_cell);
problem.cost = @(X) -capacity_BD(blkdiag(X{:}), H2, A);
problem.egrad = @(X) grad_grouped(X, H2, A, g);
这里复杂度在于梯度函数要把整块的梯度拆回每个小组。代码可以这样写:
matlab复制function G = grad_grouped(X, H2, A, g)
S = blkdiag(X{:});
Bmat = eye(size(H2,1)) + H2 * S * A * S' * H2';
Gfull = H2' * (Bmat \ (H2 * S * A)) / log(2);
G = cell(1, numel(X));
for b = 1:numel(X)
idx = (b-1)*g + (1:g);
G{b} = Gfull(idx, idx);
end
end
这种写法虽然把整个S拆开算,但胜在逻辑清晰,初学者容易看懂。如果想要性能更好,可以改成块级运算,避免构造大的blkdiag,但L不太大时差别不大。
3.4 注水功率分配和联合交替优化
上面用的是等功率分配。更严格地说,容量最大化应该同时优化发射协方差Q和散射矩阵S。对给定S,最优Q由注水算法给出:先对H = H₂ S H₁做奇异值分解,然后按奇异值和功率约束分配功率。这一步在MATLAB里很直接:
matlab复制[~, Sigma, V] = svd(H, 'econ');
lambda = diag(Sigma).^2;
% 注水求解,总功率P=1,噪声功率假设为1/rho
mu = waterfill(lambda, P, 1/rho);
Q = V * diag(mu) * V';
这里waterfill函数需要自己写,或者用CVX代替。注水后的协方差Q让发射端把功率集中到等效信道的强奇异值方向上。交替优化的思路是:固定S算Q,再用当前的Q更新S的梯度;重复直到容量不再上升。但这样做之后,S的梯度公式要改成带Q的版本,不再是简单的A = (ρ/M_t)H₁H₁ᴴ,而是A_Q = ρ H₁ Q H₁ᴴ。也就是说,把原来的A换成带当前Q的修正矩阵即可。
实际复现中,我对这个交替过程的建议是:第一轮先用等功率跑通S的收敛,确认代码没问题后再升级成注水交替。否则两个变量一起动,出了问题很难定位是S更新错了,还是功率分配算错了。
4. 仿真结果怎么对比才公平:参数设置与实测曲线
4.1 对比基准怎么选
BD-RIS论文里最常见的对比对象有三个:
- 无RIS:直接看空口信道容量,用来体现RIS带来的整体增益。
- 传统对角线RIS:某些情况下用随机相位,某些情况下用优化后的相位。用随机相位做对比会明显高估BD-RIS的增益,不够公平。要对比就应该用优化后的对角线RIS,也就是让每个相位角都参与优化。
- 全连接BD-RIS:体现性能上限。
我个人做复现时,更看重的是“优化后的对角线RIS”和“分组连接BD-RIS”之间的差距。因为这是同一套信道、同样的优化框架,只是变量结构不同,对比结论最有说服力。
4.2 我做过的典型仿真参数
下面的参数是我常用的配置,你可以直接照抄:
| 参数 | 取值 |
|---|---|
| 发射天线数 M_t | 4 |
| 接收天线数 M_r | 4 |
| RIS单元数 L | 16 |
| 分组大小 g | 1, 2, 4, 16 |
| SNR范围 | -10 ~ 20 dB |
| 信道类型 | 瑞利平坦衰落,每个元素CN(0,1) |
| 蒙特卡洛次数 | 200 |
| 初始化 | 对称酉矩阵 |
| 优化器 | manopt的conjugategradient |
在每组SNR下,先随机生成H₁和H₂,固定信道,分别跑三种方案:
- 无RIS,用注水容量;
- 优化后的对角线RIS,用相位对齐或者坐标上升;
- 优化后的全连接BD-RIS,用上文流形优化。
对200次信道实现取平均,画容量-SNR曲线。
4.3 实测曲线和结论趋势
从我的复现结果看,几个趋势是很稳定的:
- 对角线RIS在低SNR时能提供明显的阵列增益,容量比无RIS高出一截;但在高SNR时,如果等效信道的秩不够,增益会趋于饱和。
- 全连接BD-RIS在中低SNR区比对角线RIS高10%~30%,这个增益来自散射网络对等效信道奇异值的重塑。随着SNR升高,增益依然保持,但百分比会随绝对容量变大而稍微下降。
- 分组连接是一个很高效的折中方案。L=16、分组大小g=4时,基本能拿到全连接BD-RIS的大部分增益;g=2时性能略低但硬件复杂度更小。这个趋势和近来论文里的结论是一致的。
要注意的是,绝对数值和信道实现、天线数都有关系,如果你复现出来的数值比例和我说的不完全一致,不用太慌,更关键的是看相对趋势和曲线形状。
4.4 蒙特卡洛仿真中的统计置信度
只跑一次信道实现得到的容量曲线波动很大,直接画出来会很难看。标准做法是多次随机信道取平均,并且最好同时画标准差或阴影区间。
我在仿真时会额外记录每一轮的容量值,最后用:
matlab复制R_mean = mean(R_all, 1);
R_std = std(R_all, 0, 1);
然后画带误差带的曲线。200次信道平均已经足够稳定;如果追求更干净的结果,可以跑到500次。
另外,不同方案之间要用同一组信道实例,也就是H₁和H₂要固定复用。这也是保证对比公平性的关键,否则信道随机性会淹没算法之间的差异。
5. 复现BD-RIS最容易踩的五个坑
5.1 忘记对称酉约束,导致容量虚高
这是最大的一个坑。很多复现代码直接把S当成普通酉矩阵去优化,没有施加S = Sᵀ的对称性。这样优化的自由度比物理可实现的BD-RIS更大,容量结果也偏高。你对比论文时,可能看到自己的增益比论文还高,别高兴太早,多半是漏了约束。
我的建议是,从一开始就用对称酉矩阵初始化,并且在manopt里可以用对称Stiefel流形相关的方法;如果实在不好实现对称流形,也可以用U Uᵀ的参数化降维优化,不过梯度计算会稍复杂一些。至少你先跑通无约束版本,然后心里要清楚这个结果对应的是“数学上限”而不是“物理可实现结果”。
5.2 Cayley变换的数值爆炸问题
有些复现代码严格走电路理论,用Φ = j(2(I + S)⁻¹ − I)来把散射矩阵转成相移矩阵。这个变换在S接近 −I 时会出现条件数爆炸,导致容量计算出现NaN或者无穷大。我在仿真里遇到过几次,特别是在高SNR区域,算法试图把S推向极端值时,数值就不稳定了。
解决思路有两个:一是绕开Cayley变换,直接用S来算容量;二是对S做特征值裁剪,让它的特征值远离−1。从复现论文的角度,前者最简单,而且不影响相对结论。如果你必须用Cayley变换验证某个物理量,再加扰动保护和正则化。
5.3 梯度方向写反,容量曲线不升反降
复数矩阵微分很容易让人头晕。manopt里egrad的约定是返回实内积意义下的梯度矩阵,方向弄反之后算法也能跑,但容量会单调下降。我一开始在这个问题上吃了不少亏。
解决办法是固定一个S点,用checkgradient做数值校验。如果校验不过,就先别急着跑完整算法,把梯度修对了再说。如果你不想依赖manopt,也可以自己写有限差分对比,但要注意复数步长的取法,否则误差会很大。
5.4 初始化方式影响最终结果
这个问题的严重程度比想象中大。全连接BD-RIS的搜索空间远大于对角线RIS,随机初始化的酉矩阵很可能让算法收敛到较差的局部最优解。多次跑下来容量方差很大,你会觉得算法是不是写错了。
我有一个比较稳妥的初始化策略:先用传统对角线RIS优化出一组相位角,把这个解析解嵌入到对称酉矩阵的“块对角”位置上,再用该矩阵作为全连接优化的初始点。这样至少保证初始容量不低于传统方案,后续优化的收敛结果也更稳定。由于对称酉矩阵很难直接从一个普通对角相位扩展而来,实际操作中我会先做一个随机对称酉矩阵,然后把它的对角相位修正成和对角优化结果一致的方向,或者干脆多次随机初始化,取容量最高的一次。
5.5 不同方案之间的功率归一化不一致
容量仿真的绝对数值很容易受到信道归一化、SNR定义、功率分配方式的影响。比如有人用tr(Q) ≤ P但P设成1,有人用总功率P = M_t,还有人直接把噪声方差设为1,三种做法的容量曲线会差出好几dB。
在比较无RIS、对角线RIS、BD-RIS时,必须保证三种场景下的信道生成方式、SNR定义、功率约束完全一致。我习惯把所有功率统一归一化到P = 1,噪声方差σ² = 1/ρ,这样SNR不同时,噪声功率自动变化,容量曲线就是纯粹的算法增益对比。每次写新代码时,我会先用最简单的无RIS场景做校准,确认容量公式没问题,再扩展到RIS场景。
6. 最后一个实用技巧:从分组连接开始改代码
如果你手头已经有一套传统对角线RIS的Matlab实现,想快速改成BD-RIS并验证效果,我的建议是不要一上来就写全连接流形优化,而是先改成分组连接,分组大小g先取2。理由很简单:g=2时每个块是一个2×2的对称酉矩阵,优化问题只比对角线情况多一点点自由度,但已经能体现出“超越对角线”带来的增益趋势。你可以把已有的对角相位优化扩展成2×2块优化,容量公式、信道模型、对比曲线都先跑通,再逐步把g增大到4、8、16。
这种渐进式改法在调试时非常有效。我自己的经验是:从g=2到g=16,核心代码框架完全不用变,只改分组大小和流形定义。如果g=2时结果就是正的,那说明模型和算法方向没问题;如果这个阶段就出现容量下降,那一定是基本公式或者约束出了问题,不需要等到全连接才去排查。
最后再补充一个细节:无论用等功率还是注水,记得把蒙特卡洛的随机种子固定,或者至少每次运行时保存生成的H₁和H₂,否则你很难复现自己上次看到的曲线。我在并行仿真中就吃过这个亏,不同进程用的信道不同,结果对不上,排查了很久才发现是随机数流的问题。总之,BD-RIS本身并不难,难的是把物理约束、复数梯度和公平对比这三件事同时做对。希望这篇复现记录能帮你少走点弯路。
