十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多小区下行NOMA最优功率分配:从系统模型到MATLAB仿真实现

多小区下行NOMA最优功率分配:从系统模型到MATLAB仿真实现 简介面向多小区下行非正交多址系统的功率分配研究这份代码以参数化方式实现了最优功率分配算法的完整流程适合通信、电子信息、数学等专业的学生用于课程设计、期末大作业或毕业设计。压缩包共十六个文件以十四个脚本为核心涵盖信道生成、串行干扰消除解码条件检验、功率分配计算、传输速率求解等关键模块并附有说明文档整体大小仅十五千字节结构紧凑、易于阅读。目前已有五十人学习下载。代码采用参数化编程可方便修改小区数量、用户数量、基站发射功率上限等参数并通过执行脚本绘制收敛曲线、用户数与系统速率关系图等直观理解多小区场景下的干扰管理与资源分配机理。注释明细编程思路清晰支持在多个常用版本中直接运行适合快速复现算法结果或作为课程项目和毕业设计的基础代码继续扩展。1. 多小区下行NOMA的最优功率分配难点不在NOMA本身多小区下行NOMA非正交多址的功率分配问题本质上是一个“同一资源块上叠加多个用户再通过SIC串行干扰消除区分信号”的功率分割问题。单小区场景下SIC解码顺序和功率分配顺序完全一致约束条件清晰很多论文里用凸优化工具一两页就解完了。但一旦进入多小区场景情况会立刻复杂起来相邻小区的同频干扰叠加在NOMA的簇内干扰之上用户的SIC解码条件不再只取决于本小区的功率分配还受邻区干扰强度影响。此时“最优功率分配”要同时回答三个问题给谁分多少功率、SIC按什么顺序解、邻区干扰在什么水平下仍然可行。这篇文章面向的是正在做NOMA仿真、需要产出可复现MATLAB代码的通信方向研究生和工程师。你会看到从系统模型建立到优化问题求解再到仿真结果验证的完整路径。我不会贴一个“一键出图”的脚本忽悠你——最优功率分配这东西理解模型和约束比拿到代码本身更重要。有了模型MATLAB代码只是把数学写进矩阵运算而已。2. 多小区下行NOMA的系统模型与优化问题构建2.1 多小区NOMA的干扰结构簇内干扰与簇间干扰叠加单小区NOMA的基础模型里一个子信道上叠加两个或更多用户。基站发射叠加信号近用户信道条件好先解码远用户信道条件弱的信号再从接收信号中减去SIC最后解自己的信号。这里隐含着两个前提功率越大越容易解码所以功率分配要与信道增益相反SIC的复杂度与簇内用户数成正比所以工程上簇内用户数通常不超过3个。多小区场景下问题变成了多个基站同时复用同一组子信道。每个用户除了收到自己基站的叠加信号还会收到相邻基站发来的信号。这个“邻区干扰”不参与SIC——用户没用邻小区的功率分配信息也解不掉邻区信号。于是用户的信干噪比SINR表达式变成了用户m在第k个子信道上的SINR (本小区分配给用户m的功率 × 本小区信道增益) / (邻区干扰 本小区簇内SIC后残余干扰 噪声)这个分母里的“邻区干扰”是所有相邻小区在同一个子信道上的发射功率乘上各自的信道增益之和。这意味着某一个小区的功率分配决策会影响邻区用户的SINR和SIC可行性。多小区NOMA的功率分配从数学上变成了一个变量耦合的优化问题每个小区的功率向量不仅约束自己还约束别人。2.2 优化问题标准化目标函数、约束集与变量维度最常用的优化目标是“最大化系统加权吞吐量”。加权的意义在于控制用户间的公平性如果不加权系统为了追求总吞吐量会把大量功率分配给信道条件好的近用户边缘用户可能连最低速率都保证不了。加权之后优化器会在“总速率”和“用户公平”之间取折中。标准的数学形式是最大化 ∑_{i∈小区} ∑_{m∈用户} w_m · log2(1 SINR_i,m)约束条件有三个维度每个基站的总发射功率约束即本小区所有子信道上叠加的功率之和不超过P_max每个子信道上NOMA簇内的功率分配非负约束SIC解码可行性约束簇内每个用户的SINR必须满足其解码顺序要求用MATLAB表示这个优化问题常规做法是把所有变量展平成一个长向量。假设3个小区、每个小区2个用户、2个子信道功率变量就是3×2×212维。约束矩阵的行数取决于约束条件数。这个规模用CVXMATLAB的凸优化工具箱可以直接求解但如果把小区数扩到7个、用户数扩到21个、子信道扩到10个变量维度就会涨到1470此时直接调CVX的求解器会变得很慢后面第4章会讨论这个实际问题。2.3 MATLAB系统参数表仿真前先定下这些值仿真代码写得好不好一半取决于参数设定是否贴近真实场景。下面是我常用的初始参数表你可以直接复制到MATLAB脚本里。参数取值说明小区数3或73小区适合验证算法正确性7小区更接近蜂窝真实拓扑小区半径500m对应宏基站覆盖范围子信道数4 ~ 10子信道多则计算量线性增长每簇用户数2NOMA簇内2用户是工程主流SIC复杂度可控路径损耗指数3.5城市宏小区典型值对数正态阴影标准差8dB用于生成用户的位置随机性噪声功率-174dBm/Hz × 带宽底噪带宽取180kHz或1MHz视场景而定P_max46dBm对应40W典型宏基站发射功率用户公平权重w1/R̄比例公平PF权重R̄是用户历史平均速率提示首次仿真建议把小区数设成3这样功率变量的维度低能最快跑通整个链路。等代码框架验证无误再调到7小区。3. MATLAB仿真框架搭建从信道生成到NOMA收发链路3.1 多小区信道矩阵生成路径损耗、阴影衰落与快衰落的组合在写任何优化算法之前先把信道生成这步做扎实。NOMA功率分配算法的输入是信道增益矩阵这个矩阵如果生成得不对后面的优化结果全是空中楼阁。常见做法是分段生成先根据用户和基站的距离计算路径损耗dB值再加上对数正态阴影衰落最后乘上小尺度快衰落瑞利或莱斯。MATLAB代码示意如下% 系统基础参数建议以脚本顶部参数表为准 numCells 3; % 小区数 numUsersPerCell 2; % 每小区用户数每簇用户数 numSubchannels 4; % 子信道数 cellRadius 500; % 小区半径单位米 pathLossExp 3.5; % 路径损耗指数 shadowStd 8; % 阴影衰落标准差单位dB % 位置生成每个小区内随机撒用户这里简化为极坐标生成 theta 2 * pi * rand(numCells, numUsersPerCell); r cellRadius * sqrt(rand(numCells, numUsersPerCell)); % 均匀分布修正 bsPos cellRadius * 2 * [cos(0) sin(0); cos(2*pi/3) sin(2*pi/3); cos(4*pi/3) sin(4*pi/3)]; userPos zeros(numCells, numUsersPerCell, 2); for i 1:numCells for m 1:numUsersPerCell userPos(i, m, :) [r(i,m)*cos(theta(i,m)), r(i,m)*sin(theta(i,m))]; end end % 计算信道增益矩阵维度 [小区i, 用户m, 服务小区s] % 注意索引含义用户(i,m)到基站s的信道 H zeros(numCells, numUsersPerCell, numCells); for i 1:numCells for m 1:numUsersPerCell for s 1:numCells d sqrt(sum((userPos(i,m,:) - bsPos(s,:)).^2)); pl - pathLossExp * 10 * log10(max(d, 10)); % 路径损耗单位dB shadow shadowStd * randn; % 阴影衰落 smallScale (randn() 1j*randn()) / sqrt(2); % 瑞利衰落 h_dB pl shadow; H(i, m, s) (10^(h_dB/10)) * abs(smallScale)^2; % 线性域功率增益 end end end这段代码的核心逻辑是三层嵌套循环最外层遍历每个用户中间层遍历用户序号最内层遍历所有基站。信道增益的方向性体现在最后一个维度上——H(i,m,s)表示第i个小区的第m个用户到第s个小区的信道增益。功率分配算法会大量使用这个三维矩阵比如“用户(i,m)在本小区子信道k上收到的有用信号”和“用户(i,m)在邻区子信道k上受到的干扰”都从这同一个矩阵里取值。注意这里用max(d, 10)是为了避免距离过小时路径损耗变成正增益属于工程保护。真实系统里基站和用户之间总有一段最小距离10米的保护值足够模拟。3.2 NOMA发射端与SIC接收端的MATLAB实现有了信道增益下一步是搭NOMA发射与接收链路。注意这里说的“链路”不是时域波形级的物理层仿真而是信噪比级的系统级仿真以SINR为传递量。发射端要做的操作是在同一个子信道上把两个用户的信号叠加分配不同功率。接收端用户侧则要按SIC顺序处理。代码示意如下% 发射端功率分配向量P(i,k,m)表示小区i在子信道k上分配给用户m的功率 % P的总约束sum(P(i,k,:)) Pmax/size(k) —— 这里简化为每个子信道独立约束 % 以3小区2用户4子信道为例 P zeros(numCells, numSubchannels, numUsersPerCell); % 初始化均分功率后续被优化器替换 P_avg (10^(46/10)) / (numSubchannels * numUsersPerCell); % 46dBm转瓦特后均分 P(:,:,:) P_avg / 1000; % 转成瓦特级别SIC接收端的MATLAB实现核心是解码顺序的判断。NOMA的固定规则信道增益强的用户解码顺序靠后先解完弱用户才能解自己的信号。代码里用一个排序函数搞定% 对一个子信道内的用户按信道增益降序排序决定SIC顺序 % H_order(i,k)是2维向量存储该子信道上的用户配对 users_sorted sort(H(i, :, i), descend); % 用户按信道增益排序 userNames find(H(i, :, i) users_sorted(1) | H(i, :, i) users_sorted(2)); % 弱用户user1在基站侧配更大功率强用户user2配较小功率 % 仿真时直接按排序索引下标对应功率向量接收端SINR的计算要区分两类用户SIC解码顺序在自身之前的用户信号视为可消除干扰顺序在后的则视为不可消除干扰所有邻区信号都视为不可消除干扰。这个区分逻辑如果写错了仿真结果会与理论不一致——典型表现是功率分配算法给出的最优解在蒙特卡洛验证时达不到理论速率。4. 最优功率分配的求解穷搜、凸优化与迭代算法的工程取舍4.1 穷搜法为什么只配做小规模验证如果你在论文里看到“遍历所有功率组合”这种描述大概率是验证用的小规模场景。穷搜法的原理简单到不用解释把每个功率变量离散成若干档位遍历全部组合选取目标函数最大的那一组。问题出在复杂度假设每个功率变量离散成L个档位变量维度是D穷搜次数是L的D次方。前面提到3小区2用户4子信道的场景功率变量维度已经是24——就算L1010的24次方在MATLAB里跑几亿年也跑不完。所以在MATLAB里穷搜法一般只用于验证一个极简场景单小区、2用户、单子信道。这时候功率变量只有2维穷搜落在(0, Pmax)的网格上可以和解析解或CVX结果对比证明优化器正确。代码如下% 极简场景校验单小区2用户单子信道穷搜网格验证 Pmax 1; % 归一化功率 gridSize 10000; p1grid linspace(0, Pmax, gridSize); p2grid linspace(0, Pmax, gridSize); rateBest 0; pBest [0 0]; for idx 1:gridSize p1 p1grid(idx); p2 Pmax - p1; % 两个用户共享总功率 if p1 0 || p2 0, continue; end % 计算两个用户的SINR和速率假设固定信道h1,h2 sinr1 p1 * h1 / (p2 * h2 noise); % 弱用户直接解码 sinr2 p2 * h2 / noise; % 强用户SIC后解码 rateSum log2(1 sinr1) log2(1 sinr2); if rateSum rateBest rateBest rateSum; pBest [p1 p2]; end end变量p1从0遍历到Pmaxp2由总功率约束推出总功率Pmax p1p2。注意SINR表达式的写法弱用户直接解自己的信号p1的信号就是目标信号强用户解码时需要先减去弱用户信号再解自己的理想SIC下残余干扰为零。这段代码的价值是验证不同信道条件下功率分配是否遵循“信道增益弱则功率大”的直觉。4.2 凸优化CVX求解把问题交给求解器对于多小区多用户的一般场景工程上最常见的做法是用CVX工具箱把问题写成凸优化形式再由求解器默认SDPT3或SeDuMi迭代求解。重写前面的优化问题成CVX代码如下% 假设H_sub是当前子信道的信道增益矩阵H_sub(i, u) 小区i中用户u的服务信道增益 % 这里以单子信道多小区为例每小区两个用户配对 cvx_begin quiet variable P(numCells, 2) % P(i,1)弱用户功率P(i,2)强用户功率 expression rate(numCells, 2) for i 1:numCells % 弱用户SINR分母含邻区全部干扰 本小区强用户功率 interf_weak noise; interf_strong noise; for j 1:numCells if j ~ i interf_weak interf_weak P(j,1)*H_interf(i,j,1) P(j,2)*H_interf(i,j,2); interf_strong interf_strong P(j,1)*H_interf(i,j,1) P(j,2)*H_interf(i,j,2); end end % 本小区簇内干扰 interf_weak interf_weak P(i,2)*H(i,2); % 强用户信号对弱用户的干扰 % 强用户SIC后只剩邻区干扰 rate(i,1) log(1 P(i,1)*H(i,1) / interf_weak); rate(i,2) log(1 P(i,2)*H(i,2) / interf_strong); end maximize(sum(sum(rate))) subject to sum(P, 2) Pmax_cell; % 每个基站总功率约束 P 0; cvx_end这里要注意几个工程细节。第一速率表达式里用的是log而不是log2因为CVX自带的log函数能保证凹性log2乘以常数log(2)即可转换对优化结果没有影响。第二邻区干扰的计算直接用了P(j,:)*H_interf的线性乘积——SINR表达式中干扰是功率的线性函数速率是log(1SINR)但x/y形式的表达式在CVX中不是凹的所以需要写成log(yx) - log(y)的形式才能保证凸性% 将 rate(i,1) 改为 CVX 兼容形式 % log(P(i,1)*H(i,1) interf_weak) - log(interf_weak)这是一个很容易踩的坑直接写log(1 P*H/interf)会报错提示表达式非凸DCP规则违反。CVX要求所有表达式符合DCP规则分式形式的SINR必须做变换。改法如上所示用对数的减法代替除法再取对数。4.3 非凸场景下的迭代功率分配固定SIC顺序的反向注水法CVX适合问题本身是凸的情形。麻烦的是多小区NOMA的联合功率分配与SIC顺序优化往往是非凸的——因为SIC顺序本身是离散变量离散变量的引入让问题变成混合整数规划。实际做工程时一个常见处理方案是“固定SIC顺序交替优化功率与解码顺序迭代至收敛”。MATLAB代码框架如下P_prev initP; % 初始功率分配均分 for iter 1:20 % 最大迭代次数 % 第一步根据当前P_prev计算所有用户的SINR % 第二步更新SIC解码顺序按SINR从强到弱排队强用户后解码 % 第三步固定SIC顺序用CVX求解最优功率分配 % 第四步若功率变化量小于阈值则跳出否则继续 diff norm(P_new - P_prev); if diff 1e-4, break; end P_prev P_new; end这种迭代算法的收敛性在文献中有多次讨论实际表现通常是前3~5次迭代功率变化显著后面进入微调。因为SIC顺序的更新天然地朝“弱用户少被干扰”的方向调整每次固定顺序后的凸优化又给出该顺序下的最优功率目标函数单调非降所以迭代过程能保证收敛到局部最优。5. 参数设置与结果验证频谱效率、公平性与收敛性检查5.1 三个必调的仿真参数仿真代码跑通后你要关注的不是某一组功率分配结果而是参数变化下系统性能的趋势是否与理论预期一致。以下三个参数是我在做NOMA仿真时必调的用户位置分布。用户离基站越近信道增益越高SIC顺序越靠后。把用户全部撒在小区边缘NOMA的功率分配会趋向于“把所有功率给边缘弱用户”——因为强用户的信道好不需要太多功率也能解码。反之用户全部靠近基站最优功率分配会趋向于均分NOMA的增益完全消失。这两种极端情况的对比能直观看出NOMA的适用边界。邻区干扰强度。可以通过调整小区间距离或阴影衰落标准差来控制。邻区干扰增强时弱用户的SINR下降需要分配的功率增加强用户可获得的功率减少系统总吞吐量会下降。如果你设计的算法在强干扰下仍然能保证弱用户的最低速率就说明算法有实用性。用户公平性权重w。权重越大优化器越偏向该用户。将w设为1/R̄时就是比例公平边缘用户速率会显著上升总速率会有所牺牲。这个参数的调节直接体现在仿真图的曲线间隔上。5.2 代码计算结果的具体判断方法功率分配结果的正确性验证业内标准做法是画两条曲线一条是系统总速率随P_max变化的曲线另一条是用户间公平性指数随权重变化的曲线。公平性指数常用Jain公平性指数J (∑R_m)^2 / (K · ∑R_m^2)J的值在0到1之间越接近1表示用户间越公平。一个典型结果是NOMA系统在Jain指数上高于正交多址OMA系统尤其当用户信道差异大时。如果你的仿真结果是NOMA的公平性比OMA还差多半是SIC解码顺序或者功率分配约束写错了。另外需要检查的是SINR是否为正、CVX求解器是否成功收敛。CVX输出状态如果显示“Failed”或“Numerical problems”优先检查功率单位——dBm转瓦特时是否统一邻区干扰的量级是否远大于噪声导致数值差过大。6. 收敛加速与大规模场景的实用技巧6.1 变量缩放与初始点选择让CVX不再报错CVX在高维度场景下遇到的第一个问题是数值不稳定表现为约束矩阵条件数过大导致求解慢或不收敛。解决方法是把功率变量统一缩放到同一个量级。做法如下% 功率以瓦特为单位时数值可能出现1e-3到1e-6的极小量 % 将所有功率除以P_max转化为标幺值0到1之间 P_norm P / P_max_cell; % 求解完后乘以P_max恢复实际功率 P_actual P_norm * P_max_cell;标幺化之后变量范围统一到[0,1]约束矩阵条件数大幅下降CVX的求解时间通常能缩减一半以上。这个方法同样适用于自己写迭代算法时的数值稳定性控制。初始点选择上不要从零点或随机值开始用上一轮次的功率解作为下一轮初始值热启动方式可以显著减少迭代次数。对应到代码里的操作是把上一帧的信道增益矩阵和功率解缓存下来在当前帧信道变化不剧烈时直接作为CVX的x0参数传入。6.2 大规模多小区场景矩阵化替代循环7小区21用户10子信道的场景如果沿用三层嵌套循环生成信道和功率MATLAB运行一次可能要几十秒做蒙特卡洛仿真会等到怀疑人生。优化方向是向量化用矩阵运算替代for循环。以信道生成为例% 向量化生成3个小区×7用户×7基站的距离矩阵 % 核心是避免逐元素循环直接矩阵广播计算 % 具体实现取决于MATLAB版本R2020b及以上推荐使用隐式扩展语法 % dist vecnorm(userPos - reshape(bsPos, 1, 1, numCells, 2), 2, 4);大规模场景的另一做法是使用并行计算工具箱的parfor把蒙特卡洛次数分配到多个worker核心parfor mc 1:numMonteCarlo % 每次迭代独立生成信道、执行功率优化、记录结果 [rate_sum(mc), fairness(mc)] simulateOneDrop(params); end注意使用parfor时循环体内不能有互相依赖的变量写入。把每次迭代的结果存入预分配数组最后合并即可。6.3 仿真结果回归测试改动一个参数后必须验证的现象日常迭代中最怕的是改了一个参数代码跑通了但结果悄悄变错你却以为是对的。我的习惯是做三个快速回归测试固定用户位置比较CVX求解结果与穷搜结果在极简场景下是否一致。逐个关闭邻区干扰把邻区信道增益设为零系统总速率应逼近单小区NOMA的上限值——偏离超过3%就说明SIC逻辑有误。把NOMA的簇内用户数从2改成1系统退化为OMA功率分配应该退化为传统注水算法。如果这一步不一致说明功率分配的约束条件在退化成OMA时不成立。这三个测试是花费时间最少但收获最大的操作。它们能一次性验证信道生成、SIC解码逻辑、CVX建模三个环节的正确性比对着公式检查一遍代码更可靠。对于跑完蒙特卡洛后的数据处理最后再提一句输出结果时保留每轮的信道快照和功率解用MATLAB的save命令存成.mat文件。这样后续分析某个异常数据点时可以直接回到当时的信道和功率现场而不是被迫从几十轮平均结果里反推原因。这才是MATLAB仿真最舒服的工作路径——先让程序输出足够多的现场信息再谈优化和加速。本文还有配套的精品资源点击获取
返回列表