1. 坐标系基础

各位同学好,我是老张。搞导航定位这些年,我见过太多人在坐标系上栽跟头。说实话,坐标系这东西,看着简单,用起来全是坑。今天咱们就把这几个最常用的坐标系掰开揉碎了讲清楚。

1. 地球坐标系:WGS-84 与 CGCS2000

先说说地球坐标系。你想想看,地球不是完美的球体,它是个椭球。所以我们需要一个数学模型来描述它。目前全球最通用的就是 WGS-84(World Geodetic System 1984)。

WGS-84 是美国国防部建立的。GPS 卫星用的就是它。它的椭球参数是这样的:

参数 WGS-84 CGCS2000
长半轴 a 6378137.0 m 6378137.0 m
扁率 f 1/298.257223563 1/298.257222101

看到没?长半轴一模一样,扁率差了一点点。我记得刚入行时,有个项目用了 WGS-84 的数据,但客户要求输出 CGCS2000。我当时想,差这么点,忽略算了。结果在跨省域的项目中,偏差累积到了米级。嗯,从那以后我再也不敢小看这微小的扁率差异了。

CGCS2000 是中国的大地坐标系。2000 年启用,现在国内所有测绘成果都必须用这个。说白了,WGS-84 是国际标准,CGCS2000 是中国标准。两者在大部分民用场景下可以混用,但高精度场景必须区分。

⚠️ 注意: 我曾经在无人机航测项目中,直接用了 WGS-84 的基站数据,结果和当地 CGCS2000 的控制点对不上。后来发现,两个坐标系在水平方向有约 0.5 米的系统偏差。所以,涉及国土、规划的项目,一定要确认坐标系。

2. 地心地固坐标系(ECEF)

ECEF 全称 Earth-Centered, Earth-Fixed。它是个三维直角坐标系。原点在地心,Z 轴指向北极,X 轴指向本初子午线与赤道的交点,Y 轴按右手定则确定。

为什么需要 ECEF?因为经纬度是球面坐标,做向量运算很麻烦。ECEF 是笛卡尔坐标,加减乘除都方便。比如计算两个 GPS 点之间的直线距离,用 ECEF 坐标直接算欧氏距离就行。

经纬度转 ECEF 的公式是这样的:

import math

def geodetic_to_ecef(lat, lon, alt):
    # WGS-84 参数
    a = 6378137.0
    f = 1 / 298.257223563
    e2 = 2*f - f*f

    lat_rad = math.radians(lat)
    lon_rad = math.radians(lon)

    N = a / math.sqrt(1 - e2 * math.sin(lat_rad)**2)

    x = (N + alt) * math.cos(lat_rad) * math.cos(lon_rad)
    y = (N + alt) * math.cos(lat_rad) * math.sin(lon_rad)
    z = (N * (1 - e2) + alt) * math.sin(lat_rad)

    return x, y, z

我个人习惯在写定位算法时,先把所有经纬度转成 ECEF。这样后续的滤波、融合都统一在一个坐标系下,省去很多麻烦。

3. 地理坐标系(经纬度)

这个大家最熟悉。经度(Longitude)范围 -180° 到 180°,纬度(Latitude)范围 -90° 到 90°。但有个细节很多人忽略:经纬度是角度,不是长度。

一度经度在地球赤道上的长度约 111 公里,但在纬度 60° 的地方,只有约 55 公里。你想想看,如果直接用经纬度做距离计算,误差会非常大。

💡 小技巧: 我建议在做距离估算时,用这个近似公式:1 纬度 ≈ 111 km,1 经度 ≈ 111 * cos(lat) km。虽然不精确,但做快速估算够用了。

4. 站心坐标系(ENU)

ENU 全称 East-North-Up。它是个局部坐标系。原点在某个参考点(比如你的基站位置),X 轴指向东,Y 轴指向北,Z 轴指向天顶。

为什么需要 ENU?因为 ECEF 虽然计算方便,但它的坐标值太大(地球半径 6378 公里),而且方向不直观。ENU 以你为中心,东、北、天三个方向,非常符合人的直觉。

比如你在做 RTK 定位时,输出的结果通常就是 ENU 坐标。东向偏差、北向偏差、高程偏差,一看就懂。

ECEF 转 ENU 的代码:

def ecef_to_enu(ref_lat, ref_lon, ref_alt, x, y, z):
    # 先将参考点转 ECEF
    x0, y0, z0 = geodetic_to_ecef(ref_lat, ref_lon, ref_alt)

    # 计算差值
    dx = x - x0
    dy = y - y0
    dz = z - z0

    # 旋转矩阵
    lat_rad = math.radians(ref_lat)
    lon_rad = math.radians(ref_lon)

    e = -math.sin(lon_rad) * dx + math.cos(lon_rad) * dy
    n = (-math.sin(lat_rad) * math.cos(lon_rad) * dx 
         - math.sin(lat_rad) * math.sin(lon_rad) * dy 
         + math.cos(lat_rad) * dz)
    u = (math.cos(lat_rad) * math.cos(lon_rad) * dx 
         + math.cos(lat_rad) * math.sin(lon_rad) * dy 
         + math.sin(lat_rad) * dz)

    return e, n, u

5. 四个坐标系的关系图

下面这张图展示了四个坐标系之间的转换关系。我建议你把它存下来,做项目时对照着看。

坐标系转换关系图 WGS-84 / CGCS2000 (地球椭球坐标系) ECEF (地心地固坐标系) 经纬度 (地理坐标系) ENU (站心坐标系) 椭球参数 + 高度 逆变换 参考点 + 旋转矩阵 间接转换 核心思路:所有坐标最终都可以通过 ECEF 作为桥梁进行转换

6. 实际项目中的坐标系选择建议

我做了十几年定位,总结了几条经验:

  • 做卫星导航:用 WGS-84 经纬度输入,内部转 ECEF 做计算,输出时根据需要转回经纬度或 ENU。
  • 做地面基站定位:用 ENU 最方便。基站位置作为原点,东、北、天三个方向一目了然。
  • 做跨区域项目:一定要确认客户要求的是 WGS-84 还是 CGCS2000。我吃过亏,所以现在合同里都会写明坐标系。
  • 做高精度测绘:别偷懒,用完整的椭球参数做转换。近似公式只适合快速估算。

核心要点:

  • WGS-84 和 CGCS2000 是地球椭球模型,参数略有差异
  • ECEF 是三维直角坐标系,适合做数学运算
  • 经纬度是球面坐标,直观但计算不便
  • ENU 是局部坐标系,以参考点为中心,适合局部定位
  • 四个坐标系之间可以通过数学公式互相转换