RTKLIB专题学习(七)---精密单点定位实现初识(一)

RTKLIB专题学习(七)

前几篇我们主要针对RTKLIB中的单点定位流程、函数调用和具体实现以及定位效果进行了详细介绍和分析,那么接下来的几篇博文,将带大家走进RTKLIB中的精密单点定位的部分,这一块需要好好理解,好好吸收,是重中之重

1.类似于estpos在单点定位中的作用,精密单点定位中的pppos可以说是这部分的核心函数了,直接引用了卡尔曼滤波进行参数估计

/* precise point positioning -------------------------------------------------*/
extern void pppos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)
{
    const prcopt_t *opt=&rtk->opt;
    double *rs,*dts,*var,*v,*H,*R,*azel,*xp,*Pp,dr[3]={0},std[3];
    char str[32];
    int i,j,nv,num,info,svh[MAXOBS],exc[MAXOBS]={0},stat=SOLQ_SINGLE;
    
    time2str(obs[0].time,str,2);
    trace(3,"pppos   : time=%s nx=%d n=%d\n",str,rtk->nx,n);
    
    rs=mat(6,n); dts=mat(2,n); var=mat(1,n); azel=zeros(2,n);
    
    for (i=0;i<MAXSAT;i++) for (j=0;j<opt->nf;j++) rtk->ssat[i].fix[j]=0;
    
    /* temporal update of ekf states */
    udstate_ppp(rtk,obs,n,nav);
    
    /* satellite positions and clocks */
    satposs(obs[0].time,obs,n,nav,rtk->opt.sateph,rs,dts,var,svh);
    
    /* exclude measurements of eclipsing satellite (block IIA) */
    if (rtk->opt.posopt[3]) {
        testeclipse(obs,n,nav,rs);
    }
    /* earth tides correction */
    if (opt->tidecorr) {
        tidedisp(gpst2utc(obs[0].time),rtk->x,opt->tidecorr==1?1:7,&nav->erp,
                 opt->odisp[0],dr);
    }
    nv=n*rtk->opt.nf*2+MAXSAT+3;
    num = nv;
    xp=mat(rtk->nx,1); Pp=zeros(rtk->nx,rtk->nx);
    v=mat(nv,1); H=mat(rtk->nx,nv); R=mat(nv,nv);
    
    for (i=0;i<MAX_ITER;i++) {
        
        matcpy(xp,rtk->x,rtk->nx,1);
        matcpy(Pp,rtk->P,rtk->nx,rtk->nx);
        
        /* prefit residuals */
        if (!(nv=ppp_res(0,obs,n,rs,dts,var,svh,dr,exc,nav,xp,rtk,v,H,R,azel))) {
            trace(2,"%s ppp (%d) no valid obs data\n",str,i+1);
            break;
        }
        /* measurement update of ekf states */
        if ((info=filter(xp,Pp,H,v,R,rtk->nx,nv))) {
            trace(2,"%s ppp (%d) filter error info=%d\n",str,i+1,info);
            break;
        }
        /* postfit residuals */
        if (ppp_res(i+1,obs,n,rs,dts,var,svh,dr,exc,nav,xp,rtk,v,H,R,azel)) {
            matcpy(rtk->x,xp,rtk->nx,1);
            matcpy(rtk->P,Pp,rtk->nx,rtk->nx);
            stat=SOLQ_PPP;
            break;
        }
    }
    if (i>=MAX_ITER) {
        trace(2,"%s ppp (%d) iteration overflows\n",str,i);
    }
    if (stat==SOLQ_PPP) {
        
        /* ambiguity resolution in ppp */
        if (ppp_ar(rtk,obs,n,exc,nav,azel,xp,Pp)&&
            ppp_res(9,obs,n,rs,dts,var,svh,dr,exc,nav,xp,rtk,v,H,R,azel)) {
            
            matcpy(rtk->xa,xp,rtk->nx,1);
            matcpy(rtk->Pa,Pp,rtk->nx,rtk->nx);
            
            for (i=0;i<3;i++) std[i]=sqrt(Pp[i+i*rtk->nx]);
            if (norm(std,3)<MAX_STD_FIX) stat=SOLQ_FIX;
        }
        else {
            rtk->nfix=0;
        }
        /* update solution status */
        update_stat(rtk,obs,n,stat);
        
        /* hold fixed ambiguities */
        if (stat==SOLQ_FIX&&test_hold_amb(rtk)) {
            matcpy(rtk->x,xp,rtk->nx,1);
            matcpy(rtk->P,Pp,rtk->nx,rtk->nx);
            trace(2,"%s hold ambiguity\n",str);
            rtk->nfix=0;
        }
    }
    free(rs); free(dts); free(var); free(azel);
    free(xp); free(Pp); free(v); free(H); free(R);
}

pppos函数是精密单点定位中的核心函数,函数中还调用了其他函数;udstate_ppp函数,用于卡尔曼滤波状态的时间更新(即两步的预测部分):其中分为位置参数更新以及钟差参数时间更新,对流层、电离层和相位偏差的时间更新

/* temporal update of states --------------------------------------------------*/
extern void udstate_ppp(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)
{
    trace(3,"udstate_ppp: n=%d\n",n);
    
    /* temporal update of position */
    udpos_ppp(rtk);
    
    /* temporal update of clock */
    udclk_ppp(rtk);
    
    /* temporal update of tropospheric parameters */
    if (rtk->opt.tropopt==TROPOPT_EST||rtk->opt.tropopt==TROPOPT_ESTG) {
        udtrop_ppp(rtk);
    }
    /* temporal update of ionospheric parameters */
    if (rtk->opt.ionoopt==IONOOPT_EST) {
        udiono_ppp(rtk,obs,n,nav);
    }
    /* temporal update of L5-receiver-dcb parameters */
    if (rtk->opt.nf>=3) {
        uddcb_ppp(rtk);
    }
    /* temporal update of phase-bias */
    udbias_ppp(rtk,obs,n,nav);
}

其中,udstate_ppp还引用了udpos_pppudclk_ppp这两个函数,分别用于位置和钟差参数的时间更新;下面来介绍这两个子函数:
如果是PPP的固定解模式PMODE_PPP_FIXED,则只进行如下模块:

 /* fixed mode */
    if (rtk->opt.mode==PMODE_PPP_FIXED) {
        for (i=0;i<3;i++) initx(rtk,rtk->opt.ru[i],1E-8,i);
        return;
    }

如果是静态PPP模式的话,则只进行如下部分:

/* initialize position for first epoch */
    if (norm(rtk->x,3)<=0.0) {
        for (i=0;i<3;i++) initx(rtk,rtk->sol.rr[i],VAR_POS,i);
        if (rtk->opt.dynamics) {
            for (i=3;i<6;i++) initx(rtk,rtk->sol.rr[i],VAR_VEL,i);
            for (i=6;i<9;i++) initx(rtk,1E-6,VAR_ACC,i);
        }
    }
    /* static ppp mode */
    if (rtk->opt.mode==PMODE_PPP_STATIC) {
        for (i=0;i<3;i++) {
            rtk->P[i*(1+rtk->nx)]+=SQR(rtk->opt.prn[5])*fabs(rtk->tt);
        }
        return;
    }

我们可以看到,当第一个历元的初始位置为0时,该部分会调用initx函数,来将首个历元的单点定位结果赋给状态初值,以及对协方差矩阵进行初始化,接收机位置的的初始方差为(60)×(60)=3600;若定位模式为动态,则还需要初始化速度参数以及协方差矩阵的速度部分,初始方差为(10)×(10)=100;加速度初始方差也为(10)×(10)=100;
接下来,对协方差矩阵进行更新:

for (i=0;i<3;i++) {
      rtk->P[i*(1+rtk->nx)]+=SQR(rtk->opt.prn[5])*fabs(rtk->tt);
        }

以上就是静态模式时,解算每个历元前都需要进行的协方差矩阵位置部分的更新
如果是动态定位模式,但是没有运动的状态,即没有速度和加速度时,进行如下部分:

/* kinematic mode without dynamics */
    if (!rtk->opt.dynamics) {
        for (i=0;i<3;i++) {
            initx(rtk,rtk->sol.rr[i],VAR_POS,i);
        }
        return;
    }

如果是动态定位的话,则进行如下部分:

    /* generate valid state index */
    ix=imat(rtk->nx,1);
    for (i=nx=0;i<rtk->nx;i++) {
        if (rtk->x[i]!=0.0&&rtk->P[i+i*rtk->nx]>0.0) ix[nx++]=i;
    }
    if (nx<9) {
        free(ix);
        return;
    }
    /* state transition of position/velocity/acceleration */
    F=eye(nx); P=mat(nx,nx); FP=mat(nx,nx); x=mat(nx,1); xp=mat(nx,1);
    
    for (i=0;i<6;i++) {
        F[i+(i+3)*nx]=rtk->tt;
    }
    for (i=0;i<3;i++) {
        F[i+(i+6)*nx]=SQR(rtk->tt)/2.0;
    }
    for (i=0;i<nx;i++) {
        x[i]=rtk->x[ix[i]];
        for (j=0;j<nx;j++) {
            P[i+j*nx]=rtk->P[ix[i]+ix[j]*rtk->nx];
        }
    }

可以看出,动态定位必须至少有9个参数才可以执行该部分,若动态模式下参数大于九个,则进行状态转移矩阵的构建,并进行状态矩阵和协方差矩阵的预测。
接下来,为加速度部分添加过程噪声;

 /* process noise added to only acceleration */
    Q[0]=Q[4]=SQR(rtk->opt.prn[3])*fabs(rtk->tt);
    Q[8]=SQR(rtk->opt.prn[4])*fabs(rtk->tt);
    ecef2pos(rtk->x,pos);
    covecef(pos,Q,Qv);
    for (i=0;i<3;i++) for (j=0;j<3;j++) {
        rtk->P[i+6+(j+6)*rtk->nx]+=Qv[i+j*3];
    }

其中用到两个函数,分别为ecef2poscovecef函数,分别用于将XYZ转为BLH以及站心地平坐标系下的协方差矩阵变成地心地固坐标系下的协方差矩阵。
上面就是状态矩阵中位置部分的更新的全部内容了。接下来,我们看一下钟差部分是如何更新的:
钟差的时间更新无论是静态还是动态模式,都是要进行的:

/* temporal update of clock --------------------------------------------------*/
static void udclk_ppp(rtk_t *rtk)
{
    double dtr;
    int i;
    
    trace(3,"udclk_ppp:\n");
    
    /* initialize every epoch for clock (white noise) */
    for (i=0;i<NSYS;i++) {
        if (rtk->opt.sateph==EPHOPT_PREC) {
            /* time of prec ephemeris is based gpst */
            /* negelect receiver inter-system bias  */
            dtr=rtk->sol.dtr[0];
        }
        else {
            dtr=i==0?rtk->sol.dtr[0]:rtk->sol.dtr[0]+rtk->sol.dtr[i];
        }
        initx(rtk,CLIGHT*dtr,VAR_CLK,IC(i,&rtk->opt));
    }
}

可以看到,在每个历元的钟差更新过程中,钟差的协方差都要置为0,方差都要初始化为(60)×(60)=3600

好啦,这次就先把状态的时间更新讲完,下篇我们往下讲哦!

  • 1
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
好的,你想了解关于 EEG 脑图的 MATLAB 工具 EEGLAB 的初步使用方法,没问题,我可以为你提供一些信息。 EEGLAB 是一个基于 MATLAB 的开源工具箱,用于处理和分析电生理数据,特别是脑电图(EEG)数据。它提供了一系列的函数和工具,可以帮助你进行信号预处理、数据可视化、谱分析、时频分析、源分析等操作。使用 EEGLAB,你可以更轻松地进行 EEG 数据的分析和解释。 以下是一些 EEGLAB 的基本使用方法: 1. 安装 EEGLAB:首先,你需要从 EEGLAB 官网下载 EEGLAB 工具箱,并将其解压缩到 MATLAB 工作目录中。 2. 导入数据:在 MATLAB 命令窗口中输入 eeglab 命令,打开 EEGLAB 工具箱。然后,你可以使用 EEGLAB 中的导入数据工具,将你的 EEG 数据加载到 MATLAB 中。 3. 数据预处理:EEGLAB 提供了多种数据预处理工具,如滤波、去眼电、去肌电、去心电等。你可以根据需要选择相应的工具进行数据预处理。 4. 数据可视化:EEGLAB 中提供了多种可视化工具,如时间序列图、功率谱图、时频图等,可以帮助你更直观地了解数据的特征。 5. 数据分析:EEGLAB 中提供了多种数据分析工具,如独立成分分析(ICA)、时频分析、源分析等。你可以根据需要选择相应的工具进行数据分析。 以上是 EEGLAB 的基本使用方法,当然还有很多高级功能和工具,需要根据具体情况进行学习和使用。希望这些信息可以对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十八与她

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值