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的步骤:
- 根据UTM带号确定中央经线
- 用反投影公式计算经纬度
- 迭代求解直到收敛
这个迭代过程,我一般用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数据结构的实战经验,保证干货满满。