这几年做空对地通信仿真,我和团队接触最多的一个组合就是:无人机当空中基站,地面终端散落在楼宇、山体、树冠之间,非视距遮挡严重,固定基站要么够不着,要么容量不够。常规做法是让无人机沿着预设航点巡航,但用户一挪、场景一变,航线就基本作废,需要重新手动规划。后来我们把问题拆成两层来解决:物理层用NOMA(非正交多址接入)把同一个频谱资源切给多用户,提升系统容量;控制层用去中心化Q-Learning让每架无人机根据自身局部观测独立学习路径策略。整套思路最后在Matlab里落了地,今天这篇就是完整的项目拆解,包括系统建模、算法设计、仿真代码框架和调参踩坑记录。适合正在做无人机通信、NOMA资源调度、强化学习路径规划的硕博生和工程开发人员参考。1. 项目背景与问题拆解:双无人机为什么要和NOMA、Q-Learning绑在一起1.1 场景痛点与设计动机先还原一下原始问题。某个园区做应急通信演练,地面基站断电,需要临时恢复覆盖。现场有十几个终端,分布在几栋建筑之间,有一部分终端处在严重遮挡区域,地面基站临时架设难度大、周期长。这时候无人机作为空中接入点的价值就体现出来了:它飞得高,视距链路概率大,部署快,而且可以通过优化航迹主动逼近用户。但真正落地时发现三层问题。第一层是频谱资源紧张。一片区域内用户一多,频带就分不过来。如果每用户独占一个时频资源块,容量天花板很低。第二层是路径规划。双无人机各自服务一组用户,但用户分布不均匀,有的区域用户密集、有的区域稀疏,无人机如果飞得不对,距离一远信道质量就断崖式下跌。第三层是控制架构。最直观的想法是地面中心统一管控,收集所有状态、下发所有动作,但实际场景链路易断、时延不可控,一旦中心失效全盘瘫痪。NOMA解决第一层问题。它允许同一个资源块通过功率域或码域区分用户,接收端用串行干扰消除(SIC)把混叠信号拆开,频谱效率直接翻倍。Q-Learning解决第二和第三层问题。每个无人机被建模成独立智能体,根据自己的位置、用户分布和信道观测决定下一步往哪飞、用多大功率,不依赖统一中心。1.2 技术选型逻辑:NOMA解决什么,去中心化强化学习解决什么先说NOMA。传统正交多址(OMA)给每个用户分配正交资源,缺点是资源利用率上限低。NOMA的思路很直接:在发送端用不同功率叠加多个用户的信号,在接收端按信号强度排序依次解码。功率分配是核心——强用户(信道条件好的)分配较小功率,弱用户(信道条件差的)分配较大功率,这样弱用户可以直接把强用户信号当噪声解出自己的信号,强用户则通过SIC先解出并消掉弱用户信号再解自己的。放在双无人机场景里,两架无人机可以选择同一时频资源、分别服务一对“近强远弱”的用户,通过功率域NOMA叠加,在一个资源块上同时传两路数据。系统吞吐量、边缘用户速率、频谱效率三项指标都能得到改善。再说Q-Learning。很多人会问:路径规划用A*、人工势场、凸优化不是更成熟?这些方法的问题在于,当环境是动态的、用户分布不可预知、目标是长期累计吞吐量而非单步最短路径时,无模型的强化学习更有优势。Q-Learning不需要信道模型精确已知,只需要定义好状态、动作、奖励,然后通过试错迭代学出一个策略表。而且它天然适合做成去中心化——每个智能体维护自己的Q表,自己探索、自己利用,单机决策复杂度低,符合无人机集群没有地面中心节点或链路经常中断的约束条件。这里需要说清楚,去中心化不等于完全孤立。它指的是不依赖全局状态和中央调度器,但无人机之间仍然可以通过机间链路交换少量必要信息,比如避免飞入同一区域、避免信号互干扰。在设计Q表的奖励函数时,可以把碰撞惩罚和干扰惩罚嵌进去,实现“局部决策、全局协调”的效果。2. 系统模型与数学基础:信道、NOMA配对、无人机运动模型2.1 三维空对地信道模型仿真里信道模型不能随便拿一个自由空间损耗公式糊弄过去。空地信道和地面信道最大的区别在于仰角会显著影响视距概率。建筑、树木、地形遮挡会随仰角变化,典型工程做法是采用概率视距模型,把路径损耗写成视距分量和非视距分量的加权平均。上行和下行场景不同,但我这里只说下行传输。无人机到地面用户的路径损耗表达式为:L = 20log10(4πf d / c) + P_LOS * η_LOS + P_NLOS * η_NLOS其中d是三维距离:d = sqrt((x_u - x_g)^2 + (y_u - y_g)^2 + h^2)。h是无人机飞行高度,f是载波频率,c是光速。η_LOS和η_NLOS是额外损耗因子,视距条件下取小一些,非视距条件下取大一些。P_LOS和P_NLOS是视距和非视距概率,随仰角提升,P_LOS单调上升。还有一个细节是信道增益h_ch = 10^(-L/10)。后续算SINR时,直接就归一化到1毫瓦参考功率上。2.2 功率域NOMA的SINR建模假设一个时隙内,无人机A以功率P1服务弱用户,无人机B以功率P2服务强用户,两个信号在同一个子载波上叠加发射。弱用户信道增益记为g_weak,强用户信道增益记为g_strong,噪声功率N0。弱用户直接被服务,解码时把强用户信号视为干扰:SINR_weak = P1 * g_weak / (P2 * g_strong + N0)强用户采取SIC,先解弱用户信号并从混合信号中消除,再解自己的信号:SINR_strong = P2 * g_strong / N0从公式能看出来几个关键点。第一,弱用户的干扰项里含P2 * g_strong,如果两架无人机把功率都加到最大,弱用户反而容易被干扰吞掉。第二,SIC的前提是强用户能正确解出弱用户信号,这要求弱用户功率足够强,否则SIC会失效。第三,两架无人机各自服务不同用户,但它们共享同一个频段,所以彼此之间的功率分配变成了一个联合优化问题,这也是后面奖励函数要重点考虑的部分。配套还要考虑用户到哪个无人机的配对。实际工程中先在每个时隙根据信道增益做配对:信道好的用户和信道差的用户配成一组,再决定哪架无人机给哪个用户发。仿真时我用的原则是每架无人机只服务离自己最近的几个用户,两个无人机选取的配对用户保证不重复。2.3 无人机运动与能耗模型无人机运行高度固定时可以简化成二维平面运动。我仿真时把高度设为100米,速度上限12m/s,每个时隙长度1秒,也就是无人机每步最多移动12米。动作空间包含8个方向移动一步、原地悬停、以及3个功率档位。能耗模型是算奖励时绕不开的。悬停、水平飞行、加速都有不同功耗。简化但不失一般性的做法是:飞行状态时功率功耗取常值P_hover加上与速度平方成正比的增量,移动越远耗能越高。剩余能量作为一个状态分量进入Q表,让无人机学会在电量低时减少不必要的绕飞,优先飞到高价值用户区域。这里提一个容易踩的坑:如果能量消耗只作为惩罚项放进奖励,而不进入状态,无人机永远学不会“想着电量做规划”。因为Q-learning本身是马尔可夫决策过程,如果状态里没有剩余能量,这个决策问题就不是马尔可夫的,策略会受历史影响而抖动。所以剩余能量等级必须放进状态,哪怕只离散成3到5档。3. 去中心化Q-Learning算法设计:状态、动作、奖励与决策流程3.1 为什么必须去中心化中心化方案看起来更“标准”:一个地面控制中心收集所有无人机的位置、能量、用户信道状态,求解全局最优路径,逐时隙下发动作。但真实场景里有一个致命问题——控制链路开销。无人机数量一多,控制中心需要处理的联合状态空间会随无人机数量指数增长,而且每次决策还要等链路往返,时延高、可靠性差。更重要的是,控制中心一旦被干扰或链路断裂,所有无人机都会变成“无头苍蝇”。去中心化的本质是“每个智能体只根据局部观测做决策”。双无人机场景里,每架无人机知道自己相对用户的位置、自己的剩余能量、自己当前对目标用户信道的估计,以及另一个无人机的大致方位。它不需要知道另一位智能体完整的Q表,也不需要中央节点做仲裁。我这样类比:中心化像剧场导演指挥每个演员走位,导演一离开,演出就乱套;去中心化像即兴表演,每个演员只遵循基本规则、根据对手动作即兴反应。性能可能略低于全局最优,但鲁棒性完全不在一个量级。3.2 状态与动作空间设计Q表的大小取决于状态离散化。状态空间如果直接放原始坐标,比如1000米乘1000米区域、5米一格,那就是4万个状态乘8个动作,两个无人机各搞一张6位数的Q表,训练量直接爆炸。我的处理方法是用相对信息做状态压缩,而不是用绝对坐标。具体来说:把无人机周围360度分成8个扇区,每个扇区统计服务用户的个数。最近用户的距离等级,分成近(<200米)、中(200到500米)、远(>500米)3档。剩余能量等级,分成高、中、低3档。另一架无人机的相对方位,分成同扇区或不同扇区2种状态。这样单机状态数量大约是8个扇区用户数的组合数(实际按每个扇区0/1/2个用户量化),乘以3乘以3乘以2,可以控制在几千量级,这是表格型Q-Learning可以处理的范围。动作空间更简洁:8个移动方向 + 原地悬停 + 3档发射功率,一共11个动作。这里把位置决策和功率决策放在同一个动作里,是因为功率和位置对信道增益的影响是耦合的:远距离悬停配大功率,效果可能不如贴近用户配小功率。分两步决策会增加状态设计复杂度,合在一起虽然动作空间变大,但Q表规模还在可控范围。如果觉得动作数过多,可以先跑简化版本:9个动作(8方向+悬停)、功率固定。路径收敛后再放开功率维度。3.3 奖励函数设计与参数权衡奖励函数是整个算法设计里最影响收敛效果的部分。我最终用的是这样一个综合奖励:r = w1 * ΔR_sum + w2 * R_min - w3 * E_step - C_collision - C_boundary其中ΔR_sum是本时隙相对上一时隙系统总吞吐量的增量,R_min是当前时隙两用户中最小的可达速率,E_step是本步移动消耗的能量,C_collision是两架无人机距离过近时的惩罚,C_boundary是飞出预定区域的惩罚。为什么要用吞吐量增量而不是绝对吞吐量?因为Q-Learning的Q值是通过累加折扣奖励来拟合长期回报的。如果奖励里带一个很大的常数基准项,Q值会变得很大且变化不敏感,训练曲线看起来像是“已经收敛”,实际策略没有发生任何优化。用增量奖励可以让Q值对策略变化更敏感。R_min那一项是保证公平性的。如果只优化总吞吐量,无人机很快会发现“喂饱离得近的强用户”是最高效策略,边缘弱用户直接被放弃,这既不符合通信公平性原则,也浪费了NOMA弱用户链路的价值。折中方案是给最小速率乘以权重w2,倒逼无人机在飞行过程中兼顾弱势用户。再说惩罚项。C_collision我设置的是两架无人机欧氏距离小于安全距离50米时给-5,这个数值不能太小,否则无人机倾向于贴着飞,信号互相干扰严重;但也不能太大,否则两架无人机过度回避、各自往区域两边跑,导致覆盖产生空洞。C_boundary设成-3,因为仿真区域外围通常存在未知地形或禁飞区,步进过程中一旦越界就回退并惩罚。3.4 训练流程与超参选择具体训练流程按标准Q-Learning走:每个episode开始时,随机撒用户位置,无人机从固定起点起飞。每个时刻根据当前状态,用epsilon-greedy策略选动作。执行动作后计算奖励、得到下一状态、更新Q表。当无人机电量耗尽或到达最大步数时结束episode,重置场景,继续下一轮。超参数我建议这样设置:学习率alpha初始0.1,每500个episode乘以0.9衰减,最低不低于0.01;折扣因子gamma取0.9到0.95之间,gamma越大越看重长期收益,但收敛越慢;epsilon初始0.9,随着训练推进衰减到0.05,让智能体前期多探索、后期多利用。每个episode最大步数设为200,保证训练不会无休止跑下去。还有一个容易被忽略的点:状态初始化要覆盖多样场景。如果把用户位置撒点限制在一个小区内部,学出来的策略只适用于那种均匀分布,很脆弱。我在随机撒用户时会让位置分布混合模式,一部分均匀分布、一部分集中成簇,这样无人机学到的是更泛化的规则,而不是对某一种分布的过拟合。4. Matlab仿真框架实现:从信道函数到Q学习主循环4.1 工程目录与模块划分Matlab工程我按功能拆成几个脚本,别全都塞进一个主文件里,否则调试起来寸步难行。常见的目录结构如下:drone_noma_qlearning/ main_run.m config_params.m init_scenario.m compute_channel.m compute_noma_rate.m compute_reward.m select_action.m update_qtable.m plot_results.mmain_run.m是入口,负责加载参数、初始化环境、执行训练循环、保存结果。config_params.m集中存放所有超参数和系统参数,每次跑新实验只用改这一个文件。compute_channel.m算空地信道增益,compute_noma_rate.m算两个用户的SINR和可达速率,compute_reward.m按公式计算奖励,select_action.m实现epsilon-greedy选择,update_qtable.m做Q表更新。4.2 核心函数实现与讲解先看信道函数。这一块要注意输入输出向量化,避免后面循环里反复算重复量时性能拉胯。function [g_los, g_nlos, pl_prob] = compute_channel(pos_drone, pos_user, fc, h_drone, env) c = 3e8; d_3d = sqrt((pos_drone(1)-pos_user(1))^2 + ... (pos_drone(2)-pos_user(2))^2 + h_drone^2); theta = asin(h_drone / d_3d) * 180 / pi; A = env.A; % 环境相关常量,密集城区取较大值 B = env.B; p_los = 1 / (1 + A * exp(-B * (theta - A))); p_nlos = 1 - p_los; pl_free = 20*log10(4*pi*fc*d_3d/c); pl_los = pl_free + env.eta_los; pl_nlos = pl_free + env.eta_nlos; g_los = 10^(-pl_los / 10); g_nlos = 10^(-pl_nlos / 10); pl_prob = p_los; end注意我返回的是视距和非视距两套信道增益,主循环里按概率p_los抽样决定实际使用哪一套。有的简化仿真直接用了期望信道增益g = p_losg_los + p_nlosg_nlos,这样做训练更平稳,但丢失了信道随机性,学出来的策略可能对瞬时衰落过于乐观。我推荐至少保留概率抽样版本,这样策略天然带有鲁棒性。NOMA速率计算是所有调参工作的核心。下面这个函数输入是两架无人机功率、信道增益、噪声功率,输出是强用户和弱用户各自的可达速率:function [rate_strong, rate_weak, sinr_strong, sinr_weak] = compute_noma_rate(p_strong, p_weak, g_strong, g_weak, bw, p_noise) sinr_weak = p_weak * g_weak / (p_strong * g_strong + p_noise); sinr_strong = p_strong * g_strong / p_noise; rate_weak = bw * log2(1 + sinr_weak); rate_strong = bw * log2(1 + sinr_strong); end这里有一个分量容易出错:p_strong和p_weak指的是无人机发射功率,还是信号在接收端的功率?仿真里如果信道增益g已经包含路径损耗,那么接收功率就是p * g,所以SINR公式里直接用发射功率乘以信道增益没问题。但要注意单位的统一,我用的是毫瓦级别,噪声功率N0用接收机热噪声功率折算过来,常见值约-104dBm,转换为毫瓦是10^(-104/10)。4.3 主仿真循环与训练过程主循环伪代码级别如下:for episode = 1 : max_episodes scenario = init_scenario(); state1 = get_state(drone1, scenario); state2 = get_state(drone2, scenario); for step = 1 : max_steps action1 = select_action(Q1, state1, epsilon); action2 = select_action(Q2, state2, epsilon); [next_state1, next_state2, reward, done] = env_step(scenario, action1, action2); Q1(state1, action1) = Q1(state1, action1) + ... alpha * (reward1 + gamma * max(Q1(next_state1, :)) - Q1(state1, action1)); Q2(state2, action2) = Q2(state2, action2) + ... alpha * (reward2 + gamma * max(Q2(next_state2, :)) - Q2(state2, action2)); state1 = next_state1; state2 = next_state2; if done, break; end end epsilon = max(epsilon * epsilon_decay, 0.05); alpha = max(alpha * alpha_decay, 0.01); end两个细节值得特别说明。一个是reward1和reward2怎么分。双无人机共享系统总奖励,但各自更新自己的Q表时用的是同一个总奖励值。如果各用各的局部速率,两架无人机会各顾各的,最后互相干扰反而总吞吐量下降。所以这里我让reward1 = reward2 = 总奖励值,共享全局奖励是去中心化前提下最简单也最有效的协同协作方式。另一个是环境函数env_step里的碰撞处理。两架无人机如果同一时隙移动到同一点附近,动作需要回退到上一位置。回退动作会导致Q表里出现一条“这个状态向那个方向走会撞车”的经验,这正是我们希望智能体学到的。但回退本身也会改变用户距离,导致奖励跳变,所以碰撞惩罚不能只加在一个时隙,建议让碰撞后的3个时隙持续减分,这样无人机才不会反复往碰撞区域试探。完整Matlab源码的拼装逻辑就是:config_params定义参数,init_scenario生成用户分布和初始状态,env_step调用compute_channel和compute_noma_rate计算通信速率,再调用compute_reward计算奖励,主循环里反复执行select_action和update_qtable,最后调用plot_results出图。代码量不大,整个工程也就400到500行。5. 仿真参数配置与结果分析5.1 关键参数配置表这是我调试下来比较稳定的一组参数,直接贴出来供参考:参数名取值说明区域范围1000m x 1000m无人机不允许出界无人机高度100m固定高度最大速度12m/s每时隙最大位移12m时隙长度1s决策周期用户数量8双无人机各服务1个NOMA配对载波频率2GHz常用空对地频段带宽5MHzNOMA共享带宽噪声功率-104dBm接收机底噪无人机发射功率0.1W/1W/2W 三档动作空间里的功率维度学习率alpha0.1衰减至0.01每500个episode衰减折扣因子gamma0.95偏向长期累计收益epsilon0.9衰减至0.05前期探索后期利用最大episode数3000训练总轮数最大步数200单轮最大飞行时隙5.2 路径优化效果与Q值收敛分析训练到约800个episode时,总奖励曲线开始出现明显的上升趋势,到1500个episode后基本进入平台期。这里要说一下,如何判断收敛不能只看总奖励曲线,还要看每个状态下的Q值是否稳定。我在调试中发现一个现象:总奖励曲线在600到900个episode之间反复波动,看起来像没收敛,实际上是因为epsilon从0.9衰减到0.3左右,无人机还在大量探索,频繁进入低奖励状态。这个阶段属于正常现象,不要因为中间震荡就急着调小alpha,否则后面探索不足会陷入局部最优。路径可视化脚本里,叠加了无人机轨迹和用户位置。训练完成后可以看到一个明显模式:无人机先飞向用户分布最密集的区域,在靠近弱势用户的距离悬停,然后根据信道状态微调位置,而不是简单地在区域中心转圈。两架无人机的轨迹在空间上自然错开,没有撞到一起,说明碰撞惩罚项起到了作用。5.3 与中心化方案/固定航线的对比为了验证算法价值,我跑了几组对照实验。第一组是固定航线:无人机按预定的圆形航线匀速巡航,不决策、不变速、不变功率。结果是总吞吐量低,因为部分时隙无人机离服务用户太远,信道增益太低,NOMA弱用户速率几乎为零。第二组是中心化Q学习:一个中心Q表同时管理两架无人机的联合动作。效果是收敛后半数的单步吞吐量比去中心化方案高8%到12%,这个提升来自全局状态下的精准协同,但代价是状态空间膨胀了几倍,训练时间增加约3倍,而且一旦模拟链路中断,性能立刻崩溃。第三组是去中心化但无NOMA:双无人机用正交频段各自服务用户。去中心化方案加NOMA后,频谱效率大约提升了35%到40%,代价是SINR计算多了一层干扰建模,调试难度有所增加。对比结论很明确:去中心化Q-Learning方案牺牲了一部分最优性,换来了更强的鲁棒性和更低的决策复杂度,在链路不稳定、中心节点不可依赖的应急场景里意义更大。如果你所在场景有可靠的中心控制链路,又不缺算力,中心化方案确实更香;如果你的需求是抗毁和分布式部署,那去中心化是取舍之后的正确方向。6. 常见问题与调试心得6.1 训练不收敛,奖励一直震荡这是我遇到最多的问题。几个排查顺序供参考:先看奖励尺度是否合理。如果奖励值域跨度过大,比如移动能耗是0.0001量级,吞吐量增量是10量级,能耗项在Q值更新里被完全淹没,无人机根本不学“节省能量”这件事。把奖励各分量归一化到差不多的量级再跑,收敛速度会明显改善。再看状态空间是否包含关键历史信息。正如前面提的,剩余能量、上一时隙是否碰撞这类信息如果不进状态,环境对智能体来说就不是马尔可夫的,Q表会一直抖动。这类问题排查方式是:把奖励和状态打印出来,肉眼核对“相似状态”是否对应“相似奖励”。最后看探索策略。epsilon衰减太快,无人机可能还没充分探索所有动作就已经开始利用,最后卡在局部最优。把exploration的衰减速度放缓,比如每1000个episode衰减到原来的0.9,多试几次。6.2 NOMA配对失效,两用户都解不出信号仿真中常见的一个错误是SIC链路失效。前面公式里,弱用户以强用户信号为干扰完成解码,前提是弱用户自身的SINR高于解调门限。如果两架无人机功率分配颠倒,强用户功率远大于弱用户,弱用户速率为零,强用户即使SIC解出弱用户信号也毫无意义。建议在compute_reward函数里加一个约束:当弱用户SINR小于解调门限时,本时隙无效,不给任何正奖励。否则智能体会学到一种“骗奖励”的策略——只提升强用户速率、假装弱用户存在,但弱用户实际并没有通信成功。这个细节是我调试中最容易忽略的地方。6.3 双无人机总是往同一侧飞,协同失效如果奖励设计里没有明确的空间约束,两架无人机会倾向于同时飞向用户最密集的区域,导致另一侧用户无人服务。解决办法有三种:一是把覆盖均匀性加入奖励。比如计算每个无人机服务用户的平均距离,距离差距过大时给负奖励。二是设置半区偏好。初始阶段强制一架无人机偏向区域左侧、一架偏向右侧,等策略成熟后取消偏好。三是我前面提到的共享全局奖励,让每架无人机知道“整体吞吐量上去了,自己才有奖励”,这样即便局部看起来“吃亏”,也能学会配合。6.4 可复现性建议Matlab仿真存在两个天然陷阱:随机数种子和并行工具箱的随机流。如果实验跑一半发现结果对不上,先检查rng设置。我的做法是在config_params里固定rng(20240601),用户撒点、信道抽样都用这个种子。启用parfor并行训练时,每个worker要单独设置随机流,否则多个worker之间共享随机序列会导致训练数据被重复使用。另一个提示是保存中间Q表。每500个episode存一次Q1.mat和Q2.mat。这样即使后面训练跑飞了,还能回退到之前的状态继续调参,不用从头再来。整个调参周期里,这个习惯帮我省了大量时间。最后再多说两句我自己的体会是,这类算法题目最难的从来不是某个公式或某段代码,而是把通信系统的物理约束和强化学习的模型假设对齐起来。信道模型太粗糙,策略学了也和实际对不上;Q表状态设计太细,训练慢到怀疑人生;奖励函数权重没配好,无人机学出来的行为完全不符合直觉。建议你拿到这个课题后,先跑一个“单无人机、固定功率、只看位置”的最简版本,确认Q学习框架正常,再逐步加入功率维度和第二架无人机。每一步都验证了再叠加,调试成本会低很多。后续可以继续扩展的方向包括:连续动作空间的DQN替代表格Q-Learning、多无人机超过两架时的邻居通信拓扑设计、以及把NOMA的功率分配从离散动作改为连续优化并用神经网路拟合。希望这篇拆解对你有实际帮助,哪怕只是让你少踩一个我在仿真里踩过的坑。
这几年做空对地通信仿真,我和团队接触最多的一个组合就是:无人机当空中基站,地面终端散落在楼宇、山体、树冠之间,非视距遮挡严重,固定基站要么够不着,要么容量不够。常规做法是让无人机沿着预设航点巡航,但用户一挪、场景一变,航线就基本作废,需要重新手动规划。后来我们把问题拆成两层来解决:物理层用NOMA(非正交多址接入)把同一个频谱资源切给多用户,提升系统容量;控制层用去中心化Q-Learning让每架无人机根据自身局部观测独立学习路径策略。整套思路最后在Matlab里落了地,今天这篇就是完整的项目拆解,包括系统建模、算法设计、仿真代码框架和调参踩坑记录。适合正在做无人机通信、NOMA资源调度、强化学习路径规划的硕博生和工程开发人员参考。1. 项目背景与问题拆解:双无人机为什么要和NOMA、Q-Learning绑在一起1.1 场景痛点与设计动机先还原一下原始问题。某个园区做应急通信演练,地面基站断电,需要临时恢复覆盖。现场有十几个终端,分布在几栋建筑之间,有一部分终端处在严重遮挡区域,地面基站临时架设难度大、周期长。这时候无人机作为空中接入点的价值就体现出来了:它飞得高,视距链路概率大,部署快,而且可以通过优化航迹主动逼近用户。但真正落地时发现三层问题。第一层是频谱资源紧张。一片区域内用户一多,频带就分不过来。如果每用户独占一个时频资源块,容量天花板很低。第二层是路径规划。双无人机各自服务一组用户,但用户分布不均匀,有的区域用户密集、有的区域稀疏,无人机如果飞得不对,距离一远信道质量就断崖式下跌。第三层是控制架构。最直观的想法是地面中心统一管控,收集所有状态、下发所有动作,但实际场景链路易断、时延不可控,一旦中心失效全盘瘫痪。NOMA解决第一层问题。它允许同一个资源块通过功率域或码域区分用户,接收端用串行干扰消除(SIC)把混叠信号拆开,频谱效率直接翻倍。Q-Learning解决第二和第三层问题。每个无人机被建模成独立智能体,根据自己的位置、用户分布和信道观测决定下一步往哪飞、用多大功率,不依赖统一中心。1.2 技术选型逻辑:NOMA解决什么,去中心化强化学习解决什么先说NOMA。传统正交多址(OMA)给每个用户分配正交资源,缺点是资源利用率上限低。NOMA的思路很直接:在发送端用不同功率叠加多个用户的信号,在接收端按信号强度排序依次解码。功率分配是核心——强用户(信道条件好的)分配较小功率,弱用户(信道条件差的)分配较大功率,这样弱用户可以直接把强用户信号当噪声解出自己的信号,强用户则通过SIC先解出并消掉弱用户信号再解自己的。放在双无人机场景里,两架无人机可以选择同一时频资源、分别服务一对“近强远弱”的用户,通过功率域NOMA叠加,在一个资源块上同时传两路数据。系统吞吐量、边缘用户速率、频谱效率三项指标都能得到改善。再说Q-Learning。很多人会问:路径规划用A*、人工势场、凸优化不是更成熟?这些方法的问题在于,当环境是动态的、用户分布不可预知、目标是长期累计吞吐量而非单步最短路径时,无模型的强化学习更有优势。Q-Learning不需要信道模型精确已知,只需要定义好状态、动作、奖励,然后通过试错迭代学出一个策略表。而且它天然适合做成去中心化——每个智能体维护自己的Q表,自己探索、自己利用,单机决策复杂度低,符合无人机集群没有地面中心节点或链路经常中断的约束条件。这里需要说清楚,去中心化不等于完全孤立。它指的是不依赖全局状态和中央调度器,但无人机之间仍然可以通过机间链路交换少量必要信息,比如避免飞入同一区域、避免信号互干扰。在设计Q表的奖励函数时,可以把碰撞惩罚和干扰惩罚嵌进去,实现“局部决策、全局协调”的效果。2. 系统模型与数学基础:信道、NOMA配对、无人机运动模型2.1 三维空对地信道模型仿真里信道模型不能随便拿一个自由空间损耗公式糊弄过去。空地信道和地面信道最大的区别在于仰角会显著影响视距概率。建筑、树木、地形遮挡会随仰角变化,典型工程做法是采用概率视距模型,把路径损耗写成视距分量和非视距分量的加权平均。上行和下行场景不同,但我这里只说下行传输。无人机到地面用户的路径损耗表达式为:L = 20log10(4πf d / c) + P_LOS * η_LOS + P_NLOS * η_NLOS其中d是三维距离:d = sqrt((x_u - x_g)^2 + (y_u - y_g)^2 + h^2)。h是无人机飞行高度,f是载波频率,c是光速。η_LOS和η_NLOS是额外损耗因子,视距条件下取小一些,非视距条件下取大一些。P_LOS和P_NLOS是视距和非视距概率,随仰角提升,P_LOS单调上升。还有一个细节是信道增益h_ch = 10^(-L/10)。后续算SINR时,直接就归一化到1毫瓦参考功率上。2.2 功率域NOMA的SINR建模假设一个时隙内,无人机A以功率P1服务弱用户,无人机B以功率P2服务强用户,两个信号在同一个子载波上叠加发射。弱用户信道增益记为g_weak,强用户信道增益记为g_strong,噪声功率N0。弱用户直接被服务,解码时把强用户信号视为干扰:SINR_weak = P1 * g_weak / (P2 * g_strong + N0)强用户采取SIC,先解弱用户信号并从混合信号中消除,再解自己的信号:SINR_strong = P2 * g_strong / N0从公式能看出来几个关键点。第一,弱用户的干扰项里含P2 * g_strong,如果两架无人机把功率都加到最大,弱用户反而容易被干扰吞掉。第二,SIC的前提是强用户能正确解出弱用户信号,这要求弱用户功率足够强,否则SIC会失效。第三,两架无人机各自服务不同用户,但它们共享同一个频段,所以彼此之间的功率分配变成了一个联合优化问题,这也是后面奖励函数要重点考虑的部分。配套还要考虑用户到哪个无人机的配对。实际工程中先在每个时隙根据信道增益做配对:信道好的用户和信道差的用户配成一组,再决定哪架无人机给哪个用户发。仿真时我用的原则是每架无人机只服务离自己最近的几个用户,两个无人机选取的配对用户保证不重复。2.3 无人机运动与能耗模型无人机运行高度固定时可以简化成二维平面运动。我仿真时把高度设为100米,速度上限12m/s,每个时隙长度1秒,也就是无人机每步最多移动12米。动作空间包含8个方向移动一步、原地悬停、以及3个功率档位。能耗模型是算奖励时绕不开的。悬停、水平飞行、加速都有不同功耗。简化但不失一般性的做法是:飞行状态时功率功耗取常值P_hover加上与速度平方成正比的增量,移动越远耗能越高。剩余能量作为一个状态分量进入Q表,让无人机学会在电量低时减少不必要的绕飞,优先飞到高价值用户区域。这里提一个容易踩的坑:如果能量消耗只作为惩罚项放进奖励,而不进入状态,无人机永远学不会“想着电量做规划”。因为Q-learning本身是马尔可夫决策过程,如果状态里没有剩余能量,这个决策问题就不是马尔可夫的,策略会受历史影响而抖动。所以剩余能量等级必须放进状态,哪怕只离散成3到5档。3. 去中心化Q-Learning算法设计:状态、动作、奖励与决策流程3.1 为什么必须去中心化中心化方案看起来更“标准”:一个地面控制中心收集所有无人机的位置、能量、用户信道状态,求解全局最优路径,逐时隙下发动作。但真实场景里有一个致命问题——控制链路开销。无人机数量一多,控制中心需要处理的联合状态空间会随无人机数量指数增长,而且每次决策还要等链路往返,时延高、可靠性差。更重要的是,控制中心一旦被干扰或链路断裂,所有无人机都会变成“无头苍蝇”。去中心化的本质是“每个智能体只根据局部观测做决策”。双无人机场景里,每架无人机知道自己相对用户的位置、自己的剩余能量、自己当前对目标用户信道的估计,以及另一个无人机的大致方位。它不需要知道另一位智能体完整的Q表,也不需要中央节点做仲裁。我这样类比:中心化像剧场导演指挥每个演员走位,导演一离开,演出就乱套;去中心化像即兴表演,每个演员只遵循基本规则、根据对手动作即兴反应。性能可能略低于全局最优,但鲁棒性完全不在一个量级。3.2 状态与动作空间设计Q表的大小取决于状态离散化。状态空间如果直接放原始坐标,比如1000米乘1000米区域、5米一格,那就是4万个状态乘8个动作,两个无人机各搞一张6位数的Q表,训练量直接爆炸。我的处理方法是用相对信息做状态压缩,而不是用绝对坐标。具体来说:把无人机周围360度分成8个扇区,每个扇区统计服务用户的个数。最近用户的距离等级,分成近(<200米)、中(200到500米)、远(>500米)3档。剩余能量等级,分成高、中、低3档。另一架无人机的相对方位,分成同扇区或不同扇区2种状态。这样单机状态数量大约是8个扇区用户数的组合数(实际按每个扇区0/1/2个用户量化),乘以3乘以3乘以2,可以控制在几千量级,这是表格型Q-Learning可以处理的范围。动作空间更简洁:8个移动方向 + 原地悬停 + 3档发射功率,一共11个动作。这里把位置决策和功率决策放在同一个动作里,是因为功率和位置对信道增益的影响是耦合的:远距离悬停配大功率,效果可能不如贴近用户配小功率。分两步决策会增加状态设计复杂度,合在一起虽然动作空间变大,但Q表规模还在可控范围。如果觉得动作数过多,可以先跑简化版本:9个动作(8方向+悬停)、功率固定。路径收敛后再放开功率维度。3.3 奖励函数设计与参数权衡奖励函数是整个算法设计里最影响收敛效果的部分。我最终用的是这样一个综合奖励:r = w1 * ΔR_sum + w2 * R_min - w3 * E_step - C_collision - C_boundary其中ΔR_sum是本时隙相对上一时隙系统总吞吐量的增量,R_min是当前时隙两用户中最小的可达速率,E_step是本步移动消耗的能量,C_collision是两架无人机距离过近时的惩罚,C_boundary是飞出预定区域的惩罚。为什么要用吞吐量增量而不是绝对吞吐量?因为Q-Learning的Q值是通过累加折扣奖励来拟合长期回报的。如果奖励里带一个很大的常数基准项,Q值会变得很大且变化不敏感,训练曲线看起来像是“已经收敛”,实际策略没有发生任何优化。用增量奖励可以让Q值对策略变化更敏感。R_min那一项是保证公平性的。如果只优化总吞吐量,无人机很快会发现“喂饱离得近的强用户”是最高效策略,边缘弱用户直接被放弃,这既不符合通信公平性原则,也浪费了NOMA弱用户链路的价值。折中方案是给最小速率乘以权重w2,倒逼无人机在飞行过程中兼顾弱势用户。再说惩罚项。C_collision我设置的是两架无人机欧氏距离小于安全距离50米时给-5,这个数值不能太小,否则无人机倾向于贴着飞,信号互相干扰严重;但也不能太大,否则两架无人机过度回避、各自往区域两边跑,导致覆盖产生空洞。C_boundary设成-3,因为仿真区域外围通常存在未知地形或禁飞区,步进过程中一旦越界就回退并惩罚。3.4 训练流程与超参选择具体训练流程按标准Q-Learning走:每个episode开始时,随机撒用户位置,无人机从固定起点起飞。每个时刻根据当前状态,用epsilon-greedy策略选动作。执行动作后计算奖励、得到下一状态、更新Q表。当无人机电量耗尽或到达最大步数时结束episode,重置场景,继续下一轮。超参数我建议这样设置:学习率alpha初始0.1,每500个episode乘以0.9衰减,最低不低于0.01;折扣因子gamma取0.9到0.95之间,gamma越大越看重长期收益,但收敛越慢;epsilon初始0.9,随着训练推进衰减到0.05,让智能体前期多探索、后期多利用。每个episode最大步数设为200,保证训练不会无休止跑下去。还有一个容易被忽略的点:状态初始化要覆盖多样场景。如果把用户位置撒点限制在一个小区内部,学出来的策略只适用于那种均匀分布,很脆弱。我在随机撒用户时会让位置分布混合模式,一部分均匀分布、一部分集中成簇,这样无人机学到的是更泛化的规则,而不是对某一种分布的过拟合。4. Matlab仿真框架实现:从信道函数到Q学习主循环4.1 工程目录与模块划分Matlab工程我按功能拆成几个脚本,别全都塞进一个主文件里,否则调试起来寸步难行。常见的目录结构如下:drone_noma_qlearning/ main_run.m config_params.m init_scenario.m compute_channel.m compute_noma_rate.m compute_reward.m select_action.m update_qtable.m plot_results.mmain_run.m是入口,负责加载参数、初始化环境、执行训练循环、保存结果。config_params.m集中存放所有超参数和系统参数,每次跑新实验只用改这一个文件。compute_channel.m算空地信道增益,compute_noma_rate.m算两个用户的SINR和可达速率,compute_reward.m按公式计算奖励,select_action.m实现epsilon-greedy选择,update_qtable.m做Q表更新。4.2 核心函数实现与讲解先看信道函数。这一块要注意输入输出向量化,避免后面循环里反复算重复量时性能拉胯。function [g_los, g_nlos, pl_prob] = compute_channel(pos_drone, pos_user, fc, h_drone, env) c = 3e8; d_3d = sqrt((pos_drone(1)-pos_user(1))^2 + ... (pos_drone(2)-pos_user(2))^2 + h_drone^2); theta = asin(h_drone / d_3d) * 180 / pi; A = env.A; % 环境相关常量,密集城区取较大值 B = env.B; p_los = 1 / (1 + A * exp(-B * (theta - A))); p_nlos = 1 - p_los; pl_free = 20*log10(4*pi*fc*d_3d/c); pl_los = pl_free + env.eta_los; pl_nlos = pl_free + env.eta_nlos; g_los = 10^(-pl_los / 10); g_nlos = 10^(-pl_nlos / 10); pl_prob = p_los; end注意我返回的是视距和非视距两套信道增益,主循环里按概率p_los抽样决定实际使用哪一套。有的简化仿真直接用了期望信道增益g = p_losg_los + p_nlosg_nlos,这样做训练更平稳,但丢失了信道随机性,学出来的策略可能对瞬时衰落过于乐观。我推荐至少保留概率抽样版本,这样策略天然带有鲁棒性。NOMA速率计算是所有调参工作的核心。下面这个函数输入是两架无人机功率、信道增益、噪声功率,输出是强用户和弱用户各自的可达速率:function [rate_strong, rate_weak, sinr_strong, sinr_weak] = compute_noma_rate(p_strong, p_weak, g_strong, g_weak, bw, p_noise) sinr_weak = p_weak * g_weak / (p_strong * g_strong + p_noise); sinr_strong = p_strong * g_strong / p_noise; rate_weak = bw * log2(1 + sinr_weak); rate_strong = bw * log2(1 + sinr_strong); end这里有一个分量容易出错:p_strong和p_weak指的是无人机发射功率,还是信号在接收端的功率?仿真里如果信道增益g已经包含路径损耗,那么接收功率就是p * g,所以SINR公式里直接用发射功率乘以信道增益没问题。但要注意单位的统一,我用的是毫瓦级别,噪声功率N0用接收机热噪声功率折算过来,常见值约-104dBm,转换为毫瓦是10^(-104/10)。4.3 主仿真循环与训练过程主循环伪代码级别如下:for episode = 1 : max_episodes scenario = init_scenario(); state1 = get_state(drone1, scenario); state2 = get_state(drone2, scenario); for step = 1 : max_steps action1 = select_action(Q1, state1, epsilon); action2 = select_action(Q2, state2, epsilon); [next_state1, next_state2, reward, done] = env_step(scenario, action1, action2); Q1(state1, action1) = Q1(state1, action1) + ... alpha * (reward1 + gamma * max(Q1(next_state1, :)) - Q1(state1, action1)); Q2(state2, action2) = Q2(state2, action2) + ... alpha * (reward2 + gamma * max(Q2(next_state2, :)) - Q2(state2, action2)); state1 = next_state1; state2 = next_state2; if done, break; end end epsilon = max(epsilon * epsilon_decay, 0.05); alpha = max(alpha * alpha_decay, 0.01); end两个细节值得特别说明。一个是reward1和reward2怎么分。双无人机共享系统总奖励,但各自更新自己的Q表时用的是同一个总奖励值。如果各用各的局部速率,两架无人机会各顾各的,最后互相干扰反而总吞吐量下降。所以这里我让reward1 = reward2 = 总奖励值,共享全局奖励是去中心化前提下最简单也最有效的协同协作方式。另一个是环境函数env_step里的碰撞处理。两架无人机如果同一时隙移动到同一点附近,动作需要回退到上一位置。回退动作会导致Q表里出现一条“这个状态向那个方向走会撞车”的经验,这正是我们希望智能体学到的。但回退本身也会改变用户距离,导致奖励跳变,所以碰撞惩罚不能只加在一个时隙,建议让碰撞后的3个时隙持续减分,这样无人机才不会反复往碰撞区域试探。完整Matlab源码的拼装逻辑就是:config_params定义参数,init_scenario生成用户分布和初始状态,env_step调用compute_channel和compute_noma_rate计算通信速率,再调用compute_reward计算奖励,主循环里反复执行select_action和update_qtable,最后调用plot_results出图。代码量不大,整个工程也就400到500行。5. 仿真参数配置与结果分析5.1 关键参数配置表这是我调试下来比较稳定的一组参数,直接贴出来供参考:参数名取值说明区域范围1000m x 1000m无人机不允许出界无人机高度100m固定高度最大速度12m/s每时隙最大位移12m时隙长度1s决策周期用户数量8双无人机各服务1个NOMA配对载波频率2GHz常用空对地频段带宽5MHzNOMA共享带宽噪声功率-104dBm接收机底噪无人机发射功率0.1W/1W/2W 三档动作空间里的功率维度学习率alpha0.1衰减至0.01每500个episode衰减折扣因子gamma0.95偏向长期累计收益epsilon0.9衰减至0.05前期探索后期利用最大episode数3000训练总轮数最大步数200单轮最大飞行时隙5.2 路径优化效果与Q值收敛分析训练到约800个episode时,总奖励曲线开始出现明显的上升趋势,到1500个episode后基本进入平台期。这里要说一下,如何判断收敛不能只看总奖励曲线,还要看每个状态下的Q值是否稳定。我在调试中发现一个现象:总奖励曲线在600到900个episode之间反复波动,看起来像没收敛,实际上是因为epsilon从0.9衰减到0.3左右,无人机还在大量探索,频繁进入低奖励状态。这个阶段属于正常现象,不要因为中间震荡就急着调小alpha,否则后面探索不足会陷入局部最优。路径可视化脚本里,叠加了无人机轨迹和用户位置。训练完成后可以看到一个明显模式:无人机先飞向用户分布最密集的区域,在靠近弱势用户的距离悬停,然后根据信道状态微调位置,而不是简单地在区域中心转圈。两架无人机的轨迹在空间上自然错开,没有撞到一起,说明碰撞惩罚项起到了作用。5.3 与中心化方案/固定航线的对比为了验证算法价值,我跑了几组对照实验。第一组是固定航线:无人机按预定的圆形航线匀速巡航,不决策、不变速、不变功率。结果是总吞吐量低,因为部分时隙无人机离服务用户太远,信道增益太低,NOMA弱用户速率几乎为零。第二组是中心化Q学习:一个中心Q表同时管理两架无人机的联合动作。效果是收敛后半数的单步吞吐量比去中心化方案高8%到12%,这个提升来自全局状态下的精准协同,但代价是状态空间膨胀了几倍,训练时间增加约3倍,而且一旦模拟链路中断,性能立刻崩溃。第三组是去中心化但无NOMA:双无人机用正交频段各自服务用户。去中心化方案加NOMA后,频谱效率大约提升了35%到40%,代价是SINR计算多了一层干扰建模,调试难度有所增加。对比结论很明确:去中心化Q-Learning方案牺牲了一部分最优性,换来了更强的鲁棒性和更低的决策复杂度,在链路不稳定、中心节点不可依赖的应急场景里意义更大。如果你所在场景有可靠的中心控制链路,又不缺算力,中心化方案确实更香;如果你的需求是抗毁和分布式部署,那去中心化是取舍之后的正确方向。6. 常见问题与调试心得6.1 训练不收敛,奖励一直震荡这是我遇到最多的问题。几个排查顺序供参考:先看奖励尺度是否合理。如果奖励值域跨度过大,比如移动能耗是0.0001量级,吞吐量增量是10量级,能耗项在Q值更新里被完全淹没,无人机根本不学“节省能量”这件事。把奖励各分量归一化到差不多的量级再跑,收敛速度会明显改善。再看状态空间是否包含关键历史信息。正如前面提的,剩余能量、上一时隙是否碰撞这类信息如果不进状态,环境对智能体来说就不是马尔可夫的,Q表会一直抖动。这类问题排查方式是:把奖励和状态打印出来,肉眼核对“相似状态”是否对应“相似奖励”。最后看探索策略。epsilon衰减太快,无人机可能还没充分探索所有动作就已经开始利用,最后卡在局部最优。把exploration的衰减速度放缓,比如每1000个episode衰减到原来的0.9,多试几次。6.2 NOMA配对失效,两用户都解不出信号仿真中常见的一个错误是SIC链路失效。前面公式里,弱用户以强用户信号为干扰完成解码,前提是弱用户自身的SINR高于解调门限。如果两架无人机功率分配颠倒,强用户功率远大于弱用户,弱用户速率为零,强用户即使SIC解出弱用户信号也毫无意义。建议在compute_reward函数里加一个约束:当弱用户SINR小于解调门限时,本时隙无效,不给任何正奖励。否则智能体会学到一种“骗奖励”的策略——只提升强用户速率、假装弱用户存在,但弱用户实际并没有通信成功。这个细节是我调试中最容易忽略的地方。6.3 双无人机总是往同一侧飞,协同失效如果奖励设计里没有明确的空间约束,两架无人机会倾向于同时飞向用户最密集的区域,导致另一侧用户无人服务。解决办法有三种:一是把覆盖均匀性加入奖励。比如计算每个无人机服务用户的平均距离,距离差距过大时给负奖励。二是设置半区偏好。初始阶段强制一架无人机偏向区域左侧、一架偏向右侧,等策略成熟后取消偏好。三是我前面提到的共享全局奖励,让每架无人机知道“整体吞吐量上去了,自己才有奖励”,这样即便局部看起来“吃亏”,也能学会配合。6.4 可复现性建议Matlab仿真存在两个天然陷阱:随机数种子和并行工具箱的随机流。如果实验跑一半发现结果对不上,先检查rng设置。我的做法是在config_params里固定rng(20240601),用户撒点、信道抽样都用这个种子。启用parfor并行训练时,每个worker要单独设置随机流,否则多个worker之间共享随机序列会导致训练数据被重复使用。另一个提示是保存中间Q表。每500个episode存一次Q1.mat和Q2.mat。这样即使后面训练跑飞了,还能回退到之前的状态继续调参,不用从头再来。整个调参周期里,这个习惯帮我省了大量时间。最后再多说两句我自己的体会是,这类算法题目最难的从来不是某个公式或某段代码,而是把通信系统的物理约束和强化学习的模型假设对齐起来。信道模型太粗糙,策略学了也和实际对不上;Q表状态设计太细,训练慢到怀疑人生;奖励函数权重没配好,无人机学出来的行为完全不符合直觉。建议你拿到这个课题后,先跑一个“单无人机、固定功率、只看位置”的最简版本,确认Q学习框架正常,再逐步加入功率维度和第二架无人机。每一步都验证了再叠加,调试成本会低很多。后续可以继续扩展的方向包括:连续动作空间的DQN替代表格Q-Learning、多无人机超过两架时的邻居通信拓扑设计、以及把NOMA的功率分配从离散动作改为连续优化并用神经网路拟合。希望这篇拆解对你有实际帮助,哪怕只是让你少踩一个我在仿真里踩过的坑。