RTKLib源码--整体框架

源码解读,自己总结,自己看看

1 代码整体框架

1.1 RTK算法结构体

1.1.1 rtklib.h 头文件

该头文件定义了所使用到的常量、结构体、函数声明等,在其他源代码中均有使用

rnx2rtkp.c等有使用

关于PI的定义,弧度转化等

结构体的定义

函数声明

1.1.2 gtime_t  结构体  时间结构

typedef struct {       
    time_t time;        /*(秒)有符号 64 位整数数据类型*/
    double sec;         /* 时间的(秒)小数部分*/
} gtime_t;  

1.1.3 obsd_t  

用来存储某个历元中的某个卫星的观测值

typedef struct {        
    gtime_t time;       /* 接收机所用时间 */
    unsigned char sat,rcv; 
    unsigned char SNR [NFREQ+NEXOBS]; /* 信噪比,信号强度*/
    unsigned char LLI [NFREQ+NEXOBS]; /* loss of lock indicator */
    unsigned char code[NFREQ+NEXOBS]; /* code indicator (CODE_???) 卫星编码*/
    double L[NFREQ+NEXOBS]; /* observation data carrier-phase (cycle)  载波*/
    double P[NFREQ+NEXOBS]; /* observation data pseudorange (m) 伪距*/
    float  D[NFREQ+NEXOBS]; /* observation data doppler frequency (Hz) 多普勒*/
} obsd_t;

CODE 卫星编码,rtklib将GPS/GLONASS/BDS等卫星统一进行的编码

1.1.4 obs_t 结构体

该结构体存储的是所有的观测值数据。与上面的"obsd_t"呼应

typedef struct {       
    int n,nmax;         /* number of obervation data/allocated */
    obsd_t *data;       /* observation data records */
} obs_t;

n代表实际存储的观测值结构体的个数,nmax代表的是最多存储多少个观测值结构体,如果超过最大个数,需要重新开辟内存空间。

1.1.5  nav_t 星历数据结构体

存全部的星历数据,历书数据、精密星历、TEC格网、广播星历电离层参数、DGPS、SSR改正等信息

typedef struct {        /* navigation data type */
    int n,nmax;         /* number of broadcast ephemeris */
    int ng,ngmax;       /* number of glonass ephemeris */
    int ns,nsmax;       /* number of sbas ephemeris */
    int ne,nemax;       /* number of precise ephemeris */
    int nc,ncmax;       /* number of precise clock */
    int na,namax;       /* number of almanac data */
    int nt,ntmax;       /* number of tec grid data */
    int nn,nnmax;       /* number of stec grid data */
    eph_t *eph;         /* GPS/QZS/GAL ephemeris */
    geph_t *geph;       /* GLONASS ephemeris */
    seph_t *seph;       /* SBAS ephemeris */
    peph_t *peph;       /* precise ephemeris */
    pclk_t *pclk;       /* precise clock */
    alm_t *alm;         /* almanac data */
    tec_t *tec;         /* tec grid data */
    stec_t *stec;       /* stec grid data */
    erp_t  erp;         /* earth rotation parameters */
    double utc_gps[4];  /* GPS delta-UTC parameters {A0,A1,T,W} */
    double utc_glo[4];  /* GLONASS UTC GPS time parameters */
    double utc_gal[4];  /* Galileo UTC GPS time parameters */
    double utc_qzs[4];  /* QZS UTC GPS time parameters */
    double utc_cmp[4];  /* BeiDou UTC parameters */
    double utc_sbs[4];  /* SBAS UTC parameters */
    double ion_gps[8];  /* GPS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
    double ion_gal[4];  /* Galileo iono model parameters {ai0,ai1,ai2,0} */
    double ion_qzs[8];  /* QZSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
    double ion_cmp[8];  /* BeiDou iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */
    int leaps;          /* leap seconds (s) */
    double lam[MAXSAT][NFREQ]; /* carrier wave lengths (m) */
    double cbias[MAXSAT][3];   /* code bias (0:p1-p2,1:p1-c1,2:p2-c2) (m) */
    double wlbias[MAXSAT];     /* wide-lane bias (cycle) */
    double glo_cpbias[4];    /* glonass code-phase bias {1C,1P,2C,2P} (m) */
    char glo_fcn[MAXPRNGLO+1]; /* glonass frequency channel number + 8 */
    pcv_t pcvs[MAXSAT]; /* satellite antenna pcv */
    sbssat_t sbssat;    /* SBAS satellite corrections */
    sbsion_t sbsion[MAXBAND+1]; /* SBAS ionosphere corrections */
    dgps_t dgps[MAXSAT]; /* DGPS corrections */
    ssr_t ssr[MAXSAT];  /* SSR corrections */
    lexeph_t lexeph[MAXSAT]; /* LEX ephemeris */
    lexion_t lexion;    /* LEX ionosphere correction */
} nav_t;//所有星历总的结构体

1.1.6 sol_t:结果结构体

定位/解算结果的参数

typedef struct {        
    gtime_t time;       //GPST时间
    double rr[6];       /* 位置、速度结果 (m|m/s) */
                        /* {x,y,z,vx,vy,vz} or {e,n,u,ve,vn,vu} */
    float  qr[6];       /* 位置估计协方差阵 (m^2) */
                        /* {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} or */
                        /* {c_ee,c_nn,c_uu,c_en,c_nu,c_ue} */
    float  qv[6];       /* 速度估计协方差阵 (m^2/s^2) */
    double dtr[6];      /* receiver clock bias to time systems (s) */
    uint8_t type;       /* type (0:xyz-ecef,1:enu-baseline) */
    uint8_t stat;       /* solution status (SOLQ_???) */
    uint8_t ns;         //有效卫星数
    float age;          //差分龄期
    float ratio;        //模糊度固定Ratio值
    float thres;        //模糊度固定的Ratio阈值
} sol_t;

SOLQ 参数,定位模式的选择,解的类型状态

1.1.7 eph_t

存储了卫星星历中的卫星参数,主要是开普勒参数

typedef struct {        /* GPS/QZS/GAL broadcast ephemeris type */
    int sat;            /* satellite number */
    int iode,iodc;      /* IODE,IODC */
    int sva;            /* SV accuracy (URA index) */
    int svh;            /* SV health (0:ok) */
    int week;           /* GPS/QZS: gps week, GAL: galileo week */
    int code;           /* GPS/QZS: code on L2, GAL/CMP: data sources */
    int flag;           /* GPS/QZS: L2 P data flag, CMP: nav type */
    gtime_t toe,toc,ttr; /* Toe,Toc,T_trans */
                        /* SV orbit parameters */
    double A,e,i0,OMG0,omg,M0,deln,OMGd,idot;
    double crc,crs,cuc,cus,cic,cis;
    double toes;        /* Toe (s) in week */
    double fit;         /* fit interval (h) */
    double f0,f1,f2;    /* SV clock parameters (af0,af1,af2) */
    double tgd[4];      /* group delay parameters */
                        /* GPS/QZS:tgd[0]=TGD */
                        /* GAL    :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 */
                        /* CMP    :tgd[0]=BGD1,tgd[1]=BGD2 */
    double Adot,ndot;   /* Adot,ndot for CNAV */
} eph_t;

1.1.8 prcopt_t 配置存储

算法处理选项结构体

typedef struct {        /* processing options type  处理类型 */
    int mode;           /* positioning mode (PMODE_???)  单点定位/基线啥的 处理类型 */
    int soltype;        /* solution type (0:forward 前向,1:backward 后向,2:combined 都有) */
    int nf;             /* number of frequencies (1:L1,2:L1+L2,3:L1+L2+L5) 处理频率*/
    int navsys;         /* navigation system */
    double elmin;       /* elevation mask angle (rad) 高度截至角 */
    snrmask_t snrmask;  /* SNR mask 信噪比*/
    int sateph;         /* satellite ephemeris/clock (EPHOPT_???) 星历的配置*/
    int modear;         /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) 模糊度固定模式*/
    int glomodear;      /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */
    int bdsmodear;      /* BeiDou AR mode (0:off,1:on) */
    int maxout;         /* obs outage count to reset bias */
    int minlock;        /* min lock count to fix ambiguity */
    int minfix;         /* min fix count to hold ambiguity */
    int ionoopt;        /* ionosphere option (IONOOPT_???) */
    int tropopt;        /* troposphere option (TROPOPT_???) */
    int dynamics;       /* dynamics model (0:none,1:velociy,2:accel) */
    int tidecorr;       /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */
    int niter;          /* number of filter iteration */
    int codesmooth;     /* code smoothing window size (0:none) */
    int intpref;        /* interpolate reference obs (for post mission) */
    int sbascorr;       /* SBAS correction options */
    int sbassatsel;     /* SBAS satellite selection (0:all) */
    int rovpos;         /* rover position for fixed mode */
    int refpos;         /* base position for relative mode */
                        /* (0:pos in prcopt,  1:average of single pos, */
                        /*  2:read from file, 3:rinex header, 4:rtcm pos) */
    double eratio[NFREQ]; /* code/phase error ratio */
    double err[5];      /* measurement error factor */
                        /* [0]:reserved */
                        /* [1-3]:error factor a/b/c of phase (m) */
                        /* [4]:doppler frequency (hz) */
    double std[3];      /* initial-state std [0]bias,[1]iono [2]trop */
    double prn[5];      /* process-noise std [0]bias,[1]iono [2]trop [3]acch [4]accv */
    double sclkstab;    /* satellite clock stability (sec/sec) */
    double thresar[4];  /* AR validation threshold */
    double elmaskar;    /* elevation mask of AR for rising satellite (deg) */
    double elmaskhold;  /* elevation mask to hold ambiguity (deg) */
    double thresslip;   /* slip threshold of geometry-free phase (m) */
    double maxtdiff;    /* max difference of time (sec) */
    double maxinno;     /* reject threshold of innovation (m) */
    double maxgdop;     /* reject threshold of gdop */
    double baseline[2]; /* baseline length constraint {const,sigma} (m) */
    double ru[3];       /* rover position for fixed mode {x,y,z} (ecef) (m) */
    double rb[3];       /* base position for relative mode {x,y,z} (ecef) (m) */
    char anttype[2][MAXANT]; /* antenna types {rover,base} */
    double antdel[2][3]; /* antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */
    pcv_t pcvr[2];      /* receiver antenna parameters {rov,base} */
    unsigned char exsats[MAXSAT]; /* excluded satellites (1:excluded,2:included) */
    char rnxopt[2][256]; /* rinex options {rover,base} */
    int  posopt[6];     /* positioning options */
    int  syncsol;       /* solution sync mode (0:off,1:on) */
    double odisp[2][6*11]; /* ocean tide loading parameters {rov,base} */
    exterr_t exterr;    /* extended receiver error model */
} prcopt_t;

1.1.9 solopt_t 输出文件结构体

设置输出结果的格式

typedef struct {        /* solution options type 输出文件类型,例如有哪些要输出、用哪个椭球体*/
    int posf;           /* solution format (SOLF_???) */
    int times;          /* time system (TIMES_???) */
    int timef;          /* time format (0:sssss.s,1:yyyy/mm/dd hh:mm:ss.s) */
    int timeu;          /* time digits under decimal point */
    int degf;           /* latitude/longitude format (0:ddd.ddd,1:ddd mm ss) */
    int outhead;        /* output header (0:no,1:yes) */
    int outopt;         /* output processing options (0:no,1:yes) */
    int datum;          /* datum (0:WGS84,1:Tokyo) */
    int height;         /* height (0:ellipsoidal,1:geodetic) */
    int geoid;          /* geoid model (0:EGM96,1:JGD2000) */
    int solstatic;      /* solution of static mode (0:all,1:single) */
    int sstat;          /* solution statistics level (0:off,1:states,2:residuals) */
    int trace;          /* debug trace level (0:off,1-5:debug) */
    double nmeaintv[2]; /* nmea output interval (s) (<0:no,0:all) */
                        /* nmeaintv[0]:gprmc,gpgga,nmeaintv[1]:gpgsv */
    char sep[64];       /* field separator */
    char prog[64];      /* program name */
} solopt_t;

1.1.10 ssat_t 卫星状态控制结构体(过程信息)

typedef struct {        /* satellite status type */
    uint8_t sys;         //卫星导航系统
    uint8_t vs;          //有效卫星单一标志
    double azel[2];      //方位角,高度角
    double resp[NFREQ];  //伪距残差
    double resc[NFREQ];  //载波相位残差
    uint8_t vsat[NFREQ]; //有效卫星标志
    uint16_t snr[NFREQ]; //信噪比
    uint8_t fix [NFREQ]; //模糊度的状态,浮点解、固定解
    uint8_t slip[NFREQ]; /* cycle-slip flag */          
    uint8_t half[NFREQ]; /* half-cycle valid flag */
    int lock [NFREQ];   /* lock counter of phase */
    uint32_t outc [NFREQ]; //载波中断计数
    uint32_t slipc[NFREQ]; /* cycle-slip counter */
    uint32_t rejc [NFREQ]; /* reject counter */
    double gf[NFREQ-1]; /* geometry-free phase (m) */
    double mw[NFREQ-1]; /* MW-LC (m) */
    double phw;         /* phase windup (cycle) */
    gtime_t pt[2][NFREQ]; /* previous carrier-phase time */
    double ph[2][NFREQ]; /* previous carrier-phase observable (cycle) */
} ssat_t;

1.1.11 rtk_t:rtk控制结构体

typedef struct {        /* RTK control/result type */
    sol_t  sol;			//结果结构体                         
    double rb[6];        //基准站位置、速度
    int nx,na;         	 //na为除模糊度外参数数、nx为加上模糊度参数数
    double tt;           //当前历元和先前历元时间差
    double *x, *P;       //浮点解和协方差
    double *xa,*Pa;      //固定解和协方差
    int nfix;            //number of continuous fixes of ambiguity
    ambc_t ambc[MAXSAT]; //模糊度控制结构体数组
    ssat_t ssat[MAXSAT]; //卫星状态控制结构体数组
    int neb;             //错误信息的缓冲区长度
    char errbuf[MAXERRMSG];//错误信息缓冲区
    prcopt_t opt;        //处理选项,参数配置
} rtk_t;

1.2 satno() 卫星编码函数

按照HPS、GLONASS、GAL等卫星依次往后编号

extern int  satno   (int sys, int prn);

extern int satno(int sys, int prn)
{
    if (prn<=0) return 0;
    switch (sys) {
        case SYS_GPS:
            if (prn<MINPRNGPS||MAXPRNGPS<prn) return 0;
            return prn-MINPRNGPS+1; //如果是GPS的X卫星,重新编号就是...
        case SYS_GLO:
            if (prn<MINPRNGLO||MAXPRNGLO<prn) return 0;
            return NSATGPS+prn-MINPRNGLO+1; //如果是GLOSS的X卫星,在GPS卫星基础上编号,续
        case SYS_GAL:
            if (prn<MINPRNGAL||MAXPRNGAL<prn) return 0;
            return NSATGPS+NSATGLO+prn-MINPRNGAL+1;
        case SYS_QZS:
            if (prn<MINPRNQZS||MAXPRNQZS<prn) return 0;
            return NSATGPS+NSATGLO+NSATGAL+prn-MINPRNQZS+1;
        case SYS_CMP:
            if (prn<MINPRNCMP||MAXPRNCMP<prn) return 0;
            return NSATGPS+NSATGLO+NSATGAL+NSATQZS+prn-MINPRNCMP+1;
        case SYS_LEO:
            if (prn<MINPRNLEO||MAXPRNLEO<prn) return 0;
            return NSATGPS+NSATGLO+NSATGAL+NSATQZS+NSATCMP+prn-MINPRNLEO+1;
        case SYS_SBS:
            if (prn<MINPRNSBS||MAXPRNSBS<prn) return 0;
            return NSATGPS+NSATGLO+NSATGAL+NSATQZS+NSATCMP+NSATLEO+prn-MINPRNSBS+1;
    }
    return 0;
}
参数16进制向二进制转换有规律

#define SYS_NONE    0x00                /* navigation system: none */
#define SYS_GPS     0x01                /* navigation system: GPS 1*/
#define SYS_SBS     0x02                /* navigation system: SBAS 10*/
#define SYS_GLO     0x04                /* navigation system: GLONASS 100*/
#define SYS_GAL     0x08                /* navigation system: Galileo 1000*/
#define SYS_QZS     0x10                /* navigation system: QZSS 16^1=16 10000*/
#define SYS_CMP     0x20                /* navigation system: BeiDou */
#define SYS_IRN     0x40                /* navigation system: IRNSS */
#define SYS_LEO     0x80                /* navigation system: LEO */
#define SYS_ALL     0xFF                /* navigation system: all */

1.3 rtkpos() 接口调用逻辑

该函数处理的是单个历元的所有卫星观测值数据,实现单历元定位,我们需要多次调用处理全部数据。我们在VS中查看调用层级

Main( )函数中调用postpos( )函数,postpos( )调用execses_b( )进行基准站的处理,基准站下遍历每个流动站(execses_r),数据处理使得对应的基准站和流动站结合起来,将处理好结合的流动站/基准站数据进行调用execses( )函数进行定位,procpos( )遍历基准站/流动站每个历元,每个历元数据使用rtkpos( )进行处理实现单历元定位

2 配置文件读取

2.1 Main()函数中的配置参数

在main()中,我们首先是进行一系列参数的设置,设置完毕后才进行postpos()函数调用。

ret=postpos(ts,te,tint,0.0,&prcopt,&solopt,&filopt,infile,n,outfile,"","");

ts--开始时间
te--结束时间
tint--采样频率
&prcopt,&solopt,&filopt--这几个是我们上文提到的结构体
infile--输入文件
n--文件个数
outfile--输出文件
int main(int argc, char **argv)
{

//结构体的设置
    prcopt_t prcopt=prcopt_default;
    solopt_t solopt=solopt_default;
    filopt_t filopt={""};
//起始时间
    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="";
//结构体中的成员变量
    prcopt.mode  =PMODE_KINEMA;
    prcopt.navsys=SYS_GPS|SYS_GLO;
    prcopt.refpos=1;
    prcopt.glomodear=1;
    solopt.timef=0;
    sprintf(solopt.prog ,"%s ver.%s",PROGNAME,VER_RTKLIB);
    sprintf(filopt.trace,"%s.trace",PROGNAME);
    
    /* 加载配置文件,load options from configuration file */
    for (i=1;i<argc;i++) {
        if (!strcmp(argv[i],"-k")&&i+1<argc) {
            resetsysopts();
            if (!loadopts(argv[++i],sysopts)) return -1;
            getsysopts(&prcopt,&solopt,&filopt); //将全局变量sysopts配置参数,赋给局部变量
        }
    }
//根据输入的命令行进行配置
    for (i=1,n=0;i<argc;i++) {
        if      (!strcmp(argv[i],"-o")&&i+1<argc) outfile=argv[++i];
        else if (!strcmp(argv[i],"-ts")&&i+2<argc) {
            sscanf(argv[++i],"%lf/%lf/%lf",es,es+1,es+2);
            sscanf(argv[++i],"%lf:%lf:%lf",es+3,es+4,es+5);
            ts=epoch2time(es);
        }
        else if (!strcmp(argv[i],"-te")&&i+2<argc) {
            sscanf(argv[++i],"%lf/%lf/%lf",ee,ee+1,ee+2);
            sscanf(argv[++i],"%lf:%lf:%lf",ee+3,ee+4,ee+5);
            te=epoch2time(ee);
        }
        else if (!strcmp(argv[i],"-ti")&&i+1<argc) tint=atof(argv[++i]);
        else if (!strcmp(argv[i],"-k")&&i+1<argc) {++i; continue;}
        else if (!strcmp(argv[i],"-p")&&i+1<argc) prcopt.mode=atoi(argv[++i]);
        else if (!strcmp(argv[i],"-f")&&i+1<argc) prcopt.nf=atoi(argv[++i]);
        else if (!strcmp(argv[i],"-m")&&i+1<argc) prcopt.elmin=atof(argv[++i])*D2R;
        else if (!strcmp(argv[i],"-v")&&i+1<argc) prcopt.thresar[0]=atof(argv[++i]);
        else if (!strcmp(argv[i],"-s")&&i+1<argc) strcpy(solopt.sep,argv[++i]);
        else if (!strcmp(argv[i],"-d")&&i+1<argc) solopt.timeu=atoi(argv[++i]);
        else if (!strcmp(argv[i],"-b")) prcopt.soltype=1;
        else if (!strcmp(argv[i],"-c")) prcopt.soltype=2;
        else if (!strcmp(argv[i],"-i")) prcopt.modear=2;
        else if (!strcmp(argv[i],"-h")) prcopt.modear=3;
        else if (!strcmp(argv[i],"-t")) solopt.timef=1;
        else if (!strcmp(argv[i],"-u")) solopt.times=TIMES_UTC;
        else if (!strcmp(argv[i],"-e")) solopt.posf=SOLF_XYZ;
        else if (!strcmp(argv[i],"-a")) solopt.posf=SOLF_ENU;
        else if (!strcmp(argv[i],"-n")) solopt.posf=SOLF_NMEA;
        else if (!strcmp(argv[i],"-g")) solopt.degf=1;
        else if (!strcmp(argv[i],"-r")&&i+3<argc) {
            prcopt.refpos=0;
            for (j=0;j<3;j++) prcopt.rb[j]=atof(argv[++i]);
        }
        else if (!strcmp(argv[i],"-l")&&i+3<argc) {
            prcopt.refpos=0;
            for (j=0;j<3;j++) pos[j]=atof(argv[++i]);
            for (j=0;j<2;j++) pos[j]*=D2R;
            pos2ecef(pos,prcopt.rb);
        }
        else if (!strcmp(argv[i],"-y")&&i+1<argc) solopt.sstat=atoi(argv[++i]);
        else if (!strcmp(argv[i],"-x")&&i+1<argc) solopt.trace=atoi(argv[++i]);
        else if (*argv[i]=='-') printhelp();
        else if (n<MAXFILE) infile[n++]=argv[i];
    }
    if (n<=0) {
        showmsg("error : no input file");
        return -2;
    }
//配置设置完毕,开始执行
    ret=postpos(ts,te,tint,0.0,&prcopt,&solopt,&filopt,infile,n,outfile,"","");
    
    if (!ret) fprintf(stderr,"%40s\r","");
    return ret;
}

在mian()函数中,我们先加载配置文件,进行参数配置

            if (!loadopts(argv[++i],sysopts)) return -1;
            getsysopts(&prcopt,&solopt,&filopt);

然后解析命令行再次配置。所以参数设置时,配置文件的优先级是低于命令参数的。

注释里提及的命令行,就是根据rtklib使用手册中,所输入的命令,是这里面的参数(部分截图)

2.1.1  main(int argc, char **argv) 参数意义

argc--参数的个数

**argv--命令行

我们先在vs设置好调试参数

打上断点进行调试,查看值

argc值是指argv字符串数组的大小,argv数组各个成员是命令行参数的【拆分】

这样就理解了,这些参数设置就是遍历命令行,找对应的参数配置,再代码中进赋值。

2.1.2 配置文件.conf

(1)文件格式

从左到右依次是[名字、值、注释]

(2)配置文件读取

[1] loadopts()函数进行处理。argv[++i]是文件路径,sysopts是全局变量

[2] sysopts是结构体opt_t的数组,其结构和配置文件一样。

opt_t结构体是仿照配置文件的定义

typedef struct {        /* option type */
    char *name;         /* option name 名字 */
    int format;         /* option format (0:int,1:double,2:string,3:enum) 值是什么类型的 */
    void *var;          /* pointer to option variable 值 */
    char *comment;      /* option comment/enum labels/unit 注释 */
} opt_t;

[3] loadopts()函数详解

打开文件,逐行读取内容,找到每一行“=”的位置,获取值并赋予p,之后chop()函数使数组buff为配置名字,根据名字使用searchopt()寻找对应sysopts数组要素,并将其赋予opt。在str2opt()中,对应的结构体进行值的赋予。

extern int loadopts(const char *file, opt_t *opts)
{
    FILE *fp;
    opt_t *opt;
    char buff[2048],*p;
    int n=0;
    
    //日志记录
    trace(3,"loadopts: file=%s\n",file);
    //打开文件
    if (!(fp=fopen(file,"r"))) {
        trace(1,"loadopts: options file open error (%s)\n",file);
        return 0;
    }
    //遍历配置文件的每一行内容
    while (fgets(buff,sizeof(buff),fp)) {
        n++;
        chop(buff);
        
        if (buff[0]=='\0') continue;
        //strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串
        //找到值,并赋予p
        if (!(p=strstr(buff,"="))) {
            fprintf(stderr,"invalid option %s (%s:%d)\n",buff,file,n);
            continue;
        }
        *p++='\0';
        //获取名字
        chop(buff);
        //在sysopts数组中找到和该行名字一样的,并将其配置参数赋予opt
        if (!(opt=searchopt(buff,opts))) continue;
        //str2opt()根据opt.format进行值的转换。format (0:int,1:double,2:string,3:enum)
        if (!str2opt(opt,p)) {
            fprintf(stderr,"invalid option value %s (%s:%d)\n",buff,file,n);
            continue;
        }
    }
    fclose(fp);
    
    return 1;
}

[4] searchopt()函数详解

遍历opts,也就是sysopts数组。根据名字判断是否找到,找到了就返回该参数在opts这一组内容

extern opt_t *searchopt(const char *name, const opt_t *opts)
{
    int i;
    
    trace(3,"searchopt: name=%s\n",name);
    
    for (i=0;*opts[i].name;i++) {
        if (strstr(opts[i].name,name)) return (opt_t *)(opts+i);
    }
    return NULL;
}

[5] str2opt()函数详解

extern int str2opt(opt_t *opt, const char *str)
{
    //根据format,进行相应类型转换
    switch (opt->format) {
        case 0: *(int    *)opt->var=atoi(str); break;
        case 1: *(double *)opt->var=atof(str); break;
        case 2: strcpy((char *)opt->var,str);  break;
        case 3: return str2enum(str,opt->comment,(int *)opt->var);
        default: return 0;
    }
    return 1;
}

[6] 这样一来,我们就修改了全局变量的配置参数,之后我们再赋予局部变量即可

2.2 新增配置选项

在配置文件中新增pos1-sppmode=1配置选项,配置的值为int,暂定的选项为0或者1。同时你需要在prcopt_t结构体中新增变量用于存储该配置,新增的变量名字,可以为sppmode

[1] 在配置文件.conf增加这个选项,值为1

[2] 在prcopt_t结构体中新增变量。注意,这个变量放在末尾,因为在读取rinex时,有一个rtkinit()函数,进行结构体初始化,进行初始赋值,写在中间会报错。

[3] 在全局变量sysopts中新增,因为我们的值为int,所以format为0

2.3 读取rinex文件

[1] 不同类型读取o文件和n文件

[2] 读文件时,处理一个历元数据

    /* read rinex navigation data body */
    while ((stat=readrnxnavb(fp,opt,ver,sys,&type,&eph,&geph,&seph))>=0) {
        
        /* add ephemeris to navigation data */
        if (stat) {
            switch (type) {
                case 1 : stat=add_geph(nav,&geph); break;
                case 2 : stat=add_seph(nav,&seph); break;
                default: stat=add_eph (nav,&eph ); break;
            }
            if (!stat) return 0;
        }
    }

[3] 排序、去重

3 procpos( )函数详解

首先进行一些结构体的初始化,通过rtkinit()函数将变量popt【参数配置】赋予给rtk_t rtk下的prcopt_t成员,之后每个历元逐个遍历,进入定位算法,不成功跳过输出。

static void procpos(FILE *fp, const prcopt_t *popt, const solopt_t *sopt,
                    int mode)
{
    gtime_t time={0};
    sol_t sol={{0}};//定位结果
    rtk_t rtk;//中间过程
    obsd_t obs[MAXOBS*2]; /* for rover and base */ //当前历元所有流动站和基准站观测值,MAXOBS*2 当前历元最大卫星数量,若超过就存不进来,需要扩展
    double rb[3]={0};
    int i,nobs,n,solstatic,pri[]={0,1,2,3,4,5,1,6};
    
    trace(3,"procpos : mode=%d\n",mode);
    
    solstatic=sopt->solstatic&&
              (popt->mode==PMODE_STATIC||popt->mode==PMODE_PPP_STATIC);
    
    rtkinit(&rtk,popt);//初始化,将配置文件里的赋值给rtk下的prcopt_t opt
    rtcm_path[0]='\0';
    //输入单个历元的基准站+流动站数据,放入obs中
    while ((nobs=inputobs(obs,rtk.sol.stat,popt))>=0) {
        
        /* exclude satellites */
        for (i=n=0;i<nobs;i++) {
            //根据配置的系统[popt->navsys],将其他系统的卫星删除
            if ((satsys(obs[i].sat,NULL)&popt->navsys)&&
                popt->exsats[obs[i].sat-1]!=1) obs[n++]=obs[i];
        }

        if (n<=0) continue;
        //进入单点定位, 若定位不成功,则continue【不输出】
        if (!rtkpos(&rtk,obs,n,&navs)) continue;
        //前项/后项
        if (mode==0) { /* forward/backward */
            if (!solstatic) {
                outsol(fp,&rtk.sol,rtk.rb,sopt);
            }
            else if (time.time==0||pri[rtk.sol.stat]<=pri[sol.stat]) {
                sol=rtk.sol;
                for (i=0;i<3;i++) rb[i]=rtk.rb[i];
                if (time.time==0||timediff(rtk.sol.time,time)<0.0) {
                    time=rtk.sol.time;
                }
            }
        }
        else if (!revs) { /* 卡尔曼滤波结合前项 combined-forward */
            if (isolf>=nepoch) return;
            solf[isolf]=rtk.sol;
            for (i=0;i<3;i++) rbf[i+isolf*3]=rtk.rb[i];
            isolf++;
        }
        else { /* combined-backward */
            if (isolb>=nepoch) return;
            solb[isolb]=rtk.sol;
            for (i=0;i<3;i++) rbb[i+isolb*3]=rtk.rb[i];
            isolb++;
        }
    }
    if (mode==0&&solstatic&&time.time!=0.0) {
        sol.time=time;
        outsol(fp,&sol,rb,sopt); //输出函数
    }
    rtkfree(&rtk);
}

[1] rtkinit( )详解

都是通过zeros()【把所有变量设为0】进行初始化

extern void rtkinit(rtk_t *rtk, const prcopt_t *opt)
{
    sol_t sol0={{0}};
    ambc_t ambc0={{{0}}};
    ssat_t ssat0={0};
    int i;
    
    trace(3,"rtkinit :\n");
    
    rtk->sol=sol0;
    for (i=0;i<6;i++) rtk->rb[i]=0.0;
    rtk->nx=opt->mode<=PMODE_FIXED?NX(opt):pppnx(opt);
    rtk->na=opt->mode<=PMODE_FIXED?NR(opt):0;
    rtk->tt=0.0;
    rtk->x=zeros(rtk->nx,1);
    rtk->P=zeros(rtk->nx,rtk->nx);
    rtk->xa=zeros(rtk->na,1);
    rtk->Pa=zeros(rtk->na,rtk->na);
    rtk->nfix=rtk->neb=0;
    for (i=0;i<MAXSAT;i++) {
        rtk->ambc[i]=ambc0;
        rtk->ssat[i]=ssat0;
    }
    for (i=0;i<MAXERRMSG;i++) rtk->errbuf[i]=0;
    rtk->opt=*opt; //将opt赋予给rtk下的成员
}

[2] 输出函数outsol( )详解

outsol( )->outsols( )

根据参数,输出的类型

命令行中就是这些

[3] pos格式

我们也可以增加输出列数

  • 26
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值