rtklib源码 rtk差分解算,rtkpos和replos函数流程梳理

  • rtkpos函数梳理
    • 总体流程
  • replos函数梳理
    • replos总体流程
    • 1. 通过satposs函数计算卫星的位置、速度等参数
    • 2. 通过zdres函数计算基站伪距和载波相位的非差分残差
      • 2.1 初始化残差数组 y
      • 2.2 地球潮汐校正
      • 2.3 基站接收机的星地距离修正(每颗卫星都修正)
        • 2.3.1 计算接收机到卫星的几何距离 geodist
        • 2.3.2 计算每颗卫星的方位角和仰角 satazel
        • 2.3.3 剔除卫星 satexclude
        • 2.3.4 使用钟差补偿到星地几何距离
        • 2.3.5 估算对流层延迟并补偿到星地距离 tropmodel、tropmapf
          • 2.3.6 接收机天线相位中心校正
        • 2.4 计算伪距和载波相位残差 zdres_sat
    • 3. 选择移动站和基站之间所有的公共卫星 selsat
    • 4. 当前状态更新 udstate
      • 4.1 得到相邻历元时间差
      • 4.2 rover位置、速度、加速度及其方差更新 udpos

rtkpos函数梳理

总体流程

  1. 分别计算移动站和基站的观测值数量 nu和nr
  2. 通过单点定位函数得到移动站的大致位置和速度
  3. 判断定位模式,根据不同的定位模式进行解算结果输出,如果是rtk则执行replos函数进行差分解算

replos函数梳理

replos总体流程

  1. 计算卫星的位置、速度、钟差、钟漂等参数

1. 通过satposs函数计算卫星的位置、速度等参数

在函数的最开始可以看到,这里计算的卫星数据是所有移动站和基准站的观测到的卫星星历得到的。(此处的n是n=nu+nr,在replos函数头部处定义时已经相加了 )

for (i=0;i<n&&i<2*MAXOBS;i++) {

2. 通过zdres函数计算基站伪距和载波相位的非差分残差

    if (!zdres(1,obs+nu,nr,rs+nu*6,dts+nu*2,svh+nu,nav,rtk->rb,opt,1,y+nu*nf*2,e+nu*3,azel+nu*2)) {errmsg(rtk,"initial base station position error\n");free(rs); free(dts); free(var); free(y); free(e); free(azel);return 0;}

传入的obs是obs+nu而不是obs是因为,obs是由移动站和基站的观测值共同组成,基站部分的在后面,所以加一个nu作为偏移,nu:移动站观测的卫星数 nr:参考站观测的卫星数
输入的rtk->rb是基站的位置信息,这个在前面已经进行了定位了,或者配置中已经给出了基站位置

2.1 初始化残差数组 y

for (i=0;i<n*nf*2;i++) y[i]=0.0;  //nf=2,载波数量

2.2 地球潮汐校正

   if (opt->tidecorr) {tidedisp(gpst2utc(obs[0].time),rr_,opt->tidecorr,&nav->erp,opt->odisp[base],disp);for (i=0;i<3;i++) rr_[i]+=disp[i];}

(在配置中没有用到这个改正)

2.3 基站接收机的星地距离修正(每颗卫星都修正)

    //huhaoming:将 ecef 转换为大地坐标 pos是转化后的坐标ecef2pos(rr_,pos);for (i=0;i<n;i++) {/* compute geometric-range and azimuth/elevation angle 计算几何范围和方位角/仰角 */if ((r=geodist(rs+i*6,rr_,e+i*3))<=0.0) continue;if (satazel(pos,e+i*3,azel+i*2)<opt->elmin) continue;/* excluded satellite? 剔除卫星*/if (satexclude(obs[i].sat,svh[i],opt)) continue;/* satellite clock-bias 使用钟差补偿到星地几何距离 */r+=-CLIGHT*dts[i*2];/* troposphere delay model (hydrostatic)*/zhd=tropmodel(obs[0].time,pos,zazel,0.0);r+=tropmapf(obs[i].time,pos,azel+i*2,NULL)*zhd;/* receiver antenna phase center correction 接收机天线相位中心校正*/antmodel(opt->pcvr+index,opt->antdel[index],azel+i*2,opt->posopt[1], dant);/* undifferenced phase/code residual for satellite */zdres_sat(base,r,obs+i,nav,azel+i*2,dant,opt,y+i*nf*2);}

2.3.1 计算接收机到卫星的几何距离 geodist

 //huhaoming:求接收机到卫星的几何距离,存在变量r中if ((r=geodist(rs+i*6,rr_,e+i*3))<=0.0) continue;``````c
/* geometric distance ----------------------------------------------------------* compute geometric distance and receiver-to-satellite unit vector* args   : double *rs       I   satellilte position (ecef at transmission) (m)*          double *rr       I   receiver position (ecef at reception) (m)*          double *e        O   line-of-sight vector (ecef)* return : geometric distance (m) (0>:error/no satellite position)* notes  : distance includes sagnac effect correction
*-----------------------------------------------------------------------------*/
extern double geodist(const double *rs, const double *rr, double *e)
{double r;int i;if (norm(rs,3)<RE_WGS84) return -1.0;for (i=0;i<3;i++) e[i]=rs[i]-rr[i];r=norm(e,3);for (i=0;i<3;i++) e[i]/=r;//huhaoming:OMGE*(rs[0]*rr[1]-rs[1]*rr[0])/CLIGHT:地球自转改正return r+OMGE*(rs[0]*rr[1]-rs[1]*rr[0])/CLIGHT;
}
  • rs:卫星位置
  • rr:接收机位置
  • e:接收机到卫星的单位向量,方向是由接收机指向卫星

计算的时候通过两个三维向量相减,最后再求范数即可得到星地距离
最后返回值是地球自转改正后的星地距离

2.3.2 计算每颗卫星的方位角和仰角 satazel

//如果大于最小值,则在后面用卫星钟差和对流层延时来修正星地距离
if (satazel(pos,e+i*3,azel+i*2)<opt->elmin) continue;```
/* satellite azimuth/elevation angle -------------------------------------------
* compute satellite azimuth/elevation angle
* args   : double *pos      I   geodetic position {lat,lon,h} (rad,m)
*          double *e        I   receiver-to-satellilte unit vevtor (ecef)
*          double *azel     IO  azimuth/elevation {az,el} (rad) (NULL: no output)
*                               (0.0<=azel[0]<2*pi,-pi/2<=azel[1]<=pi/2)
* return : elevation angle (rad)
*-----------------------------------------------------------------------------*/
extern double satazel(const double *pos, const double *e, double *azel)
{double az=0.0,el=PI/2.0,enu[3];if (pos[2]>-RE_WGS84) {ecef2enu(pos,e,enu);az=dot(enu,enu,2)<1E-12?0.0:atan2(enu[0],enu[1]);if (az<0.0) az+=2*PI;el=asin(enu[2]);}if (azel) {azel[0]=az; azel[1]=el;}return el;
}

先判断基站位置在经纬高坐标系中的高度是否大于-RE_WGS84(基准椭球面的长半径),只有满足才可以进行方位角和高度角的计算。
传入的位置信息 pos 是大地坐标系下的坐标,需要将基站位置坐标由经纬高转换为东北天坐标系中。

ecef2enu(pos,e,enu);

然后在enu坐标系下用课本的公式来计算即可

        az=dot(enu,enu,2)<1E-12?0.0:atan2(enu[0],enu[1]);if (az<0.0) az+=2*PI;el=asin(enu[2]);

2.3.3 剔除卫星 satexclude

排除卫星的主要是根据prcopt_t结构体中的exsats进行判断是否有要排除或者保留的卫星数据

2.3.4 使用钟差补偿到星地几何距离

r+=-CLIGHT*dts[i*2];

2.3.5 估算对流层延迟并补偿到星地距离 tropmodel、tropmapf

     //huhaoming:用saastamoinen经验模型,通过测站纬度、高程、气温、气压和水汽压等信息计算对流层延迟zhd=tropmodel(obs[0].time,pos,zazel,0.0);/*huhaoming:计算对流层延迟投影函数(即天顶方向到接收机相对卫星观测方向上的对流层延迟投影系数)* 这个函数中有两种投影函数的计算方法,分别是GMF和NMF,对应的两篇参考论文为“Global mapping functions for the atmosphere delay at radio wavelengths”和“Global Mapping Function(GMF): A new empirical mapping function base on numerical weather model data”*默认使用的是NMF方法,也可以通过定义IERS_MODEL宏来使用GMF方法。*这个函数调用完成后,会将返回的干投影函数和tropmodel中计算得到的天顶方向对流层干延迟相乘,从而得到接收机相对卫星观测方向上的对流层延迟。*干投影函数是通过返回值获得的,而湿投影是通过输入/输出参数mapfw获得的。在zdres函数中,本函数输入的mapfw=NULL,即不输出湿投影。*湿分量会在之后的ddres(计算双差残差的函数)函数中进行扣除。*/r+=tropmapf(obs[i].time,pos,azel+i*2,NULL)*zhd;
2.3.6 接收机天线相位中心校正
  antmodel(opt->pcvr+index,opt->antdel[index],azel+i*2,opt->posopt[1], dant);

生成一组接收机相对于卫星观测方向的单位矢量e,e[0],e[1],e[2]分别为东、北、天三个方向上的分量;
频段不同,天线的相位中心偏移(PCO)不同。先计算出每个频段天线在东、北、天三个方向总的偏移,即相位中心偏移pcv-off[i][j]与del[j]之和
计算2中的相位中心偏移在观测单位矢量e上的投影dot(off,e,3),由于e是单位矢量,所以和它求内积实际上就在该方向上的投影;
计算天线相位中心变化量(PCV):不同的高度角,相位中心变化不同,因此根据高度角对pcv->var[i]进行插值计算。
3、4两部分即为总的天线偏移:dant[i]=-dot(off,e,3)+(opt?interpvar(90.0-azel[1]*R2D,pcv->var[i]):0.0);

2.4 计算伪距和载波相位残差 zdres_sat

zdres_sat(base,r,obs+i,nav,azel+i*2,dant,opt,y+i*nf*2);
/* undifferenced phase/code residual for satellite ---------------------------*/
static void zdres_sat(int base, double r, const obsd_t *obs, const nav_t *nav,const double *azel, const double *dant,const prcopt_t *opt, double *y)
{const double *lam=nav->lam[obs->sat-1];double f1,f2,C1,C2,dant_if;int i,nf=NF(opt);if (opt->ionoopt==IONOOPT_IFLC) { /* iono-free linear combination */if (lam[0]==0.0||lam[1]==0.0) return;if (testsnr(base,0,azel[1],obs->SNR[0]*0.25,&opt->snrmask)||testsnr(base,1,azel[1],obs->SNR[1]*0.25,&opt->snrmask)) return;f1=CLIGHT/lam[0];f2=CLIGHT/lam[1];C1= SQR(f1)/(SQR(f1)-SQR(f2));C2=-SQR(f2)/(SQR(f1)-SQR(f2));dant_if=C1*dant[0]+C2*dant[1];if (obs->L[0]!=0.0&&obs->L[1]!=0.0) {y[0]=C1*obs->L[0]*lam[0]+C2*obs->L[1]*lam[1]-r-dant_if;}if (obs->P[0]!=0.0&&obs->P[1]!=0.0) {y[1]=C1*obs->P[0]+C2*obs->P[1]-r-dant_if;}}else {for (i=0;i<nf;i++) {if (lam[i]==0.0) continue;/* check snr mask *//*函数testsnr()是用来排除接收信号强度小于规定强度的数据,这个规定信号强度(最小信号强度)是根据卫星的仰角来得到的(或者说与卫星的仰角有关)。*/if (testsnr(base,i,azel[1],obs->SNR[i]*0.25,&opt->snrmask)) {continue;}/* residuals = observable - pseudorange 残差 = 观测值 - 伪距 *///huhaoming: 计算每个频段下的载波相位、伪距残差:残差 = 观测量 - 卫地距 - 天线偏移//dant:天线相位偏差//y[0]到y[nf - 1]保存载波相位残差,y[nf]到y[2nf - 1]保存伪距残差if (obs->L[i]!=0.0) y[i   ]=obs->L[i]*lam[i]-r-dant[i];//载波相位if (obs->P[i]!=0.0) y[i+nf]=obs->P[i]       -r-dant[i];//伪距}}
}

处理过程
如果在配置中选择了无电离层线性组合(IFLC:Ionospheric free linear combination):
a). 调用testsnr函数检查L1,L2观测量的载噪比是否大于配置中SNR Mask的最低要求(SNR Mask设置见RTKlib mannual 3.5章);
b). 计算无电离层线性组合系数C1、C2, 并采用该系数计算无电离层组合的天线偏移量;
c). 计算无电离层线性组合载波相位和伪距残差:残差 = IFLC观测量 - 卫地距 - 天线偏移量。
如果不是无电离层组合:
a). 调用testsnr,检查每个频段的载噪比是否大于配置中SNR Mask的要求;
b). 计算每个频段下的载波相位、伪距残差:残差 = 观测量 - 卫地距 - 天线偏移量。

3. 选择移动站和基站之间所有的公共卫星 selsat

/* select common satellites between rover and reference station 选择流动站和参考站之间的公共卫星 --------------*/
static int selsat(const obsd_t *obs, double *azel, int nu, int nr,const prcopt_t *opt, int *sat, int *iu, int *ir)
{int i,j,k=0;trace(3,"selsat  : nu=%d nr=%d\n",nu,nr);for (i=0,j=nu;i<nu&&j<nu+nr;i++,j++) {if      (obs[i].sat<obs[j].sat) j--;else if (obs[i].sat>obs[j].sat) i--;else if (azel[1+j*2]>=opt->elmin) { /* elevation at base station */sat[k]=obs[i].sat; iu[k]=i; ir[k++]=j;trace(3,"(%2d) sat=%3d iu=%2d ir=%2d\n",k-1,obs[i].sat,i,j);}}return k;
}

查找算法:
基站和移动站的观测数据都在obs中,并且obs的卫星号都是经过排序的,所以星号大小是按照从小打到的顺序排列。如果移动站所观察的数据卫星号小于基站所观察的卫星号,则基站观察数据不变,依次搜寻移动站的观察数据,直到不再小于,此时有两种情况,一种是等于,一种是大于。

等于时:将当前为星号存入sat[0,1….]中,将这颗卫星所对应的移动站观测数据号i,
基站观测数据j,分别存入iu[0,1….],ir[0,1…].

大于时:说明移动站没有观测的卫星与当前基站的这颗卫星相同。

如果移动站所观察的数据卫星号大于基站所观察的卫星号,算法思路与上面的一致。

4. 当前状态更新 udstate

主要更新:

  1. udpos :kalman中状态更新方程、状态协方差方程更新,包括接收机位置、速度、加速度;
  2. udion : 电离层状态、协方差更新;
  3. udtrop : 对流层状态、协方差更新;
  4. udrcvbias:接收器的时间更新
  5. udbias :更新单差模糊度状态、协方差;
    最后存放到了rtk参数中

4.1 得到相邻历元时间差

double tt=rtk->tt,bl,dr[3];

在前面的时候rtk->tt已经计算过了 rtk->tt=timediff(rtk->sol.time,time); time是前一历元时间,rtk->sol.time是当前历元时间

4.2 rover位置、速度、加速度及其方差更新 udpos

udpos(rtk,tt); :更新位置、速度、加速度,得到rtk->x,也就是浮点解 float状态

  • 如果定位模式是PMODE_FIXED,则将配置中的移动站坐标rtk->opt.ru[]赋值给rtk->x,由此得到状态的协方差矩阵
  • 初始化第一个历元的位置
    如果检测到状态矩阵位置为0,则说明是当前的历元是首历元,我们将状态的位置部分初始化为单点定位得到的大致移动站位置,状态矩阵对应的协方差矩阵为:
  • 如果是静态模式 static mode 则直接返回,结束udpos
  • 如果是 Kinmatic模式(无动力模型)(本次分析属于这种模式)
    当前的状态矩阵为当前的状态矩阵为:将状态的位置部分初始化为单点定位得到的大致移动站位置。协方差矩阵:

最后更新时间:2022年7月18日15:43:15

rtklib源码 rtk差分解算,rtkpos和replos函数流程梳理相关推荐

  1. JVM——从源码编译到类执行与内存管理全流程梳理

    从Java源码编译开始说起 分为三个步骤: 1:分析和输入到符号表 分析:词法和语法分析,将代码字符串转变为token序列,由token序列生产抽象语法树 输入:将符号输入到符号表,确定类的超类型和接 ...

  2. RTKLIB源码——如何在VS2019中配置、调试

    RTKLIB源码--如何在VS2019中配置.调试 一. 准备源码: 二.Visual Studio中新建工程: 三.编译结果: 四.实例 一. 准备源码: 注:第三方rtklib修改后的源码地址 h ...

  3. RTKLIB源码解析(一)、单点定位(pntpos.c)

      目录 pntpos satposs estpos raim_fde estvel ephclk satpos satsys seleph eph2clk ephpos eph2pos rescod ...

  4. postgresql源码学习(52)—— vacuum①-准备工作与主要流程

    关于vacuum的基础知识,参考,本篇从源码层继续学习 https://blog.csdn.net/Hehuyi_In/article/details/102992065 https://blog.c ...

  5. Mahout源码K均值聚类算分析(2)

    首先说下,为什么题目后面会有个"无语篇",因为我觉得今晚这几个钟头太坑爹了.为什么,且听我慢慢道来: 按照昨天的计划,我应该把代码仿造成单机可运行的代码.但是首先我要有输入数据不是 ...

  6. Android源码定制(2)——Android10.0的编译流程

    一.背景 已经在AOSP 7.1.1 nexus 5x上面实现了修改位置打卡,现在是想在pixel3中继续尝试. 作者:会飞的笨猫 二.如何选择代码 要选择有对应驱动版本的代码分支,如果没有标明,强行 ...

  7. djangorestframework源码分析2:serializer序列化数据的执行流程

    djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-serial ...

  8. djangorestframework源码分析1:generics中的view执行流程

    djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-generi ...

  9. HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程

    在<HDFS源码分析心跳汇报之数据结构初始化>一文中,我们了解到HDFS心跳相关的BlockPoolManager.BPOfferService.BPServiceActor三者之间的关系 ...

最新文章

  1. Eclipse引入spring约束详细教程
  2. java 生成 防伪码,C#生成防伪码的思路及源码分享
  3. C#构造函数、私有构造函数、静态构造函数与构造函数执行顺序
  4. 前端学习(713)创建数组
  5. 遗传算法编码方式整数编码_如何编码卫星算法并从头开始烹制西班牙海鲜饭
  6. Spring MVC中的基本流程
  7. web.config forms节点中的属性的含义和用途
  8. C#中判断服务器图片是否存在
  9. python 差异表达_Python设置差异
  10. 多线程总结之旅(9):线程同步之事件
  11. 传染病SIR模型及蒙特卡洛方法
  12. 8266WIFI模块
  13. android 数字 余额宝,仿余额宝数字滚动增长的效果实现
  14. 中小计算机机房管理制度,酒店计算机机房管理制度|计算机机房管理制度
  15. requests.exceptions.SSLError: HTTPSConnectionPool(host='XXX', port=443)问题
  16. Android 10 SystemUI 如何添加4G信号和WiFi图标
  17. 什么是FDM 3D打印技术?
  18. PHPMyWind编辑器支持PowerPoint导入
  19. Java实现短信验证码(阿里云短信服务)
  20. 安装OpenSSH服务

热门文章

  1. SDS技术面试课题分享
  2. iphone 投屏软件
  3. javascript Promise使用与小结
  4. 高级筛选英语或计算机分数大于85,利用高级筛选功能筛选出语文或数学成绩大于等于80的所有记录...
  5. Elasticsearch 7新特性
  6. 如何解决“无法手动启动VMware Tools安装”问题(转)
  7. 计蒜客——草药的价值——背包问题
  8. 【花一周,打造属于自己的一台DIY3D打印机1.0】
  9. Fresco原理分析
  10. 【学习笔记】OFDM的原理和技术介绍以及仿真结果分析附代码--MATLAB