简介一套面向低地球轨道LEO卫星网络研究的高完整性仿真框架适用对象为卫星通信领域的研究人员、工程师及高校相关专业学生可支撑星座布局设计、链路级仿真、协议评估与覆盖规划等任务。包内共312个文件以py脚本、plt绘图文件、h/cc/cpp源码、txt说明、sh脚本与md文档为主深度覆盖Hypatia框架的轨道动力学、射频传播、网络协议、资源管理等模块压缩包约33.63MB目录结构清晰便于直接复用和二次开发。已有449人学习/下载。借助该框架用户可基于Hypatia示例场景快速开展卫星星座优化、干扰分析、通信协议对比等仿真实验并结合辅助脚本完成参数调整与结果可视化框架内置多种星座配置、TCP/IP及DVB-S2X协议模拟、频率分配与功率控制策略适合需要系统理解LEO网络行为并开展定量研究的开发者。1. 低地球轨道仿真为什么值得自己跑一遍Hypatia 框架与这份源码能解决什么低地球轨道(LEO)卫星网络这几年从论文一路走进了工程部署星间激光链路、星地 Ka 链路、以及每几十秒就变一次的拓扑让地面网络那套配好静态路由然后压测的仿真思路直接失效。Hypatia 是一个基于 ns-3 的开源 LEO 卫星网络仿真框架这份 zip 里装的是它最核心的十几个源文件覆盖了星座拓扑、星地链路、激光星间链路和路由仲裁四个层面。它解决的问题很具体我的星座在某个纬度覆盖怎么样、一条端到端路径的延迟是多少、星间链路带宽够不够、贪心路由会不会绕路。这些都不需要发射卫星在仿真里跑一遍就有量化结果。适合的人群也清楚做卫星通信的研究生、做星座规划的系统工程师、写星载路由协议的开发者。下面我会按文件分工 → 搭起来跑 → 调参 → 避坑 → 校验的顺序展开所有命令和参数都以能落地为准。2. 先拆文件再看架构十个源文件的分工与 ns-3 的接口设计这份源码最大的特点是麻雀虽小五脏俱全。拿到手不要急着编译先把文件名的规律摸清楚后面排查问题会省一半力气。这里先给一张速查表再分三节细讲。源文件职责关键点iers-data.cc地球定向参数(EOP)数据dUT1、极移、UT1-UTCjulian-date.cc儒略日与时间换算JD、历元、时间系统constants-gen.cc星座常量生成轨道根数、查表加速satellite.cc卫星节点位置、轨道、转发topology-satellite-network.cc星座拓扑构建轨道面×每轨卫星数gsl-net-device.cc星地链路设备射频、可见性判断gsl-channel.cc星地信道动态时延、衰减point-to-point-laser-net-device.cc激光星间链路设备全双工、动态时延point-to-point-laser-helper.ccISL 安装助手ns-3 helper 模式arbiter-single-forward-helper.cc路由决策单跳贪心转发2.1 时间与坐标是 LEO 仿真的地基julian-date、iers-data 与 constants-gen 的作用LEO 卫星的轨道位置通常在地心惯性系里描述地面站坐标却在地球固连系里。两个坐标系之间的夹角由格林尼治恒星时决定而恒星时要靠儒略日算出来。julian-date.cc 干的就是公历时刻 ↔ 儒略日的换算它是整个坐标转换链的第一环改错一个历元偏置后面所有卫星位置都是偏的。iers-data.cc 提供的是地球定向参数EOP。真实地球的自转轴会摆动极移自转速度也不均匀UT1 和 UTC 之间最大能差到 0.9 秒。别小看这 0.9 秒LEO 卫星速度约 7.8 公里每秒乘起来就是约 7 公里的位置误差足够让一个 30GHz 的窄波束星地链路彻底对不上。所以 iers-data 不是可选项而是精度底线。我一般会在仿真初始化时一次性读入这张 EOP 表按儒略日查表并做线性插值。constants-gen.cc 则是一个生成器它把轨道面数、每轨卫星数、倾角、高度、相位因子展开成每颗卫星的轨道六根数常量表。Hypatia 这么设计是为了运行时快几百颗星的轨道不用现场解方程查表就行。代价是改一次星座参数就要重新跑一次生成器。这里面最容易翻车的是相位因子它决定相邻轨道面的卫星错开多少直接影响星间链路能不能建立别随手设成 0。2.2 两条链路两类信道GSL 射频链路与 point-to-point 激光 ISLGSL星地链路走的是射频典型工作在 Ka 频段。gsl-net-device.cc 是挂在卫星和地面站节点上的网卡gsl-channel.cc 是它的信道。每次发包信道会拿着两端设备的位置算一次瞬时距离用这个距离生成传播时延再算接收功率。可见性判断用的是地面站仰角大于最小仰角低于阈值链路直接 down。这个最小仰角是 GSL 仿真里最影响结果的参数之一。同样 1100 公里的轨道高度仰角门限从 10° 提到 40°单条链路的斜距能差出一倍以上——低仰角门限下链路多、时延大、信号弱高仰角门限下链路变少但质量好。这就是星地链路的经典折中。ISL星间链路走的是激光。point-to-point-laser-net-device.cc 在语义上继承了 ns-3 里 PointToPointNetDevice 的无差错、固定速率、全双工模型但把固定链路时延替换成了由当前两星几何距离决定的动态时延。同一轨道面前后相邻的两颗星相对位置稳定激光链路常年可用相邻轨道面的两颗星相对速度大距离和指向都在变仿真里通常用最大链路距离来约束。helper 文件在 ns-3 里承担安装职责把设备属性设置好再挂到信道上。point-to-point-laser-helper.cc 干的就是这件事。这里我想强调一个理解这份源码的关键文件名里的 net-device、channel、helper 就是 ns-3 留给新链路的三层接口。网上常说的卫星网络中的接口指的就是这套抽象搞懂了它加一种新链路只是照葫芦画瓢。2.3 卫星节点、星座拓扑与单跳转发路由satellite.cc、topology 与 arbiter-helpersatellite.cc 实现的是轻量卫星节点主要职责是位置 转发不跑完整协议栈。它保存轨道参数提供按时刻查询位置和速度的接口。理解成会移动的网络节点就行不要想复杂。topology-satellite-network.cc 负责把 N 个轨道面 × M 颗卫星摆成一个星座给每颗卫星算四个 ISL 邻居同轨道面前后两颗、相邻轨道面各一颗再根据地面站位置和最小仰角建立 GSL 连接关系。LEO 拓扑是随时间变化的不能像地面网那样把邻居关系当常量所以这个类同时维护拓扑的快照更新。arbiter-single-forward-helper.cc 是路由决策的核心名字里的 single forward 指的是单跳贪心转发。原理很朴素卫星收到包以后遍历自己的 ISL 邻居和自身 GSL计算每个候选下一跳到目的地面站的距离把包交给距离最近的那个。这样每颗星只靠本地邻居信息就能决策复杂度是 O(邻居数)不需要任何全局状态非常适合卫星上算力有限的场景。代价是贪心不一定最优。在星座边缘、极区、或者相邻轨道面链路断开的时候局部最近的选择可能把包带进死胡同表现为跳数突增、时延变大。Hypatia 常见的做法是再提供一个 Dijkstra 风格的全局路由仲裁器做对比实验这份 zip 里只带了 single-forward 这一种够用来理解机制。3. 把 zip 变成能跑的仿真编译、星座配置与运行检查这一章的目标只有一个让这份源码在你的机器上编译通过并且跑出带日志的仿真。先把环境说清楚再给配置骨架最后讲怎么确认仿真真的在动。3.1 环境准备目录放置与 waf 构建这份源码是 ns-3 的模块不是独立工程。先解压 zip把整个 hypatia 目录放到 ns-3 的 src 目录下去。unzip leo_hypatia.zip -d ~/ns3-workspace mv ~/ns3-workspace/hypatia ~/ns3-workspace/ns-3/src/hypatia cd ~/ns3-workspace/ns-3 ./waf configure --enable-examples --enable-tests ./waf build这里有几个关键点。第一解压路径别带中文和空格ns-3 的构建系统对路径很敏感。第二hypatia 目录必须落在 src/ 下面构建系统只扫描这个目录下的模块放错位置就会静默跳过。第三这份源码的年代对应的是 waf 构建的 ns-33.3x 这一代如果你手里是 3.37 之后的版本构建系统已经换成了 CMake编译方式会不一样。./waf build跑完后在输出里搜一下 hypatia 关键字确认模块确实被编译进去了。这一步不查后面所有缺头文件的报错都会让你怀疑人生。3.2 定义星座参数一个可改的 demo 骨架在 scratch 目录下建一个 demo 文件核心是把星座和链路参数暴露成变量。下面这个骨架的类名和方法名以你解压出来的头文件为准我这里的重点是参数含义不是 API 签名。// scratch/leo-demo.cc —— LEO 星座仿真骨架接口名以解压后的头文件为准 #include ns3/core-module.h #include ns3/network-module.h #include ns3/hypatia-module.h using namespace ns3; int main(int argc, char *argv[]) { uint32_t orbits 6; // 轨道面数 uint32_t satsPerOrbit 12; // 每轨道面卫星数共 72 颗 double altitude 1100e3; // 轨道高度 1100 km单位米 double inclination 53.0; // 轨道倾角 53 度 double phaseFactor 0.5; // Walker 相位因子错开相邻轨道面 DataRate gslRate(1000Mbps); // 星地链路速率 1 Gbps DataRate islRate(10Gbps); // 激光星间链路速率 10 Gbps double minElevation 25.0; // GSL 最小仰角 25 度 // 创建拓扑对象并写入星座参数 PtrTopologySatelliteNetwork topo CreateObjectTopologySatelliteNetwork(); topo-SetOrbits(orbits); topo-SetSatellitesPerOrbit(satsPerOrbit); topo-SetAltitude(altitude); topo-SetInclination(inclination); topo-SetPhaseFactor(phaseFactor); topo-SetGslRate(gslRate); topo-SetIslRate(islRate); topo-SetMinElevation(minElevation); topo-Build(); // 生成卫星、GSL 与 ISL 链路 Simulator::Run(); Simulator::Destroy(); return 0; }参数里最需要解释的是两组。轨道面数 6 × 每轨 12 颗 72 颗这是经典 Walker 星座规模的缩小版够跑通流程又不至于让仿真慢到没法等。高度 1100 公里是 OneWeb 一类的典型值单跳 GSL 时延在 6 毫秒量级如果你改到 550 公里Starlink 风格单跳时延会降到约 3 毫秒但覆盖半径也变小需要的卫星总数会变多。ISL 速率特意比 GSL 高一个数量级这是符合现实的配置星地链路才是瓶颈星间链路要留足余量。如果你把两处速率设成一样星座内部会先开始排队你做延迟实验时会把排队延迟误当成传播延迟。3.3 编译运行与日志检查编译运行用 waf 的 run 命令输出重定向到文件再过滤关键日志。./waf --run scratch/leo-demo 21 | tee run.log grep -E ISL|GSL|Delay run.log | head -50第一次跑通过后至少要确认两件事。第一ISS 链路日志里有没有 ISL up 的记录72 颗星、每颗 4 条星间链路理论上初始化时应该出现约 144 条 ISL 链路每条链路会被两端各记录一次所以看到 144 上下是正常的数量对不上说明拓扑生成有问题。第二连续观察同一个 GSL 链路的时延数值在不在变化——如果从头到尾纹丝不动说明卫星位置没有被更新仿真可能只是搭了个静态拓扑这对 LEO 来说等于没仿真。如果运行时报段错误优先怀疑星星座参数越界比如轨道面数小于 3 或者相位因子导致链路重复建立。把参数换回上面的默认值再跑一次能过就是参数问题。4. 参数怎么调高度、带宽与路由策略的三组取舍跑通只是开始真正花时间的是调参。LEO 仿真里参数互相牵连我把最常见的三组取舍讲清楚你改参数的时候心里就有数了。4.1 轨道高度延迟、覆盖与卫星数量的三角关系高度是第一个要动的参数因为它同时影响延迟、覆盖和卫星总数。下面这张表是用 30° 最小仰角算出来的典型值。轨道高度 (km)单跳 GSL 斜距 (km)单跳 GSL 时延 (ms)同轨相邻星弧距 (km)星数需求550约 10003.3约 1970高需要上千颗星做全球覆盖1100约 18506.2约 3900中1500约 24008.1约 5300低这里有个经常被忽略的点同轨相邻星的弧距在高轨道上会变得很大。1100 公里高度、每轨 12 颗星同轨两颗相邻卫星的距离接近 3900 公里激光链路单向时延就有 13 毫秒这比单跳 GSL 时延还大。也就是说跨多跳星间链路的延迟主要贡献是 ISL 而不是 GSL。所以调高度的逻辑不是越低越好或越高越好而是看你的仿真目标。做覆盖仿真低轨高星数是优势做端到端延迟仿真要综合 GSL 和 ISL 两部分把同轨星数加多弧距变小比单纯降高度更有效。4.2 GSL 与 ISL 参数带宽比、频率与最小仰角链路参数我一般分成两类调一类是速率一类是物理层参数。速率方面ISL 和 GSL 的带宽比建议保持在 5:1 以上。现实中激光星间链路做到 10 Gbps 并不难而星地 Ka 链路通常几百 MHz 带宽换算成速率上限也就在 1 Gbps 量级。如果你在仿真里把它们设成等带宽星间链路先变成瓶颈端到端吞吐会虚低这时候的延迟数据没有参考价值。物理层参数里GSL 重点是载波频率和最小仰角。Ka 频段一个典型配置是上行 28 GHz、下行 18 GHz发射功率 10~30 dBW天线增益 30~40 dBi。注意 Ka 频段雨衰非常可观重雨条件下附加损耗可以到十几 dBns-3 默认模型里没有雨衰常见做法是在 gsl-channel 外面再挂一个随降雨率变化的附加损耗函数。最小仰角我建议从 25° 起步看覆盖结果再降到 20° 或升到 35°每 5° 一档做对比。ISL 方面激光波长一般取 1550 纳米光通信最成熟的窗口链路速率按星座总吞吐反推。还有一个隐藏参数是最大链路距离它限制了邻轨 ISL 能否建立。这个值必须覆盖同轨相邻两星的弧距否则会出现同轨链路都断了的诡异现象。4.3 路由策略单跳转发的代价与观察手段single-forward 路由是本地贪心它没有全局视图每个转发决策只保证这一步更近不保证整体路径最优。在仿真里观察这个代价最直接的手段是打印每个包的跳数。做法是在路由仲裁器里加一行日志输出当前包的下一跳选择和累计跳数。然后选一对距离很远的地面站手算理论最小跳数两点经度差除以单跳 ISL 的角跨度得到下限。如果仿真出来的实际跳数比这个下限大一半以上基本就是贪心绕路了——常见触发场景是极区那里所有轨道面汇聚本地最近的选择会把包带向极点再折回来。想验证这个判断可以把仲裁器换成 Dijkstra 风格的全路径路由做对比实验。同一场景下Dijkstra 的跳数和时延会比 single-forward 低一截这个差值就是贪心策略的真实代价。换路由仲裁器需要改代码并重新 waf build但这是理解 LEO 路由问题最值得做的实验。5. 避坑排查Hypatia 的五个典型翻车点与定位方法这部分内容来自我实际跑这类 ns-3 卫星模块的血泪经验。每一条都按现象 → 原因 → 解决写你可以直接当排查手册用。5.1 编译期找不到 gsl-net-device.h模块没进构建系统现象./waf build报fatal error: ns3/gsl-net-device.h: No such file or directory。原因hypatia 模块没有被构建系统收录。最常见的是目录没有放在 src/ 下面或者放在了 src/ 下面但 build 缓存没刷新。解决先确认目录结构然后清掉 build 产物重新配置编译。ls ~/ns3-workspace/ns-3/src/hypatia rm -rf build ./waf configure --enable-examples --enable-tests ./waf build 21 | grep -i hypatia如果 grep 没有输出说明模块没被扫描到如果编译报错但报错文件来自别的地方那就是模块依赖顺序问题把 hypatia 目录名改成字母序靠前的名字比如 aaa-hypatia可以绕过。5.2 全是 GSL 没有 ISL相位因子与最大链路距离现象日志里 GSL 链路频繁 up/down但 ISL 从头到尾一条都没有。原因两个常见根因。其一是 Walker 相位因子设成了 0相邻轨道面的卫星在相同时刻处于相同纬度相对位置要么贴近要么错开导致邻轨 ISL 被最大距离约束剪掉其二是激光链路的最大距离参数没有跟着轨道高度调整1100 公里高度下同轨相邻星弧距约 3900 公里如果最大距离只有 2000 公里ISL 全断。解决把相位因子设到 0.25~0.5 之间然后按公式2*(地球半径轨道高度)*sin(π/每轨星数)计算同轨弧距把 ISL 最大距离设成这个值的 1.3~1.5 倍留出轨道摄动余量。5.3 端到端时延比手算高 40%排队延迟和传播延迟先分开现象仿真输出的端到端时延是 15 毫秒手算的几何传播时延只有 10 毫秒出头怎么都对不上。原因排队延迟混进了你的统计里。链路速率设得太低、发包间隔太密时包会在卫星节点的设备队列里排队这个时间算进端到端时延和传播时延是两码事。解决先找到日志里同时输出的传播时延和排队时延分量把它们分开看。然后把发包间隔调大到 10 毫秒一个包再看端到端时延是否回落到几何值附近。如果回落说明传播建模没问题是排队在干扰你的结论如果没回落才需要去查链路是不是绕路了。5.4 卫星位置跳变时间系统错位与 IERS 数据缺失现象打印同一颗星在相邻仿真时刻的位置坐标跳了几百公里。原因时间系统没对齐。最常见的是儒略日换算里的历元偏置写错J2000 历元对应的儒略日是 2451545.0错一位就是几百年其次是 IERS 数据表没有在初始化时加载仿真只能用 UT1≈UTC 的近似误差最多约 0.9 秒折算成轨道位移约 7 公里。解决先查 julian-date.cc 里的历元常量再确认 iers-data.cc 的数据表在初始化时被读入并做了插值。一个快速验证办法是打印某颗星在一个轨道周期约 90 分钟前后的位置应该基本回到起点偏差不超过几十公里才对。5.5 内存涨到被杀死日志、构建类型与分步定位现象仿真跑到第 60 秒左右内存持续上涨最后被系统 OOM 杀掉。原因日志全开NS_LOG 设为 ALL、debug 构建下每个事件都带大量检查或者 trace 回调在每个包上重复注册。LEO 仿真里包数量和链路变更频率都很高小泄漏会被放大成 OOM。解决先把日志级别关到只剩错误级换成 release 构建然后把仿真时间拆成 10 秒一段跑先确认无业务流量时内存稳定再逐步叠加业务流量。如果加流量才涨重点查 trace 回调注册如果无流量也涨重点查拓扑刷新的内存释放逻辑。6. 结果校验与批量调参把仿真跑成可信实验的两个习惯仿真跑出来的数字只有经过理论校验才值得写进报告。这一章讲两个我每次必做的动作做完之后参数扫描的结果才敢往外拿。6.1 用自由空间损耗公式做基线校验第一个动作是手算一对链路的理论值和仿真输出对一下。自由空间损耗公式在 30GHz、1850 公里斜距下的典型结果可以这样算import math c 299792458.0 # 光速m/s f_gsl 30e9 # GSL 载波频率 30 GHz d_gsl 1850e3 # 1100 km 高度、仰角 30° 的斜距 delay_gsl d_gsl / c # 单向传播时延 fspl 20 * math.log10(d_gsl) 20 * math.log10(f_gsl) - 147.55 print(fGSL 单向时延 {delay_gsl*1000:.2f} ms) print(f自由空间损耗 {fspl:.1f} dB)公式里的 147.55 是常数推导结果20*log10(4π/c)它的作用是让距离以米、频率以赫兹为单位时直接相加得出 dB 值。这段代码跑出来单向时延约 6.2 毫秒损耗约 182 dB。然后去仿真日志里找对应的那条 GSL 链路的时延和接收功率误差在 5% 以内才算链路建模可信。误差偏大时先检查斜距是不是你预期的值——很多时候是仰角门限不一样导致配了另一条链路。6.2 参数扫描脚本与小场景先行校验通过后批量调参才有意义。下面这个脚本扫描最小仰角对平均时延的影响前提是你的 demo 用 CommandLine 接收 MinElevation 参数import subprocess def extract_avg_delay(log_text): # 假设日志里有一行 AverageDelay 6.21 ms for line in log_text.splitlines(): if AverageDelay in line: return float(line.split()[1].strip().split()[0]) return None for elev in [20, 25, 30, 35, 40]: tmpl f--command-template%s --MinElevation{elev} cmd [./waf, --run, scratch/leo-demo, tmpl] out subprocess.run(cmd, capture_outputTrue, textTrue).stdout print(felev{elev}, avg_delay{extract_avg_delay(out)} ms)脚本本身很简单但有两个习惯比脚本更重要。第一每次改参数之前先跑一个 20 秒的小场景确认时延和手算基线一致再放大到完整仿真——在错误拓扑上调一整晚参数是最亏的事。第二日志解析脚本要写稳定碰到缺字段就报错而不是静默返回 None否则你分析半天用的可能是不完整的数据。从那以后我每次拿到陌生的仿真源码包第一天只做一件事手算一对链路的时延和损耗把仿真输出贴上去对。对得上才继续调参数对不上就先查时间系统、查链路选择、查路由路径直到理论值和仿真值咬合。这个习惯帮我挡掉了不少次在错误拓扑上浪费整晚的窘境。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?