有了之前的函数做铺垫,接下来的代码就好读多了。其实rtklib的代码构成和我们平时写程序的代码构成是一致的,先是写出一个一个最底层的函数,然后再写出中层的函数,最后利用高层的函数将这些函数一个一个组建起来。就像搭积木一样,先造积木块,然后搭房子,最后组成社区。(hiahiahiahia,强行比喻( ̄▽ ̄)/)
static int readrnxobsb(FILE *fp, const char *opt, double ver, char tobs[][MAXOBSTYPE][4], int *flag, obsd_t *data)
这个函数就是读取o文件中的观测值记录(除了文件头剩下的部分)的函数了。严格地说,这个函数只是读取一个观测历元的观测数据。
/* set signal index */
set_index(ver,SYS_GPS,opt,tobs[0],index );
set_index(ver,SYS_GLO,opt,tobs[1],index+1);
set_index(ver,SYS_GAL,opt,tobs[2],index+2);
set_index(ver,SYS_QZS,opt,tobs[3],index+3);
set_index(ver,SYS_SBS,opt,tobs[4],index+4);
set_index(ver,SYS_CMP,opt,tobs[5],index+5);
首先,按照上面的方式建立索引。将三维观测值类型数组退化成二维数组,建立一个索引数组。
然后剩下的所有代码就是读取这个历元中的数据了。
在读取的过程中,读取历元头,然后读取观测数据。答题思路就是这样的,代码也简洁易懂,没什么坑。
static int readrnxobs(FILE *fp, gtime_t ts, gtime_t te, double tint,
const char *opt, int rcv, double ver, int tsys,
char tobs[][MAXOBSTYPE][4], obs_t *obs)
这个函数就是读取o文件中整个观测值数据了,也就是除了文件头之外的所有部分。readrnxobsb函数只读取一个历元的观测值,因此在readrnxobs函数中,添加了内存分配语句之后,便是重复调用readrnxobsb函数,直到所有的观测值全被读完,或者是出现了某个历元没有卫星的情况为止。
在rtklib.h文件中定义的关于卫星星历的结构体eph_t。
typedef struct { /* GPS/QZS/GAL broadcast ephemeris type */
int sat; /* satellite number */
int iode,iodc; /* IODE,IODC */
int sva; /* SV accuracy (URA index) */
int svh; /* SV health (0:ok) */
int week; /* GPS/QZS: gps week, GAL: galileo week */
int code; /* GPS/QZS: code on L2, GAL/CMP: data sources */
int flag; /* GPS/QZS: L2 P data flag, CMP: nav type */
gtime_t toe,toc,ttr; /* Toe,Toc,T_trans */
/* SV orbit parameters */
double A,e,i0,OMG0,omg,M0,deln,OMGd,idot;
double crc,crs,cuc,cus,cic,cis;
double toes; /* Toe (s) in week */
double fit; /* fit interval (h) */
double f0,f1,f2; /* SV clock parameters (af0,af1,af2) */
double tgd[4]; /* group delay parameters */
/* GPS/QZS:tgd[0]=TGD */
/* GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 */
/* CMP :tgd[0]=BGD1,tgd[1]=BGD2 */
} eph_t;
从结构体的定义可以看出,eph_t中存储了卫星星历中的卫星参数,也就是说把星历按照实际意义存储在了结构体中。
static int decode_eph(double ver, int sat, gtime_t toc, const double *data,
eph_t *eph)
从函数原型可以看出,data是没有经过分类的原始卫星数据,没有任何的物理意义,只是单纯的数据。至于它是怎么得到的,下面的函数可以看到。参数eph是将data归类后的结果。函数本身没有什么特别的坑,主要思想就是将星历中相同的参数提取出来,由于各个卫星系统中还有不一样的数据,因此需要利用if语句将每个系统特有的数据提取出来。
下面的两个函数是针对GLONASS系统和GALILEO系统特别的星历归类函数。因此就不特别的进行说明了。
static int decode_geph(double ver, int sat, gtime_t toc, double *data,
geph_t *geph);
static int decode_seph(double ver, int sat, gtime_t toc, double *data,
seph_t *seph);
首先,还是先说明一下用到的几个子函数。satid2no函数之前已经说过了,就是将卫星的id号转换为唯一的一个整数类型号码,作为卫星的唯一标识。
还是老样子,这个函数也是定义在rtkcnm.h中的一个函数。函数原型如下
extern int str2time(const char *s, int i, int n, gtime_t *t)
{
double ep[6];
char str[256],*p=str;
if (i<0||(int)strlen(s)=0;) *p++=*s++; *p='\0';
if (sscanf(str,"%lf %lf %lf %lf %lf %lf",ep,ep+1,ep+2,ep+3,ep+4,ep+5)<6)
return -1;
if (ep[0]<100.0) ep[0]+=ep[0]<80.0?2000.0:1900.0;
*t=epoch2time(ep);
return 0;
}
函数不长,利用了sscanf函数格式化读取字符串中的内容,并且将读取到的数组转化成gtime_t类型的结构体输出。
这个函数之前也说过,之所以把它单独列出来就是因为这个函数比较重要,建议记住。
里面的子函数清楚了,接下来可以研究主函数了。主函数实际上用一次就读取一个卫星的星历,是利用i来控制是否读完了一个历元的数据。设计的思想很巧妙,由于GLONASS和GALILEO的卫星星历比较特殊,所以要控制单独判断。这个函数就是先读取卫星星历数据到data中,然后再对data进行解码。只要上面的函数清楚了,这个函数就没有什么疑惑的地方了。
这三个函数其实和前面添加观测值的函数类似,都是判断结构体的大小是否够用,然后将新一个卫星的星历添加到原有的观测值结构体中。
static int readrnxnav(FILE *fp, const char *opt, double ver, int sys,
nav_t *nav)
这个函数也没有什么好说的,就是将之前所有的读取星历文件的函数整理一下,根据文件头的标识符判断文件是哪一种卫星系统的星历文件,利用相应的函数读取并添加星历。但是一定要注意,这个函数并非是读取整个星历文件,它只能读取星历文件的数据记录,不能读取文件头,读取文件头的函数在之前已经介绍过了。
static int readrnxfp(FILE *fp, gtime_t ts, gtime_t te, double tint,
const char *opt, int flag, int index, char *type,
obs_t *obs, nav_t *nav, sta_t *sta)
这个函数就是真正能够读取真个RINEX文件的函数,它能读取包括o文件,n文件等等的一系列文件,也就是之前函数的整合。没什么好说的。
static int readrnxfile(const char *file, gtime_t ts, gtime_t te, double tint,
const char *opt, int flag, int index, char *type,
obs_t *obs, nav_t *nav, sta_t *sta)
这个函数就是增加了一个解压的功能,然后再进行读取。
由于我还没有接触RINEX文件中的钟差文件,因此就不进行有关于中读取钟差文件的函数记录了。哎,要去写课程作业了,这个可能要抽空闲时间弄了/(ㄒoㄒ)/~~