定位方程的数学推导与伪距误差分析
1. 伪距误差的来源与建模
在卫星导航中,伪距测量值 ρ i \rho_i ρi 受多种误差因素影响,主要来源包括:
- 电离层延迟:信号穿过电离层时折射导致的额外路径延迟。
- 对流层延迟:信号穿过对流层(大气底层)时的折射。
- 多径效应:信号反射或散射导致的额外路径。
- 接收机噪声:硬件误差、量化误差等。
- 卫星钟差:卫星时钟与系统时间偏差(已通过导航电文修正,但残余误差仍存在)。
- 轨道误差:卫星位置计算误差。
这些误差可建模为伪距的加性误差项:
ρ
i
=
d
i
+
c
Δ
t
+
ϵ
i
\rho_i = d_i + c \Delta t + \epsilon_i
ρi=di+cΔt+ϵi
其中:
- d i d_i di 是真实几何距离
- c Δ t c \Delta t cΔt 是接收机钟差
-
ϵ
i
\epsilon_i
ϵi 是总误差项,包含上述所有误差源,通常假设为随机误差,满足:
ϵ i ∼ N ( 0 , σ i 2 ) \epsilon_i \sim \mathcal{N}(0, \sigma_i^2) ϵi∼N(0,σi2)
2. 含误差的定位方程
考虑误差后的定位方程为:
(
x
i
−
x
)
2
+
(
y
i
−
y
)
2
+
(
z
i
−
z
)
2
+
c
Δ
t
=
ρ
i
−
ϵ
i
\sqrt{(x_i - x)^2 + (y_i - y)^2 + (z_i - z)^2} + c \Delta t = \rho_i - \epsilon_i
(xi−x)2+(yi−y)2+(zi−z)2+cΔt=ρi−ϵi
线性化后(参考之前的推导)变为:
A
Δ
x
=
b
−
ϵ
A \Delta \mathbf{x} = \mathbf{b} - \mathbf{\epsilon}
AΔx=b−ϵ
写成矩阵形式:
[
x
1
−
x
0
d
1
y
1
−
y
0
d
1
z
1
−
z
0
d
1
1
x
2
−
x
0
d
2
y
2
−
y
0
d
2
z
2
−
z
0
d
2
1
x
3
−
x
0
d
3
y
3
−
y
0
d
3
z
3
−
z
0
d
3
1
x
4
−
x
0
d
4
y
4
−
y
0
d
4
z
4
−
z
0
d
4
1
]
[
Δ
x
Δ
y
Δ
z
Δ
t
]
=
(
[
ρ
1
−
d
1
ρ
2
−
d
2
ρ
3
−
d
3
ρ
4
−
d
4
]
−
[
ϵ
1
ϵ
2
ϵ
3
ϵ
4
]
)
\begin{bmatrix} \frac{x_1 - x_0}{d_1} & \frac{y_1 - y_0}{d_1} & \frac{z_1 - z_0}{d_1} & 1 \\ \frac{x_2 - x_0}{d_2} & \frac{y_2 - y_0}{d_2} & \frac{z_2 - z_0}{d_2} & 1 \\ \frac{x_3 - x_0}{d_3} & \frac{y_3 - y_0}{d_3} & \frac{z_3 - z_0}{d_3} & 1 \\ \frac{x_4 - x_0}{d_4} & \frac{y_4 - y_0}{d_4} & \frac{z_4 - z_0}{d_4} & 1 \end{bmatrix} \begin{bmatrix} \Delta x \\ \Delta y \\ \Delta z \\ \Delta t \end{bmatrix} = \left( \begin{bmatrix} \rho_1 - d_1 \\ \rho_2 - d_2 \\ \rho_3 - d_3 \\ \rho_4 - d_4 \end{bmatrix} - \begin{bmatrix} \epsilon_1 \\ \epsilon_2 \\ \epsilon_3 \\ \epsilon_4 \end{bmatrix} \right)
d1x1−x0d2x2−x0d3x3−x0d4x4−x0d1y1−y0d2y2−y0d3y3−y0d4y4−y0d1z1−z0d2z2−z0d3z3−z0d4z4−z01111
ΔxΔyΔzΔt
=
ρ1−d1ρ2−d2ρ3−d3ρ4−d4
−
ϵ1ϵ2ϵ3ϵ4
3. 误差对定位结果的影响分析
(1)最小二乘解的误差传播
使用最小二乘求解时,得到修正量:
Δ
x
=
(
A
T
A
)
−
1
A
T
b
\Delta \mathbf{x} = (A^T A)^{-1} A^T \mathbf{b}
Δx=(ATA)−1ATb
由于
ϵ
\mathbf{\epsilon}
ϵ 存在,实际解存在偏差。根据误差传播定律,
Δ
x
\Delta \mathbf{x}
Δx 的协方差矩阵为:
Cov
(
Δ
x
)
=
(
A
T
A
)
−
1
A
T
Cov
(
ϵ
)
A
(
A
T
A
)
−
1
\text{Cov}(\Delta \mathbf{x}) = (A^T A)^{-1} A^T \text{Cov}(\mathbf{\epsilon}) A (A^T A)^{-1}
Cov(Δx)=(ATA)−1ATCov(ϵ)A(ATA)−1
假设各伪距误差独立且方差已知(例如通过误差模型估计):
Cov
(
ϵ
)
=
diag
(
σ
1
2
,
σ
2
2
,
…
,
σ
4
2
)
\text{Cov}(\mathbf{\epsilon}) = \text{diag}(\sigma_1^2, \sigma_2^2, \ldots, \sigma_4^2)
Cov(ϵ)=diag(σ12,σ22,…,σ42)
则:
Cov
(
Δ
x
)
=
(
A
T
A
)
−
1
∑
i
=
1
4
σ
i
2
⋅
第i行向量外积
\text{Cov}(\Delta \mathbf{x}) = (A^T A)^{-1} \sum_{i=1}^4 \sigma_i^2 \cdot \text{第i行向量外积}
Cov(Δx)=(ATA)−1i=1∑4σi2⋅第i行向量外积
对角线元素即为各参数(
Δ
x
,
Δ
y
,
Δ
z
,
Δ
t
\Delta x, \Delta y, \Delta z, \Delta t
Δx,Δy,Δz,Δt)的估计方差,反映了误差对定位精度的影响。
(2)几何精度因子(GDOP)
GDOP 衡量几何布局对定位误差的放大效应,定义为:
GDOP
=
σ
x
2
+
σ
y
2
+
σ
z
2
+
σ
Δ
t
2
\text{GDOP} = \sqrt{\sigma_x^2 + \sigma_y^2 + \sigma_z^2 + \sigma_{\Delta t}^2}
GDOP=σx2+σy2+σz2+σΔt2
其中
σ
x
,
σ
y
,
σ
z
,
σ
Δ
t
\sigma_x, \sigma_y, \sigma_z, \sigma_{\Delta t}
σx,σy,σz,σΔt 是
Δ
x
\Delta \mathbf{x}
Δx 各分量的标准差。GDOP 越大,定位误差被放大的程度越高,通常要求 GDOP < 4。
示例:若四颗卫星均匀分布在用户上方,GDOP 较小;若卫星集中在同一方向,GDOP 增大,定位精度下降。
4. 误差修正与处理策略
- 加权最小二乘:根据误差大小分配权重,降低大误差项的影响。例如,用
W
=
diag
(
1
/
σ
1
2
,
1
/
σ
2
2
,
…
)
W = \text{diag}(1/\sigma_1^2, 1/\sigma_2^2, \ldots)
W=diag(1/σ12,1/σ22,…) 替换标准最小二乘中的单位矩阵:
Δ x = ( A T W A ) − 1 A T W b \Delta \mathbf{x} = (A^T W A)^{-1} A^T W \mathbf{b} Δx=(ATWA)−1ATWb - 误差模型修正:
- 电离层延迟:使用双频观测(如GPS的L1和L2频率)或电离层模型(如Klobuchar模型)修正。
- 对流层延迟:通过气象参数(温度、湿度、气压)建模修正。
- 多径效应:通过天线设计(如扼流圈天线)或信号处理(如窄相关技术)抑制。
- 卡尔曼滤波:动态跟踪误差,利用多历元观测数据平滑结果。
5.仿真实战
以用Python 仿真,包含伪距生成、最小二乘定位解算、误差协方差分析和 GDOP 计算。通过模拟卫星信号传播和误差影响,直观展示定位误差与卫星几何布局的关系。完整仿真代码如下:
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 23 09:39:48 2025
@author: Neol
"""
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
plt.close('all')
# 设置全局字体为支持中文的字体
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei'] # 黑体
# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False
# ====================== 参数设置 ======================
c = 299792458 # 精确光速值 (m/s)
true_user_pos = np.array([0.0, 0.0, 0.0]) # 用户位于坐标原点
true_clock_bias = 1e-7 # 接收机钟差 (s)
sigma = 10.0 # 伪距噪声标准差 (m)
num_satellites = 8 # 卫星数量
orbit_radius = 2.02e7 # 卫星轨道半径 (m)
lambda_ridge = 1e2 # 调整:增大初始正则化系数
max_iterations = 20 # 最大迭代次数
max_step = 1e2 # 新增:最大允许步长 (m)
# ====================== 卫星生成函数 ======================
def generate_optimal_sats(user_pos):
"""生成方位角均匀分布、仰角分层的卫星"""
np.random.seed(42)
azimuth = np.linspace(0, 2*np.pi, num_satellites, endpoint=False)
elevation_deg = np.array([80, 70, 60, 50, 40, 30, 20, 10])
theta = np.deg2rad(90 - elevation_deg)
# 方向矢量归一化
x_dir = np.sin(theta) * np.cos(azimuth)
y_dir = np.sin(theta) * np.sin(azimuth)
z_dir = np.cos(theta)
directions = np.column_stack((x_dir, y_dir, z_dir))
# 验证方向矢量
assert np.allclose(np.linalg.norm(directions, axis=1), 1.0), "方向矢量未正确归一化"
return user_pos + orbit_radius * directions, elevation_deg
# ====================== 初始化卫星 ======================
sat_positions, elevation_deg = generate_optimal_sats(true_user_pos)
# ====================== 加权矩阵 ======================
weights = np.array([2.0 if elev > 60 else 1.5 if elev > 30 else 1.0 for elev in elevation_deg])
W = np.diag(weights)
# ====================== 生成伪距观测值 ======================
true_distances = np.linalg.norm(sat_positions - true_user_pos, axis=1)
noise = np.random.normal(0, sigma, num_satellites)
pseudo_ranges = true_distances + c * true_clock_bias + noise # 明确定义伪距
# ====================== 鲁棒最小二乘解算 ======================
est_user_pos = true_user_pos + np.random.normal(1e1, 1e2, 3)
est_clock_bias = 0.0
positions = [est_user_pos.copy()]
original_lambda = lambda_ridge
for _ in range(max_iterations):
current_lambda = lambda_ridge
# 构建设计矩阵(含数值保护)
est_distances = np.linalg.norm(sat_positions - est_user_pos, axis=1)
A = []
valid = True
for i in range(num_satellites):
dx = sat_positions[i,0] - est_user_pos[0]
dy = sat_positions[i,1] - est_user_pos[1]
dz = sat_positions[i,2] - est_user_pos[2]
# 检测大值异常
if np.any(np.abs([dx, dy, dz]) > 1e10):
valid = False
break
dist = np.sqrt(dx**2 + dy**2 + dz**2 + 1e-6) # 防除零
A.append([dx/dist, dy/dist, dz/dist, 1.0])
if not valid:
break
A = np.array(A)
b = pseudo_ranges - est_distances - c * est_clock_bias # 使用已定义的伪距
try:
# 动态正则化系数衰减
current_lambda = lambda_ridge * (0.5 ** _) # 每次迭代衰减50%
weighted_matrix = A.T @ W @ A + current_lambda * np.eye(4)
# 条件数监测
cond_num = np.linalg.cond(weighted_matrix)
if cond_num > 1e10:
current_lambda *= 10
weighted_matrix += 9e-6 * np.eye(4)
delta_X = np.linalg.inv(weighted_matrix) @ A.T @ W @ b
# 严格步长控制(同时缩放钟差分量)
step_size = np.linalg.norm(delta_X)
if step_size > max_step:
delta_X *= (max_step / step_size) # 统一缩放所有分量
except np.linalg.LinAlgError:
lambda_ridge *= 10
continue
# 更新估计值
est_user_pos += delta_X[:3]
est_clock_bias += delta_X[3]
positions.append(est_user_pos.copy())
# 收敛判断
if np.linalg.norm(delta_X) < 1e-4:
lambda_ridge = original_lambda # 重置正则化系数
break
# ====================== 稳健GDOP计算 ======================
try:
# 使用无正则化的设计矩阵计算GDOP
design_matrix = A.T @ W @ A
cov_matrix = sigma**2 * np.linalg.inv(design_matrix + 1e-6*np.eye(4)) # 微小正则化
# 验证协方差有效性
if np.any(np.diag(cov_matrix) < 0) or np.any(np.isnan(cov_matrix)):
gdop = float('inf')
else:
var_pos = np.diag(cov_matrix[:3,:3])
var_clock = cov_matrix[3,3]
gdop = np.sqrt(np.sum(var_pos) + var_clock) / sigma
except:
gdop = float('inf')
# ====================== 可视化 ======================
fig = plt.figure(figsize=(18, 6))
# ---------------------- 极坐标图 ----------------------
ax1 = fig.add_subplot(131, projection='polar')
azimuth = np.arctan2(sat_positions[:,1], sat_positions[:,0])
elevation = 90 - np.rad2deg(np.arccos((sat_positions[:,2] - true_user_pos[2]) / orbit_radius))
sc1 = ax1.scatter(azimuth, elevation, c=elevation_deg, s=100,
cmap='viridis', edgecolors='k', label='Satellites')
ax1.set_theta_zero_location('N')
ax1.set_theta_direction(-1)
ax1.set_ylim(0, 90)
ax1.set_yticks([10, 30, 50, 70, 90])
ax1.set_title('卫星仰角-方位角分布', pad=20)
cbar1 = plt.colorbar(sc1, ax=ax1, pad=0.1)
cbar1.set_label('仰角 (度)')
# ---------------------- 三维卫星分布 ----------------------
ax2 = fig.add_subplot(132, projection='3d')
sc2 = ax2.scatter(sat_positions[:,0], sat_positions[:,1], sat_positions[:,2],
c=elevation_deg, marker='^', s=80, cmap='viridis', label='Satellites')
ax2.scatter(0, 0, 0, c='r', s=100, label='User Position', depthshade=False)
ax2.set_xlabel('X (m)'), ax2.set_ylabel('Y (m)'), ax2.set_zlabel('Z (m)')
ax2.set_title('三维卫星分布')
cbar2 = plt.colorbar(sc2, ax=ax2, pad=0.1)
cbar2.set_label('仰角 (度)')
ax2.legend(loc='upper right')
# ---------------------- 定位轨迹 ----------------------
positions = np.array(positions)
ax3 = fig.add_subplot(133, projection='3d')
ax3.plot(positions[:,0], positions[:,1], positions[:,2], 'b.-',
markersize=10, label='Iteration Path')
ax3.scatter(0, 0, 0, c='r', s=100, label='True Position', depthshade=False)
ax3.set_xlabel('X (m)'), ax3.set_ylabel('Y (m)'), ax3.set_zlabel('Z (m)')
ax3.set_title(f'定位轨迹 (GDOP={gdop:.2f})')
ax3.legend(loc='upper right')
plt.tight_layout()
plt.show()
# ====================== 结果输出 ======================
print(f"真实位置: {true_user_pos}")
print(f"估计位置: {np.round(est_user_pos, 2)}")
print(f"定位误差: {np.linalg.norm(est_user_pos):.2f} m")
print(f"GDOP: {gdop:.2f}")
仿真结果:
真实位置: [0. 0. 0.]
估计位置: [-34.8 67.08 -64.28]
定位误差: 99.21 m
GDOP: 2.75
可视化结果:
6. 实际应用中的误差分析
- 城市峡谷:高楼遮挡导致多径效应严重,定位误差可达数十米。
- 电离层活跃区:如赤道附近,电离层延迟误差可能超过10米,需使用双频接收机。
- 接收机钟差:普通接收机钟差可达数十纳秒,对应米级误差,需通过模型实时修正。
示例:假设伪距误差标准差 σ i = 1 \sigma_i = 1 σi=1 米,若 GDOP = 2,则用户位置误差约为 2 2 2 米( 2 × σ i 2 \times \sigma_i 2×σi)。
总结
- 伪距误差直接影响定位精度,其来源复杂且动态变化。
- 通过误差建模、加权最小二乘和修正技术可显著提升定位可靠性。
- 实际应用中需结合具体场景选择误差处理策略,如城市导航需重点解决多径效应,航空导航需修正电离层延迟。