Skip to content

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_tnav_t 结构体,最后调用 rtkpos() 处理。

注意对于以上内容仅保留一个初略的印象即可,实际上 rtkpos() 函数的执行流程远比上述过程复杂得多。算法的解析、理解或优化并不会因为梳理完整个流程就能通透,而是需要解决一些有针对性的问题,用以满足研究或工程的需求。

9.1.2 obs_t:原始观测数据结构体

obs_t 结构体实际上维护了一个由原始观测数据所组成的数组 obsd_t *data

c
/* observation data */
typedef struct {        
    int n,nmax;         /* 观测数据数目/最大存储数量(与申请内存空间相关) */
    obsd_t *data;       /* 观测数据(数组) */
} obs_t;

obsd_t 组成:

  • data 字段是 obsd_t 数组。
  • n 字段表示存着的 obsd_t 数目。
  • nmax 字段表示目前 data 内存空间最大能存的 obsd_t 数目。
c
/* 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改正信息,存储 ephgephsephpephpclkalmerp的方式与 obs_tobs 的方式类似。

点击查看代码
c
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 数据pephpclk 用于 PPP。
  • UTC:历书(或概略星历)参数,目前基本不用,utc_* 为与系统相关参数,从导航电文更新。
  • 电离层参数:klobuchar 模型参数,ion_* 为与系统相关参数,需从导航电文更新。
  • GLONASS FCNglo_fcn 需正确初始化,否则会影响频率计算。
  • DCB 和 PCVcbias, rbias, pcvs 用于高精度校正,需从外部文件加载。
  • 增强数据sbssat, sbsion, dgps, ssr 支持差分和增强。
  • ERPerp 影响高精度坐标转换,需加载有效数据。

关于 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 定位状态的核心,主要用于存储定位结果和一些过程数据。

c
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.statsol.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:算法处理选项结构体

点击查看代码
c
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:结果结构体

c
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

c
#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:模糊度固定控制结构体

c
/* 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:卫星状态控制结构体

c
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 中被赋值,另外:
    • rejcudbias 函数中下会起作用,当 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 组合对电离层和几何距离不敏感,适合宽巷模糊度估计。
  • phw:相位缠绕(Phase Windup,单位:cycle)。
    • 记录卫星和接收机天线相位缠绕效应引起的相位偏差;
    • model_phw 函数计算,主要再 ppp 中使用。
  • pt:上一历元载波相位时间,与 detslp_dop 有关。
  • ph:上一历元载波相位观测值 (cycle),与 detslp_dop 有关。

对于观测数据的线性组合,若不加任何限制,可组成无数的线性组合观测值。而我们关心的仅仅是那些对 GPS 测量有实际价值和意义的线性组合观测值, 因此这些观测值至少应符合下列标准之一[19]:

  • 整数特性:组合观测应能保持模糊度的整数特性,以利于正确确定整数模糊度度;
  • 波长特性:组合观测应具有适当的波长;
  • 大气层误差:组合观测应不受或基本不受电离层折射的影响;
  • 噪声水平:组合观测应具有较小的测量噪声。

9.1.9 rtkpos.c 中的宏定义

RTKLIB 中常用比较长的一维数组存储数据,为方便查找对应数据的数组下标,rtkpos.c 定义了一些宏函数:

定义说明
NFdefine NF(opt) ((opt)->ionoopt==IONOOPT_IFLC?1:(opt)->nf)频段数,电离层与双频的线性组合时为 1,否则为设置的频率数
NPdefine NP(opt) ((opt)->dynamics==0?3:9)位置参数数量,默认为 3,dynamics 动态模式为 9
NIdefine NI(opt) ((opt)->ionoopt!=IONOOPT_EST?0:MAXSAT)Estimate STEC 估算斜电子含量时为最大卫星数,否则为 0
NTdefine NT(opt) ((opt)->tropopt<TROPOPT_EST?0:((opt)->tropopt<TROPOPT_ESTG?2:6))对流层参数,不估计时为 0,TROPOPT_EST时为 2,TROPOPT_ESTG时为 6
NLdefine NL(opt) ((opt)->glomodear!=2?0:NFREQGLO)GLONASS AR 模式,auto cal 为 0,其它为 GLONASS 的载波频率数 2
NBdefine NB(opt) ((opt)->mode<=PMODE_DGPS?0:MAXSAT*NF(opt))模糊度参数,DGPS 和单点定位模式为 0,其它模式为最大卫星数 MAXSAT 乘频段数 NF(opt)
NRdefine NR(opt) (NP(opt)+NI(opt)+NT(opt)+NL(opt))非模糊度参数 = 位置参数 NP(opt) + 电离层估计参数 NI(opt) + 对流层参数 NT(opt)+GLONASS AR 参数 NL(opt)
NXdefine NX(opt) (NR(opt)+NB(opt))总参数 = 非模糊度参数 NR + 模糊度参数 NB
IIdefine II(s,opt) (NP(opt)+(s)-1)电离层参数下标 (s 是卫星编号)
ITdefine IT(r,opt) (NP(opt)+NI(opt)+NT(opt)/2*(r))对流层参数下标 (流动站是 0、基准站是 1)
ILdefine IL(f,opt) (NP(opt)+NI(opt)+NT(opt)+(f))GLONASS 接收机 h/w 延迟
IBdefine IB(s,f,opt) (NR(opt)+MAXSAT*(f)+(s)-1)整周模糊度参数下标,(s 是卫星编号,f 是频率编号)