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;
}
相关推荐
Li_RuiQi16 小时前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi20 小时前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu20 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇20 小时前
turtle 入门教程笔记
笔记
跨知易知识产权21 小时前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理21 小时前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生21 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈11111 天前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈11111 天前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡1 天前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节