
做定位解算这些年我踩过最深的坑之一就是对流层延时。卫星钟差、轨道误差、电离层这些误差源各有各的脾气但真正让我在数据处理时反复折腾的往往是这个看起来不大不小的对流层延时——天顶方向上撑死也就是两米多听起来好像不怎么夸张可它实实在在地卡在所有单点定位和精密定位的处理流程里一不留神就让高程偏出去几十厘米甚至更多。这篇就专门把它拎出来说透GPS信号穿过对流层时到底发生了什么我们手里有哪些模型可以用以及在实际解算中应该怎么对付它。这不只是给搞科研的朋友看的。平时做测量、跑无人机、用RTK、写PPP代码的人都会遇到对流层延时挖的坑。把这套东西吃透你就明白为什么下雨天定位会飘为什么低仰角的卫星有时候反而帮倒忙也知道该用什么手段把这些误差压下去。1. 先说清楚信号穿过大气层时发生了什么1.1 对流层和GPS信号的“折射”关系很多人以为GPS信号从卫星下来走的是真空中的直线时间就等于几何距离除以光速。但现实不是这样的信号从两万公里左右的高度一路落到地面要穿过整个大气层其中从地表往上大约十到五十公里这一片就是我们常说的对流层和部分平流层区域在GPS定位领域习惯统称为“中性大气层”。信号进入这片区域后介质的折射率大于1传播速度就会变慢。你可以把它想象成光从空气斜着射进水里不光方向发生偏折传播速度也会改变走同样的路程会多花一点时间。GPS测距的原理是测信号从卫星到接收机的飞行时间时间慢了解算出来的距离就变长了。这个多出来的伪距就叫对流层延时英文一般写tropospheric delay也有人叫对流层延迟。这里有一个特别容易踩的认知误区很多人一听“对流层延时”以为它跟电离层延时一样能用双频接收机干掉。这正是对流层延时最阴险的地方——中性大气对GPS信号来说是非色散的也就是说L1和L2两个频段的信号在经过对流层时受到的延迟量几乎一模一样。双频消电离层组合是把两个频率上的电离层延迟之差消掉但碰上对流层延时它一点办法都没有而且还会把残余误差进一步放大。所以对流层延时必须靠建模或者其他手段处理不能指望双频一锅端。1.2 干延迟、湿延迟谁才是真正的“主角”对流层延时可以拆成两个分量干延迟和湿延迟。干延迟由大气中的干燥气体主要是氮气和氧气引起湿延迟则来自大气中的水汽。干延迟占了总延迟的大头。在天顶方向标准大气压约1013.25 hPa、温度15摄氏度的情况下干延迟大约有2.3米。这个值相对稳定可以用气象参数建得很好。湿延迟在天顶方向大约只有0.1到0.4米看起来不大但它恰恰是所有误差源里最难缠的。原因很简单水汽在大气里的分布极不均匀空间上可能几百米就变个样时间上可能一阵风过来就变了而且它的变化没有任何规律可言。热带地区水汽充足湿延迟的波动更大高海拔干燥地区湿延迟就小很多。我自己的经验是干延迟虽然数值大但它就像一个安静的老实人给它模型就能压住。湿延迟则是那个随时都在搞事的家伙数值不大但方差很大模型修完还剩不少残差而且残差会随风、降雨、昼夜温差剧烈波动。这也是为什么雨天或者高湿环境下单点定位的精度会肉眼可见地变差尤其是在垂直方向。2. 延迟有多大什么时候最头疼2.1 天顶方向2米出头不是小数目有人可能觉得才2米多现在消费级GPS的精度也就几米这点误差无所谓吧问题在于如果你完全不对流层延时做修正它在伪距里是以系统误差的形式存在的而且所有卫星的信号都带有这个误差只是大小不同而已。定位解算时这些带方向的误差会被“分配”到各个待估参数上受影响最大的往往是接收机天顶方向也就是高程分量。我之前做过一个对比实验用同一组静态观测数据一组加对流层模型修正一组完全不加最后解算出来的平面位置可能只差个几十厘米但高程能差出去一米多。而且这个差值跟观测卫星的分布高度相关卫星少、几何构型差的时候误差会被放大得更厉害。再说直白一点2.3米的天顶干延迟如果不处理相当于在高程方向给你叠了一个一层楼多高的系统偏差。就算做相对定位只要基线不是足够短两端测站的大气状态不完全一致残余的对流层延时依然会影响高程精度。搞测量的人都知道平面精度容易做高程精度才是真正考验人的地方对流层延时就是主要元凶之一。2.2 低仰角的“延迟放大效应”有多恐怖对流层延时跟卫星仰角的关系非常密切。卫星在头顶的时候信号从垂直方向穿过大气层走过的延迟路径最短近似等于天顶方向延迟。当卫星靠近地平线的时候信号几乎是擦着地表斜着穿过整个大气层路径大大加长延时也随之迅速增大。最粗糙的近似模型是投影函数把天顶方向的延时除以仰角的正弦值也就是1/sin(仰角)。拿这个算一下天顶方向延时2.4米在仰角30度时延迟就变成约4.8米到仰角10度时直接飙到约13.8米。虽然真实的映射函数不会这么线性爆炸但低仰角时延迟增大几倍甚至上十倍是客观事实。这带来一个两难局面低仰角的卫星能改善几何构型让定位解算的精度因子DOP更好看但代价是它们携带的对流层延时误差非常大而且很难建准。我自己处理数据时通常会把仰角掩码设在10到15度低过这个阈值的卫星宁可不用。你看着DOP值降下去了实际定位结果反而可能更差这种赔本买卖不能做。2.3 对流层延时和坐标误差的方向特征对流层延时还有一个特点它对水平分量和高程分量的影响是不对称的。由于接收机上空的对流层近似呈水平层状结构天顶方向是延迟最大的方向而这个方向在定位解算里基本对应着高程分量。所以对流层延时解算不完的时候通常表现为高程方向的系统性偏差而不是平面坐标的偏移。在实际项目中我见过不少人在平面坐标没问题的情况下高程忽高忽低怎么找原因都找不到最后才发现是对流层模型的参数设置不对或者用的气象数据离测站太远。所以做高精度高程测量时对流层延时怎么处理是绕不开的核心问题之一。3. 模型怎么选Saastamoinen、Hopfield、映射函数3.1 Saastamoinen模型的公式与手算步骤对作GNSS数据处理的人来说Saastamoinen模型应该是背得最熟的一个。它的天顶方向对流层延时公式并不复杂ZTD 0.002277 / cos(z) × [P (1255/T 0.05) × e − B·tan²(z) δR]这里z是天顶距也就是90度减去卫星仰角P是测站处的大气压强单位hPaT是绝对温度单位Ke是水汽分压单位hPa。B和δR是两项较小的修正项在常规仰角可以查表或者忽略对最终结果的影响一般只有毫米级到厘米级。实际工程里更常用的是把天顶方向延时算出来再配合投影函数得到任意方向的延时。天顶方向的总延迟可以分成干、湿两部分分别计算ZHD 0.002277 × PZWD 0.002277 × (1255/T 0.05) × e算一个具体的例子。假设测站处气压P1013.25 hPa温度T288.15 K15摄氏度水汽压e11.5 hPa那么干延迟约等于0.002277×1013.252.307米湿延迟约等于0.002277×(1255/288.150.05)×11.5≈0.115米天顶总延迟约为2.422米。这个量级和实际观测结果是吻合的。代码如下我用了好几年顺手放这import math def saastamoinen(P, T, e, E): Saastamoinen 对流层延迟估算 P : 大气压 (hPa) T : 绝对温度 (K) e : 水汽分压 (hPa) E : 卫星仰角 (deg) 返回: 干延迟, 湿延迟, 天顶总延迟, 投影到E方向的总延迟 (m) z math.radians(90.0 - E) cosz math.cos(z) zhd 0.002277 * P zwd 0.002277 * (1255.0 / T 0.05) * e ztd zhd zwd # 简单投影函数 1/cos(z)低仰角时精度下降 delay_dir ztd / cosz return zhd, zwd, ztd, delay_dir zhd, zwd, ztd, delay saastamoinen(1013.25, 288.15, 11.5, 30) print(f天顶干延迟: {zhd:.3f} m) print(f天顶湿延迟: {zwd:.3f} m) print(f天顶总延迟: {ztd:.3f} m) print(f30度仰角方向延迟: {delay:.3f} m)跑出来大约是干延迟2.307米、湿延迟0.115米、天顶总延迟2.422米30度仰角方向投影后约4.844米。这个量级可以用来当日常估算的尺子。3.2 Hopfield模型的思路和局限Hopfield模型比Saastamoinen更早但思路很直观。它假设大气折射率N在地表处有一个初始值然后随着高度向上按四次方衰减直到某个等效高度处衰减为0。其中干大气的等效高度大约取42到43公里湿大气大约取11到12公里。基于这个假设天顶干延迟可以写成ZHD ≈ 1.552×10⁻⁵ × (P_s/T_s) × (h_d − h_s)其中P_s和T_s是测站处的气压和温度h_d是干大气等效高度h_s是测站海拔。代入海平面标准气象参数算出来的结果也是2.3米左右。湿延迟的形式类似但需要用湿折射率和水汽相关的等效高度。用下来的感受是Hopfield模型在标准大气条件下表现不错但它的四次方衰减假设毕竟是对真实大气的一种近似。强对流天气、温度逆温层、海拔剧烈变化的情况下模型残差会比Saastamoinen大一些。它的优势在于参数少、好实现适合嵌入式设备或者实时解算里对计算量敏感的场景。精度要求高的话还是用Saastamoinen或者更新一点的GPT系列经验模型更靠谱。3.3 映射函数把天顶延迟挪到观测方向模型算出来的通常都是天顶方向延迟可卫星在绝大多数时间不在头顶所以需要一个映射函数把天顶延迟换算到实际的观测仰角方向。最简单的映射函数就是1/sin(仰角)也就是1/cos(天顶距)。这个玩意在仰角大于30度时还算能看仰角一低误差就大幅增加因为真实的大气是弯曲的、水平分层不是均匀的斜路径跟平面投影差别很大。现代GNSS数据处理里用的多是Niell映射函数、VMF1或者GMF这类。它们把映射函数写成带系数的连分式展开干延迟和湿延迟分别用不同的系数系数根据测站纬度、高程和年积日来计算或查表。VMF1是目前公认比较准的但它需要外部气象数据和数值天气模型的格网产品支持不是随便跑个公式就能拿到。GMF则是一个经验模型在没有实测气象数据时也能用效果还不错。实际项目中如果你的需求是事后精密处理直接使用GAMIT、Bernese这类软件内置的映射函数和模型就行但如果自己写代码做PPP或者对流层水汽反演GMF或VMF1的代码还是要准备一份。4. 实操中压制对流层延时的几种主流打法4.1 差分定位短基线的“天然抹除器”对流层延时在地理空间上有很强的相关性。如果测站A和测站B距离很近比如几公里到十几公里它们上方的大气状态非常接近信号到两个测站的对流层延时也基本相同。这时候做差分定位不管是RTK还是静态后处理差分解对流层延时这一项基本就被差分操作直接干掉了。这也是为什么RTK在短基线下能实现厘米级定位的核心原因之一。基线越短差分之后残留的对流层延时误差越小通常小于一厘米。但基线一旦拉长到几十公里两个测站的大气状态开始出现明显差异差分之后残留的对流层延时就会增大。长基线RTK、网络RTK这时候就引入了区域大气误差建模把各个参考站的大气延迟内插到流动站位置本质上还是在对付对流层延时。我个人的建议是如果做RTK测绘尽量别指望在超长基线下还能获得稳定厘米级精度哪怕网络RTK给了你虚拟参考站你也需要看看当前测区大气活跃程度。雷雨季节、冷锋过境这种天气剧烈变化的时候区域大气误差梯度很大网络RTK的内插效果也会打折扣。4.2 精密单点定位中的参数估计单点定位无法靠差分消掉对流层延时所以精密单点定位PPP的做法是先用模型把大部分延迟算掉剩下的残差作为未知参数估计出来。PPP处理中通常把天顶对流层总延迟ZTD设为待估参数一般建模为随机游走过程配合高度角相关的投影函数把所有卫星观测值一起约束解算。这个过程有点像先给一个初值再让数据自己说话。初值一般用Saastamoinen模型加标准气象参数给定然后通过卡尔曼滤波逐步更新ZTD。当观测数据足够多、几何构型好时PPP解算出的ZTD精度可以达到几毫米到一厘米级别这已经能满足高精度定位需求也支撑起了GNSS气象学里水汽反演这个方向。这里要提醒一点消电离层组合虽然能把电离层延迟消掉但对流层延迟不会因为组合而被消除反而因为组合系数的原因ZTD的估计误差会被放大。如果做双频PPP分析残差你会发现ZTD参数和后验残差是高度耦合的。处理不当ZTD估计值会吸收掉一部分其他误差源的信号导致高程分量失真。4.3 气象数据的采集与模型参数处理不管用Saastamoinen还是Hopfield都需要输入测站的气压、温度和水汽压。很多GNSS接收机周边没有配气象传感器大家就直接用标准大气模型的经验值凑合。这在小范围内、非极端天气下问题不大但高精度应用就不太够了。我之前在山区做过一个项目测站海拔在3000米左右气温比海平面低很多气压也只有海平面的七成左右。如果偷懒用标准海平面气象参数套进去干延迟算出来多了接近一米最后高程结果自然一塌糊涂。所以海拔超过一定范围后要么用实测气象数据要么用改进的经验模型——比如GPT2/GPT3这类全球气压温度模型它可以根据测站的经纬度和高程给出比较合理的气象参数。另一个容易被忽视的细节是水汽压的计算。很多人从相对湿度反推水汽压时公式选错了或者用的是饱和水汽压而不是实际水汽压导致湿延迟偏差很大。比较稳妥的做法是用Magnus公式算饱和水汽压再乘相对湿度得到实际水汽压。补充一下Magnus公式es 6.1078 × exp(17.27 × Td / (Td 237.3))如果你手头有露点温度直接用露点温度代入算饱和水汽压得到的就是实际水汽压这是气象上常用的处理方式。如果没有露点只有相对湿度和气温那就先用气温算饱和水汽压再乘相对湿度。5. 常见问题与排查技巧实录5.1 对流层和电离层别再把它们绑在一起对流层延时和电离层延时是两类完全不同的误差源但我在不少微信群和论坛上看到有人把它们混为一谈。我整理过一个速查对比表格写代码和排查问题时直接对照对比项对流层延时电离层延时发生区域地面至约50公里约60公里至数千公里高空是否色散否与信号频率无关是与频率平方成反比双频能否消除不能能大气组成干燥气体、水汽电离气体、自由电子天顶方向量级约2.2至2.6米约1至30米受太阳活动影响主要变化周期天气变化、昼夜水汽当地时间午后最大夜间最小强太阳活动影响基本无影响影响剧烈常用处理手段模型参数估计差分消除双频组合模型差分消除记住一句话能靠双频消掉的是电离层消不掉的是对流层。你拿双频接收机做了消电离层组合结果发现残差里还有一个平滑但数值不小的大气误差那基本就是对流层延时。5.2 雨天为什么定位会飘雨天和雷暴天气里单点定位的垂直精度变差这是很多测量员的共同感受。本质上是因为对流层湿延迟在水汽充足的条件下急剧增大且波动剧烈。雨水到来之前大气水汽含量快速上升湿延迟从平时的十几厘米一路涨到三四十厘米甚至更多。更麻烦的是降雨通常伴随冷空气和风场大气水汽的空间分布变得更加不均匀。原本平坦的水平层状大气被打破延迟残差在空间上出现明显的梯度。这种情况下即使静态观测解算ZTD参数估计也可能出现较大的抖动。如果你要在雨季做高精度测量我的建议是加长静态观测时间让ZTD参数有足够的时间被滤波收敛同时密切盯住后验残差如果残差里出现了系统性随仰角变化的趋势基本就是映射函数或者ZTD估计有问题。如果实在赶工可以试试引入外部水汽产品或者改用网络RTK依赖区域误差内插但要接受精度可能不如天气稳定的时期。5.3 低仰角卫星遮不遮阈值怎么定前面提到低仰角卫星的对流层延时又大又难建模那仰角掩码到底设多少合适这个问题没有绝对答案取决于你的应用场景和观测环境。在开阔地带做静态测量10度阈值是常见选项在城市峡谷或者山地遮挡严重本来就找不到多少卫星有人会把阈值降到5度救急。但救急是要付出代价的。低仰角卫星引入的对流层延时残差如果没有足够的模型精度和历史气象数据支撑很可能会污染整组解算结果。我自己的经验是做高精度静态解算阈值设置不低于10度做动态定位能设15度就设15度。如果你确实需要用低仰角卫星改善几何构型那至少要把映射函数换成GMF或者VMF1级别并且给低仰角观测值分配更小的权重让它们参与解算但不至于主导结果。总结成一个决策口诀低仰角卫星是双刃剑几何精度因子降了大气误差上来了。要它参与就得有匹配的模型和权重策略没有把握宁可放弃也别让它拖垮整条基线。5.4 一个容易被忽略的坑高程、大地高和气象参数的匹配问题最后说一个实操中特别容易翻车的地方模型输入的高程和气象参数来源不一致。Saastamoinen和Hopfield模型里很多公式用的是测站的正高或者海拔高但GNSS定位得到的是椭球高。两者之间隔着大地水准面差距在很多地方动辄几十米。如果你拿椭球高直接代入模型算出来的气压、温度可能就会有偏差延迟自然也受影响。正确做法是先把椭球高换算成海拔高再代入气象模型取参数。或者直接使用GPT2/GPT3这类经验模型它们内部已经处理了高程换算输入经纬度和椭球高也能给出相对合理的结果。以前我刚开始写PPP代码时就在这个细节上栽过高程差个50米算出来的干延迟就偏了十几厘米排查了半天才发现问题出在高程基准上。这件事给我的教训是做GNSS数据处理细节决定成败。对流层延时的模型说复杂也复杂说简单也简单但真正影响精度的往往不是公式本身而是你在输入参数时对单位、基准、观测条件这些细节有没有较真。把气象参数、高程基准、映射函数、仰角权重这几件事捋顺了对流层延时这个坎基本就迈过去了。