目录
2.2.5 assign index for highest priority code
1、readrnxh
readrnxh(fp,&ver,type,&sys,&tsys,tobs,nav,sta)
变量说明:
tobs
存储的是下面框选的区域,rtklib会将2版本的rinex转为3版本进行存储
char tobs[NUMSYS][MAXOBSTYPE][4]={{""}};
rinex3版本格式:
2、readrnxobsb中set_index函数
2.1、sigind_t结构体
n——代表观测类型个数(数据第二列)
code——观测类型后两个字符的指向(index)--[参考rtkcmn.c 函数->obs2code]--比如1c的code为1
type——观测值类型的索引,对应下面obscodes[]="CLDS"中的索引(L1C中的L)
idx——不同卫星系统频率index--[参考rtkcmn.c函数->code2idx]详细定义了不同卫星系统的频率
pri——不同通道的优先级(每一个频率都有对应不同的通道)--[参考rtkcmn.c函数->getcodepri]越高的优先级数值越大
pos——是判断是否使用该观测值的一个索引,-1代表不适用,在后面代码中经常会用到
/* type definition -----------------------------------------------------------*/
typedef struct { /* signal index type */
int n; /* number of index */
int idx[MAXOBSTYPE]; /* signal freq-index */
int pos[MAXOBSTYPE]; /* signal index in obs data (-1:no) */
uint8_t pri [MAXOBSTYPE]; /* signal priority (15-0) */
uint8_t type[MAXOBSTYPE]; /* type (0:C,1:L,2:D,3:S) */
uint8_t code[MAXOBSTYPE]; /* obs-code (CODE_L??) */
double shift[MAXOBSTYPE]; /* phase shift (cycle) */
} sigind_t;
2.2、函数
其数据的读取主要通过上面这个setindex函数(rinex.c)实现
//此处循环某个卫星系统所有观测值类型
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;
}
代码学习
下面这段代码先进行匹配,获得匹配到字母的地址,然后与原字符数组相减,获得一个该索引的整数值
ind->type[i]=(p=strchr(obscodes,tobs[i][0]))?(int)(p-obscodes):0;
2.2.1、obs2code :
传入code string (“1C”,“1P”,“1Y”,…),在下面定义的obscodes里面的索引,这里需要注意的是,这里的索引和作者定义的obs code (CODE_???)相对应,所以可以理解为返回的是CODE_???
static const char obscodes[]="CLDS"; /* observation type codes */
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","1I","1Q","5A", /* 40-49 */
"5B","5C","9A","9B","9C", "9X","1D","5D","5P","5Z", /* 50-59 */
"6E","7D","7P","7Z","8D", "8P","4A","4B","4X","" /* 60-69 */
};
#define CODE_NONE 0 /* obs code: none or unknown */
#define CODE_L1C 1 /* obs code: L1C/A,G1C/A,E1C (GPS,GLO,GAL,QZS,SBS) */
#define CODE_L1P 2 /* obs code: L1P,G1P,B1P (GPS,GLO,BDS) */
#define CODE_L1W 3 /* obs code: L1 Z-track (GPS) */
#define CODE_L1Y 4 /* obs code: L1Y (GPS) */
#define CODE_L1M 5 /* obs code: L1M (GPS) */
#define CODE_L1N 6 /* obs code: L1codeless,B1codeless (GPS,BDS) */
#define CODE_L1S 7 /* obs code: L1C(D) (GPS,QZS) */
#define CODE_L1L 8 /* obs code: L1C(P) (GPS,QZS) */
#define CODE_L1E 9 /* (not used) */
#define CODE_L1A 10 /* obs code: E1A,B1A (GAL,BDS) */
#define CODE_L1B 11 /* obs code: E1B (GAL) */
#define CODE_L1X 12 /* obs code: E1B+C,L1C(D+P),B1D+P (GAL,QZS,BDS) */
#define CODE_L1Z 13 /* obs code: E1A+B+C,L1S (GAL,QZS) */
#define CODE_L2C 14 /* obs code: L2C/A,G1C/A (GPS,GLO) */
#define CODE_L2D 15 /* obs code: L2 L1C/A-(P2-P1) (GPS) */
#define CODE_L2S 16 /* obs code: L2C(M) (GPS,QZS) */
#define CODE_L2L 17 /* obs code: L2C(L) (GPS,QZS) */
#define CODE_L2X 18 /* obs code: L2C(M+L),B1_2I+Q (GPS,QZS,BDS) */
#define CODE_L2P 19 /* obs code: L2P,G2P (GPS,GLO) */
#define CODE_L2W 20 /* obs code: L2 Z-track (GPS) */
#define CODE_L2Y 21 /* obs code: L2Y (GPS) */
#define CODE_L2M 22 /* obs code: L2M (GPS) */
#define CODE_L2N 23 /* obs code: L2codeless (GPS) */
#define CODE_L5I 24 /* obs code: L5I,E5aI (GPS,GAL,QZS,SBS) */
#define CODE_L5Q 25 /* obs code: L5Q,E5aQ (GPS,GAL,QZS,SBS) */
#define CODE_L5X 26 /* obs code: L5I+Q,E5aI+Q,L5B+C,B2aD+P (GPS,GAL,QZS,IRN,SBS,BDS) */
#define CODE_L7I 27 /* obs code: E5bI,B2bI (GAL,BDS) */
#define CODE_L7Q 28 /* obs code: E5bQ,B2bQ (GAL,BDS) */
#define CODE_L7X 29 /* obs code: E5bI+Q,B2bI+Q (GAL,BDS) */
#define CODE_L6A 30 /* obs code: E6A,B3A (GAL,BDS) */
#define CODE_L6B 31 /* obs code: E6B (GAL) */
#define CODE_L6C 32 /* obs code: E6C (GAL) */
#define CODE_L6X 33 /* obs code: E6B+C,LEXS+L,B3I+Q (GAL,QZS,BDS) */
#define CODE_L6Z 34 /* obs code: E6A+B+C,L6D+E (GAL,QZS) */
#define CODE_L6S 35 /* obs code: L6S (QZS) */
#define CODE_L6L 36 /* obs code: L6L (QZS) */
#define CODE_L8I 37 /* obs code: E5abI (GAL) */
#define CODE_L8Q 38 /* obs code: E5abQ (GAL) */
#define CODE_L8X 39 /* obs code: E5abI+Q,B2abD+P (GAL,BDS) */
#define CODE_L2I 40 /* obs code: B1_2I (BDS) */
#define CODE_L2Q 41 /* obs code: B1_2Q (BDS) */
#define CODE_L6I 42 /* obs code: B3I (BDS) */
#define CODE_L6Q 43 /* obs code: B3Q (BDS) */
#define CODE_L3I 44 /* obs code: G3I (GLO) */
#define CODE_L3Q 45 /* obs code: G3Q (GLO) */
#define CODE_L3X 46 /* obs code: G3I+Q (GLO) */
#define CODE_L1I 47 /* obs code: B1I (BDS) (obsolute) */
#define CODE_L1Q 48 /* obs code: B1Q (BDS) (obsolute) */
#define CODE_L5A 49 /* obs code: L5A SPS (IRN) */
#define CODE_L5B 50 /* obs code: L5B RS(D) (IRN) */
#define CODE_L5C 51 /* obs code: L5C RS(P) (IRN) */
#define CODE_L9A 52 /* obs code: SA SPS (IRN) */
#define CODE_L9B 53 /* obs code: SB RS(D) (IRN) */
#define CODE_L9C 54 /* obs code: SC RS(P) (IRN) */
#define CODE_L9X 55 /* obs code: SB+C (IRN) */
#define CODE_L1D 56 /* obs code: B1D (BDS) */
#define CODE_L5D 57 /* obs code: L5D(L5S),B2aD (QZS,BDS) */
#define CODE_L5P 58 /* obs code: L5P(L5S),B2aP (QZS,BDS) */
#define CODE_L5Z 59 /* obs code: L5D+P(L5S) (QZS) */
#define CODE_L6E 60 /* obs code: L6E (QZS) */
#define CODE_L7D 61 /* obs code: B2bD (BDS) */
#define CODE_L7P 62 /* obs code: B2bP (BDS) */
#define CODE_L7Z 63 /* obs code: B2bD+P (BDS) */
#define CODE_L8D 64 /* obs code: B2abD (BDS) */
#define CODE_L8P 65 /* obs code: B2abP (BDS) */
#define CODE_L4A 66 /* obs code: G1aL1OCd (GLO) */
#define CODE_L4B 67 /* obs code: G1aL1OCd (GLO) */
#define CODE_L4X 68 /* obs code: G1al1OCd+p (GLO) */
#define MAXCODE 68 /* max number of obs code */
2.2.2、code2obs
传入CODE_???,返回obs code string ("1C","1P","1P",...)
extern char *code2obs(uint8_t code)
{
if (code<=CODE_NONE||MAXCODE<code) return "";
return obscodes[code];
}
2.2.3、code2idx
传入obs code (CODE_???) 和卫星系统(SYS_???) ,返回载波频率的下标,即上面的01234索引
frequency index (-1: error)
* 0 1 2 3 4
* --------------------------------------
* GPS L1 L2 L5 - -
* GLONASS G1 G2 G3 - - (G1=G1,G1a,G2=G2,G2a)
* Galileo E1 E5b E5a E6 E5ab
* QZSS L1 L2 L5 L6 -
* SBAS L1 - L5 - -
* BDS B1 B2 B2a B3 B2ab (B1=B1I,B1C,B2=B2I,B2b)
* NavIC L5 S - - -
2.2.4、getcodepri
obs[1]是信号通道代码,比如L1P里面的P,codepris[i][j]——卫星系统(i)和信号频率idx(j),由此输出该优先级
/* search code priority */
return (p=strchr(codepris[i][j],obs[1]))?14-(int)(p-codepris[i][j]):0;
static char codepris[7][MAXFREQ][16]={ /* code priority for each freq-index */
/* 0 1 2 3 4 5 */
{"CPYWMNSL","PYWCMNDLSX","IQX" ,"" ,"" ,"" ,""}, /* GPS */
{"CPABX" ,"PCABX" ,"IQX" ,"" ,"" ,"" ,""}, /* GLO */
{"CABXZ" ,"IQX" ,"IQX" ,"ABCXZ" ,"IQX" ,"" ,""}, /* GAL */
{"CLSXZ" ,"LSX" ,"IQXDPZ" ,"LSXEZ" ,"" ,"" ,""}, /* QZS */
{"C" ,"IQX" ,"" ,"" ,"" ,"" ,""}, /* SBS */
{"IQXDPAN" ,"IQXDPZ" ,"DPX" ,"IQXA" ,"DPX" ,"" ,""}, /* BDS */
{"ABCX" ,"ABCX" ,"" ,"" ,"" ,"" ,""} /* IRN */
};
2.2.5 assign index for highest priority code
这里根据频率分类进行优先级设置,(以我们上面的观测值文件为例)其具体数值参照下面两个表格,
/* assign index for highest priority code */
//根据频率分配优先级,将最高的对应pos设置为频率索引
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;
//每种观测值类型(C/L/S)都有一个pos被置为0或1或2
for (j=0;j<n;j++) {
if (ind->code[j]==ind->code[k]) ind->pos[j]=i;
}
}
C1 | C2 | L1 | L2 | P1 | P2 | S1 | S2 | |
rinex2->rinex3 | C1C | C2X | L1C | L2W | C1W | C2W | S1C | S2W |
ind->code[i] | 1 | 18 | 1 | 20 | 3 | 20 | 1 | 20 |
ind->type[i] | 0 | 0 | 1 | 1 | 0 | 0 | 3 | 3 |
ind->idx[i] | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
ind->pri[i] | 14 | 5 | 14 | 12 | 11 | 12 | 14 | 12 |
第一次pos[i] | 0 | -1 | 0 | -1 | -1 | -1 | 0 | -1 |
第二次pos[i] | 0 | -1 | 0 | 1 | -1 | 1 | 0 | 1 |
注:上面标红字母即为频率2变化后的值
3、readrnxobsb中decode_obsdata
3.1 obsd_t结构体
注意:在观测值文件中,所记录的载波相位数据的单位为周,伪距数据的单位为m。
观测值所对应的时标(即观测时刻)是依据接收机钟的读数所生成的,而不是标准的GPS时,因而在该时标中含有接收机的钟差。
typedef struct { /* observation data record */
gtime_t time; /* receiver sampling time (GPST) */
uint8_t sat,rcv; /* satellite/receiver number */
uint16_t SNR[NFREQ+NEXOBS]; /* signal strength (0.001 dBHz) */
uint8_t LLI[NFREQ+NEXOBS]; /* loss of lock indicator */
uint8_t 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;
该段代码流程是
先读取数据存储在val lli中——>后面是对于测距码的观测值进行选择,只选择优先级更大或者不为空的——>然后赋值给结构体obsd_t,代码段如下
/* 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; //因为在obsd_t定义以0.001 dBHz存储
}
}
参考链接:
梳理rtklib读o文件及建立索引时,对北斗系统观测类型的处理原理 - 知乎 (zhihu.com)
(46条消息) RTKLIB源码解析(三)、 Rinex文件读取(rinex.c)——2_他人是一面镜子,保持谦虚的态度的博客-CSDN博客