From 3243afeb6e30852504a8857448b7a1c683c94de9 Mon Sep 17 00:00:00 2001 From: Daniel Burr Date: Fri, 18 Feb 2022 16:20:42 +0100 Subject: [PATCH 1/4] Wide-lane ambiguity fixing for multi-constellation, L1/L2 or L1/L5. Wide lane support is enabled by setting modear to 'wide-lane' (ARMODE_WL). Wide lane AR fix and hold can be enabled using the wlmodear option. Also includes an example configuration file for using rtkrcv with Swift Navigation's Skylark Cloud Correction Service. --- app/consapp/rtkrcv/conf/rtk_skylark_l1l5.conf | 160 +++++++++++ src/options.c | 5 +- src/rtcm3.c | 4 +- src/rtkcmn.c | 13 +- src/rtklib.h | 4 +- src/rtkpos.c | 251 ++++++++++++++++-- 6 files changed, 412 insertions(+), 25 deletions(-) create mode 100644 app/consapp/rtkrcv/conf/rtk_skylark_l1l5.conf diff --git a/app/consapp/rtkrcv/conf/rtk_skylark_l1l5.conf b/app/consapp/rtkrcv/conf/rtk_skylark_l1l5.conf new file mode 100644 index 000000000..23830252f --- /dev/null +++ b/app/consapp/rtkrcv/conf/rtk_skylark_l1l5.conf @@ -0,0 +1,160 @@ +# rtkrcv options (2022/02/09 22:11:36, v.2.4.3 b34) + +console-passwd =admin +console-timetype =gpst # (0:gpst,1:utc,2:jst,3:tow) +console-soltype =dms # (0:dms,1:deg,2:xyz,3:enu,4:pyl) +console-solflag =1 # (0:off,1:std+2:age/ratio/ns) +inpstr1-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http) +inpstr2-type =ntripcli # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http) +inpstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripcli,7:ftp,8:http) +inpstr1-path =username:password@igs-ip.net:2101/STFU00USA0 +# SWIFT: Skylark host may vary depending on geographic region and frequency range +inpstr2-path =username:password@na2.skylark.swiftnav.com:2101/CRS +inpstr3-path = +inpstr1-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17) +inpstr2-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17) +inpstr3-format =rtcm3 # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:javad,9:nvs,10:binex,11:rt17) +inpstr2-nmeareq =single # (0:off,1:latlon,2:single) +inpstr2-nmealat =0 # (deg) +inpstr2-nmealon =0 # (deg) +inpstr2-nmeahgt =0 # (m) +outstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr,11:ntripc_c) +outstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr,11:ntripc_c) +outstr1-path = +outstr2-path = +outstr1-format =xyz # (0:llh,1:xyz,2:enu,3:nmea,4:stat) +outstr2-format =llh # (0:llh,1:xyz,2:enu,3:nmea,4:stat) +logstr1-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr,11:ntripc_c) +logstr2-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr,11:ntripc_c) +logstr3-type =off # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr,11:ntripc_c) +logstr1-path = +logstr2-path = +logstr3-path = +misc-svrcycle =10 # (ms) +misc-timeout =10000 # (ms) +misc-reconnect =10000 # (ms) +misc-nmeacycle =5000 # (ms) +misc-buffsize =32768 # (bytes) +misc-navmsgsel =all # (0:all,1:rover,2:base,3:corr) +misc-proxyaddr = +misc-fswapmargin =30 # (s) +misc-startcmd = +misc-stopcmd = +file-cmdfile1 = +file-cmdfile2 = +file-cmdfile3 = +pos1-posmode =kinematic # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed) +# SWIFT: l1+2 for L1/L2, l1+2+3 for L1/L5 +pos1-frequency =l1+2+3 # (1:l1,2:l1+2,3:l1+2+3,4:l1+2+3+4,5:l1+2+3+4+5) +pos1-soltype =forward # (0:forward,1:backward,2:combined) +pos1-elmask =15 # (deg) +pos1-snrmask_r =off # (0:off,1:on) +pos1-snrmask_b =off # (0:off,1:on) +pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0 +pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0 +pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0 +pos1-dynamics =off # (0:off,1:on) +pos1-tidecorr =off # (0:off,1:on,2:otl) +pos1-ionoopt =brdc # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc) +pos1-tropopt =saas # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad) +pos1-sateph =brdc # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom) +pos1-posopt1 =on # (0:off,1:on) +pos1-posopt2 =on # (0:off,1:on) +pos1-posopt3 =on # (0:off,1:on,2:precise) +pos1-posopt4 =on # (0:off,1:on) +pos1-posopt5 =on # (0:off,1:on) +pos1-posopt6 =off # (0:off,1:on) +pos1-exclsats =C02 # (prn ...) +pos1-navsys =41 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic) +pos2-armode =wide-lane # (0:off,1:continuous,2:instantaneous,3:fix-and-hold,4:WLNL,5:TCAR,6:wide-lane) +# SWIFT: only enable for static positioning mode +pos2-wlarmode =off # (0:off,1:on) +pos2-gloarmode =off # (0:off,1:on) +pos2-bdsarmode =off # (0:off,1:on) +pos2-arthres =3 +pos2-arthres1 =0.9999 +pos2-arthres2 =0.25 +pos2-arthres3 =0.1 +pos2-arthres4 =0.05 +pos2-arlockcnt =30 +pos2-arelmask =0 # (deg) +pos2-arminfix =30 +pos2-armaxiter =1 +pos2-elmaskhold =0 # (deg) +pos2-aroutcnt =30 +pos2-maxage =30 # (s) +pos2-syncsol =off # (0:off,1:on) +pos2-slipthres =0.05 # (m) +pos2-rejionno =30 # (m) +pos2-rejgdop =30 +pos2-niter =1 +pos2-baselen =0 # (m) +pos2-basesig =0 # (m) +out-solformat =xyz # (0:llh,1:xyz,2:enu,3:nmea) +out-outhead =off # (0:off,1:on) +out-outopt =off # (0:off,1:on) +out-outvel =off # (0:off,1:on) +out-timesys =gpst # (0:gpst,1:utc,2:jst) +out-timeform =tow # (0:tow,1:hms) +out-timendec =3 +out-degform =dms # (0:deg,1:dms) +out-fieldsep = +out-outsingle =on # (0:off,1:on) +out-maxsolstd =0 # (m) +out-height =geodetic # (0:ellipsoidal,1:geodetic) +out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) +out-solstatic =all # (0:all,1:single) +out-nmeaintv1 =0 # (s) +out-nmeaintv2 =0 # (s) +out-outstat =state # (0:off,1:state,2:residual) +stats-eratio1 =100 +stats-eratio2 =100 +stats-errphase =0.01 # (m) +stats-errphaseel =0.01 # (m) +stats-errphasebl =0 # (m/10km) +stats-errdoppler =1 # (Hz) +stats-stdbias =30 # (m) +stats-stdiono =0.03 # (m) +stats-stdtrop =0.3 # (m) +stats-prnaccelh =10 # (m/s^2) +stats-prnaccelv =10 # (m/s^2) +stats-prnbias =0.0001 # (m) +stats-prniono =0.001 # (m) +stats-prntrop =0.0001 # (m) +stats-prnpos =0 # (m) +stats-clkstab =5e-12 # (s/s) +ant1-postype =llh # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw,7:rinexdynamic) +ant1-pos1 =90 # (deg|m) +ant1-pos2 =0 # (deg|m) +ant1-pos3 =-6335367.6285 # (m|m) +ant1-anttype = +ant1-antdele =0 # (m) +ant1-antdeln =0 # (m) +ant1-antdelu =0 # (m) +ant2-postype =rtcm # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw,7:rinexdynamic) +ant2-pos1 =0 # (deg|m) +ant2-pos2 =0 # (deg|m) +ant2-pos3 =0 # (m|m) +ant2-anttype = +ant2-antdele =0 # (m) +ant2-antdeln =0 # (m) +ant2-antdelu =0 # (m) +ant2-maxaveep =3600 +ant2-initrst =on # (0:off,1:on) +misc-timeinterp =off # (0:off,1:on) +misc-sbasatsel =0 # (0:all) +misc-rnxopt1 = +misc-rnxopt2 = +misc-pppopt = +file-satantfile = +file-rcvantfile = +file-staposfile = +file-geoidfile = +file-ionofile = +file-dcbfile = +file-eopfile = +file-blqfile = +file-tempdir = +file-geexefile = +file-solstatfile = +file-tracefile = diff --git a/src/options.c b/src/options.c index a64b12e31..dac0bf298 100644 --- a/src/options.c +++ b/src/options.c @@ -58,7 +58,7 @@ static char snrmask_[NFREQ][1024]; #define GEOOPT "0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000" #define STAOPT "0:all,1:single" #define STSOPT "0:off,1:state,2:residual" -#define ARMOPT "0:off,1:continuous,2:instantaneous,3:fix-and-hold" +#define ARMOPT "0:off,1:continuous,2:instantaneous,3:fix-and-hold,4:WLNL,5:TCAR,6:wide-lane" #define POSOPT "0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw" #define TIDEOPT "0:off,1:on,2:otl" #define PHWOPT "0:off,1:on,2:precise" @@ -86,8 +86,9 @@ EXPORT opt_t sysopts[]={ {"pos1-posopt6", 3, (void *)&prcopt_.posopt[5], SWTOPT }, {"pos1-exclsats", 2, (void *)exsats_, "prn ..."}, {"pos1-navsys", 0, (void *)&prcopt_.navsys, NAVOPT }, - + {"pos2-armode", 3, (void *)&prcopt_.modear, ARMOPT }, + {"pos2-wlarmode", 3, (void *)&prcopt_.wlmodear, SWTOPT }, {"pos2-gloarmode", 3, (void *)&prcopt_.glomodear, GAROPT }, {"pos2-bdsarmode", 3, (void *)&prcopt_.bdsmodear, SWTOPT }, {"pos2-arthres", 1, (void *)&prcopt_.thresar[0], "" }, diff --git a/src/rtcm3.c b/src/rtcm3.c index 1aa92989b..252c9b906 100644 --- a/src/rtcm3.c +++ b/src/rtcm3.c @@ -113,7 +113,7 @@ const char *msm_sig_sbs[32]={ const char *msm_sig_cmp[32]={ /* BeiDou: ref [17] table 3.5-108 */ "" ,"2I","2Q","2X","" ,"" ,"" ,"6I","6Q","6X","" ,"" , - "" ,"7I","7Q","7X","" ,"" ,"" ,"" ,"" ,"" ,"" ,"" , + "" ,"7I","7Q","7X","" ,"" ,"" ,"" ,"" ,"5D","5P","5X", "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" }; const char *msm_sig_irn[32]={ @@ -2088,7 +2088,7 @@ static void save_msm_obs(rtcm_t *rtcm, int sys, msm_h_t *h, const double *r, (float)(-(rr[i]+rrf[j])*freq/CLIGHT); } rtcm->obs.data[index].LLI[idx[k]]= - lossoflock(rtcm,sat,idx[k],lock[j])+(half[j]?3:0); + lossoflock(rtcm,sat,idx[k],lock[j])+(half[j]?2:0); rtcm->obs.data[index].SNR [idx[k]]=(uint16_t)(cnr[j]/SNR_UNIT+0.5); rtcm->obs.data[index].code[idx[k]]=code[k]; } diff --git a/src/rtkcmn.c b/src/rtkcmn.c index 9a0acf58c..6c55b76be 100644 --- a/src/rtkcmn.c +++ b/src/rtkcmn.c @@ -204,7 +204,7 @@ const double chisqr[100]={ /* chi-sqr(n) (alpha=0.001) */ const prcopt_t prcopt_default={ /* defaults processing options */ PMODE_SINGLE,0,2,SYS_GPS, /* mode,soltype,nf,navsys */ 15.0*D2R,{{0,0}}, /* elmin,snrmask */ - 0,1,1,1, /* sateph,modear,glomodear,bdsmodear */ + 0,1,0,1,1, /* sateph,modear,wlmodear,glomodear,bdsmodear */ 5,0,10,1, /* maxout,minlock,minfix,armaxiter */ 0,0,0,0, /* estion,esttrop,dynamics,tidecorr */ 1,0,0,0,0, /* niter,codesmooth,intpref,sbascorr,sbassatsel */ @@ -3114,10 +3114,13 @@ extern void traceobs(int level, const obsd_t *obs, int n) for (i=0;i +#include #include "rtklib.h" /* constants/macros ----------------------------------------------------------*/ @@ -1278,7 +1279,7 @@ static int ddidx(rtk_t *rtk, int *ix) /* restore SD (single-differenced) ambiguity ---------------------------------*/ static void restamb(rtk_t *rtk, const double *bias, int nb, double *xa) { - int i,n,m,f,index[MAXSAT],nv=0,nf=NF(&rtk->opt); + int i,n,m,f,index[MAXSAT]={0},index0[MAXSAT]={0},nv=0,nf=NF(&rtk->opt); trace(3,"restamb :\n"); @@ -1291,23 +1292,41 @@ static void restamb(rtk_t *rtk, const double *bias, int nb, double *xa) if (!test_sys(rtk->ssat[i].sys,m)||rtk->ssat[i].fix[f]!=2) { continue; } + if (f==0) { + index0[n]=IB(i+1,0,&rtk->opt); + } index[n++]=IB(i+1,f,&rtk->opt); } if (n<2) continue; - xa[index[0]]=rtk->x[index[0]]; - - for (i=1;iopt.modear==ARMODE_WL) { + for (i=1;i0&&index0[0]!=0&& + index0[i]!=0&& + index[0] !=0&& + index[i] !=0) { + xa[index[i]]=bias[nv++]-(xa[index0[0]]-xa[index0[i]]-xa[index[0]]); + } + } + } + else { + xa[index[0]]=rtk->x[index[0]]; + + for (i=1;inx-rtk->na,nv=0,nf=NF(&rtk->opt); - + int i,n,m,f,info,index[MAXSAT]={0},index0[MAXSAT]={0},nb=rtk->nx-rtk->na; + int nv=0,nf=NF(&rtk->opt); + trace(3,"holdamb :\n"); v=mat(nb,1); H=zeros(nb,rtk->nx); @@ -1319,16 +1338,43 @@ static void holdamb(rtk_t *rtk, const double *xa) rtk->ssat[i].azel[1]opt.elmaskhold) { continue; } + if (f==0) { + index0[n]=IB(i+1,0,&rtk->opt); + } index[n++]=IB(i+1,f,&rtk->opt); rtk->ssat[i].fix[f]=3; /* hold */ } /* constraint to fixed ambiguity */ - for (i=1;ix[index[0]]-rtk->x[index[i]]); - - H[index[0]+nv*rtk->nx]= 1.0; - H[index[i]+nv*rtk->nx]=-1.0; - nv++; + if (rtk->opt.modear==ARMODE_WL) { + for (i=1;i0&&index0[0]!=0&& + index0[i]!=0&& + index[0] !=0&& + index[i] !=0) { + v[nv]=xa[index0[0]]-xa[index0[i]] + -(xa[index[0]]-xa[index[i]]) + -(rtk->x[index0[0]]-rtk->x[index0[i]] + -(rtk->x[index[0]]-rtk->x[index[i]])); + + trace(3,"hold_amb = %lf \n",xa[index0[0]]-xa[index0[i]] + -(xa[index[0]]-xa[index[i]])); + + H[index[0]+nv*rtk->nx]= -1.0; + H[index[i]+nv*rtk->nx]= 1.0; + H[index0[0]+nv*rtk->nx]= 1.0; + H[index0[i]+nv*rtk->nx]=-1.0; + nv++; + } + } + } else { + for (i=1;ix[index[0]]-rtk->x[index[i]]); + + H[index[0]+nv*rtk->nx]= 1.0; + H[index[i]+nv*rtk->nx]=-1.0; + nv++; + } } } if (nv>0) { @@ -1343,6 +1389,174 @@ static void holdamb(rtk_t *rtk, const double *xa) } free(v); free(H); } + +/* single to double-differenced wide-lane transformation matrix (D') ---------*/ +static int dd_wl_mat(rtk_t *rtk, double *D) +{ + int i,j,k,m,f,nb=0,nx=rtk->nx,na=rtk->na,nf=NF(&rtk->opt),nofix; + + trace(3,"dd_wl_mat :\n"); + + for (i=0;issat[i].fix[j]=0; + } + for (i=0;iopt.glomodear==0)||(m==3&&rtk->opt.bdsmodear==0); + if (nofix) { + continue; + } + + k=na; + f=nf==2?1:2; + for (i=k;ix[i]==0.0|| + rtk->x[i+f*MAXSAT]==0.0|| + !test_sys(rtk->ssat[i-k].sys,m)|| + !rtk->ssat[i-k].vsat[0]|| + !rtk->ssat[i-k].half[0]|| + !rtk->ssat[i-k].vsat[f]|| + !rtk->ssat[i-k].half[f]) { + continue; + } + if (rtk->ssat[i-k].lock[0]>0&& + rtk->ssat[i-k].lock[f]>0&& + !(rtk->ssat[i-k].slip[f]&2)&& + !(rtk->ssat[i-k].slip[0]&2)&& + rtk->ssat[i-k].azel[1]>=rtk->opt.elmaskar) { + rtk->ssat[i-k].fix[0]=2; /* fix */ + rtk->ssat[i-k].fix[f]=2; /* fix */ + break; + } + else { + rtk->ssat[i-k].fix[0]=1; + rtk->ssat[i-k].fix[f]=1; + } + } + + for (j=k;jx[j]==0.0|| + rtk->x[j+f*MAXSAT]==0.0|| + !test_sys(rtk->ssat[j-k].sys,m)|| + !rtk->ssat[j-k].vsat[0]|| + !rtk->ssat[j-k].vsat[f]) { + continue; + } + if (rtk->ssat[j-k].lock[0]>0&& + rtk->ssat[j-k].lock[f]>0&& + !(rtk->ssat[j-k].slip[0]&2)&& + !(rtk->ssat[j-k].slip[f]&2)&& + rtk->ssat[j-k].azel[1]>=rtk->opt.elmaskar) { + D[i+(na+nb)*nx]= 1.0; + D[i+f*MAXSAT+(na+nb)*nx]=-1.0; + D[j+(na+nb)*nx]=-1.0; + D[j+f*MAXSAT+(na+nb)*nx]=1.0; + nb++; + rtk->ssat[j-k].fix[f]=2; /* fix */ + rtk->ssat[j-k].fix[0]=2; /* fix */ + } + else { + rtk->ssat[j-k].fix[0]=1; + rtk->ssat[j-k].fix[f]=1; + } + } + } + + trace(4,"Dw=\n"); tracemat(4,D,nx,na+nb,2,0); + return nb; +} + +/* resolve integer ambiguity by LAMBDA ---------------------------------------*/ +static int resamb_WL(rtk_t *rtk, double *bias, double *xa) +{ + prcopt_t *opt=&rtk->opt; + int i,j,ny,nb,info,nx=rtk->nx,na=rtk->na; + double *D,*DP,*y,*Qy,*b,*db,*Qb,*Qab,*QQ,s[2]; + + trace(3,"resamb_WL : nx=%d\n",nx); + + rtk->sol.ratio=0.0; + + if (rtk->opt.modear!=ARMODE_WL||rtk->opt.thresar[0]<1.0||rtk->opt.nf<2) { + return 0; + } + /* single to double-differenced wide-lane transformation matrix (D') */ + D=zeros(nx,nx); + if ((nb=dd_wl_mat(rtk,D))<=0) { + errmsg(rtk,"no valid double, wide-lane difference\n"); + free(D); + return 0; + }; + trace(2,"na = %d, nb = %d\n", na, nb); + ny=na+nb; y=mat(ny,1); Qy=mat(ny,ny); DP=mat(ny,nx); + b=mat(nb,2); db=mat(nb,1); Qb=mat(nb,nb); Qab=mat(na,nb); QQ=mat(na,nb); + + /* transform single to DD wide-lane phase-bias (y=D'*x, Qy=D'*P*D) */ + matmul("TN",ny, 1,nx,1.0,D ,rtk->x,0.0,y ); + matmul("TN",ny,nx,nx,1.0,D ,rtk->P,0.0,DP); + matmul("NN",ny,ny,nx,1.0,DP,D ,0.0,Qy); + + /* phase-bias covariance (Qb) and real-parameters to bias covariance (Qab) */ + for (i=0;ixa); + + /* covariance of fixed solution (Qa=Qa-Qab*Qb^-1*Qab') */ + matmul("NN",na,nb,nb, 1.0,Qab,Qb ,0.0,QQ); + matmul("NT",na,na,nb,-1.0,QQ ,Qab,1.0,rtk->Pa); + + trace(3,"resamb : validation ok (nb=%d ratio=%.2f s=%.2f/%.2f)\n", + nb,s[0]==0.0?0.0:s[1]/s[0],s[0],s[1]); + + /* restore single-differenced ambiguity */ + trace(2,"nb = %d\n",nb); + restamb(rtk,bias,nb,xa); + } + else nb=0; + } + else { /* validation failed */ + errmsg(rtk,"ambiguity validation failed (nb=%d ratio=%.2f s=%.2f/%.2f)\n", + nb,s[1]/s[0],s[0],s[1]); + nb=0; + } + } + else { + errmsg(rtk,"lambda error (info=%d)\n",info); + nb=0; + } + free(D); free(y); free(Qy); free(DP); + free(b); free(db); free(Qb); free(Qab); free(QQ); + + return nb; /* number of ambiguities */ +} /* resolve integer ambiguity by LAMBDA ---------------------------------------*/ static int resamb_LAMBDA(rtk_t *rtk, double *bias, double *xa) { @@ -1567,8 +1781,15 @@ static int relpos(rtk_t *rtk, const obsd_t *obs, int nu, int nr, } else stat=SOLQ_NONE; } + /* resolve integer ambiguity by WL */ + if (stat!=SOLQ_NONE&&rtk->opt.modear==ARMODE_WL) { + if (resamb_WL(rtk,bias,xa)>1) { + if (rtk->opt.wlmodear==1) holdamb(rtk,xa); + stat=SOLQ_FIX; + } + } /* resolve integer ambiguity by LAMBDA */ - if (stat!=SOLQ_NONE&&resamb_LAMBDA(rtk,bias,xa)>1) { + else if (stat!=SOLQ_NONE&&resamb_LAMBDA(rtk,bias,xa)>1) { if (zdres(0,obs,nu,rs,dts,var,svh,nav,xa,opt,0,y,e,azel,freq)) { @@ -1773,7 +1994,7 @@ extern int rtkpos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) /* count rover/base station observations */ for (nu=0;nu sol.time; /* previous epoch */ /* rover position by single point positioning */ From 0123f7dfd94792d2b2367bfc583455fed71fb1ef Mon Sep 17 00:00:00 2001 From: Daniel Burr Date: Fri, 18 Feb 2022 16:30:52 +0100 Subject: [PATCH 2/4] Add new command-line arguments to rnx2rtkp to enable post-processing of wide-lane corrections from Skylark: 1. -w argument enables widelane integer ambiguity resolution 2. -z argument to output SPP position if no RTK solution 3. -rb argument to specify reference position to use for base station. New posopt (POSOPT_RINEX_DYN==6) to read base station position from RINEX header and subsequent site occupation events --- app/consapp/rnx2rtkp/rnx2rtkp.c | 49 ++++++++++++++++++++++----------- src/options.c | 2 +- src/rinex.c | 13 +++++++-- src/rtklib.h | 9 +++++- src/rtkpos.c | 7 +++++ 5 files changed, 59 insertions(+), 21 deletions(-) diff --git a/app/consapp/rnx2rtkp/rnx2rtkp.c b/app/consapp/rnx2rtkp/rnx2rtkp.c index 54fe48a48..c8e30ef02 100644 --- a/app/consapp/rnx2rtkp/rnx2rtkp.c +++ b/app/consapp/rnx2rtkp/rnx2rtkp.c @@ -28,7 +28,7 @@ static const char *help[]={ "", " usage: rnx2rtkp [option]... file file [...]", "", -" Read RINEX OBS/NAV/GNAV/HNAV/CLK, SP3, SBAS message log files and ccompute ", +" Read RINEX OBS/NAV/GNAV/HNAV/CLK, SP3, SBAS message log files and compute ", " receiver (rover) positions and output position solutions.", " The first RINEX OBS file shall contain receiver (rover) observations. For the", " relative mode, the second RINEX OBS file shall contain reference", @@ -57,16 +57,22 @@ static const char *help[]={ " -c forward/backward combined solutions [off]", " -i instantaneous integer ambiguity resolution [off]", " -h fix and hold for integer ambiguity resolution [off]", +" -w widelane integer ambiguity resolution [off]", " -e output x/y/z-ecef position [latitude/longitude/height]", " -a output e/n/u-baseline [latitude/longitude/height]", " -n output NMEA-0183 GGA sentence [off]", " -g output latitude/longitude in the form of ddd mm ss.ss' [ddd.ddd]", " -t output time in the form of yyyy/mm/dd hh:mm:ss.ss [sssss.ss]", " -u output time in utc [gpst]", +" -z output single point position when unable to compute", +" DGPS/float/fix/PPP position", " -d col number of decimals in time [3]", " -s sep field separator [' ']", " -r x y z reference (base) receiver ecef pos (m) [average of single pos]", " rover receiver ecef pos (m) for fixed or ppp-fixed mode", +" -rb mode reference (base) receiver position mode (1:average of single pos,", +" 2:read from file,3:read from RINEX header,6:read from RINEX header", +" and subsequent site occupancy events) [1]", " -l lat lon hgt reference (base) receiver latitude/longitude/height (deg/m)", " rover latitude/longitude/height for fixed or ppp-fixed mode", " -y level output soltion status (0:off,1:states,2:residuals) [0]", @@ -99,16 +105,18 @@ int main(int argc, char **argv) gtime_t ts={0},te={0}; double tint=0.0,es[]={2000,1,1,0,0,0},ee[]={2000,12,31,23,59,59},pos[3]; int i,j,n,ret; - char *infile[MAXFILE],*outfile="",*p; - - prcopt.mode =PMODE_KINEMA; + char *infile[MAXFILE] = {[0 ... (MAXFILE-1)] = ""}; + char *outfile = ""; + char *p = NULL; + + prcopt.mode = PMODE_KINEMA; prcopt.navsys=0; prcopt.refpos=1; prcopt.glomodear=1; solopt.timef=0; sprintf(solopt.prog ,"%s ver.%s %s",PROGNAME,VER_RTKLIB,PATCH_LEVEL); sprintf(filopt.trace,"%s.trace",PROGNAME); - + /* load options from configuration file */ for (i=1;ipos[0]; + data[n].refpos[1]=sta->pos[1]; + data[n].refpos[2]=sta->pos[2]; + } + n++; + } } else if (*flag==3||*flag==4) { /* new site or header info follows */ @@ -1035,7 +1042,7 @@ static int readrnxobs(FILE *fp, gtime_t ts, gtime_t te, double tint, 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); + trace(4,"readrnxobs: rcv=%d ver=%.2f tsys=%d\n",rcv,ver,*tsys); if (!obs||rcv>MAXRCV) return 0; diff --git a/src/rtklib.h b/src/rtklib.h index 38632967c..5b97cd37c 100644 --- a/src/rtklib.h +++ b/src/rtklib.h @@ -425,7 +425,9 @@ extern "C" { #define POSOPT_SINGLE 1 /* pos option: average of single pos */ #define POSOPT_FILE 2 /* pos option: read from pos file */ #define POSOPT_RINEX 3 /* pos option: rinex header pos */ -#define POSOPT_RTCM 4 /* pos option: rtcm/raw station pos */ +#define POSOPT_RTCM 4 /* pos option: rtcm station pos */ +#define POSOPT_RAW 5 /* pos option: raw station pos */ +#define POSOPT_RINEX_DYN 6 /* pos option: rinex site occupation pos */ #define STR_NONE 0 /* stream type: none */ #define STR_SERIAL 1 /* stream type: serial */ @@ -543,6 +545,8 @@ typedef struct { /* observation data record */ 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) */ + /* only used if refpos == POSOPT_RINEX_DYN */ + double refpos[3]; /* station coordinates associated with this observation */ } obsd_t; typedef struct { /* observation data */ @@ -1170,6 +1174,9 @@ typedef struct { /* receiver raw data control type */ char opt[256]; /* receiver dependent options */ int format; /* receiver stream format */ void *rcv_data; /* receiver dependent data */ + + /* only used for STRFMT_SBP and STRFMT_SBPJSON */ + int staid; /* station id */ } raw_t; typedef struct { /* stream type */ diff --git a/src/rtkpos.c b/src/rtkpos.c index b83bf3e48..1e8543a4a 100644 --- a/src/rtkpos.c +++ b/src/rtkpos.c @@ -1994,6 +1994,13 @@ extern int rtkpos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav) /* count rover/base station observations */ for (nu=0;nu refpos==POSOPT_RINEX_DYN&&opt->mode!=PMODE_SINGLE&& + opt->mode!=PMODE_MOVEB) { + if (nr > 0) { + for (i=0;i<6;i++) rtk->rb[i]=i<3?obs[nu].refpos[i]:0.0; + } + } time=rtk->sol.time; /* previous epoch */ From c1f64f15d9bd64a8c1849ba348883465852c2a4f Mon Sep 17 00:00:00 2001 From: Daniel Burr Date: Fri, 18 Feb 2022 16:40:52 +0100 Subject: [PATCH 3/4] New options for RTKPOST: 1. allow Wide Lane Integer Ambiguity Resolution (with optional Fix and Hold) to be selected 2. allow base station positions to be read from RINEX Header and Site Occupation Events --- app/winapp/rtkpost/postmain.cpp | 7 ++++++- app/winapp/rtkpost/postopt.cpp | 21 +++++++++++++++++---- app/winapp/rtkpost/postopt.dfm | 12 +++++++----- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app/winapp/rtkpost/postmain.cpp b/app/winapp/rtkpost/postmain.cpp index ae3653eaa..2143784b6 100644 --- a/app/winapp/rtkpost/postmain.cpp +++ b/app/winapp/rtkpost/postmain.cpp @@ -894,6 +894,11 @@ int __fastcall TMainForm::GetOption(prcopt_t &prcopt, solopt_t &solopt, prcopt.maxgdop =RejectGdop; prcopt.maxinno =RejectThres; prcopt.outsingle=OutputSingle; + prcopt.wlmodear=0; + if (AmbRes>3) { + prcopt.modear=ARMODE_WL; + if(AmbRes==5) prcopt.wlmodear=1; + } if (BaseLineConst) { prcopt.baseline[0]=BaseLine[0]; prcopt.baseline[1]=BaseLine[1]; @@ -916,7 +921,7 @@ int __fastcall TMainForm::GetOption(prcopt_t &prcopt, solopt_t &solopt, else if (RefPosType<=2) { for (int i=0;i<3;i++) prcopt.rb[i]=RefPos[i]; } - else prcopt.refpos=RefPosType-2; + else prcopt.refpos=RefPosType==6?6:RefPosType-2; if (RovAntPcv) { strcpy(prcopt.anttype[0],RovAnt.c_str()); diff --git a/app/winapp/rtkpost/postopt.cpp b/app/winapp/rtkpost/postopt.cpp index 5be742db4..b82404770 100644 --- a/app/winapp/rtkpost/postopt.cpp +++ b/app/winapp/rtkpost/postopt.cpp @@ -632,8 +632,16 @@ void __fastcall TOptDialog::LoadOpt(AnsiString file) PosOpt4 ->Checked =prcopt.posopt[3]; PosOpt5 ->Checked =prcopt.posopt[4]; PosOpt6 ->Checked =prcopt.posopt[5]; - - AmbRes ->ItemIndex =prcopt.modear; + + if(prcopt.modear>ARMODE_FIXHOLD) { + if(prcopt.wlmodear==0) { + AmbRes ->ItemIndex =4; + } else { + AmbRes ->ItemIndex =5; + } + } else { + AmbRes ->ItemIndex =prcopt.modear; + } GloAmbRes ->ItemIndex =prcopt.glomodear; BdsAmbRes ->ItemIndex =prcopt.bdsmodear; ValidThresAR ->Text =s.sprintf("%.3g",prcopt.thresar[0]); @@ -703,7 +711,7 @@ void __fastcall TOptDialog::LoadOpt(AnsiString file) IntpRefObs ->ItemIndex =prcopt.intpref; SbasSat ->Text =s.sprintf("%d",prcopt.sbassatsel); RovPosType ->ItemIndex =prcopt.rovpos==0?0:prcopt.rovpos+2; - RefPosType ->ItemIndex =prcopt.refpos==0?0:prcopt.refpos+2; + RefPosType ->ItemIndex =prcopt.refpos==0?0:prcopt.refpos==POSOPT_RINEX_DYN?6:prcopt.refpos+2; RovPosTypeP =RovPosType->ItemIndex; RefPosTypeP =RefPosType->ItemIndex; SetPos(RovPosType->ItemIndex,editu,prcopt.ru); @@ -779,6 +787,11 @@ void __fastcall TOptDialog::SaveOpt(AnsiString file) // prcopt.mapfunc =MapFunc ->ItemIndex; prcopt.modear =AmbRes ->ItemIndex; + prcopt.wlmodear=0; + if(AmbRes->ItemIndex>3) { + prcopt.modear=ARMODE_WL; + if(AmbRes->ItemIndex==5) prcopt.wlmodear=1; + } prcopt.glomodear=GloAmbRes ->ItemIndex; prcopt.bdsmodear=BdsAmbRes ->ItemIndex; prcopt.thresar[0]=str2dbl(ValidThresAR->Text); @@ -843,7 +856,7 @@ void __fastcall TOptDialog::SaveOpt(AnsiString file) prcopt.intpref =IntpRefObs->ItemIndex; prcopt.sbassatsel=SbasSat->Text.ToInt(); prcopt.rovpos=RovPosType->ItemIndex<3?0:RovPosType->ItemIndex-2; - prcopt.refpos=RefPosType->ItemIndex<3?0:RefPosType->ItemIndex-2; + prcopt.refpos=RefPosType->ItemIndex<3?0:RefPosType->ItemIndex==6?POSOPT_RINEX_DYN:RefPosType->ItemIndex-2; if (prcopt.rovpos==0) GetPos(RovPosType->ItemIndex,editu,prcopt.ru); if (prcopt.refpos==0) GetPos(RefPosType->ItemIndex,editr,prcopt.rb); diff --git a/app/winapp/rtkpost/postopt.dfm b/app/winapp/rtkpost/postopt.dfm index 31e38bdef..0632e5cb5 100644 --- a/app/winapp/rtkpost/postopt.dfm +++ b/app/winapp/rtkpost/postopt.dfm @@ -535,7 +535,8 @@ object OptDialog: TOptDialog 'Continuous' 'Instantaneous' 'Fix and Hold' - 'PPP-AR') + 'Wide Lane' + 'Wide Lane with Fix and Hold') end object ValidThresAR: TEdit Left = 248 @@ -1260,7 +1261,7 @@ object OptDialog: TOptDialog Caption = 'Delta-E/N/U (m)' end object Label24: TLabel - Left = 149 + Left = 231 Top = 17 Width = 31 Height = 13 @@ -1351,7 +1352,7 @@ object OptDialog: TOptDialog object RefPosType: TComboBox Left = 6 Top = 14 - Width = 137 + Width = 219 Height = 21 Style = csDropDownList ItemIndex = 0 @@ -1364,10 +1365,11 @@ object OptDialog: TOptDialog 'X/Y/Z-ECEF (m)' 'Average of Single Position' 'Get from Position File' - 'RINEX Header Postion') + 'RINEX Header Postion' + 'RINEX Header Position and Site Occupation Events') end object DatumRef: TComboBox - Left = 186 + Left = 268 Top = 14 Width = 76 Height = 21 From d0f0c826980b871d0526562b59634208b4c2668e Mon Sep 17 00:00:00 2001 From: ebethon Date: Thu, 17 Mar 2022 23:11:01 -0700 Subject: [PATCH 4/4] Improvements for RTKNAVI (#77) Add support for the following functionality to RTKNAVI: 1. Support for Wide Lane Ambiguity Resolution 2. Support for Wide Lane Ambiguity Resolution with hold and fix 3. Resize Options window for larger AR mode labels (cherry picked from commit c58b38853c5fe7932526228154422636111c5b91) --- app/winapp/rtknavi/navimain.cpp | 2 ++ app/winapp/rtknavi/naviopt.cpp | 31 ++++++++++++++++++++++++++++--- app/winapp/rtknavi/naviopt.dfm | 20 +++++++++++--------- app/winapp/rtknavi/rtknavi.cbproj | 3 +++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/app/winapp/rtknavi/navimain.cpp b/app/winapp/rtknavi/navimain.cpp index 3a5db349f..7bc299b58 100644 --- a/app/winapp/rtknavi/navimain.cpp +++ b/app/winapp/rtknavi/navimain.cpp @@ -2453,6 +2453,7 @@ void __fastcall TMainForm::LoadOpt(void) PrcOpt.dynamics =ini->ReadInteger("prcopt", "dynamics", 0); PrcOpt.tidecorr =ini->ReadInteger("prcopt", "tidecorr", 0); PrcOpt.modear =ini->ReadInteger("prcopt", "modear", 1); + PrcOpt.wlmodear =ini->ReadInteger("prcopt", "wlmodear", 0); PrcOpt.glomodear=ini->ReadInteger("prcopt", "glomodear", 0); PrcOpt.bdsmodear=ini->ReadInteger("prcopt", "bdsmodear", 0); PrcOpt.maxout =ini->ReadInteger("prcopt", "maxout", 5); @@ -2701,6 +2702,7 @@ void __fastcall TMainForm::SaveOpt(void) ini->WriteInteger("prcopt", "dynamics", PrcOpt.dynamics ); ini->WriteInteger("prcopt", "tidecorr", PrcOpt.tidecorr ); ini->WriteInteger("prcopt", "modear", PrcOpt.modear ); + ini->WriteInteger("prcopt", "wlmodear", PrcOpt.wlmodear ); ini->WriteInteger("prcopt", "glomodear", PrcOpt.glomodear ); ini->WriteInteger("prcopt", "bdsmodear", PrcOpt.bdsmodear ); ini->WriteInteger("prcopt", "maxout", PrcOpt.maxout ); diff --git a/app/winapp/rtknavi/naviopt.cpp b/app/winapp/rtknavi/naviopt.cpp index 6151b3fce..839dd1f83 100644 --- a/app/winapp/rtknavi/naviopt.cpp +++ b/app/winapp/rtknavi/naviopt.cpp @@ -405,7 +405,15 @@ void __fastcall TOptDialog::GetOpt(void) IonoOpt ->ItemIndex=PrcOpt.ionoopt; TropOpt ->ItemIndex=PrcOpt.tropopt; SatEphem ->ItemIndex=PrcOpt.sateph; - AmbRes ->ItemIndex=PrcOpt.modear; + if(PrcOpt.modear>ARMODE_FIXHOLD) { + if(PrcOpt.wlmodear==0) { + AmbRes ->ItemIndex =4; + } else { + AmbRes ->ItemIndex =5; + } + } else { + AmbRes ->ItemIndex =PrcOpt.modear; + } GloAmbRes ->ItemIndex=PrcOpt.glomodear; BdsAmbRes ->ItemIndex=PrcOpt.bdsmodear; ValidThresAR ->Text =s.sprintf("%.1f",PrcOpt.thresar[0]); @@ -533,6 +541,11 @@ void __fastcall TOptDialog::SetOpt(void) PrcOpt.tropopt =TropOpt ->ItemIndex; PrcOpt.sateph =SatEphem ->ItemIndex; PrcOpt.modear =AmbRes ->ItemIndex; + PrcOpt.wlmodear=0; + if(AmbRes->ItemIndex>3) { + PrcOpt.modear=ARMODE_WL; + if(AmbRes->ItemIndex==5) PrcOpt.wlmodear=1; + } PrcOpt.glomodear =GloAmbRes ->ItemIndex; PrcOpt.bdsmodear =BdsAmbRes ->ItemIndex; PrcOpt.thresar[0]=str2dbl(ValidThresAR->Text); @@ -720,8 +733,15 @@ void __fastcall TOptDialog::LoadOpt(AnsiString file) PosOpt4 ->Checked =prcopt.posopt[3]; PosOpt5 ->Checked =prcopt.posopt[4]; PosOpt6 ->Checked =prcopt.posopt[5]; - - AmbRes ->ItemIndex =prcopt.modear; + if(prcopt.modear>ARMODE_FIXHOLD) { + if(prcopt.wlmodear==0) { + AmbRes ->ItemIndex =4; + } else { + AmbRes ->ItemIndex =5; + } + } else { + AmbRes ->ItemIndex =prcopt.modear; + } GloAmbRes ->ItemIndex =prcopt.glomodear; BdsAmbRes ->ItemIndex =prcopt.bdsmodear; ValidThresAR ->Text =s.sprintf("%.1f",prcopt.thresar[0]); @@ -937,6 +957,11 @@ void __fastcall TOptDialog::SaveOpt(AnsiString file) prcopt.posopt[5]=PosOpt6->Checked; prcopt.modear =AmbRes ->ItemIndex; + prcopt.wlmodear=0; + if(AmbRes->ItemIndex>3) { + prcopt.modear=ARMODE_WL; + if(AmbRes->ItemIndex==5) prcopt.wlmodear=1; + } prcopt.glomodear=GloAmbRes ->ItemIndex; prcopt.bdsmodear=BdsAmbRes ->ItemIndex; prcopt.thresar[0]=str2dbl(ValidThresAR->Text); diff --git a/app/winapp/rtknavi/naviopt.dfm b/app/winapp/rtknavi/naviopt.dfm index 033f793b5..7f4b469be 100644 --- a/app/winapp/rtknavi/naviopt.dfm +++ b/app/winapp/rtknavi/naviopt.dfm @@ -5,7 +5,7 @@ object OptDialog: TOptDialog BorderStyle = bsDialog Caption = 'Options' ClientHeight = 297 - ClientWidth = 411 + ClientWidth = 491 Color = clWhite Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText @@ -55,7 +55,7 @@ object OptDialog: TOptDialog object Options: TPageControl Left = 0 Top = 0 - Width = 411 + Width = 491 Height = 263 ActivePage = TabSheet1 Align = alTop @@ -481,7 +481,7 @@ object OptDialog: TOptDialog object AmbRes: TComboBox Left = 248 Top = 4 - Width = 61 + Width = 141 Height = 21 Style = csDropDownList ItemIndex = 0 @@ -492,7 +492,9 @@ object OptDialog: TOptDialog 'OFF' 'Continuous' 'Instantaneous' - 'Fix and Hold') + 'Fix and Hold' + 'Wide Lane' + 'Wide Lane with Fix and Hold') end object ValidThresAR: TEdit Left = 248 @@ -559,7 +561,7 @@ object OptDialog: TOptDialog Text = '1' end object GloAmbRes: TComboBox - Left = 311 + Left = 391 Top = 4 Width = 43 Height = 21 @@ -653,7 +655,7 @@ object OptDialog: TOptDialog 'ON') end object BdsAmbRes: TComboBox - Left = 356 + Left = 436 Top = 4 Width = 43 Height = 21 @@ -1832,7 +1834,7 @@ object OptDialog: TOptDialog ExplicitWidth = 0 ExplicitHeight = 0 DesignSize = ( - 403 + 483 235) object Label19: TLabel Left = 32 @@ -1849,7 +1851,7 @@ object OptDialog: TOptDialog Caption = 'Solution Font' end object FontLabel2: TLabel - Left = 265 + Left = 345 Top = 188 Width = 80 Height = 18 @@ -1921,7 +1923,7 @@ object OptDialog: TOptDialog Caption = 'Panel Font' end object FontLabel1: TLabel - Left = 265 + Left = 345 Top = 164 Width = 80 Height = 18 diff --git a/app/winapp/rtknavi/rtknavi.cbproj b/app/winapp/rtknavi/rtknavi.cbproj index 5fc42983c..d8d2fffda 100644 --- a/app/winapp/rtknavi/rtknavi.cbproj +++ b/app/winapp/rtknavi/rtknavi.cbproj @@ -403,6 +403,9 @@ 31 2 + + 59 + 48 15