学习rtklib(二)

1.decode_obsh函数

static void decode_obsh(FILE *fp, char *buff, double ver, int *tsys, char tobs[][MAXOBSTYPE][4], nav_t *nav, sta_t *sta)

在介绍decode_obsh函数之前,先说明一下其中的一个子函数。

extern double str2num(const char *s, int i, int n)

s是指定的字符串,i是从s中第i个字符开始,一直截取n位,然后将截取的字符串转化为数值。这个函数是将字符串转化为double类型的数值的函数。里面利用sscanf函数实现。举个例子,例如“123E01”这个字符串会被转化为1230。但是只有其中的字母是E的时候才象征着科学计数法。星历中使用D表示科学计数法,所以在函数中先将D替换为E,然后进行转化。
学习rtklib(二)_第1张图片
上面的图片是观测值头文件的一部分。参照RINEX说明文档,可以知道在文件头的每一行的前60个字节是值,60个字节后面的部分是相应的标签说明。各种标签对应的意义在RINEX说明文档里面已经详细说明。
按照字节数读取我们需要的值。将读取到的观测系统的观测类型放入tobs这个三维数组中,将关于测站的信息(测站名字,大概位置等等)放到sta中。其中涉及到比较多的技巧大家自己对照代码看吧,这里主要是写清每个函数的作用,梳理大致脉络,理清每个函数和变量的作用,方便后续查看。
至于nav这个参数只是为了方便观测值中含有GLONASS观测值的文件使用的。

2.decode_navh函数

static void decode_navh(char *buff, nav_t *nav)

这个函数没有什么太多要注意的,就是单纯地将卫星星历文件中的文件头按照字节将buff中的各个参数读进nav中,提取出有用的信息。

3.readrnxh函数

static int readrnxh(FILE *fp, double *ver, char *type, int *sys, int *tsys, char tobs[][MAXOBSTYPE][4], nav_t *nav, sta_t *sta)

这个函数就是先判断文件是什么类型的文件,然后分别对应上面的读文件头的函数。也就是说将上面的代码组合起来,形成一个完整的读文件头的函数。读到的导航文件头中卫星的信息存在nav参数中,读到的测站信息存在sta参数中。

4.decode_obsepoch函数

static int decode_obsepoch(FILE *fp, char *buff, double ver, gtime_t *time, int *flag, int *sats)

这个函数是将每个观测历元的时间提取出来放入time参数中,也就是将下面的图片中的内容放入time中。
观测历元

5.decode_obsdata函数

static int decode_obsdata(FILE *fp, char *buff, double ver, sigind_t *index, obsd_t *obs)

先介绍一下这个函数里面的子函数。

5.1 satid2no函数

extern int satid2no(const char *id)

这个函数也是位于rtkcnm.c中的一个函数。这个函数是根据卫星系统的类型加上卫星的prn号返回一个卫星的整数标记。举个例子吧,例如id是“R09”,那么返回的值就是32+9=41,反过来,后面还会有专门能将41转化为“R09”的函数。也就是说,在rtklib中,卫星系统连同卫星号被设计成一个连续的整数。依照依次累加的算法进行转化。也就是说在卫星号传递的时候,可以直接传递整数,而不用传递一个字符串。这样无论是什么卫星系统的卫星都对应唯一一个整数。会大大降低运行时间,不得不说,rtklib无论是在代码架构上还是在效率上都近乎于达到了当时的最高水平,还是很值得研究的ヾ(◍°∇°◍)ノ゙。

5.2 sigind_t结构体

typedef struct {                        /* signal index type */
    int n;                              /* number of index */
    int frq[MAXOBSTYPE];                /* signal frequency (1:L1,2:L2,...) */
    int pos[MAXOBSTYPE];                /* signal index in obs data (-1:no) */
    unsigned char pri [MAXOBSTYPE];     /* signal priority (15-0) */
    unsigned char type[MAXOBSTYPE];     /* type (0:C,1:L,2:D,3:S) */
    unsigned char code[MAXOBSTYPE];     /* obs code (CODE_L??) */
    double shift[MAXOBSTYPE];           /* phase shift (cycle) */
} sigind_t;

在这里不得不提这个结构体了。我在第一次看这个结构体是懵圈的,因为我不知道这个是干什么的,也不知道这个东西是怎么来的。在“瞻前顾后”了好长时间才发现这个的用途。其实这个和我们文件头中的观测值类型有着很大的关系,也就是和下面的图片上的东西有着很大的关系。
学习rtklib(二)_第2张图片
这个实在o文件的文件头中,表示每种卫星系统的载波类型和观测值类型。sigind_t就是根据这个建立起来的。
在下面的代码中就会发现,每种类型的系统其实对应的就是一个sigind_t结构体,也就是说只需要建立六个结构体就够了。
结构体中的n代表这个卫星系统总的观测值类型,对应的卫星系统标识符后面的数字,例如G后面的16,R后面的12等等。
剩下的观测值类型就拆开存在结构体中的相应位置。
总之sigind_t结构体就像一个索引一样,告诉主函数每个卫星系统的观测值类型是什么,使用了哪种频率的载波,采用了哪种测距码观测的等等信息。

3.主要函数

下面回到decode_obsdata函数。
判断观测值文件是否是3.0以上的版本,如果是3.0以上版本,就将每个历元下面的观测值按照一行一行的提取出来,每次提取一行,根据前三位判断卫星系统和prn号。这里的prn号就是连续的,也就是其中既包含了卫星系统的信息,也包含了卫星的真实prn号。
对应不同的系统采用相应的索引,根据版本号来读取相应的观测值数据暂时存在val中,LLI信息存在lli中,最后将这两个数组中的信息存放在obs结构体中。
最后的存放过程是这样的。

/* save obs data */
    for (i=0;in;i++) {
        if (p[i]<0||val[i]==0.0) continue;
        switch (ind->type[i]) {
            case 0: obs->P[p[i]]=val[i]; obs->code[p[i]]=ind->code[i]; break;
            case 1: obs->L[p[i]]=val[i]; obs->LLI [p[i]]=lli[i];       break;
            case 2: obs->D[p[i]]=(float)val[i];                        break;
            case 3: obs->SNR[p[i]]=(unsigned char)(val[i]*4.0+0.5);    break;
        }
    }

上面代码中的obs->P代表着这个观测值结构体中的伪距观测值。不管是伪距观测值还是载波相位观测值和多普勒观测值,都是利用各种载波得到的。这里还是举个例子吧,载波一般的情况下有三种频率,所以无论是obs->P,还是obs->L和obs->D,在没有扩展载波的情况下都是大小为3的数组。obs->P[0]就是利用L1载波观测到的伪距,obs->P[1]就是利用L2载波观测到的伪距…大家以此类推就行了。那么这个函数就完成了。

总结

本来还想继续写的,但是发现这篇实在是太长了,所以把它拆开了。这些都是我在没有运行调试rtklib时的学习结果,所以不一定对啊,没经过检验,有不对的地方请大家指出来ヾ(≧▽≦*)o

你可能感兴趣的:(学习rtklib(二))