1.C5X和C5Q会不会作为同一个频率使用会。至少对 GPS / Galileo / QZSS 来说5X、5Q都会被映射到同一个 L5/E5a 频率槽。关键代码在src/rtkcmn.cstatic int code2freq_GPS(uint8_t code, double *freq) { const char *obscode2obs(code); switch (obs[0]) { case 1: *freqFREQL1; return 0; /* L1 */ case 2: *freqFREQL2; return 1; /* L2 */ case 5: *freqFREQL5; return 2; /* L5 */ } return -1; }也就是说代码只看obs[0]即C5Q - obs code 5Q - obs[0] 5 - L5 - frequency index 2 C5X - obs code 5X - obs[0] 5 - L5 - frequency index 2所以在频率层面C5Q 和 C5X 都属于第 3 个频率槽 f2即 L5/E5a/B2a 类频率不是按Q、X分开作为两个独立频率。2. 读 RINEX 时是否区分码通道读入阶段是区分的但只用于“选择哪个码通道进入该频率槽”。代码里rinex.c - set_index()会先把每个观测类型转成观测码ind-code[i]obs2code(tobs[i]1); ind-type[i](pstrchr(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;然后对每个频率槽只选一个优先级最高的码for (i0;iNFREQ;i) { for (j0,k-1;jn;j) { if (ind-idx[j]iind-pri[j](k0||ind-pri[j]ind-pri[k])) { kj; } } if (k0) continue; for (j0;jn;j) { if (ind-code[j]ind-code[k]) ind-pos[j]i; } }当前编译参数是#define NFREQ 4 #define NEXOBS 0这意味着每个频率槽只保留一个码通道没有扩展观测槽。所以如果同一个系统、同一个频率下同时有C5Q和C5X代码不会同时用两个而是根据优先级保留一个。3.C5Q和C5X谁优先由rtkcmn.c里的codepris决定static char codepris[7][MAXFREQ][16]{ /* L1/E1/B1 L2/E5b/B2b L5/E5a/B2a E6/LEX/B3 E5(ab) */ {CPYWMNSLX,CPYWMNDLSX,IQX , , ,}, /* GPS */ {CPABX ,CPABX ,IQX , , ,}, /* GLO */ {CABXZ ,XIQ ,XIQ ,ABCXZ ,IQX ,}, /* GAL */ {CLSXZBE ,LSX ,IQXDPZ ,LSXEZ , ,}, /* QZS */ {C ,IQX , , , ,}, /* SBS */ {IQX ,IQXDPZ ,DPX ,IQXDPZA,DPXSLZAN,DPX}, /* BDS */ {ABCX ,ABCX ,DPX , , ,} /* IRN */ };对5Q / 5X系统L5/E5a/B2a 槽优先级结果GPSIQX5I 5Q 5XGalileoXIQ5X 5I 5QQZSSIQXDPZ5I 5Q 5X 5D 5P 5ZBDSDPX5D 5P 5X5Q默认没有优先级所以对于 GPS如果同一文件里同时有C5Q和C5X默认会选C5QC5X不进入普通频率槽。对于 Galileo如果同时有C5Q和C5X默认会选C5X。4. 相对定位阶段是否区分码通道基本不区分。相对定位阶段按频率索引f处理不检查 rover 和 base 的码通道是否相同。在rtkpos.c - zdres_sat()中残差是这样算的for (i0;inf;i) { if ((freq[i]sat2freq(obs-sat,obs-code[i],nav))0.0) continue; if (obs-L[i]!0.0) y[i ]obs-L[i]*CLIGHT/freq[i]-r-dant[i]; if (obs-P[i]!0.0) y[inf]obs-P[i] -r-dant[i]; }这里i是频率槽例如i0 - L1 i1 - L2 / E5b / B2b i2 - L5 / E5a / B2a i3 - E6 / B3 / L6到了ddres()双差阶段代码只检查该频率槽的残差是否有效if (!validobs(iu[j],ir[j],f,nf,y)) continue;而validobs()只是检查残差非零static int validobs(int i, int j, int f, int nf, double *y) { return y[fi*nf*2]!0.0y[fj*nf*2]!0.0; }它没有检查obs[iu[j]].code[frq] obs[ir[j]].code[frq]也就是说假设某一颗 GPS 卫星rover: C5Q / L5Q base : C5X / L5X当前代码会认为它们都是GPS L5, frequency index 2然后直接参与相对定位双差不会因为Q和X不同而跳过。5. 这实验有什么影响对相对定位来说载波相位和伪距都可能受影响但影响性质不同。伪距C5Q和C5X属于同一载频但码通道不同可能存在不同的码偏差、接收机跟踪偏差、信号组合偏差。当前代码没有单独建模这些码间偏差。所以如果接收机1 使用 C5Q 接收机1 使用 C5X代码会把它们当成同一 L5 伪距来做差分可能引入未建模的码偏差。载波相位载波相位主要依赖载频L5Q和L5X的频率相同所以频率换算没有问题obs-L[i] * CLIGHT / freq[i]但是不同信号通道的相位硬件偏差、初始相位偏差、跟踪特性仍可能不同。当前代码把这些差异吸收到模糊度或残差中没有显式区分Q/X。6. 当前代码的实际处理逻辑可以概括为RINEX 观测类型 C5Q / L5Q / D5Q / S5Q ↓ obs2code() 得到 5Q ↓ code2idx() 根据第一个字符 5 判断为 L5/E5a/B2a ↓ 进入 obs-P[2], obs-L[2], obs-D[2], obs-SNR[2] ↓ 相对定位中按 f2 参与残差和双差 ↓ 不再把 5Q 和 5X 作为两个独立通道处理所以答案是C5X 和 C5Q 在相对定位中会被作为同一频率槽使用。 代码读入时知道它们是不同码通道但相对定位解算时没有把它们作为独立观测类型区分。7. 如果你想严格区分码通道建议怎么改最稳妥的做法是在rtkpos.c的双差阶段增加码通道一致性检查至少保证同一颗卫星在 rover 和 base 上使用相同码通道。原来的函数static int validobs(int i, int j, int f, int nf, double *y) { /* check for valid residuals */ return y[fi*nf*2]!0.0y[fj*nf*2]!0.0; }可以新增一个函数static int validobs_samecode(const obsd_t *obs, int iu, int ir, int f, int nf, double *y) { int frqf%nf; /* first check residual availability */ if (!validobs(iu,ir,f,nf,y)) return 0; /* require valid code indicator */ if (!obs[iu].code[frq] || !obs[ir].code[frq]) return 0; /* require rover/base use the same signal code on this frequency */ return obs[iu].code[frq]obs[ir].code[frq]; }然后把ddres()里类似这种判断if (!validobs(iu[j],ir[j],f,nf,y)) continue;改成if (!validobs_samecode(obs,iu[j],ir[j],f,nf,y)) continue;如果想更严格要求双差四个观测值都来自同一信号码还可以加static int validobs_samecode_dd(const obsd_t *obs, const int *iu, const int *ir, int i, int j, int f, int nf, double *y) { int frqf%nf; uint8_t c; if (!validobs(iu[i],ir[i],f,nf,y)) return 0; if (!validobs(iu[j],ir[j],f,nf,y)) return 0; cobs[iu[i]].code[frq]; if (!c) return 0; return obs[ir[i]].code[frq]c obs[iu[j]].code[frq]c obs[ir[j]].code[frq]c; }在形成双差前加if (!validobs_samecode_dd(obs,iu,ir,i,j,f,nf,y)) continue;这样就可以避免rover 用 C5Qbase 用 C5X但代码仍把它们当成同一 L5 观测这种情况。
RTKLIB中关于不同的码通道
1.C5X和C5Q会不会作为同一个频率使用会。至少对 GPS / Galileo / QZSS 来说5X、5Q都会被映射到同一个 L5/E5a 频率槽。关键代码在src/rtkcmn.cstatic int code2freq_GPS(uint8_t code, double *freq) { const char *obscode2obs(code); switch (obs[0]) { case 1: *freqFREQL1; return 0; /* L1 */ case 2: *freqFREQL2; return 1; /* L2 */ case 5: *freqFREQL5; return 2; /* L5 */ } return -1; }也就是说代码只看obs[0]即C5Q - obs code 5Q - obs[0] 5 - L5 - frequency index 2 C5X - obs code 5X - obs[0] 5 - L5 - frequency index 2所以在频率层面C5Q 和 C5X 都属于第 3 个频率槽 f2即 L5/E5a/B2a 类频率不是按Q、X分开作为两个独立频率。2. 读 RINEX 时是否区分码通道读入阶段是区分的但只用于“选择哪个码通道进入该频率槽”。代码里rinex.c - set_index()会先把每个观测类型转成观测码ind-code[i]obs2code(tobs[i]1); ind-type[i](pstrchr(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;然后对每个频率槽只选一个优先级最高的码for (i0;iNFREQ;i) { for (j0,k-1;jn;j) { if (ind-idx[j]iind-pri[j](k0||ind-pri[j]ind-pri[k])) { kj; } } if (k0) continue; for (j0;jn;j) { if (ind-code[j]ind-code[k]) ind-pos[j]i; } }当前编译参数是#define NFREQ 4 #define NEXOBS 0这意味着每个频率槽只保留一个码通道没有扩展观测槽。所以如果同一个系统、同一个频率下同时有C5Q和C5X代码不会同时用两个而是根据优先级保留一个。3.C5Q和C5X谁优先由rtkcmn.c里的codepris决定static char codepris[7][MAXFREQ][16]{ /* L1/E1/B1 L2/E5b/B2b L5/E5a/B2a E6/LEX/B3 E5(ab) */ {CPYWMNSLX,CPYWMNDLSX,IQX , , ,}, /* GPS */ {CPABX ,CPABX ,IQX , , ,}, /* GLO */ {CABXZ ,XIQ ,XIQ ,ABCXZ ,IQX ,}, /* GAL */ {CLSXZBE ,LSX ,IQXDPZ ,LSXEZ , ,}, /* QZS */ {C ,IQX , , , ,}, /* SBS */ {IQX ,IQXDPZ ,DPX ,IQXDPZA,DPXSLZAN,DPX}, /* BDS */ {ABCX ,ABCX ,DPX , , ,} /* IRN */ };对5Q / 5X系统L5/E5a/B2a 槽优先级结果GPSIQX5I 5Q 5XGalileoXIQ5X 5I 5QQZSSIQXDPZ5I 5Q 5X 5D 5P 5ZBDSDPX5D 5P 5X5Q默认没有优先级所以对于 GPS如果同一文件里同时有C5Q和C5X默认会选C5QC5X不进入普通频率槽。对于 Galileo如果同时有C5Q和C5X默认会选C5X。4. 相对定位阶段是否区分码通道基本不区分。相对定位阶段按频率索引f处理不检查 rover 和 base 的码通道是否相同。在rtkpos.c - zdres_sat()中残差是这样算的for (i0;inf;i) { if ((freq[i]sat2freq(obs-sat,obs-code[i],nav))0.0) continue; if (obs-L[i]!0.0) y[i ]obs-L[i]*CLIGHT/freq[i]-r-dant[i]; if (obs-P[i]!0.0) y[inf]obs-P[i] -r-dant[i]; }这里i是频率槽例如i0 - L1 i1 - L2 / E5b / B2b i2 - L5 / E5a / B2a i3 - E6 / B3 / L6到了ddres()双差阶段代码只检查该频率槽的残差是否有效if (!validobs(iu[j],ir[j],f,nf,y)) continue;而validobs()只是检查残差非零static int validobs(int i, int j, int f, int nf, double *y) { return y[fi*nf*2]!0.0y[fj*nf*2]!0.0; }它没有检查obs[iu[j]].code[frq] obs[ir[j]].code[frq]也就是说假设某一颗 GPS 卫星rover: C5Q / L5Q base : C5X / L5X当前代码会认为它们都是GPS L5, frequency index 2然后直接参与相对定位双差不会因为Q和X不同而跳过。5. 这实验有什么影响对相对定位来说载波相位和伪距都可能受影响但影响性质不同。伪距C5Q和C5X属于同一载频但码通道不同可能存在不同的码偏差、接收机跟踪偏差、信号组合偏差。当前代码没有单独建模这些码间偏差。所以如果接收机1 使用 C5Q 接收机1 使用 C5X代码会把它们当成同一 L5 伪距来做差分可能引入未建模的码偏差。载波相位载波相位主要依赖载频L5Q和L5X的频率相同所以频率换算没有问题obs-L[i] * CLIGHT / freq[i]但是不同信号通道的相位硬件偏差、初始相位偏差、跟踪特性仍可能不同。当前代码把这些差异吸收到模糊度或残差中没有显式区分Q/X。6. 当前代码的实际处理逻辑可以概括为RINEX 观测类型 C5Q / L5Q / D5Q / S5Q ↓ obs2code() 得到 5Q ↓ code2idx() 根据第一个字符 5 判断为 L5/E5a/B2a ↓ 进入 obs-P[2], obs-L[2], obs-D[2], obs-SNR[2] ↓ 相对定位中按 f2 参与残差和双差 ↓ 不再把 5Q 和 5X 作为两个独立通道处理所以答案是C5X 和 C5Q 在相对定位中会被作为同一频率槽使用。 代码读入时知道它们是不同码通道但相对定位解算时没有把它们作为独立观测类型区分。7. 如果你想严格区分码通道建议怎么改最稳妥的做法是在rtkpos.c的双差阶段增加码通道一致性检查至少保证同一颗卫星在 rover 和 base 上使用相同码通道。原来的函数static int validobs(int i, int j, int f, int nf, double *y) { /* check for valid residuals */ return y[fi*nf*2]!0.0y[fj*nf*2]!0.0; }可以新增一个函数static int validobs_samecode(const obsd_t *obs, int iu, int ir, int f, int nf, double *y) { int frqf%nf; /* first check residual availability */ if (!validobs(iu,ir,f,nf,y)) return 0; /* require valid code indicator */ if (!obs[iu].code[frq] || !obs[ir].code[frq]) return 0; /* require rover/base use the same signal code on this frequency */ return obs[iu].code[frq]obs[ir].code[frq]; }然后把ddres()里类似这种判断if (!validobs(iu[j],ir[j],f,nf,y)) continue;改成if (!validobs_samecode(obs,iu[j],ir[j],f,nf,y)) continue;如果想更严格要求双差四个观测值都来自同一信号码还可以加static int validobs_samecode_dd(const obsd_t *obs, const int *iu, const int *ir, int i, int j, int f, int nf, double *y) { int frqf%nf; uint8_t c; if (!validobs(iu[i],ir[i],f,nf,y)) return 0; if (!validobs(iu[j],ir[j],f,nf,y)) return 0; cobs[iu[i]].code[frq]; if (!c) return 0; return obs[ir[i]].code[frq]c obs[iu[j]].code[frq]c obs[ir[j]].code[frq]c; }在形成双差前加if (!validobs_samecode_dd(obs,iu,ir,i,j,f,nf,y)) continue;这样就可以避免rover 用 C5Qbase 用 C5X但代码仍把它们当成同一 L5 观测这种情况。