我所基于的代码版本是RTKlib 2.4.3的一个拓展版本RTKexplore Demo5,这个版本主要针对低成本的GNSS进行了一些改进完善。
extern void pppos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)
args: IO rtk_t *rtk rtk solution structure
I const obsd_t *obs 当前历元观测值
I int n 当前移动站观测值数目
I const nav_t *nav 星历
- 调用udstate_ppp函数进行卡尔曼滤波的一步预测;
- 调用satposs函数计算卫星位置;
- 如果在配置中选择排除block IIA卫星,调用testeclipse函数,将这些卫星的位置、速度置0;
- 如果在配置中选择潮汐修正,调用tidedisp函数进行潮汐修正;
- 调用ppp_res函数计算预测值与量测值之间的残差;
- 待用filter函数进行卡尔曼滤波的量测更新;
- 调用ppp_res函数计算量测更新后的残差;
- 调用ppp_ar进行整周模糊度结算,并调用ppp_res进行残差计算;
- 调用update_stat更新输入、输出参数rtk solution的状态
- 需要注意的是,步骤8中ppp_ar是个空函数,返回值为0,因此实际后面的ppp_res函数也不会被调用。如此来看,实际PPP的解为通过卡尔曼滤波得到的浮点解。
- satposs和相对定位中的函数一致,不再进行解析,可参考RTKLIB源码解析——单点定位
static void udstate_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)
args: IO rtk_t *rtk rtk solution structure
I const obsd_t *obs 当前历元观测值
I int n 当前移动站观测值数目
I const nav_t *nav 星历
- 调用udpos_ppp函数位置、速度、加速度状态量 rtk->x以及相应协方差阵 rtk->P的更新;
- 调用udclk_ppp函数,更新钟差状态量(以gpst为基准);
- 如果在配置中选择的对流层模型为ZTD estimation或者ZTD+grad estimation,调用udtrop_ppp进行对流层参数状态量的更新;
- 如果在配置中选择电离层模型为estimation,调用udiono_ppp函数,更新电离层误差参数状态量;
- 如果选择的频率数>=3,则进行L5 dcb状态量的更新;
- 调用udbias_ppp函数进行相位bias状态量的更新。
- 参考RTklib manual 来看,PPP算法中使用的量测量为“无电离层组合的伪距、载波相位”,所以配置中可以将电离层模型选择为“Iono free LC”。通过参考RTKexplorer博客Exploring kinematic single-receiver solutions with RTKLIB and the u-blox F9P. 中的配置,对流层模型应该至少配置为ZTD estimation。我在之后的博客中会测试一下不同的PPP配置对精度有多大的影响。
- 参考 RTKLIB Manual 可知状态量包括位置、速度、接收机钟差、对流层参数、卫星相位偏差;
- udpos_ppp、udtrop_ppp、udiono_ppp函数与之前相对定位中udpos、udtrop、udion函数流程基本一致,就不再详细解释,具体可参考RTKlib相对定位源码解析: udstate函数。由于udbias_ppp和相对定位中不同,因此在下文中进行解析。
static void udbias_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)
args: IO rtk_t *rtk rtk solution structure
I const obsd_t *obs 当前历元观测值
I int n 当前移动站观测值数目
I const nav_t *nav 星历
- 首先是对所有共视星进行周跳检测:调用了detslp_ll函数,根据LLI来判断基站和移动站周跳;然后调用detslp_gf利用几何无关组合进行周跳检测;最后调用了detslp_gf_mw函数进行周跳检测。对RTKlib的周跳检测函数,我专门写了一篇博客解析RTKlib源码解析:ppp和rtkpost中的周跳检测函数
- 对所有卫星进行循环,判断是否需要重置单差相位偏移状态量。如果所配置的AR的模式为instantaneous(实际由于当前PPP中使用的是浮点解,通常将PPP的AR配置为OFF),或者卫星载波相位的中断次数大于配置中所设置的最大次数,则将单差相位偏移状态量重置为0;
- 对每一组观测数据,调用 corr_meas函数对伪距、载波相位进行修正,并计算无电离层组合的伪距、载波相位量测量Pc和Lc;
- 将每颗卫星的载波相位偏差bias初始化为0,如果电离层模型为电离层无关模型,则直接计算bias[i]=Lc-Pc;否则的话,通过伪距计算电离层延迟ion=(obs[i].P[0]-obs[i].P[l])/(1.0-SQR(lam[l]/lam[0]));由于L1和L2伪距相减后,只剩下L1和L2的电离层误差之差,以及伪距噪声项,因此由此计算出来的电离层误差实际包含了伪距噪声,误差相对较大。利用修正电离层误差后的伪距和载波相位之差计算bias: bias[i]=L[f]-P[f]+2.0ionSQR(lam[f]/lam[0]);
- 计算每颗卫星的bias与载波相位偏差状态量rtk->x之间的偏差offset之和;
- 在原有的载波相位偏差状态量上加上offset的平均值,以此来作为载波相位偏差一步预测值:rtk->x[j]+=offset/k;
7.对每颗卫星循环,更新一步预测协方差阵,对有周跳的卫星、或者没有初始化载波相位偏差状态量的卫星,用之前计算的bias值重新初始化载波相位偏差状态量。
static void corr_meas(const obsd_t *obs, const nav_t *nav, const double *azel,
const prcopt_t *opt, const double *dantr,
const double *dants, double phw, double *L, double *P,
double *Lc, double *Pc)
args: I const obsd_t *obs 当前历元观测值
I const nav_t *nav 星历
I const double *azel 方位角和俯仰角 (rad)
I const prcopt_t *opt 处理选项
I const double *dantr 接收机天线校正值
I const double *dants 卫星天线校正值
I double phw 相位缠绕校正值
O double *L 修正后的载波相位
O double *P 修正后的伪距值
O double *Lc 无电离层组合的载波相位值
O double *Pc 无电离层组合的伪距值
- 调用 testsnr函数检查观测值的信噪比是否大于mask;
- 对伪距天线修正、相位缠绕校正,对载波相位进行天线修正;
- 如果星历类型是broadcast + SSR_APC或者broadcast + SSR_COM,对伪距值进行ssr 修正;如果是其他星历类型,进行 DCB 校正;
- 计算无电离层组合的伪距、载波相位值Lc,Pc
static int ppp_res(int post, const obsd_t *obs, int n, const double *rs,
const double *dts, const double *var_rs, const int *svh,
const double *dr, int *exc, const nav_t *nav,
const double *x, rtk_t *rtk, double *v, double *H, double *R,
double *azel)
args: I int post 是否是修正后残差计算标志
I const obsd_t *obs 当前历元观测值
I int n 当前移动站观测值数目
I const double *dts 卫星钟差
I const double *var_rs 星位置和钟差的协方差
I const int *svh 卫星健康标志
I const double *dr 地球潮汐位移
IO int *exc 卫星排除标志
I const nav_t *nav 星历
IO const double *x 状态量
IO rtk_t *rtk rtk solution structure
IO double *v 载波相位和伪距残差
IO double *H 卡尔曼滤波中的观测矩阵
IO double *R 测量误差的协方差矩阵
I const double *azel 方位角和俯仰角 (rad)
- 把卫星的有效标志位均置0,rtk->ssat[i].vsat[j]=0;
- 在一步预测值x[i]基础上加上潮汐修正,作为移动站位置:rr[i]=x[i]+dr[i];
- 对每颗星进行循环,根据移动站位置,计算卫星仰角,如果小于设定阈值,排除该卫星,并且检查该卫星系统、单点定位卫星有效标志、是否在设置中排除,重置排除标志:exc[i]=1;
- 调用model_trop函数计算对流层误差dtrp,调用model_iono函数计算电离层误差dion;
- 调用satantpcv函数计算卫星天线校正参数dants;调用antmodel函数计算根据接收机天线的相位中心参数计算天线偏移量dantr,该函数在此博客曾进行解析;
- 调用model_phw函数计算相位缠绕校正值rtk->ssat[sat-1].phw;
- 调用corr_meas函数对伪距和载波相位进行修正,得到量测量;
- 计算量测矩阵H和残差v,相位残差存放在 rtk->ssat[sat-1].resc中,伪距残差在rtk->ssat[sat-1].resp中;
- 综合考虑伪距(载波相位)噪声、对流层噪声、电离层噪声、卫星位置钟差噪声后,作为量测噪声;如果是GLONASS卫星,在伪距量测噪声上,还要加上IFB噪声(频间差噪声);
- 如果是 pre-fit,即!post的情况,如果某颗残差值大于阈值,将这颗星排除;
- 如果post为1,某颗残差值大于阈值,将这颗星记录下来;整个循环结束;
- 如果post为1,找到11步中残差值最大的那颗星,将其排除。