
简介在地理信息系统与航空航天领域坐标转换是数据定位与分析的基础环节。这套MATLAB工具包面向需要处理地球坐标的工程师与研究人员重点解决地心地固坐标系ECEF与经纬度高度LLH之间以及局部东-北-上ENU坐标系与ECEF之间的换算问题。压缩包内共2个m文件大小约2KB代码简洁紧凑适合直接调用或二次移植。一个脚本基于WGS84椭球模型实现ECEF转经纬高另一个完成局部ENU到ECEF的转换两者结合可覆盖从空间绝对位置到局部参考系的完整转换链路常用于GPS数据处理、遥感影像几何校正和飞行路径规划。目前已有480人学习下载。对希望深入掌握坐标转换原理的开发者而言这份代码提供了可运行示例和基于地球椭球参数的详细解算过程既能帮助理解背后的数学推导也能快速集成到实际项目中。1. 坐标系转换在 MATLAB 里最常见的起点是地固坐标系和经纬高之间的地球坐标转换同样一个观测点在 GPS 接收机里读到的是北纬 40.06°、东经 116.32°、椭球高 43 米后端仿真或雷达数据处理却要求给出地固坐标系ECEF下的 x、y、z。这不是换单位那么简单经纬高定义在 WGS-84 椭球面上地固坐标定义在随地球旋转的直角参考架里二者靠三个椭球常数和一组非线性公式衔接。标题里的 plateza9 这类脚本本质上就是在 MATLAB 里把“地球坐标转换”封装成可调函数。下面从公式出发给出手写转换函数、CSV 批量导入和结果验证的完整路径适合在地理信息、卫星导航和仿真项目里处理坐标数据的工程师。2. 地固坐标系与地球坐标转换从经纬高到 ECEF 的三条公式2.1 地固坐标系不是“地心坐标系”的另一个名字地固坐标系的全称是 Earth-Centered, Earth-Fixed直译就是“地心、地球固定”MATLAB 文档里常缩写成 ECEF。坐标系原点在地球质心Z 轴指向国际协议北极X 轴指向本初子午线与赤道交点Y 轴按右手系补齐。关键在“Fixed”坐标系与地球壳层固连地球自转时地面站坐标不会漂移。与之相对的经纬高坐标系属于大地坐标系参考面是旋转椭球而不是地面。北斗、GPS 原始输出大多是大地坐标而卫星轨道计算、双天线测姿、地基增强系统里ECEF 几乎被当成默认语言。坐标系转换做的一件事就是把这两套读数相互翻译地固坐标系的地位决定了它通常是整个转换流程的中间锚点。2.2 正向转换公式WGS-84 椭球参数怎么进来正向转换指从经纬高lat, lon, h到 ECEFx, y, z核心就是 WGS-84 椭球的四个量。a 是长半轴f 是扁率e² 是第一偏心率平方N 是卯酉圈曲率半径。参数一旦用错结果不是差几米而是差出几个数量级。符号WGS-84 数值说明a6378137.0 m赤道半轴f1 / 298.257223563椭球扁率e²f × (2 − f)第一偏心率平方Na / sqrt(1 − e²·sin²φ)卯酉圈曲率半径正向计算的 MATLAB 写法非常短a 6378137.0; f 1 / 298.257223563; e2 f * (2 - f); N a ./ sqrt(1 - e2 .* sind(lat).^2); x (N h) .* cosd(lat) .* cosd(lon); y (N h) .* cosd(lat) .* sind(lon); z (N .* (1 - e2) h) .* sind(lat);这里必须用sind和cosdMATLAB 默认的sin、cos接收弧度直接套会得到完全错乱的结果。变量 lat、lon、h 支持向量输入.*和.^是保证逐元素运算如果写成*和^三列向量会触发矩阵维度错误。输出 x、y、z 单位是米与 h 保持一致。有个容易忽略的点h 是椭球高不是海拔。GPS 接收机解算出的高程默认是 WGS-84 椭球高而测绘成果常用正常高两者相差一个高程异常在同一城市可能差几十米。做转换前先确认数据来自哪个高程基准。2.3 反算时要迭代不能直接开方ECEF 转经纬高的反解经度可以一步拿到lon atan2d(y, x)。但纬度和椭球高互相耦合因为 N 本身是纬度的函数而 h 又出现在平面分量的表达式里无法得到闭式解。常用的做法是给定一个初值然后迭代修正。p hypot(x, y); lat atan2d(z, p .* (1 - e2)); for k 1:8 N a ./ sqrt(1 - e2 .* sind(lat).^2); h p ./ cosd(lat) - N; lat atan2d(z, p .* (1 - e2 .* N ./ (N h))); end初值的选取很关键atan2d(z, p*(1-e2))给出的纬度比真实值略小但它能保证迭代单调收敛。8 次迭代对绝大多数地球表面点已经足够高程精度能到毫米级。若把迭代次数改成 3经纬度变化很小但 h 可能差出厘米级这是后续做高程拟合时注意的精度拐点。2.4 框架转换之外还有基准转换经常被混用的还有另一类转换WGS-84、CGCS2000、北京 54、西安 80 之间的坐标基准转换。椭球参数、原点定向和尺度都不同光靠经纬高和 ECEF 的三条公式解决不了标准做法是七参数布尔莎模型Xt Tx (1 k) * X wz * Y - wy * Z; Yt Ty - wz * X (1 k) * Y wx * Z; Zt Tz wy * X - wx * Y (1 k) * Z;其中 Tx、Ty、Tz 是三个平移wx、wy、wz 是三个旋转k 是尺度变化。这部分在工程中往往通过布尔莎或者三维四参数完成。标题里的“plateza9”如果设计成通用入口通常会把框架转换和基准转换分层先转 ECEF再套七参数最后转目标椭球的经纬高。3. 在 MATLAB 里跑通地球坐标转换工具箱函数与手写函数3.1 有 Mapping Toolbox 时直接用 lla2ecef 和 ecef2llaMATLAB 的 Mapping Toolbox 提供了lla2ecef和ecef2lla这是最快的一条路不需要自己维护椭球参数。函数默认使用 WGS-84 参考椭球输入矩阵规格是 N×3列顺序固定为纬度、经度、椭球高单位分别是度、度、米。lla [40.0, 116.0, 50]; % 纬度、经度、椭球高 ecef lla2ecef(lla); % 1×3 的 ECEF lla_back ecef2lla(ecef); % 转回去输出 ecef 的三个分量是 x、y、z单位米。ecef2lla内部使用迭代算法所以不必关心反解收敛问题。需要注意这个函数对第三列的解释永远是椭球高把海拔直接填进去在起伏较大的地区会引入不可接受的误差。3.2 最小可运行代码单点转换和十万点批量实际项目里很少只转一个点更多是从日志文件里拉出几十万行轨迹。批量处理时只要把经纬高组织成 N×3 矩阵即可n 1e5; lat -90 180 * rand(n, 1); lon -180 360 * rand(n, 1); h zeros(n, 1); lla [lat, lon, h]; ecef lla2ecef(lla); fprintf(ECEF 坐标范围\n); disp([min(ecef); max(ecef)]);这段代码生成 10 万个全球随机点对每个点做 WGS-84 正向转换。rand生成的纬度覆盖 −90° 到 90°经度覆盖 −180° 到 180°高程全部按椭球高 0 处理。人脸图上创建 N×3 矩阵比循环调lla2ecef快一个量级以上因为函数内部对矩阵做了向量化运算。3.3 没有工具箱手写 geodetic2ecef 和 ecef2geodetic如果目标机器没有 Mapping Toolbox或者需要在算法流程里嵌入可读性较高的源码手写版本最稳妥。把第 2 章的公式整理成完整函数function [x, y, z] geodetic2ecef(lat, lon, h) % geodetic2ecef 经纬高转地固坐标系 % 输入 lat, lon 单位为度h 单位为米 a 6378137.0; f 1 / 298.257223563; e2 f * (2 - f); N a ./ sqrt(1 - e2 .* sind(lat).^2); x (N h) .* cosd(lat) .* cosd(lon); y (N h) .* cosd(lat) .* sind(lon); z (N .* (1 - e2) h) .* sind(lat); end function [lat, lon, h] ecef2geodetic(x, y, z) % ecef2geodetic 地固坐标转经纬高 a 6378137.0; f 1 / 298.257223563; e2 f * (2 - f); lon atan2d(y, x); p hypot(x, y); lat atan2d(z, p .* (1 - e2)); for k 1:8 N a ./ sqrt(1 - e2 .* sind(lat).^2); h p ./ cosd(lat) - N; lat atan2d(z, p .* (1 - e2 .* N ./ (N h))); end end正向函数里的N与h都是同尺寸数组所以三条输出语句全部用点乘。反向函数里p hypot(x, y)返回逐元素模长等价于sqrt(x.^2 y.^2)但数值稳定性更好。迭代初值故意用了(1-e2)修正项避免在低纬度处出现台阶式跳变。这组函数与lla2ecef的差异控制在微米级差别来自ecef2lla内部使用的参考椭球细节和迭代停止条件。手写版还有一个额外优势可以随时替换a和f兼容克氏椭球或自定义参考椭球这在做地方坐标系转换时非常实用。4. 把 plateza9 变成批量工具从 CSV / TXT 导入到统一输出4.1 读取坐标文件readmatrix 和 readtable 两种姿势很多人在“coord 在主界面的什么地方导入 csv 或者 txt 文件”这个问题上绕路以为 MATLAB 有个隐藏的坐标导入按钮。实际处理坐标数据时命令行脚本比图形界面靠谱得多。无表头的纯数据文件直接用readmatrixdata readmatrix(stations.csv); lla data(:, 1:3);readmatrix会自动判定分隔符空格、逗号、Tab 都能处理。如果 CSV 带表头需要用readtable保住列名tbl readtable(stations.csv); lat tbl{:, lat}; lon tbl{:, lon}; h tbl{:, height}; lla [lat, lon, h];readtable返回的是 table 对象用花括号取值得到的是数值矩阵。表头里有中文列名时tbl.lat这类点索引可能失效最稳的方式是tbl{:,列名}。读取后立刻检查isnan(lla(:))因为文件里的空行和注释行会被读成 NaN直接进入转换函数会把整行结果污染成 NaN。4.2 按 plateza9 的命名封装转换入口压缩包里的文件名未必规范但封装思路是固定的一个总入口、两个方向、一个固定输出格式。以下代码把前面的手写函数包装成 plateza9function out plateza9(coords, mode) % plateza9 地球坐标转换便捷入口 % coords 为 m×3 或 m×3 以上矩阵取前三列 % mode 可选 lla2ecef 或 ecef2lla arguments coords (:,3) double mode (1,1) string lla2ecef end switch mode case lla2ecef [x, y, z] geodetic2ecef(coords(:,1), coords(:,2), coords(:,3)); case ecef2lla [x, y, z] ecef2geodetic(coords(:,1), coords(:,2), coords(:,3)); otherwise error(plateza9:unknownMode, 不支持的模式: %s, mode); end out [x, y, z]; endarguments块里的(:,3) double强制输入至少三列并且必须是双精度数组。mode默认指向正向转换只给一个参数时也能工作。反向转换输出仍然是三列前两列是经纬度、第三列是椭球高这样上游代码不必区分到底是哪一类坐标。4.3 向量化、循环与异常定位早期版本常写成逐行循环for i 1:size(lla, 1) [x, y, z] geodetic2ecef(lla(i,1), lla(i,2), lla(i,3)); out(i, :) [x, y, z]; end这个写法在 1 万点以下没问题到 100 万点就会明显拖慢原因不是 MATLAB 循环慢而是每次迭代都要做函数调用和矩阵拼接。改用列向量直接调用一次性能差异能到两个量级[x, y, z] geodetic2ecef(lla(:,1), lla(:,2), lla(:,3)); out [x, y, z];批处理异常时不要直接看 100 万行的原始结果先做范围检查。下面这张表是实际项目里最常见的四类问题现象大概率原因排查方式输出出现 NaN源文件含表头或空行检查isnan(lla)的行索引坐标差几十公里用了平均半径 6371 km确认代码里写的是a6378137.0纬度与经度明显颠倒CSV 列顺序不是 lat, lon, h查看第一列数值是否在 −90 到 90 之间全部高程为 0第三列被读成空值用readtable看列名和缺失值5. 转完不验收等于白转往返误差验证和三个易错点5.1 把输出再转回原坐标系误差看两个量坐标系转换写完验证方法只有一个标准答案将 ECEF 结果反向转回经纬高然后与原始输入比对。往返误差能同时验证正向公式、反向迭代次数和椭球参数是否一致。lat0 40 rand(100, 1) * 0.1; lon0 116 rand(100, 1) * 0.1; h0 50 randn(100, 1) * 10; lla_in [lat0, lon0, h0]; ecef_out plateza9(lla_in, lla2ecef); lla_back plateza9(ecef_out, ecef2lla); fprintf(纬度最大误差: %.3e 度\n, max(abs(lla_in(:,1) - lla_back(:,1)))); fprintf(经度最大误差: %.3e 度\n, max(abs(lla_in(:,2) - lla_back(:,2)))); fprintf(高度最大误差: %.3e 米\n, max(abs(lla_in(:,3) - lla_back(:,3))));运行后经纬度误差应在 1e-10 度数量级对应毫米级高程误差在 1e-6 米数量级。这个结果说明代码本体没有问题后续如果出现更大偏差问题几乎都在数据侧而不是转换侧。5.2 三个在地固坐标系转换中被反复问到的边界细节第一点经度方向别被 360° 包络骗了。atan2d返回的经度范围是 −180° 到 180°源数据如果是 0° 到 360° 的格式反向输出会突然跳到负值这时用mod(lla_back(:,2), 360)统一到 0–360° 再比较否则会被误判成上千公里的偏差。第二点极点附近经度不稳定。纬度接近 ±90° 时所有经度对应的空间位置几乎重叠反解出的经度会受迭代初值影响而跳动。这是地固坐标系的固有奇点不是算法缺陷项目如果涉及极区数据验证时要单独对纬度和经度分别设容差。第三点如果系统下一步需要ecef2eci也就是从地固坐标系转地心惯性系必须引入地球自转矩阵和格林尼治恒星时角不能把 ECEF 坐标直接当成惯性系坐标使用。时间戳不同同一组 ECEF 坐标对应的惯性系坐标相差很大这也是“地球坐标转换”里最容易和框架转换混淆的一层。把 plateza9 的输入侧加上时间参数或者让调用方在外部完成时间对齐再把结果交给后续矩阵旋转。本文还有配套的精品资源点击获取