9.1 主要数据类型
9.1.1 概述
1. 主要关系

图9.1-1 rtkpos() 简略输入输出
如果比较简单地理解 rtkpos()
函数的输入输出,我们可以认为:
- 输入:原始观测数据
obs
, 星历相关数据nav
和配置选项opt
。 - 输出:定位结果与过程数据
rtk
。
其中 rtkpos()
内部包含的 relpos()
则是本章节我们需要重点关注的内容。实际上整个过程会更加复杂,例如 rtk_t
结构体中的数据既可能作为输入,也会同时作为输出,因为 rtk_t
中存储了很多过程数据,它们会作为滤波器下一轮迭代的初值,而 opt
配置选项其实也包含于 rtk_t
结构体中。
- 后处理时:postpos.c 中的
procpos()
函数循环中,调用inputobs()
每次取一个历元的观测数据用rtkpos()
处理; - 实时定位时:rtkrcv.c 中的 rtksvrthread() 函数循环调用 strread 读取原始观测数据流,再利用 decoderaw 函数解码为
obs_t
和nav_t
结构体,最后调用rtkpos()
处理。
注意对于以上内容仅保留一个初略的印象即可,实际上 rtkpos()
函数的执行流程远比上述过程复杂得多。算法的解析、理解或优化并不会因为梳理完整个流程就能通透,而是需要解决一些有针对性的问题,用以满足研究或工程的需求。
9.1.2 obs_t:原始观测数据结构体
obs_t
结构体实际上维护了一个由原始观测数据所组成的数组 obsd_t *data
。
/* observation data */
typedef struct {
int n,nmax; /* 观测数据数目/最大存储数量(与申请内存空间相关) */
obsd_t *data; /* 观测数据(数组) */
} obs_t;
obsd_t
组成:
data
字段是obsd_t
数组。n
字段表示存着的obsd_t
数目。nmax
字段表示目前data
内存空间最大能存的obsd_t
数目。
/* observation data record */
typedef struct {
gtime_t time; /* 接收机信号采样时间 (GPST) */
uint8_t sat,rcv; /* 卫星/接收机编号 */
uint16_t SNR[NFREQ+NEXOBS]; /* SNR,准确来说是C/N0 (0.001 dBHz) */
uint8_t LLI[NFREQ+NEXOBS]; /* 周跳标识(来自于接收机,而非算法探测) */
uint8_t code[NFREQ+NEXOBS]; /* 信号码标识 (CODE_???),用以识别信号频点类型 */
double L[NFREQ+NEXOBS]; /* 载波相位(cycle) */
double P[NFREQ+NEXOBS]; /* 伪距(m) */
float D[NFREQ+NEXOBS]; /* 多普勒频率(Hz) */
} obsd_t;
对于观测数据的解析过程,可以以后处理为例(rinex.c):
addobsdata()
函数执行向obs->data[]
中添加obs
观测值数据的操作,先检验nmax
值,不够再realloc()
动态申请更多内存;readobsnav()
函数中读取完obs
数据后,会调用sortobs()
根据time, rcv, sat
,对obs->data
的元素进行排序、去重,得到历元数nepoch
,调用uniqnav()
,进行星历数据的排序去重;
9.1.3 nav_t:导航电文信息结构体
nav_t
用以存储星历数据、历书数据、精密星历、TEC格网、广播星历电离层参数、DGPS和SSR改正信息,存储 eph
、geph
、seph
、peph
、pclk
、alm
、erp
的方式与 obs_t
存 obs
的方式类似。
点击查看代码
typedef struct { /* navigation data type */
int n,nmax; /* number of broadcast ephemeris */
int ng,ngmax; /* number of glonass ephemeris */
int ns,nsmax; /* number of sbas ephemeris */
int ne,nemax; /* number of precise ephemeris */
int nc,ncmax; /* number of precise clock */
int na,namax; /* number of almanac data */
int nt,ntmax; /* number of tec grid data */
eph_t *eph; /* GPS/QZS/GAL/BDS/IRN ephemeris */
geph_t *geph; /* GLONASS ephemeris */
seph_t *seph; /* SBAS ephemeris */
peph_t *peph; /* precise ephemeris */
pclk_t *pclk; /* precise clock */
alm_t *alm; /* almanac data */
tec_t *tec; /* tec grid data */
erp_t erp; /* earth rotation parameters */
double utc_gps[8]; /* GPS delta-UTC parameters {A0,A1,Tot,WNt,dt_LS,WN_LSF,DN,dt_LSF} */
double utc_glo[8]; /* GLONASS UTC time parameters {tau_C,tau_GPS} */
double utc_gal[8]; /* Galileo UTC parameters */
double utc_qzs[8]; /* QZS UTC parameters */
double utc_cmp[8]; /* BeiDou UTC parameters */
double utc_irn[9]; /* IRNSS UTC parameters {A0,A1,Tot,...,dt_LSF,A2} */
double utc_sbs[4]; /* SBAS UTC parameters */
double ion_gps[8]; /* GPS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
double ion_gal[4]; /* Galileo iono model parameters {ai0,ai1,ai2,0} */
double ion_qzs[8]; /* QZSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
double ion_cmp[8]; /* BeiDou iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
double ion_irn[8]; /* IRNSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
int glo_fcn[32]; /* GLONASS FCN + 8 */
double cbias[MAXSAT][3]; /* satellite DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */
double rbias[MAXRCV][2][3]; /* receiver DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */
pcv_t pcvs[MAXSAT]; /* satellite antenna pcv */
sbssat_t sbssat; /* SBAS satellite corrections */
sbsion_t sbsion[MAXBAND+1]; /* SBAS ionosphere corrections */
dgps_t dgps[MAXSAT]; /* DGPS corrections */
ssr_t ssr[MAXSAT]; /* SSR corrections */
} nav_t;
其中:
- 多系统支持:包含 GPS、GLONASS、Galileo 等星历(eph, geph, seph),需区分格式和更新频率。
- PPP 数据:
peph
和pclk
用于 PPP。 - UTC:历书(或概略星历)参数,目前基本不用,
utc_*
为与系统相关参数,从导航电文更新。 - 电离层参数:klobuchar 模型参数,
ion_*
为与系统相关参数,需从导航电文更新。 - GLONASS FCN:
glo_fcn
需正确初始化,否则会影响频率计算。 - DCB 和 PCV:
cbias
,rbias
,pcvs
用于高精度校正,需从外部文件加载。 - 增强数据:
sbssat
,sbsion
,dgps
,ssr
支持差分和增强。 - ERP:
erp
影响高精度坐标转换,需加载有效数据。
关于 GLONASS FCN:
由于 GLONASS 采用 FDMA,其每颗卫星频段都不同,因此在实际使用时,需要根据观测数据中的卫星槽号(PRN)到星历数据中找对应的频段号(FCN),才能解析出信号频率,并应用到算法执行过程中。更多内容可以参考 附录 B.5 差分数据中 GLO 卫星无法投入计算。
关于 ERP:
对于其中的 erp
,它在 zdres
函数(rtkpos.c)中调用,其作用是提供地球自转参数(极移 xp
, yp
和 UT1-UTC 差 ut1_utc
),用于计算极潮校正,提供位置精度:
- 当
opt->tidecorr = 2
(Solid/OTL),tidedisp
使用nav->erp
计算极潮位移(disp
),校正接收机位置,影响几何距离和残差计算。 需从 ERP 文件加载数据,缺失可能导致厘米级误差。 - 对 PPP 和长基线 RTK 影响显著,短基线 RTK 可忽略。
- 配置需确保
tidecorr
和 ERP 文件匹配,nav->utc_gps
正确以支持时间转换。
9.1.4 rtk_t:rtk 控制结构体
rtk_t
结构体是 RTKLIB 定位状态的核心,主要用于存储定位结果和一些过程数据。
sol_t sol; // 解算结果结构体
double rb[6]; // 基站位置、速度
int nx,na; // na为除模糊度外参数数,nx为加上模糊度参数数
double tt; // 当前历元与先前历元时间差
double *x, *P; // 浮点解及其误差协方差
double *xa,*Pa; // 固定解及其误差协方差
int nfix; // 持续固定的历元计数
ambc_t ambc[MAXSAT]; // 模糊度控制结构体数组
ssat_t ssat[MAXSAT]; // 卫星状态控制结构体数组
int neb; // 错误信息的缓冲区长度
char errbuf[MAXERRMSG]; // 错误信息缓冲区
prcopt_t opt; // 算法处理配置选项
其中:
sol
:存储解算结果(位置、速度、状态),需检查sol.stat
和sol.qr
评估解算质量。rb
:基站位置/速度,由于 RTK 算法计算的是基线向量,因此需要通过基站的位置推算出流动站的位置。nx
,na
:状态向量维度。tt
:时间差,滤波器更新时使用。x
,P
:浮点解和协方差。xa
,Pa
,nfix
:固定解相关,nfix 会 hold 状态提供依据。ambc
,ssat
:管理模糊度和卫星状态,需关注周跳(slip
)和锁定(lock
)。neb
,errbuf
:调试错误信息。opt
:配置选项。
9.1.5 prcopt_t:算法处理选项结构体
点击查看代码
typedef struct { /* processing options type */
int mode; /* positioning mode (PMODE_???) */
int soltype; /* solution type (0:forward,1:backward,2:combined) */
int nf; /* number of frequencies (1:L1,2:L1+L2,3:L1+L2+L5) */
int navsys; /* navigation system */
double elmin; /* elevation mask angle (rad) */
snrmask_t snrmask; /* SNR mask */
int sateph; /* satellite ephemeris/clock (EPHOPT_???) */
int modear; /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */
int glomodear; /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */
int bdsmodear; /* BeiDou AR mode (0:off,1:on) */
int maxout; /* obs outage count to reset bias */
int minlock; /* min lock count to fix ambiguity */
int minfix; /* min fix count to hold ambiguity */
int armaxiter; /* max iteration to resolve ambiguity */
int ionoopt; /* ionosphere option (IONOOPT_???) */
int tropopt; /* troposphere option (TROPOPT_???) */
int dynamics; /* dynamics model (0:none,1:velociy,2:accel) */
int tidecorr; /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */
int niter; /* number of filter iteration */
int codesmooth; /* code smoothing window size (0:none) */
int intpref; /* interpolate reference obs (for post mission) */
int sbascorr; /* SBAS correction options */
int sbassatsel; /* SBAS satellite selection (0:all) */
int rovpos; /* rover position for fixed mode */
int refpos; /* base position for relative mode */
/* (0:pos in prcopt, 1:average of single pos, */
/* 2:read from file, 3:rinex header, 4:rtcm pos) */
double eratio[NFREQ]; /* code/phase error ratio */
double err[5]; /* measurement error factor */
/* [0]:reserved */
/* [1-3]:error factor a/b/c of phase (m) */
/* [4]:doppler frequency (hz) */
double std[3]; /* initial-state std [0]bias,[1]iono [2]trop */
double prn[6]; /* process-noise std [0]bias,[1]iono [2]trop [3]acch [4]accv [5] pos */
double sclkstab; /* satellite clock stability (sec/sec) */
double thresar[8]; /* AR validation threshold */
double elmaskar; /* elevation mask of AR for rising satellite (deg) */
double elmaskhold; /* elevation mask to hold ambiguity (deg) */
double thresslip; /* slip threshold of geometry-free phase (m) */
double maxtdiff; /* max difference of time (sec) */
double maxinno; /* reject threshold of innovation (m) */
double maxgdop; /* reject threshold of gdop */
double baseline[2]; /* baseline length constraint {const,sigma} (m) */
double ru[3]; /* rover position for fixed mode {x,y,z} (ecef) (m) */
double rb[3]; /* base position for relative mode {x,y,z} (ecef) (m) */
char anttype[2][MAXANT]; /* antenna types {rover,base} */
double antdel[2][3]; /* antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */
pcv_t pcvr[2]; /* receiver antenna parameters {rov,base} */
uint8_t exsats[MAXSAT]; /* excluded satellites (1:excluded,2:included) */
int maxaveep; /* max averaging epoches */
int initrst; /* initialize by restart */
int outsingle; /* output single by dgps/float/fix/ppp outage */
char rnxopt[2][256]; /* rinex options {rover,base} */
int posopt[6]; /* positioning options */
int syncsol; /* solution sync mode (0:off,1:on) */
double odisp[2][6*11]; /* ocean tide loading parameters {rov,base} */
int freqopt; /* disable L2-AR */
char pppopt[256]; /* ppp option */
} prcopt_t;
更多关于配置参数的分析,可以查看附录C: 配置参数解析。
9.1.6 sol_t:结果结构体
gtime_t time; // GPST时间
double rr[6]; // 位置、速度结果 (m|m/s)
/* {x,y,z,vx,vy,vz} or {e,n,u,ve,vn,vu} */
float qr[6]; // 位置估计协方差阵 (m^2)
/* {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} or */
/* {c_ee,c_nn,c_uu,c_en,c_nu,c_ue} */
float qv[6]; // 速度估计协方差阵 (m^2/s^2)
double dtr[6]; // 接收机钟差 (s)
uint8_t type; // 坐标系类型 (0:xyz-ecef,1:enu-baseline)
uint8_t stat; // 定位结果状态 (SOLQ_???)
uint8_t ns; // 有效卫星数
float age; // 差分龄期
float ratio; // 模糊度固定Ratio值
float thres; // 模糊度固定的Ratio阈值
其中的解状态类型 stat
:
#define SOLQ_NONE 0 /* solution status: no solution */
#define SOLQ_FIX 1 /* solution status: fix */
#define SOLQ_FLOAT 2 /* solution status: float */
#define SOLQ_SBAS 3 /* solution status: SBAS */
#define SOLQ_DGPS 4 /* solution status: DGPS/DGNSS */
#define SOLQ_SINGLE 5 /* solution status: single */
#define SOLQ_PPP 6 /* solution status: PPP */
#define SOLQ_DR 7 /* solution status: dead reconing */
#define MAXSOLQ 7 /* max number of solution status */
SOLQ_DR
状态并没有用到。
9.1.7 ambc_t:模糊度固定控制结构体
/* ambiguity control type */
typedef struct {
gtime_t epoch[4]; /* last epoch */
int n[4]; /* number of epochs */
double LC [4]; /* linear combination average */
double LCv[4]; /* linear combination variance */
int fixcnt; /* fix count */
char flags[MAXSAT]; /* fix flags */
} ambc_t;
该结构体似乎在 PPP
算法中才会被使用。
9.1.8 ssat_t:卫星状态控制结构体
typedef struct {
uint8_t sys; // 卫星系统
uint8_t vs; // 卫星有效性标志
double azel[2]; // 方位角,高度角
double resp[NFREQ]; // 伪距残差
double resc[NFREQ]; // 载波相位残差
uint8_t vsat[NFREQ]; // 卫星频段有效性标志
uint16_t snr[NFREQ]; // C/N0(dB/Hz)
uint8_t fix [NFREQ]; // 模糊度固定状态(1:float;2:fix;3:hold)
uint8_t slip[NFREQ]; /* 周跳标识 */
uint8_t half[NFREQ]; /* 半周跳有效性标识 */
int lock [NFREQ]; /* 相位锁定计数 */
uint32_t outc [NFREQ]; // 载波中断计数
uint32_t slipc[NFREQ]; /* 周跳计数 */
uint32_t rejc [NFREQ]; /* 拒绝计数 */
double gf[NFREQ-1]; /* gf(几何无关)相位观测 (m) */
double mw[NFREQ-1]; /* MW 组合 (m) */
double phw; /* 相位缠绕 (cycle) */
gtime_t pt[2][NFREQ]; /* 上一历元载波相位时间 */
double ph[2][NFREQ]; /* 上一历元载波相位观测值 (cycle) */
} ssat_t;
ssat_t
结构体用于跟踪每颗卫星的状态。
1. 观测质量相关成员:
fix
:模糊度固定状态,0:初始化状态;1:float;2:fix;3:hold。slip
:周跳标识。除了来自接收机的 LLI 状态,也包含算法自身的周跳探测。half
:主要来自接收机的 LLI 状态。lock
:锁定计数(从时间的维度来看载波观测的可靠性,如卫星在10个历元无法周跳或粗差)。- 记录该频率相位观测的连续锁定时间(正值表示连续历元数,负值表示需重新锁定)。
- 用于判断模糊度稳定性,lock[f] >= opt->minlock 表示可靠。
- 高 lock[f] 增加固定成功率,低值可能导致浮点解。
outc
:中断计数。源码中并非在检测到观测异常之后才对outc
进行累加,而是一直在udbias
中累加,在认为观测没有问题的时候再将其置 0。源码中包含的 2 次置 0 调用条件:udbias
(rtkpos.c):存在单差模糊度数据,则进行置 0 操作;relpos
(rtkpos.c):卫星频点数据有效(rtk->ssat[sat[i]-1].vsat[f]
),同时解算出了浮点解或伪距差分解,并能通过valpos
检验(该过程位于上述udbias
之后)。
slipc
:周跳计数,除了来自接收机的 LLI 状态,也包含算法自身的周跳探测。该值只会进行输出查看,不会影响算法的逻辑。rejc
:拒绝计数(双差残差较大,则视为粗差),在ddres
中被赋值,另外:rejc
在udbias
函数中下会起作用,当rejc>=2
会重置模糊度,此时rejc
也会重新计数。
2. 周跳探测相关成员:
多频组合有关博客备忘:https://blog.csdn.net/hyisoe/article/details/114385269
gf
:几何无关组合相位差(L1-L2 或 L1-L5,m)。- 用于周跳检测
detslp_gf
(rtkpos.c)。 gf
变化超阈值(opt->thresslip
)触发slip[f] = 1
。
- 用于周跳检测
mw
:Melbourne-Wübbena 线性组合(MW-LC,单位:m)。- 存储 MW 组合(宽巷模糊度),用于周跳检测
detslp_mw
(ppp.c); - MW 组合对电离层和几何距离不敏感,适合宽巷模糊度估计。
- 存储 MW 组合(宽巷模糊度),用于周跳检测
phw
:相位缠绕(Phase Windup,单位:cycle)。- 记录卫星和接收机天线相位缠绕效应引起的相位偏差;
- 由
model_phw
函数计算,主要再 ppp 中使用。
pt
:上一历元载波相位时间,与detslp_dop
有关。ph
:上一历元载波相位观测值 (cycle),与detslp_dop
有关。
对于观测数据的线性组合,若不加任何限制,可组成无数的线性组合观测值。而我们关心的仅仅是那些对 GPS 测量有实际价值和意义的线性组合观测值, 因此这些观测值至少应符合下列标准之一[19]:
- 整数特性:组合观测应能保持模糊度的整数特性,以利于正确确定整数模糊度度;
- 波长特性:组合观测应具有适当的波长;
- 大气层误差:组合观测应不受或基本不受电离层折射的影响;
- 噪声水平:组合观测应具有较小的测量噪声。
9.1.9 rtkpos.c 中的宏定义
RTKLIB 中常用比较长的一维数组存储数据,为方便查找对应数据的数组下标,rtkpos.c 定义了一些宏函数:
宏 | 定义 | 说明 |
---|---|---|
NF | define NF(opt) ((opt)->ionoopt==IONOOPT_IFLC?1:(opt)->nf) | 频段数,电离层与双频的线性组合时为 1,否则为设置的频率数 |
NP | define NP(opt) ((opt)->dynamics==0?3:9) | 位置参数数量,默认为 3,dynamics 动态模式为 9 |
NI | define NI(opt) ((opt)->ionoopt!=IONOOPT_EST?0:MAXSAT) | Estimate STEC 估算斜电子含量时为最大卫星数,否则为 0 |
NT | define NT(opt) ((opt)->tropopt<TROPOPT_EST?0:((opt)->tropopt<TROPOPT_ESTG?2:6)) | 对流层参数,不估计时为 0,TROPOPT_EST 时为 2,TROPOPT_ESTG 时为 6 |
NL | define NL(opt) ((opt)->glomodear!=2?0:NFREQGLO) | GLONASS AR 模式,auto cal 为 0,其它为 GLONASS 的载波频率数 2 |
NB | define NB(opt) ((opt)->mode<=PMODE_DGPS?0:MAXSAT*NF(opt)) | 模糊度参数,DGPS 和单点定位模式为 0,其它模式为最大卫星数 MAXSAT 乘频段数 NF(opt) |
NR | define NR(opt) (NP(opt)+NI(opt)+NT(opt)+NL(opt)) | 非模糊度参数 = 位置参数 NP(opt) + 电离层估计参数 NI(opt) + 对流层参数 NT(opt)+GLONASS AR 参数 NL(opt) |
NX | define NX(opt) (NR(opt)+NB(opt)) | 总参数 = 非模糊度参数 NR + 模糊度参数 NB |
II | define II(s,opt) (NP(opt)+(s)-1) | 电离层参数下标 (s 是卫星编号) |
IT | define IT(r,opt) (NP(opt)+NI(opt)+NT(opt)/2*(r)) | 对流层参数下标 (流动站是 0、基准站是 1) |
IL | define IL(f,opt) (NP(opt)+NI(opt)+NT(opt)+(f)) | GLONASS 接收机 h/w 延迟 |
IB | define IB(s,f,opt) (NR(opt)+MAXSAT*(f)+(s)-1) | 整周模糊度参数下标,(s 是卫星编号,f 是频率编号) |