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

2023-11-19

 

目录

pntpos

satposs

estpos

 raim_fde

estvel

ephclk

satpos

satsys

seleph

eph2clk

ephpos

eph2pos

rescode

lsq

valsol

matmul

dops

ecef2enu

xyz2enu

ecef2pos

geodist

satazel

prange

satexclude

ionocorr

tropcorr

varerr

testsnr

gettgd

ionmodel

iontec

iondelay

ionppp

interptec

resdop






本博客是转载,感谢:RTKLIB源码解析(一)——单点定位(pntpos.c) - 作业部落 Cmd Markdown 编辑阅读器

pntpos

    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)
  • 所在文件:pntpos.c
  • 功能说明:依靠多普勒频移测量值和伪距来进行单点定位,给出接收机的位置、速度和钟差
  • 参数说明
    函数参数,8个:
    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
    返回类型:
    int                  O     (1:ok,0:error)
  • 调用关系
    如无特别说明,本文所出现的流程图中,纵向代表时间上的先后调用顺序,横向代表层次上的逐级调用顺序。

                                                   satposs estpos  raim_fde  estvel  

处理过程

  1. 检查卫星个数是否大于 0
  2. 当处理选项 opt中的模式不是单点模式时,电离层校正采用 Klobuchar模型,对流层校正则采用 Saastamoinen模型;相反,当其为单点模式时,对输入参数 opt不做修改。
  3. 调用 satposs函数,按照所观测到的卫星顺序计算出每颗卫星的位置、速度、{钟差、频漂}。
  4. 调用 estpos函数,通过伪距实现绝对定位,计算出接收机的位置和钟差,顺带返回实现定位后每颗卫星的{方位角、仰角}、定位时有效性、定位后伪距残差。
  5. 调用 raim_fde函数,对上一步得到的定位结果进行接收机自主正直性检测(RAIM)。通过再次使用 vsat数组,这里只会在对定位结果有贡献的卫星数据进行检测。
  6. 调用 estvel函数,依靠多普勒频移测量值计算接收机的速度。这里只使用通过了上一步 RAIM_FDE操作的卫星数据,所以对于计算出的速度就没有再次进行 RAIM了。
  7. 首先将 ssat_t结构体数组的 vs(定位时有效性)、azel(方位角、仰角)、resp(伪距残余)、resc(载波相位残余)和 snr(信号强度)都置为 0,然后再将实现定位后的 azel、snr赋予 ssat_t结构体数组,而 vs、resp则只赋值给那些对定位有贡献的卫星,没有参与定位的卫星,这两个属性值为 0。

注意事项

  1. 这里只计算了接收机的钟差,而没有计算接收机的频漂,原因在于 estvel函数中虽然计算得到了接收机频漂,但并没有将其输出到 sol_t:dtr中。
  2. C语言中用 malloc申请的内存需要自己调用 free来予以回收,源码中的 matimatzeros等函数都只是申请了内存,并没有进行内存的回收,在使用这些函数时,用户必须自己调用 free来回收内存!源码中将使用这些函数的代码放置在同一行,在调用函数结尾处也统一进行内存回收,位置较为明显,不致于轻易忘记。

我的疑惑

  1. 源码中将 obs[0].time作为星历选择时间传递给 satposs函数,这样对于每一颗观测卫星,都要使用第一颗观测卫星的数据接收时间作为选择星历的时间标准。是否应该每颗卫星都使用自己的观测时间?或者应该使用每颗卫星自己的信号发射时间?,还是说这点差别对选择合适的星历其实没有关系?
  2. 这里规定能够执行 raim_fde函数的前提是数目大于等于 6,感觉不是只要大于等于 5就可以了吗? (因为大于5代表可以检测到故障,大于6可以知道哪颗卫星出现了故障)

satposs

    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)
  • 所在文件:ephemeris.c
  • 功能说明:按照所观测到的卫星顺序计算出每颗卫星的位置、速度、{钟差、频漂}
  • 参数说明
    函数参数,9个:
    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,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
    double   *dts      O   satellite clocks,长度为2*n, {bias,drift} (s|s/s)
    double   *var      O   sat position and clock error variances (m^2)
    int      *svh      O   sat health flag (-1:correction not available)
    返回类型:
    none

调用关系

                                                                   satposs     ephclk      satpos

处理过程

  1. 按照观测数据的顺序,首先将将当前观测卫星的 rs、dts、var和svh数组的元素置 0。
  2. 通过判断某一频率下信号的伪距是否为 0,来得到此时所用的频率个数。注意,频率个数不能大于 NFREQ(默认为 3)。
  3. 用数据接收时间减去伪距信号传播时间,得到卫星信号的发射时间。
  4. 调用 ephclk函数,由广播星历计算出当前观测卫星的钟差。注意,此时的钟差是没有考虑相对论效应和 TGD的。
  5. 用 3中的信号发射时间减去 4中的钟偏,得到 GPS时间下的卫星信号发射时间。
  6. 调用 satpos函数,计算信号发射时刻卫星的 P(ecef,m)、V(ecef,m/s)、C((s|s/s))。注意,这里计算出的钟差是考虑了相对论效应的了,只是还没有考虑 TGD。
  7. 如果由 6中计算出的钟偏为 0,就再次调用 ephclk函数,将其计算出的卫星钟偏作为最终的结果。

(1)卫星钟钟差计算ephclk(ephemeris.c)

  • 求取卫星信号发射时刻

 式中, 表示第 颗星, 表示第 个测站,此处只有一个测站即基准站, 为P1码的伪距观测值, 为光速, 表示以接收机钟为时间基准的卫星信号接收时刻, 表示以卫星钟为时间基准的卫星信号发射时刻。

  • 用广播星历求取卫星钟钟差

(2) 卫星位置计算satpos(ephemeris.c)

  • 计算观测瞬间卫星的平近点角

  •  计算偏近点角

  •  计算升交距角 u、卫星矢径 r 、卫星轨道倾角 i

  •  计算卫星在轨道面坐标系中的位置

  • 计算卫星在ECEF坐标系中的位置

 

注意事项

ephclk函数计算的钟偏是没有考虑相对论和 TGD的,而 satpos函数考虑了相对论,没有考虑 TGD。

我的疑惑

  1. 对于处理过程中的第3步,数据接收时间减去伪距信号传播时间,这里的数据接收时间应该是有接收机得到的,本身应该是包含接收机钟差的,所以最终得到的信号发射时间应该也是不准确的。难道说接收机钟差较小,在此时可以忽略不计?
  2. ephclk函数最终是通过调用 eph2clk来计算卫星钟偏的,但对于后者,我有问题。见 eph2clk处我的疑惑
  3. 为什么要进行 7中操作?

estpos

    int estpos(const obsd_t *obs, int n, const double *rs, const double *dts,
               const double *vare, const int *svh, const nav_t *nav,
               const prcopt_t *opt, sol_t *sol, double *azel, int *vsat,
               double *resp, char *msg)
  • 所在文件:pntpos.c
  • 功能说明:通过伪距实现绝对定位,计算出接收机的位置和钟差,顺带返回实现定位后每颗卫星的{方位角、仰角}、定位时有效性、定位后伪距残差。
  • 参数说明
 
 
  1. 函数参数,13个:
  2. obsd_t *obs I observation data
  3. int n I number of observation data
  4. double *rs I satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  5. double *dts I satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  6. double *vare I sat position and clock error variances (m^2)
  7. int *svh I sat health flag (-1:correction not available)
  8. nav_t *nav I navigation data
  9. prcopt_t *opt I processing options
  10. sol_t *sol IO solution
  11. double *azel IO azimuth/elevation angle (rad)
  12. int *vsat IO 表征卫星在定位时是否有效
  13. double *resp IO 定位后伪距残差 (P-(r+c*dtr-c*dts+I+T))
  14. char *msg O error message for error exit
  15. 返回类型:
  16. int O (1:ok,0:error)

调用关系

                                                                   estpos    rescode    lsq valsol
- 处理过程

  1. sol->rr的前 3项赋值给 x数组。
  2. 开始迭代定位计算,首先调用 rescode函数,计算在当前接收机位置和钟差值的情况下,定位方程的右端部分 v(nv\*1)、几何矩阵 H(NX*nv)、此时所得的伪距残余的方差 var、所有观测卫星的 azel{方位角、仰角}、定位时有效性 vsat、定位后伪距残差 resp、参与定位的卫星个数 ns和方程个数 nv
  3. 确定方程组中方程的个数要大于未知数的个数。
  4. 以伪距残余的标准差的倒数作为权重,对 H和 v分别左乘权重对角阵,得到加权之后的 H和 v。
  5. 调用 lsq函数,根据 和 ,得到当前 x的修改量和定位误差协方差矩阵中的权系数阵。
  6. 将 5中求得的 x加入到当前 x值中,得到更新之后的 x值。
  7. 如果 5中求得的修改量小于截断因子(目前是1e-4),则将 6中得到的 x值作为最终的定位结果,对 sol的相应参数赋值,之后再调用 valsol函数确认当前解是否符合要求(伪距残余小于某个 值和 GDOP小于某个门限值)。否则,进行下一次循环。
  8. 如果超过了规定的循环次数,则输出发散信息后,返回 0。

注意事项

  • 关于第 1步,如果是第一次定位,即输入的 sol为空,则 x初值为 0;如果之前有过定位,则通过 1中操作可以将上一历元的定位值作为该历元定位的初始值。
  • 关于定位方程,书中的写法如下:

  其中,

 

  • 关于加权最小二乘,这里的权重值是对角阵,这是建立在假设不同测量值的误差之间是彼此独立的;另外,这个权重值并不单是距测量误差的,而是方程右端 b整体的测量误差。最后,大部分资料上这里都是把权重矩阵 W保留到方程的解的表达式当中,而这里是直接对 H和 v分别左乘权重对角阵,得到加权之后的 H和 v,其表示形式像是没有加权一样
  • 如果某次迭代过程中步长小于门限值(1e-4),但经 valsol函数检验后该解无效,则会直接返回 0,并不会再进行下一次迭代计算。
  • 因为该函数有两个返回路径,而且又调用了 mat函数来构建矩阵,所以在两个返回路径处都需要调用 free函数来回收内存。
  • 源码中的 dtr实际上单位是 m,是乘以了光速之后的。
  • 在对 sol结构体赋值时,并没有直接将接收机钟差 dtr赋值给 sol_dtr,而是通过在 sol中存储的是减去接收机钟差后的信号观测时间,来讲该信息包括到 sol中了。
  • 源码中定位方程的个数 nv要大于有效观测卫星的个数 ns,这里为了防止亏秩,似乎又加了 3个未知数和观测方程。
  • 在每一次重新调用 rescode函数时,其内部并没有对 v、H和 var清零处理,所以当方程数变少时,可能会存在尾部仍保留上一次数据的情况,但是因为数组相乘时都包含所需计算的长度,所以这种情况并不会对计算结果造成影响。

备注:

1、求伪距残差(即误差方程自由项 l )rescode(pntpos.c)

伪距原始观测方程为:

 

 2、最小二乘法求方程解lsq(rtkcmn.c)

 

我的疑惑

NX =7不明白,应该只有个未知数的啊!

 raim_fde

    int raim_fde(const obsd_t *obs, int n, const double *rs,
                 const double *dts, const double *vare, const int *svh,
                 const nav_t *nav, const prcopt_t *opt, sol_t *sol,
                 double *azel, int *vsat, double *resp, char *msg)
  • 所在文件:pntpos.c
  • 功能说明:对计算得到的定位结果进行接收机自主正直性检测(RAIM)。通过再次使用 vsat数组,这里只会在对定位结果有贡献的卫星数据进行检测。
  • 参数说明
 
 
  1. 函数参数,13个:
  2. obsd_t *obs I observation data
  3. int n I number of observation data
  4. double *rs I satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  5. double *dts I satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  6. double *vare I sat position and clock error variances (m^2)
  7. int *svh I sat health flag (-1:correction not available)
  8. nav_t *nav I navigation data
  9. prcopt_t *opt I processing options
  10. sol_t *sol IO solution
  11. double *azel IO azimuth/elevation angle (rad)
  12. int *vsat IO 表征卫星在定位时是否有效
  13. double *resp IO 定位后伪距残差 (P-(r+c*dtr-c*dts+I+T))
  14. char *msg O error message for error exit
  15. 返回类型:
  16. int O (1:ok,0:error)

调用关系

                                                                             raim_fde estpos

处理过程

  1. 关于观测卫星数目的循环,每次舍弃一颗卫星,计算使用余下卫星进行定位的定位值。
  2. 舍弃一颗卫星后,将剩下卫星的数据复制到一起,调用 estpos函数,计算使用余下卫星进行定位的定位值。
  3. 累加使用当前卫星实现定位后的伪距残差平方和与可用微信数目,如果 nvsat<5,则说明当前卫星数目过少,无法进行 RAIM_FDE操作。
  4. 计算伪距残差平方和的标准平均值,如果大于 rms,则说明当前定位结果更合理,将 stat置为 1,重新更新 solazelvsat(当前被舍弃的卫星,此值置为0)、resp等值,并将当前的 rms_e更新到 `rms'中。
  5. 继续弃用下一颗卫星,重复 2-4操作。总而言之,将同样是弃用一颗卫星条件下,伪距残差标准平均值最小的组合所得的结果作为最终的结果输出。
  6. 如果 stat不为 0,则说明在弃用卫星的前提下有更好的解出现,输出信息,指出弃用了哪科卫星。
  7. 使用 free函数回收相应内存。

注意事项

  1. 使用了 matmalloc函数后要使用 free函数来回收内存。
  2. 源码中有很多关于 i、j、k的循环。其中,i表示最外面的大循环,每次将将第 i颗卫星舍弃不用,这是通过 if (j==i) continue实现的;j表示剩余使用的卫星的循环,每次进行相应数据的赋值;k表示参与定位的卫星的循环,与 j一起使用。

我的疑惑

  1. 这里执行 RAIM至少要有 6颗可用卫星,可是我感觉 5颗就够了呀! (4颗卫星定位;5颗卫星故障检测;6颗卫星识别故障卫星

estvel

    void estvel(const obsd_t *obs, int n, const double *rs, const double *dts,
                const nav_t *nav, const prcopt_t *opt, sol_t *sol,
                const double *azel, const int *vsat)
  • 所在文件:pntpos.c
  • 功能说明:依靠多普勒频移测量值计算接收机的速度。
  • 参数说明
 
 
  1. 函数参数,9个:
  2. obsd_t *obs I observation data
  3. int n I number of observation data
  4. double *rs I satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  5. double *dts I satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  6. nav_t *nav I navigation data
  7. prcopt_t *opt I processing options
  8. sol_t *sol IO solution
  9. double *azel IO azimuth/elevation angle (rad)
  10. int *vsat IO 表征卫星在定位时是否有效
  11. 返回类型:
  12. int O (1:ok,0:error)

调用关系

                                                                              estvel resdop lsq

处理过程

  1. 在最大迭代次数限制内,调用 resdop,计算定速方程组左边的几何矩阵和右端的速度残余,返回定速时所使用的卫星数目。
  2. 调用 lsq函数,解出 {速度、频漂}的步长,累加到 x中。
  3. 检查当前计算出的步长的绝对值是否小于 1E-6。是,则说明当前解已经很接近真实值了,将接收机三个方向上的速度存入到 sol_t.rr中;否,则进行下一次循环。
  4. 执行完所有迭代次数,使用 free回收内存。
  5. 注意事项
  6. 最终向 sol_t类型存储定速解时,并没有存储所计算出的接收器时钟频漂。
  7. 这里不像定位时,初始值可能为上一历元的位置(从 sol中读取初始值),定速的初始值直接给定为 0.

ephclk

    int ephclk(gtime_t time, gtime_t teph, int sat, const nav_t *nav, double *dts)
  • 所在文件:ephemeris.c
  • 功能说明:通过广播星历来确定卫星钟偏
  • 参数说明
  1. 函数参数,5个:
  2. gtime_t time I transmission time by satellite clock
  3. gtime_t teph I time to select ephemeris (gpst)
  4. int sat I satellite number (1-MAXSAT)
  5. nav_t *nav I navigation data
  6. double *dts O satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  7. 返回类型:
  8. int O (1:ok,0:error)

调用关系

                                                              ephclk satsys seleph eph2clk 

处理过程

  1. 首先调用 satsys函数,根据卫星编号确定该卫星所属的导航系统和该卫星在该系统中的 PRN编号。
  2. 对于 GPS导航系统,调用 seleph函数来选择 toe值与星历选择时间标准 teph最近的那个星历。
  3. 调用 eph2clk函数,通过广播星历和信号发射时间计算出卫星钟差。

注意事项

  1. 此时计算出的卫星钟偏是没有考虑相对论效应和 TGD的。
  2. 目前我还只关心 RTKLIB对于 GPS导航所进行的数据处理,所以这里在选择星历和计算钟差时都只介绍与 GPS系统有关的函数

我的疑惑

  1. 见 eph2clk处

satpos

    int satpos(gtime_t time, gtime_t teph, int sat, int ephopt, const nav_t *nav, 
               double *rs, double *dts, double *var, int *svh)
  • 所在文件:ephemeris.c
  • 功能说明:计算信号发射时刻卫星的 P(ecef,m)、V(ecef,m/s)、C((s|s/s))
  • 参数说明
  1. 函数参数,9个:
  2. gtime_t time I time (gpst)
  3. gtime_t teph I time to select ephemeris (gpst)
  4. int sat I satellite number
  5. nav_t *nav I navigation data
  6. int ephopt I ephemeris option (EPHOPT_???)
  7. double *rs O sat position and velocity {x,y,z,vx,vy,vz} (ecef)(m|m/s)
  8. double *dts O sat clock {bias,drift} (s|s/s)
  9. double *var O sat position and clock error variance (m^2)
  10. int *svh O sat health flag (-1:correction not available)
  11. 返回类型:
  12. int O (1:ok,0:error)

调用关系

                                                                                satpos ephpos

  • 处理过程

    1. 判断星历选项的值,如果是 EPHOPT_BRDC,调用 ephpos函数,根据广播星历计算出算信号发射时刻卫星的 P、V、C
  • 注意事项

    1. 此时计算出的卫星钟差考虑了相对论,还没有考虑 TGD。
    2. 目前还只阅读了如何从广播星历中计算卫星 P、V、C的代码,关于如何从精密星历中计算,等对精密星历的理论背景有了更多了解之后再予以添加。

satsys

  1. int satsys(int sat, int *prn)
  • 所在文件:rtkcmn.c
  • 功能说明:根据卫星编号确定该卫星所属的导航系统和该卫星在该系统中的 PRN编号
  • 参数说明
  1. 函数参数,2个:
  2. int sat I satellite number (1-MAXSAT)
  3. int *prn IO satellite prn/slot number (NULL: no output)
  4. 返回类型:
  5. int satellite system (SYS_GPS,SYS_GLO,...)
  • 处理过程

    1. 为处理意外情况(卫星号不在 1-MAXSAT之内),先令卫星系统为 SYS_NONE
    2. 按照 TRKLIB中定义相应宏的顺序来判断是否是 GPS、GLO、GAL系统等,判断标准是将卫星号减去前面的导航系统所拥有的卫星个数,来判断剩余卫星个数是否小于等于本系统的卫星个数。
    3. 确定所属的系统后,通过加上最小卫星编号的 PRN再减去 1,得到该卫星在该系统中的 PRN编号。
  • 注意事项

    1. 这里的卫星号是从 1开始排序的,这也是很多函数中与之有关的数组在调用时形式写为 A[B.sat-1]

seleph

  1. eph_t *seleph(gtime_t time, int sat, int iode, const nav_t *nav)
  • 所在文件:ephemeris.c
  • 功能说明:从导航数据中选择星历。当 iode>=0时,选择与输入期号相同的星历;否则,选择 toe值与星历选择时间标准 time最近的那个星历。
  • 参数说明
  1. 函数参数,4个:
  2. gtime_t time I time to select ephemeris (gpst)
  3. int sat I satellite number (1-MAXSAT)
  4. int iode I 星历数据期号
  5. nav_t *nav I navigation data
  6. 返回类型:
  7. eph_t * 星历数据
  • 处理过程

    1. 根据该卫星所属的导航系统给与星历参考时间的最大时间间隔 tmax赋予相应的值。
    2. 遍历导航数据,首先确保所查找星历的卫星号是否相同,接着确保星历期号是否相同。
    3. 接着确保星历选择时间与代查找星历的参考时间的间隔是否小于 tmax
    4. 对于通过了 2-3验证的星历,如果此时对于输入的期号,有 iode>=0,则该星历就是所要寻找的星历;否则,验证 3中的 t是否满足 t<=tmin。满足的话,就令 tmin=t,该星历目前是距离参考时间最近的。
    5. 循环 2-4步操作,遍历完导航数据中的所有星历。如果都没有符合条件的,就输出信息并返回 NULL;否则,返回所查找到的星历。
  • 注意事项

    1. 对于 GPS系统,星历数据期号每 2h更新一次,所以 RTKLIB中对 MAXDTOE的定义为 7200。
    2. 如果存在两个相邻时间段的星历,通过 4中令 tmin=t的操作可以最终查找出参考时间距 time最近的那个星历。
  • 我的疑惑
    1. 为什么 tmaxtmin都要加 1?
    2. IODE正常情况下应该都是 >=0的,为什么还要考虑 <0的情况?
    3. 考虑到星历中卫星的健康状况,这里在选择星历时是否也应该验证 eph.svh==0呢?

eph2clk

  1. int eph2clk (gtime_t time, const eph_t *eph)
  • 所在文件:ephemeris.c
  • 功能说明:根据信号发射时间和广播星历,计算卫星钟差
  • 参数说明
  1. 函数参数,2个
  2. gtime_t time I time by satellite clock (gpst)
  3. eph_t *eph I broadcast ephemeris
  4. 返回类型:
  5. double satellite clock bias (s) without relativeity correction
  • 处理过程
    1. 计算与星历参考时间的偏差 dt = t-toc。
    2. 利用二项式校正计算出卫星钟差,从 dt中减去这部分,然后再进行一次上述操作,得到最终的 dt。
    3. 使用二项式校正得到最终的钟差。
  • 我的疑惑
    1. 看不懂上述处理过程,跟以往资料上都不一样。咋回事?


ephpos

  1. int ephpos(gtime_t time, gtime_t teph, int sat, const nav_t *nav,
  2. int iode, double *rs, double *dts, double *var, int *svh)
  • 所在文件:ephemeris.c
  • 功能说明:根据广播星历计算出算信号发射时刻卫星的 P、V、C
  • 参数说明
  1. 函数参数,9个
  2. gtime_t time I transmission time by satellite clock
  3. gtime_t teph I time to select ephemeris (gpst)
  4. int sat I satellite number (1-MAXSAT)
  5. nav_t *nav I navigation data
  6. int iode I 星历数据期号
  7. double *rs O satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  8. double *dts O satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  9. double *var O sat position and clock error variances (m^2)
  10. int *svh O sat health flag (-1:correction not available)
  11. 返回类型:
  12. int O (1:ok,0:error)
  • 调用关系

                                                              ephpos satsys seleph eph2pos

  • 处理过程

    1. 调用 satsys函数,确定该卫星所属的导航系统。
    2. 如果该卫星属于 GPS系统,则调用 seleph函数来选择广播星历。
    3. 根据选中的广播星历,调用 eph2pos函数来计算信号发射时刻卫星的 位置、钟差和相应结果的误差。
    4. 在信号发射时刻的基础上给定一个微小的时间间隔,再次计算新时刻的 P、V、C。与 3结合,通过扰动法计算出卫星的速度和频漂。
  • 注意事项

    1. 这里是使用扰动法计算卫星的速度和频漂,并没有使用那些位置和钟差公式对时间求导的结果。
    2. 由于是调用的 eph2pos函数,计算得到的钟差考虑了相对论效应,还没有考虑 TGD

eph2pos

  1. void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, double *var)
  • 所在文件:ephemeris.c
  • 功能说明:根据广播星历计算出算信号发射时刻卫星的位置和钟差
  • 参数说明
  1. 函数参数,5个
  2. gtime_t time I transmission time by satellite clock
  3. eph_t *eph I broadcast ephemeris
  4. double *rs O satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  5. double *dts O satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  6. double *var O sat position and clock error variances (m^2)
  7. 返回类型:
  8. none
  • 处理过程

    1. 与大部分资料上计算卫星位置和钟差的过程是一样的,只是这里在计算偏近点角 E时采用的是牛顿法来进行迭代求解。
    2. 计算误差直接采用 URA值来标定,具体对应关系可在 ICD-GPS-200C P83中找到。
  • 注意事项

    1. 这里在计算钟差时,就与大部分资料上介绍的一样了,只进行了一次二项式校正。另外,这里的钟差考虑了相对论效应,并没有考虑 TGD。
    2. 在计算偏近点角 E时,这里采用的是牛顿法来进行迭代求解,这里与很多资料上可能不一样,具体内容可在 RTKLIB manual P143中找到。
    3. 补充几个程序中的参数说明:
       
           
      1. mu, 地球引力常数
      2. eph->A, 轨道长半径
      3. omgea, 地球自转角速度

rescode

  1. int rescode(int iter, const obsd_t *obs, int n, const double *rs,
  2. const double *dts, const double *vare, const int *svh,
  3. const nav_t *nav, const double *x, const prcopt_t *opt,
  4. double *v, double *H, double *var, double *azel, int *vsat,
  5. double *resp, int *ns)
  • 所在文件:pntpos.c
  • 功能说明:计算在当前接收机位置和钟差值的情况下,定位方程的右端部分 v(nv\*1)、几何矩阵 H(NX*nv)、此时所得的伪距残余的方差 var、所有观测卫星的 azel{方位角、仰角}、定位时有效性 vsat、定位后伪距残差 resp、参与定位的卫星个数 ns和方程个数 nv
  • 参数说明
  1. 函数参数,17个
  2. int iter I 迭代次数
  3. obsd_t *obs I observation data
  4. int n I number of observation data
  5. double *rs I satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  6. double *dts I satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  7. double *vare I sat position and clock error variances (m^2)
  8. int *svh I sat health flag (-1:correction not available)
  9. nav_t *nav I navigation data
  10. double *x I 本次迭代开始之前的定位值
  11. prcopt_t *opt I processing options
  12. double *v O 定位方程的右端部分,伪距残余
  13. double *H O 定位方程中的几何矩阵
  14. double *var O 参与定位的伪距残余方差
  15. double *azel O 对于当前定位值,每一颗观测卫星的 {方位角、高度角}
  16. int *vsat O 每一颗观测卫星在当前定位时是否有效
  17. double *resp O 每一颗观测卫星的伪距残余, (P-(r+c*dtr-c*dts+I+T))
  18. int *ns O 参与定位的卫星的个数
  19. 返回类型:
  20. int O 定位方程组的方程个数
  • 调用关系

        rescode ecef2pos satsys geodist satazel prange satexclude ionocorr tropcorr varerr

  • 处理过程

    1. 将之前得到的定位解信息赋值给 rrdtr数组,以进行关于当前解的伪距残余的相关计算。
    2. 调用 ecef2pos函数,将上一步中得到的位置信息由 ECEF转化为大地坐标系。
    3. vsatazelresp数组置 0,因为在前后两次定位结果中,每颗卫星的上述信息都会发生变化。
    4. 调用 satsys函数,验证卫星编号是否合理及其所属的导航系统。
    5. 检测当前观测卫星是否和下一个相邻数据重复。是,则 i++后继续下一次循环;否,则进入下一步。
    6. 调用 geodist函数,计算卫星和当前接收机位置之间的几何距离和 receiver-to-satellite方向的单位向量。然后检验几何距离是否 >0。
    7. 调用 satazel函数,计算在接收机位置处的站心坐标系中卫星的方位角和仰角,检验仰角是否 截断值。
    8. 调用 prange函数,得到伪距值。
    9. 可以在处理选项中事先指定只选用哪些导航系统或卫星来进行定位,这是通过调用 satexclude函数完成的。
    10. 调用 ionocorr函数,计算电离层延时(m)。
    11. 上一步中所得的电离层延时是建立在 L1信号上的,当使用其它频率信号时,依据所用信号频组中第一个频率的波长与 L1波长的关系,对上一步得到的电离层延时进行修正。
    12. 调用 tropcorr函数,计算对流层延时(m)。
    13. 由 ,计算出此时的伪距残余。
    14. 组装几何矩阵,前 3行为 6中计算得到的视线单位向量的反向,第 4行为 1,其它行为 0。
    15. 将参与定位的卫星的定位有效性标志设为 1,给当前卫星的伪距残余赋值,参与定位的卫星个数 ns加 1.
    16. 调用 varerr函数,计算此时的导航系统误差(可能会包括 IFLC选项时的电离层延时),然后累加计算用户测距误差(URE)。
    17. 为了防止亏秩,人为的添加了几组观测方程。
  • 注意事项

    1. 返回值 vresp的主要区别在于长度不一致, v是需要参与定位方程组的解算的,维度为 nv*1;而 resp仅表示所有观测卫星的伪距残余,维度为 n*1,对于没有参与定位的卫星,该值为 0。
    2. 源码中 dtr的单位是 m。
    3. 16中的 URE值包括 ①卫星星历和钟差的误差 ②大气延时误差 ③伪距测量的码偏移误差 ④导航系统的误差
  • 我的疑惑

    1. 关于 5中的去除重复数据的过程,有以下几个看法:
      ① 这样做的前提是相同卫星的重复数据必须相邻出现!
      ② 为什么在这里要进行重复数据检测,在构建 obsd_t结构体时就可以进行这项工作呀?
      ③ 5中当数据重复时,i++后继续下一次循环,这样的话会直接略去后面所重复的数据,这样做就会将两个相邻重复数据都忽略掉,就相当于重复数据都不使用。感觉可以用其中一个的啊!
    2. 11步中,为什么要选择所用信号频组中第一个频率的波长来进行电离层延时修正呢?还有,电离层延时的值发生了改变,那这里的方差是否也需要跟着一起改变呢?
    3. 在计算电离/对流层延时时,均传入了 iter>0?opt->ionoopt:IONOOPT_BRDCiter>0?opt->tropopt:TROPOPT_SAAS参数,都强调了当 iter==0时,会强制使用 KlobucharSaastamoinen模型。这会不会是因为这两种模型都是属于对接收机位置不是非常敏感的类型?
    4. 这里亏秩应该就是欠定方程的意思吧?这里 17中的操作没有看懂,也没能找到相关理论依据

lsq

  1. int lsq(const double *A, const double *y, int n, int m, double *x, double *Q)
  • 所在文件:rtkcmn.c
  • 功能说明:计算得到方程 左边的值和该值的协方差矩阵
  • 参数说明
  1. 函数参数,6个
  2. double *A I transpose of (weighted) design matrix (n x m)
  3. double *y I (weighted) measurements (m x 1)
  4. int n,m I number of parameters and measurements (n<=m)
  5. double *x O estmated parameters (n x 1)
  6. double *Q O esimated parameters covariance matrix (n x n)
  7. 返回类型:
  8. int O (0:ok,0>:error)
  • 调用关系

                                                                                   lsq matmul 

valsol

  1. int valsol(const double *azel, const int *vsat, int n,
  2. const prcopt_t *opt, const double *v, int nv, int nx, char *msg)
  • 所在文件:pntpos.c
  • 功能说明:确认当前解是否符合要求,即伪距残余小于某个 卡方分布值GDOP小于某个门限值)
  • 参数说明
  1. 函数参数,8个
  2. double *azel I azimuth/elevation angle (rad)
  3. int *vsat I 表征卫星在定位时是否有效
  4. int n I number of observation data
  5. prcopt_t *opt I processing options
  6. double *v I 定位后伪距残差 (P-(r+c*dtr-c*dts+I+T))
  7. int nv I 定位方程的方程个数
  8. int nx I 未知数的个数
  9. char *msg O error message for error exit
  10. 返回类型:
  11. int O (1:ok,0:error)
  • 调用关系

                                                                                  valsol dops

matmul

源码中定义了两个 matmul函数,一个是在包含了 LAPACK/BLAS/MKL库使用,调用其中的 degmn函数来完成矩阵相乘操作。这里主要说明在没有包含上述库时自定义的矩阵相乘函数。

  1. void matmul(const char *tr, int n, int k, int m, double alpha,
  2. const double *A, const double *B, double beta, double *C)
  • 所在文件:rtkcmn.c
  • 功能说明:可进行如下矩阵运算 C = alpha*A*B + beta*C,并且能通过 tr标志来选择是否对 A、B进行转置
  • 参数说明
  1. 函数参数,6个
  2. char *tr I transpose flags ("N":normal,"T":transpose)
  3. int n,k,m I size of (transposed) matrix A,B
  4. double alpha I alpha
  5. double *A,*B I (transposed) matrix A (n x m), B (m x k)
  6. double beta I beta
  7. double *C IO matrix C (n x k)
  8. 返回类型:
  9. none

dops

  1. void dops(int ns, const double *azel, double elmin, double *dop)

 调用关系

                                                                     dops matmul matinv

ecef2enu

  1. void ecef2enu(const double *pos, const double *r, double *e)
  • 所在文件:rtkcmn.c
  • 功能说明:将 ECEF坐标系(X、Y、Z)中的向量转换成站心坐标系。
  • 参数说明
  1. 函数参数,3个
  2. double *pos I geodetic position {lat,lon} (rad)
  3. double *r I vector in ecef coordinate {x,y,z}
  4. double *e O vector in local tangental coordinate {e,n,u}
  5. 返回类型:
  6. none
  • 调用关系

 

                                                                    ecef2enu xyz2enu matmul

xyz2enu

  1. void xyz2enu(const double *pos, double *E)
  • 所在文件:rtkcmn.c
  • 功能说明:计算将ECEF中的向量转换到站心坐标系中的转换矩阵。
  • 参数说明
  1. 函数参数,2个
  2. double *pos I geodetic position {lat,lon} (rad)
  3. double *E O vector in local tangental coordinate {e,n,u}
  4. 返回类型:
  5. none
  • 处理过程
    1. 按照大部分资料上的写法计算 3*3的矩阵,优先按列存储。


ecef2pos

  1. void ecef2pos(const double *r, double *pos)
  • 所在文件:rtkcmn.c
  • 功能说明:将 ECEF坐标系(X、Y、Z)转换成大地坐标系(、、)。
  • 参数说明
  1. 函数参数,2个
  2. double *r I ecef position {x,y,z} (m)
  3. double *pos O geodetic position {lat,lon,h} (rad,m)
  4. 返回类型:
  5. none
  • 处理过程

    这里采用的方法与很多资料上的并不一致,而关于源码中方法的具体理论推导和计算过程,见 ECEF和大地坐标系的相互转化一文。


geodist

  1. double geodist(const double *rs, const double *rr, double *e)
  • 所在文件:rtkcmn.c
  • 功能说明:计算卫星和当前接收机位置之间的几何距离和 receiver-to-satellite方向的单位向量。
  • 参数说明
  1. 函数参数,3个
  2. double *rs I satellilte position (ecef at transmission) (m)
  3. double *rr I receiver position (ecef at reception) (m)
  4. double *e O line-of-sight unit vector (ecef)
  5. 返回类型:
  6. double O geometric distance (m) (0>:error/no satellite position)
  • 处理过程

    1. 检查卫星到 WGS84坐标系原点的距离是否大于基准椭球体的长半径。
    2. ps-pr,计算由接收机指向卫星方向的观测矢量,之后在计算出相应的单位矢量。
    3. 考虑到地球自转,即信号发射时刻卫星的位置与信号接收时刻卫星的位置在 WGS84坐标系中并不一致,进行关于 Sagnac效应的校正。
  • 我的疑惑

    1. 3中使用关于 Sagnac效应的校正来考虑地球自转对卫星位置的影响,与教材中的地球自转校正并不一样,二者是否描述的是同一个事情?

satazel

  1. double satazel(const double *pos, const double *e, double *azel)
  • 所在文件:rtkcmn.c
  • 功能说明:计算在接收机位置处的站心坐标系中卫星的方位角和仰角
  • 参数说明
  1. 函数参数,3个
  2. double *pos I geodetic position {lat,lon,h} (rad,)
  3. double *e I receiver-to-satellilte unit vevtor (ecef)
  4. double *azel IO azimuth/elevation {az,el} (rad) (NULL: no output) (0.0<=azel[0]<2*pi,-pi/2<=azel[1]<=pi/2)
  5. 返回类型:
  6. double O elevation angle (rad)
  • 调用关系

                                                                             satazel ecef2enu

  • 处理过程

    1. 调用 ecef2enu函数,将 pos处的向量转换到以改点为原点的站心坐标系中。
    2. 调用 atan2函数计算出方位角,然后再算出仰角。
  • 注意事项

    1. 这里在计算方位角时,要使用 atan2函数,而不能是 atan函数,详细原因见 C语言中的atan和atan2

prange

  1. double prange(const obsd_t *obs, const nav_t *nav, const double *azel,
  2. int iter, const prcopt_t *opt, double *var)
  • 所在文件:pntpos.c
  • 功能说明
  • 参数说明
  1. 函数参数,6个
  2. obsd_t *obs I observation data
  3. nav_t *nav I navigation data
  4. double *azel I 对于当前定位值,每一颗观测卫星的 {方位角、高度角}
  5. int iter I 迭代次数
  6. prcopt_t *opt I processing options
  7. double *vare O 伪距测量的码偏移误差
  8. 返回类型:
  9. double O 最终能参与定位解算的伪距值
  • 调用关系

                                                                  prange satsys testsnr gettgd

  • 处理过程

    1. 首先调用 satsys确定该卫星属于 RTKLIB设计时给定的几个导航系统之中。
    2. 如果 NFREQ>=3且该卫星属于 GAL/SBS系统,则 j=2。而如果出现 NFREQ<2||lam[i]==0.0||lam[j]==0.0中的其中一个,直接返回 0.
    3. iter>0时,调用 testsnr函数,测试第i、j(IFLC)个频率信号的载噪比是否符合要求。
    4. 计算出 值(f1^2/f2^2,见ICD-GPS-200C P90),从 obsnav数据中读出测量伪距值和 码偏移值(?)
    5. 从数据中读出的P1_P2==0,则使用 TGD代替,TGD值由 gettgd函数计算得到。
    6. 如果 ionoopt==IONOOPT_IFLC,根据 obs->code的值来决定是否对 P1、P2进行修正,之后再组合出 IFLC时的伪距值(ICD-GPS-200C P91)。否则,则是针对单频接收即进行的数据处理。先对 P1进行修正,然后再计算出伪距值(PC)
    7. 如果 sateph==EPHOPT_SBAS,则还要对 PC进行处理。之后给该函数计算出的伪距值的方差赋值。
  • 我的疑惑

    1. 该函数到底在对伪距进行哪部分的计算?计算进行 C/A码修正后的伪距值?
    2. 在调用 testsnr函数时,为什么要有 iter>0的限制?为什么第一次迭代就不能调用这些函数呢?
    3. 2中操作的含义不明白,还有为什么出现 3个条件中的一个,就要返回 0呢?
    4. 5中关于 IFLC模型伪距的重新计算是看明白了,但是 P1_P2P1_C1P1_C2这些变量具体代表什么含义,以及P1_P2==0.0时使用 TGD代替和最后关于 sbas clock based C1的操作看不懂。。。

satexclude

  1. int satexclude(int sat, int svh, const prcopt_t *opt)
  • 所在文件:rtkcmn.c
  • 功能说明:检测某颗卫星在定位时是否需要将其排除,排除标准为该卫星是否处理选项预先规定的导航系统或排除标志。
  • 参数说明
  1. 函数参数,3个
  2. int sat I satellite number,从 1开始
  3. int svh I sv health flag(0:ok)
  4. prcopt_t *opt I processing options (NULL: not used)
  5. 返回类型:
  6. int O 1:excluded,0:not excluded
  • 处理过程

    1. 首先调用 satsys函数得到该卫星所属的导航系统。
    2. 接着检验 svh<0。是,则说明在 ephpos函数中调用 seleph为该卫星选择星历时,并无合适的星历可用,返回 1;否,则进入下一步。
    3. 如果处理选项不为空,则检测处理选项中对该卫星的排除标志的值(1:excluded,2:included),之后再检测该卫星所属的导航系统与处理选项中预先设定的是否一致。否,返回 1;是,进入下一步。
    4. 如果此时 svh>0,说明此时卫星健康状况出现问题,此卫星不可用,返回 1。
  • 注意事项

    1. 3中再在比较该卫星与预先规定的导航系统是否一致时,使用了 sys&opt->navsys来进行比较。这样做的好处是当 opt->navsys=sysopt->navsys=SYS_ALL时,结果都会为真。之所以会这样,是因为在 rtklib.h文件中定义这些导航系统变量的时候,所赋的值在二进制形式下都是只有一位为 1的数。
  • 我的疑惑
    1. 对于 3中检测,先验证状态排除标志,后验证导航系统,这样就可能出现排除标志符合要求而所属系统不符合要求的状况,而 3中做法会将上述状况设为 included!
    2. 另外,注意到在 3中检测之后仍验证了 svh>0,那如果出现 svh不合乎要求而排除标志符合要求的状况,3中做法却会将上述状况设为 included!

ionocorr

  1. int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos,
  2. const double *azel, int ionoopt, double *ion, double *var)
  • 所在文件:pntpos.c
  • 功能说明:计算给定电离层选项时的电离层延时(m)。
  • 参数说明
  1. 函数参数,8个
  2. gtime_t time I time
  3. nav_t *nav I navigation data
  4. int sat I satellite number
  5. double *pos I receiver position {lat,lon,h} (rad|m)
  6. double *azel I azimuth/elevation angle {az,el} (rad)
  7. int ionoopt I ionospheric correction option (IONOOPT_???)
  8. double *ion O ionospheric delay (L1) (m)
  9. double *var O ionospheric delay (L1) variance (m^2)
  10. 返回类型:
  11. int O (1:ok,0:error)
  • 调用关系

                                                  ionocorr ionmodel iontec

  • 处理过程

    1. 根据 opt的值,选用不同的电离层模型计算方法。当 ionoopt==IONOOPT_BRDC时,调用 ionmodel,计算 Klobuchar模型时的电离层延时 (L1,m);当 ionoopt==IONOOPT_TEC时,调用 iontec,计算 TEC网格模型时的电离层延时 (L1,m)。
  • 注意事项

    1. ionoopt==IONOOPT_IFLC时,此时通过此函数计算得到的延时和方差都为 0。其实,对于 IFLC模型,其延时值在 prange函数中计算伪距时已经包括在里面了,而方差是在 varerr函数中计算的,并且会作为导航系统误差的一部分给出。

tropcorr

  1. int int tropcorr(gtime_t time, const nav_t *nav, const double *pos,
  2. const double *azel, int tropopt, double *trp, double *var)
  • 所在文件:pntpos.c
  • 功能说明:计算对流层延时(m)。
  • 参数说明
  1. 函数参数,7个
  2. gtime_t time I time
  3. nav_t *nav I navigation data
  4. double *pos I receiver position {lat,lon,h} (rad|m)
  5. double *azel I azimuth/elevation angle {az,el} (rad)
  6. int tropopt I tropospheric correction option (TROPOPT_???)
  7. double *trp O tropospheric delay (m)
  8. double *var O tropospheric delay variance (m^2)
  9. 返回类型:
  10. int O (1:ok,0:error)
  • 调用关系

 

dops tropmodel

  • 处理过程

    1. tropopt==TROPOPT_SAAS或一些其它情况时,调用 tropmodel函数,计算 Saastamoinen模型下的对流层延时。
  • 注意事项

    1. 貌似对流层延时与信号频率无关,所以这里计算得到的值并不是只针对于 L1信号!

varerr

  1. double varerr(const prcopt_t *opt, double el, int sys)
  • 所在文件:pntpos.c
  • 功能说明:计算导航系统伪距测量值的误差
  • 参数说明
  1. 函数参数,3个
  2. prcopt_t *opt I processing options
  3. double el I elevation angle (rad)
  4. int sys I 所属的导航系统
  5. 返回类型:
  6. double O 导航系统伪距测量值的误差
  • 处理过程

    1. 确定 sys系统的误差因子。
    2. 计算由导航系统本身所带来的误差的方差。
    3. 如果 ionoopt==IONOOPT_IFLC时,IFLC模型的方差也会添加到最终计算得到的方差中。
  • 我的疑惑

    1. 本函数整体到底是为了计算哪一部分的误差,还是没搞清楚。
    2. IFLC模型的方差为什么可以用 varr*=SQR(3.0)计算?

testsnr

  1. int testsnr(int base, int freq, double el, double snr,
  2. const snrmask_t *mask)
  • 所在文件:rtkcmn.c
  • 功能说明:检测接收机所属类型和频率信号的有效性
  • 参数说明
  1. 函数参数,5个
  2. int base I rover or base-station (0:rover,1:base station)
  3. int freq I frequency (0:L1,1:L2,2:L3,...)
  4. double el I elevation angle (rad)
  5. double snr I C/N0 (dBHz)
  6. snrmask_t *mask I SNR mask
  7. 返回类型:
  8. int O (1:masked,0:unmasked)
  • 调用关系

                                                                          dops matmul matinv

  • 处理过程

    1. 满足下列情况之一 !mask->ena[base]||freq<0||freq>=NFREQ,返回 0.
    2. el处理变换,根据后面 i的值得到不同的阈值 minsnr,而对 1<=i<=8的情况,则使用线性插值计算出 minsnr的值。
  • 我的疑惑

    1. 这个函数貌似是根据接收机高度角和信号频率来检测该信号是否可用,但 mask在这里应该翻译成什么?看了下调用该函数的地方,返回 0(unmasked)似乎是合理的、希望看到的情况,即 snr>=minsnr
    2. 满足 1中条件的情况,感觉应该是不合理的情形,为什么反而返回 0呢?

gettgd

  1. double gettgd(int sat, const nav_t *nav)
  • 所在文件:pntpos.c
  • 功能说明:检测某颗卫星在定位时是否需要将其排除,排除标准为该卫星是否处理选项预先规定的导航系统或排除标志。
  • 参数说明
  1. 函数参数,2个
  2. int sat I satellite number,从 1开始
  3. nav_t *nav I navigation data
  4. 返回类型:
  5. double O tgd parameter (m)
  • 处理过程
    1. 从导航数据的星历中选择卫星号与 sat相同的那个星历,读取 tgd[0]参数后乘上光速。

ionmodel

  1. double ionmodel(gtime_t t, const double *ion, const double *pos,
  2. const double *azel)
  • 所在文件:rtkcmn.c
  • 功能说明:计算采用 Klobuchar模型时的电离层延时 (L1,m)。
  • 参数说明
  1. 函数参数,4个
  2. gtime_t t I time (gpst)
  3. double *ion I iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3}
  4. double *pos I receiver position {lat,lon,h} (rad,m)
  5. double *azel I azimuth/elevation angle {az,el} (rad)
  6. 返回类型:
  7. double O ionospheric delay (L1) (m)
  • 处理过程

    1. 主要都是数学计算,其过程可以在 ICD-GPS-200C P148中找到。

iontec

  1. int iontec(gtime_t time, const nav_t *nav, const double *pos,
  2. const double *azel, int opt, double *delay, double *var)
  • 所在文件:ionex.c
  • 功能说明:由所属时间段两端端点的 TEC网格数据插值计算出电离层延时 (L1) (m)
  • 参数说明
  1. 函数参数,3个
  2. gtime_t time I time (gpst)
  3. nav_t *nav I navigation data
  4. double *pos I receiver position {lat,lon,h} (rad,m)
  5. double *azel I azimuth/elevation angle {az,el} (rad)
  6. int opt I model option
  7. bit0: 0:earth-fixed,1:sun-fixed
  8. bit1: 0:single-layer,1:modified single-layer
  9. double *delay O ionospheric delay (L1) (m)
  10. double *var O ionospheric dealy (L1) variance (m^2)
  11. 返回类型:
  12. int O (1:ok,0:error)
  • 调用关系

                                                                                 iontec iondelay

  • 处理过程

    1. 检测高度角和接收机高度是否大于阈值。否,则延迟为 0,方差为 VAR_NOTEC,返回 1;是,则进入下一步。
    2. nav_t.tec中找出第一个 tec[i].time > time(输入参数,信号接收时间)的 tec数据。然后通过 i==0||i>=nav->nt,确保 time是在所给出的 nav_t.tec包含的时间段之中!
    3. 通过确认所找到的时间段的右端点减去左端点,来确保时间间隔 != 0。
    4. 调用 iondelay来计算所属时间段两端端点的电离层延时。
    5. 由两端的延时,插值计算出观测时间点处的值。而对于两端延时的组合,有 3种情况。
      ① 两个端点都计算出错,输出错误信息,返回 0.
      ② 两个端点都有值,线性插值出观测时间点的值,返回 1.
      ③ 只有一个端点有值,将其结果作为观测时间处的值,返回 1.

iondelay

  1. int iondelay(gtime_t time, const tec_t *tec, const double *pos,
  2. const double *azel, int opt, double *delay, double *var)
  • 所在文件:ionex.c
  • 功能说明:根据当前电离层网格模型,计算电离层延时 (L1) (m)。
  • 参数说明
  1. 函数参数,3个
  2. gtime_t time I time (gpst)
  3. tec_t *tec I tec grid data
  4. double *pos I receiver position {lat,lon,h} (rad,m)
  5. double *azel I azimuth/elevation angle {az,el} (rad)
  6. int opt I model option
  7. bit0: 0:earth-fixed,1:sun-fixed
  8. bit1: 0:single-layer,1:modified single-layer
  9. double *delay O ionospheric delay (L1) (m)
  10. double *var O ionospheric dealy (L1) variance (m^2)
  11. 返回类型:
  12. int O (1:ok,0:error)
  • 调用关系

                                                                   iondelay ionppp interptec 

ionppp

  1. double ionppp(const double *pos, const double *azel, double re,
  2. double hion, double *posp)
  • 所在文件:rtkcmn.c
  • 功能说明:计算电离层穿刺点的位置 {lat,lon,h} (rad,m)和倾斜率( )。
  • 参数说明
  1. 函数参数,5个
  2. double *pos I receiver position {lat,lon,h} (rad,m)
  3. double *azel I azimuth/elevation angle {az,el} (rad)
  4. double re I earth radius (km)
  5. double hion I altitude of ionosphere (km)
  6. double *posp O pierce point position {lat,lon,h} (rad,m)
  7. 返回类型:
  8. double O 倾斜率
  • 处理过程

    1. 与处理过程相对应的公式,请见 RTKLIB manual P151
  • 注意事项

    1. 说明文档中的 z并不是仰角azel[1],而是仰角关于的补角,所以程序中在计算 rp是采用的是 cos(azel[1])的写法。
    2. 可能因为后面再从 TEC网格数据中插值时,并不需要高度信息,所以这里穿刺点位置 posp中的第三项高度,其实并没有进行赋值,

interptec

  1. int interptec(const tec_t *tec, int k, const double *posp, double *value,
  2. double *rms)
  • 所在文件:ionex.c
  • 功能说明:通过在经纬度网格点上进行双线性插值,计算第 k个高度层时穿刺点处的电子数总量 TEC
  • 参数说明
  1. 函数参数,5个
  2. tec_t *tec I tec grid data
  3. int k I 高度方向上的序号,可以理解为电离层序号
  4. double *posp I pierce point position {lat,lon,h} (rad,m)
  5. double *value O 计算得到的刺穿点处的电子数总量(tecu)
  6. double *rms O 所计算的电子数总量的误差的标准差(tecu)
  7. 返回类型:
  8. int O (1:ok,0:error)
  • 处理过程

    1. valuerms所指向的值置为 0。
    2. 检验 tec的纬度和经度间隔是否为 0。是,则直接返回 0。
    3. 将穿刺点的经纬度分别减去网格点的起始经纬度,再除以网格点间距,对结果进行取整,得到穿刺点所在网格的序号和穿刺点所在网格的位置(比例)。
    4. 按照下图的顺序,调用 dataindex函数分别计算这些网格点的 tec数据在 tec.data中的下标,从而得到这些网格点处的 TEC值和相应误差的标准差。

     5. 如果四个网格点的 TEC值都 >0,则说明穿刺点位于网格内,使用双线性插值计算出穿刺点的 TEC值;否则使用最邻近的网格点值作为穿刺点的 TEC值,不过前提是网格点的 TEC>0;否则,选用四个网格点中 >0的值的平均值作为穿刺点的 TEC值。

  • 注意事项

    1. 对于lats[3],其含义分别为起始纬度、终止纬度和间隔,对 lons[3]、hgts[3],其含义也是类似的。
    2. 对于 dataindex函数, i、j、k都是从 0开始的,意味着分别代表各自方向上第 i+1、j+1、k+1层,并且是按照纬度、经度、高度的优先顺序来存储网格点数据的。
  • 我的疑惑

    1. 关于输出参数 rms,按照其名称,应该是 均方根值,但是在调用了该函数的 iondelay中,确是把它的平方当做方差的一部分进行累加。所以我估计 tec.rms值得应该是相应网格点数据值的方差
    2. 老实说,源码中关于 tec->lons[2]大于或者小于 0所做的处理,并没有看得太明白。另外,个人感觉 3中减去网格点起始经度后的差值应该也不会超过 360°吧?
    3. 整体由网格点数据插值穿刺点值得过程可以明白,但 tec.data会 <0吗?还有在网格外是指某一个网格的外面,还是整体 TEC大网格的四个角外面?


  1. double tropmodel(gtime_t time, const double *pos, const double *azel,
  2. double humi)
  • 所在文件:rtkcmn.c
  • 功能说明:由标准大气和 Saastamoinen模型,计算电离层延时(m)
  • 参数说明
  1. 函数参数,4个
  2. gtime_t time I time
  3. double *pos I receiver position {lat,lon,h} (rad,m)
  4. double *azel I azimuth/elevation angle {az,el} (rad)
  5. double humi I relative humidity
  6. 返回类型:
  7. double O tropospheric delay (m)
  • 处理过程

    1. 与处理过程相对应的公式,请见 RTKLIB manual P149
  • 我的疑惑

    1. 源码中关于 trph的计算,与大多数文献和 RTKLIB manual P149 (E.5.4)有所不同,咋回事儿呢?

resdop

  1. int resdop(const obsd_t *obs, int n, const double *rs, const double *dts,
  2. const nav_t *nav, const double *rr, const double *x,
  3. const double *azel, const int *vsat, double *v, double *H)
  • 所在文件:pntpos.c
  • 功能说明:计算定速方程组左边的几何矩阵和右端的速度残余,返回定速时所使用的卫星数目
  • 参数说明
  1. 函数参数,11个:
  2. obsd_t *obs I observation data
  3. int n I number of observation data
  4. double *rs I satellite positions and velocities,长度为6*n,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  5. double *dts I satellite clocks,长度为2*n, {bias,drift} (s|s/s)
  6. nav_t *nav I navigation data
  7. double *rr I receiver positions and velocities,长度为6,{x,y,z,vx,vy,vz}(ecef)(m,m/s)
  8. double *x I 本次迭代开始之前的定速值
  9. double *azel I azimuth/elevation angle (rad)
  10. int *vsat I 表征卫星在定速时是否有效
  11. double *v O 定速方程的右端部分,速度残余
  12. double *H O 定速方程中的几何矩阵
  13. 返回类型:
  14. int O 定速时所使用的卫星数目
  • 调用关系

                                                           resdop ecef2pos xyz2enu matmul

  • 处理过程

    1. 调用 ecef2pos函数,将接收机位置由 ECEF转换为大地坐标系。
    2. 调用 xyz2enu函数,计算此时的坐标转换矩阵。
    3. 满足下列条件 obs[i].D[0]==0.0||lam==0.0||!vsat[i]||norm(rs+3+i*6,3)<=0.0之一,则当前卫星在定速时不可用,直接进行下一次循环。
    4. 计算当前接收机位置下 ENU中的视向量,然后转换得到 ECEF中视向量的值。
    5. 计算 ECEF中卫星相对于接收机的速度,然后再计算出考虑了地球自转的用户和卫星之间的几何距离变化率,校正公式见 RTKLIB manual P159 (E.6.29)
    6. 根据公式 计算出方程右端项的多普勒残余,然后再构建左端项的几何矩阵。最后再将观测方程数增 1.

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RTKLIB源码解析(一)、单点定位(pntpos.c) 的相关文章

  • RTKLIB ppp rtk_post

    1 实时ppp xff1a IGS MGEX数据处理中心的播发的实时轨道钟差产品 xff0c 结合广播星历 xff0c 实现实时定位 2 事后的 xff08 近似实时 xff09 xff1a 下载精密星历 钟差产品 xff0c 结合其他的精
  • Vins-fusion GPS融合部分测试(自己的数据ZED+RTK)

    经过前一段时间的积累 xff0c 目前暂时成功实现了用自己的数据测试实现Vins fusion 43 GPS融合 xff0c 其实放在数据采集处理上的时间比较多 xff0c 踩了很多坑 xff0c 效果在一些部分还不是很好 xff0c 后期
  • 【高精度定位】关于GPS、RTK、PPK三种定位技术的探讨

    高精度定位通常是指亚米级 厘米级以及毫米级的定位 xff0c 从市场需求来看 xff0c 定位的精度越高往往越好 高精度 低成本 的定位方案无疑将是未来市场的趋势 在物联网时代 xff0c 大多数的应用或多或少都与位置服务相关联 xff0c
  • GPS、RTK、PPK三种定位技术的原理及应用

    一 GPS技术 1 原理 之前做过集成GPS功能的产品 xff0c 对这种不以定位为主要功能的产品 xff0c 精度是没有要求的 xff0c 例如我只是用它来得到当前社区的位置 xff0c 一般的GPS模块都能满足要求 理论上 xff0c
  • vins-fusion 融合rtk原理

    vins fusion融合rtk原理 xff1a 使用优化的方式融合 xff0c 假设融合后的位姿是fusion T n vio输出的位姿是vio T n xff0c rtk输出的位姿是rtk T 只有最后一帧 那么 fusion T的初值
  • QGC开发 显示双GPS/RTK信息以及自定义页面(ubuntu)

    一 QGC开发 显示双GPS RTK信息 1 在sitl中进行仿真 xff0c 虚拟出第二个GPS mavlink发送到地面站 如下图中 xff0c 在mavlink msg gps2 raw h中找到发送第二组gps rtk数据函数mav
  • RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)

    RTK 43 GPS提高定位精度原理解析 xff08 一个小白写给另一个小白系列 xff09 GPS定位原理回顾RTK基本概念RTK组成RTK传输差分示意RTK数据链接坐标转换RTK应用后记 我们在上一篇文章导航定位系统的原理解析 xff0
  • RTK与网络RTK技术的工作原理和区别对比

    一 RTK RTK是一种利用GPS载波相位观测值进行实时动态相对定位的技术 进行RTK测量时 xff0c 至少需配备2台GPS接收机 xff0c 一台安装在基准站上 xff0c 另一台在基准站附近进行实时相对定位 xff0c 进而根据基准站
  • GPS RTK测量定位原理

    转自 xff1a https baijiahao baidu com s id 61 1603136753092877848 amp wfr 61 spider amp for 61 pc 手机定位是什么原理 xff1f 实时动态工程测量是
  • host ntrip 千寻rtk_手把手教你怎样使用瑞得R90T RTK连接千寻cors账号

    瑞得RTK是南方测绘旗下的RTK品牌之一 xff0c 不过相比于南方旗下其他品牌的RTK xff0c 瑞得RTK在操作使用方面以及普及度方面相对来说没有那么高 xff0c 因此很多人对于瑞得RTK连接千寻cors账号的操作比较陌生 xff0
  • 关于PPP-RTK技术优势的一些思考与总结

    文章目录 一 前言二 SSR修正与PPP三 RTK与PPP RTK的对比四 PPP RTK的技术优势五 总结参考文章 欢迎关注个人公众号 xff1a 导航员学习札记 一 前言 感觉近几年PPP和PPP RTK一直都是GNSS比较火的方向 x
  • RTK和网络RTK

    浅谈传统RTK工作模式与网络RTK工作模式 谈谈传统RTK工作模式与网络RTK工作模式 传统RTK工作模式就是电台工作模式 xff0c 网络RTK工作模式就是CORS系统测量 本文主旨 有网络信号和CORS覆盖范围的地方就选择网络RTK工作
  • 【分享】5G+北斗RTK高精度人员定位解决方案

    5G 43 北斗RTK高精度定位系统旨在通过5G网络实时提供亚米级 厘米级 毫米级高精度定位服务 xff0c 构建全天候 全天时 全地理的精准时空服务体系 伴随着信息技术日新月异的发展 xff0c 各类 智慧 顺势而出 xff0c 智慧城市
  • GPS 和 RTK 定位

    refers xff1a https blog csdn net u012241570 article details 80802675 GPS定位的基本原理 测量出已知位置的卫星到地面GPS接收器之间的距离 xff0c 然后接收器通过与至
  • RTK

    实时动态技术 xff08 英语 xff1a Real Time Kinematic xff0c RTK xff09 是实时动态载波相位差分技术的简称 xff0c 是一种通过基准站和流动站的同步观测 xff0c 利用载波相位观测值实现快速高精
  • 你了解RTK技术吗?—— 揭秘GNSS中的定位技术

    上期文章中我们一起探讨了GNSS仿真及其对测试验证的重要意义 xff0c 今天我们将一起走进GNSS中的定位技术 RTK技术 什么是RTK技术 xff1f 传统RTK技术与网络RTK技术又有什么区别呢 xff1f 随着GNSS系统的迅速发展
  • RTK使用笔记-千寻CORS模式

    一 千寻CORS模式 与基站 43 接收机1对1相比 xff0c 优点为携带方便 xff0c 也不用考虑10公里移动基站问题 xff1b 缺点为第一千寻CORS模式有自己基站涵盖范围 xff0c 所以需要提前确定好范围 xff08 下文有介
  • GNSS入门2-RTD, RTK,精度

    2 1 RTD vs RTK RTD xff08 Real Time Differential xff09 xff1a 实时码 xff08 C A码 P码 xff09 相位差分技术 xff0c 流动站与基站距离需小于100km xff0c
  • RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)

    目录 GPS定位原理回顾 RTK基本概念 RTK组成 RTK传输差分示意 RTK数据链接 坐标转换 RTK应用 后记 我们在上一篇文章导航定位系统的原理解析 xff08 一个小白写给另一个小白 xff09 中跟大家介绍了GPS定位的基本原理
  • rtklib源码 rtk差分解算,rtkpos和replos函数流程梳理

    rtklib源码 rtk差分解算 rtkpos和replos函数流程梳理 rtkpos函数梳理 总体流程 replos函数梳理 replos总体流程 1 通过satposs函数计算卫星的位置 速度等参数 2 通过zdres函数计算基站伪距和

随机推荐

  • 【GPLT】【2022天梯赛真题题解】

    L1 1 今天我要赢 5分 题目描述 2018 年我们曾经出过一题 是输出 2018 我们要赢 今年是 2022 年 你要输出的句子变成了 我要赢 就在今天 然后以比赛当天的日期落款 输入格式 本题没有输入 输出格式 输出分 2 行 在第一
  • RocketMQ消费者可以手动消费但无法主动消费问题,或生成者发送超时

    1 大多数是配置问题 修改rocketmq文件夹broker conf 2 配置与集群IP或本地IPV4一样 重启 在RocketMQ独享实例中支持IPv4和IPv6双栈 主要是通过在网络层面上同时支持IPv4和IPv6协议栈来实现的 Ro
  • java之二进制与数据类型(二)

    一 各数据类型的最大值和最小值 整数 以byte为例 我们知道 byte共有8个bit位 最大值是0111111 最小值是10000000 用十进制来表示就是 128 127 即 2 7 2 7 依照上面的推理方式可知 总结下表 数据类型
  • Redis学习总结

    Redis Redis 是完全开源免费的 遵守BSD协议 是一个高性能的key value数据库 Redis支持数据的持久化 可以将内存中的数据保存在磁盘中 重启的时候可以再次加载进行使用 Redis的优势 性能极高 Redis读的速度可达
  • 格雷码介绍与应用

    注 学习 交流就在博主的个人weixin公众号 FPGA动力联盟 留言或直接 博主weixin fpga start 私信 学过晶体管知识的朋友们都知道 数据位跳变就相当于硬件电路中的晶体管翻转 许多位同时跳变就相当于多个晶体管同时翻转 会
  • SHELL 文件内容的行数打印、统计,空行处理,每行字段的逆序输出

    file txt 用来实验的文本文件 how they are implemented and applied in computer that is your bag is this your bag to the degree or e
  • 服务器系统怎么重新启动,服务器win7系统不能重新启动

    1 电脑关不机 有很多因素 有可能是中毒了 有可能是系统问题 有可能是硬件问题 也有可能是设置问题 所以我们要一个个的排除 2 第一 中毒可能性 如果电脑可能中毒导致关不了机 就需要下载杀毒软件 然后进行木马杳然 点击全盘杀毒 一个也不能放
  • iOS开发助手、ipa便捷上传工具!

    ipa上传助手Appuploader是一个iOS APP上架辅助助手 帮助开发者可以快速的申请iOS证书打包ipa文件上传到App Store审核 非常方便的iOS上架助手 提升上架效率 ipa上传助手Appuploader官网http w
  • 【C++】类:构造函数、默认构造函数模板

    目录 模板一 两个类名构造函数 一个传参 一个不传参 模板二 成员初始化列表 推荐 性能高 构造函数 默认构造函数的作用 构造函数 传一些参数进来 用于给类的成员变量赋值 默认构造函数 程序员给类的成员变量设定一个默认值 也是用于给类的成员
  • 逻辑回归(二):Loss易导

    目录 回顾 梯度下降 对Loss函数求偏导 更新公式 多分类问题 总结 回顾 书接上回 讲到了逻辑回归的Loss函数的一般形式 大体如下 L 1
  • AWVS使用教程

    AWVS可以用来 Site Crawler 爬取URL Target Finder IP端口扫描 Subdomain Scanner 用DNS进行域名解析 找域名下的子域及其主机名 Blind SQL Injector 在相应参数位置按 添
  • sql的几种约束,非空,不重

    NOT NULL 用于控制字段的内容一定不能为空 NULL UNIQUE 控件字段内容不能重复 一个表允许有多个 Unique 约束 PRIMARY KEY 也是用于控件字段内容不能重复 但它在一个表只允许出现一个 FOREIGN KEY
  • 位移运算使用技巧

    位移运算使用技巧 左位移 lt lt 右位移 gt gt 左位移 lt lt 将二进制数向左位移操作 高位溢出则丢弃 地位补0 int a 11 int b a lt lt 1 b 22 位移前 0000 1011 位移后 0001 011
  • 达芬奇传

    列奥纳多 迪 皮耶罗 达 芬奇 出生于1452年 1519年逝世 享年67岁 画家 发明家 科学家 生物学家 工程师 达 芬奇的意思是 来自芬奇镇 他的名字叫做列奥纳多 达 芬奇的父亲叫瑟 皮耶罗 达 芬奇 是佛罗伦萨的法律公证员 因此十分
  • git:批处理启动Git-Bash窗口并显示特定目录

    参考 使用批处理脚本 在特定目录中启动Git Bash窗口
  • 【数据结构】复杂度

    博客主页 小王又困了 系列专栏 数据结构 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 什么是数据结构 二 什么是算法 三 算法的效率 四 时间复杂度 4 1大O渐进表示法 4 2常见时间复杂度计算举例 4 3例题 消失的数字
  • StarkNet 批量交互 mint 铸造 js 脚本

    代码使用 starknet 模块与 StarkNet 网络进行交互 通过读取私钥文件和执行铸造操作来创建 NFT 非同质化代币 它通过批量运行的方式处理多个私钥和地址对 并将结果输出到控制台和日志文件中 代码的详细步骤 导入模块和变量 co
  • QT5串口编程----线程循环发送不成功问题

    今天想写一个QT5的串口编程 能够循环发送数据 想具体到us级别 不需要设置ms发送 所以想用一个线程一直发送 关键问题是碰到在线程循环发送竟然发不出去 见鬼了 最后找到问题是要在每次发送后要判断waitForBytesWritten是否发
  • jmeter接口测试,CSV数据文件引用,参数化

    1 新增一个Excel文件 填写会用到的变量数据 2 将文件保存为CSV格式文件 3 在jmeter里添加 CSV数据文件配置 导入登录的用户和密码数据等信息 在jmeter里引用Excel转化的CSV格式数据文件 说明 带入的数据依次是
  • RTKLIB源码解析(一)、单点定位(pntpos.c)

    目录 pntpos satposs estpos raim fde estvel ephclk satpos satsys seleph eph2clk ephpos eph2pos rescode lsq valsol matmul do