4. 卫星导航基础:GPS/北斗信号结构,伪距与载波相位观测方程,单点定位原理,最小二乘定位解算
各位同学,今天咱们聊聊卫星导航的根基。说实话,搞组合导航这么多年,我见过太多人一上来就扑到卡尔曼滤波上,结果连伪距和载波相位都分不清。嗯,这不行。地基打不牢,楼盖得再高也得塌。
我个人习惯,讲卫星导航之前,先让大家明白一件事:卫星到底在发什么?我们怎么用它来算位置?
4.1 GPS/北斗信号结构
GPS和北斗的信号,说白了就是电磁波。但这不是普通的电磁波,它上面「驮」着三样东西:载波、测距码、导航电文。
- 载波:就是那个高频正弦波。GPS的L1频率是1575.42 MHz,L2是1227.60 MHz。北斗的B1I是1561.098 MHz。频率越高,测距精度理论上越好,但穿透性差。
- 测距码:也叫伪随机噪声码(PRN)。GPS的C/A码速率1.023 MHz,码长1023个码片,周期1毫秒。北斗的B1I码速率2.046 MHz。这个码是干嘛用的?用来测量卫星到接收机的距离。
- 导航电文:包含卫星的轨道参数(星历)、时钟修正参数、电离层修正参数等。没有这些,你就算测出了距离,也不知道卫星在哪。
核心要点:信号结构决定了你能测什么、能测多准。载波相位精度高但有整周模糊度,伪距精度低但无模糊度。这就是后面紧组合里要用到的互补特性。
我记得刚入行时,有个老工程师跟我说:「小伙子,别小看信号结构。你连卫星发的是啥都不知道,怎么敢做定位?」后来我在一个车载项目里,因为没注意北斗B1I和B2I的码速率差异,导致伪距测量偏差,定位结果飘了十几米。嗯,从那以后,我再也不敢跳过信号结构这一节。
4.2 伪距与载波相位观测方程
好,现在卫星信号到了接收机。我们怎么用它算距离?
伪距观测方程:
ρ = r + c·(δt_u - δt_s) + I + T + ε_ρ
其中:
- ρ:伪距测量值(米)
- r:卫星到接收机的几何距离(米)
- c:光速(299792458 m/s)
- δt_u:接收机钟差(秒)
- δt_s:卫星钟差(秒)
- I:电离层延迟(米)
- T:对流层延迟(米)
- ε_ρ:伪距测量噪声(米)
你想想看,伪距为什么叫「伪」?因为它不是真实距离,里面掺杂了钟差、大气延迟等各种误差。说白了,伪距就是「带误差的测量值」。
载波相位观测方程:
φ = (r + c·(δt_u - δt_s) - I + T) / λ + N + ε_φ
其中:
- φ:载波相位测量值(周)
- λ:载波波长(米)
- N:整周模糊度(整数)
- ε_φ:载波相位测量噪声(周)
注意看,电离层延迟在伪距里是加号,在载波相位里是减号。为什么?因为电离层对码和载波的影响是相反的。这个特性在双频组合里非常有用。
实战经验:我在做高精度定位时,伪距用来解算初始位置和钟差,载波相位用来做厘米级定位。但载波相位有个麻烦——整周模糊度N。你想想看,你只知道相位的小数部分,不知道整数部分是多少。这就好比你知道现在是0.3秒,但不知道是第几秒。怎么解?这就是后面要讲的模糊度固定问题。
4.3 单点定位原理
单点定位,也叫绝对定位。就是只用一台接收机,接收卫星信号,算出自己的位置。
原理其实很简单:
- 已知卫星的位置(从导航电文里解出来)
- 测量卫星到接收机的距离(伪距)
- 以卫星为球心,距离为半径画球
- 多个球相交的点,就是接收机的位置
但这里有个坑:接收机钟差是未知的。所以实际上我们有4个未知数:三维位置(x, y, z)加上钟差δt_u。因此至少需要4颗卫星才能解算。
注意:单点定位的精度一般在米级(5-15米),受大气延迟、卫星轨道误差、多径效应等影响。如果你想要厘米级精度,单点定位是不够的,需要差分定位或RTK。
我曾经在测试一个车载导航系统时,发现定位结果总是偏东3米。查了半天,原来是卫星星历里的轨道参数有误差。嗯,单点定位就是这样,你只能依赖卫星播发的信息,自己没法修正。
4.4 最小二乘定位解算
好,现在我们有4颗以上的卫星,每个卫星都有一个伪距方程。怎么解?
最小二乘法。说白了,就是找一组位置和钟差,使得所有卫星的伪距残差平方和最小。
解算步骤:
- 线性化:伪距方程是非线性的,需要泰勒展开,取一阶近似。
- 构建观测矩阵:H矩阵,每行对应一颗卫星的方向余弦。
- 计算残差:测量伪距减去计算伪距。
- 求解增量:Δx = (H^T·H)^{-1}·H^T·Δρ
- 更新状态:x = x_0 + Δx
- 迭代:重复2-5步,直到收敛。
代码实现(伪代码):
function least_squares_positioning(sat_positions, pseudoranges):
x = [0, 0, 0, 0] # 初始位置和钟差
for iter in range(10):
H = []
delta_rho = []
for i in range(len(sat_positions)):
r = norm(sat_positions[i] - x[0:3])
rho_calc = r + x[3] # 计算伪距
H_row = [-(sat_positions[i][0] - x[0])/r,
-(sat_positions[i][1] - x[1])/r,
-(sat_positions[i][2] - x[2])/r, 1]
H.append(H_row)
delta_rho.append(pseudoranges[i] - rho_calc)
H = matrix(H)
delta_rho = vector(delta_rho)
delta_x = (H^T * H)^(-1) * H^T * delta_rho
x = x + delta_x
if norm(delta_x) < 1e-4:
break
return x[0:3], x[3] # 位置和钟差
关键点:H^T·H矩阵的逆是否存在,取决于卫星的几何分布。如果卫星都挤在一起,矩阵会奇异,解算结果不可靠。这就是为什么我们常说「GDOP(几何精度因子)」要小。
我个人习惯,在解算前先检查一下卫星数量和几何分布。如果GDOP大于5,我建议你等一等,或者换一组卫星。曾经有个项目,在峡谷里测试,卫星信号被遮挡,只剩4颗星,GDOP高达8,定位结果跳来跳去。后来加了惯性导航辅助,才稳住。
4.5 本章知识体系
下面这张图,是我自己画的,把本章的核心逻辑串起来了。你仔细看看,信号结构是基础,观测方程是桥梁,单点定位是目标,最小二乘是工具。四者缺一不可。
好了,这一章的内容就这些。信号结构是基础,观测方程是核心,单点定位是应用,最小二乘是算法。你把这四块吃透了,后面讲紧组合、松组合、深组合,你才能跟得上。
我的建议:学完这一章,你最好自己动手写一个最小二乘定位程序。用真实的卫星数据跑一遍,看看定位结果和真实位置差多少。纸上得来终觉浅,绝知此事要躬行。
公众号:蓝海资料掘金营,微信deep3321