LPC_经纬海拔转XYZ

发布时间:2026/10/28 10:14:16

LPC_经纬海拔转XYZ LPCLocalization Planning and Control输入GNSS 输出LLH(lat, lon, h)WGS84纬度 φ经度 λ大地高 h输出ENU东、北、天 / NED北、东、地很多无人机 / IMU 用 NED你说的西北地很少见行业标准是 NED变换链路标准(LLH \xrightarrow{椭球公式} ECEF(X,Y,Z) \xrightarrow{平移旋转矩阵} ENU)基准点(P_0(\phi_0,\lambda_0,h_0))也就是 ENU 原点。注意ENU/NED 不是地图投影是站心切平面坐标变换LTP两套方向约定ENUE 东N 北U 天向上——Waymo、GTSAM、大多数自动驾驶定位后端NEDN 北E 东D 地向下——PX4、飞控、很多 IMU 器件坐标系NED 和 ENU 只是坐标轴重排 U 取反[NED][01010000−1][ENU] \begin{bmatrix} N \\ E \\ D \end{bmatrix} \begin{bmatrix} 0 1 0 \\ 1 0 0 \\ 0 0 -1 \end{bmatrix} \begin{bmatrix} E \\ N \\ U \end{bmatrix}​NED​​​010​100​00−1​​​ENU​​前置WGS84 椭球常数(\begin{aligned}a 6378137.0 \quad \text{半长轴(m)} \f 1/298.257223563 \quad \text{扁率} \e^2 2f-f^2 \quad \text{第一偏心率平方}\end{aligned})卯酉圈半径 (R_N \dfrac{a}{\sqrt{1-e2\sin2\phi}})a6378137.0半长轴(m)f1/298.257223563扁率e22f−f2第一偏心率平方 \begin{aligned} a 6378137.0 \quad \text{半长轴(m)} \\ f 1/298.257223563 \quad \text{扁率} \\ e^2 2f-f^2 \quad \text{第一偏心率平方} \end{aligned}afe2​6378137.0半长轴(m)1/298.257223563扁率2f−f2第一偏心率平方​卯酉圈半径RNa1−e2sin⁡2ϕ R_N \dfrac{a}{\sqrt{1-e^2\sin^2\phi}}RN​1−e2sin2ϕ​a​方法一标准完整变换工业 / 自动驾驶首选Waymo/GTSAM 底层实现步骤LLH → ECEF地心地固直角坐标求基准点 (P_0) 的 ECEF(X_0,Y_0,Z_0)矢量差(\Delta X X-X_0,\Delta YY-Y_0,\Delta ZZ-Z_0)ECEF → ENU 旋转矩阵(R_{enu} \begin{bmatrix}-\sin\lambda_0 \cos\lambda_0 0 \-\sin\phi_0\cos\lambda_0 -\sin\phi_0\sin\lambda_0 \cos\phi_0 \\cos\phi_0\cos\lambda_0 \cos\phi_0\sin\lambda_0 \sin\phi_0\end{bmatrix})(\begin{bmatrix}E\N\U\end{bmatrix} R_{enu}\begin{bmatrix}\Delta X \ \Delta Y \ \Delta Z\end{bmatrix})所有角度计算弧度逆变换ENU → ECEF → LLH方法二局部近似公式简易微分公式小范围 1km适合低成本小车不经过 ECEF直接用经纬度差换算东、北偏移(\begin{aligned}\Delta E R_N \cos\phi_0 \cdot (\lambda-\lambda_0) \\Delta N R_M \cdot (\phi-\phi_0) \\Delta U h - h_0\end{aligned})(R_M\dfrac{a(1-e2)}{(1-e2\sin2\phi_0){3/2}}) 子午圈半径⚠️ 缺点距离原点远了曲率误差明显不能用于高精度激光 IMU 融合下面代码优先实现【方法一标准 ECEF 中转版本】工程主用附带简易近似版本。Python 实现可直接运行WGS84 LLH - ENU - NEDimport math class Wgs84Ltp: # WGS84 椭球参数 A 6378137.0 F 1.0 / 298.257223563 E2 2 * F - F * F staticmethod def llh2ecef(lat_deg, lon_deg, h): LLH(度,度,m) - ECEF X,Y,Z (m) lat math.radians(lat_deg) lon math.radians(lon_deg) sin_lat math.sin(lat) cos_lat math.cos(lat) sin_lon math.sin(lon) cos_lon math.cos(lon) rn Wgs84Ltp.A / math.sqrt(1.0 - Wgs84Ltp.E2 * sin_lat * sin_lat) x (rn h) * cos_lat * cos_lon y (rn h) * cos_lat * sin_lon z (rn * (1 - Wgs84Ltp.E2) h) * sin_lat return x, y, z staticmethod def ecef2llh(x, y, z, max_iter10): ECEF - LLH (lat_deg, lon_deg, h) lon math.atan2(y, x) p math.hypot(x, y) lat math.atan2(z, p * (1 - Wgs84Ltp.E2)) for _ in range(max_iter): sin_lat math.sin(lat) rn Wgs84Ltp.A / math.sqrt(1.0 - Wgs84Ltp.E2 * sin_lat * sin_lat) h p / math.cos(lat) - rn lat math.atan2(z, p * (1 - Wgs84Ltp.E2 * rn / (rn h))) return math.degrees(lat), math.degrees(lon), h staticmethod def ecef2enu(x, y, z, x0, y0, z0, lat0_deg, lon0_deg): ECEF to ENU, origin P0(lat0,lon0,h0) lat0 math.radians(lat0_deg) lon0 math.radians(lon0_deg) dX x - x0 dY y - y0 dZ z - z0 s_lon0 math.sin(lon0) c_lon0 math.cos(lon0) s_lat0 math.sin(lat0) c_lat0 math.cos(lat0) e -s_lon0 * dX c_lon0 * dY n -s_lat0 * c_lon0 * dX - s_lat0 * s_lon0 * dY c_lat0 * dZ u c_lat0 * c_lon0 * dX c_lat0 * s_lon0 * dY s_lat0 * dZ return e, n, u staticmethod def enu2ecef(e, n, u, x0, y0, z0, lat0_deg, lon0_deg): ENU back to ECEF lat0 math.radians(lat0_deg) lon0 math.radians(lon0_deg) s_lon0 math.sin(lon0) c_lon0 math.cos(lon0) s_lat0 math.sin(lat0) c_lat0 math.cos(lat0) dx -s_lon0 * e - s_lat0 * c_lon0 * n c_lat0 * c_lon0 * u dy c_lon0 * e - s_lat0 * s_lon0 * n c_lat0 * s_lon0 * u dz c_lat0 * n s_lat0 * u return x0 dx, y0 dy, z0 dz staticmethod def llh2enu(lat, lon, h, lat0, lon0, h0): LLH - ENU 主入口 x0, y0, z0 Wgs84Ltp.llh2ecef(lat0, lon0, h0) x, y, z Wgs84Ltp.llh2ecef(lat, lon, h) return Wgs84Ltp.ecef2enu(x, y, z, x0, y0, z0, lat0, lon0) staticmethod def enu2llh(e, n, u, lat0, lon0, h0): ENU - LLH x0, y0, z0 Wgs84Ltp.llh2ecef(lat0, lon0, h0) x, y, z Wgs84Ltp.enu2ecef(e, n, u, x0, y0, z0, lat0, lon0) return Wgs84Ltp.ecef2llh(x, y, z) staticmethod def enu2ned(e, n, u): ENU转NED return n, e, -u staticmethod def ned2enu(n, e, d): NED转ENU return e, n, -d staticmethod def llh2enu_approx(lat, lon, h, lat0, lon0, h0): 【简易近似版本 方法二】适合小范围1km lat0_r math.radians(lat0) rn Wgs84Ltp.A / math.sqrt(1.0 - Wgs84Ltp.E2 * math.sin(lat0_r)**2) rm Wgs84Ltp.A * (1 - Wgs84Ltp.E2) / ((1 - Wgs84Ltp.E2 * math.sin(lat0_r)**2)**1.5) dlon math.radians(lon - lon0) dlat math.radians(lat - lat0) e rn * math.cos(lat0_r) * dlon n rm * dlat u h - h0 return e, n, u if __name__ __main__: # 测试样例 # 基准原点 P0 lat0 34.76 lon0 113.65 h0 100.0 # 目标点 lat 34.761 lon 113.652 h 105.0 e,n,u Wgs84Ltp.llh2enu(lat, lon, h, lat0, lon0, h0) print(fENU: E{e:.3f}, N{n:.3f}, U{u:.3f}) ned Wgs84Ltp.enu2ned(e,n,u) print(fNED: N{ned[0]:.3f}, E{ned[1]:.3f}, D{ned[2]:.3f}) # 逆变换验证 lat2, lon2, h2 Wgs84Ltp.enu2llh(e,n,u, lat0, lon0, h0) print(f逆算LLH: lat{lat2:.6f}, lon{lon2:.6f}, h{h2:.3f}) # 简易近似版本对比 e_ap, n_ap, u_ap Wgs84Ltp.llh2enu_approx(lat, lon, h, lat0, lon0, h0) print(f近似ENU: E{e_ap:.3f}, N{n_ap:.3f}, U{u_ap:.3f})C 实现Header cppROS/GTSAM 工程直接嵌入无第三方依赖wgs84_ltp.h#pragma once #include cmath struct ENU { double E, N, U; }; struct NED { double N, E, D; }; struct ECEF { double X, Y, Z; }; struct LLH { double lat; // deg double lon; // deg double h; // m }; class Wgs84Ltp { public: static constexpr double A 6378137.0; static constexpr double F 1.0 / 298.257223563; static constexpr double E2 2 * F - F * F; static ECEF llh2ecef(const LLH llh); static LLH ecef2llh(const ECEF ecef, int iter 10); static ENU ecef2enu(const ECEF p, const ECEF origin_ecef, double lat0_deg, double lon0_deg); static ECEF enu2ecef(const ENU enu, const ECEF origin_ecef, double lat0_deg, double lon0_deg); static ENU llh2enu(const LLH point, const LLH origin); static LLH enu2llh(const ENU enu, const LLH origin); static NED enu2ned(const ENU enu); static ENU ned2enu(const NED ned); // 简易微分近似版本 static ENU llh2enu_approx(const LLH point, const LLH origin); };wgs84_ltp.cpp#include wgs84_ltp.h ECEF Wgs84Ltp::llh2ecef(const LLH llh) { double lat llh.lat * M_PI / 180.0; double lon llh.lon * M_PI / 180.0; double slat sin(lat); double clat cos(lat); double slon sin(lon); double clon cos(lon); double rn A / sqrt(1.0 - E2 * slat * slat); ECEF out{}; out.X (rn llh.h) * clat * clon; out.Y (rn llh.h) * clat * slon; out.Z (rn * (1 - E2) llh.h) * slat; return out; } LLH Wgs84Ltp::ecef2llh(const ECEF ecef, int iter) { LLH out{}; out.lon atan2(ecef.Y, ecef.X); double p hypot(ecef.X, ecef.Y); double lat atan2(ecef.Z, p * (1 - E2)); double h 0.0; for(int i0; iiter; i){ double slat sin(lat); double rn A / sqrt(1.0 - E2 * slat * slat); h p / cos(lat) - rn; lat atan2(ecef.Z, p * (1 - E2 * rn/(rn h))); } out.lat lat * 180.0 / M_PI; out.lon out.lon * 180.0 / M_PI; out.h h; return out; } ENU Wgs84Ltp::ecef2enu(const ECEF p, const ECEF o, double lat0_deg, double lon0_deg) { double lat0 lat0_deg * M_PI / 180.0; double lon0 lon0_deg * M_PI / 180.0; double dX p.X - o.X; double dY p.Y - o.Y; double dZ p.Z - o.Z; double slon0 sin(lon0); double clon0 cos(lon0); double slat0 sin(lat0); double clat0 cos(lat0); ENU enu{}; enu.E -slon0 * dX clon0 * dY; enu.N -slat0*clon0*dX - slat0*slon0*dY clat0*dZ; enu.U clat0*clon0*dX clat0*slon0*dY slat0*dZ; return enu; } ECEF Wgs84Ltp::enu2ecef(const ENU enu, const ECEF o, double lat0_deg, double lon0_deg) { double lat0 lat0_deg * M_PI / 180.0; double lon0 lon0_deg * M_PI / 180.0; double slon0 sin(lon0); double clon0 cos(lon0); double slat0 sin(lat0); double clat0 cos(lat0); double dX -slon0 * enu.E - slat0*clon0*enu.N clat0*clon0*enu.U; double dY clon0 * enu.E - slat0*slon0*enu.N clat0*slon0*enu.U; double dZ clat0 * enu.N slat0 * enu.U; ECEF out{}; out.X o.X dX; out.Y o.Y dY; out.Z o.Z dZ; return out; } ENU Wgs84Ltp::llh2enu(const LLH point, const LLH origin) { ECEF o_ecef llh2ecef(origin); ECEF p_ecef llh2ecef(point); return ecef2enu(p_ecef, o_ecef, origin.lat, origin.lon); } LLH Wgs84Ltp::enu2llh(const ENU enu, const LLH origin) { ECEF o_ecef llh2ecef(origin); ECEF p_ecef enu2ecef(enu, o_ecef, origin.lat, origin.lon); return ecef2llh(p_ecef); } NED Wgs84Ltp::enu2ned(const ENU enu) { return {enu.N, enu.E, -enu.U}; } ENU Wgs84Ltp::ned2enu(const NED ned) { return {ned.E, ned.N, -ned.D}; } ENU Wgs84Ltp::llh2enu_approx(const LLH point, const LLH origin) { double lat0_r origin.lat * M_PI / 180.0; double slat0 sin(lat0_r); double rn A / sqrt(1.0 - E2 * slat0 * slat0); double rm A*(1-E2) / pow(1.0 - E2 * slat0*slat0, 1.5); double dlon_r (point.lon - origin.lon) * M_PI / 180.0; double dlat_r (point.lat - origin.lat) * M_PI / 180.0; ENU enu{}; enu.E rn * cos(lat0_r) * dlon_r; enu.N rm * dlat_r; enu.U point.h - origin.h; return enu; }main.cpp 测试#include iostream #include wgs84_ltp.h int main(){ LLH origin{34.76, 113.65, 100.0}; LLH pt{34.761, 113.652, 105.0}; ENU enu Wgs84Ltp::llh2enu(pt, origin); NED ned Wgs84Ltp::enu2ned(enu); std::cout ENU E: enu.E N: enu.N U: enu.U \n; std::cout NED N: ned.N E: ned.E D: ned.D \n; LLH back Wgs84Ltp::enu2llh(enu, origin); std::cout back lat: back.lat lon: back.lon h: back.h \n; return 0; }CMakeLists.txt编译cmake_minimum_required(VERSION 3.16) project(ltp_demo) set(CMAKE_CXX_STANDARD 17) add_executable(demo main.cpp wgs84_ltp.cpp)两种转换方法对比总结工程选型表格方案原理精度适用场景后端适配你前面 GTSAM / 联邦滤波【标准 ECEF 中转】LLH→ECEF→ENU严格椭球几何旋转矩阵变换全范围高精度自动驾驶、GNSS 后处理、激光 ICP、IMU 预积分✅首选Waymo 同款【局部微分近似】直接 Δlat Δlon 算 EN一阶泰勒切平面近似忽略高阶曲率项1km 很好远了漂移低成本单片机、简易小车可视化粗算❌ 不建议放进因子图优化残差补充工程实操要点和你之前定位链路打通原点选择策略固定原点高精地图原点整张地图一套 ENU缺点离原点几十公里曲率误差上来滑动原点sliding LTP以当前车辆 GNSS 位置动态刷新 P0Waymo/Cruise 滑动窗口定位后端方案永远保持车辆在原点附近曲率误差压到极小和 GTSAM 对接GTSAM 自带Pose3、Point3就是 ENU 空间把 GNSS、激光匹配、IMU 预积分全部放到 ENU 下构建因子坐标系转换顺序GNSS LLH → ENU后端优化域 → LLH → UTM/GK地图存储、可视化
延伸阅读

更多相关文章

2026/10/28 10:14:16

宿主机要重启、业务不能停?KVM 热迁移 + NFS 共享存储实操记录

生产机上的一次重启,往往意味着一片业务的停顿。KVM 热迁移要解决的就是这件事:把一台正在运行的虚拟机从 A 宿主机搬到 B 宿主机,业务几乎无感知。这篇用一套三节点实验(KVM1 / KVM2 / NFS)走完「克隆 → 配网络 → 搭…

2026/10/28 10:14:16

在 1Panel 应用商店部署 RustFS:安装、配置与验证步骤

装一套对象存储,教程往往一上来就是十几行的 docker run:挂卷、设环境变量、开端口,装完还得自己琢磨凭证和 TLS 的事。如果只是想给备份、图床或者网盘找个存储后端,可以先走一条更省事的路:RustFS 已经上架了 1Panel…

2026/10/28 10:09:13

电商用户画像构建方案:多源数据融合与DeepSeek偏好预测实战

简介:这份213页的PDF方案面向电商数据从业者、算法工程师与推荐系统学习者,围绕多源数据融合下的用户画像构建展开,系统解决消费者行为分析与偏好预测中的工程落地问题。内容从行业痛点与DeepSeek方案定位切入,依次覆盖多源数据采…

2026/10/28 11:25:07

Riffusion音频生成技术解析与应用实践

1. Riffusion音频生成技术解析Riffusion作为当前最前沿的AI音频生成模型,其核心是基于扩散模型(Diffusion Model)的频谱图生成技术。与传统音频生成方式不同,Riffusion直接在频谱域进行操作,通过迭代去噪过程生成高质量的音频频谱图&#xff…

2026/10/28 11:25:07

智能零售系统架构设计:高并发支付与实时行为分析

1. 项目背景与核心挑战大阪作为日本关西地区的商业中心,近年来智能零售业态快速发展。我们团队为当地某大型连锁便利店集团设计的这套系统,需要同时解决两个关键问题:一是高峰时段每秒数千笔的移动支付处理需求,二是对顾客动线、停…

2026/10/28 11:25:07

RT-DETR:实时目标检测的Transformer架构解析与实践

1. RT-DETR技术概述:当Transformer遇上实时目标检测RT-DETR(Real-Time Detection Transformer)是近年来目标检测领域最具突破性的架构之一。作为DETR系列的最新进化版本,它成功解决了传统Transformer检测器在实时性上的瓶颈问题。…

2026/10/28 11:25:07

家庭清洁清单:从区域到核对

先把范围写清楚整理家庭清洁清单时,可以先按厨房、卫生间、卧室和公共区域分类。每个区域只列需要处理的具体位置,例如台面、柜门外侧或地面。把整理物品与清洁表面分开记录,能更容易看清本次要做什么,也方便之后逐项核对。让步骤…

2026/10/28 11:25:07

AIC、MDL、MEVARC信源数目估计:原理、MATLAB实现与避坑指南

做阵列信号处理的朋友大概率都遇到过这个场景:采了一段多通道数据,画完特征值谱,盯着那条曲线琢磨——到底有几个源?信源数目估错了,后面的波束形成、DOA估计、盲源分离全是白搭。我最早做这套东西的时候,图…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/28 0:02:13

Python股票自动交易系统源码解析:从行情获取到风控的完整链路

简介:这份资源是面向高校计算机、金融相关专业毕业设计场景的完整项目源码包,主题为基于Python的股票自动交易系统,适合需要完成毕设选题、课程设计或自学金融量化交易开发的学生与开发者参考。压缩包共收录687个文件,整体约14.93…

2026/10/28 0:02:13

视酷酷信IM源码部署指南:Java 17+MySQL 8.0.33实战配置

简介:这是一套2024年亲测可部署的视酷酷信IM即时通讯系统源码,面向具备Java、OC、C#及Vue开发能力的技术人员,解决私有化即时通讯平台快速搭建与二次定制需求,尤其适用于需集成商城、保障数据主权的中小型企业或独立开发者。资源共…

2026/10/28 0:02:13

Python爬取百度迁徙数据:接口解析、批量采集与避坑指南

简介:这份资源是一个用Python爬取百度迁徙数据的脚本压缩包,面向具备Python基础、希望入门网络爬虫与数据解析的开发者,解决按日期获取全国热门城市人口迁徙数据的问题。包内共1个文件,为单个py脚本,压缩包约1KB&#…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑