LDACS(L-band Digital Aeronautical Communications System,L 波段数字航空通信系统)调度算法仿真与对比研究项目。
包含四种调度算法:RR(轮询)、PF(比例公平)、MaxCI(最大载干比)、DDQN(Double Deep Q-Network 深度强化学习)
LDACS_py/ # 项目根目录
├── main.py # 主入口:训练、验证、测试、推理
├── config.py # 全局仿真参数配置
├── requirements.txt # 项目依赖列表
│
├── src/ldacs/ # 主包
│ ├── core/ # 信道建模与仿真基础
│ │ ├── channel.py # 信道模型:路径损耗、大尺度增益、SCME 快衰落、干扰环境
│ │ ├── system_model.py # 系统模型:GS/AS 拓扑、GS-AS 关联、距离矩阵
│ │ ├── rate_calculator.py # 速率计算:SINR → Shannon 容量(统一调度/评估两用)
│ │ └── metrics.py # 统计指标:RateMetrics(样本级)、SampleSetMetrics(样本集级)
│ │
│ ├── scheduling/ # 调度算法
│ │ ├── rr_scheduler.py # Round Robin 轮询调度
│ │ ├── pf_scheduler.py # Proportional Fair 比例公平调度
│ │ ├── maxci_scheduler.py # Maximum C/I 最大载干比调度
│ │ └── ddqn/ # DDQN 深度强化学习调度
│ │ ├── __init__.py
│ │ ├── network.py # Q-Network(共享全连接 + mask 屏蔽)
│ │ ├── replay_buffer.py # 经验回放缓冲区(FIFO + 均匀采样)
│ │ ├── agent.py # DDQN Agent(ε-greedy、Double DQN 训练、目标网络软更新)
│ │ └── ddqn_scheduler.py# DDQNScheduler(统一 schedule() 接口,状态/奖励归一化)
│ │
│ └── views/ # 可视化
│ └── plot_results.py # 逐样本步长曲线、速率 PDF 直方图、DDQN 训练/验证曲线
│
├── sample_generator/ # 场景样本生成
│ ├── generate_gs.py # 六边形蜂窝 GS 布局生成
│ ├── generate_as.py # 高度分层 AS 位置生成
│ ├── generate_samples.py # 综合样本生成与 3D 可视化
│ └── sample_storage/ # 生成的样本数据(CSV)
│
├── fastfading/ # SCME 快衰落信道数据(MATLAB/C++ 预生成)
│
├── results/ # 仿真结果输出
│ ├── per_sample/ # 逐样本步长对比图
│ ├── ddqn_models/ # DDQN 训练保存的模型权重
│ ├── ddqn_training/ # DDQN 训练/验证曲线(loss / ε / reward / val metrics)
│ ├── data/ # 数值结果(JSON 汇总 + NPZ 原始数据)
│ └── rate_pdf.png # 速率 PDF 分布图(直方图)
│
└── tests/ # 单元测试
集中定义仿真参数:
| 类别 | 参数 | 值 |
|---|---|---|
| 区域 | 尺寸 | 200 km × 200 km × 6 km |
| GS | 数量 / 带宽 / 覆盖半径 | 12 站 / 498,050 Hz / 25 NM |
| AS | 数量 / 最大发射功率 | 150 架 / 41 dBm |
| 物理层 | 中心频率 / 子载波间隔 / 每 tile 子载波 | 987 MHz / 9.765625 kHz / 25 |
| 资源栅格 | FFT 长度 / 占用子载波 / tiles per frame | 64 / 50 / 160 |
| 仿真 | 步长 / drops | 100 步 / 10 drops |
DDQN 训练参数详见下方专节。
| 模块 | 说明 |
|---|---|
channel.py |
自由空间路径损耗、3D 距离矩阵、大尺度信道增益、SCME 快衰落(FFT 实时计算)、InterferenceEnvironment(跨 GS 干扰管理) |
system_model.py |
网络拓扑构建(GS-AS 最近关联)、位置加载(CSV) |
rate_calculator.py |
compute_tile_rate():SINR → Shannon 容量;统一服务调度决策(+1 假设)和速率评估(实际 tile 数) |
metrics.py |
RateMetrics:样本级统计(per-AS 时间均值、样本均值/方差、Jain index、百分位);SampleSetMetrics:样本集级聚合 |
| 算法 | 选择标准 | 特点 |
|---|---|---|
| RR | 轮询序号 | 公平性最好,忽略信道质量 |
| PF | argmax(瞬时速率 / 平均速率) | 效率与公平折中,EMA 更新平均吞吐量 |
| MaxCI | argmax(瞬时速率) | 吞吐量最高,边缘用户可能饥饿 |
| DDQN | argmax Q(s, a) | 学习调度策略,兼顾吞吐量与公平性 |
所有调度器共享统一接口:
scheduler.schedule(tile_num, gs_idx, current_step,
large_scale_gain_db, as_power_dbm,
scme_channel, interference_env) → tile_assignment| 要素 | 定义 |
|---|---|
| State | 每 AS 的 5 维归一化特征向量(padding 至 max_as),外加 bool mask 标记有效/填充位 |
| Action | 整数 ∈ [0, max_as),选择将当前 tile 分配给哪个 AS;填充位 Q = -∞ |
| Reward | 每步 r = instantaneous_rate(selected_AS) / RATE_SCALE,归一化至 ~O(1) |
| Episode | 一帧(160 tiles)= 一个 episode;前 num_as 个 tile 为控制 tile(固定分配),其余为数据 tile(agent 决策) |
所有特征归一化至 ~O(1),确保 Q 网络输入量级一致,避免梯度不稳定:
| 特征 | 维度 | 归一化方式 | 原始量级 → 归一后 |
|---|---|---|---|
instantaneous_rate |
0 | / RATE_SCALE (1e5) |
~1e6 → ~3-10 |
tile_count |
1 | / TILE_NUM (160) |
0-160 → 0-1 |
avg_throughput |
2 | / RATE_SCALE (1e5) |
~1e6 → ~3-10 |
channel_gain_db |
3 | / GAIN_SCALE (100) |
-120~-40 → -1.2~-0.4 |
tile_position |
4 | t / (TILE_NUM - 1) |
0-1(不变) |
填充(padding)位全零特征,mask = False,Q 值被屏蔽为 -∞ 不会被选中。
reward = instantaneous_rate(selected_AS) / RATE_SCALE
RATE_SCALE = 1e5,per-tile reward ~O(3-10)- Q 值 ~O(100-500),TD Loss ~O(1-10),学习稳定、尖峰减少
Input: (batch, max_as, 5) + mask (batch, max_as)
↓ reshape → (batch×max_as, 5)
↓ FC(5→256) → ReLU
↓ FC(256→256) → ReLU × num_hidden layers
↓ FC(256→1)
↓ reshape → (batch, max_as)
↓ masked_fill(~mask, -inf)
Output: Q-values (batch, max_as)
- 所有 AS 共享同一组全连接参数(weight-sharing),天然适应不同 GS 下 AS 数量变化
- 隐藏层维度 256,3 层隐藏层,输出每 AS 一个 Q 值
- 通过 mask 屏蔽填充位,确保只在有效 AS 中选择
y = r + γ · Q_target(s', argmax_a Q_online(s', a))
^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
目标网络评估 在线网络选动作
- 从 replay buffer 均匀采样 mini-batch
- 在线网络计算
Q_online(s, a) - Double DQN:在线网络选动作
a* = argmax Q_online(s', ·),目标网络评估Q_target(s', a*) - MSE loss → 反向传播 → 梯度裁剪(max_norm=10)→ 参数更新
- ε 衰减(per training step)+ 目标网络软更新(Polyak averaging)
每次 learn() 后,目标网络参数按如下方式平滑追踪在线网络:
θ_target ← τ · θ_online + (1 - τ) · θ_target
τ = 0.005:目标网络每步吸收在线网络 0.5% 的参数- 等效于约 200 步的指数移动平均,远比硬同步平滑
- 避免 TD target 突变导致的 Loss 尖峰,训练更稳定
- Step-Major 并行训练:所有 50 个训练 drop 在同一 time step 并行推进,而非逐个 drop 跑完。每步收集 ~88,000 条 transition(50 drops × ~12 GS × ~148 data tiles),经验多样性远优于逐 drop 训练
- 经验收集:每个 data tile 产生一条 transition
(s, a, r, s', done),存入共享 replay buffer - 学习频率:每个 GS 的
schedule()结尾调用learn()一次;每 step 共 ~600 次 learn - Warmup:replay buffer 积累至
LEARN_START(2,000)条之前不启动学习 - 探索:ε-greedy,ε 从 1.0 指数衰减至 0.01(per training step 衰减,因子 0.955;100 步内从 1.0 降至 0.01,全程渐进探索)
- 目标网络:Polyak 软更新(τ=0.005),每步平滑追踪,避免硬同步导致的 TD Loss 尖峰
- Episode Reward:每个 GS 的
schedule()为一个 episode,训练循环中累加后重置,确保记录的是单步 reward 而非累计值 - 共享 Agent:所有 GS、所有 drop 共享同一个
DDQNAgent(同一 Q 网络、同一 replay buffer) - 共享 SCME:所有 drop 共享同一个
SCMEChannel实例,避免重复加载 ~440MB 信道数据
ε 在每个 training step 结束时衰减一次(而非每次 learn),确保探索-利用的渐进过渡:
step 0: ε = 1.000
step 10: ε = 0.631
step 20: ε = 0.399
step 30: ε = 0.252
step 50: ε = 0.101
step 70: ε = 0.040
step 90: ε = 0.016
step 100: ε = 0.010 ← 到达 ε_end
| 集合 | Drop 编号 | 数量 | 用途 |
|---|---|---|---|
| 训练集 | 1 ~ 50 | 50 | 更新 Q 网络参数(push transition + learn) |
| 验证集 | 51 ~ 60 | 10 | 训练中周期评估(ε=0,不学习),选 best 模型 |
| 测试集 | 61 ~ 70 | 10 | 训练结束后一次性评估,不参与调参 |
三组互不重叠。验证集用于模型选择,测试集仅在最终评估时使用一次。
| 参数 | 值 | 说明 |
|---|---|---|
DDQN_TRAIN_SAMPLES |
50 | 训练 drops 数(drop 1~50) |
DDQN_VAL_SAMPLES |
10 | 验证 drops 数(drop 51~60) |
DDQN_TEST_SAMPLES |
10 | 测试 drops 数(drop 61~70) |
DDQN_VAL_INTERVAL |
10 | 每隔多少 step 做一次验证 |
DDQN_EARLY_STOP_PATIENCE |
3 | 连续 N 次验证无提升则早停 |
DDQN_HIDDEN_DIM |
256 | 隐藏层维度 |
DDQN_NUM_HIDDEN |
3 | 隐藏层数量 |
DDQN_LR |
1e-4 | 学习率(Adam) |
DDQN_GAMMA |
0.95 | 折扣因子 |
DDQN_EPSILON_START |
1.0 | 初始探索率 |
DDQN_EPSILON_END |
0.01 | 最小探索率 |
DDQN_EPSILON_DECAY |
0.955 | 每 training step ε 衰减因子(100 步内 1.0→0.01) |
DDQN_BUFFER_CAPACITY |
50,000 | 经验回放缓冲区容量 |
DDQN_BATCH_SIZE |
128 | Mini-batch 大小 |
DDQN_LEARN_START |
2,000 | 开始学习所需最少 transition 数 |
DDQN_TAU |
0.005 | 目标网络软更新系数(Polyak averaging:τ→1=硬同步,τ→0=极慢追踪) |
DDQN_SEED |
42 | 随机种子 |
DDQN_RATE_SCALE |
1e5 | 速率/吞吐量归一化因子(bps → 100kbps 量级,reward ~3-10) |
DDQN_GAIN_SCALE |
100.0 | 信道增益归一化因子(dB → ~[-1.2, -0.4]) |
| 模块 | 说明 |
|---|---|
network.py |
Q-Network:共享全连接层 + mask 屏蔽,输出 (batch, max_as) Q 值 |
replay_buffer.py |
ReplayBuffer:固定大小 FIFO,均匀随机采样,存储 (s, a, r, s', done) |
agent.py |
DDQNAgent:在线/目标双网络、ε-greedy、Double DQN 训练步、目标网络软更新(Polyak averaging)、ε per-step 衰减(decay_epsilon())、模型保存/加载 |
ddqn_scheduler.py |
DDQNScheduler:统一 schedule() 接口;状态特征归一化、奖励归一化;训练时每 tile 收集经验、每 GS 调度完毕 learn 一次;推理时纯贪心(ε=0) |
| 函数 | 说明 |
|---|---|
plot_per_sample_curves() |
每个样本一张图,多调度器逐步速率/方差对比 |
plot_rate_pdf() |
用户平均速率的 PDF(直方图),直观展示公平性 |
plot_ddqn_training_curves() |
DDQN 训练曲线:Total Reward vs Step、ε vs Learn Step、TD Loss vs Learn Step |
| 模块 | 说明 |
|---|---|
generate_gs.py |
六边形蜂窝 GS 布局 |
generate_as.py |
按高度分层比例分布的 AS 位置 |
generate_samples.py |
综合生成 + 3D 可视化,支持批量多组 |
基于 IEEE 802.16m 标准的 SCME 信道模型,已预生成 10 组信道数据(MATLAB/C++ MEX),适配 LDACS 频段(987 MHz)和航空速度(300 km/h)。
数据结构:
SCME_channel_drop{i}.mat:shape(numPaths, mutiframe_num, link_num),各路径衰落权重SCME_channel_index_drop{i}.mat:shape(max_UE, num_gs, 2),time_index / link_index 映射
CSV 样本 (GS + AS 位置)
→ SystemModel (GS-AS 关联: 最近 GS)
→ 信道计算 (路径损耗 → 大尺度增益 + SCME 快衰落)
→ InterferenceEnvironment (跨 GS 干扰功率)
→ Scheduler.schedule() (RR / PF / MaxCI / DDQN 逐 tile 决策)
→ compute_tile_rate() (SINR → Shannon 容量)
→ RateMetrics → SampleSetMetrics (样本 / 样本集两级统计)
→ plot_results (逐样本曲线 + PDF 直方图 + DDQN 训练/验证曲线)
→ data/ (JSON 汇总 + NPZ 原始数据)
for each scheduler (RR, PF, MaxCI, DDQN-inference):
for each drop (1..N):
加载 GS/AS 位置 → 构建系统模型 → 计算信道 → 创建 per-GS 调度器
for each step (1..100):
1. 调度 (schedule) ← 各 GS 独立分配 tile
2. 转换为全局 0/1 矩阵
3. 更新干扰环境 ← updateInterferenceEnvironment
4. 计算实际速率 ← compute_tile_rate (最终 tile 数)
5. 记录指标 ← RateMetrics.record()
6. PF/DDQN 更新平均吞吐量 ← scheduler.update()
收集样本统计
保存结果 (JSON + NPZ) + 输出样本集统计 + 生成图表
1. 初始化
├── 设置随机种子
├── 创建 DDQNAgent(Q 网络、目标网络、replay buffer)
├── 加载 1 个共享 SCMEChannel(~440MB,所有 drop 共享)
└── 初始化 50 个 drop 的环境状态
└── 对每个 drop (1~50):
├── 加载 AS 位置 → SystemModel
├── 计算路径损耗 → channel_gain_db
├── 创建 InterferenceEnvironment
└── 创建 per-GS DDQNScheduler(共享 agent,训练模式)
2. Step-Major 训练循环(100 步)
└── for current_step = 1 to 100:
├── 遍历 50 个 drop(并行推进同一 step):
│ └── 对每个 drop:
│ ├── 各 GS 调度所有 data tile → push transition;GS 调度完毕 → learn()
│ ├── 更新干扰环境
│ ├── 计算速率 + 记录指标
│ ├── 更新 avg_throughput
│ ├── 累加 episode_reward(每 GS 一个 episode)
│ └── 重置 episode_reward = 0(避免跨步累计)
│
├── ε 衰减(per training step,非 per learn)
├── 目标网络软更新(Polyak averaging,每 learn 步执行)
├── 显示进度条(ε, loss, mean_rate, buffer 大小)
│
└── 每 10 步:验证
├── 保存 ε → 设 ε=0(纯贪心)
├── 在 drop 51~60 跑评估
│ └── evaluate_ddqn() → mean_rate, 5%tile, Jain
├── 恢复 ε
├── 若 val_mean_rate > best → 保存 best 模型
└── 连续 3 次无提升 → 早停
3. 训练结束
├── 保存最终模型(ddqn_agent.pt)
├── 加载 best 模型(ddqn_agent_best.pt)
└── 在 drop 61~70 跑最终测试
└── evaluate_ddqn() → mean_rate, 5%tile, Jain index
4. 输出图表 + 数据
├── training_curves.png(Total Reward vs Step, ε vs Learn Step, TD Loss vs Learn Step)
├── validation_curves.png(mean_rate, 5%tile, Jain vs Step)
├── data/ddqn_training_results.json(测试结果、验证日志、训练摘要)
└── data/ddqn_training_log.npz(loss/ε/total reward per step/验证曲线数组)
训练完成后自动在测试集(drop 61~70)上评估,终端输出:
============================================================
DDQN Training Complete
Early stopped: False
Best val mean_rate: 3.52e+06
Test results (drop 61~70):
mean_rate = 3.48e+06
5% rate = 1.21e+06
Jain index = 0.7823
============================================================
| 指标 | 含义 |
|---|---|
| mean_rate | 测试集所有 AS 的平均速率(bps) |
| 5% rate | 5% 分位速率,衡量边缘用户体验 |
| Jain index | 公平性指数,范围 [1/N, 1.0],1.0 = 完全公平 |
DDQN 推理模式(--inference)同样在测试集(drop 61~70)上运行,加载 best 模型、ε=0 纯贪心。
所有仿真结果自动保存至 results/data/,方便后续分析。
| 文件 | 内容 |
|---|---|
{scheduler}_results.json |
汇总统计:set mean/variance、每个 drop 的 sample_mean/variance、Jain index、5% rate、per-AS mean 列表 |
{scheduler}_rate_history.npz |
每个 drop 的原始速率矩阵 (num_as, sim_length),键名 drop_1, drop_2, ... |
| 文件 | 内容 |
|---|---|
ddqn_training_results.json |
测试结果(mean_rate/p5_rate/jain_index)、验证日志、训练摘要(learn steps/final ε/buffer size) |
ddqn_training_log.npz |
训练日志数组(train_step/loss/epsilon)、total reward per step、验证曲线数据 |
import json, numpy as np
# JSON
with open("results/data/pf_results.json") as f:
data = json.load(f)
print(data["set_mean"])
# NPZ
h = np.load("results/data/pf_rate_history.npz")
drop1 = h["drop_1"] # shape: (num_as, sim_length)# 运行完整仿真(4 种算法对比)
python main.py
# 仅运行指定调度器
python main.py --schedulers DDQN
python main.py --schedulers RR PF MaxCI
# DDQN 推理模式(加载已训练模型,不学习)
python main.py --schedulers DDQN --inference
# 指定模型路径
python main.py --schedulers DDQN --inference --model-dir results/ddqn_models
# 调试模式(5 train / 2 val / 2 test drops,10 steps,快速验证流程)
python main.py --schedulers DDQN --debug训练进度通过 tqdm 显示,并附带 DDQN 训练指标:
DDQN (Training): 30%|███████ | 30/100 [12:45<29:45, mean_rate=3.47e+06, ε=0.399, loss=0.0234, buffer=50000]
输出至 results/:
| 文件 | 说明 |
|---|---|
per_sample/sample_*.png |
逐样本步长对比图(基线调度器) |
rate_pdf.png |
速率 PDF 分布图(直方图) |
ddqn_models/ddqn_agent.pt |
DDQN 最终模型权重 |
ddqn_models/ddqn_agent_best.pt |
DDQN 验证集最优模型权重 |
ddqn_training/training_curves.png |
训练曲线(Total Reward / ε / TD Loss) |
ddqn_training/validation_curves.png |
验证曲线(mean_rate / 5%tile / Jain) |
data/{scheduler}_results.json |
基线调度器汇总统计 |
data/{scheduler}_rate_history.npz |
基线调度器原始速率数据 |
data/ddqn_training_results.json |
DDQN 训练汇总(测试结果 + 验证日志) |
data/ddqn_training_log.npz |
DDQN 训练日志数组 |
numpy
scipy
torch
tqdm
matplotlib
安装:pip install -r requirements.txt