RTKLIB源码和理论结合分析笔记三

rtklib中关于单点定位的框架如下图所示:

源码如下:

rtkpos()

复制代码
/* precise positioning ---------------------------------------------------------
* input observation data and navigation message, compute rover position by 
* precise positioning
* args   : rtk_t *rtk       IO  RTK control/result struct
*            rtk->sol       IO  solution
*                .time      O   solution time定位时间
*                .rr[]      IO  rover position/velocity流动站的位置和速度
*                               (I:fixed mode,O:single mode)
*                .dtr[0]    O   receiver clock bias (s) 接收机钟偏
*                .dtr[1-5]  O   receiver GLO/GAL/BDS/IRN/QZS-GPS time offset (s)通道时延,是相对于GPS的系统时间偏差
*                .Qr[]      O   rover position covarinace流动站位置的方差协方差矩阵
*                .stat      O   solution status (SOLQ_???)解的状态,是单点解、差分解、浮动解还是固定解
*                .ns        O   number of valid satellites有效卫星数量
*                .age       O   age of differential (s)
*                .ratio     O   ratio factor for ambiguity validation
*            rtk->rb[]      IO  base station position/velocity基准站的位置和速度
*                               (I:relative mode,O:moving-base mode)
*            下面是浮点解的状态量和协方差矩阵
*            rtk->nx        I   number of all states浮点解的状态量(即所有数据的状态量)
*            rtk->na        I   number of integer states固定解的状态量
*            rtk->ns        O   number of valid satellites in use使用的卫星数量
*            rtk->tt        O   time difference between current and previous (s)前后两包观测值的时间差
*            rtk->x[]       IO  float states pre-filter and post-filter浮点解的状态量
*            rtk->P[]       IO  float covariance pre-filter and post-filter浮点解的协方差矩阵
*            rtk->xa[]      O   fixed states after AR模糊度固定后的状态量
*            rtk->Pa[]      O   fixed covariance after AR模糊度固定后的方差协方差矩阵
*            rtk->ssat[s]   IO  satellite {s+1} status每个卫星的状态信息
*                .sys       O   system (SYS_???)
*                .az   [r]  O   azimuth angle   (rad) (r=0:rover,1:base)方位角
*                .el   [r]  O   elevation angle (rad) (r=0:rover,1:base)高度角
*                .vs   [r]  O   data valid single     (r=0:rover,1:base)是否可用
*                .resp [f]  O   freq(f+1) pseudorange residual (m)伪距残差
*                .resc [f]  O   freq(f+1) carrier-phase residual (m)载波残差
*                .vsat [f]  O   freq(f+1) data vaild (0:invalid,1:valid)频率是否可用
*                .fix  [f]  O   freq(f+1) ambiguity flag是否模糊度固定
*                               (0:nodata,1:float,2:fix,3:hold)
*                .slip [f]  O   freq(f+1) cycle slip flag是否有周跳
*                               (bit8-7:rcv1 LLI, bit6-5:rcv2 LLI,
*                                bit2:parity unknown, bit1:slip)
*                .lock [f]  IO  freq(f+1) carrier lock count是否失锁
*                .outc [f]  IO  freq(f+1) carrier outage count载波是否超出预值
*                .slipc[f]  IO  freq(f+1) cycle slip count周跳统计数
*                .rejc [f]  IO  freq(f+1) data reject count被拒绝掉的统计数
*                .gf        IO  geometry-free phase (L1-L2) (m)
*                .gf2       IO  geometry-free phase (L1-L5) (m)
*            rtk->nfix      IO  number of continuous fixes of ambiguity
*            rtk->neb       IO  bytes of error message buffer
*            rtk->errbuf    IO  error message buffer
*            rtk->tstr      O   time string for debug
*            rtk->opt       I   processing options
*          obsd_t *obs      I   observation data for an epoch
*                               obs[i].rcv=1:rover,2:reference
*                               sorted by receiver and satellte
*          int    n         I   number of observation data
*          nav_t  *nav      I   navigation messages
* return : status (0:no solution,1:valid solution)
* notes  : before calling function, base station position rtk->sol.rb[] should
*          be properly set for relative mode except for moving-baseline
*-----------------------------------------------------------------------------*/
//rtk存放的是中间信息,包括定位结果、卫星状态、模糊度等信息
//obs存放的是观测值信息,包括卫星号、接收机号、观测时间、伪距、载波相位、多普勒等信息
//n是观测值的数量,即有多少颗卫星的观测值   
//nav存放的是星历信息,包括卫星位置、钟差、轨道参数等信息
extern int rtkpos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav)//一个历元的数据,包括rtk是中间信息;obs是观测值信息;n是颗卫星的观测值;nav星历信息
{
    prcopt_t *opt=&rtk->opt;
    sol_t solb={{0}};
    gtime_t time;
    int i,nu,nr;
    char msg[128]="";
    
    trace(3,"rtkpos  : time=%s n=%d\n",time_str(obs[0].time,3),n);
    trace(4,"obs=\n"); traceobs(4,obs,n);
    
    /* set base staion position设置基准站的位置 */
    if (opt->refpos<=POSOPT_RINEX&&opt->mode!=PMODE_SINGLE&&
        opt->mode!=PMODE_MOVEB) {
        for (i=0;i<6;i++) rtk->rb[i]=i<3?opt->rb[i]:0.0;
    }
    /* count rover/base station observations 统计流动站和基准站的观测值数量*/
    for (nu=0;nu   <n&&obs[nu   ].rcv==1;nu++) ;//流动站的数据
    for (nr=0;nu+nr<n&&obs[nu+nr].rcv==2;nr++) ;//基准站的数据
    
    time=rtk->sol.time; /* previous epoch 上个历元的时间*/
    
    /* rover position by single point positioning 用单点定位算一个流动站的大概位置*/
    if (!pntpos(obs,nu,nav,&rtk->opt,&rtk->sol,NULL,rtk->ssat,msg)) {
        errmsg(rtk,"point pos error (%s)\n",msg);
        
        if (!rtk->opt.dynamics) {
            outsolstat(rtk);
            return 0;
        }
    }
    if (time.time!=0) rtk->tt=timediff(rtk->sol.time,time);
    
    /* single point positioning 如果定位模式只是单点定位,直接输出结果结束流程*/
    if (opt->mode==PMODE_SINGLE) {
        outsolstat(rtk);
        return 1;
    }
    /* suppress output of single solution */
    if (!opt->outsingle) {
        rtk->sol.stat=SOLQ_NONE;
    }
    /* precise point positioning 精密单点定位流程*/
    if (opt->mode>=PMODE_PPP_KINEMA) {
        pppos(rtk,obs,nu,nav);
        outsolstat(rtk);
        return 1;
    }
    /* check number of data of base station and age of differential 如果是差分定位,要检查有没有基准站数据*/
    if (nr==0) {
        errmsg(rtk,"no base station observation data for rtk\n");
        outsolstat(rtk);
        return 1;
    }
    if (opt->mode==PMODE_MOVEB) { /*  moving baseline 基线移动的定位模式也即双天线定向模式。比如车载的双天线进行定向这种模式就是固定基线长度的基线移动定位。它可以告诉你基线在当地坐标框架下的enu分量,从而可以算高度角*/
        
        /* estimate position/velocity of base station */
        if (!pntpos(obs+nu,nr,nav,&rtk->opt,&solb,NULL,NULL,msg)) {
            errmsg(rtk,"base station position error (%s)\n",msg);
            return 0;
        }
        rtk->sol.age=(float)timediff(rtk->sol.time,solb.time);
        
        if (fabs(rtk->sol.age)>TTOL_MOVEB) {
            errmsg(rtk,"time sync error for moving-base (age=%.1f)\n",rtk->sol.age);
            return 0;
        }
        for (i=0;i<6;i++) rtk->rb[i]=solb.rr[i];
        
        /* time-synchronized position of base station */
        for (i=0;i<3;i++) rtk->rb[i]+=rtk->rb[i+3]*rtk->sol.age;
    }
    else {//不是基线模式就是rtk差分定位模式
        rtk->sol.age=(float)timediff(obs[0].time,obs[nu].time);
        
        if (fabs(rtk->sol.age)>opt->maxtdiff) {
            errmsg(rtk,"age of differential error (age=%.1f)\n",rtk->sol.age);
            outsolstat(rtk);
            return 1;
        }
    }
    /* relative potitioning 开始rtk差分定位*/
    relpos(rtk,obs,nu,nr,nav);
    outsolstat(rtk);
    
    return 1;
}

用单点定位算一个流动站的大概位置pntpos()

复制代码
/* single-point positioning ----------------------------------------------------
* compute receiver position, velocity, clock bias by single-point positioning
* with pseudorange and doppler observables
* args   : obsd_t *obs      I   observation data观测值数据
*          int    n         I   number of observation data有多少个观测值数据
*          nav_t  *nav      I   navigation data星历数据
*          prcopt_t *opt    I   processing options配置参数
*          sol_t  *sol      IO  solution定位结果
*          double *azel     IO  azimuth/elevation angle (rad) (NULL: no output)方位角/高度角
*          ssat_t *ssat     IO  satellite status              (NULL: no output)存一些卫星的中间信息
*          char   *msg      O   error message for error exit存一些错误信息
* return : status(1:ok,0:error)
*-----------------------------------------------------------------------------*/
extern int pntpos(const obsd_t *obs, int n, const nav_t *nav,
                  const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat,
                  char *msg)
{
    prcopt_t opt_=*opt;//复制一份opt,以免修改原来的opt,原来的为const也不让修改
    double *rs,*dts,*var,*azel_,*resp;
    int i,stat,vsat[MAXOBS]={0},svh[MAXOBS];//svh是卫星状态变量,表示卫星是否可用
    
    trace(3,"pntpos  : tobs=%s n=%d\n",time_str(obs[0].time,3),n);//日志打印,表明已经进入单点定位函数里面了
    
    sol->stat=SOLQ_NONE;//初始化定位结果为还没有定位结果
    
    if (n<=0) {//如果没有观测值数据,直接返回错误
        strcpy(msg,"no observation data");
        return 0;
    }
    sol->time=obs[0].time;//卫星观测值时间
    msg[0]='\0';
    //mat是申请矩阵空间的函数,6行n列矩阵。这里矩阵用的是1维数组来存储的。n是和卫星相关的数据,即矩阵里面放的是卫星相关的数据
   //rs是卫星的位置、速度的矩阵,在ecef框架下,位置是x,y,z,速度是vx,vy,vz,总共是六维的。
   //dts是卫星钟和钟漂矩阵,是二维的。
   //var是观测值方差矩阵,每个卫星计算的轨道+钟的精度,是一维的。
   //azel_是方位角和高度角矩阵,是二维的。
   //resp是伪距残差矩阵
    rs=mat(6,n); dts=mat(2,n); var=mat(1,n); azel_=zeros(2,n); resp=mat(1,n);
    
    if (opt_.mode!=PMODE_SINGLE) { /* for precise positioning 如果不是单点定位,就用广播向量和Saastamoinen模型来改正电离层和对流层*/
        opt_.ionoopt=IONOOPT_BRDC;
        opt_.tropopt=TROPOPT_SAAS;
    }
    /* satellite positons, velocities and clocks 计算卫星的位置、速度和钟*/
    satposs(sol->time,obs,n,nav,opt_.sateph,rs,dts,var,svh);
    
    /* estimate receiver position with pseudorange计算接收机的位置 */
    stat=estpos(obs,n,rs,dts,var,svh,nav,&opt_,sol,azel_,vsat,resp,msg);
    
    /* RAIM FDE 接收机完好性监测,看计算的结果对不对*/
    if (!stat&&n>=6&&opt->posopt[4]) {
        stat=raim_fde(obs,n,rs,dts,var,svh,nav,&opt_,sol,azel_,vsat,resp,msg);
    }
    /* estimate receiver velocity with Doppler 如果计算结果正确,然后开始算接收机速度*/
    if (stat) {
        estvel(obs,n,rs,dts,nav,&opt_,sol,azel_,vsat);
    }
    if (azel) {//高度角、方位角填充回来
        for (i=0;i<n*2;i++) azel[i]=azel_[i];
    }
    if (ssat) {//卫星状态信息填充回来
        for (i=0;i<MAXSAT;i++) {
            ssat[i].vs=0;
            ssat[i].azel[0]=ssat[i].azel[1]=0.0;
            ssat[i].resp[0]=ssat[i].resc[0]=0.0;
            ssat[i].snr[0]=0;
        }
        for (i=0;i<n;i++) {
            ssat[obs[i].sat-1].azel[0]=azel_[  i*2];
            ssat[obs[i].sat-1].azel[1]=azel_[1+i*2];
            ssat[obs[i].sat-1].snr[0]=obs[i].SNR[0];
            if (!vsat[i]) continue;
            ssat[obs[i].sat-1].vs=1;
            ssat[obs[i].sat-1].resp[0]=resp[i];
        }
    }
    free(rs); free(dts); free(var); free(azel_); free(resp);
    return stat;
}

计算卫星的位置、速度和钟satposs()

复制代码
/* satellite positions and clocks ----------------------------------------------
* compute satellite positions, velocities and clocks
* args   : gtime_t teph     I   time to select ephemeris (gpst)//历元的时间
*          obsd_t *obs      I   observation data    //观测值数据
*          int    n         I   number of observation data //观测值数据的个数
*          nav_t  *nav      I   navigation data //星历数据
*          int    ephopt    I   ephemeris option (EPHOPT_???)//配置选项
*          double *rs       O   satellite positions and velocities (ecef)是卫星的位置、速度的矩阵,在ecef框架下,位置是x,y,z,速度是vx,vy,vz,总共是六维的
*          double *dts      O   satellite clocksd是卫星钟和钟漂矩阵,是二维的
*          double *var      O   sat position and clock error variances (m^2)是卫星位置和钟差方差,是一维的
*          int    *svh      O   sat health flag (-1:correction not available)
* return : none
* notes  : rs [(0:2)+i*6]= obs[i] sat position {x,y,z} (m)矩阵数组的0:2存放卫星位置,3:5存放卫星速度,后面根据前面的格式依次存放
*          rs [(3:5)+i*6]= obs[i] sat velocity {vx,vy,vz} (m/s)
*          dts[(0:1)+i*2]= obs[i] sat clock {bias,drift} (s|s/s)
*          var[i]        = obs[i] sat position and clock error variance (m^2)
*          svh[i]        = obs[i] sat health flag
*          if no navigation data, set 0 to rs[], dts[], var[] and svh[]
*          satellite position and clock are values at signal transmission time
*          satellite position is referenced to antenna phase center
*          satellite clock does not include code bias correction (tgd or bgd)
*          any pseudorange and broadcast ephemeris are always needed to get
*          signal transmission time
*如果没有星历rs[], dts[], var[] and svh[]这些都要设置为0,卫星位置和钟都是信号发射时刻的时间,卫星位置是参考卫星的天线相位
*中心的,卫星钟不包括码偏差校正(tgd或bgd),为了得到信号发射时间,伪距和广播星历总是需要的
*-----------------------------------------------------------------------------*/
extern void satposs(gtime_t teph, const obsd_t *obs, int n, const nav_t *nav,
                    int ephopt, double *rs, double *dts, double *var, int *svh)
{
    gtime_t time[2*MAXOBS]={{0}};
    double dt,pr;
    int i,j;
    
    trace(3,"satposs : teph=%s n=%d ephopt=%d\n",time_str(teph,3),n,ephopt);
    
    for (i=0;i<n&&i<2*MAXOBS;i++) {//遍历n个卫星
        for (j=0;j<6;j++) rs [j+i*6]=0.0;//初始化卫星位置和速度矩阵,初始化为0
        for (j=0;j<2;j++) dts[j+i*2]=0.0;//初始化卫星钟和钟漂矩阵,初始化为0
        var[i]=0.0; svh[i]=0;///初始化卫星健康标志
        
        /* search any pseudorange */
        for (j=0,pr=0.0;j<NFREQ;j++) if ((pr=obs[i].P[j])!=0.0) break;//伪距不为0就认为他有效
        
        if (j>=NFREQ) {
            trace(3,"no pseudorange %s sat=%2d\n",time_str(obs[i].time,3),obs[i].sat);
            continue;
        }
        /* transmission time by satellite clock 计算卫星的发射时刻;卫星的发射时刻=观测时刻-伪距/光速-卫星钟改正*/
        time[i]=timeadd(obs[i].time,-pr/CLIGHT);//pr为卫星到接收机之间的伪距,除以光速。观测时刻-伪距/光速
        
        /* satellite clock bias by broadcast ephemeris 计算卫星钟的改正*/
        if (!ephclk(time[i],teph,obs[i].sat,nav,&dt)) {
            trace(3,"no broadcast clock %s sat=%2d\n",time_str(time[i],3),obs[i].sat);
            continue;
        }
        time[i]=timeadd(time[i],-dt);//(观测时刻-伪距/光速)的值再-卫星钟改正
        
        /* satellite position and clock at transmission time 计算卫星的位置和卫星钟*/
        if (!satpos(time[i],teph,obs[i].sat,ephopt,nav,rs+i*6,dts+i*2,var+i,
                    svh+i)) {
            trace(3,"no ephemeris %s sat=%2d\n",time_str(time[i],3),obs[i].sat);
            continue;
        }
        /* if no precise clock available, use broadcast clock instead */
        if (dts[i*2]==0.0) {
            if (!ephclk(time[i],teph,obs[i].sat,nav,dts+i*2)) continue;
            dts[1+i*2]=0.0;
            *var=SQR(STD_BRDCCLK);
        }
    }
    for (i=0;i<n&&i<2*MAXOBS;i++) {
        trace(4,"%s sat=%2d rs=%13.3f %13.3f %13.3f dts=%12.3f var=%7.3f svh=%02X\n",
              time_str(time[i],6),obs[i].sat,rs[i*6],rs[1+i*6],rs[2+i*6],
              dts[i*2]*1E9,var[i],svh[i]);
    }
}

transmission time by satellite clock 计算卫星的发射时刻理论:

计算卫星的位置和卫星钟satpos()

复制代码
/* satellite position and clock ------------------------------------------------
* compute satellite position, velocity and clock
* args   : gtime_t time     I   time (gpst)卫星信息发射时刻时间
*          gtime_t teph     I   time to select ephemeris (gpst)选择星历的时间
*          int    sat       I   satellite number
*          nav_t  *nav      I   navigation data
*          int    ephopt    I   ephemeris option (EPHOPT_???)
*          double *rs       O   sat position and velocity (ecef)
*                               {x,y,z,vx,vy,vz} (m|m/s)
*          double *dts      O   sat clock {bias,drift} (s|s/s)
*          double *var      O   sat position and clock error variance (m^2)
*          int    *svh      O   sat health flag (-1:correction not available)
* return : status (1:ok,0:error)
* notes  : satellite position is referenced to antenna phase center
*          satellite clock does not include code bias correction (tgd or bgd)
*-----------------------------------------------------------------------------*/
extern int satpos(gtime_t time, gtime_t teph, int sat, int ephopt,
                  const nav_t *nav, double *rs, double *dts, double *var,
                  int *svh)
{
    trace(4,"satpos  : time=%s sat=%2d ephopt=%d\n",time_str(time,3),sat,ephopt);
    
    *svh=0;
    
    switch (ephopt) {
        case EPHOPT_BRDC  : return ephpos     (time,teph,sat,nav,-1,rs,dts,var,svh);//单点定位 RTK使用广播星历
        case EPHOPT_SBAS  : return satpos_sbas(time,teph,sat,nav,   rs,dts,var,svh);
        case EPHOPT_SSRAPC: return satpos_ssr (time,teph,sat,nav, 0,rs,dts,var,svh);//PPP使用天线相位中心的SSR改正
        case EPHOPT_SSRCOM: return satpos_ssr (time,teph,sat,nav, 1,rs,dts,var,svh);//PPP使用天线质量中心的SSR改正
        case EPHOPT_PREC  :
            if (!peph2pos(time,sat,nav,1,rs,dts,var)) break; else return 1;//精密星历的计算
    }
    *svh=-1;
    return 0;
}
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
starlaky4 天前
Django入门笔记
笔记·django
勇气要爆发4 天前
吴恩达《LangChain LLM 应用开发精读笔记》1-Introduction_介绍
笔记·langchain·吴恩达
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
勇气要爆发4 天前
吴恩达《LangChain LLM 应用开发精读笔记》2-Models, Prompts and Parsers 模型、提示和解析器
android·笔记·langchain
qianshanxue114 天前
计算机操作的一些笔记标题
笔记
土拨鼠烧电路4 天前
笔记11:数据中台:不是数据仓库,是业务能力复用的引擎
数据仓库·笔记
土拨鼠烧电路4 天前
笔记14:集成与架构:连接孤岛,构建敏捷响应能力
笔记·架构
烟花落o4 天前
栈和队列的知识点及代码
开发语言·数据结构·笔记·栈和队列·编程学习