简介:面向5G非正交多址(NOMA)研究的MATLAB用户配对资源包,适合通信工程学生与科研人员理解功率域NOMA原理并验证强弱用户配对算法。压缩包共15个文件,大小27.11MB,含7个m脚本、5个PDF文献和3张示意图。仿真代码覆盖2用户、4用户、8用户、12用户等多种组网规模,包含信道状态信息生成、用户强弱分类、贪婪配对、功率分配与SIC串行干扰消除等完整流程,脚本采用模块化设计,便于调整用户数、信道条件与功率因子;文献部分收录了用户配对公平性、NOMA教程及综述类论文,可辅助研究脉络梳理。3张示意图直观展示配对方案结构与NOMA/OMA对比,方便直接用于汇报或论文插图。已有236人学习下载,适合希望从零搭建NOMA仿真平台、快速复现不同配对策略效果并开展对比实验的研究者。
1. 5G 网络里 NOMA 的用户配对,为什么第一步是 MATLAB 仿真
5G 网络里决定 NOMA 增益的往往不是功率分配,而是用户配对——把哪两个用户放进同一个资源块,直接决定了串行干扰消除(SIC)能不能做干净,也决定了系统总速率和用户公平性能不能兼顾。做这个方向的人,十个里有八个是在 MATLAB 里先跑通配对仿真,再去谈调度、谈功率优化。用 MATLAB 搭 NOMA 用户配对,会连续遇到三个坎:功率域的信道建模、SIC 之后的容量计算、配对方案的搜索。很多初学代码跑出来曲线异常,问题几乎都出在这三处。这篇文章按我平时自己搭仿真的顺序,把每一个坎的参数、代码和判断依据都写清楚,适合正在写课程设计、准备论文复现或者刚接手 5G 物理层仿真任务的工程师。
2. 用户配对为什么成对出现:NOMA 的功率域机制与 SIC 顺序
2.1 功率域叠加:基站侧在做什么
NOMA 与 OMA 的本质区别在于:OMA 把时频资源切给不同用户,NOMA 让多个用户共享同一份资源,用功率维度来区分用户。基站侧的操作是把两个用户的信号直接叠加发射:
x = sqrt(α_w·P)·s_w + sqrt(α_s·P)·s_s
其中 α_w + α_s = 1,s_w 是弱用户(远端、信道增益低)的符号,s_s 是强用户(近端、信道增益高)的符号。注意功率分配的原则:弱用户拿大功率,强用户拿小功率。原因在于弱用户的信道衰减大,发射功率即便给得多,到达接收端的信号强度依然有限;强用户信道好,给小功率一样能正确解调。
很多初学代码把「强用户分大功率」当作默认条件,导致两个信号的功率差完全颠倒,SIC 的解码顺序跟着全乱,画出来的容量曲线一路向下。这个错误在公式层面几乎看不出来,因为公式本身是自洽的,只有在多个用户配对对比时才会暴露。所以我在写仿真时,会先把用户按信道增益排序,再进入配对逻辑,排序这一步写在函数内部而不是依赖外部传入顺序,这样能避免上层代码不小心把强弱用户传反。
2.2 SIC 接收流程与两条速率公式
接收端侧的解码顺序与功率分配是反向对应的。强用户先解码弱用户的信号——因为弱用户信号功率大,更容易被正确解出来——然后从叠加信号中减掉它,再解码自己的信号。弱用户不解任何其他用户的信号,直接把自己的信号解出来,把强用户的信号当作噪声处理。
写成速率公式:
- 强用户速率:R_s = log2(1 + α_s·P·|h_s|² / N₀)
- 弱用户速率:R_w = log2(1 + α_w·P·|h_w|² / (α_s·P·|h_w|² + N₀))
注意强用户的信干噪比分母里只有噪声 N₀,因为 SIC 已经把弱用户信号消除掉了;弱用户的分母里还留着强用户信号的功率项。这个差异是 NOMA 容量计算的核心,也是代码里最容易写反的地方。
| 用户类型 | 功率分配 | 解码方式 | 信干噪比分母 |
|---|---|---|---|
| 强用户(信道增益高) | 小功率 α_s·P | 先解弱用户信号并消除,再解自身 | 仅噪声 N₀ |
| 弱用户(信道增益低) | 大功率 α_w·P | 直接解自身信号 | 强用户干扰 α_s·P· |
从公式也能看出另一个关键点:α 不是越大越好。弱用户拿到的功率占比增加,自身速率会上升,但强用户速率会下降,二者是一个权衡关系。仿真里常用 α 取 0.7~0.9 来代表弱用户获得主要功率。
2.3 配对增益的来源:信道差异
NOMA 的增益来自配对用户之间的信道差异。当两个用户的信道增益比接近 1,即强弱差异不明显时,NOMA 叠加后强用户能消除的干扰有限,弱用户被强用户信号干扰的部分却不小,整体增益趋近于零;当信道增益差异拉大,强用户能更干净地解出弱用户信号,弱用户也受益于大功率分配,系统总速率才有明显提升。
这引出一个反直觉的配对结论:配对应该拉大差异,而不是把信道质量相近的用户分到一起。同一小区里,把近端用户和远端用户配成一对,比把两个近端用户配在一起效果更好。这也是后续排序首尾配对算法的理论依据。实际工程里还要考虑公平性,比如不能让某个远端用户每次都和不同的近端用户配对而承受不稳定的干扰,这时通常引入比例公平因子做加权,这部分可以从仿真之后再扩展。
提示:NOMA 配对仿真里每个资源块上配 2 个用户是绝对主流。3 个以上用户的配对在文献里存在,但 SIC 解码级数随用户数线性增加,速率公式里要逐级减去前序用户信号,数值稳定性和仿真复杂度都大幅上升,MATLAB 里跑蒙特卡洛会明显变慢。
3. 用 MATLAB 搭 5G 网络信道与 NOMA 配对容量计算:最小可运行版本
3.1 参数表与信道生成代码
先建立 5G 场景下的仿真参数。下面这套参数以低频子载波为基础,每个资源块内的配对用单个子载波代表,蒙特卡洛循环跑 1000 次信道实现:
% noma_pairing_sim.m % 5G 低频段单子载波场景,NOMA 用户配对仿真参数 K = 8; % 用户总数(配对要求为偶数) Ptx_dBm = 46; % 基站单子载波发射功率(dBm) NF_dB = 7; % UE 噪声系数(dB) B = 15e3; % 5G NR 单子载波带宽 15 kHz noise_dBm = -174 + NF_dB + 10*log10(B); Ptx_W = 10^((Ptx_dBm - 30)/10); noise_W = 10^((noise_dBm - 30)/10); % 用户距离(km),对应城区宏站覆盖范围 d_km = [0.10, 0.50, 1.50, 0.30, 0.90, 2.00, 0.70, 1.80]; % 路径损耗:城区宏站模型,单位 dB PL_dB = 128.1 + 37.6*log10(d_km); % 蒙特卡洛信道实现:瑞利衰落 + 路径损耗 L = 1000; h = zeros(L, K); rng(42); % 固定随机种子,保证结果可复现 for l = 1:L for k = 1:K smallScale = (randn + 1i*randn)/sqrt(2); % 瑞利衰落,功率归一 h(l,k) = smallScale * sqrt(10^(-PL_dB(k)/10)); end end这套代码里两个细节值得说明。第一,10^((Ptx_dBm-30)/10)是把 dBm 换算成瓦特,30 是 dBm 与 dBW 的偏移量;噪声功率则先用 -174 dBm/Hz 加上噪声系数和带宽增益得到 dBm 值,再转瓦特。第二,瑞利衰落项(randn + 1i*randn)/sqrt(2)保证实部虚部各占一半功率,合成后 E[|h_small|²]=1,最终的 |h(l,k)|² 就只反映路径损耗的数量级,方便后续对比信道增益。
3.2 NOMA 用户配对容量函数与 alpha 参数
信道建好后,下一步实现配对容量计算。这段函数是整个仿真的核心,SIC 顺序、功率分配、log2 都在这里体现:
function [R, R_s, R_w] = nomaPairCapacity(h1, h2, Ptx_W, noise_W, alpha) % nomaPairCapacity - 计算 NOMA 用户对的容量 % % 输入: % h1, h2 - 两个用户的信道系数(复数,已含路径损耗与衰落) % Ptx_W - 基站单子载波发射功率(瓦特) % noise_W - 子载波噪声功率(瓦特) % alpha - 弱用户功率占比,范围 [0.5, 1) % 输出: % R - 该用户对的总速率(bit/s/Hz) % R_s, R_w - 强用户与弱用户的各自速率 g1 = abs(h1)^2; g2 = abs(h2)^2; % 按信道增益判断强弱,避免上层传参顺序错误 if g1 >= g2 g_s = g1; g_w = g2; else g_s = g2; g_w = g1; end % 强用户拿到 (1-alpha) 比例功率;SIC 已消除弱用户干扰 R_s = log2(1 + (1-alpha)*Ptx_W*g_s / noise_W); % 弱用户拿到 alpha 比例功率;强用户信号视为干扰 R_w = log2(1 + alpha*Ptx_W*g_w / ((1-alpha)*Ptx_W*g_w + noise_W)); R = R_s + R_w; end函数内部先比较两个信道增益的模平方,确定谁是强用户谁是弱用户,再按 SIC 顺序计算速率。这里强用户的分母里只有noise_W,弱用户的分母里保留(1-alpha)*Ptx_W*g_w作为强用户干扰——这两个公式的顺序直接决定仿真曲线是否正确。alpha 的取值一般放在 0.6 到 0.9 之间,小于 0.5 意味着给强用户更多功率,不符合 NOMA 的功率分配逻辑。
调用方式很简单:外层循环里取两个用户的信道系数,加上功率参数和 alpha,一次返回该配对的总速率。这个函数的输入输出都是标量,方便后续在不同配对策略间复用,也方便把单次结果累加做蒙特卡洛平均。
3.3 配对函数里最容易写反的 3 个判断
写 NOMA 配对容量函数,有一个高频错误模式:SIC 顺序和功率分配搭配反了。下面是三个我在看别人代码时最先检查的位置。
- 强弱用户的判定用
abs(h)^2而不是abs(h)。前者是功率增益,后者是幅度增益,两者大小关系一致,但公式里功率项直接对应abs(h)^2,用错会导致和公式对不上。 - 强用户一定对应小功率系数
(1-alpha)。如果代码里强用户用了 alpha,弱用户用了(1-alpha),那么弱用户解调时面临的干扰反而比自己信号还强,SIC 根本不可能正常工作。 - 速率公式的底数是 2,MATLAB 里必须写
log2(...)而不是log(...)。log默认是自然对数,误用会让所有速率数值偏大约 1.44 倍,趋势正确但绝对数值不对,论文里一旦对比文献数据就会暴露。
注意:这三处问题不会导致 MATLAB 报错,只会让结果悄无声息地出错。建议写完函数之后,先用一组手工计算的简单信道系数做单元测试,确认输出和手算一致,再进入蒙特卡洛循环。
4. 用户配对算法的 MATLAB 实现:从随机配对到穷举搜索
4.1 固定配对(信道增益排序 + 首尾配对)的实现
有了容量函数,配对策略就是外层的事。最常用的启发式方法是:把用户按信道增益从小到大排序,然后第一个和最后一个配对,第二个和倒数第二个配对,依此类推。这种配对的依据是 2.3 节说的「拉大信道差异」原则。
% 固定配对:按信道增益排序后首尾配对 g_user = mean(abs(h).^2, 1); % 每个用户在蒙特卡洛中的平均信道增益 [~, idx_sorted] = sort(g_user); % 增益从小到大排序 pairs_fixed = zeros(K/2, 2); for p = 1:K/2 pairs_fixed(p, 1) = idx_sorted(p); pairs_fixed(p, 2) = idx_sorted(K - p + 1); end排序后,idx_sorted(1)是信道最差的用户,idx_sorted(K)是信道最好的用户,二者配成一对。这种首尾配对在 K=8 时产生 4 个用户对,每个用户对内部信道差异尽量大,NOMA 叠加后的 SIC 收益也最大。随机配对则简单得多:randperm(K)打乱顺序后两两分组即可,但随机配对的性能方差很大,一组信道实现下可能很好,下一组可能很差,因此更适合做 baseline 而不是实际方案。
4.2 穷举所有配对方案的递归实现
固定配对效果不错,但它是启发式的,不保证全局最优。想要知道最优结果,需要枚举所有配对方案。配对方案数服从双阶乘:K=8 时有 105 种,K=10 时是 945 种,K=12 时涨到 10395 种。增长是超指数级的,K=16 就达到 200 万量级,所以穷举只适合小规模验证。
function pairs_all = enumeratePairings(user_list) % enumeratePairings - 递归枚举用户列表的所有两两配对方案 % 输入: user_list - 用户索引向量,如 [1 2 3 4] % 输出: pairs_all - 元胞数组,每个元胞是 (K/2)x2 的配对矩阵 n = numel(user_list); if isempty(user_list) pairs_all = {zeros(0, 2)}; return; end first = user_list(1); rest = user_list(2:end); pairs_all = {}; for i = 1:numel(rest) partner = rest(i); remain = rest; remain(i) = []; % 移除已配对的用户 sub = enumeratePairings(remain); % 递归枚举剩余用户 for j = 1:numel(sub) this_pair = [first, partner]; pairs_all{end+1, 1} = [this_pair; sub{j}]; end end end递归逻辑的关键是固定第一个用户,让它依次与剩余每个用户配对,然后递归处理剩下的用户。这样枚举出来的方案不会重复。调用时传入1:K,返回的每个元胞都是一套完整的配对方案。配对方案再配合上一章的nomaPairCapacity,在蒙特卡洛循环里逐对累加总速率,最后比较所有方案选出最优:
best_rate = -inf; best_pairs = []; pairs_all = enumeratePairings(1:K); for t = 1:numel(pairs_all) pairs = pairs_all{t}; rate_sum = 0; for p = 1:size(pairs, 1) u1 = pairs(p, 1); u2 = pairs(p, 2); rate_sum = rate_sum + nomaPairCapacity(... h(l, u1), h(l, u2), Ptx_W, noise_W, 0.8); end if rate_sum > best_rate best_rate = rate_sum; best_pairs = pairs; end end这段代码里,外层循环在 105 种配对方案之间做全搜索,内层循环对每种方案的 4 个用户对分别计算容量后求和。如果 K 增大到 16,这个双循环会非常吃力,需要把配对方案预先存成矩阵、用向量化替代元胞数组。
4.3 三种策略怎么选:复杂度与公平性权衡
| 配对策略 | K=8 时的方案数 | 单次选择的计算量 | 公平性 | 适用场景 |
|---|---|---|---|---|
| 随机配对 | 1(随机取一种) | 极低 | 不稳定,某些配对会让弱用户速率极低 | 作为性能 baseline |
| 排序首尾配对 | 1(确定性方案) | 只需排序 | 较好,弱用户总能分到大功率 | 工程常用、论文对比主方案 |
| 穷举搜索 | 105 | 遍历全部方案 | 最优但不一定公平 | K≤12 时的性能上界参考 |
实践里我一般这样安排:先用排序首尾配对跑通完整蒙特卡洛仿真,确认曲线形态合理;再用穷举配对在 K=8 时对比一次,看启发式方案离最优差多少。通常信道差异越大,排序首尾配对离穷举越近;如果小区用户分布集中,信道差异小,启发式方案的优势就不明显,这时更需要关注的是功率分配 alpha 而不是配对策略本身。
5. 验证你的 NOMA 配对仿真:3 个检查点与蒙特卡洛收敛
5.1 检查点 1:用 OMA 做基准对比
NOMA 配对仿真最容易出现的假象是「跑出来了,但不知道对不对」。最可靠的验证方法是用 OMA 做基准:让每个用户独占总功率,不叠加、无 SIC,容量就是 R_oma = log2(1 + P·|h|² / N₀)。把同一组信道下所有用户的 OMA 速率求和,再与 NOMA 配对总速率对比,NOMA 至少不该明显低于 OMA。这个检查在代码里只需要一行替代逻辑,把nomaPairCapacity换掉就行。
5.2 检查点 2:蒙特卡洛收敛判断
蒙特卡洛的迭代次数不是拍脑袋定的。做法是把 L 从 100 依次增加到 5000,每次记录平均总速率,观察均值随 L 的变化是否进入平稳区间。信道实现数太少时,均值抖动可达 10% 以上,这种情况下比较不同配对策略没有任何意义。我的经验是:K=8、1000 次瑞利信道实现通常能稳定到小数点后两位,但这取决于路径损耗的方差——用户距离跨度越大,需要的迭代越多。
5.3 检查点 3:alpha 的极端取值测试
把 alpha 设为 0.5,NOMA 退化为两个用户等功率分配,此时 SIC 仍可工作,但强用户的干扰消除压力最大;把 alpha 设为 0.99,弱用户拿到几乎全部功率,强用户速率趋近于零。分别跑一次仿真,如果两种极端值下总速率变化方向不对,说明nomaPairCapacity里的功率分配或 SIC 顺序还有问题。这三步检查全部通过后,再放心扩大参数扫描范围,比如改变 alpha 的步长、更换路径损耗模型,或引入用户移动性。
本文还有配套的精品资源,点击获取