[学习]RTKLib详解:convkml.c、convrnx.c与geoid.c


本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。

[学习] RTKlib详解:功能、工具与源码结构解析
[学习]RTKLib详解:pntpos.c与postpos.c
[学习]RTKLib详解:rtkcmn.c与rtkpos.c
[学习]RTKLib详解:ppp.c与ppp_ar.c
[学习]RTKLib详解:ephemeris.c与rinex.c


文章目录


Part A: convkml.c 文件解析

一、文件整体说明

convkml.c 是 RTKLIB 中用于将 GNSS 数据转换为 KML(Keyhole Markup Language)格式的工具,便于在 Google Earth 等地理可视化软件中展示轨迹、观测点等信息。该文件主要实现了从 RINEX 或 RTKLIB 内部数据结构到 KML 标记语言的转换。

主要功能:

  • 将 GNSS 观测数据转换为 KML 格式。
  • 支持多种显示样式,如路径、标记点、高度剖面图等。
  • 可选输出模式包括静态点、动态路径等。

主要特色:

  • 支持多频段和多系统数据。
  • 提供灵活的样式配置选项。
  • 可导出不同时间分辨率的数据点。

二、执行流程与函数调用关系

程序执行流程如下:

  1. 初始化参数设置。
  2. 读取输入数据(如 RINEX 文件)。
  3. 处理数据并提取位置信息。
  4. 生成 KML 文件内容。
  5. 写入 KML 文件并关闭资源。

函数调用关系如下所示:
main readcmdline initopt readobsfile convkml writekmlhead writekmlbody writekmldata writekmltail

其中:

  • readcmdline: 解析命令行参数。
  • initopt: 初始化输出选项。
  • readobsfile: 读取观测文件(RINEX等)。
  • convkml: 主要转换逻辑入口。
  • writekml* 函数负责生成 KML 的各个部分。

三、主要函数说明

3.1 main
c 复制代码
int main(int argc, char *argv[])

功能:

主函数,负责接收命令行参数并调度各模块完成 KML 转换。

输入参数:

  • argc: 命令行参数个数。
  • argv[]: 命令行参数数组。

输出参数:

  • 返回状态码(0 表示成功,非零表示错误)。

3.2 readcmdline
c 复制代码
void readcmdline(int argc, char *argv[], opt_t *opt)

功能:

解析命令行参数并填充配置结构体 opt

输入参数:

  • argc, argv[]: 命令行参数。
  • opt: 输出参数,包含所有配置选项。

3.3 readobsfile
c 复制代码
int readobsfile(const char *file, obs_t *obs, nav_t *nav, opt_t *opt)

功能:

读取观测文件(如 RINEX),并将数据存储到 obsnav 结构体中。

输入参数:

  • file: 输入文件路径。
  • obs: 存储观测数据的结构体指针。
  • nav: 存储导航数据的结构体指针。
  • opt: 配置选项。

返回值:

  • 成功返回 1,失败返回 0。

3.4 convkml
c 复制代码
int convkml(FILE *fp, const obs_t *obs, const nav_t *nav, const opt_t *opt)

功能:

核心转换函数,将 GNSS 数据转换为 KML 格式并写入文件。

输入参数:

  • fp: 文件指针。
  • obs, nav, opt: 输入数据与配置。

返回值:

  • 成功返回 1,失败返回 0。

3.5 writekmlhead
c 复制代码
void writekmlhead(FILE *fp, const opt_t *opt)

功能:

写入 KML 文件头部信息,包括文档声明、命名空间等。

输入参数:

  • fp: 文件指针。
  • opt: 配置信息。

3.6 writekmlbody
c 复制代码
void writekmlbody(FILE *fp, const obs_t *obs, const nav_t *nav, const opt_t *opt)

功能:

写入 KML 主体内容,包括路径、标记点等。

输入参数:

  • fp, obs, nav, opt: 同上。

3.7 writekmltail
c 复制代码
void writekmltail(FILE *fp)

功能:

写入 KML 文件尾部标签,结束文档。

输入参数:

  • fp: 文件指针。

四、关键算法数学原理与推导

地理坐标系到 ECEF 的转换

GNSS 接收机通常输出经纬度和高度(LLH),但 KML 使用的是地心坐标系(ECEF)。因此需要进行 LLH 到 ECEF 的转换。

公式如下:

N = a 1 − e 2 sin ⁡ 2 ( ϕ ) x = ( N + h ) cos ⁡ ( ϕ ) cos ⁡ ( λ ) y = ( N + h ) cos ⁡ ( ϕ ) sin ⁡ ( λ ) z = [ N ( 1 − e 2 ) + h ] sin ⁡ ( ϕ ) \begin{aligned} &N = \frac{a}{\sqrt{1 - e^2 \sin^2(\phi)}} \\ &x = (N + h)\cos(\phi)\cos(\lambda) \\ &y = (N + h)\cos(\phi)\sin(\lambda) \\ &z = \left[N(1 - e^2) + h\right]\sin(\phi) \end{aligned} N=1−e2sin2(ϕ) ax=(N+h)cos(ϕ)cos(λ)y=(N+h)cos(ϕ)sin(λ)z=[N(1−e2)+h]sin(ϕ)

其中:

  • ϕ \phi ϕ: 纬度(弧度)
  • λ \lambda λ: 经度(弧度)
  • h h h: 椭球高
  • a a a: WGS84 长半轴
  • e 2 = 1 − b 2 a 2 e^2 = 1 - \frac{b^2}{a^2} e2=1−a2b2: 第一偏心率平方

这个转换是绘制轨迹的基础。


Part B: convrnx.c 文件解析

一、文件整体说明

convrnx.c 是 RTKLIB 中用于将各种原始观测数据(如 BINEX、UBX、RTCM 等)转换为 RINEX 格式的工具。RINEX 是 GNSS 数据的标准格式,广泛用于后处理和分析。

主要功能:

  • 多种原始数据格式转 RINEX。
  • 支持多频段、多系统。
  • 自动识别输入数据格式。

主要特色:

  • 支持自动探测输入数据类型。
  • 提供灵活的时间过滤与输出选项。
  • 可以输出压缩的 RINEX(.crx/.gz)。

二、执行流程与函数调用关系

程序执行流程如下:

  1. 解析命令行参数。
  2. 打开输入/输出文件。
  3. 读取并解析原始数据流。
  4. 转换为 RINEX 格式并写入文件。
  5. 清理资源并退出。

函数调用关系如下:
main readcmdline initrnx openfiles convertrnx readrawdata outputrnx closefiles


三、主要函数说明

3.1 main
c 复制代码
int main(int argc, char *argv[])

功能:

主函数,解析命令行参数并控制整个转换流程。

输入输出:

  • 同前文。

3.2 readcmdline
c 复制代码
void readcmdline(int argc, char *argv[], rnxopt_t *opt)

功能:

解析命令行参数并填充 rnxopt_t 结构体。

输入输出:

  • 同前文。

3.3 initrnx
c 复制代码
int initrnx(rnxopt_t *opt)

功能:

根据用户配置初始化 RINEX 转换参数。

输入参数:

  • opt: 转换配置结构体。

3.4 openfiles
c 复制代码
int openfiles(const char *infile, const char *outfile, FILE **fpin, FILE **fpout, rnxopt_t *opt)

功能:

打开输入和输出文件,支持压缩格式。

输入参数:

  • infile, outfile: 文件路径。
  • fpin, fpout: 文件指针地址。
  • opt: 配置。

3.5 convertrnx
c 复制代码
int convertrnx(FILE *fpin, FILE *fpout, rnxopt_t *opt)

功能:

主转换循环,读取原始数据并写入 RINEX。

输入输出:

  • 同上。

3.6 readrawdata
c 复制代码
int readrawdata(FILE *fp, unsigned char *buff, int nmax, int format, raw_t *raw)

功能:

读取原始观测数据并解析为内部结构。

输入参数:

  • fp: 输入文件指针。
  • buff: 缓冲区。
  • nmax: 最大读取长度。
  • format: 数据格式(如 RTCM3, UBX 等)。
  • raw: 输出解析后的数据。

返回值:

  • 成功返回字节数,失败返回负值。

3.7 outputrnx
c 复制代码
int outputrnx(FILE *fp, const raw_t *raw, const rnxopt_t *opt)

功能:

将解析后的数据按 RINEX 格式写入输出文件。

输入参数:

  • fp, raw, opt: 同上。

3.8 closefiles
c 复制代码
void closefiles(FILE *fpin, FILE *fpout)

功能:

关闭输入输出文件句柄。


四、关键算法数学原理与推导

时间系统转换

原始数据中的时间戳可能使用 GPS 时间、UTC、本地时间等,而 RINEX 要求使用 GPS 时间或 UTC。因此需要进行时间系统转换。

GPS 时间与 UTC 的关系为:

t G P S = t U T C + Δ t l e a p t_{GPS} = t_{UTC} + \Delta t_{leap} tGPS=tUTC+Δtleap

其中 Δ t l e a p \Delta t_{leap} Δtleap 是闰秒修正值,需通过星历或头文件获取。


Part C: geoid.c 文件解析

一、文件整体说明

geoid.c 实现了大地高与正常高的相互转换,依赖于大地水准面模型(如 EGM96、EGM2008)。它提供了基于插值方法的大地高与正高之间的转换功能。

主要功能:

  • 计算某一点的大地水准面高(N)。
  • 支持多种大地水准面模型。
  • 提供双线性插值功能。

主要特色:

  • 支持网格化模型数据。
  • 可扩展性强,易于添加新模型。
  • 高效的插值算法。

二、执行流程与函数调用关系

程序执行流程如下:

  1. 加载大地水准面模型文件。
  2. 对给定的地理坐标进行插值计算。
  3. 输出大地水准面高。

函数调用关系如下:
geoid_hgt load_geoid interp_geoid bilin_interp


三、主要函数说明

3.1 geoid_hgt
c 复制代码
double geoid_hgt(double lat, double lon, const char *model)

功能:

对外接口,输入经纬度和模型名,返回大地水准面高。

输入参数:

  • lat, lon: 地理纬度和经度(十进制度)。
  • model: 模型名称(如 "egm96_15")。

返回值:

  • 大地水准面高 N(米)。

3.2 load_geoid
c 复制代码
int load_geoid(const char *model, geoid_t *geoid)

功能:

加载指定模型的网格数据到内存。

输入参数:

  • model: 模型名。
  • geoid: 存储模型数据的结构体。

返回值:

  • 成功返回 1,失败返回 0。

3.3 interp_geoid
c 复制代码
double interp_geoid(double lat, double lon, const geoid_t *geoid)

功能:

调用双线性插值函数计算某点的大地水准面高。

输入参数:

  • lat, lon: 插值点坐标。
  • geoid: 模型数据结构体。

返回值:

  • 插值结果(米)。

3.4 bilin_interp
c 复制代码
double bilin_interp(double x, double y, double *v, int nx, int ny)

功能:

实现双线性插值算法。

输入参数:

  • x, y: 插值点坐标。
  • v: 网格数据数组。
  • nx, ny: 网格尺寸。

返回值:

  • 插值结果。

四、关键算法数学原理与推导

双线性插值

设四个角点分别为:

  • f ( x 1 , y 1 ) f(x_1, y_1) f(x1,y1)
  • f ( x 2 , y 1 ) f(x_2, y_1) f(x2,y1)
  • f ( x 1 , y 2 ) f(x_1, y_2) f(x1,y2)
  • f ( x 2 , y 2 ) f(x_2, y_2) f(x2,y2)

目标点 ( x , y ) (x, y) (x,y) 在矩形区域内,则插值公式为:

f ( x , y ) = ( x 2 − x ) ( y 2 − y ) Δ x Δ y f ( x 1 , y 1 ) + ( x − x 1 ) ( y 2 − y ) Δ x Δ y f ( x 2 , y 1 ) + ( x 2 − x ) ( y − y 1 ) Δ x Δ y f ( x 1 , y 2 ) + ( x − x 1 ) ( y − y 1 ) Δ x Δ y f ( x 2 , y 2 ) f(x,y) = \frac{(x_2 - x)(y_2 - y)}{\Delta x \Delta y} f(x_1,y_1) + \frac{(x - x_1)(y_2 - y)}{\Delta x \Delta y} f(x_2,y_1) + \frac{(x_2 - x)(y - y_1)}{\Delta x \Delta y} f(x_1,y_2) + \frac{(x - x_1)(y - y_1)}{\Delta x \Delta y} f(x_2,y_2) f(x,y)=ΔxΔy(x2−x)(y2−y)f(x1,y1)+ΔxΔy(x−x1)(y2−y)f(x2,y1)+ΔxΔy(x2−x)(y−y1)f(x1,y2)+ΔxΔy(x−x1)(y−y1)f(x2,y2)

其中 Δ x = x 2 − x 1 \Delta x = x_2 - x_1 Δx=x2−x1, Δ y = y 2 − y 1 \Delta y = y_2 - y_1 Δy=y2−y1。

此方法用于大地水准面模型的离散数据插值。


研究学习不易,点赞易。

工作生活不易,收藏易,点收藏不迷茫 :)


相关推荐
菲兹园长9 分钟前
MyBatis-Plus
java·开发语言·mybatis
strongwyy14 分钟前
DA14585墨水屏学习(2)
前端·javascript·学习
renhl25214 分钟前
英语句型结构
学习
修修修也34 分钟前
【C++】特殊类设计
开发语言·c++·特殊类·类与对象
Cloud Traveler39 分钟前
Java并发编程常见问题与陷阱解析
java·开发语言·python
海尔辛1 小时前
学习黑客了解Python3的“HTTPServer“
学习
虾球xz1 小时前
游戏引擎学习第274天:基于弹簧的动态动画
c++·学习·游戏引擎
byte轻骑兵1 小时前
【C++重载操作符与转换】转换与继承
开发语言·c++
少了一只鹅1 小时前
深入理解指针(5)
java·c语言·数据结构·算法
白天学嵌入式2 小时前
STM32f103 标准库 零基础学习之按键点灯(不涉及中断)
stm32·单片机·学习