
做无人机辅助蜂窝卸载这个方向最难的不是把NOMA的公式背出来而是把整个系统在Matlab里跑通并且跑对。这个项目我前后改了三四版从最初只做OMA下的卸载仿真到后来把UAV、NOMA、部分卸载三件事揉在一起做性能分析和优化中间踩过的坑、试错的经验值得完整记录下来。这篇博文就围绕无人机辅助非正交多址蜂窝卸载这个仿真项目展开把系统模型怎么搭、Matlab代码怎么组织、优化迭代怎么做、仿真结果怎么解读讲透适合正在做无线通信方向毕业设计、论文复现或者准备投会议期刊的研究生参考。1. 项目整体设计与选题背后的逻辑1.1 为什么无人机、NOMA和蜂窝卸载要放在一起先理清三个概念各自解决什么问题。蜂窝卸载指的是终端设备把计算任务发送给边缘服务器或者基站处理以节省本地能量、降低任务处理时延。传统的地面蜂窝网络中基站位置固定、覆盖范围有限一旦用户处在小区边缘或者被建筑物遮挡卸载链路的信道质量就很差传输速率上不去任务传不出去卸载也就失去了意义。无人机辅助的核心价值在于它能把基站或者中继节点搬到空中通过机动性缩短与用户之间的通信距离构建一条更大概率是视距Line of SightLoS的传输链路。这样一来边缘用户的卸载速率显著提升系统吞吐量和任务处理效率都跟着改善。那NOMA为什么也要卷进来正交多址OMA方案下每个时频资源块同一时刻只能服务一个用户用户多了就得排队或者划分时隙频谱效率有限。非正交多址NOMA在功率域做叠加编码允许多个用户共享同一个资源块接收端用串行干扰消除SIC分离信号在用户过载场景下能明显提升频谱利用率和连接数。放到无人机蜂窝卸载的场景里NOMA可以让无人机同时为多个设备提供卸载服务一台无人机、一个信道、多个用户任务并行传输这对任务队列比较密集的场景非常友好。把三者叠加后项目要回答的核心问题就很清晰了在无人机辅助的蜂窝网络中如何通过NOMA提升多用户的卸载性能如何联合优化无人机位置、NOMA功率分配和卸载决策使系统时延或能耗最小化这个问题既有理论深度又有工程落地空间非常适合用Matlab做仿真验证。1.2 项目方案选型为什么用部分卸载而非二进制卸载卸载决策在边缘计算研究中分为两类二进制卸载和部分卸载。二进制卸载的模型比较简单粗暴一个任务要么全部留在本地执行要么整个卸载到边缘服务器不存在一半本地、一半卸载的状态。这种模型适合任务不可分割的场景比如一个包含固定依赖关系的完整应用模块。部分卸载则允许将任务按比特或按数据块拆分本地处理一部分、卸载处理一部分通过调整卸载比例来权衡本地计算时延与传输时延。这个项目选定的是部分卸载原因很实际整体优化的自由度更高。引入卸载比例因子后系统多了一个连续优化变量展示算法收敛曲线和性能随参数变化的规律时更直观审稿人或者导师看到的结果也更丰满。例如当本地CPU计算能力较弱但信道条件很好时卸载比例可以接近1如果信道质量差、任务数据量又大完全卸载会导致传输成为瓶颈此时适当保留一部分在本地算反而是最优策略。在我给的这套Matlab代码里卸载比例可以是固定值用于对照实验也可以参与联合优化用于展示算法增益。建议初学者先把固定比例跑通理解NOMA和无人机带来的影响再过渡到变量优化。1.3 性能指标怎么选时延与能耗的加权权衡通信系统研究里最常见的性能指标是吞吐量、频谱效率、时延、能耗、能效。对于蜂窝卸载这种面向任务处理的场景时延和能耗更贴近用户的真实体验所以我把系统的加权和代价函数定义为cost alpha * T_total (1 - alpha) * E_total其中T_total是所有用户卸载任务的总时延开销E_total是总能耗开销alpha是权重系数取值0到1。alpha 1表示纯时延优化alpha 0表示纯能耗优化。这个设计的好处是可以通过调节alpha画出Pareto前沿在文章里展示系统在不同需求偏好下的性能折中。具体的时延计算分为本地计算时延和卸载传输时延。本地计算时延 任务数据量 * 卸载剩余比例 / 设备CPU频率卸载传输时延 任务数据量 * 卸载比例 / 传输速率。传输速率由香农公式给出在NOMA场景下还要考虑SIC解码顺序带来的信干噪比差异。2. 系统模型构建与核心原理拆解2.1 网络场景一个无人机、多用户、单基站的卸载架构先把仿真场景固定下来。考虑一个单小区蜂窝网络地面基站位于坐标原点覆盖范围500米。小区内有K个单天线用户随机分布在基站覆盖区域内比如在半径300到500米的圆环区域内撒点模拟边缘用户的处境。一架无人机作为空中边缘节点悬停在某个高度H水平坐标可以移动。用户产生的任务有三种处理路径路径1本地直接计算路径2卸载给无人机处理无人机配备边缘计算服务器路径3先卸载给无人机无人机再做转发给地面基站处理这条路径在这个项目里作为可选扩展基础版本通常只用到前两条这样设置的原因是要模拟真实蜂窝网络中无人机补盲的场景。边缘用户直连地面基站的信道差但直连无人机的信道可能很好因为空地信道大概率是视距信道路径损耗更小、链路更稳定。Matlab里的参数初始化建议做成一个独立的脚本或者函数块统一管理例如% 系统基本参数 B 2e6; % 带宽 2MHz fc 2e9; % 载频 2GHz N0 -174 10*log10(B); % 噪声功率单位dBm P_bs 43; % 基站发射功率 dBm P_uav 30; % 无人机发射功率 dBm K 6; % 用户数量 H_uav 100; % 无人机悬停高度米 R_cov 500; % 小区覆盖半径米 data_size 500e3; % 任务数据量 500kbit C_local 1e9; % 本地CPU频率 1GHz C_edge 10e9; % 边缘服务器CPU频率 10GHz alpha_weight 0.5; % 时延-能耗权衡系数2.2 空地信道模型视距概率计算结果空地信道和地面信道的最大区别是要显式建模视距和非视距NLoS的混合状态。无人机虽然飞得高但不能假设链路100%是视距当无人机和用户之间的仰角较小或者建筑物遮挡严重时NLoS的路径损耗会明显增大。常用的概率模型把LoS概率表示为仰角的函数p_LoS(theta) 1 / (1 a * exp(-b * (theta - a)))其中a和b是由环境决定的常数比如密集城区a 9.61、b 0.28郊区a 4.88、b 0.43。theta是用户到无人机的仰角。路径损耗相应分为两类LoS链路PL_LoS 20log10(4pifcd/c) eta_LoSNLoS链路PL_NLoS 20log10(4pifcd/c) eta_NLoS其中eta_LoS和eta_NLoS是额外的环境衰减因子比如LoS链路取1 dBNLoS链路取20 dB。信道系数再叠加小尺度衰落一般建模为莱斯衰落视距分量占比由K因子控制。Matlab实现时要注意每次生成用户位置后都要先计算仰角再计算LoS概率然后随机判定该次仿真的链路状态。不能用简单的路径损耗公式一把梭否则仿出来的结果没有空地链路的特征。2.3 NOMA功率域叠加与SIC解码机制NOMA的核心是发送端叠加、接收端串行干扰消除。以两个用户为一组为例无人机或基站在同一个子信道上向用户u1和u2发送叠加信号x sqrt(P1) * x1 sqrt(P2) * x2其中P1 P2 P_total信道质量较差的用户分配更高的发射功率这是NOMA的基本分配原则因为SIC解码时先解信道好的用户把信道差的用户信号当作干扰。接收端u1在解码自己信号时会把u2的信号视作干扰此时SINR为SINR_1 P1 * |h1|^2 / (P2 * |h1|^2 sigma^2)如果用户1的信道增益大于用户2那么用户1先解出自己的信号再从接收信号中减去SIC后续用户2解码时已经没有了用户1的干扰SINR变成SINR_2 P2 * |h2|^2 / sigma^2这个机制在Matlab里实现时最关键的步骤是正确排序。我在第一次写代码时直接把所有用户按信道增益从大到小排列然后依次做SIC结果发现某些场景下出现在干扰项里的用户顺序反了导致SINR算错误码率完全对不上。后来改用函数封装排序逻辑并添加了断言确保每一层SIC都使用正确的信道增益顺序仿真才算稳定。2.4 任务卸载模型与总代价函数假设第k个用户的卸载比例为xita_k取值范围0到1。任务数据量为D_k则本地计算量 (1 - xita_k) * D_k卸载计算量 xita_k * D_k本地计算时延 (1 - xita_k) * D_k / C_local 卸载传输时延 xita_k * D_k / R_k其中R_k是用户到无人机的可达速率由信道带宽和SINR决定。边缘计算时延 xita_k * D_k / C_edge这部分和传输相比通常较小但严谨起见也加进去。总代价还是上面说的那套加权公式。Matlab实现时我建议把代价函数单独写成一个function后面无论是遍历搜索、梯度下降还是使用CVX求解都可以直接调用这个函数评估结果避免重复计算导致的不一致。3. Matlab仿真架构与代码模块实现3.1 顶层脚本与模块划分整个项目我采用主脚本 功能函数的结构主脚本负责参数初始化、蒙特卡洛循环和结果绘图功能函数包括信道生成、NOMA传输、代价计算、优化求解。%% 主脚本UAV_NOMA_Offloading_Main.m clear; close all; clc; % 载入参数 initParams; % 蒙特卡洛循环 numIter 100; resTotal zeros(numIter, 1); for iter 1:numIter % 生成用户位置 posUser generateUsers(K, R_cov); % 生成信道 channelInfo generateChannel(posUser, posUAV, params); % NOMA功率分配 [pPower, order] nomaPowerAllocation(channelInfo, P_uav); % 卸载优化 [xitaOpt, costOpt] optimizeOffloading(channelInfo, pPower, sysPar); resTotal(iter) costOpt; end % 平均结果 avgCost mean(resTotal); fprintf(平均代价%.4f\n, avgCost);3.2 信道生成模块的完整实现信道生成是UAV仿真里最容易出bug的地方我把我的实现贴出来重点讲解function chanInfo generateChannel(posUser, posUAV, par) % 输入 % posUser: Kx2 用户平面坐标 % posUAV: 1x2 无人机平面坐标 % par: 参数结构体 % 输出 % chanInfo.h: Kx1 信道系数复数 % chanInfo.pl: Kx1 路径损耗dB % chanInfo.losFlag: Kx1 链路状态 K size(posUser, 1); chanInfo.h zeros(K, 1); chanInfo.pl zeros(K, 1); chanInfo.losFlag zeros(K, 1); for k 1:K dist2D norm(posUser(k, :) - posUAV); dist3D sqrt(dist2D^2 par.H_uav^2); theta atan2(par.H_uav, dist2D) * 180 / pi; % LoS概率市区模型 pLoS 1 / (1 par.a_env * exp(-par.b_env * (theta - par.a_env))); isLoS rand pLoS; if isLoS pl 20*log10(4*pi*par.fc*dist3D/par.c) par.eta_LoS; chanInfo.losFlag(k) 1; else pl 20*log10(4*pi*par.fc*dist3D/par.c) par.eta_NLoS; chanInfo.losFlag(k) 0; end % 叠加小尺度衰落莱斯衰落视距分量K因子 Kfactor 10; if isLoS % 莱斯信道直射分量散射分量 direct sqrt(Kfactor/(Kfactor1)) * exp(1i*2*pi*rand); scatter sqrt(1/(Kfactor1)) * (randn 1i*randn)/sqrt(2); smallFade direct scatter; else % Rayleigh衰落 smallFade (randn 1i*randn)/sqrt(2); end chanInfo.h(k) smallFade * sqrt(10^(-pl/10)); chanInfo.pl(k) pl; end end注意几个要点。第一theta计算必须用atan2而不是atan因为用户和无人机的相对位置在四个象限都可能出现atan2能正确返回[-180, 180]区间的角度。第二LoS概率是随机性的判断所以每轮蒙特卡洛仿真的链路状态都不同这就需要在报告中说明统计次数一般至少1000次以上才能看到稳定的平均性能。第三莱斯衰落里的K因子直接影响信道质量这个参数在代码里应该由环境决定而不是随便写死建议把它和LoS/NLoS状态绑定。3.3 NOMA功率分配模块从固定分配到注水算法功率分配模块决定了NOMA叠加信号的功率分布。最简单也最常用的是分数阶功率分配FTPAfunction [pPower] nomaPowerAllocation(h, P_total, alpha_f) % 分数阶功率分配 % alpha_f典型值0.2~0.6越大越偏向信道差的用户 hAbs abs(h); [~, idx] sort(hAbs, descend); % 信道好的用户排前面 % 按信道增益从大到小功率从小到大逆序分配 K length(h); pPower zeros(K, 1); denom sum((1 ./ hAbs(idx)).^alpha_f); for k 1:K pPower(idx(k)) P_total * (1/hAbs(idx(k)))^alpha_f / denom; end end上面这个实现信道最差的用户会分到最大功率符合NOMA功率分配原则。这里alpha_f是一个可调参数当alpha_f 0时退化为等功率分配当alpha_f增大时功率向信道差的用户倾斜相当于提升了SIC解码过程中最弱链路的可靠性但代价是信道好的用户受到更强干扰。3.4 卸载比例优化一维搜索与二分法在给定信道和功率分配的条件下卸载比例的优化是一个一维问题因为每个用户的卸载代价函数在其定义域内往往是凸的。对于单个用户代价函数可以写为f(x) alpha * max(T_local(x), T_offload(x)) (1-alpha) * E(x)这个max函数会带来非光滑性所以实际问题里工程上更常用的是遍历搜索法因为用户数量不大时计算量完全可以接受。例如把卸载比例从0到1按0.01的步长离散化对每个用户分别寻找最优比例100个采样点乘以K个用户耗时不过几十毫秒。如果追求严谨可以在每个区间内用fminbnd做精细搜索% 单用户卸载优化 fun (x) costFunction(x, hk, Pk, par); xitaOpt fminbnd(fun, 0, 1);fminbnd用的是黄金分割法适合单变量有界优化不需要导数信息。实践下来收敛很快而且能处理非光滑目标函数。3.5 蒙特卡洛仿真与结果存储整个仿真框架我最推荐的方式是外层跑蒙特卡洛内层做单次随机场景的优化最后把所有样本的平均性能存下来。原因在于UAV信道有随机性LoS状态、小尺度衰落都是随机的单次仿真的结果波动很大不取平均就得出最优方案比OMA方案好50%的结论是没有统计学意义的。我在实际项目中每次随机撒点用户位置跑完一轮优化之后会额外把OMA方案在相同信道条件下的代价也算出来作为对照组。这样做的好处是两次对比使用完全相同的信道随机种子排除了信道随机性对对比结果的干扰。Matlab里可以通过rng(iter)控制随机种子确保公平对比。4. 性能分析与联合优化4.1 无人机位置优化从穷举网格到连续优化无人机的位置对空地信道质量影响极大。这个项目的第一个优化维度就是无人机水平坐标。最直接、最稳妥的方法是二维网格搜索。把目标区域划分成10米间隔的网格在每个候选位置计算系统总代价选择代价最小的点作为无人机最优位置。这种方法简单、可复现、不需要推导梯度在目标函数非凸、不光滑的情况下非常实用。缺点是复杂度和网格分辨率相关。后期如果想要展示更高级的优化能力可以换成连续优化。比如固定用户位置和功率分配后用户到无人机的距离是无人机坐标的凸函数但代价函数涉及对数整体不是全局凸的。此时常用的做法是连续凸逼近SCA把非凸项在每轮迭代中替换成其下界然后求解凸子问题。SCA的实现相对复杂但对审稿人和导师而言更有说服力。我在代码里默认提供网格搜索版本但接口设计成可替换的优化器形式后续想升级成SCA或者粒子群算法只需修改optimizeUavPosition函数的内部实现。4.2 功率分配优化与用户调度的联合设计NOMA场景里哪些用户配上对和每对用户怎么分功率是耦合的。很多论文把用户配对当组合问题处理先按信道增益排序再相邻配对这样可以减少NOMA组内用户信道差异过大的情况。如果信道差异太大SIC解码时弱用户的信号会干扰强用户强用户即使功率小也可能解码失败。如果信道差异太小NOMA的增益不明显和OMA相比没有优势。所以配对策略一般遵循信道好的配信道差的但差距不能拉得过大。功率分配这块除了FTPA还可以用迭代注水算法。在NOMA组内优化各用户的功率使组吞吐量最大化是一个典型的凸问题可以用CVX求解cvx_begin variable p(K, 1) maximize(sum(log(1 p .* hVec ./ noiseInter))); subject to sum(p) P_total; p 0; cvx_end当然CVX需要额外安装而且在做蒙特卡洛大循环时速度会明显变慢。我建议在基础仿真阶段先用FTPA到了做对比实验阶段再用CVX求解作为性能上界。4.3 NOMA与OMA的对比实验结果解读仿真结果对比是整篇论文的核心支撑。从项目复现的典型结果来看有以下几个规律值得注意。在用户数较多且任务密集的场景下NOMA比OMA的卸载时延能降低20%到40%。增益来源在于NOMA允许两个用户同时共享同一个子信道单位时间内能传输更多任务比特排队时延显著下降。而在用户数少、信道质量都很好的场景下NOMA和OMA的性能差距缩小有时甚至接近这说明NOMA的收益和过载程度正相关。无人机悬停高度对性能的影响是双面的。高度增加覆盖范围扩大但路径损耗增大高度过低LoS概率下降信道波动加剧。仿真结果显示存在一个最优高度通常在80到120米之间具体取决于环境参数和小区半径。这个结论在论文里可以作为参数敏感性分析的一部分。4.4 算法收敛性与运行时间对比联合优化如果采用交替迭代策略例如固定无人机位置优化功率分配、固定功率分配优化无人机位置循环迭代直到收敛那么需要记录每一轮迭代的代价函数值绘制收敛曲线。正常情况下代价函数应该单调不增迭代次数大约在10到20轮之间因为无人机位置的网格搜索和功率分配的凸优化都已经各自收敛交替迭代不会出现明显振荡。如果发现收敛曲线有振荡大概率是某个子问题求解没到位或者离散化网格太粗导致无人机位置在相邻网格间来回跳解决方法是加密网格或改用连续优化。5. 常见问题与排查技巧实录5.1 信道生成模块最容易忽略的细节很多复现论文的代码信道模型只写了一个大尺度路径损耗公式没有区分LoS和NLoS导致无人机高度对性能的影响完全反映不出来。正确的做法是必须把LoS概率公式、两类路径损耗参数、小尺度衰落类型三者一起建模。另外概率型LoS模型每次仿真都会随机判断链路状态这导致如果只跑几十次仿真结果方差极大。我建议所有对比实验至少跑500到1000次蒙特卡洛并且在代码里记录每条链路的LoS比例如果统计出来的LoS概率和理论值偏离超过5%说明随机数生成或者角度计算有问题。5.2 SIC解码顺序引发的看似正常其实错误NOMA仿真的错误很大一部分出在SIC上。常见错误是直接把用户按信道增益排序后功率分配也按同一顺序解出来的SINR却是反的。另一个常见问题是用户分组内有一个用户信道特别差导致SIC第一层的解码失败率很高这时应在功率分配上给强用户更小的功率、给弱用户更大的功率否则系统整体性能反而比OMA更差。我在仿真里加了一个自检机制计算完SINR之后检查每个用户的可达速率是否为正如果出现负数则直接终止程序并输出告警。这个简单操作帮助我抓出了好几处排序错误。5.3 蒙特卡洛仿真的随机种子管理随机种子管理在项目初期容易被忽略但在对比实验阶段是保命技能。如果每次仿真的用户位置、信道状态都不一样OMA和NOMA的对比结果受随机噪声影响看不出真实性能差距。正确做法是设置全局随机种子比如rng(2024)或者在外层循环里每轮固定种子再分别调用不同算法。5.4 CVX安装与求解精度问题如果做凸优化部分CVX是绕不开的工具。安装时注意版本兼容性在Windows上建议使用Matlab R2020b以上的版本否则容易出现内部求解器无法初始化的问题。CVX默认使用SDPT3求解器在处理大规模问题时速度偏慢可以换成SeDuMi或Mosek。实际仿真中如果变量规模不大SDPT3足够如果用户数超过20个建议直接上Mosek否则一轮蒙特卡洛要跑好几分钟。5.5 仿真程序运行速度的优化心得Matlab跑通信仿真天然比C慢但通过几个技巧可以显著提速。一是避免在for循环中使用动态数组所有矩阵预先分配二是把蒙特卡洛循环中不依赖随机种子的部分提到循环外三是使用parfor做并行蒙特卡洛前提是每次迭代之间要独立。我实测过在8核CPU上用parfor替换for1000次蒙特卡洛仿真的耗时从约12分钟降到约3分钟。6. 代码工程化与后续扩展方向6.1 目录结构与脚本命名规范代码量上来之后工程的目录结构就很重要。我建议按以下目录组织UAV_NOMA_Offloading/ ├── main/ % 主脚本入口 ├── functions/ % 核心功能函数 ├── optimization/ % 优化算法 ├── plot/ % 绘图脚本 ├── results/ % 结果数据存储 └── README.md % 使用说明6.2 可扩展方向多无人机协同与动态轨迹这个项目做完了基础版本之后扩展空间很大。比如把单无人机扩展成多无人机协同多个无人机组成空中边缘计算网络这时需要引入无人机间的任务调度和干扰管理模型复杂度上一个大台阶但也更容易出创新点。再比如把悬停无人机扩展成动态轨迹无人机沿着优化出的轨迹飞行在移动中完成卸载服务这在实际巡检和应急场景中很有意义但仿真量也会成倍增加。6.3 从仿真到论文的衔接要点最后分享一点关于出成果的经验。仿真做完只是第一步要形成一篇像样的论文建议把结果整理成三类图表一是系统架构和流程图二是性能对比曲线NOMA vs OMA、有无无人机三是参数敏感性分析表格。这三类内容分别对应了文章的问题阐述、核心贡献和工程指导意义缺一不可。Matlab代码本身不是成果代码背后的分析和结论才是。