在了解这个函数之前,应该先说这个函数中对应的几个结构体。
这个结构体是在rtklib.h中定义的一个用来存储某个历元中的某个卫星的观测值的。定义如下:
typedef struct { /* observation data record */
gtime_t time; /* receiver sampling time (GPST) */
unsigned char sat,rcv; /* satellite/receiver number */
unsigned char SNR [NFREQ+NEXOBS]; /* signal strength (0.25 dBHz) */
unsigned char LLI [NFREQ+NEXOBS]; /* loss of lock indicator */
unsigned char code[NFREQ+NEXOBS]; /* code indicator (CODE_???) */
double L[NFREQ+NEXOBS]; /* observation data carrier-phase (cycle) */
double P[NFREQ+NEXOBS]; /* observation data pseudorange (m) */
float D[NFREQ+NEXOBS]; /* observation data doppler frequency (Hz) */
} obsd_t;
之前的博客说过这里面的数组名称代表观测值类型,数组的下标代表载波类型。其中的数组名称如果看过RINEX的格式说明,一眼就能知道代表的意思。
typedef struct { /* observation data */
int n,nmax; /* number of obervation data/allocated */
obsd_t *data; /* observation data records */
} obs_t;
这个结构体中存储的是所有的观测值数据,n代表实际存储的观测值结构体的个数,nmax代表的是最多存储多少个观测值结构体,如果超过最大个数,需要重新开辟内存空间。在C++中,内存报错是比较讨厌的一类错误。在rtklib中,我们会发现其中的异常捕捉机制运用的非常好,几乎是一步一trace,这也让我学到了需要利用trace语句来处理异常,以便调试代码。
static int addobsdata(obs_t *obs, const obsd_t *data)
在了解了上面的结构体之后,就可以知道这个函数就是添加新的观测值,而且还可以很轻松的读懂这个函数的每一条语句。当然,如果只是想要对rtklib有整体的把握,就不用太过于纠结每一个语句了。
这个函数是一个比较重要的函数。而且比较容易让人迷惑。顾名思义,这个函数就是为了建立之前我们用到的索引。大家可能忘了,在读取观测值文件的时候,我们用到了索引函数,就是根据观测值文件头中的SYS / # / OBS TYPES这一行的东西。
static void set_index(double ver, int sys, const char *opt, char tobs[MAXOBSTYPE][4], sigind_t *ind)
函数的参数意义如下
ver //RINEX文件版本号
sys //卫星所属系统
opt //选项
tobs //观测值类型数组
ind //得到的索引
其中,选项是什么可以先不用知道。观测值类型数组是一个比较容易困惑的地方。之前我们用过这样的一个数组tobs[][MAXOBSTYPE][4],这个是在读取RIENX观测值文件的文件头得到的。里面存储了下面的内容。
还是举个例子来说明吧,针对于数组tobs[][MAXOBSTYPE][4]来说,tobs[0]意味着一个指向二位数组的指针,而0代表的是GPS系统,因此tobs[0]代表的是GPS系统的观测值类型。再看tobs[0][0],这个就是指向一个一维数组的指针,代表着GPS系统的第一个观测值类型,也就是说tobs[0][0]="C1C ",注意,一定是一个四位的字符串,因为在RINEX的格式说明中,每一个观测值类型占四位,包括了最后的一个空格。也就是说tobs[0][0]代表着GPS系统中利用L1载波上的C/A码测得的伪距。这下应该理解了吧。哎,因为我当时就迷糊了好一段时间,所以就把这个地方仔细说一下,一是为了防止我以后忘了,二是给大家提个醒。不要嫌弃我啰嗦啊(〃‘▽’〃)
tobs[][MAXOBSTYPE][4] //以前用的
tobs[MAXOBSTYPE][4] //本函数中的
对比上面两个可以发现,数组维数少了一维,但是由于函数的参数中已经指明了系统,所以就可以将三维数组退化成为了二维数组了。
参数说明完了,下面看这个函数中用了哪些子函数吧。
这个函数是位于rtkcnm.c中的一个函数,代码长度不长,但是可能比较难理解。先看主函数中调用obs2code函数的语句吧。
ind->code[i]=obs2code(tobs[i]+1,ind->frq+i);
还是老样子,看传递的参数。tobs[i]+1,这个很考验C语言的指针方面的功底了。由于tobs是一个二维数组,因此tobs[i]+1应该表示的是二维数组中的第i+1个字符串向后舍弃第一位后的子串。说起来很拗口,举个例子就好了。比如对于GPS系统来说,tobs[0]+1就是“C1C "中的"1C "子串。也就是传递了子串和索引中的频率。由于索引中的频率尚未有值,因此可以推断出来,这个函数一定是根据tobs[i]+1来为索引中的频率赋值。
下面来看obs2code的函数体
extern unsigned char obs2code(const char *obs, int *freq)
{
int i;
if (freq) *freq=0;
for (i=1;*obscodes[i];i++) {
if (strcmp(obscodes[i],obs)) continue;
if (freq) *freq=obsfreqs[i];
return (unsigned char)i;
}
return CODE_NONE;
}
这个里面的obscodes和obsfreqs都是在rtkcnm.c的文件开头定义的数组。
static char *obscodes[]={ /* observation code strings */
"" ,"1C","1P","1W","1Y", "1M","1N","1S","1L","1E", /* 0- 9 */
"1A","1B","1X","1Z","2C", "2D","2S","2L","2X","2P", /* 10-19 */
"2W","2Y","2M","2N","5I", "5Q","5X","7I","7Q","7X", /* 20-29 */
"6A","6B","6C","6X","6Z", "6S","6L","8L","8Q","8X", /* 30-39 */
"2I","2Q","6I","6Q","3I", "3Q","3X","" /* 40-49 */
};
static unsigned char obsfreqs[]={ /* 1:L1,2:L2,3:L5,4:L6,5:L7,6:L8,7:L3 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0- 9 */
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, /* 10-19 */
2, 2, 2, 2, 3, 3, 3, 5, 5, 5, /* 20-29 */
4, 4, 4, 4, 4, 4, 4, 6, 6, 6, /* 30-39 */
2, 2, 4, 4, 3, 3, 3, 0 /* 40-49 */
};
也就是说,obscodes中定义的全部是卫星观测值类型的后两个字母。再看obs2code函数体,可以发现,这个函数的作用就是在所有的观测值类型的后两位字母中找到传入的观测值类型。然后将对应的载波赋值给索引中的频率值,最后返回的是唯一确定的位置。
回到主函数,主函数中虽然有很多语句,但是我认为最终要的就是下面的语句,其它的语句可以暂时先不考虑,以后用到了再回头看。
for (i=n=0;*tobs[i];i++,n++) {
ind->code[i]=obs2code(tobs[i]+1,ind->frq+i);
ind->type[i]=(p=strchr(obscodes,tobs[i][0]))?(int)(p-obscodes):0;
ind->pri[i]=getcodepri(sys,ind->code[i],opt);
ind->pos[i]=-1;
}
static const char obscodes[]="CLDS";
我感觉解释完第一句之后,其它的句子就可以类推出来了。
上面说了好多,总而言之,这个函数就是建立索引的一个函数,索引就是将o文件头中的观测值类型分割开来,分别存入不同的数组中,这些数组合起来构成了索引。
这一篇就先写这么多吧,才写了两个函数,实在是太多了,我怕我自己忘记的东西实在是太多了,我要抓紧时间写了,不然之后又忘记了,感觉自己活成了一条金鱼,只有几秒的记忆(▼皿▼#)