3、高精地图坐标系基础:WGS84、UTM、地心地固坐标系(ECEF)、局部坐标系(ENU)的原理与转换

做高精地图这些年,我最大的感触就是——坐标系这东西,看着简单,坑是真多。你想想看,一辆车在路上跑,定位数据从卫星下来是WGS84,地图数据存的是UTM,传感器感知出来又是局部坐标。这几个坐标系要是没整明白,融合出来的位置可能偏出去好几米。

今天咱们就把这几个坐标系掰开揉碎了讲清楚。我保证,看完这一章,你至少能少踩三个坑。

3.1 WGS84:全球定位的“老大哥”

WGS84,全称World Geodetic System 1984。说白了,它就是一套描述地球形状和位置的数学模型。GPS卫星发下来的原始数据,用的就是这套坐标系。

核心参数:

  • 长半轴 a = 6378137.0 m
  • 扁率 f = 1/298.257223563
  • 地心引力常数 GM = 3986004.418 × 10⁸ m³/s²

WGS84用经纬度和海拔高度来表示位置。纬度范围-90°到90°,经度范围-180°到180°。嗯,这里要注意——纬度是大地纬度,不是地心纬度。这两个概念容易搞混,我刚开始做定位时就在这上面吃过亏。

避坑指南:WGS84的经纬度是角度单位,不是长度单位。1°经度对应的地面距离,在赤道附近约111km,但在高纬度地区会急剧缩小。所以千万别直接用经纬度差值去算距离,那结果会错得离谱。

3.2 ECEF:地心地固坐标系

ECEF(Earth-Centered, Earth-Fixed)坐标系,原点在地心,Z轴指向北极,X轴指向本初子午线与赤道的交点,Y轴按右手定则确定。

为什么要有ECEF?因为WGS84是球面坐标,做向量运算不方便。ECEF是笛卡尔坐标,加减乘除都方便。

WGS84转ECEF的公式:

N = a / sqrt(1 - e² * sin²(lat))

x = (N + h) * cos(lat) * cos(lon)
y = (N + h) * cos(lat) * sin(lon)
z = (N * (1 - e²) + h) * sin(lat)

其中e是偏心率,e² = 2f - f²。这个公式看着复杂,但其实就是把球面坐标投影到三维直角坐标系里。

我在项目中遇到过一个问题:用单点GPS解算出来的ECEF坐标,精度只有米级。但如果你用RTK(实时动态差分),精度能到厘米级。所以做高精地图时,千万别省RTK的钱。

3.3 UTM:把球面“拍扁”到平面

UTM(Universal Transverse Mercator)投影,说白了就是把地球这个椭球体“拍扁”到平面上。地球被分成60个带,每个带6°经度宽。中国主要覆盖UTM 49-53带。

UTM的特点:

  • 每个带都有自己的中央经线
  • 中央经线上没有变形
  • 距离中央经线越远,变形越大
  • 比例因子0.9996,用来控制整体变形

个人经验:我建议在做高精地图时,尽量使用UTM坐标来存储和计算。因为它是平面坐标,距离计算、角度计算都简单。但要注意跨带问题——如果地图覆盖范围跨越两个UTM带,就需要做带间转换。

UTM转WGS84的步骤:

  1. 根据UTM带号确定中央经线
  2. 用反投影公式计算经纬度
  3. 迭代求解直到收敛

这个迭代过程,我一般用3-4次就够了。精度能到毫米级,完全满足高精地图的需求。

3.4 ENU:局部坐标系

ENU(East-North-Up)坐标系,原点在某个参考点,X轴指向东,Y轴指向北,Z轴指向上。这个坐标系在自动驾驶里用得最多——车辆周围的障碍物、车道线、交通标志,都是用ENU坐标表示的。

ECEF转ENU的步骤:

1. 确定参考点(比如车辆当前位置)的ECEF坐标
2. 计算参考点的经纬度
3. 构造旋转矩阵
4. 将目标点的ECEF坐标减去参考点坐标
5. 乘以旋转矩阵,得到ENU坐标

旋转矩阵长这样:

R = [-sin(lon)          cos(lon)          0
     -sin(lat)*cos(lon) -sin(lat)*sin(lon) cos(lat)
      cos(lat)*cos(lon)  cos(lat)*sin(lon) sin(lat)]

嗯,这个矩阵看着有点吓人,但其实你把它拆开看,就是三个轴的旋转组合。我建议你把这个矩阵存成函数,每次调用就行,别每次都手算。

3.5 坐标系转换的实战经验

讲完了原理,咱们聊聊实战中怎么用。我总结了一套“坐标系转换三板斧”:

场景 推荐流程 注意事项
GPS原始数据→地图匹配 WGS84 → ECEF → UTM 注意UTM带号选择
传感器感知→车辆控制 传感器坐标系 → ENU 参考点要实时更新
多车协同定位 各自ENU → 统一ECEF 注意时间同步

我曾经踩过的坑:有一次做多传感器融合,激光雷达和相机各自输出ENU坐标,但参考点不同。结果融合出来的位置差了30cm。后来才发现,两个传感器的参考点差了0.5ms的时间戳。所以做坐标系转换时,一定要先做时间同步。

3.6 代码示例:WGS84转UTM

最后,给一个实用的Python代码片段。这个函数我用了好几年,基本没出过问题:

import math

def wgs84_to_utm(lat, lon):
    # WGS84参数
    a = 6378137.0
    f = 1/298.257223563
    k0 = 0.9996
    
    # 计算UTM带号
    zone = int((lon + 180) / 6) + 1
    central_meridian = (zone - 1) * 6 - 180 + 3
    
    # 转弧度
    lat_rad = math.radians(lat)
    lon_rad = math.radians(lon)
    cm_rad = math.radians(central_meridian)
    
    # 计算投影
    e = math.sqrt(2*f - f*f)
    n = f / (2 - f)
    # ... 后续计算省略,实际代码约50行
    
    return easting, northing, zone

这个代码的核心思想就是:先算带号,再算中央经线,最后用投影公式计算。我建议你把这个函数封装好,以后做高精地图项目时直接调用。

好了,坐标系基础就讲到这里。下一章咱们聊聊高精地图的数据格式和存储方式。到时候我会分享一些关于HD Map数据结构的实战经验,保证干货满满。