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
函数中的内容:
/* read obs and nav data -----------------------------------------------------*/
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;
}
/* read rinex obs and nav file */
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;
}
/* sort observation data */
nepoch=sortobs(obs);
/* delete duplicated ephemeris */
uniqnav(nav);
/* set time span for progress display */
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
函数来进一步实现:
/* read RINEX OBS and NAV files ------------------------------------------------
* read RINEX OBS and NAV files
* args : char *file I file (wild-card * expanded) ("": stdin)
* int rcv I receiver number for obs data
* (gtime_t ts) I observation time start (ts.time==0: no limit)
* (gtime_t te) I observation time end (te.time==0: no limit)
* (double tint) I observation time interval (s) (0:all)
* char *opt I RINEX options (see below,"": no option)
* obs_t *obs IO observation data (NULL: no input)
* nav_t *nav IO navigation data (NULL: no input)
* sta_t *sta IO station parameters (NULL: no input)
* return : status (1:ok,0:no data,-1:error)
* notes : read data are appended to obs and nav struct
* before calling the function, obs and nav should be initialized.
* observation data and navigation data are not sorted.
* navigation data may be duplicated.
* call sortobs() or uniqnav() to sort data or delete duplicated eph.
*
* RINEX options (separated by spaces) :
*
* -GLss[=shift]: select GPS signal ss (ss: RINEX 3 code, "1C","2W"...)
* -RLss[=shift]: select GLO signal ss
* -ELss[=shift]: select GAL signal ss
* -JLss[=shift]: select QZS signal ss
* -CLss[=shift]: select BDS signal ss
* -ILss[=shift]: select IRN signal ss
* -SLss[=shift]: select SBS signal ss
*
* shift: carrier phase shift to be added (cycle)
*
* -SYS=sys[,sys...]: select navigation systems
* (sys=G:GPS,R:GLO,E:GAL,J:QZS,C:BDS,I:IRN,S:SBS)
*
*-----------------------------------------------------------------------------*/
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;
}
}
/* expand wild-card */
if ((n=expath(file,files,MAXEXFILE))<=0) {
for (i=0;i<MAXEXFILE;i++) free(files[i]);
return 0;
}
/* read rinex files */
for (i=0;i<n&&stat>=0;i++) {
stat=readrnxfile(files[i],ts,te,tint,opt,0,rcv,&type,obs,nav,sta);
}
/* if station name empty, set 4-char name from file head */
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
用于读取压缩之后的文件,代码分别如下:
/* read RINEX file -----------------------------------------------------------*/
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);
/* read RINEX file header */
if (!readrnxh(fp,&ver,type,&sys,&tsys,tobs,nav,sta)) return 0;
/* flag=0:except for clock,1:clock */
if ((!flag&&*type=='C')||(flag&&*type!='C')) return 0;
/* read RINEX file body */
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); /* extension */
case 'L': return readrnxnav(fp,opt,ver,SYS_GAL,nav); /* extension */
case 'C': return readrnxclk(fp,opt,index,nav);
}
trace(2,"unsupported rinex type ver=%.2f type=%c\n",ver,*type);
return 0;
}
/* uncompress and read RINEX file --------------------------------------------*/
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);
/* uncompress file */
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;
}
/* read RINEX file */
stat=readrnxfp(fp,ts,te,tint,opt,flag,index,type,obs,nav,sta);
fclose(fp);
/* delete temporary file */
if (cstat) remove(tmpfile);
return stat;
}
以压缩的文件为例,使用readrnxfile
函数解压之后,调用readrnxfp
函数来进行RINEX
文件的读取;而又调用读取文件头函数readrnxh
和读取文件体函数readrnxobs
、readrnxnav
和readrnxclk
,对应函数代码如下:
读取文件头函数
/* read RINEX file header ----------------------------------------------------*/
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);
/* 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;
}
else if (strstr(label,"PGM / RUN BY / DATE")) {
continue;
}
else if (strstr(label,"COMMENT")) {
continue;
}
switch (*type) { /* file 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 */
}
if (strstr(label,"END OF HEADER")) return 1;
if (++i>=MAXPOSHEAD&&*type==' ') break; /* no RINEX file */
}
return 0;
}
其又主要调用了解码观测头文件函数decode_obsh
以及星历头文件函数decode_navh
;
读取观测值文件函数
/* read RINEX observation data -----------------------------------------------*/
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;
/* read RINEX observation data body */
while ((n=readrnxobsb(fp,opt,ver,tsys,tobs,&flag,data,sta))>=0&&stat>=0) {
for (i=0;i<n;i++) {
/* UTC -> GPST */
if (*tsys==TSYS_UTC) data[i].time=utc2gpst(data[i].time);
/* save cycle slip */
saveslips(slips,data+i);
}
/* screen data by time */
if (n>0&&!screent(data[0].time,ts,te,tint)) continue;
for (i=0;i<n;i++) {
/* restore cycle slip */
restslips(slips,data+i);
data[i].rcv=(uint8_t)rcv;
/* save obs data */
if ((stat=addobsdata(obs,data+i))<0) break;
}
}
trace(4,"readrnxobs: nobs=%d stat=%d\n",obs->n,stat);
free(data);
return stat;
}
其中关键函数为readrnxobsb
/* read RINEX observation data body ------------------------------------------*/
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;
/* set system mask */
mask=set_sysmask(opt);
/* set signal index */
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);
/* read record */
while (fgets(buff,MAXRNXLEN,fp)) {
/* decode observation epoch */
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];
/* decode RINEX observation data */
if (decode_obsdata(fp,buff,ver,mask,index,data+n)) n++;
}
else if (*flag==3||*flag==4) { /* new site or header info follows */
/* decode RINEX observation data file header */
decode_obsh(fp,buff,ver,tsys,tobs,NULL,sta);
}
if (++i>nsat) return n;
}
return -1;
}
其又调用设置信号标识的set_index
函数和解码RINEX
观测值文件的decode_obsdata
函数;代码分别如下:
/* set signal index ----------------------------------------------------------*/
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;
}
/* parse phase shift options */
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);
}
}
/* assign index for highest priority code */
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;
}
}
/* assign index of extended observation data */
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 debug */
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
}
/* decode observation data ---------------------------------------------------*/
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) { /* ver.3 */
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;
}
/* read observation data fields */
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) { /* ver.2 */
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;
}
/* assign position in observation data */
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; /* C1? index */
if (ind->type[i]==0&&p[i]==1) l[m++]=i; /* C2? index */
}
if (ver<=2.11) {
/* if multiple codes (C1/P1,C2/P2), select higher priority */
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;
}
}
}
/* save observation data */
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
还需要使用如下代码,进行观测值数据的分类和重复星历数据的剔除:
/* sort observation data */
nepoch=sortobs(obs);
/* delete duplicated ephemeris */
uniqnav(nav);
sortobs
函数代码如下:
/* sort and unique observation data --------------------------------------------
* sort and unique observation data by time, rcv, sat
* args : obs_t *obs IO observation data
* return : number of epochs
*-----------------------------------------------------------------------------*/
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);
/* delete duplicated data */
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;
}
以上就是读取观测值文件的主要的函数了,只是粗略的展示了以下函数的调用关系,具体的内容很庞大,博主也是了解尚浅,需要进一步学习。