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

 

目录

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.

 

  • 25
    点赞
  • 213
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
RTKLIB是一款用于实时运动定位和姿态解算的源软件包,拥有丰富的功能和强大的处理能力。下面是对RTKLIB源码解析RTKLIB源码主要由C和C++编写,文件结构清晰,便于理解和修改。源码中包含了几个主要模块,如导航定位模块、信号处理模块和数据存储模块等。 其中导航定位模块是RTKLIB的核心,主要实现了千兆定位算法和RTK定位算法。这些算法包括双差定位、载波相位平滑、相位差分和整周模糊度解算等。通过这些算法,RTKLIB能够将多频GNSS接收机接收到的GPS、GLONASS和北斗等卫星信号解算为准确的位置和姿态信息。 信号处理模块用于处理接收器接收到的原始观测数据,并转换为可用于定位计算的格式。该模块实现了伪距和载波单频和多频观测数据的读取、解码和处理。此外,还包括了DGNSS和PPP等方法的实现。 数据存储模块用于保存和管理接收器接收到的原始观测数据和定位计算结果。该模块实现了将观测数据保存为日志文件,以及读取和解析日志文件的功能。同时,还能够将定位计算结果保存为坐标文件,以供后续分析和应用。 在RTKLIB源码解析过程中,可以根据需要进行修改和定制。例如,可以添加新的定位算法、改进信号处理方法、增加新的卫星系统支持等。此外,还可以对界面进行修改,以满足特定需求。 综上所述,RTKLIB源码解析涉及到多个模块和算法的实现,包括导航定位、信号处理和数据存储等。通过对源码解析,可以深入了解RTKLIB的工作原理和内部机制,并且可以根据需要进行修改和定制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值