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 是中国标准。两者在大部分民用场景下可以混用,但高精度场景必须区分。
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 公里。你想想看,如果直接用经纬度做距离计算,误差会非常大。
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. 四个坐标系的关系图
下面这张图展示了四个坐标系之间的转换关系。我建议你把它存下来,做项目时对照着看。
6. 实际项目中的坐标系选择建议
我做了十几年定位,总结了几条经验:
- 做卫星导航:用 WGS-84 经纬度输入,内部转 ECEF 做计算,输出时根据需要转回经纬度或 ENU。
- 做地面基站定位:用 ENU 最方便。基站位置作为原点,东、北、天三个方向一目了然。
- 做跨区域项目:一定要确认客户要求的是 WGS-84 还是 CGCS2000。我吃过亏,所以现在合同里都会写明坐标系。
- 做高精度测绘:别偷懒,用完整的椭球参数做转换。近似公式只适合快速估算。
核心要点:
- WGS-84 和 CGCS2000 是地球椭球模型,参数略有差异
- ECEF 是三维直角坐标系,适合做数学运算
- 经纬度是球面坐标,直观但计算不便
- ENU 是局部坐标系,以参考点为中心,适合局部定位
- 四个坐标系之间可以通过数学公式互相转换