1302 lines
46 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*------------------------------------------------------------------------------
* 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 <stdbool.h>
#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 (el<MIN_EL) el=MIN_EL;
/* var = R^2*(a^2 + (b^2/sin(el) + c^2*(10^(0.1*(snr_max-snr_rover)))) + (d*rcv_std)^2) */
varr=SQR(opt->err[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;i<nav->ng;i++) {
if (nav->geph[i].sat==sat) break;
}
return (i>=nav->ng)?0.0:-nav->geph[i].dtaun*CLIGHT;
}
else {
for (i=0;i<nav->n;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;i<n&&i<MAXOBS;i++) {
vsat[i]=0; azel[i*2]=azel[1+i*2]=resp[i]=0.0;
time=obs[i].time;
sat=obs[i].sat;
if (!(sys=satsys(sat,NULL))) continue;
/* reject duplicated observation data */
if (i<n-1&&i<MAXOBS-1&&sat==obs[i+1].sat) {
trace(2,"duplicated obs data %s sat=%d\n",time_str(time,3),sat);
i++;
continue;
}
/* excluded satellite? */
if (satexclude(sat,vare[i],svh[i],opt)) continue;
/* geometric distance and elevation mask*/
if ((r=geodist(rs+i*6,rr,e))<=0.0) continue;
if (satazel(pos,e,azel+i*2)<opt->elmin) 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;j<NX;j++) {
H[j+nv*NX]=j<3?-e[j]:(j==3?1.0:0.0);
}
/* time system offset and receiver bias correction */
if (sys==SYS_GLO) {v[nv]-=x[4]; H[4+nv*NX]=1.0; mask[1]=1;}
else if (sys==SYS_GAL) {v[nv]-=x[5]; H[5+nv*NX]=1.0; mask[2]=1;}
else if (sys==SYS_CMP) {v[nv]-=x[6]; H[6+nv*NX]=1.0; mask[3]=1;}
else if (sys==SYS_IRN) {v[nv]-=x[7]; H[7+nv*NX]=1.0; mask[4]=1;}
#if 0 /* enable QZS-GPS time offset estimation */
else if (sys==SYS_QZS) {v[nv]-=x[8]; H[8+nv*NX]=1.0; mask[5]=1;}
#endif
else mask[0]=1;
vsat[i]=1; resp[i]=v[nv]; (*ns)++;
/* variance of pseudorange error */
var[nv++]=varerr(opt,&ssat[i],&obs[i],azel[1+i*2],sys)+vare[i]+vmeas+vion+vtrp;
trace(4,"sat=%2d azel=%5.1f %4.1f res=%7.3f sig=%5.3f\n",obs[i].sat,
azel[i*2]*R2D,azel[1+i*2]*R2D,resp[i],sqrt(var[nv-1]));
}
/* constraint to avoid rank-deficient */
for (i=0;i<NX-3;i++) {
if (mask[i]) continue;
v[nv]=0.0;
for (j=0;j<NX;j++) H[j+nv*NX]=j==i+3?1.0:0.0;
var[nv++]=0.01;
}
return nv;
}
/* jacobian of doppler measurement by ins velocity---------------------------*/
static void jaco_dop_dv(const double *e,const double *rs,double *dopdv)
{
dopdv[0]=e[0]-OMGE/CLIGHT*rs[1];
dopdv[1]=e[1]+OMGE/CLIGHT*rs[0];
dopdv[2]=e[2];
}
/* jacobian of doppler measurement by attitude error-------------------------
* args : double *dr I jacobian matrix of ins position
* double *Cbe I transform matrix from b-frame to ecef
* double *l I lever arm of b-frame to antenna position
* double *dopdv I jacobian matrix of velocity
* double *gyro I gyro measurement data
* double *dopda O output jacobian matrix
* return : none
* --------------------------------------------------------------------------*/
static void jaco_dop_da(const double *dr,const double *Cbe,const double *l,
const double *dopdv,const double *gyro,double *dopda)
{
int i;
double T[9],sl[3],S[9];
/* partial matrix by ins position */
matmul("NN",3,1,3,-1.0,Cbe,l,0.0,dopda);
skewsym3(dopda,T);
matmul("NN",1,3,3,1.0,dr,T,0.0,dopda);
/* partial matrix by ins velocity */
skewsym3(gyro,T);
matmul33("NNN",Cbe,T,l,3,3,3,1,sl);
skewsym3(sl,T);
matmul("NN",1,3,3,1.0,dopdv,T,0.0,S);
for (i=0;i<3;i++) dopda[i]-=S[i];
matmul("NN",3,1,3,1.0,Cbe,l,0.0,sl);
skewsym3(sl,T);
matmul("NN",3,3,3,1.0,Omge,T,0.0,S);
matmul("NN",1,3,3,1.0,dopdv,S,0.0,T);
for (i=0;i<3;i++) dopda[i]+=T[i];
}
/* jacobian of doppler measurement by ins position---------------------------
* args : double *rs I satellite position
* double *rr I receiver position
* double *vs I satellite velocity
* double *dopdp O output jacobian matrix
* return : none
* --------------------------------------------------------------------------*/
static void jaco_dop_dp(const double *rs,const double *rr,const double *vs,
const double *vr,double *dopdp)
{
int i;
double dv[3],dp[3],pr,t;
for (i=0;i<3;i++) dp[i]=rs[i]-rr[i]; pr=norm(dp,3);
for (i=0;i<3;i++) dv[i]=vs[i]-vr[i];
t=pow(SQR(pr),1.5);
dopdp[0]=2.0*dv[2]*dp[2]*dp[0]/(2.0*t)-dv[0]/pr+2.0*dv[0]*dp[0]*dp[0]/(2.0*t)+
2.0*dv[1]*dp[1]*dp[0]/(2.0*t)+OMGE/CLIGHT*vs[1];
dopdp[1]=2.0*dv[1]*dp[1]*dp[0]/(2.0*t)-dv[1]/pr+2.0*dv[2]*dp[2]*dp[1]/(2.0*t)+
2.0*dv[0]*dp[0]*dp[1]/(2.0*t)-OMGE/CLIGHT*vs[0];
dopdp[2]=2.0*dv[0]*dp[0]*dp[2]/(2.0*t)-dv[1]/pr+2.0*dv[1]*dp[1]*dp[2]/(2.0*t)+
2.0*dv[2]*dp[2]*dp[2]/(2.0*t);
for (i=0;i<3;i++) dopdp[i]=-dopdp[i];
}
/* jacobian of doppler measurement by gyro bias------------------------------*/
static void jaco_dop_bg(const double *dopdv,const double *Cbe,const double *l,
double *dopbg)
{
double T[9],S[9];
skewsym3(l,T);
matmul("NN",3,3,3,-1.0,Cbe,T,0.0,S);
matmul("NN",1,3,3, 1.0,dopdv,S,0.0,dopbg);
}
/* pseudorange and doppler residuals -----------------------------------------------------*/
static int tc_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, double *x, const prcopt_t *opt,
const ssat_t *ssat,
const ins_t *ins,
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],vr[3],pos[3],e[3],P;
int i,j,nv=0,sat,sys,mask[3]={0};
int nx,index_GPS,index_GLO,index_GAL,index_BDS,index_IRN,index_dtrr;
double dpda[3];
trace(3,"rescode: n=%d\n");
/* receiver clock state index */
index_GPS = 15;/* receiver clock state index */
index_GAL=index_GPS+1;
index_BDS=index_GPS+2;
index_dtrr = 18;
nx = ins->nx;
/* 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;i<n&&i<MAXOBS;i++) {
vsat[i]=0;
azel[i*2]=azel[1+i*2]=resp[i]=0.0;
time=obs[i].time;
sat=obs[i].sat;
if (!(sys=satsys(sat,NULL))) continue;
/* reject duplicated observation data */
if (i<n-1&&i<MAXOBS-1&&sat==obs[i+1].sat) {
trace(2,"duplicated obs data %s sat=%d\n",time_str(time,3),sat);
i++;
continue;
}
/* excluded satellite? */
if (satexclude(sat,vare[i],svh[i],opt)) continue;
/* geometric distance and elevation mask */
if ((r=geodist(rs+i*6,rr,e))<=0.0||satazel(pos,e,azel+i*2)<opt->elmin) 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.3fsys=%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;i<n;i++) {
if (!vsat[i]) continue;
azels[ ns*2]=azel[ i*2];
azels[1+ns*2]=azel[1+i*2];
ns++;
}
dops(ns,azels,opt->elmin,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;i<MAXITR;i++) {
/* pseudorange residuals (m) */
nv=rescode(i,obs,n,rs,dts,vare,svh,nav,x,opt,ssat,v,H,var,azel,vsat,resp,
&ns);
if (nv<NX) {
sprintf(msg,"lack of valid sats ns=%d",nv);
break;
}
/* weight by variance (lsq uses sqrt of weight */
for (j=0;j<nv;j++) {
sig=sqrt(var[j]);
v[j]/=sig;
for (k=0;k<NX;k++) H[k+j*NX]/=sig;
}
/* least square estimation */
if ((info=lsq(H,v,NX,nv,dx,Q))) {
sprintf(msg,"lsq error info=%d",info);
break;
}
for (j=0;j<NX;j++) {
x[j]+=dx[j];
}
if (norm(dx,NX)<1E-4) {
sol->type=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;i<n;i++) {
/* satellite exclusion */
for (j=k=0;j<n;j++) {
if (j==i) continue;
obs_e[k]=obs[j];
matcpy(rs_e +6*k,rs +6*j,6,1);
matcpy(dts_e+2*k,dts+2*j,2,1);
vare_e[k]=vare[j];
svh_e[k++]=svh[j];
}
/* estimate receiver position without a satellite */
if (!estpos(obs_e,n-1,rs_e,dts_e,vare_e,svh_e,nav,opt,ssat,&sol_e,azel_e,
vsat_e,resp_e,msg_e)) {
trace(3,"raim_fde: exsat=%2d (%s)\n",obs[i].sat,msg);
continue;
}
for (j=nvsat=0,rms_e=0.0;j<n-1;j++) {
if (!vsat_e[j]) continue;
rms_e+=SQR(resp_e[j]);
nvsat++;
}
if (nvsat<5) {
trace(3,"raim_fde: exsat=%2d lack of satellites nvsat=%2d\n",
obs[i].sat,nvsat);
continue;
}
rms_e=sqrt(rms_e/nvsat);
trace(3,"raim_fde: exsat=%2d rms=%8.3f\n",obs[i].sat,rms_e);
if (rms_e>rms) continue;
/* save result */
for (j=k=0;j<n;j++) {
if (j==i) continue;
matcpy(azel+2*j,azel_e+2*k,2,1);
vsat[j]=vsat_e[k];
resp[j]=resp_e[k++];
}
stat=1;
sol_e.eventime = sol->eventime;
*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;i<n&&i<MAXOBS;i++) {
freq=sat2freq(obs[i].sat,obs[i].code[0],nav);
if (obs[i].D[0]==0.0||freq==0.0||!vsat[i]||norm(rs+3+i*6,3)<=0.0) {
continue;
}
/* LOS (line-of-sight) vector in ECEF */
cosel=cos(azel[1+i*2]);
a[0]=sin(azel[i*2])*cosel;
a[1]=cos(azel[i*2])*cosel;
a[2]=sin(azel[1+i*2]);
matmul("TN",3,1,3,1.0,E,a,0.0,e);
/* satellite velocity relative to receiver in ECEF */
for (j=0;j<3;j++) {
vs[j]=rs[j+3+i*6]-x[j];
}
/* range rate with earth rotation correction */
rate=dot(vs,e,3)+OMGE/CLIGHT*(rs[4+i*6]*rr[0]+rs[1+i*6]*x[0]-
rs[3+i*6]*rr[1]-rs[ i*6]*x[1]);
/* Std of range rate error (m/s) */
sig=(err<=0.0)?1.0:err*CLIGHT/freq;
/* range rate residual (m/s) */
v[nv]=(obs[i].D[0]*CLIGHT/freq-(rate+x[3]-CLIGHT*dts[1+i*2]))/sig;
/* design matrix */
for (j=0;j<4;j++) {
H[j+nv*4]=((j<3)?-e[j]:1.0)/sig;
}
nv++;
}
return nv;
}
/* estimate receiver velocity ------------------------------------------------*/
static void estvel(const obsd_t *obs, int n, const double *rs, const double *dts,
const nav_t *nav, const prcopt_t *opt, sol_t *sol,
const double *azel, const int *vsat)
{
double x[4]={0},dx[4],Q[16],*v,*H;
double err=opt->err[4]; /* Doppler error (Hz) */
int i,j,nv;
v=mat(n,1);
H=mat(4,n);
for (i=0;i<MAXITR;i++) {
/* range rate residuals (m/s) */
if ((nv=resdop(obs,n,rs,dts,nav,sol->rr,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;i<MAXSAT;i++) {
ssat[i].snr_rover[0]=0;
ssat[i].snr_base[0]=0;
}
for (i=0;i<n;i++)
ssat[obs[i].sat-1].snr_rover[0]=obs[i].SNR[0];
}
if (opt_.mode!=PMODE_SINGLE) { /* for precise positioning */
opt_.ionoopt=IONOOPT_BRDC;
opt_.tropopt=TROPOPT_SAAS;
}
/* satellite positons, velocities and clocks */
satposs(sol->time,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;i<n*2;i++) azel[i]=azel_[i];
}
if (ssat) {
for (i=0;i<MAXSAT;i++) {
ssat[i].vs=0;
ssat[i].azel[0]=ssat[i].azel[1]=0.0;
ssat[i].resp[0]=ssat[i].resc[0]=0.0;
}
for (i=0;i<n;i++) {
ssat[obs[i].sat-1].azel[0]=azel_[ i*2];
ssat[obs[i].sat-1].azel[1]=azel_[1+i*2];
if (!vsat[i]) continue;
ssat[obs[i].sat-1].vs=1;
ssat[obs[i].sat-1].resp[0]=resp[i];
}
}
free(rs); free(dts); free(var); free(azel_); free(resp);
return stat;
}
/* validate solution for ins filter-------------------------------------------*/
static int valins(const double *azel, const int *vsat, int n,const prcopt_t *opt,
const double *v, int nv,const double *x,const double *R,
double thres,char *msg)
{
const insopt_t *insopt=&opt->insopt;
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;i<nv;i++) {
if (v[2*i]*v[2*i]<fact*R[2*i+2*i*2*nv]) continue;
trace(2,"large residual (v=%6.3f sig=%.3f)\n",v[i],SQRT(R[2*i+2*i*2*nv]));
return 0;
}
/* large gdop check */
// for (i=ns=0;i<n;i++) {
// if (!vsat[i]) continue;
// azels[ ns*2]=azel[ i*2];
// azels[1+ns*2]=azel[1+i*2];
// ns++;
// }
// dops(ns,azels,opt->elmin,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;i<m;i++) {
mean_psr+=v[2*i];
mean_dp+=v[2*i+1];
}
mean_psr/=m;
mean_dp/=m;
for(int i=0;i<m;i++) {
sigma_psr+=(v[2*i]-mean_psr)*(v[2*i]-mean_psr);
sigma_dp+=(v[2*i+1]-mean_dp)*(v[2*i+1]-mean_dp);
}
sigma_psr/=m;
sigma_dp/=m;
int k=0;
for(int i=0;i<m;i++) {
if((v[2*i]-mean_psr)<sqrt(sigma_psr)*3) {
v[2*k]=v[2*i];
v[2*k+1]=v[2*i+1];
for(int j=0;j<n;j++) {
H[j+2*k*n]=H[j+2*i*n];
H[j+(2*k+1)*n]=H[j+(2*i+1)*n];
var[2*k]=var[2*i];
var[2*k+1]=var[2*i+1];
}
k++;
}
}
return k;
}
/* iteration for tightly coupled ---------------------------------------------*/
static int itertc(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,double *Pp,double *azel,ins_t *ins,
int *vsat,double *resp, char *msg,ssat_t *ssat)
{
int nx,nv,ns,n_dtrr,stat=0,clk_index,ddtr_index;
double *x,*R,*v,*H,*var;
const insopt_t *insopt=&opt->insopt;
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;i<nv;i++) {
// R[2*i+2*i*2*nv]= sqrt(var[2*i]);
// R[(2*i+1)+(2*i+1)*2*nv]= SQR(var[(2*i+1)]);
R[2*i+2*i*2*nv]=1.0;
R[(2*i+1)+(2*i+1)*2*nv]=0.01;
}
trace(3,"R=\n");
tracemat(3,R,2*nv,2*nv,15,6);
/* ekf filter */
stat=robust_filter(x,Pp,H,v,R,nx,2*nv);
if(stat){
trace(3,"ekf filter error info=%d\n",stat);
stat=0;
}
else{
// matcpy(ins->P0,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;i<MAXSAT;i++) {
ssat[i].snr_rover[0]=0;
ssat[i].snr_base[0]=0;
}
for (i=0;i<n;i++){
ssat[obs[i].sat-1].snr_rover[0]=obs[i].SNR[0];
}
}
if (opt_.mode!=PMODE_SINGLE) { /* for precise positioning */
opt_.ionoopt=IONOOPT_BRDC;
opt_.tropopt=TROPOPT_SAAS;
}
/* satellite positons, velocities and clocks */
satposs(sol->time,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<n*2;i++) azel[i]=azel_[i];
}
if (ssat) {
for (i=0;i<MAXSAT;i++) {
ssat[i].vs=0;
ssat[i].azel[0]=ssat[i].azel[1]=0.0;
ssat[i].resp[0]=ssat[i].resc[0]=0.0;
}
for (i=0;i<n;i++) {
ssat[obs[i].sat-1].azel[0]=azel_[ i*2];
ssat[obs[i].sat-1].azel[1]=azel_[1+i*2];
if (!vsat[i]) continue;
ssat[obs[i].sat-1].vs=1;
ssat[obs[i].sat-1].resp[0]=resp[i];
}
}
free(rs); free(dts); free(var); free(azel_); free(resp);
return stat;
}