2、坐标系与时间系统:地球坐标系、站心坐标系、时间系统与坐标转换原理

说实话,做导航系统开发这么多年,我踩过最大的坑,往往不是算法本身,而是坐标系搞混了。

你想想看,卫星发来的位置是 WGS84,地图用的是 CGCS2000,传感器输出的是站心坐标,时间戳还分 UTC 和 GPS 时。但凡有一个没对齐,定位结果就飘到天边去了。

这一章,咱们就把这些基础概念彻底理清楚。

2.1 地球坐标系:WGS84 与 CGCS2000

地球坐标系,说白了就是给地球上的点一个唯一的「门牌号」。最常用的两个,一个是 WGS84,一个是 CGCS2000。

2.1.1 WGS84(World Geodetic System 1984)

WGS84 是 GPS 系统使用的坐标系。它的原点在地球质心,Z 轴指向 BIH(国际时间局)定义的协议地球极(CTP),X 轴指向本初子午线与赤道的交点。

我个人习惯把它理解为「GPS 的母语」。你从 GPS 接收机里读出来的经纬度,默认就是 WGS84 坐标。

核心参数:
  • 长半轴 a = 6378137.0 m
  • 扁率 f = 1/298.257223563
  • 地心引力常数 GM = 3986004.418 × 10⁸ m³/s²
  • 地球自转角速度 ω = 7292115.0 × 10⁻¹¹ rad/s

2.1.2 CGCS2000(China Geodetic Coordinate System 2000)

CGCS2000 是我国自主建立的坐标系,2008 年 7 月 1 日起正式启用。它的参数和 WGS84 几乎一样——长半轴都是 6378137 米,扁率也相同。

嗯,这里要注意:虽然参数一样,但两者在实现上存在厘米级的差异。为什么?因为参考框架不同。WGS84 的参考框架是 WGS84(G1762),CGCS2000 的参考框架是 ITRF97。

避坑指南: 我曾经在一个项目中,直接把 WGS84 坐标当作 CGCS2000 用,结果在跨省范围出现了 0.5 米的偏差。对于高精度测绘来说,这已经不可接受了。所以,不要默认两者等价,该转换时一定要转换。

2.2 站心坐标系

站心坐标系,也叫局部坐标系。它是以观测站为原点建立的坐标系。

你想想看,地球坐标系虽然全球统一,但用起来不方便。比如你要描述「前方 10 米、右侧 5 米」这种相对位置,用经纬度就很别扭。这时候站心坐标系就派上用场了。

站心坐标系通常定义为:

  • 东向(E):指向正东方向
  • 北向(N):指向正北方向
  • 天向(U):垂直于当地水平面向上

所以它也叫 ENU 坐标系。我习惯在自动驾驶项目中用这个坐标系做局部路径规划,因为直观——车头朝北,左边就是西,右边就是东。

小技巧: 站心坐标和地球坐标的转换,本质上是一个旋转加平移。旋转矩阵由观测点的经纬度决定。我一般会提前算好旋转矩阵,避免在实时循环里重复计算三角函数。

2.3 时间系统:UTC 与 GPS 时

时间系统是导航系统里最容易忽略、也最容易出问题的一环。

2.3.1 UTC(协调世界时)

UTC 是我们日常生活中使用的时间标准。它基于原子时(TAI),但通过插入闰秒来保持与天文时间的同步。

截至 2025 年,UTC 比 TAI 慢了 37 秒。嗯,这个数字还在缓慢增长,因为地球自转在减速。

2.3.2 GPS 时

GPS 时是 GPS 系统内部使用的时间系统。它从 1980 年 1 月 6 日 0 时开始计时,不插入闰秒。

所以 GPS 时和 UTC 之间有一个固定的偏移量:

时间系统 起点 闰秒 与 UTC 的关系
UTC 1972-01-01 有(已插入 37 秒) 基准
GPS 时 1980-01-06 GPS 时 = UTC + 18 秒(1980 年时)
当前:GPS 时 = UTC + 18 秒 + 闰秒数
避坑指南: 我曾经在写时间同步模块时,忘了处理闰秒。结果 GPS 接收机输出的时间戳和系统 UTC 时间差了整整 18 秒。18 秒对于高速移动的车辆来说,意味着几百米的定位误差。从那以后,我每次都会显式检查时间偏移量。

2.4 坐标转换原理

坐标转换,说白了就是把一个坐标系下的坐标,换算到另一个坐标系下。常见的转换场景有:

  1. WGS84 转 CGCS2000:七参数转换(三个平移、三个旋转、一个尺度因子)
  2. 大地坐标转空间直角坐标:经纬高(BLH)转 X/Y/Z
  3. 空间直角坐标转站心坐标:通过旋转矩阵实现

2.4.1 大地坐标与空间直角坐标的转换

这是最基础的转换。给定经纬度 (B, L, H) 和椭球参数,可以算出空间直角坐标 (X, Y, Z):

// 伪代码示例:BLH 转 XYZ
function blh2xyz(B, L, H, a, f) {
    e2 = 2*f - f*f;  // 第一偏心率平方
    N = a / sqrt(1 - e2 * sin(B) * sin(B));
    
    X = (N + H) * cos(B) * cos(L);
    Y = (N + H) * cos(B) * sin(L);
    Z = (N * (1 - e2) + H) * sin(B);
    
    return [X, Y, Z];
}

反过来,从 XYZ 求 BLH 需要迭代计算,因为纬度 B 出现在公式两边。我一般用牛顿迭代法,3 次迭代就能收敛到毫米级精度。

2.4.2 空间直角坐标转站心坐标

假设站心原点在 (X₀, Y₀, Z₀),目标点在 (X, Y, Z)。先求相对向量:

dX = X - X₀
dY = Y - Y₀
dZ = Z - Z₀

然后通过旋转矩阵转到 ENU 坐标系:

// 旋转矩阵 R 由站心原点的经纬度 (B₀, L₀) 决定
R = [
    [-sin(L₀),          cos(L₀),          0],
    [-sin(B₀)*cos(L₀), -sin(B₀)*sin(L₀),  cos(B₀)],
    [ cos(B₀)*cos(L₀),  cos(B₀)*sin(L₀),  sin(B₀)]
];

[E, N, U] = R * [dX, dY, dZ]
小技巧: 我习惯把旋转矩阵写成列主序存储,这样在 C/C++ 里用 SIMD 指令可以一次算完三个分量。实测能快 30% 左右。

2.5 知识体系总览

下面这张图,把本章的核心知识点串起来了。你一看就明白:

坐标系与时间系统知识体系 地球坐标系 WGS84 CGCS2000 大地坐标 (BLH) 空间直角坐标 (XYZ) 站心坐标系 东向 (E) 北向 (N) 天向 (U) ENU 局部坐标系 时间系统 UTC(协调世界时) GPS 时 闰秒偏移 时间戳对齐 七参数 旋转+平移 偏移量 核心结论 坐标系和时间系统是导航系统的「语言」 语言不通,定位必错 每次做坐标转换前,先确认源和目标坐标系 每次做时间同步前,先确认 UTC 和 GPS 时的偏移量

这张图把三个核心模块和它们之间的转换关系都画出来了。你写代码的时候,可以把它贴在工位旁边,每次做转换前扫一眼,能省不少 debug 时间。

我的个人习惯: 我会在项目里统一用一个坐标转换库,把所有转换函数封装好。上层业务代码只调用接口,不直接操作矩阵。这样万一坐标系参数变了,改一个地方就行,不用满世界找代码。

好了,坐标系和时间系统就聊到这儿。这些东西看着基础,但真到了项目里,每一个细节都可能让你加班到深夜。记住一句话:先对齐坐标系,再谈定位精度


公众号:蓝海资料掘金营,微信deep3321