/*------------------------------------------------------------------------------ * pntpos.c : standard positioning * * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. * * version : $Revision:$ $Date:$ * history : 2010/07/28 1.0 moved from rtkcmn.c * changed api: * pntpos() * deleted api: * pntvel() * 2011/01/12 1.1 add option to include unhealthy satellite * reject duplicated observation data * changed api: ionocorr() * 2011/11/08 1.2 enable snr mask for single-mode (rtklib_2.4.1_p3) * 2012/12/25 1.3 add variable snr mask * 2014/05/26 1.4 support galileo and beidou * 2015/03/19 1.5 fix bug on ionosphere correction for GLO and BDS * 2018/10/10 1.6 support api change of satexclude() * 2020/11/30 1.7 support NavIC/IRNSS in pntpos() * no support IONOOPT_LEX option in ioncorr() * improve handling of TGD correction for each system * use E1-E5b for Galileo dual-freq iono-correction * use API sat2freq() to get carrier frequency * add output of velocity estimation error in estvel() *-----------------------------------------------------------------------------*/ #include #include "rtklib.h" #include "time.h" /* constants/macros ----------------------------------------------------------*/ #define SQR(x) ((x)*(x)) #define MAX(x,y) ((x)>=(y)?(x):(y)) #if 0 /* enable GPS-QZS time offset estimation */ #define NX (4+5) /* # of estimated parameters */ #else #define NX (4+3) /* # of estimated parameters */ #endif #define MAXITR 10 /* max number of iteration for point pos */ #define ERR_ION 5.0 /* ionospheric delay Std (m) */ #define ERR_TROP 3.0 /* tropspheric delay Std (m) */ #define ERR_SAAS 0.3 /* Saastamoinen model error Std (m) */ #define ERR_BRDCI 0.5 /* broadcast ionosphere model error factor */ #define ERR_CBIAS 0.3 /* code bias error Std (m) */ #define REL_HUMI 0.7 /* relative humidity for Saastamoinen model */ #define MIN_EL (5.0*D2R) /* min elevation for measurement error (rad) */ #define STDOPP 0.1 /* doppler measurement standard variance */ /* jacobian of pseudorange measurement by ins attitude error states----------- * args : double *e I line-of-sight vector (ecef) * double *l I lever arm of body frame to gps antenna * double *Cbe I transform matrix of body frame to ecef * double *dpda O jacobian of ins attitude error states * return : none * --------------------------------------------------------------------------*/ static void jacob_dp_da(const double *e,const double *l,const double *Cbe, double *dpda) { double T[9]; matmul("NN",3,1,3,-1.0,Cbe,l,0.0,dpda); skewsym3(dpda,T); matmul("NN",1,3,3,1.0,e,T,0.0,dpda); } /* pseudorange measurement error variance ------------------------------------*/ static double varerr(const prcopt_t *opt, const ssat_t *ssat, const obsd_t *obs, double el, int sys) { double fact=1.0,varr,snr_rover; switch (sys) { case SYS_GPS: fact *= EFACT_GPS; break; case SYS_GLO: fact *= EFACT_GLO; break; case SYS_SBS: fact *= EFACT_SBS; break; case SYS_CMP: fact *= EFACT_CMP; break; case SYS_QZS: fact *= EFACT_QZS; break; case SYS_IRN: fact *= EFACT_IRN; break; default: fact *= EFACT_GPS; break; } if (elerr[1])+SQR(opt->err[2])/sin(el); if (opt->err[6]>0.0) { /* if snr term not zero */ snr_rover=(ssat)?SNR_UNIT*ssat->snr_rover[0]:opt->err[5]; varr+=SQR(opt->err[6])*pow(10,0.1*MAX(opt->err[5]-snr_rover,0)); } varr*=SQR(opt->eratio[0]); if (opt->err[7]>0.0) { varr+=SQR(opt->err[7]*0.01*(1<<(obs->Pstd[0]+5))); /* 0.01*2^(n+5) m */ } if (opt->ionoopt==IONOOPT_IFLC) varr*=SQR(3.0); /* iono-free */ return SQR(fact)*varr; } /* get group delay parameter (m) ---------------------------------------------*/ static double gettgd(int sat, const nav_t *nav, int type) { int i,sys=satsys(sat,NULL); if (sys==SYS_GLO) { for (i=0;ing;i++) { if (nav->geph[i].sat==sat) break; } return (i>=nav->ng)?0.0:-nav->geph[i].dtaun*CLIGHT; } else { for (i=0;in;i++) { if (nav->eph[i].sat==sat) break; } return (i>=nav->n)?0.0:nav->eph[i].tgd[type]*CLIGHT; } } /* test SNR mask -------------------------------------------------------------*/ static int snrmask(const obsd_t *obs, const double *azel, const prcopt_t *opt) { int f2; if (testsnr(0,0,azel[1],obs->SNR[0]*SNR_UNIT,&opt->snrmask)) { return 0; } if (opt->ionoopt==IONOOPT_IFLC) { f2=seliflc(opt->nf,satsys(obs->sat,NULL)); if (testsnr(0,f2,azel[1],obs->SNR[f2]*SNR_UNIT,&opt->snrmask)) return 0; } return 1; } static double prange(const obsd_t *obs, const nav_t *nav, const prcopt_t *opt, double *var) { double P1,P2,gamma,b1,b2; int sat,sys,f2; sat=obs->sat; sys=satsys(sat,NULL); P1=obs->P[0]; f2=seliflc(opt->nf,satsys(obs->sat,NULL)); P2=obs->P[f2]; *var=0.0; if (P1==0.0||(opt->ionoopt==IONOOPT_IFLC&&P2==0.0)) return 0.0; /* P1-C1,P2-C2 DCB correction */ if (sys==SYS_GPS||sys==SYS_GLO) { if (obs->code[0]==CODE_L1C) P1+=nav->cbias[sat-1][1]; /* C1->P1 */ if (obs->code[1]==CODE_L2C) P2+=nav->cbias[sat-1][2]; /* C2->P2 */ } if (opt->ionoopt==IONOOPT_IFLC) { /* dual-frequency */ if (sys==SYS_GPS||sys==SYS_QZS) { /* L1-L2 or L1-L5 */ gamma=f2==1?SQR(FREQL1/FREQL2):SQR(FREQL1/FREQL5); return (P2-gamma*P1)/(1.0-gamma); } else if (sys==SYS_GLO) { /* G1-G2 or G1-G3 */ gamma=f2==1?SQR(FREQ1_GLO/FREQ2_GLO):SQR(FREQ1_GLO/FREQ2_GLO); return (P2-gamma*P1)/(1.0-gamma); } else if (sys==SYS_GAL) { /* E1-E5b, E1-E5a */ gamma=f2==1?SQR(FREQL1/FREQE5b):SQR(FREQL1/FREQL5); if (f2==1&&getseleph(SYS_GAL)) { /* F/NAV */ P2-=gettgd(sat,nav,0)-gettgd(sat,nav,1); /* BGD_E5aE5b */ } return (P2-gamma*P1)/(1.0-gamma); } else if (sys==SYS_CMP) { /* B1-B2 */ gamma=SQR(((obs->code[0]==CODE_L2I)?FREQ1_CMP:FREQL1)/FREQ2_CMP); if (obs->code[0]==CODE_L2I) b1=gettgd(sat,nav,0); /* TGD_B1I */ else if (obs->code[0]==CODE_L1P) b1=gettgd(sat,nav,2); /* TGD_B1Cp */ else b1=gettgd(sat,nav,2)+gettgd(sat,nav,4); /* TGD_B1Cp+ISC_B1Cd */ b2=gettgd(sat,nav,1); /* TGD_B2I/B2bI (m) */ return ((P2-gamma*P1)-(b2-gamma*b1))/(1.0-gamma); } else if (sys==SYS_IRN) { /* L5-S */ gamma=SQR(FREQL5/FREQs); return (P2-gamma*P1)/(1.0-gamma); } } else { /* single-freq (L1/E1/B1) */ *var=SQR(ERR_CBIAS); if (sys==SYS_GPS||sys==SYS_QZS) { /* L1 */ b1=gettgd(sat,nav,0); /* TGD (m) */ return P1-b1; } else if (sys==SYS_GLO) { /* G1 */ gamma=SQR(FREQ1_GLO/FREQ2_GLO); b1=gettgd(sat,nav,0); /* -dtaun (m) */ return P1-b1/(gamma-1.0); } else if (sys==SYS_GAL) { /* E1 */ if (getseleph(SYS_GAL)) b1=gettgd(sat,nav,0); /* BGD_E1E5a */ else b1=gettgd(sat,nav,1); /* BGD_E1E5b */ return P1-b1; } else if (sys==SYS_CMP) { /* B1I/B1Cp/B1Cd */ if (obs->code[0]==CODE_L2I) b1=gettgd(sat,nav,0); /* TGD_B1I */ else if (obs->code[0]==CODE_L1P) b1=gettgd(sat,nav,2); /* TGD_B1Cp */ else b1=gettgd(sat,nav,2)+gettgd(sat,nav,4); /* TGD_B1Cp+ISC_B1Cd */ return P1-b1; } else if (sys==SYS_IRN) { /* L5 */ gamma=SQR(FREQs/FREQL5); b1=gettgd(sat,nav,0); /* TGD (m) */ return P1-gamma*b1; } } return P1; } /* ionospheric correction ------------------------------------------------------ * compute ionospheric correction * args : gtime_t time I time * nav_t *nav I navigation data * int sat I satellite number * double *pos I receiver position {lat,lon,h} (rad|m) * double *azel I azimuth/elevation angle {az,el} (rad) * int ionoopt I ionospheric correction option (IONOOPT_???) * double *ion O ionospheric delay (L1) (m) * double *var O ionospheric delay (L1) variance (m^2) * return : status(1:ok,0:error) *-----------------------------------------------------------------------------*/ extern int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, const double *azel, int ionoopt, double *ion, double *var) { int err=0; trace(4,"ionocorr: time=%s opt=%d sat=%2d pos=%.3f %.3f azel=%.3f %.3f\n", time_str(time,3),ionoopt,sat,pos[0]*R2D,pos[1]*R2D,azel[0]*R2D, azel[1]*R2D); /* SBAS ionosphere model */ if (ionoopt==IONOOPT_SBAS) { if (sbsioncorr(time,nav,pos,azel,ion,var)) return 1; err=1; } /* IONEX TEC model */ if (ionoopt==IONOOPT_TEC) { if (iontec(time,nav,pos,azel,1,ion,var)) return 1; err=1; } /* QZSS broadcast ionosphere model */ if (ionoopt==IONOOPT_QZS&&norm(nav->ion_qzs,8)>0.0) { *ion=ionmodel(time,nav->ion_qzs,pos,azel); *var=SQR(*ion*ERR_BRDCI); return 1; } /* GPS broadcast ionosphere model */ if (ionoopt==IONOOPT_BRDC||err==1) { *ion=ionmodel(time,nav->ion_gps,pos,azel); *var=SQR(*ion*ERR_BRDCI); return 1; } *ion=0.0; *var=ionoopt==IONOOPT_OFF?SQR(ERR_ION):0.0; return 1; } /* tropospheric correction ----------------------------------------------------- * compute tropospheric correction * args : gtime_t time I time * nav_t *nav I navigation data * double *pos I receiver position {lat,lon,h} (rad|m) * double *azel I azimuth/elevation angle {az,el} (rad) * int tropopt I tropospheric correction option (TROPOPT_???) * double *trp O tropospheric delay (m) * double *var O tropospheric delay variance (m^2) * return : status(1:ok,0:error) *-----------------------------------------------------------------------------*/ extern int tropcorr(gtime_t time, const nav_t *nav, const double *pos, const double *azel, int tropopt, double *trp, double *var) { trace(4,"tropcorr: time=%s opt=%d pos=%.3f %.3f azel=%.3f %.3f\n", time_str(time,3),tropopt,pos[0]*R2D,pos[1]*R2D,azel[0]*R2D, azel[1]*R2D); /* Saastamoinen model */ if (tropopt==TROPOPT_SAAS||tropopt==TROPOPT_EST||tropopt==TROPOPT_ESTG) { *trp=tropmodel(time,pos,azel,REL_HUMI); *var=SQR(ERR_SAAS/(sin(azel[1])+0.1)); return 1; } /* SBAS (MOPS) troposphere model */ if (tropopt==TROPOPT_SBAS) { *trp=sbstropcorr(time,pos,azel,var); return 1; } /* no correction */ *trp=0.0; *var=tropopt==TROPOPT_OFF?SQR(ERR_TROP):0.0; return 1; } /* pseudorange residuals -----------------------------------------------------*/ static int rescode(int iter, const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const double *x, const prcopt_t *opt, const ssat_t *ssat, double *v, double *H, double *var, double *azel, int *vsat, double *resp, int *ns) { gtime_t time; double r,freq,dion=0.0,dtrp=0.0,vmeas,vion=0.0,vtrp=0.0,rr[3],pos[3],dtr,e[3],P; int i,j,nv=0,sat,sys,mask[NX-3]={0}; trace(3,"resprng : n=%d\n",n); for (i=0;i<3;i++) rr[i]=x[i]; dtr=x[3]; ecef2pos(rr,pos); for (i=*ns=0;ielmin) continue; if (iter>0) { /* test SNR mask */ if (!snrmask(obs+i,azel+i*2,opt)) continue; /* ionospheric correction */ if (!ionocorr(time,nav,sat,pos,azel+i*2,opt->ionoopt,&dion,&vion)) { continue; } if ((freq=sat2freq(sat,obs[i].code[0],nav))==0.0) continue; dion*=SQR(FREQL1/freq); vion*=SQR(FREQL1/freq); /* tropospheric correction */ if (!tropcorr(time,nav,pos,azel+i*2,opt->tropopt,&dtrp,&vtrp)) { continue; } } /* psendorange with code bias correction */ if ((P=prange(obs+i,nav,opt,&vmeas))==0.0) continue; /* pseudorange residual */ v[nv]=P-(r+dtr-CLIGHT*dts[i*2]+dion+dtrp); /* design matrix */ for (j=0;jnx; /* lever arm */ rmlever(NULL,ins->position,ins->velocity,ins->L_ba_b,ins->Cbe,ins->omgb,rr,vr); /* receiver clock */ for(i=0;i<3;i++) { x[index_GPS + i] = ins->clk[i] + ins->dtrr[i]; x[index_dtrr + i]= ins->dtrr[i]; } ecef2pos(rr,pos); for (i=*ns=0;ielmin) continue; if (iter>0) { /* test SNR mask */ if (!snrmask(obs+i,azel+i*2,opt)) continue; /* ionospheric correction */ if (!ionocorr(time,nav,sat,pos,azel+i*2,opt->ionoopt,&dion,&vion)) { continue; } if ((freq=sat2freq(sat,obs[i].code[0],nav))==0.0) continue; dion*=SQR(FREQL1/freq); vion*=SQR(FREQL1/freq); /* tropospheric correction */ if (!tropcorr(time,nav,pos,azel+i*2,opt->tropopt,&dtrp,&vtrp)) { continue; } } /* psendorange with code bias correction */ if ((P=prange(obs+i,nav,opt,&vmeas))==0.0) continue; /* pseudorange residual */ v[2*nv]=P-(r-CLIGHT*dts[i*2]+dion+dtrp); /* design matrix */ jacob_dp_da(e,ins->L_ba_b,ins->Cbe,dpda); /* position index = 6 */ for(j=6;j<9;j++) H[j+2*nv*nx]=e[j-6]; for (j=0;j<0+3;j++) H[j+2*nv*nx]=dpda[j-0]; /* time system offset and receiver bias correction */ if (sys==SYS_GPS) {v[2*nv]-=x[index_GPS];H[index_GPS+2*nv*nx]=1.0;} else if (sys==SYS_GAL) {v[2*nv]-=x[index_GAL];H[index_GAL+2*nv*nx]=1.0;mask[1]=1;} else if (sys==SYS_CMP) {v[2*nv]-=x[index_BDS];H[index_BDS+2*nv*nx]=1.0;mask[2]=1;} else mask[0]=1; vsat[i]=1; resp[i]=v[2*nv]; (*ns)++; /* doppler residuals */ double rate,vs[3]={0},dopdv[3]={0},dopdp[3]={0},dopda[3]={0},dopbg[3]={0}; /* satellite velocity relative to receiver in ecef */ vs[0]=rs[0+3+i*6]-vr[0]; vs[1]=rs[1+3+i*6]-vr[1]; vs[2]=rs[2+3+i*6]-vr[2]; /* range rate with earth rotation correction */ rate=dot(vs,e,3)+OMGE/CLIGHT*(rs[4+i*6]*rr[0]+rs[1+i*6]*vr[0]- rs[3+i*6]*rr[1]-rs[ i*6]*vr[1]); /* doppler residual */ #ifdef LG69T v[2*nv+1]=(-obs[i].D[0]*CLIGHT/freq-(rate-CLIGHT*dts[1+i*2])); #elif defined(MPU6050) v[2*nv+1]=(obs[i].D[0]*CLIGHT/freq-(rate-CLIGHT*dts[1+i*2])); #endif if(1){ jaco_dop_dp(rs+6*i,rr,rs+3+6*i,vr,dopdp); jaco_dop_da(dopdp,ins->Cbe,ins->L_ba_b,dopdv,ins->omgb,dopda); jaco_dop_dv(e,rs+6*i,dopdv); jaco_dop_bg(dopdv,ins->Cbe,ins->L_ba_b,dopbg); for (j=0;j<0+3;j++) H[j+(2*nv+1)*nx]=dopda[j-0]; for (j=3;j<3+3;j++) H[j+(2*nv+1)*nx]=dopdv[j-3]; for (j=6;j<6+3;j++) H[j+(2*nv+1)*nx]=dopdp[j-6]; H[12+0+(2*nv+1)*nx]=dopbg[0]; H[12+1+(2*nv+1)*nx]=dopbg[1]; H[12+2+(2*nv+1)*nx]=dopbg[2]; if (sys == SYS_GPS) { v[(2*nv+1)] -= x[index_dtrr+0]; H[index_dtrr+0 + (2*nv+1) * nx] = 1.0; } else if (sys == SYS_GAL) { v[(2*nv+1)] -= x[index_dtrr+1]; H[index_dtrr+1 + (2*nv+1) * nx] = 1.0; } else if (sys == SYS_CMP) { v[(2*nv+1)] -= x[index_dtrr+2]; H[index_dtrr+2 + (2*nv+1) * nx] = 1.0; } } /* variance of pseudorange error */ var[2*nv]=varerr(opt,&ssat[i],&obs[i],azel[1+i*2],sys)+vare[i]+vmeas+vion+vtrp; var[2*nv+1]=STDOPP/sin(azel[1]); trace(3,"sat=%2d azel=%5.1f %4.1f res=%7.3f doppler_res=%7.3f sig=%5.3f,sys=%d\n",obs[i].sat, azel[i*2]*R2D,azel[1+i*2]*R2D,resp[i],v[2*nv+1],sqrt(var[2*nv]),sys); nv++; } return nv; } /* validate solution ---------------------------------------------------------*/ static int valsol(const double *azel, const int *vsat, int n, const prcopt_t *opt, const double *v, int nv, int nx, char *msg) { double azels[MAXOBS*2],dop[4],vv; int i,ns; trace(3,"valsol : n=%d nv=%d\n",n,nv); /* Chi-square validation of residuals */ vv=dot(v,v,nv); if (nv>nx&&vv>chisqr[nv-nx-1]) { sprintf(msg,"Warning: large chi-square error nv=%d vv=%.1f cs=%.1f",nv,vv,chisqr[nv-nx-1]); /* return 0; */ /* threshold too strict for all use cases, report error but continue on */ } /* large GDOP check */ for (i=ns=0;ielmin,dop); if (dop[0]<=0.0||dop[0]>opt->maxgdop) { sprintf(msg,"gdop error nv=%d gdop=%.1f",nv,dop[0]); return 0; } return 1; } /* estimate receiver position ------------------------------------------------*/ static int estpos(const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const prcopt_t *opt, const ssat_t *ssat, sol_t *sol, double *azel, int *vsat, double *resp, char *msg) { double x[NX]={0},dx[NX],Q[NX*NX],*v,*H,*var,sig; int i,j,k,info,stat,nv,ns; trace(3,"estpos : n=%d\n",n); v=mat(n+4,1); H=mat(NX,n+4); var=mat(n+4,1); for (i=0;i<3;i++) x[i]=sol->rr[i]; for (i=0;itype=0; sol->time=timeadd(obs[0].time,-x[3]/CLIGHT); sol->dtr[0]=x[3]/CLIGHT; /* receiver clock bias (s) */ sol->dtr[1]=x[4]/CLIGHT; /* GLO-GPS time offset (s) */ sol->dtr[2]=x[5]/CLIGHT; /* GAL-GPS time offset (s) */ sol->dtr[3]=x[6]/CLIGHT; /* BDS-GPS time offset (s) */ sol->dtr[4]=x[7]/CLIGHT; /* IRN-GPS time offset (s) */ for (j=0;j<6;j++) sol->rr[j]=j<3?x[j]:0.0; for (j=0;j<3;j++) sol->qr[j]=(float)Q[j+j*NX]; sol->qr[3]=(float)Q[1]; /* cov xy */ sol->qr[4]=(float)Q[2+NX]; /* cov yz */ sol->qr[5]=(float)Q[2]; /* cov zx */ sol->ns=(uint8_t)ns; sol->age=sol->ratio=0.0; /* validate solution */ if ((stat=valsol(azel,vsat,n,opt,v,nv,NX,msg))) { sol->stat=opt->sateph==EPHOPT_SBAS?SOLQ_SBAS:SOLQ_SINGLE; } free(v); free(H); free(var); return stat; } } if (i>=MAXITR) sprintf(msg,"iteration divergent i=%d",i); free(v); free(H); free(var); return 0; } /* RAIM FDE (failure detection and exclution) -------------------------------*/ static int raim_fde(const obsd_t *obs, int n, const double *rs, const double *dts, const double *vare, const int *svh, const nav_t *nav, const prcopt_t *opt, const ssat_t *ssat, sol_t *sol, double *azel, int *vsat, double *resp, char *msg) { obsd_t *obs_e; sol_t sol_e={{0}}; char tstr[32],name[16],msg_e[128]; double *rs_e,*dts_e,*vare_e,*azel_e,*resp_e,rms_e,rms=100.0; int i,j,k,nvsat,stat=0,*svh_e,*vsat_e,sat=0; trace(3,"raim_fde: %s n=%2d\n",time_str(obs[0].time,0),n); if (!(obs_e=(obsd_t *)malloc(sizeof(obsd_t)*n))) return 0; rs_e = mat(6,n); dts_e = mat(2,n); vare_e=mat(1,n); azel_e=zeros(2,n); svh_e=imat(1,n); vsat_e=imat(1,n); resp_e=mat(1,n); for (i=0;irms) continue; /* save result */ for (j=k=0;jeventime; *sol=sol_e; sat=obs[i].sat; rms=rms_e; vsat[i]=0; strcpy(msg,msg_e); } if (stat) { time2str(obs[0].time,tstr,2); satno2id(sat,name); trace(2,"%s: %s excluded by raim\n",tstr+11,name); } free(obs_e); free(rs_e ); free(dts_e ); free(vare_e); free(azel_e); free(svh_e); free(vsat_e); free(resp_e); return stat; } /* range rate residuals ------------------------------------------------------*/ static int resdop(const obsd_t *obs, int n, const double *rs, const double *dts, const nav_t *nav, const double *rr, const double *x, const double *azel, const int *vsat, double err, double *v, double *H) { double freq,rate,pos[3],E[9],a[3],e[3],vs[3],cosel,sig; int i,j,nv=0; trace(3,"resdop : n=%d\n",n); ecef2pos(rr,pos); xyz2enu(pos,E); for (i=0;ierr[4]; /* Doppler error (Hz) */ int i,j,nv; v=mat(n,1); H=mat(4,n); for (i=0;irr,x,azel,vsat,err,v,H))<4) { break; } /* least square estimation */ if (lsq(H,v,4,nv,dx,Q)) break; for (j=0;j<4;j++) x[j]+=dx[j]; if (norm(dx,4)<1E-6) { trace(3,"estvel : vx=%.3f vy=%.3f vz=%.3f, n=%d\n",x[0],x[1],x[2],n); matcpy(sol->rr+3,x,3,1); /* velocity */ sol->dtrr[0] = x[3]; sol->qv[0]=(float)Q[0]; /* xx */ sol->qv[1]=(float)Q[5]; /* yy */ sol->qv[2]=(float)Q[10]; /* zz */ sol->qv[3]=(float)Q[1]; /* xy */ sol->qv[4]=(float)Q[6]; /* yz */ sol->qv[5]=(float)Q[2]; /* zx */ break; } } free(v); free(H); } /* single-point positioning ---------------------------------------------------- * compute receiver position, velocity, clock bias by single-point positioning * with pseudorange and doppler observables * args : obsd_t *obs I observation data * int n I number of observation data * nav_t *nav I navigation data * prcopt_t *opt I processing options * sol_t *sol IO solution * double *azel IO azimuth/elevation angle (rad) (NULL: no output) * ssat_t *ssat IO satellite status (NULL: no output) * char *msg O error message for error exit * return : status(1:ok,0:error) *-----------------------------------------------------------------------------*/ extern int pntpos(const obsd_t *obs, int n, const nav_t *nav, const prcopt_t *opt, sol_t *sol, double *azel, ssat_t *ssat, char *msg) { prcopt_t opt_=*opt; double *rs,*dts,*var,*azel_,*resp; int i,stat,vsat[MAXOBS]={0},svh[MAXOBS]; trace(3,"pntpos : tobs=%s n=%d\n",time_str(obs[0].time,3),n); sol->stat=SOLQ_NONE; if (n<=0) { strcpy(msg,"no observation data"); return 0; } sol->time=obs[0].time; msg[0]='\0'; sol->eventime = obs[0].eventime; rs=mat(6,n); dts=mat(2,n); var=mat(1,n); azel_=zeros(2,n); resp=mat(1,n); if (ssat) { for (i=0;itime,obs,n,nav,opt_.sateph,rs,dts,var,svh); /* estimate receiver position and time with pseudorange */ stat=estpos(obs,n,rs,dts,var,svh,nav,&opt_,ssat,sol,azel_,vsat,resp,msg); /* RAIM FDE */ if (!stat&&n>=6&&opt->posopt[4]) { stat=raim_fde(obs,n,rs,dts,var,svh,nav,&opt_,ssat,sol,azel_,vsat,resp,msg); } /* estimate receiver velocity with Doppler */ if (stat) { estvel(obs,n,rs,dts,nav,&opt_,sol,azel_,vsat); } if (azel) { for (i=0;iinsopt; double azels[MAXOBS*2],dop[4],fact=SQR(thres); int i,ns,nba=0,iba=0,nbg=0,ibg=0; trace(3,"valins : n=%d nv=%d\n",n,nv); nba=3; iba=9; nbg=3; ibg=12; /* check estimated states */ // if (norm(x,3)>15.0*D2R||(nba?norm(x+iba,3)>1E4*Mg2M:false) // ||(nbg?norm(x+ibg,3)>5.0*D2R:false)) { // /* 输出 状态 */ // trace(2,"%lf,%lf,%lf\n",norm(x,3),norm(x+iba,3),norm(x+ibg,3)); // trace(2,"too large estimated state error\n"); // return 0; // } /* post-fit residual test */ for (i=0;ielmin,dop); // if (dop[0]<=0.0||dop[0]>opt->maxgdop) { // sprintf(msg,"gdop error nv=%d gdop=%.1f",nv,dop[0]); // return 0; // } return 1; } /* outlier ----------------------------------------------------- * args: * double *v IO residual vector * int n I number of states * int m I number of measurement * double *H IO design matirx * double *var IO variance * -----------------------------------------------------------*/ static int outlier(double *v,int n, int m, double *H,double *var) { double mean_psr=0.0,sigma_psr=0.0, mean_dp=0.0,sigma_dp=0.0; for(int i=0;iinsopt; static ins_t inss={0}; trace(3,"estinspr:\n"); nx = ins->nx; n_dtrr = 1; clk_index = 15; ddtr_index = 18; x = zeros(nx,1); R = zeros(2*n,2*n); H = zeros(nx, 2*n); v = zeros(2*n,1); var = mat(2*n,1); /* prefit residuals */ nv = tc_rescode(1,obs,n,rs,dts,vare,svh,nav,x,opt,ssat,ins,v,H,var,azel,vsat, resp,&ns); /* outlier */ nv = outlier(v,nx,nv,H,var); for (int i=0;i<15;i++) { x[i]=1E-20; } /* tightly coupled */ if(nv>=1){ // matcpy(P,ins->P,nx,nx); trace(3,"P=\n"); tracemat(3,Pp,nx,nx,15,10); trace(3,"H=\n"); tracemat(3,H,nx,2*nv,15,6); /* measurement variance */ for (int i=0;iP0,Pp,nx,nx); /* correction for receiver clock */ for (int i=0;i<3;i++) { ins->clk[i]=x[clk_index+i]; ins->dtrr[i]=x[ddtr_index+i]; } /* close loop */ clp(ins,insopt,x); /* postfit residuals */ nv = tc_rescode(1,obs,n,rs,dts,vare,svh,nav,x,opt,ssat,ins,v,H,var,azel,vsat, resp,&ns); /* valid solutions */ if(nv&&(stat=valins(azel,vsat,n,opt,v,nv,x,R,30.0,msg))){ trace(3,"att and vel and pos and acc_bias %lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%.15lf,%.15lf,%.15lf\n",x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11]); trace(3,"clk : %lf,%lf,%lf\n",ins->clk[0],ins->clk[1],ins->clk[2]); trace(3,"dtrr : %lf,%lf,%lf\n",ins->dtrr[0],ins->dtrr[1],ins->dtrr[2]); trace(3,"velocity: %lf,%lf,%lf\n", ins->velocity[0],ins->velocity[1],ins->velocity[2]); double rpy[3]; getatt(ins,rpy); trace(3,"roll=%lf, pitch=%lf, yaw=%lf\n",rpy[0]*R2D,rpy[1]*R2D,rpy[2]*R2D); ins->ns=(unsigned char)ns; stat = 1; sol->stat=opt->sateph==EPHOPT_SBAS?SOLQ_SBAS:SOLQ_SINGLE; ins->gstat=opt->sateph==EPHOPT_SBAS?SOLQ_SBAS:SOLQ_SINGLE; } else { trace(2,"tightly coupled valid solutions fail\n"); stat=0; } } } else { trace(2,"no observation data\n"); stat=0; } free(v); free(H); free(var); free(x); free(R); return stat; } /* update ins states----------------------------------------------------------*/ static void updinsstate(const ins_t *insp,const double *Pp,ins_t *ins) { matcpy(ins->p_position,ins->position,1,3); matcpy(ins->p_velocity,ins->velocity,1,3); /* update ins states if solution is ok */ matcpy(ins->position ,insp->position ,1,3); matcpy(ins->velocity ,insp->velocity ,1,3); matcpy(ins->Cbe,insp->Cbe,3,3); /* no update ba/bg/Ma/Mg */ matcpy(ins->acc_bias,insp->acc_bias,1,3); matcpy(ins->gyro_bias,insp->gyro_bias,1,3); matcpy(ins->P,Pp,ins->nx,ins->nx); for(int i=0;i<3;i++){ ins->clk[i]=insp->clk[i]; ins->dtrr[i]=insp->dtrr[i]; } ins->ns=insp->ns; ins->gstat=insp->gstat; } /* ins estimate states by using pseudorange measurement-----------------------*/ static int est_ins_pr(const obsd_t *obs,int n,const double *rs,const double *dts, const double *vare,const int *svh,const nav_t *nav, const prcopt_t *opt,sol_t *sol, ssat_t *ssat, ins_t *ins, double *azel, int *vsat,double *resp, char *msg) { static ins_t insp={0}; double *Pp; int i,nx=ins->nx,info=1; trace(3,"estinspr: time=%lf n=%d\n",ins->time,n); Pp=mat(ins->nx,ins->nx); insp=*ins; for (i=0;i<1;i++) { matcpy(Pp,ins->P,nx,nx); /* iteration for tightly coupled */ info&=itertc(obs,n,rs,dts,vare,svh,nav,opt,sol,Pp,azel,&insp,vsat,resp,msg,ssat); if (!info) { trace(2,"iteration for tightly coupled fail\n"); break; } } if (info) { // sol->stat=(unsigned char)ins->gstat; updinsstate(&insp,Pp,ins); } free(Pp); return info; } /* single-point positioning/TC coupled ---------------------------------------------------- * compute receiver position, velocity, clock bias by single-point positioning * with pseudorange and doppler observables * args : obsd_t *obs I observation data * int n I number of observation data * nav_t *nav I navigation data * prcopt_t *opt I processing options * sol_t *sol IO solution * ins_t *ins IO ins state * double *azel IO azimuth/elevation angle (rad) (NULL: no output) * ssat_t *ssat IO satellite status (NULL: no output) * char *msg O error message for error exit * return : status(1:ok,0:error) *-----------------------------------------------------------------------------*/ extern int tc_pntpos(const obsd_t *obs, int n, const nav_t *nav, const prcopt_t *opt, sol_t *sol, ins_t *ins,double *azel, ssat_t *ssat, char *msg) { prcopt_t opt_=*opt; double *rs,*dts,*var,*azel_,*resp; int i,stat,stat2,vsat[MAXOBS]={0},svh[MAXOBS]; int tc=0; trace(3,"pntpos : tobs=%s n=%d\n",time_str(obs[0].time,3),n); sol->stat=SOLQ_NONE; tc = opt_.mode==PMODE_INS_TGNSS&&opt_.insopt.tc>=INSTC_SINGLE&&ins; if (n<=0) { strcpy(msg,"no observation data"); return 0; } sol->time=obs[0].time; msg[0]='\0'; sol->eventime = obs[0].eventime; rs=mat(6,n); dts=mat(2,n); var=mat(1,n); azel_=zeros(2,n); resp=mat(1,2*n); if (ssat) { for (i=0;itime,obs,n,nav,opt_.sateph,rs,dts,var,svh); if(tc){ /* tightly coupled */ stat=est_ins_pr(obs,n,rs,dts,var,svh,nav,&opt_, sol,ssat,ins,azel_,vsat,resp,msg); } else{ /* estimate receiver position and time with pseudorange */ stat=estpos(obs,n,rs,dts,var,svh,nav,&opt_,ssat,sol,azel_,vsat,resp,msg); } /* RAIM FDE */ if (!stat&&n>=6&&opt->posopt[4]) { stat=raim_fde(obs,n,rs,dts,var,svh,nav,&opt_,ssat,sol,azel_,vsat,resp,msg); } /* estimate receiver velocity with Doppler */ if (stat&&!tc) { estvel(obs,n,rs,dts,nav,&opt_,sol,azel_,vsat); } if (azel) { for (i=0;i