注释的 // 没加是为了在代码块中显示更加明显,若直接复制源代码需加之。
static void decode_obsh(FILE *fp, char *buff, double ver, int *tsys,
char tobs[][MAXOBSTYPE][4], nav_t *nav, sta_t *sta)
{
/* default codes for unknown code */
const char *defcodes[]={
"CWX ", /* GPS: L125____ */
"CC ", /* GLO: L12_____ */
"X XXXX ", /* GAL: L1_5678_ */
"CXXX ", /* QZS: L1256___ */
"C X ", /* SBS: L1_5____ */
"X XX ", /* BDS: L1__67__ */
" A A" /* IRN: L__5___9 */
}; 定义一个指针数组,不知道的编码直接采取默认字符串加空格的形式存储
double del[3];
int i,j,k,n,nt,prn,fcn;
const char *p;
char *label=buff+60,str[4];
trace(4,"decode_obsh: ver=%.2f\n",ver);
if (strstr(label,"MARKER NAME" )) {
if (sta) setstr(sta->name,buff,60);
} label指向第61例,与字符串比较,若相同则将缓冲区第1到60列复制到结构体sta中的name数组中,表示制造商的名称,else if类同。
else if (strstr(label,"MARKER NUMBER" )) { /* opt */
if (sta) setstr(sta->marker,buff,20);
}
else if (strstr(label,"MARKER TYPE" )) ; /* ver.3 */
else if (strstr(label,"OBSERVER / AGENCY" )) ; 不做处理空语句
else if (strstr(label,"REC # / TYPE / VERS" )) {
if (sta) {
setstr(sta->recsno, buff, 20);
setstr(sta->rectype,buff+20,20);
setstr(sta->recver, buff+40,20);
} setstr函数在rtklib-RINEX文件读取-rinex.c解析(一)种做过解释,意思是复制第二参数到第三参数之间位置上的所有字符并去除尾部空格,详细可转到(一)
}
else if (strstr(label,"ANT # / TYPE" )) {
if (sta) {
setstr(sta->antsno,buff ,20);
setstr(sta->antdes,buff+20,20);
}
}
else if (strstr(label,"APPROX POSITION XYZ" )) {
if (sta) {
for (i=0,j=0;i<3;i++,j+=14) sta->pos[i]=str2num(buff,j,14);
} str2num函数将在下面介绍具体细节
}
else if (strstr(label,"ANTENNA: DELTA H/E/N")) {
if (sta) {
for (i=0,j=0;i<3;i++,j+=14) del[i]=str2num(buff,j,14);
sta->del[2]=del[0]; /* h */
sta->del[0]=del[1]; /* e */
sta->del[1]=del[2]; /* n */
}
}
else if (strstr(label,"ANTENNA: DELTA X/Y/Z")) ; /* opt ver.3 */
else if (strstr(label,"ANTENNA: PHASECENTER")) ; /* opt ver.3 */
else if (strstr(label,"ANTENNA: B.SIGHT XYZ")) ; /* opt ver.3 */
else if (strstr(label,"ANTENNA: ZERODIR AZI")) ; /* opt ver.3 */
else if (strstr(label,"ANTENNA: ZERODIR XYZ")) ; /* opt ver.3 */
else if (strstr(label,"CENTER OF MASS: XYZ" )) ; /* opt ver.3 */
else if (strstr(label,"SYS / # / OBS TYPES" )) { /* ver.3 */
if (!(p=strchr(syscodes,buff[0]))) {
trace(2,"invalid system code: sys=%c\n",buff[0]);
return;
} 如果观测类型不在static const char syscodes[]="GREJSCI"; 中输出错误消息
i=(int)(p-syscodes);
n=(int)str2num(buff,3,3);
for (j=nt=0,k=7;j<n;j++,k+=4) {
if (k>58) {
if (!fgets(buff,MAXRNXLEN,fp)) break;
k=7;
}
if (nt<MAXOBSTYPE-1) setstr(tobs[i][nt++],buff+k,3);
}
*tobs[i][nt]='\0'; 存储观测类型,分星座类型用三维数组进行存储【星座类型】【观测类型】【数量】
/* change beidou B1 code: 3.02 draft -> 3.02/3.03 */
if (i==5) {
for (j=0;j<nt;j++) if (tobs[i][j][1]=='2') tobs[i][j][1]='1'; 北斗数据类型转换
}
/* if unknown code in ver.3, set default code */
for (j=0;j<nt;j++) {
if (tobs[i][j][2]) continue;
if (!(p=strchr(frqcodes,tobs[i][j][1]))) continue;
tobs[i][j][2]=defcodes[i][(int)(p-frqcodes)];
trace(2,"set default for unknown code: sys=%c code=%s\n",buff[0],
tobs[i][j]); 如果没有该观测类型,就进行错误提示
}
}
else if (strstr(label,"WAVELENGTH FACT L1/2")) ; /* opt ver.2 */
else if (strstr(label,"# / TYPES OF OBSERV" )) { /* ver.2 */
n=(int)str2num(buff,0,6);
for (i=nt=0,j=10;i<n;i++,j+=6) {
if (j>58) {
if (!fgets(buff,MAXRNXLEN,fp)) break;
j=10;
} rinex2版本的观测类型存储
if (nt>=MAXOBSTYPE-1) continue;
if (ver<=2.99) {
setstr(str,buff+j,2);
convcode(ver,SYS_GPS,str,tobs[0][nt]);
convcode(ver,SYS_GLO,str,tobs[1][nt]);
convcode(ver,SYS_GAL,str,tobs[2][nt]);
convcode(ver,SYS_QZS,str,tobs[3][nt]);
convcode(ver,SYS_SBS,str,tobs[4][nt]);
convcode(ver,SYS_CMP,str,tobs[5][nt]);
}
nt++;
} rinex从2到3版本的转换
*tobs[0][nt]='\0'; 末尾加上空字符
}
else if (strstr(label,"SIGNAL STRENGTH UNIT")) ; /* opt ver.3 */
else if (strstr(label,"INTERVAL" )) ; /* opt */
else if (strstr(label,"TIME OF FIRST OBS" )) {
if (!strncmp(buff+48,"GPS",3)) *tsys=TSYS_GPS;
else if (!strncmp(buff+48,"GLO",3)) *tsys=TSYS_UTC;
else if (!strncmp(buff+48,"GAL",3)) *tsys=TSYS_GAL;
else if (!strncmp(buff+48,"QZS",3)) *tsys=TSYS_QZS; /* ver.3.02 */
else if (!strncmp(buff+48,"BDT",3)) *tsys=TSYS_CMP; /* ver.3.02 */
else if (!strncmp(buff+48,"IRN",3)) *tsys=TSYS_IRN; /* ver.3.03 */
} 根据历元开始时间第49-51列判断星座类型
else if (strstr(label,"TIME OF LAST OBS" )) ; /* opt */
else if (strstr(label,"RCV CLOCK OFFS APPL" )) ; /* opt */
else if (strstr(label,"SYS / DCBS APPLIED" )) ; /* opt ver.3 */
else if (strstr(label,"SYS / PCVS APPLIED" )) ; /* opt ver.3 */
else if (strstr(label,"SYS / SCALE FACTOR" )) ; /* opt ver.3 */
else if (strstr(label,"SYS / PHASE SHIFTS" )) ; /* ver.3.01 */
else if (strstr(label,"GLONASS SLOT / FRQ #")) { /* ver.3.02 */
if (nav) {
for (i=0,p=buff+4;i<8;i++,p+=8) {
if (sscanf(p,"R%2d %2d",&prn,&fcn)<2) continue;
if (1<=prn&&prn<=MAXPRNGLO) nav->glo_fcn[prn-1]=fcn+8;
}
}
}
else if (strstr(label,"GLONASS COD/PHS/BIS" )) { /* ver.3.02 */
if (nav) {
for (i=0,p=buff;i<4;i++,p+=13) {
if (strncmp(p+1,"C1C",3)) nav->glo_cpbias[0]=str2num(p,5,8);
else if (strncmp(p+1,"C1P",3)) nav->glo_cpbias[1]=str2num(p,5,8);
else if (strncmp(p+1,"C2C",3)) nav->glo_cpbias[2]=str2num(p,5,8);
else if (strncmp(p+1,"C2P",3)) nav->glo_cpbias[3]=str2num(p,5,8);
}
} GLONASS数据处理不做介绍
}
else if (strstr(label,"LEAP SECONDS" )) { /* opt */
if (nav) nav->leaps=(int)str2num(buff,0,6);
} 记录跳秒,GLONASS观测文件中独有
else if (strstr(label,"# OF SALTELLITES" )) { /* opt */
/* skip */ ;
}
else if (strstr(label,"PRN / # OF OBS" )) { /* opt */
/* skip */ ;
}
} 其余不做记录
这个函数是对观测文件o文件重新编码,以方便后序rtklib直接进行处理,需要对rinex2/3版本的观测文件格式比较了解才能够进行有效的学习,读者可以在阅读源代码的过程中将两个版本的观测文件放在旁边对比学习,笔者便是这么做的。通过buff与label精确定位读取字节进行对比,然后将涉及测站类型的数据例如天线类型、系列号、版本等信息放在sta这个结构体中,而对于不同星座不同的观测数据类型放置在三维数组tobs中。这里最主要的是要明白每个函数的作用,对读取观测文件头部有个脉络,以方便日后在进行算法分析的时候明白原始数据的储存位置,方便使用和查看。
extern double str2num(const char *s, int i, int n)
{
double value;
char str[256],*p=str;
if (i<0||(int)strlen(s)<i||(int)sizeof(str)-1<n) return 0.0; 检验i必须大于0,起始的i位置必须小于原字符串的长度,复制总数必须小于str数组的长度
for (s+=i;*s&&--n>=0;s++) *p++=*s=='d'||*s=='D'?'E':*s; 将原字符串s全部复制到str数组中,若其中有 d/D 改成 E 进行存储
*p='\0'; 末尾加上终止符
return sscanf(str,"%lf",&value)==1?value:0.0; 将str以长浮点型格式放入value,成功则返回value值,不成功返回0
}
s是需要复制的字符串,i是从s中第i个字符开始,一直截取n位,然后将截取的字符串转化为数值类型。这个函数是将字符串转化为double类型的数值的函数,利用sscanf函数实现,具体函数的解释都在上面的注释中。对于d/D改成E读者可能有疑惑?举个例子您就明白了,例如“123E01”这个字符串会被转化为1230。但是只有其中的字母是E的时候才象征着科学计数法。星历中使用D表示科学计数法,所以在函数中先将D替换为E,然后进行转化。
static void decode_navh(char *buff, nav_t *nav)
{
int i,j;
char *label=buff+60;
trace(4,"decode_navh:\n");
if (strstr(label,"ION ALPHA" )) { /* opt ver.2 */
if (nav) {
for (i=0,j=2;i<4;i++,j+=12) nav->ion_gps[i]=str2num(buff,j,12);
}
}
else if (strstr(label,"ION BETA" )) { /* opt ver.2 */
if (nav) {
for (i=0,j=2;i<4;i++,j+=12) nav->ion_gps[i+4]=str2num(buff,j,12);
}
}
else if (strstr(label,"DELTA-UTC: A0,A1,T,W")) { /* opt ver.2 */
if (nav) {
for (i=0,j=3;i<2;i++,j+=19) nav->utc_gps[i]=str2num(buff,j,19);
for (;i<4;i++,j+=9) nav->utc_gps[i]=str2num(buff,j,9);
}
}
else if (strstr(label,"IONOSPHERIC CORR" )) { /* opt ver.3 */
if (nav) {
if (!strncmp(buff,"GPSA",4)) {
for (i=0,j=5;i<4;i++,j+=12) nav->ion_gps[i]=str2num(buff,j,12);
}
else if (!strncmp(buff,"GPSB",4)) {
for (i=0,j=5;i<4;i++,j+=12) nav->ion_gps[i+4]=str2num(buff,j,12);
}
else if (!strncmp(buff,"GAL",3)) {
for (i=0,j=5;i<4;i++,j+=12) nav->ion_gal[i]=str2num(buff,j,12);
}
else if (!strncmp(buff,"QZSA",4)) { /* v.3.02 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_qzs[i]=str2num(buff,j,12);
}
else if (!strncmp(buff,"QZSB",4)) { /* v.3.02 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_qzs[i+4]=str2num(buff,j,12);
}
else if (!strncmp(buff,"BDSA",4)) { /* v.3.02 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_cmp[i]=str2num(buff,j,12);
}
else if (!strncmp(buff,"BDSB",4)) { /* v.3.02 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_cmp[i+4]=str2num(buff,j,12);
}
else if (!strncmp(buff,"IRNA",4)) { /* v.3.03 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_irn[i]=str2num(buff,j,12);
}
else if (!strncmp(buff,"IRNB",4)) { /* v.3.03 */
for (i=0,j=5;i<4;i++,j+=12) nav->ion_irn[i+4]=str2num(buff,j,12);
}
}
}
else if (strstr(label,"TIME SYSTEM CORR" )) { /* opt ver.3 */
if (nav) {
if (!strncmp(buff,"GPUT",4)) {
nav->utc_gps[0]=str2num(buff, 5,17);
nav->utc_gps[1]=str2num(buff,22,16);
nav->utc_gps[2]=str2num(buff,38, 7);
nav->utc_gps[3]=str2num(buff,45, 5);
}
else if (!strncmp(buff,"GLUT",4)) {
nav->utc_glo[0]=str2num(buff, 5,17);
nav->utc_glo[1]=str2num(buff,22,16);
}
else if (!strncmp(buff,"GAUT",4)) { /* v.3.02 */
nav->utc_gal[0]=str2num(buff, 5,17);
nav->utc_gal[1]=str2num(buff,22,16);
nav->utc_gal[2]=str2num(buff,38, 7);
nav->utc_gal[3]=str2num(buff,45, 5);
}
else if (!strncmp(buff,"QZUT",4)) { /* v.3.02 */
nav->utc_qzs[0]=str2num(buff, 5,17);
nav->utc_qzs[1]=str2num(buff,22,16);
nav->utc_qzs[2]=str2num(buff,38, 7);
nav->utc_qzs[3]=str2num(buff,45, 5);
}
else if (!strncmp(buff,"BDUT",4)) { /* v.3.02 */
nav->utc_cmp[0]=str2num(buff, 5,17);
nav->utc_cmp[1]=str2num(buff,22,16);
nav->utc_cmp[2]=str2num(buff,38, 7);
nav->utc_cmp[3]=str2num(buff,45, 5);
}
else if (!strncmp(buff,"SBUT",4)) { /* v.3.02 */
nav->utc_cmp[0]=str2num(buff, 5,17);
nav->utc_cmp[1]=str2num(buff,22,16);
nav->utc_cmp[2]=str2num(buff,38, 7);
nav->utc_cmp[3]=str2num(buff,45, 5);
}
else if (!strncmp(buff,"IRUT",4)) { /* v.3.03 */
nav->utc_irn[0]=str2num(buff, 5,17);
nav->utc_irn[1]=str2num(buff,22,16);
nav->utc_irn[2]=str2num(buff,38, 7);
nav->utc_irn[3]=str2num(buff,45, 5);
}
}
}
else if (strstr(label,"LEAP SECONDS" )) { /* opt */
if (nav) nav->leaps=(int)str2num(buff,0,6);
}
}
此函数主要是应用字符串比较strstr函数和strncmp函数实现对头文件描述部分进行配对,然后使用str2num函数实现文本文件到数字的转换,从而读取数据。
while (fgets(buff,MAXRNXLEN,fp)) {
if (strlen(buff)<=60) continue;
else if (strstr(label,"RINEX VERSION / TYPE")) {
*ver=str2num(buff,0,9);
*type=*(buff+20);
/* satellite system */
switch (*(buff+40)) {
case ' ':
case 'G': *sys=SYS_GPS; *tsys=TSYS_GPS; break;
case 'R': *sys=SYS_GLO; *tsys=TSYS_UTC; break;
case 'E': *sys=SYS_GAL; *tsys=TSYS_GAL; break; /* v.2.12 */
case 'S': *sys=SYS_SBS; *tsys=TSYS_GPS; break;
case 'J': *sys=SYS_QZS; *tsys=TSYS_QZS; break; /* v.3.02 */
case 'C': *sys=SYS_CMP; *tsys=TSYS_CMP; break; /* v.2.12 */
case 'I': *sys=SYS_IRN; *tsys=TSYS_IRN; break; /* v.3.03 */
case 'M': *sys=SYS_NONE; *tsys=TSYS_GPS; break; /* mixed */
default :
trace(2,"not supported satellite system: %c\n",*(buff+40));
break;
}
continue;
}
/* file type */
switch (*type) {
case 'O': decode_obsh(fp,buff,*ver,tsys,tobs,nav,sta); break;
case 'N': decode_navh (buff,nav); break;
case 'G': decode_gnavh(buff,nav); break;
case 'H': decode_hnavh(buff,nav); break;
case 'J': decode_navh (buff,nav); break; /* extension */
case 'L': decode_navh (buff,nav); break; /* extension */
}
此函数主要是对真正输入文件进行读取,通过第一行的41识别符进行文件类型的判断,并用switch语句对刚刚获取的type进行读取,然后调用之前写的重新编码的函数,实现具体功能,例如*type=O,则调用刚刚的decode_obsh函数,进行头文件相关重要信息的存储。
学习rtklib(二)
头文件的处理到这里基本形成体系,接下来的系列会介绍具体文件的实际数据的读取与存储。