RTKLIB专题学习(十二)—支持的信号ID/观测类型
基础理论知识
观测值类型
RTKLIB 支持的信号id /观测类型如下表所示。表中还列出了RINEX 2 、RINEX 3 观测类型、RTCM 3 MSM 信号id 和BINEX 观测代码id 。使用RTKCONV 和CONVBIN 实现RTCM3 和RINEX 以及RTCM 2 到RINEX 的转换,当使用STRSVR 和STR2STR 实现RTCM 2 和BINEX 到RTCM3 的转换,也使用了该表。 对于各系统的目前的频率和观测值类型,可参见如下:(表中观测值类型分别为:伪距观测值 、载波相位观测值 、多普勒观测值 、信号强度观测值 )
多信号默认优先级
如果输入的观测数据在同一频率内包含多个信号,RTKLIB 将按照以下默认优先级选择一个信号进行处理。要选择合适的信号,请使用附录D.5中描述的RINEX 选项或接收器相关选项。在用户ap 中,要改变或获取信号优先级,可以使用API setcodepri() 或getcodepri() 。 可以看到,对于北斗系统来说,三个频率信号选择的优先级是C2I、C7I、C6I ,也就是说当选择单频定位时,使用C2I 信号对应的观测值,当选择L1+L2 时,使用C2I+C7I 信号对应的观测值进行观测方程的建立。
源码读取函数
源码简介
源码中,读取观测值文件和星历文件的函数为readobsnav ,由execses 函数调用,下面是readobsnav 函数中的内容:
static int readobsnav(gtime_t ts, gtime_t te, double ti, char **infile,
const int *index, int n, const prcopt_t *prcopt,
obs_t *obs, nav_t *nav, sta_t *sta)
{
int i,j,ind=0,nobs=0,rcv=1;
trace(3,"readobsnav: ts=%s n=%d\n",time_str(ts,0),n);
obs->data=NULL; obs->n =obs->nmax =0;
nav->eph =NULL; nav->n =nav->nmax =0;
nav->geph=NULL; nav->ng=nav->ngmax=0;
nav->seph=NULL; nav->ns=nav->nsmax=0;
nepoch=0;
for (i=0;i<n;i++) {
if (checkbrk("")) return 0;
if (index[i]!=ind) {
if (obs->n>nobs) rcv++;
ind=index[i]; nobs=obs->n;
}
if (readrnxt(infile[i],rcv,ts,te,ti,prcopt->rnxopt[rcv<=1?0:1],obs,nav,
rcv<=2?sta+rcv-1:NULL)<0) {
checkbrk("error : insufficient memory");
trace(1,"insufficient memory\n");
return 0;
}
}
if (obs->n<=0) {
checkbrk("error : no obs data");
trace(1,"\n");
return 0;
}
if (nav->n<=0&&nav->ng<=0&&nav->ns<=0) {
checkbrk("error : no nav data");
trace(1,"\n");
return 0;
}
nepoch=sortobs(obs);
uniqnav(nav);
if (ts.time==0||te.time==0) {
for (i=0; i<obs->n;i++) if (obs->data[i].rcv==1) break;
for (j=obs->n-1;j>=0;j--) if (obs->data[j].rcv==1) break;
if (i<j) {
if (ts.time==0) ts=obs->data[i].time;
if (te.time==0) te=obs->data[j].time;
settspan(ts,te);
}
}
return 1;
}
而readobsnav 又通过调用readrnxt 函数来进一步实现:
extern int readrnxt(const char *file, int rcv, gtime_t ts, gtime_t te,
double tint, const char *opt, obs_t *obs, nav_t *nav,
sta_t *sta)
{
int i,n,stat=0;
const char *p;
char type=' ',*files[MAXEXFILE]={0};
trace(3,"readrnxt: file=%s rcv=%d\n",file,rcv);
if (!*file) {
return readrnxfp(stdin,ts,te,tint,opt,0,1,&type,obs,nav,sta);
}
for (i=0;i<MAXEXFILE;i++) {
if (!(files[i]=(char *)malloc(1024))) {
for (i--;i>=0;i--) free(files[i]);
return -1;
}
}
if ((n=expath(file,files,MAXEXFILE))<=0) {
for (i=0;i<MAXEXFILE;i++) free(files[i]);
return 0;
}
for (i=0;i<n&&stat>=0;i++) {
stat=readrnxfile(files[i],ts,te,tint,opt,0,rcv,&type,obs,nav,sta);
}
if (type=='O'&&sta) {
if (!(p=strrchr(file,FILEPATHSEP))) p=file-1;
if (!*sta->name) setstr(sta->name,p+1,4);
}
for (i=0;i<MAXEXFILE;i++) free(files[i]);
return stat;
}
readrnxt 函数又调用readrnxfp 和readrnxfile 函数;其中,readrnxfp 函数用于读取未压缩的文件,而readrnxfile 用于读取压缩之后的文件,代码分别如下:
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)
{
double ver;
int sys,tsys=TSYS_GPS;
char tobs[NUMSYS][MAXOBSTYPE][4]={{""}};
trace(3,"readrnxfp: flag=%d index=%d\n",flag,index);
if (!readrnxh(fp,&ver,type,&sys,&tsys,tobs,nav,sta)) return 0;
if ((!flag&&*type=='C')||(flag&&*type!='C')) return 0;
switch (*type) {
case 'O': return readrnxobs(fp,ts,te,tint,opt,index,ver,&tsys,tobs,obs,
sta);
case 'N': return readrnxnav(fp,opt,ver,sys ,nav);
case 'G': return readrnxnav(fp,opt,ver,SYS_GLO,nav);
case 'H': return readrnxnav(fp,opt,ver,SYS_SBS,nav);
case 'J': return readrnxnav(fp,opt,ver,SYS_QZS,nav);
case 'L': return readrnxnav(fp,opt,ver,SYS_GAL,nav);
case 'C': return readrnxclk(fp,opt,index,nav);
}
trace(2,"unsupported rinex type ver=%.2f type=%c\n",ver,*type);
return 0;
}
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)
{
FILE *fp;
int cstat,stat;
char tmpfile[1024];
trace(3,"readrnxfile: file=%s flag=%d index=%d\n",file,flag,index);
if (sta) init_sta(sta);
if ((cstat=rtk_uncompress(file,tmpfile))<0) {
trace(2,"rinex file uncompact error: %s\n",file);
return 0;
}
if (!(fp=fopen(cstat?tmpfile:file,"r"))) {
trace(2,"rinex file open error: %s\n",cstat?tmpfile:file);
return 0;
}
stat=readrnxfp(fp,ts,te,tint,opt,flag,index,type,obs,nav,sta);
fclose(fp);
if (cstat) remove(tmpfile);
return stat;
}
以压缩的文件为例,使用readrnxfile 函数解压之后,调用readrnxfp 函数来进行RINEX 文件的读取;而又调用读取文件头函数readrnxh 和读取文件体函数readrnxobs 、readrnxnav 和readrnxclk ,对应函数代码如下:
读取文件头函数
static int readrnxh(FILE *fp, double *ver, char *type, int *sys, int *tsys,
char tobs[][MAXOBSTYPE][4], nav_t *nav, sta_t *sta)
{
char buff[MAXRNXLEN],*label=buff+60;
int i=0;
trace(3,"readrnxh:\n");
*ver=2.10; *type=' '; *sys=SYS_GPS;
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);
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;
case 'S': *sys=SYS_SBS; *tsys=TSYS_GPS; break;
case 'J': *sys=SYS_QZS; *tsys=TSYS_QZS; break;
case 'C': *sys=SYS_CMP; *tsys=TSYS_CMP; break;
case 'I': *sys=SYS_IRN; *tsys=TSYS_IRN; break;
case 'M': *sys=SYS_NONE; *tsys=TSYS_GPS; break;
default :
trace(2,"not supported satellite system: %c\n",*(buff+40));
break;
}
continue;
}
else if (strstr(label,"PGM / RUN BY / DATE")) {
continue;
}
else if (strstr(label,"COMMENT")) {
continue;
}
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;
case 'L': decode_navh (buff,nav); break;
}
if (strstr(label,"END OF HEADER")) return 1;
if (++i>=MAXPOSHEAD&&*type==' ') break;
}
return 0;
}
其又主要调用了解码观测头文件函数decode_obsh 以及星历头文件函数decode_navh ;
读取观测值文件函数
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, sta_t *sta)
{
obsd_t *data;
uint8_t slips[MAXSAT][NFREQ+NEXOBS]={{0}};
int i,n,flag=0,stat=0;
trace(4,"readrnxobs: rcv=%d ver=%.2f tsys=%d\n",rcv,ver,tsys);
if (!obs||rcv>MAXRCV) return 0;
if (!(data=(obsd_t *)malloc(sizeof(obsd_t)*MAXOBS))) return 0;
while ((n=readrnxobsb(fp,opt,ver,tsys,tobs,&flag,data,sta))>=0&&stat>=0) {
for (i=0;i<n;i++) {
if (*tsys==TSYS_UTC) data[i].time=utc2gpst(data[i].time);
saveslips(slips,data+i);
}
if (n>0&&!screent(data[0].time,ts,te,tint)) continue;
for (i=0;i<n;i++) {
restslips(slips,data+i);
data[i].rcv=(uint8_t)rcv;
if ((stat=addobsdata(obs,data+i))<0) break;
}
}
trace(4,"readrnxobs: nobs=%d stat=%d\n",obs->n,stat);
free(data);
return stat;
}
其中关键函数为readrnxobsb
static int readrnxobsb(FILE *fp, const char *opt, double ver, int *tsys,
char tobs[][MAXOBSTYPE][4], int *flag, obsd_t *data,
sta_t *sta)
{
gtime_t time={0};
sigind_t index[NUMSYS]={{0}};
char buff[MAXRNXLEN];
int i=0,n=0,nsat=0,nsys=NUMSYS,sats[MAXOBS]={0},mask;
mask=set_sysmask(opt);
if (nsys>=1) set_index(ver,SYS_GPS,opt,tobs[0],index );
if (nsys>=2) set_index(ver,SYS_GLO,opt,tobs[1],index+1);
if (nsys>=3) set_index(ver,SYS_GAL,opt,tobs[2],index+2);
if (nsys>=4) set_index(ver,SYS_QZS,opt,tobs[3],index+3);
if (nsys>=5) set_index(ver,SYS_SBS,opt,tobs[4],index+4);
if (nsys>=6) set_index(ver,SYS_CMP,opt,tobs[5],index+5);
if (nsys>=7) set_index(ver,SYS_IRN,opt,tobs[6],index+6);
while (fgets(buff,MAXRNXLEN,fp)) {
if (i==0) {
if ((nsat=decode_obsepoch(fp,buff,ver,&time,flag,sats))<=0) {
continue;
}
}
else if ((*flag<=2||*flag==6)&&n<MAXOBS) {
data[n].time=time;
data[n].sat=(uint8_t)sats[i-1];
if (decode_obsdata(fp,buff,ver,mask,index,data+n)) n++;
}
else if (*flag==3||*flag==4) {
decode_obsh(fp,buff,ver,tsys,tobs,NULL,sta);
}
if (++i>nsat) return n;
}
return -1;
}
其又调用设置信号标识的set_index 函数和解码RINEX 观测值文件的decode_obsdata 函数;代码分别如下:
static void set_index(double ver, int sys, const char *opt,
char tobs[MAXOBSTYPE][4], sigind_t *ind)
{
const char *p;
char str[8],*optstr="";
double shift;
int i,j,k,n;
for (i=n=0;*tobs[i];i++,n++) {
ind->code[i]=obs2code(tobs[i]+1);
ind->type[i]=(p=strchr(obscodes,tobs[i][0]))?(int)(p-obscodes):0;
ind->idx[i]=code2idx(sys,ind->code[i]);
ind->pri[i]=getcodepri(sys,ind->code[i],opt);
ind->pos[i]=-1;
}
switch (sys) {
case SYS_GPS: optstr="-GL%2s=%lf"; break;
case SYS_GLO: optstr="-RL%2s=%lf"; break;
case SYS_GAL: optstr="-EL%2s=%lf"; break;
case SYS_QZS: optstr="-JL%2s=%lf"; break;
case SYS_SBS: optstr="-SL%2s=%lf"; break;
case SYS_CMP: optstr="-CL%2s=%lf"; break;
case SYS_IRN: optstr="-IL%2s=%lf"; break;
}
for (p=opt;p&&(p=strchr(p,'-'));p++) {
if (sscanf(p,optstr,str,&shift)<2) continue;
for (i=0;i<n;i++) {
if (strcmp(code2obs(ind->code[i]),str)) continue;
ind->shift[i]=shift;
trace(2,"phase shift: sys=%2d tobs=%s shift=%.3f\n",sys,
tobs[i],shift);
}
}
for (i=0;i<NFREQ;i++) {
for (j=0,k=-1;j<n;j++) {
if (ind->idx[j]==i&&ind->pri[j]&&(k<0||ind->pri[j]>ind->pri[k])) {
k=j;
}
}
if (k<0) continue;
for (j=0;j<n;j++) {
if (ind->code[j]==ind->code[k]) ind->pos[j]=i;
}
}
for (i=0;i<NEXOBS;i++) {
for (j=0;j<n;j++) {
if (ind->code[j]&&ind->pri[j]&&ind->pos[j]<0) break;
}
if (j>=n) break;
for (k=0;k<n;k++) {
if (ind->code[k]==ind->code[j]) ind->pos[k]=NFREQ+i;
}
}
for (i=0;i<n;i++) {
if (!ind->code[i]||!ind->pri[i]||ind->pos[i]>=0) continue;
trace(4,"reject obs type: sys=%2d, obs=%s\n",sys,tobs[i]);
}
ind->n=n;
#if 0
for (i=0;i<n;i++) {
trace(2,"set_index: sys=%2d,tobs=%s code=%2d pri=%2d idx=%d pos=%d shift=%5.2f\n",
sys,tobs[i],ind->code[i],ind->pri[i],ind->idx[i],ind->pos[i],
ind->shift[i]);
}
#endif
}
static int decode_obsdata(FILE *fp, char *buff, double ver, int mask,
sigind_t *index, obsd_t *obs)
{
sigind_t *ind;
double val[MAXOBSTYPE]={0};
uint8_t lli[MAXOBSTYPE]={0};
char satid[8]="";
int i,j,n,m,stat=1,p[MAXOBSTYPE],k[16],l[16];
trace(4,"decode_obsdata: ver=%.2f\n",ver);
if (ver>2.99) {
sprintf(satid,"%.3s",buff);
obs->sat=(uint8_t)satid2no(satid);
}
if (!obs->sat) {
trace(4,"decode_obsdata: unsupported sat sat=%s\n",satid);
stat=0;
}
else if (!(satsys(obs->sat,NULL)&mask)) {
stat=0;
}
switch (satsys(obs->sat,NULL)) {
case SYS_GLO: ind=index+1; break;
case SYS_GAL: ind=index+2; break;
case SYS_QZS: ind=index+3; break;
case SYS_SBS: ind=index+4; break;
case SYS_CMP: ind=index+5; break;
case SYS_IRN: ind=index+6; break;
default: ind=index ; break;
}
for (i=0,j=ver<=2.99?0:3;i<ind->n;i++,j+=16) {
if (ver<=2.99&&j>=80) {
if (!fgets(buff,MAXRNXLEN,fp)) break;
j=0;
}
if (stat) {
val[i]=str2num(buff,j,14)+ind->shift[i];
lli[i]=(uint8_t)str2num(buff,j+14,1)&3;
}
}
if (!stat) return 0;
for (i=0;i<NFREQ+NEXOBS;i++) {
obs->P[i]=obs->L[i]=0.0; obs->D[i]=0.0f;
obs->SNR[i]=obs->LLI[i]=obs->code[i]=0;
}
for (i=n=m=0;i<ind->n;i++) {
p[i]=(ver<=2.11)?ind->idx[i]:ind->pos[i];
if (ind->type[i]==0&&p[i]==0) k[n++]=i;
if (ind->type[i]==0&&p[i]==1) l[m++]=i;
}
if (ver<=2.11) {
if (n>=2) {
if (val[k[0]]==0.0&&val[k[1]]==0.0) {
p[k[0]]=-1; p[k[1]]=-1;
}
else if (val[k[0]]!=0.0&&val[k[1]]==0.0) {
p[k[0]]=0; p[k[1]]=-1;
}
else if (val[k[0]]==0.0&&val[k[1]]!=0.0) {
p[k[0]]=-1; p[k[1]]=0;
}
else if (ind->pri[k[1]]>ind->pri[k[0]]) {
p[k[1]]=0; p[k[0]]=NEXOBS<1?-1:NFREQ;
}
else {
p[k[0]]=0; p[k[1]]=NEXOBS<1?-1:NFREQ;
}
}
if (m>=2) {
if (val[l[0]]==0.0&&val[l[1]]==0.0) {
p[l[0]]=-1; p[l[1]]=-1;
}
else if (val[l[0]]!=0.0&&val[l[1]]==0.0) {
p[l[0]]=1; p[l[1]]=-1;
}
else if (val[l[0]]==0.0&&val[l[1]]!=0.0) {
p[l[0]]=-1; p[l[1]]=1;
}
else if (ind->pri[l[1]]>ind->pri[l[0]]) {
p[l[1]]=1; p[l[0]]=NEXOBS<2?-1:NFREQ+1;
}
else {
p[l[0]]=1; p[l[1]]=NEXOBS<2?-1:NFREQ+1;
}
}
}
for (i=0;i<ind->n;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]]=(uint16_t)(val[i]/SNR_UNIT+0.5); break;
}
}
trace(4,"decode_obsdata: time=%s sat=%2d\n",time_str(obs->time,0),obs->sat);
return 1;
}
需要注意,再调用完readrnxt 函数之后,readobsnav 还需要使用如下代码,进行观测值数据的分类和重复星历数据的剔除:
nepoch=sortobs(obs);
uniqnav(nav);
sortobs 函数代码如下:
extern int sortobs(obs_t *obs)
{
int i,j,n;
trace(3,"sortobs: nobs=%d\n",obs->n);
if (obs->n<=0) return 0;
qsort(obs->data,obs->n,sizeof(obsd_t),cmpobs);
for (i=j=0;i<obs->n;i++) {
if (obs->data[i].sat!=obs->data[j].sat||
obs->data[i].rcv!=obs->data[j].rcv||
timediff(obs->data[i].time,obs->data[j].time)!=0.0) {
obs->data[++j]=obs->data[i];
}
}
obs->n=j+1;
for (i=n=0;i<obs->n;i=j,n++) {
for (j=i+1;j<obs->n;j++) {
if (timediff(obs->data[j].time,obs->data[i].time)>DTTOL) break;
}
}
return n;
}
以上就是读取观测值文件的主要的函数了,只是粗略的展示了以下函数的调用关系,具体的内容很庞大,博主也是了解尚浅,需要进一步学习。
|