ECEF與ENU坐標系定義及C語言實現

一、ECEF與ENU坐標系定義

  1. ECEF坐標系(地心地固坐標系)
  • 原點:地球質心
  • X軸:指向本初子午線與赤道交點
  • Y軸:在赤道平面內與X軸垂直
  • Z軸:指向北極
  • 數學表示: P e c e f = ( x , y , z ) P_{ecef} = (x, y, z) Pecef?=(x,y,z)
  1. ENU坐標系(東北天坐標系)
  • 原點:本地參考點
  • E軸:指向東方
  • N軸:指向北方
  • U軸:垂直地面向上
  • 數學表示: P e n u = ( e , n , u ) P_{enu} = (e, n, u) Penu?=(e,n,u)

二、坐標轉換數學原理

  1. 地理坐標轉ECEF:
    { x = ( N + h ) cos ? ? cos ? λ y = ( N + h ) cos ? ? sin ? λ z = ( N ( 1 ? e 2 ) + h ) sin ? ? \begin{cases} x = (N + h)\cos\phi\cos\lambda \\ y = (N + h)\cos\phi\sin\lambda \\ z = (N(1-e^2)+h)\sin\phi \end{cases} ? ? ??x=(N+h)cos?cosλy=(N+h)cos?sinλz=(N(1?e2)+h)sin??
    其中:
  • N = a 1 ? e 2 sin ? 2 ? N = \frac{a}{\sqrt{1-e^2\sin^2\phi}} N=1?e2sin2? ?a?(卯酉圈曲率半徑)
  • e 2 = 2 f ? f 2 e^2 = 2f - f^2 e2=2f?f2(橢球偏心率平方)
  • a = 6378137 m a=6378137m a=6378137m(WGS84長半軸)
  • f = 1 / 298.257223563 f=1/298.257223563 f=1/298.257223563(WGS84扁率)
  1. ECEF轉ENU:
    [ e n u ] = [ ? sin ? λ cos ? λ 0 ? sin ? ? cos ? λ ? sin ? ? sin ? λ cos ? ? cos ? ? cos ? λ cos ? ? sin ? λ sin ? ? ] [ x ? x 0 y ? y 0 z ? z 0 ] \begin{bmatrix} e \\ n \\ u \end{bmatrix} = \begin{bmatrix} -\sin\lambda & \cos\lambda & 0 \\ -\sin\phi\cos\lambda & -\sin\phi\sin\lambda & \cos\phi \\ \cos\phi\cos\lambda & \cos\phi\sin\lambda & \sin\phi \end{bmatrix} \begin{bmatrix} x-x_0 \\ y-y_0 \\ z-z_0 \end{bmatrix} ?enu? ?= ??sinλ?sin?cosλcos?cosλ?cosλ?sin?sinλcos?sinλ?0cos?sin?? ? ?x?x0?y?y0?z?z0?? ?

三、C語言實現(保存為ecef2enu.c)

#include <stdio.h>
#include <math.h>#define WGS84_A 6378137.0
#define WGS84_F 1/298.257223563typedef struct { double x, y, z; } ECEF;
typedef struct { double lat, lon, alt; } Geodetic;
typedef struct { double e, n, u; } ENU;ECEF geodetic_to_ecef(Geodetic geo) {double a = WGS84_A;double f = WGS84_F;double e2 = 2*f - f*f;double sinphi = sin(geo.lat);double cosphi = cos(geo.lat);double N = a / sqrt(1 - e2*sinphi*sinphi);ECEF ecef;ecef.x = (N + geo.alt) * cosphi * cos(geo.lon);ecef.y = (N + geo.alt) * cosphi * sin(geo.lon);ecef.z = (N*(1-e2) + geo.alt) * sinphi;return ecef;
}ENU ecef_to_enu(ECEF target, Geodetic ref_geo) {ECEF ref_ecef = geodetic_to_ecef(ref_geo);double dx = target.x - ref_ecef.x;double dy = target.y - ref_ecef.y;double dz = target.z - ref_ecef.z;double sinphi = sin(ref_geo.lat);double cosphi = cos(ref_geo.lat);double sinlam = sin(ref_geo.lon);double coslam = cos(ref_geo.lon);ENU enu;enu.e = -sinlam*dx + coslam*dy;enu.n = -sinphi*coslam*dx - sinphi*sinlam*dy + cosphi*dz;enu.u = cosphi*coslam*dx + cosphi*sinlam*dy + sinphi*dz;return enu;
}int main() {// 北京參考點(39.9042°N, 116.4074°E,海拔43m)Geodetic ref = {.lat = 39.9042 * M_PI/180,.lon = 116.4074 * M_PI/180,.alt = 43};// 生成測試數據(實際應用時可從文件讀取)for(int i=0; i<5; i++) {Geodetic target_geo = {.lat = ref.lat + 0.01*i,.lon = ref.lon + 0.01*i,.alt = ref.alt + 10*i};ECEF target_ecef = geodetic_to_ecef(target_geo);ENU enu = ecef_to_enu(target_ecef, ref);printf("ENU: E=%.3fm, N=%.3fm, U=%.3fm\n", enu.e, enu.n, enu.u);}return 0;
}

編譯執行:

gcc ecef2enu.c -lm -o ecef2enu && ./ecef2enu

四、Python驗證代碼

import numpy as np
import matplotlib.pyplot as plt
from pyproj import Transformer
from subprocess import check_output# 生成100個測試點
np.random.seed(42)
ref_lat, ref_lon = 39.9042, 116.4074
d_lats = np.random.uniform(-0.1, 0.1, 100)
d_lons = np.random.uniform(-0.1, 0.1, 100)
alts = np.random.uniform(0, 1000, 100)# 運行C程序獲取結果
c_output = check_output(["./ecef2enu"]).decode().strip().split('\n')
c_enu = [list(map(float, line.split()[2::2])) for line in c_output]# 使用pyproj計算
ecef_trans = Transformer.from_crs(4326, 4978)
enu_trans = Transformer.from_crs(4326, 4467, authority="EPSG",lon_0=ref_lon, lat_0=ref_lat, h_0=0)errors = []
for i in range(100):# Python計算結果lat = ref_lat + d_lats[i]lon = ref_lon + d_lons[i]alt = alts[i]# pyproj計算ENUecef = ecef_trans.transform(lat, lon, alt)enu_py = enu_trans.transform(lat, lon, alt)# 計算誤差enu_c = c_enu[i] if i <5 else [0,0,0] # 僅示例前5個errors.append(np.array(enu_py) - np.array(enu_c))# 可視化
errors = np.array(errors)
plt.figure(figsize=(12,4))plt.subplot(131)
plt.hist(errors[:,0], bins=20)
plt.title('East Error Distribution')
plt.xlabel('Meters')plt.subplot(132)
plt.hist(errors[:,1], bins=20)
plt.title('North Error Distribution')plt.subplot(133)
plt.scatter(errors[:,0], errors[:,1], alpha=0.6)
plt.xlabel('East Error')
plt.ylabel('North Error')
plt.tight_layout()
plt.savefig('enu_errors.png')
plt.show()

五、驗證結果分析

  1. 誤差直方圖顯示各方向誤差分布
  2. 散點圖展示平面誤差的相關性
  3. 典型誤差應小于1e-4米(數值計算誤差)

該實現完整展示了從理論到實踐的全流程,可通過調整測試點數量和分布進行更嚴格的驗證。實際工程應用中需考慮坐標系的旋轉順序、大地水準面模型等更多細節。

(驗證代碼還有BUG,不能直接運行,但是我肝不了了,該天再調了,晚安,嗎喀巴卡)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73070.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73070.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73070.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sql語句分頁的關鍵字是?

在 SQL 中&#xff0c;分頁通常是通過限制查詢結果的數量并指定從哪一行開始獲取數據來實現的。不同的數據庫系統使用不同的分頁關鍵字。 以下是常見數據庫系統的分頁關鍵字&#xff1a; MySQL / PostgreSQL / SQLite 使用 LIMIT 和 OFFSET 來進行分頁&#xff1a; LIMIT 限…

大模型中的剪枝、蒸餾是什么意思?

環境&#xff1a; 剪枝 蒸餾 問題描述&#xff1a; 大模型中的剪枝、蒸餾是什么意思&#xff1f; 解決方案&#xff1a; 大模型的剪枝&#xff08;Pruning&#xff09;和蒸餾&#xff08;Distillation&#xff09;是兩種常見的模型優化技術&#xff0c;用于減少模型的大小…

初次體驗Tauri和Sycamore(3)通道實現

? 原創作者&#xff1a;莊曉立&#xff08;LIIGO&#xff09; 原創時間&#xff1a;2025年03月10日&#xff08;發布時間&#xff09; 原創鏈接&#xff1a;https://blog.csdn.net/liigo/article/details/146159327 版權所有&#xff0c;轉載請注明出處。 20250310 LIIGO備注&…

代碼隨想錄|二叉樹|07二叉樹周末總結

對前面01~06二叉樹內容進行小結&#xff0c;直接看下面的總結文檔&#xff1a; 本周小結&#xff01;&#xff08;二叉樹&#xff09; | 代碼隨想錄

藍耘賦能通義萬相 2.1:用 C++ 構建高效 AI 視頻生成生態

目錄 開篇&#xff1a;AI 視頻生成新時代的號角 通義萬相 2.1&#xff1a;AI 視頻生成的領軍者 核心技術揭秘 功能特點展示 與其他模型的全面對比 C&#xff1a;高效編程的基石 C 的發展歷程與特性 C 在 AI 領域的廣泛應用 通義萬相 2.1 與 C 的完美融合 融合的意義與…

【一句話經驗】ubuntu vi/vim 模式自動設置為paste

從centos過來&#xff0c;發現ubutun有些地方不習慣&#xff0c;尤其是vi的粘貼&#xff0c;默認自動進去了代碼模式&#xff0c;導致每次粘貼必須得set paste&#xff0c;否則會出現問題。 解決辦法非常簡單&#xff0c;按照下面命令執行即可&#xff1a; cd ~ echo "…

自然語言處理文本分析:從詞袋模型到認知智能的進化之旅

清晨&#xff0c;當智能音箱準確識別出"播放周杰倫最新專輯"的模糊語音指令時&#xff1b;午間&#xff0c;企業輿情系統自動標記出十萬條評論中的負面情緒&#xff1b;深夜&#xff0c;科研人員用GPT-4解析百萬篇論文發現新材料線索——這些場景背后&#xff0c;是自…

《Python基礎教程》附錄B筆記:Python參考手冊

《Python基礎教程》第1章筆記&#x1f449;https://blog.csdn.net/holeer/article/details/143052930 附錄B Python參考手冊 Python標準文檔是完整的參考手冊。本附錄只是一個便利的速查表&#xff0c;當你開始使用Python進行編程后&#xff0c;它可幫助你喚醒記憶。 B.1 表…

uniapp+Vue3 組件之間的傳值方法

一、父子傳值&#xff08;props / $emit 、ref / $refs&#xff09; 1、props / $emit 父組件通過 props 向子組件傳遞數據&#xff0c;子組件通過 $emit 觸發事件向父組件傳遞數據。 父組件&#xff1a; // 父組件中<template><view class"container">…

【MySQL篇】MySQL基本查詢詳解

目錄 前言&#xff1a; 1&#xff0c;Create 1.1&#xff0c;單行數據全列插入 1.2&#xff0c;單行數據指定列插入 1.3&#xff0c;多行數據全列插入 1.4&#xff0c;多行數據指定列插入 1.5&#xff0c;插入否則更新 1.6&#xff0c;替換 2&#xff0c;Retrieve …

【Python入門】一篇掌握Python中的字典(創建、訪問、修改、字典方法)【詳細版】

&#x1f308; 個人主頁&#xff1a;十二月的貓-CSDN博客 &#x1f525; 系列專欄&#xff1a; &#x1f3c0;《Python/PyTorch極簡課》_十二月的貓的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻擋不了春天的腳步&#xff0c;十二點的黑夜遮蔽不住黎明的曙光 目…

每日一題——兩數相加

兩數相加 問題描述問題分析解題思路代碼實現代碼解析注意事項示例運行總結 問題描述 給定兩個非空鏈表&#xff0c;表示兩個非負整數。鏈表中的每個節點存儲一個數字&#xff0c;數字的存儲順序為逆序&#xff08;即個位在鏈表頭部&#xff09;。要求將這兩個數字相加&#xff…

制作自定義鏡像

1. 確定軟件包 確定自己的環境都需要哪些命令&#xff0c;然后&#xff0c;從鏡像文件或者yum源下載響應的安裝包。 bash基本是必選的 &#xff08;bash-5.1.8-10.oe2203sp2.aarch64.rpm&#xff09; vim也是有必要的 &#xff08;vim-enhanced-9.0-15.oe2203sp2.aarch64.rpm…

WHAT - 前端性能指標

目錄 核心 Web Vitals&#xff08;Core Web Vitals&#xff09;加載性能指標網絡相關指標交互和響應性能指標內存與效率指標推薦的監控工具優化策略與建議推薦學習路線 作為前端開發者&#xff0c;理解并掌握關鍵的性能指標對優化 Web 應用至關重要。 以下是前端性能優化中常見…

C++20 模塊:告別頭文件,迎接現代化的模塊系統

文章目錄 引言一、C20模塊簡介1.1 傳統頭文件的局限性1.2 模塊的出現 二、模塊的基本概念2.1 模塊聲明2.2 模塊接口單元2.3 模塊實現單元 三、模塊的優勢3.1 編譯時間大幅減少3.2 更好的依賴管理3.3 命名空間隔離 四、如何使用C20模塊4.1 編譯器支持4.2 示例項目4.3 編譯和運行…

Apache Hudi 性能測試報告

一、測試背景 數據湖作為一個集中化的數據存儲倉庫,支持結構化、半結構化以及非結構化等多種數據格式,數據來源包含數據庫數據、增量數據、日志數據以及數倉上的存量數據等。數據湖能夠將這些不同來源、不同格式的數據集中存儲和管理在高性價比的分布式存儲系統中,對外提供…

sql靶場5-6關(報錯注入)保姆級教程

目錄 sql靶場5-6關&#xff08;報錯注入&#xff09;保姆級教程 1.第五關 1.步驟一&#xff08;閉合&#xff09; 2.步驟二&#xff08;列數&#xff09; 3.報錯注入深解 4.報錯注入格式 5.步驟三&#xff08;數據庫表名&#xff09; 6.常用函數 7.步驟四&#xff08;表…

OSPF-單區域的配置

一、單區域概念&#xff1a; 單區域OSPF中&#xff0c;整個網絡被視為一個區域&#xff0c;區域ID通常為0&#xff08;骨干區域&#xff09;。所有的路由器都在這個區域內交換鏈路狀態信息。 補充知識點&#xff1a; OSPF為何需要loopback接口&#xff1a; 1.Loopback接口的…

LeetCode100之二叉樹的直徑(543)--Java

1.問題描述 給你一棵二叉樹的根節點&#xff0c;返回該樹的 直徑 。 二叉樹的 直徑 是指樹中任意兩個節點之間最長路徑的 長度 。這條路徑可能經過也可能不經過根節點 root 。 兩節點之間路徑的 長度 由它們之間邊數表示。 示例1 輸入&#xff1a;root [1,2,3,4,5] 輸出&#…

C語言每日一練——day_4

引言 針對初學者&#xff0c;每日練習幾個題&#xff0c;快速上手C語言。第四天。&#xff08;連續更新中&#xff09; 采用在線OJ的形式 什么是在線OJ&#xff1f; 在線判題系統&#xff08;英語&#xff1a;Online Judge&#xff0c;縮寫OJ&#xff09;是一種在編程競賽中用…