RSMA速率拆分仿真:MMSE接收机与功率分配实战指南
简介这份资源面向通信系统仿真方向的研究生与工程师聚焦RSMA速率拆分技术在有限反馈场景下的MMSE基预编码实现帮助读者理解多用户MIMO中公共与私有信息拆分、有限反馈量化及预编码矩阵设计的完整链路。压缩包共14个文件全部为m脚本整体约7KB涵盖信道模型建立、RVQ有限反馈、MMSE与鲁棒MMSE预编码、速率拆分功率分配、ZF与正则化ZF对比以及和速率与遍历性能评估等模块结构紧凑便于逐文件研读。目前已有1129人学习下载。通过运行与修改这些脚本读者可复现不同反馈精度与CSI误差下的和速率曲线对比各类预编码策略的干扰抑制效果为5G/6G多址接入与预编码研究提供可直接复用的仿真框架与排错参考。1. 从 code.zip 说起RSMA 速率拆分仿真到底在算什么如果你手头正好有一个叫code.zip的压缩包里面是 RSMARate Splitting Multiple Access速率拆分多址的通信系统仿真代码那你大概率正卡在同一个问题上速率拆分Rate Splitting听起来逻辑很顺——把干扰拆成公共部分和私有部分分别处理——但真跑起来公共速率和私有速率怎么分、MMSE 接收机怎么接、功率分配怎么调每一步都能让人翻车。这个方向不是新概念但它在 5G 演进和 6G 预研里一直是热门原因很直接相比把干扰当噪声的经典多址RSMA 能在同一时频资源上让多个用户同时传输还能通过速率拆分把部分干扰“解码掉”而不是“忍掉”频谱效率和用户公平性都有实打实的提升。这套仿真要解决的核心问题就一个给定信道条件和功率预算怎么把总速率拆成公共层和私有层让每个用户的可达速率最大化。适合谁看通信物理层方向的研究生、做链路级仿真的工程师、以及想从零复现 RSMA 增益的开发者。下面我按自己跑这类仿真的顺序把原理、代码结构、参数设置和踩坑点一次讲透。2. RSMA 速率拆分的信号模型与仿真框架怎么搭2.1 速率拆分到底拆的是什么先把这个概念说清楚不然后面代码没法看。传统多用户下行里基站给每个用户发一个独立数据流用户端把其他用户的信号当干扰。RSMA 的做法是基站把所有用户的消息拆成两部分——一部分放进一个公共流所有用户都解码这个公共流另一部分是每个用户各自的私有流只给自己解码。公共流承载的是“大家都能用”的信息私有流承载的是“只对你有用”的信息。接收端处理顺序是固定的先解公共流把公共流从接收信号里减掉再解自己的私有流。这个顺序不能反因为私有流解码时公共流已经被消除了剩下的干扰只有其他用户的私有流。这就是速率拆分的核心用一次公共流解码换掉一部分私有流之间的干扰。为什么这个思路有效因为公共流对所有用户都是有用的解码它不算浪费。而私有流之间的干扰在公共流被消除后强度会下降。代价是公共流要分走一部分功率和速率预算所以功率分配和速率分配就成了整个系统的关键参数。2.2 系统模型与关键参数一个典型的 RSMA 下行仿真包含这些要素一个基站K 个单天线用户基站配置 M 根天线。总功率 P 要在公共流和 K 个私有流之间分配。信道用瑞利衰落或者莱斯衰落建模接收端用 MMSE 检测。关键参数表如下参数含义典型取值影响K用户数2~10用户越多私有流干扰越复杂M基站天线数4~64影响波束成形增益P总发射功率归一化为 1功率分配的基础α_c公共流功率占比0.1~0.5太大浪费私有速率太小公共流解不出来R_c公共流目标速率由信道决定必须所有用户都能解码SNR信噪比范围0~30 dB扫描看性能曲线公共流功率占比 α_c 是最需要调的参数。我一般从 0.2 开始扫看总速率和公平性的变化。α_c 太小边缘用户解不出公共流整个拆分就失效α_c 太大私有流功率不够总速率上不去。2.3 最小可跑通的仿真骨架下面这段代码是我从code.zip这类仿真包里提炼出的最小骨架用 Python 写依赖 numpy。它不追求完整但能让你把速率拆分的流程跑通看到公共速率和私有速率怎么算出来。import numpy as np def rsm_rate_split(K4, M8, P1.0, alpha_c0.3, snr_db10, n_real1000): RSMA 下行速率拆分最小仿真 K: 用户数 M: 基站天线数 P: 总功率归一化 alpha_c: 公共流功率占比 snr_db: 信噪比(dB) n_real: 蒙特卡洛次数 snr_lin 10 ** (snr_db / 10.0) noise_var P / snr_lin # 噪声方差 sum_rate 0.0 fair_rate 0.0 for _ in range(n_real): # 瑞利衰落信道: M x K H (np.random.randn(M, K) 1j * np.random.randn(M, K)) / np.sqrt(2) # 公共流波束成形: 匹配所有用户的等效信道 # 这里用简单的共轭转置归一化作为公共波束 h_eff np.sum(H, axis1, keepdimsTrue) # M x 1 w_c h_eff / np.linalg.norm(h_eff) # 私有流波束成形: 每个用户用匹配滤波 W_p np.zeros((M, K), dtypecomplex) for k in range(K): hk H[:, k:k1] W_p[:, k:k1] hk / np.linalg.norm(hk) # 功率分配 P_c alpha_c * P P_p (1 - alpha_c) * P / K # 计算每个用户的公共流 SINR sinr_c np.zeros(K) for k in range(K): hk H[:, k] sig P_c * np.abs(hk.conj() w_c) ** 2 # 公共流解码时私有流全部视为干扰 interf 0.0 for j in range(K): interf P_p * np.abs(hk.conj() W_p[:, j]) ** 2 sinr_c[k] sig / (interf noise_var) # 公共流速率受最差用户限制 R_c np.log2(1 np.min(sinr_c)) # 私有流 SINR: 公共流已被消除 sinr_p np.zeros(K) for k in range(K): hk H[:, k] sig P_p * np.abs(hk.conj() W_p[:, k]) ** 2 interf 0.0 for j in range(K): if j ! k: interf P_p * np.abs(hk.conj() W_p[:, j]) ** 2 sinr_p[k] sig / (interf noise_var) R_p np.log2(1 sinr_p) # 每个用户总速率 公共速率 私有速率 user_rate R_c R_p sum_rate np.sum(user_rate) fair_rate np.sum(np.log2(user_rate 1e-9)) return sum_rate / n_real, fair_rate / n_real # 跑一组对比 for a in [0.1, 0.2, 0.3, 0.4, 0.5]: sr, fr rsm_rate_split(alpha_ca) print(falpha_c{a:.1f} sum_rate{sr:.3f} fair_rate{fr:.3f})这段代码的逻辑说明公共流波束用所有用户信道的和做匹配私有流用各自信道匹配。公共流解码时把所有私有流当干扰取最差用户的 SINR 算公共速率这是 RSMA 的标准约束——公共流必须让所有用户都能解。私有流解码时公共流已消除只剩其他私有流干扰。最后每个用户的总速率是公共速率加私有速率。参数说明alpha_c控制公共流功率占比snr_db控制噪声水平K和M决定空间自由度。跑出来你会看到alpha_c在 0.2~0.3 附近总速率和公平性比较平衡这就是速率拆分里最需要调的参数。提示这段代码用的是匹配滤波波束不是最优的 MMSE 或 SLNR 波束。要复现论文级性能波束成形部分需要换成 MMSE 或迭代优化但流程和参数含义是一样的。3. MMSE 接收机与功率分配仿真精度的分水岭3.1 为什么 MMSE 是 RSMA 仿真的标配上一章的骨架用的是匹配滤波简单但性能有上限。RSMA 仿真里真正拉开差距的是接收端检测和波束成形的联合设计。MMSE最小均方误差接收机在 RSMA 里的作用是把公共流和私有流的检测都做到干扰最小化。具体来说公共流解码时MMSE 接收向量要同时考虑私有流干扰和噪声私有流解码时公共流已经被减掉MMSE 只需要处理其他私有流。MMSE 的公式不复杂但实现时矩阵维度容易搞错这是第一个翻车点。MMSE 接收向量w (H H^H σ² I)^(-1) h_k其中h_k是目标用户的信道列向量。公共流解码时H包含所有用户的信道私有流解码时H只包含其他用户的私有流信道。3.2 用 MMSE 替换匹配滤波的代码改动把上一章的波束和接收部分换成 MMSE核心改动在接收端。下面这段代码展示 MMSE 接收机怎么算公共流和私有流的 SINR。def mmse_receiver(H, P_c, P_p, noise_var, K): MMSE 接收机计算 RSMA 各流 SINR H: M x K 信道矩阵 P_c: 公共流功率 P_p: 每个私有流功率 noise_var: 噪声方差 M H.shape[0] sinr_c np.zeros(K) sinr_p np.zeros(K) # 公共流 MMSE: 干扰为所有私有流 噪声 R_in_c noise_var * np.eye(M) for j in range(K): hj H[:, j:j1] R_in_c P_p * (hj hj.conj().T) for k in range(K): hk H[:, k:k1] # MMSE 权重 w_mmse np.linalg.solve(R_in_c, hk) w_mmse w_mmse / np.linalg.norm(w_mmse) sig P_c * np.abs(w_mmse.conj().T hk) ** 2 # 剩余干扰 interf 0.0 for j in range(K): hj H[:, j:j1] interf P_p * np.abs(w_mmse.conj().T hj) ** 2 # 减去目标信号自身的私有流贡献公共流解码时私有流全是干扰不扣 sinr_c[k] sig / (interf noise_var * np.linalg.norm(w_mmse) ** 2) # 私有流 MMSE: 公共流已消除干扰为其他私有流 for k in range(K): R_in_p noise_var * np.eye(M) for j in range(K): if j ! k: hj H[:, j:j1] R_in_p P_p * (hj hj.conj().T) hk H[:, k:k1] w_mmse np.linalg.solve(R_in_p, hk) w_mmse w_mmse / np.linalg.norm(w_mmse) sig P_p * np.abs(w_mmse.conj().T hk) ** 2 interf 0.0 for j in range(K): if j ! k: hj H[:, j:j1] interf P_p * np.abs(w_mmse.conj().T hj) ** 2 sinr_p[k] sig / (interf noise_var * np.linalg.norm(w_mmse) ** 2) return sinr_c, sinr_p逻辑说明公共流的干扰协方差矩阵R_in_c包含所有私有流和噪声私有流的R_in_p只包含其他私有流和噪声。MMSE 权重用np.linalg.solve解线性方程组比直接求逆数值更稳。归一化权重后算 SINR注意噪声项要乘权重范数的平方。参数说明P_c和P_p来自功率分配noise_var由 SNR 决定。MMSE 的性能优势在用户数多、干扰强的时候最明显用户数少的时候和匹配滤波差距不大。3.3 功率分配α_c 怎么扫才不白跑功率分配是 RSMA 仿真里最耗时间的环节。我一般分两步先粗扫alpha_c从 0.05 到 0.6步长 0.05看总速率曲线再在峰值附近细扫步长 0.01。每次扫描固定随机种子不然蒙特卡洛噪声会让你误判峰值位置。除了alpha_c公共流和私有流之间的功率还可以用注水算法做自适应分配但那个复杂度高仿真里一般先用固定比例扫出趋势再考虑自适应。如果你要对比 RSMA 和 NOMA、SDMA功率分配必须对齐总功率不然对比不公平。注意扫alpha_c时如果公共流速率R_c出现零或负值说明公共流功率太低边缘用户解不出来。这时候不要继续往下扫先把alpha_c下限提上去。4. 避坑与排查RSMA 仿真里最容易翻车的 5 个点4.1 公共流速率取最差用户导致总速率上不去现象仿真跑出来总速率比预期低很多检查私有流 SINR 正常但公共流速率R_c很小。原因公共流速率必须取所有用户中最小的 SINR 来算这是 RSMA 的硬约束。如果有一个用户信道很差R_c就被它拖死。解决两个方向。一是调整公共流波束让最差用户的等效信道增益提上来比如用最大化最小 SINR 的波束设计二是适当降低alpha_c把功率让给私有流牺牲一点公共速率换私有速率。我一般先看最差用户的 SINR 曲线确认是波束问题还是功率问题。4.2 MMSE 矩阵求逆出现奇异现象代码报LinAlgError: Singular matrix或者 SINR 出现inf或nan。原因干扰协方差矩阵R_in在用户数接近天线数时容易接近奇异或者噪声方差设得太小。解决用np.linalg.solve替代np.linalg.inv数值稳定性更好。如果还不行给对角线加一个小的正则项比如R_in 1e-8 * np.eye(M)。另外检查noise_var是不是设成了 0SNR 再高也要留一个非零噪声底。4.3 公共流消除顺序写反现象私有流 SINR 异常高总速率好得不真实。原因代码里先解私有流再解公共流或者私有流解码时没有把公共流从接收信号里减掉。解决RSMA 的固定顺序是先公共后私有。私有流解码前接收信号要减去公共流的估计值y_p y - sqrt(P_c) * h_k^H w_c * s_c。仿真里如果直接算 SINR 而不做减法私有流干扰就少算了一项结果虚高。4.4 信道生成没有固定随机种子现象每次跑出来的曲线不一样调参时无法判断是参数效果还是随机波动。原因蒙特卡洛仿真每次生成新的信道样本样本数不够时方差大。解决调参阶段固定np.random.seed(42)确认趋势后再放开种子跑多次取平均。蒙特卡洛次数至少 1000 次用户数多的时候要 5000 次以上。我一般先用 1000 次粗调最终结果用 10000 次。4.5 对比基准没有对齐总功率和带宽现象RSMA 比 NOMA 好很多但审稿人或同事质疑对比不公平。原因RSMA 的公共流和私有流总功率是 PNOMA 的功率也是 P但 NOMA 没有公共流开销如果 RSMA 的alpha_c设得小相当于私有流功率接近 P对比就偏了。解决对比时明确总功率约束RSMA 的P_c sum(P_p) PNOMA 的sum(P_noma) P。带宽和噪声功率谱密度也要一致。最好把对比代码放在同一个脚本里共用信道生成和噪声设置。5. 从仿真到结论怎么验证速率拆分的增益是真的5.1 用总速率-公平性曲线判断拆分是否值得跑完仿真最直观的验证是画两条曲线总速率随 SNR 的变化以及公平性指数随alpha_c的变化。RSMA 的增益通常体现在两个地方高 SNR 时总速率比 SDMA 高因为公共流消除了部分干扰用户信道差异大时公平性比 NOMA 好因为公共流保证了边缘用户的基本速率。我一般会跑三组对比RSMA、SDMA无速率拆分、NOMA。固定总功率和带宽扫 SNR 从 0 到 30 dB。如果 RSMA 在某个 SNR 区间没有优势先检查alpha_c是不是没调好再检查公共流波束是不是太简单。5.2 一个容易被忽略的验证技巧公共流速率上界公共流速率R_c有一个理论上界由所有用户中最差等效信道决定。仿真里可以单独把R_c打出来和理论上界对比。如果仿真值明显高于上界说明公共流 SINR 计算有误大概率是干扰项漏了或者消除顺序写反。这个检查花不了几分钟但能帮你快速定位大部分逻辑错误。我习惯在每次改完接收机代码后先跑这个检查确认R_c在合理范围内再跑完整仿真。5.3 参数扫描的收敛判断扫alpha_c时总速率曲线一般是一个单峰形状。如果曲线出现多个峰或者剧烈抖动说明蒙特卡洛次数不够或者信道生成有问题。我的经验是先用 500 次跑一遍看形状形状对了再加到 5000 次确认峰值位置。峰值位置在两次不同种子下偏差不超过 0.02就可以认为收敛了。最后说个我自己的习惯每次打开一个新的code.zip类仿真包我不会直接跑完整脚本而是先把信道生成、波束成形、SINR 计算、速率求和这四个模块拆开每个模块单独用一个小例子验证。速率拆分这种多步骤流程错一步后面全错拆开验证比调整个脚本快得多。希望帮到你。本文还有配套的精品资源点击获取