简介:这份PPT面向卫星导航与精密定轨方向的学习者与工程人员,系统梳理了在QT环境下搭建Groops定轨流程的完整思路。Groops是用于地球观测与导航系统数据处理的软件,核心功能是高精度卫星轨道确定与数据预处理,资源围绕站信息定义、接收机配置、天线PCO/PCV改正、原始数据转换、LEO数据预处理、GNSS观测值处理、辅助数据应用及高精度轨道计算等环节展开,帮助读者建立从数据准备到精密轨道拟合的整体框架。压缩包共1个pptx文件,约1.47MB,以幻灯片形式呈现流程要点与模块关系,便于对照理解各步骤的输入输出与配置方式。目前已有1619人学习,适合具备一定卫星导航基础、希望深入掌握Groops定轨流程的中高级读者参考。
1. 从一份 PPT 拆出的 groops 定轨全流程:它到底能解决什么
如果你手头有一份groops定轨流程.pptx,翻完第一反应大概率是“步骤真多,但每一步到底在干嘛”。这份材料讲的不是某个孤立算法,而是一套在 QT 环境下把 GNSS 与低轨卫星观测数据一路推到高精度轨道的完整链路:从站信息文件生成、接收机与天线定义,到原始观测数据转换、LEO 数据预处理、辅助力模型配置,最后用 Loop Programs 遍历卫星做精密轨道插值与姿态拟合。它适合已经接触过 GNSS 数据处理、但面对 groops 一堆 cpp 程序和配置文件不知从哪下手的从业者,也适合做低轨卫星精密定轨、需要把观测数据和动力学模型串起来的人。整条流程的核心价值在于:把“数据准备—模型配置—轨道计算”这三段最容易翻车的环节,拆成可逐项检查的工程步骤,而不是丢给你一个黑匣子。
2. 站信息与接收机定义:GnssStationinfoCreate 和 GnssReceiverDefinitionCreate 怎么落地
2.1 先搞清楚这两个程序各自管什么
GnssStationinfoCreate.cpp负责生成 stationinfo 文件,输入是 makerName、makerNumber、approxPosition、antenna、receive,输出是站点或低轨卫星相关信息文件。这里有个容易混淆的点:站点和低轨卫星共用同一套结构,但低轨卫星的很多信息需要手动输入,不能指望程序自动填。GnssReceiverDefinitionCreate.cpp则是定义接收机能观测到的卫星类型和信号类型,输入是 GNSS types,输出是可观测卫星相关信息以及信号类型。两个程序的关系是:前者告诉 groops “这个测站/卫星在哪、用什么天线和接收机”,后者告诉 groops “这个接收机能收到哪些系统的哪些信号”。顺序上我一般先跑 receiver definition,再跑 stationinfo,因为 stationinfo 里的 receive 字段需要和接收机定义对得上。
2.2 手动输入低轨卫星信息时的参数清单
低轨卫星的 stationinfo 不能只靠近似位置糊弄过去,下面这些字段建议提前整理成表,跑程序时逐项核对:
| 字段 | 含义 | 常见取值/注意点 |
|---|---|---|
| makerName | 制造商名称 | 按实际任务填写,不要留空 |
| makerNumber | 制造商编号 | 与 makerName 对应,用于内部索引 |
| approxPosition | 近似位置 | 低轨卫星给的是概略轨道位置,不是地面站坐标 |
| antenna | 天线信息 | 要和后续 PCO/PCV 定义一致 |
| receive | 接收机信息 | 必须与 GnssReceiverDefinitionCreate 输出匹配 |
手动输入时最常见的翻车是 approxPosition 单位搞错。地面站用经纬度高程,低轨卫星用惯性系或地固系直角坐标,两者混用不会报错,但后面轨道拟合会直接跑偏。我一般会在输入前把坐标框架写在注释里,跑完再用简单量级检查一遍:低轨卫星的 approxPosition 模长应该在 6700 km 到 7200 km 之间,如果算出来是 6371 km 左右,那多半是把地面站坐标填进去了。
2.3 接收机定义与天线 PCO/PCV 的衔接
GnssReceiverDefinitionCreate.cpp的输出决定了后面能选哪些观测值。GNSS types 里通常要勾选 GPS、GLONASS、Galileo、BeiDou 四大系统,但具体勾哪些信号类型,取决于你的接收机实际能输出什么。勾多了不会让结果更好,反而会在数据预处理阶段引入大量缺失值。天线 PCO 和 PCV 是绕不过去的:PCO 是相位中心偏移,PCV 是相位中心变化,两者都需要手动输入。程序里gnssAntennaDefintist提供 5 种方式,实际用的时候选fromfile最稳,因为文件里的 PCO/PCV 值可以版本化管理,换天线时只改文件不改代码。new方式适合临时测试,但值设错了很难排查,不建议在正式流程里用。
# 典型调用顺序(示意,具体可执行文件名以实际编译结果为准) ./GnssReceiverDefinitionCreate --gnss GPS,GLONASS,Galileo,BeiDou ./GnssStationinfoCreate --makerName LEO_MK --makerNumber 001 \ --approxPosition 6800000,0,0 --antenna ANT01 --receive REC01上面两条命令的逻辑是:先让接收机定义程序知道要处理哪几个 GNSS 系统,再把站信息写进去。参数里--approxPosition给的是低轨卫星概略直角坐标,单位是米;--antenna和--receive是字符串标识,必须和后续天线文件、接收机文件里的名字完全一致,大小写敏感。如果跑完发现 stationinfo 文件里 receive 字段是空的,先检查接收机定义那一步有没有成功输出对应标识。
3. 原始数据转换与 LEO 预处理:从 inputfileOrbit 到分弧段观测值
3.1 原始数据转换的三类输出
原始数据转换的输入是轨道数据(inputfileOrbit)、姿态数据和观测数据,输出是 groops 格式的 appro、starcamera 和 GNSS observation。这三类文件分别对应:概略轨道、星敏感器姿态、GNSS 观测值。转换时最容易出问题的是时间系统。观测数据的时间标签可能是 GPS 时、UTC 或本地时,而 groops 内部通常按 GPS 秒处理。如果转换前不统一,后面插值出来的轨道和观测值会对不上,对比图看起来就是两条平行线。我一般会在转换脚本里强制做一次时间系统检查,把观测文件头里的时间标识读出来,和轨道文件头比对,不一致就先做时标转换再进 groops。
3.2 用 unique 和 isnan 做数据清洗与分弧段
LEO 数据预处理这一步,材料里提到用uniqe和isnan函数整合数据,删除缺失数据和重复数据,并按设置分为 N 个弧段。这里的uniqe大概率是unique的笔误,实际用法是对时间标签去重。GNSS 观测数据里重复历元通常来自接收机输出抖动或文件拼接,不去重的话后面多项式插值会报奇异矩阵。isnan用来剔除无效观测值,比如信噪比过低或载波相位失锁的历元。
// 伪代码示意:按时间标签去重并剔除无效值 std::vector<Observation> raw = readObservations("gnss_obs.txt"); std::sort(raw.begin(), raw.end(), byEpoch); auto last = std::unique(raw.begin(), raw.end(), [](const Observation& a, const Observation& b) { return a.epoch == b.epoch; // 同一历元只保留第一条 }); raw.erase(last, raw.end()); raw.erase(std::remove_if(raw.begin(), raw.end(), [](const Observation& o) { return std::isnan(o.value) || o.snr < 10.0; // 无效值剔除 }), raw.end());这段逻辑的关键参数是snr < 10.0,这是一个经验阈值,不是固定标准。信噪比阈值设太高会丢掉大量低仰角观测,设太低会把噪声当信号。我一般会先画一张信噪比分布图,看主峰位置,再把阈值设在主峰左侧一个明显低谷处。分弧段时,N 的取值取决于轨道机动和观测连续性,通常按每弧段不少于 30 分钟有效观测来切,太短了动力学模型拟合不出来,太长了中间如果有轨道机动会污染整段。
3.3 轨道和姿态插值到观测历元
LEO 轨道和姿态数据插值,按观测数据的历元时间做,材料里提到多项式插值和最小二乘多项式拟合。这里的选择逻辑是:如果轨道数据本身采样率高于观测数据,用多项式插值就够;如果轨道数据有噪声或采样率低于观测数据,用最小二乘多项式拟合更稳。插值阶数一般取 7 到 9 阶,阶数太低拟合不了轨道曲率,阶数太高会在弧段两端产生龙格现象。姿态插值同理,但要注意四元数插值不能直接对分量做多项式插值,得先转成旋转矢量或做球面插值,否则姿态文件在 180 度附近会跳变。
// 轨道插值示意:按观测历元做 8 阶多项式拟合 for (const auto& epoch : obsEpochs) { auto coeff = polyfit(orbitEpochs, orbitPositions, 8); Eigen::Vector3d pos = polyval(coeff, epoch); interpolatedOrbit.push_back({epoch, pos}); }polyfit的第三个参数 8 是拟合阶数,orbitEpochs和orbitPositions是原始轨道时间和位置。跑完插值后一定要做残差检查:把插值结果和原始轨道在重叠历元上做差,残差应该在毫米到厘米量级,如果到了米级,说明阶数或弧段划分有问题。
4. 辅助数据与力模型配置:EOP、重力场、保守力与非保守力怎么选
4.1 地球定向参数 EOP 的 10 种方式与 TRF-CRF 转换
EOP 的作用是实现 TRF 到 CRF 的转换,材料里说有 10 种方式。实际用的时候不需要全懂,但要知道你选的 EOP 文件覆盖了哪些参数:极移、UT1-UTC、天球中间原点偏差等。如果 EOP 文件里缺少某一段时间的值,groops 可能会用外推,外推精度在几天内还可以,超过一周误差就明显了。我一般会在配置前先检查 EOP 文件的时间覆盖范围,确保它包住整个观测弧段,并且首尾各多留几天余量。
4.2 重力场模型与保守力摄动的 7 种配置
重力场模型支持多种计算方式和阶数选择。阶数不是越高越好,低轨卫星定轨通常用 60 到 120 阶,再高了对轨道精度提升有限,反而拖慢计算。保守力摄动模型有 7 种,每种摄动力单独配置一次。材料里提到默认已有文件:固体潮用 IERS2003、极潮用 IERS2003、海洋潮汐用公式、离心势用公式、soildmoonTide 用 IERS2003。这些默认文件在标准数据包里都有,但要注意版本一致性:如果固体潮用 IERS2003 而极潮用了 IERS2010,两者在极区会有微小不一致,虽然量级不大,但在毫米级定轨里值得统一。
4.3 非保守力摄动:太阳光压、大气阻力与相对论效应
非保守力摄动模型有 5 种,材料里明确提到相对论效用 IERS2010、太阳光压用论文里的 eclipse 取 [0-1]、地球反照率用论文、大气阻力用论文、推力用 marco model。这里有个关键信息:太阳光压和大气阻力虽然可以按常用的 CR 和 CD 方式用对应文件直接计算影响,但下载的数据包里未含有这两类文件。也就是说,如果你直接跑默认配置,这两项要么被跳过,要么用内置简化模型。大气阻力采用 JB2008 大气模型,对应文件是thermosphereJB2008.h;太阳光压采用eclipseConical或eclipseSOLAARS计算。如果要做高精度定轨,我建议不要跳过这两项,而是直接估计大气密度和 ECOM 太阳光压模型参数,让定轨过程自己吸收模型误差。
| 摄动类型 | 默认文件/模型 | 数据包是否包含 | 建议处理方式 |
|---|---|---|---|
| 固体潮 | IERS2003 | 是 | 直接用,注意版本统一 |
| 极潮 | IERS2003 | 是 | 直接用 |
| 海洋潮汐 | 公式 | 是 | 直接用 |
| 离心势 | 公式 | 是 | 直接用 |
| 太阳光压 | eclipseConical / eclipseSOLAARS | 否 | 估计 ECOM 参数或补文件 |
| 大气阻力 | JB2008 | 否 | 估计大气密度或补文件 |
| 相对论效应 | IERS2010 | 是 | 直接用 |
提示:数据包里没有太阳光压和大气阻力文件时,不要强行把对应开关打开却不给文件路径,groops 可能不报错但结果里这两项贡献为零,轨道精度会悄悄变差。
5. GNSS 精密轨道计算与 Loop Programs 避坑排查
5.1 Loop Programs 遍历卫星与 1s 采样插值
GNSS 高精密轨道计算用 Loop Programs 遍历所有卫星,默认定义了期望的 orbitsampling 采样数,按 1s 采样率插值精密轨道,命名为 resample orbit。这一步的输入是精密星历、钟差、姿态文件、EOP 文件等,输出是重采样后的高精度轨道。1s 采样率意味着计算量不小,如果卫星数多、弧段长,内存和磁盘都要提前留够。我一般会先拿一颗卫星跑通全流程,确认 resample orbit 文件里的时间标签和观测历元对得上,再放开遍历所有卫星。
5.2 姿态文件拟合与 XML 创建
给 resampling 轨道拟合姿态文件,并创建 XML 格式文件。姿态拟合的输入是原始姿态数据和重采样后的轨道时间标签,输出是 XML 格式的姿态文件。这里容易踩的坑是姿态坐标系定义:星敏感器输出的姿态可能是相对于惯性系,而 groops 内部可能期望相对于轨道系,转换矩阵搞反了姿态文件看起来正常但动力学积分会发散。检查方法是把拟合后的姿态和原始姿态在几个历元上做差,如果四元数符号相反但旋转等效,那是正常的;如果旋转矩阵差了一个大角度,那就是坐标系定义错了。
5.3 避坑排查:5 条血泪经验
现象一:stationinfo 文件生成成功,但后续程序读不到低轨卫星信息。原因:makerName 或 makerNumber 里带了空格或特殊字符,程序按分隔符解析时截断了。 解决:所有标识字段只用字母、数字和下划线,不要用空格和中文。
现象二:LEO 数据预处理后弧段数为零。原因:分弧段的最小观测数阈值设得比实际有效观测数还高,或者时间标签去重后把整段数据删空了。 解决:先把阈值降到 1,确认有数据输出,再逐步调高到合理值;同时检查 unique 的比较函数是不是把不同观测类型的同一历元也去重了。
现象三:轨道插值结果在弧段两端明显偏离原始轨道。原因:多项式阶数过高导致龙格现象,或者弧段划分太短,端点附近没有足够约束。 解决:把阶数降到 7 或 8,或者改用最小二乘拟合并增加弧段长度;端点附近可以单独用低阶插值。
现象四:太阳光压和大气阻力配置后轨道精度反而变差。原因:数据包里没有对应的 CR/CD 文件,程序用了默认值或零值,相当于引入了错误的力模型。 解决:要么补齐文件,要么在参数估计里把大气密度和 ECOM 参数设为待估,让观测数据自己修正。
现象五:GNSS 精密轨道重采样后,resample orbit 文件时间标签和观测文件对不上。原因:精密星历的时间系统是 GPS 时,而观测文件转换时用了 UTC,两者差了跳秒。 解决:在数据转换阶段统一到 GPS 时,或者在重采样前做一次时标对齐,检查跳秒是否已正确扣除。
6. 高精度轨道准备:从 resample orbit 到可复现的验证习惯
走到高精度轨道准备这一步,流程上其实和前面 GNSS 精密轨道计算有重复:还是 Loop Programs 遍历所有卫星,还是按 1s 采样率插值精密轨道,但这次输入里多了姿态文件、EOP 文件等 GNSS 文件,输出是最终的高精度 GNSS 精密轨道。重复不是冗余,而是把“概略轨道”和“精密轨道”分阶段处理,避免一次配置太多参数导致排查困难。我一般会把这一步拆成三个检查点:第一,确认 resample orbit 文件里的卫星编号和精密星历里的编号一一对应,不能有孤儿卫星;第二,确认姿态 XML 文件的时间覆盖范围包住整个轨道弧段,首尾各多留至少一个采样间隔;第三,确认 EOP 文件在轨道弧段内没有缺值,如果有缺值,要么补文件,要么把缺值段裁掉。
验证方法上,最直接的是做轨道重叠弧段比较:把相邻两个弧段的轨道在重叠时间段内做差,如果差异在厘米级以内,说明弧段拼接一致;如果到了米级,说明力模型或姿态数据有问题。另一个方法是把定轨结果和外部精密轨道产品做对比,但要注意外部产品的参考框架和时间系统是否一致,不一致的话先做框架转换再比较。参数方面,1s 采样率是材料里明确的默认值,实际用的时候如果观测数据采样率更低,可以适当降低重采样率来节省计算资源,但不要低于观测采样率,否则会丢失观测信息。
# 验证 resample orbit 与观测历元对齐的简易检查 awk '{print $1}' resample_orbit.txt | sort -u > orbit_epochs.txt awk '{print $1}' gnss_obs.txt | sort -u > obs_epochs.txt comm -3 orbit_epochs.txt obs_epochs.txt | head -20这段脚本的作用是找出轨道历元和观测历元的不一致项。comm -3会输出只在其中一个文件里出现的行,如果输出为空,说明两者完全对齐;如果有输出,就要看是轨道多了还是观测多了,再回到对应步骤排查。参数上没有什么需要调的,关键是养成习惯:每次改完配置或换数据包,都先跑一遍这个检查,再进正式定轨。
从那以后我每次拿到新的 groops 数据包,都强制走一遍“站信息—接收机—数据转换—预处理—力模型—重采样—对齐检查”这条链,哪怕只换了一颗卫星,也不跳过任何一步。希望帮到你。
本文还有配套的精品资源,点击获取