RTKLIB源码阅读(四)后处理主函数、rnx2rtkp.c、main函数参数、配置选项、Option文件读取、Trace输出

编程入门 行业动态 更新时间:2024-10-05 19:20:57

RTKLIB源码阅读(四)后处理主<a href=https://www.elefans.com/category/jswz/34/1771370.html style=函数、rnx2rtkp.c、main函数参数、配置选项、Option文件读取、Trace输出"/>

RTKLIB源码阅读(四)后处理主函数、rnx2rtkp.c、main函数参数、配置选项、Option文件读取、Trace输出

原始 Markdown文档、Visio流程图、XMind思维导图见:

文章目录

    • 一、rnx2rtkp
      • 1、简介
      • 2、main函数参数
      • 3、main函数题解读
    • 二、自己写后处理主函数
      • 1、精密单点定位
      • 2、差分定位
    • 三、C语言字符串处理、文件IO知识补充
      • 1、C语言字符串的存储
        • 1.字符串常量
        • 2.字符串变量
      • 2、处理字符串的函数
    • 四、Option/Configuration文件读取
      • 1、Option文件格式介绍
      • 2、存Option的类型
        • 1.prcopt_t结构体:存算法处理选项
        • 2.solopt_t 结构体:存输出结果设置
        • 3.filopt_t 结构体:存文件设置
        • 4.opt_t结构体:存一条有选项信息的结构体
      • 3、options.c函数
        • 1.chop ():去除#后的注释,把#替换为\0。
        • 2.eunm2str():把选项序号转为选项字符串。
        • 3.str2enum():把选项字符串转为选项序号。
        • 4.searchopt():根据选项名找选项
        • 5.str2opt():把字符串转为对应的opt值
        • 6.opt2str():把opt值转为字符串(value)
        • 7.opt2buf():把opt转为字符串(keyword=value # comment)
        • 8.loadopts():从文件中加载选项信息
        • 9.saveopts():保存选项信息到文件
        • 10.resetsysopts():重置选项到默认。
        • 11.buff2sysopts():选项缓冲区转选项结构体
        • 12.sysopts2buff():选项结构体转选项缓冲区
        • 13.getsysopts():获取配置选项
        • 14.setsysopts():保存配置选项
    • 五、Trace
      • 1、rtkcmn.c关于trace的静态全局变量
      • 2、Trace相关函数
        • 1.trace():将传入的trace格式化字符串写入trace文件
        • 2.tracet():写入带秒数的trace格式字符串
        • 3.traceclose():关闭trace文件描述符,将文件指针置空
        • 4.traceopen():创建或打开trace文件
        • 5.tracelevel():将传入的trace等级赋值给level_trace
        • 6.traceswap():根据时间分trace文件
        • 7.tracemat():写入矩阵
        • 8.traceobs():写入obsd_t
        • 9.tracenav():写入导航电文
        • 10.traceb():写入buff缓冲区数据

一、rnx2rtkp

配置选项可以参考本系列上一篇博客中的RTKPOS:

1、简介

  • 使用方式:rnx2rtkp [option]... file file [...] 。VS 中加 main 函数参数:在项目的 配置属性-调试-命令参数 中设置。

  • 读取RINEX OBS/NAV/GNAV/HNAV/CLK, SP3, SBAS 等文件,计算接收机、流动站坐标,并输出结果。

  • 对与相对定位,第一个OBS观测值文件需含接收机、流动站观测值,第二个OBS文件需含基准站观测值。

  • 输入文件至少要有一个星历文件,RINEX NAV/GNAV/HNAV 。

  • 想用SP3精密星历文件,需提供.sp3/.eph文件的路径。

  • 输入文件路径可包含通配符*,为了防止与命令行命令冲突,要用"…" 括起带通配符符路径。

2、main函数参数

  1. -?、-:打印help
  2. -k file:配置文件的输入选项,默认值是[off]
  3. -o file:输出文件选项,默认值是[stdout]
  4. -ts ds ts:设置开始解算时间(ds=y/m/d ts=h:m:s) ,默认值是[obs start time]
  5. -te de ds:设置结束解算时间(de=y/m/d te=h:m:s) ,默认值是[obs end time]
  6. -ti tint:设置解算时间间隔频率(sec) ,默认值是[all]
  7. -p mode:设置解算模式,(0:single,1:dgps,2:kinematic,3:static,4:moving-base,5:fixed,6:ppp-kinematic,7:ppp-static),默认值是[2]
  8. -m mask:设置截止高度角,(deg) ,默认值是[15]
  9. -sys s:设置用于计算的导航系统,(s=G:GPS,R:GLO,E:GAL,J:QZS,C:BDS,I:IRN) ,默认值是[G|R]
  10. -f freq:设置用于计算的频率,(1:L1,2:L1+L2,3:L1+L2+L5),默认值是[2]
  11. -v thres:设置整周模糊度Ratio值,写0.0为不固定整周模糊度,默认值是[3.0]
  12. -b:后向滤波
  13. -c:前后向滤波组合
  14. -i:单历元模糊度固定instantaneous
  15. -h:fix and hold模糊度固定
  16. -e:输出XYZ-ecef坐标
  17. -a:输出ENU-baseline
  18. -n:输出NMEA-0183 GGA
  19. -g:输出经纬度格式为ddd mm ss.ss ,默认为[ddd.ddd]
  20. -t:输出时间格式为yyyy/mm/dd hh:mm:ss.ss ,默认为[sssss.ss]
  21. -u:输出为UTC时间,默认为[gpst]
  22. -d col:设置时间的小数位数,默认为[3]
  23. -s sep:设置文件分隔符,要写在单引号中,默认为[’ ']
  24. -r x y z:基站位置ECEF-XYZ (m),默认[average of single pos] ,流动站位置用于fixed模式
  25. -l lat lon hgt:基站位置LLH (deg/m),默认[average of single pos],流动站位置用于fixed模式
  26. -y level:输出结果信息(0:off,1:states,2:residuals) ,默认为[0]
  27. -x level:输出debug trace等级,默认为[0]

3、main函数题解读

我根据自己的理解给代码加了中文注释

  • 读取配置文件过程
    • 循环判断参数是否有-k
    • 创建porcopt_t/solopt_t/filopt_t 变量用于接受读取到的配置
    • resetsysopts() ,重置配置为默认
    • loadopts(),从文件中读取配置,存到opt_t类型的sysopt中
    • getsysopts(),把opt_t类型的sysopt转到porcopt_t/solopt_t/filopt_t 变量中,会调用buff2sysopts()
  • 读其它参数
    • 循环内,if-else if,判断参数,根据参数赋值
    • 若都不是参数,最后一个到else if,认为是文件路径,用infile数组接收
  • 调用postpos()后处理解算
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};              //ts开始时间、te结束时间double tint=0.0,es[]={2000,1,1,0,0,0},ee[]={2000,12,31,23,59,59},pos[3];int i,  //for循环的计数j,  //嵌套的for循环计数n,  //记录读入文件数ret;    //接受postpos的返回值char *infile[MAXFILE],  //读入文件,默认最多16个,可改MAXFILE定义*outfile="",       //输出文件*p;                //指向字符串的指针,用于循环指向各main函数参数prcopt.mode  =PMODE_KINEMA;     //定位模式默认动态相对定位Kinematicprcopt.navsys=0;        //卫星系统,先设置无prcopt.refpos=1;        //基准站坐标prcopt.glomodear=1;     //GLONASS AR mode,先设onsolopt.timef=0;         //输出时间格式,先设sssss.ssprintf(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;i<argc;i++) {if (!strcmp(argv[i],"-k")&&i+1<argc) {  //如果有-k和配置文件输入resetsysopts();         //先重置所有配置if (!loadopts(argv[++i],sysopts)) return -1;    //再读取配置文件内容,存入opt_t的sysopt中getsysopts(&prcopt,&solopt,&filopt);    //opt_t转到porcopt_t/solopt_t/filopt_t,}   }                  for (i=1,n=0;i<argc;i++) {  //循环判断main函数参数if      (!strcmp(argv[i],"-o")&&i+1<argc) outfile=argv[++i];//读取输出文件路径,赋值给outfileelse 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);      //转为gtime_t}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);  //转为gtime_t}else if (!strcmp(argv[i],"-ti")&&i+1<argc) tint=atof(argv[++i]);    //读取解算时间间隔频率else if (!strcmp(argv[i],"-k")&&i+1<argc) {++i; continue;}  //有-k,跳过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],"-sys")&&i+1<argc) {       //读取用于计算的导航系统for (p=argv[++i];*p;p++) {      switch (*p) {   //有对应导航系统,就把它的码做与运算加上                 case 'G': prcopt.navsys|=SYS_GPS;case 'R': prcopt.navsys|=SYS_GLO;case 'E': prcopt.navsys|=SYS_GAL;case 'J': prcopt.navsys|=SYS_QZS;case 'C': prcopt.navsys|=SYS_CMP;case 'I': prcopt.navsys|=SYS_IRN;}if (!(p=strchr(p,','))) break;  }}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]);    //设置整周模糊度Ratio值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;    //fix and hold模糊度固定else if (!strcmp(argv[i],"-t")) solopt.timef=1;     //输出时间格式为yyyy/mm/dd hh:mm:ss.sselse if (!strcmp(argv[i],"-u")) solopt.times=TIMES_UTC;    //输出为UTC时间else if (!strcmp(argv[i],"-e")) solopt.posf=SOLF_XYZ;      //输出XYZ-ecef坐标else if (!strcmp(argv[i],"-a")) solopt.posf=SOLF_ENU;      //输出ENU-baselineelse if (!strcmp(argv[i],"-n")) solopt.posf=SOLF_NMEA;     //输出NMEA-0183 GGAelse if (!strcmp(argv[i],"-g")) solopt.degf=1;             //输出经纬度格式为ddd mm ss.sselse if (!strcmp(argv[i],"-r")&&i+3<argc) { //基站位置ECEF-XYZ (m)              prcopt.refpos=prcopt.rovpos=0;          //基准站和流动站位置都先设0for (j=0;j<3;j++) prcopt.rb[j]=atof(argv[++i]); //循环存入基准站坐标matcpy(prcopt.ru,prcopt.rb,3,1);    //}else if (!strcmp(argv[i],"-l")&&i+3<argc) {     //循环存入基站位置基站位置LLH (deg/m)prcopt.refpos=prcopt.rovpos=0;              //基准站和流动站位置都先设0for (j=0;j<3;j++) pos[j]=atof(argv[++i]);   for (j=0;j<2;j++) pos[j]*=D2R;           //角度转弧度   pos2ecef(pos,prcopt.rb);        //LLH转XYZmatcpy(prcopt.ru,prcopt.rb,3,1);}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]); //输出debug trace等级else if (*argv[i]=='-') printhelp();    //输入-,打印帮助else if (n<MAXFILE) infile[n++]=argv[i];    //循环判断完一遍参数之后,认为参数是文件路径,用infile数组接收}if (!prcopt.navsys) {               //如果没设卫星系统,默认为GPS、GLONASSprcopt.navsys=SYS_GPS|SYS_GLO;}if (n<=0) {         //如果读入文件数为0,报错,-2退出showmsg("error : no input file");return -2;}//   gtime_t ts       I   processing start time (ts.time==0: no limit)//   gtime_t te       I   processing end time   (te.time==0: no limit)//   double ti        I   processing interval  (s) (0:all)//   double tu        I   processing unit time (s) (0:all)//   prcopt_t *popt   I   processing options//   solopt_t *sopt   I   solution options//   filopt_t *fopt   I   file options//   char   **infile  I   input files (see below)//   int    n         I   number of input files//   char   *outfile  I   output file ("":stdout, see below)//   char   *rov      I   rover id list        (separated by " ")//   char   *base     I   base station id list (separated by " ")//后处理定位解算ret=postpos(ts,te,tint,0.0,&prcopt,&solopt,&filopt,infile,n,outfile,"",""); if (!ret) fprintf(stderr,"%40s\r","");return ret;
}

二、自己写后处理主函数

转载一篇写RTKLIB后处理main函数的博客,也推荐去原网站看,页面显示效果特别好。

1、精密单点定位

所选用的数据为武汉大学IGS数据中心上下载的2020年9月25日长春站(chan)的观测数据,同时下载了当天的广播星历以及精密星历。(chan2690.20o、brdc2690.20n、igs21245.sp3)

int main() {int i, n, ret;double tint = 0.0;       /* 求解时间间隔(0:默认) */gtime_t ts = { 0 }, te = { 0 }; /* 历元时段始末控制变量 */char *infile[MAXFILE], outfile[MAXSTRPATH] = { '\0' };char resultpath[MAXSTRPATH] = "H:\\20211108\\result"; /* 结果输出路径 */char sep = (char)FILEPATHSEP;prcopt_t prcopt = prcopt_default; /* 默认处理选项设置 */solopt_t solopt = solopt_default; /* 默认求解格式设置 */filopt_t filopt = { /* 参数文件路径设置 */"", /* 卫星天线参数文件 */"", /* 接收机天线参数文件 */"", /* 测站位置文件 */"", /* 扩展大地水准面数据文件 */"", /* 电离层数据文件 */"", /* DCB数据文件 */"", /* 地球自转参数文件 */"", /* 海洋潮汐负荷文件 */};char infile_[MAXFILE][MAXSTRPATH] = {"H:\\20211108\\chan2690.20o","H:\\20211108\\brdc2690.20n","H:\\20211108\\igs21245.sp3","","","","",""};long t1, t2;double eps[]={2020,9,25,0,0,0},epe[]={2020,9,25,23,0,0}; /* 设置计算的历元时段 */ts=epoch2time(eps);te=epoch2time(epe);for (i = 0, n = 0; i < MAXFILE; i++)if (strcmp(infile_[i], "")) infile[n++] = &infile_[i][0];sprintf(outfile, "%s%c", resultpath, sep);//设置输出路径/* 自定义求解格式 --------------------------------------------------------*/solopt.posf = SOLF_XYZ;   /* 选择输出的坐标格式,经纬度或是XYZ坐标等 */solopt.times  =TIMES_UTC; /* 控制输出解的时间系统类型 */solopt.degf   =0;         /* 输出经纬度格式(0:°, 1:°′″) */solopt.outhead=1;         /* 是否输出头文件(0:否,1:是) */solopt.outopt =1;         /* 是否输出prcopt变量(0:否,1:是) */solopt.height =1;         /* 高程(0:椭球高,1:大地高) *//* 自定义处理选项设置 ----------------------------------------------------*/prcopt.mode = PMODE_PPP_KINEMA; /* PPP动态处理 */prcopt.modear = 4;     /* 求解模糊度类型 */prcopt.sateph = EPHOPT_PREC;      /* 使用精密星历 */prcopt.ionoopt = IONOOPT_IFLC;     /* 使用双频消电离层组合模型 */prcopt.tropopt = TROPOPT_EST;      /* 使用对流层天顶延迟估计模型 */prcopt.tidecorr = 0; /* 地球潮汐改正选项(0:关闭,1:固体潮,2:固体潮+?+极移) */prcopt.posopt[0] = 0; /* 卫星天线模型 */prcopt.posopt[1] = 0; /* 接收机天线模型 */prcopt.posopt[2] = 0; /* 相位缠绕改正 */prcopt.posopt[3] = 0; /* 排除掩星 */prcopt.posopt[4] = 0; /* 求解接收机坐标出错后的检查选项 */prcopt.navsys = SYS_GPS; /* 处理的导航系统 */sprintf(outfile, "%s%cChan200925.pos", resultpath, sep); /* 输出结果名称 */prcopt.nf       =2;       /* 参与计算的载波频率个数 */prcopt.elmin    =10.0*D2R;/* 卫星截止高度角 */prcopt.soltype  =0;       /* 求解类型(0:向前滤波,1:向后滤波,2:混合滤波) */t1 = clock();ret = postpos(ts, te, tint, 0.0, &prcopt, &solopt, &filopt, infile, n, outfile, "", "");t2 = clock();if (!ret) fprintf(stderr, "%40s\r", "");printf("\n * The total time for running the program: %6.3f seconds\n%c", (double)(t2 - t1) / CLOCKS_PER_SEC, '\0');printf("Press any key to exit!\n");getchar();return ret;
}

2、差分定位

所选用的数据为武汉大学IGS数据中心上下载的2020年9月25日长春站(chan)与北京佛山站(bjfs)的观测数据,同时下载了当天的广播星历以及精密星历。(chan2690.20o、bjfs2690.20o、brdc2690.20n、igs21245.sp3)

在差分定位中,需要至少两个站的观测值,在RTKLIB中只有第一个观测值文件会被当做移动站处理,这里笔者将chan作为移动站,bjfs作为基准站

int main() {int i, n, ret;double tint = 0.0;       /* 求解时间间隔(0:默认) */gtime_t ts = { 0 }, te = { 0 }; /* 历元时段始末控制变量 */char *infile[MAXFILE], outfile[MAXSTRPATH] = { '\0' };char resultpath[MAXSTRPATH] = "H:\\20211108\\result"; /* 结果输出路径 */char sep = (char)FILEPATHSEP;prcopt_t prcopt = prcopt_default; /* 默认处理选项设置 */solopt_t solopt = solopt_default; /* 默认求解格式设置 */filopt_t filopt = { /* 参数文件路径设置 */"", /* 卫星天线参数文件 */"", /* 接收机天线参数文件 */"", /* 测站位置文件 */"", /* 扩展大地水准面数据文件 */"", /* 电离层数据文件 */"", /* DCB数据文件 */"", /* 地球自转参数文件 */"", /* 海洋潮汐负荷文件 */};char infile_[MAXFILE][MAXSTRPATH] = { /* 前面观测值为移动站,后面观测值为基准站 */"H:\\20211108\\chan2690.20o","H:\\20211108\\brdc2690.20n","H:\\20211108\\igs21245.sp3","H:\\20211108\\bjfs2690.20o","","","",""};long t1, t2;double eps[]={2020,9,25,0,0,0},epe[]={2020,9,25,23,0,0}; /* 设置计算的历元时段 */ts=epoch2time(eps);te=epoch2time(epe);for (i = 0, n = 0; i < MAXFILE; i++)if (strcmp(infile_[i], "")) infile[n++] = &infile_[i][0];sprintf(outfile, "%s%c", resultpath, sep);/* 自定义求解格式 --------------------------------------------------------*/solopt.timef = 1;       /* 时间格式(0:sssss.s, 1:yyyy/mm/dd hh:mm:ss.s) */solopt.outhead = 1;       /* 是否输出头文件(0:否,1:是) */solopt.posf = SOLF_XYZ;  /* 输出的坐标格式 *///solopt.sstat =1;         /* 输出状态文件 */solopt.times =TIMES_UTC; /* 控制输出解的时间系统类型 *///solopt.degf  =0;         /* 输出经纬度格式(0:°, 1:°′″) */solopt.outopt=1;         /* 是否输出prcopt变量(0:否,1:是) */solopt.height=1;         /* 高程(0:椭球高,1:大地高) *///solopt.sstat =1;         /* 输出求解状态 *//* 自定义处理选项设置 ----------------------------------------------------*/prcopt.mode = PMODE_DGPS; /* 差分GPS处理 */prcopt.modear = ARMODE_FIXHOLD;  /* 求解模糊度类型 */prcopt.sateph = EPHOPT_BRDC; /* 使用广播星历 */prcopt.ionoopt = IONOOPT_BRDC;  /* 使用广播电离层模型 */prcopt.tropopt = TROPOPT_SAAS;  /* 使用萨斯坦莫宁模型 */prcopt.refpos =3;       /* 相对模式中基站位置获得方式 *//* (0:pos in prcopt,  1:average of single pos, *//*  2:read from file, 3:rinex header, 4:rtcm pos) *///freqindex     =0;       /* 单频计算时设置所用计算的波段 */prcopt.nf     =2;       /* 参与计算的载波频率个数 L1+L2*///prcopt.glomodear =2;//prcopt.thresar[0]=2;//prcopt.posopt[4]=1;     /* 求解接收机坐标出错后的检查选项 *///prcopt.intpref=1;prcopt.elmin  =10.0*D2R;/* 卫星截止高度角 */prcopt.soltype=0;       /* 求解类型(0:向前滤波,1:向后滤波,2:混合滤波) */prcopt.navsys = SYS_GPS; /* 处理的导航系统 */sprintf(outfile, "%s%cchan200925DGPS.pos", resultpath, sep); /* 输出结果名称 *///prcopt.navsys =SYS_GPS|SYS_CMP; /* 处理的导航系统 *///sprintf(outfile,"%s%cresult_MIX.txt",resultpath,sep);t1 = clock();ret = postpos(ts, te, tint, 0.0, &prcopt, &solopt, &filopt, infile, n, outfile, "", "");t2 = clock();if (!ret) fprintf(stderr, "%40s\r", "");printf("\n * The total time for running the program: %6.3f seconds\n%c", (double)(t2 - t1) / CLOCKS_PER_SEC, '\0');printf("Press any key to exit!\n");getchar();return ret;
}

三、C语言字符串处理、文件IO知识补充

1、C语言字符串的存储

C语言没有专门用于存储字符串的数据类型,字符串都存在char类型的数组里,数组由连续的存储单元组成,每个存储单元存一个字符,C语言字符串末尾用\0表示字符串的结束。

1.字符串常量

用双引号扩起来的内容,编译时自动在末尾加\0

2.字符串变量

字符串变量一般有两种方法创建,指针或者是数组

 ```cchar a[]="hello world !";   //数组char* b=" hello world !";   //指针```
  • 数组形式:初始化数组把静态存储区的字符串拷贝到数组中,你的数组得到的只是它的副本 。

  • 指针形式:初始化指针只把字符串的地址拷贝给指针,你得的是静态存储区字符串的地址,用指针你不能修改字符串字面量 ,如果你打算修改字符串,就不要用指针去初始化。 你用多个指针初始化的字符串字面量是一样的,它们得到的是同一个地址 。

2、处理字符串的函数

大多数用到string.h头文件

  • sscanfsprintf效果很强大,见博客:sscanf函数和sprintf函数

  • gets():接受从终端输入的一个字符串,以/0结束

  • puts():将一个字符串输出到终端,以/0结束

  • strcat():字符串连接,结果存在str1中

    char str1[10] = "aa";
    char str2[10] = "bb";strcat(str1,str2);
    puts(str1);
    
  • strcpy():字符串复制,将str2内容复制到str1中

    strncpy():复制前n个字符串

    注意:str2会覆盖str1中全部的字符,str2长度不能超过str1

    char str1[10] = " ";
    char str2[10] = "bb";strcpy(str1,str2);
    puts(str1);
    
  • strcmp():字符串比较,相同返回0,str1>str2返回1,str1<str2返回-1

    strncmp():比较前n个字符

    stricmp():忽略大小写比较

    char str1[10] = "abc";
    char str2[10] = "bbb";int n = strcmp(str1,str2);
    printf("%d\n", n);
    
  • strlen():返回字符串长度,不计/0

  • strlow():字符串转小写

    strupr():字符串转大写

  • strstr():返回查找str2中str1首次出现的位置,没出现返回NULL

    strrstr():在字符串中反向查找

    strchr():在字符串中找字符

    strrchr():在字符中找字符,成功返回该位置到字符串结尾的所有字符

  • strtok():字符串分割

    1. 功能:在字符串中查找指定标记:如在(add@acdd#sd$)中,查找标记:(@#¥),然后把标记隔开的字符打印;
    2. 第一个参数是字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分隔标记;
    3. strtok函数找到str中的标记符,并将它替换为’\0’,并且用一个指针保存这个地址,然后返回这个指针;strtok函数会改变被操作的字符串,所以在使用之前应该拷贝所要操作的字符串,然后传递拷贝的字符串给strtok函数,这样目标字符串就不会被改变;
    4. strtok函数第一个参数不为NULL时,函数讲找到str字符串中的第一个标记,strtok函数将保存它在字符串中的位置;
    5. strtok函数的第一个参数为NULL时,函数将在同一个字符串中被保存的位置开始,查找下一个标记;
    6. 如果字符串中不存在更多的标记,则返回NULL指针;
    int main()
    {char arr[] = "zyth@guhdh.tech";char* p ="@ .";char tmp[20] ={0};strcpy(tmp,arr);char* ret = NULL;ret = strtok(tmp,p);printf("%s\n",ret);ret = strtok(NULL,p);printf("%s\n",ret);ret = strtok(NULL,p);printf("%s\n",ret);
    //进阶用法:for(ret = strtok(tmp,p);ret != NULL;ret = strtok(NULL,p)){printf("%s\n",ret);}
    }
    
  • atoi():把字符串转为整型,atoi()函数的功能:将字符串转换成整型数;atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负号才开始做转换,而再遇到非数字或字符串时(‘\0’)才结束转化,并将结果返回(返回转换后的整型数)。
  • atof():把字符串转为浮点型double,名字来源于 ascii to floating point numbers 的缩写,它会扫描参数str字符串,跳过前面的空白字符(例如空格,tab缩进等,可以通过 isspace() 函数来检测),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换,并将结果返回。参数str 字符串可包含正负号、小数点或E(e)来表示指数部分,如123. 456 或123e-2

文件IO:

  • Linux文件IO参考博客:c语言系统编程二:文件IO操做
  • Windows文件IO参考博客:C语言的文件IO操作,非常详细!!

四、Option/Configuration文件读取

1、Option文件格式介绍

  • 配置文件包含了processing options、solution options、file options三大块,用于RTKNAVI、RTKPOST、RTKRCV、RNX2RTKP。

  • 文件中都以Keyword = Value形式记录不同的配置项。

  • 对于枚举选项,可选值是选项序号(0,1,2,…) 或选项字符串(off, on, …)。

  • 以#开头的行和行中#之后的文本被视为注释。

    # RTKNAVI options (2013/03/01 10:41:04, v.2.4.2)pos1-posmode       =single     # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static)
    pos1-frequency     =l1+l2      # (1:l1,2:l1+l2,3:l1+l2+l5)
    pos1-soltype       =forward    # (0:forward,1:backward,2:combined)
    pos1-elmask        =10         # (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)
    pos1-ionoopt       =brdc       # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:vtec_sf,9:vtec_ef,10:gtec)
    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)
    pos1-posopt4       =on         # (0:off,1:on)
    pos1-posopt5       =off        # (0:off,1:on)
    pos1-exclsats      =           # (prn ...)
    pos1-navsys        =63         # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp)
    pos2-armode        =fix-and-hold # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
    pos2-gloarmode     =off        # (0:off,1:on,2:autocal)
    pos2-arthres       =3
    pos2-arlockcnt     =0
    pos2-arelmask      =20         # (deg)
    pos2-arminfix      =0
    pos2-elmaskhold    =0          # (deg)
    pos2-aroutcnt      =5
    pos2-maxage        =30         # (s)
    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      =llh        # (0:llh,1:xyz,2:enu,3:nmea)
    out-outhead        =off        # (0:off,1:on)
    out-outopt         =off        # (0:off,1:on)
    out-timesys        =gpst       # (0:gpst,1:utc,2:jst)
    out-timeform       =hms        # (0:tow,1:hms)
    out-timendec       =3
    out-degform        =deg        # (0:deg,1:dms)
    out-fieldsep       =
    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      =1          # (s)
    out-nmeaintv2      =1          # (s)
    out-outstat        =off        # (0:off,1:state,2:residual)
    stats-eratio1      =300
    stats-eratio2      =300
    stats-errphase     =0.003      # (m)
    stats-errphaseel   =0.003      # (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-clkstab      =5e-12      # (s/s)
    ant1-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm)
    ant1-pos1          =90         # (deg|m)
    ant1-pos2          =0          # (deg|m)
    ant1-pos3          =-6335367.6285 # (m|m)
    ant1-anttype       =NOV702GG
    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)
    ant2-pos1          =0          # (deg|m)
    ant2-pos2          =0          # (deg|m)
    ant2-pos3          =0          # (m|m)
    ant2-anttype       =TRM29659.00
    ant2-antdele       =0          # (m)
    ant2-antdeln       =0          # (m)
    ant2-antdelu       =0          # (m)
    misc-timeinterp    =off        # (0:off,1:on)
    misc-sbasatsel     =0          # (0:all)
    misc-rnxopt1       =
    misc-rnxopt2       =
    file-satantfile    =Y:\madoca\data\igs08.atx
    file-rcvantfile    =Y:\madoca\data\igs08.atx
    file-staposfile    =
    file-geoidfile     =
    file-ionofile      =
    file-dcbfile       =Y:\madoca\data\dcb\P1P21201.DCB
    file-eopfile       =
    file-blqfile       =
    file-tempdir       =C:\Temp
    file-geexefile     =
    file-solstatfile   =
    file-tracefile     =inpstr1-type       =ntripcli   # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
    inpstr1-path       =kaiyodai:tuomsat00@mgex.igs-ip:2101/CUT07:
    inpstr2-path       =
    inpstr3-path       =
    inpstr1-format     =rtcm3      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,15:sp3)
    inpstr2-format     =rtcm3      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,15:sp3)
    inpstr3-format     =rtcm3      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,15:sp3)
    inpstr2-nmeareq    =off        # (0:off,1:latlon,2:single)
    inpstr2-nmealat    =26.37293571 # (deg)
    inpstr2-nmealon    =127.143649075 # (deg)
    outstr1-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    outstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    outstr1-path       =
    outstr2-path       =
    outstr1-format     =llh        # (0:llh,1:xyz,2:enu,3:nmea)
    outstr2-format     =nmea       # (0:llh,1:xyz,2:enu,3:nmea)
    logstr1-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
    logstr1-path       =
    logstr2-path       =
    logstr3-path       =
    misc-svrcycle      =10         # (ms)
    misc-timeout       =30000      # (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)
    

2、存Option的类型

1.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 armaxiter;      /* max iteration to resolve 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[6];      /* process-noise std [0]bias,[1]iono [2]trop [3]acch [4]accv [5] pos */double sclkstab;    /* satellite clock stability (sec/sec) */double thresar[8];  /* 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} */uint8_t exsats[MAXSAT]; /* excluded satellites (1:excluded,2:included) */int  maxaveep;      /* max averaging epoches */int  initrst;       /* initialize by restart */int  outsingle;     /* output single by dgps/float/fix/ppp outage */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} */int  freqopt;       /* disable L2-AR */char pppopt[256];   /* ppp option */
} prcopt_t;
2.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 outvel;         /* output velocity 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 */double maxsolstd;   /* max std-dev for solution output (m) (0:all) */
} solopt_t;
3.filopt_t 结构体:存文件设置
typedef struct {        /* file options type */char satantp[MAXSTRPATH]; /* satellite antenna parameters file */char rcvantp[MAXSTRPATH]; /* receiver antenna parameters file */char stapos [MAXSTRPATH]; /* station positions file */char geoid  [MAXSTRPATH]; /* external geoid data file */char iono   [MAXSTRPATH]; /* ionosphere data file */char dcb    [MAXSTRPATH]; /* dcb data file */char eop    [MAXSTRPATH]; /* eop data file */char blq    [MAXSTRPATH]; /* ocean tide loading blq file */char tempdir[MAXSTRPATH]; /* ftp/http temporaly directory */char geexe  [MAXSTRPATH]; /* google earth exec file */char solstat[MAXSTRPATH]; /* solution statistics file */char trace  [MAXSTRPATH]; /* debug trace file */
} filopt_t;
  • 系统配置选项表:系统配置选项序号表,每条都是一个字符串,“选项序号:选项字符串,选项序号:选项字符串…”

    #define SWTOPT  "0:off,1:on"    
    #define MODOPT  "0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed"
    #define FRQOPT  "1:l1,2:l1+2,3:l1+2+3,4:l1+2+3+4,5:l1+2+3+4+5"
    #define TYPOPT  "0:forward,1:backward,2:combined"
    #define IONOPT  "0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc"
    #define TRPOPT  "0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad"
    #define EPHOPT  "0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom"
    #define NAVOPT  "1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic"
    #define GAROPT  "0:off,1:on"
    #define SOLOPT  "0:llh,1:xyz,2:enu,3:nmea"
    #define TSYOPT  "0:gpst,1:utc,2:jst"
    #define TFTOPT  "0:tow,1:hms"
    #define DFTOPT  "0:deg,1:dms"
    #define HGTOPT  "0:ellipsoidal,1:geodetic"
    #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 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"
    
4.opt_t结构体:存一条有选项信息的结构体

opt_t数组sysopts:存所有的选项

  • 第一个值为选项名。
  • 第二个为选项内容格式,0int、1double、2string、3enum。
  • 第三个值为指向存配置选项内容(prcopt_t、solopt_t、filopt_t、antpos_t结构体内的字段)的指针。
  • 第四个值为选项的表示形式,格式、系统配置选项序号表。
typedef struct {        /* option type */const char *name;   /* option name */int format;         /* option format (0:int,1:double,2:string,3:enum) */void *var;          /* pointer to option variable */const char *comment; /* option comment/enum labels/unit */
} opt_t;
  • 开头的静态变量,配置选项缓冲区

    static prcopt_t prcopt_;
    static solopt_t solopt_;
    static filopt_t filopt_;
    static int antpostype_[2];
    static double elmask_,elmaskar_,elmaskhold_;
    static double antpos_[2][3];
    static char exsats_[1024];
    static char snrmask_[NFREQ][1024];
    

3、options.c函数

1.chop ():去除#后的注释,把#替换为\0。
static void chop(char *str)
{char *p;if ((p=strchr(str,'#'))) *p='\0'; /* comment */for (p=str+strlen(str)-1;p>=str&&!isgraph((int)*p);p--) *p='\0';
}
2.eunm2str():把选项序号转为选项字符串。
3.str2enum():把选项字符串转为选项序号。
  • 如时间类型选项表:“0:gpst,1:utc,2:jst”,用enum2str()把0转为gpst,用str2enum()把gpst转为0.
static int enum2str(char *s, const char *comment, int val)  
{char str[32],*p,*q;int n;n=sprintf(str,"%d:",val);           //把val选项序号转为字符串,并用n记录长度if (!(p=strstr(comment,str))) {     //在系统配置选项序号表查找val序号,P指针移动到对应位置return sprintf(s,"%d",val);     //找不到直接把val号转成字符串返回}if (!(q=strchr(p+n,','))&&!(q=strchr(p+n,')'))) {   //如果后面找不到“,”和“)”,那p+n以后的字符串就是选项序号要转为的选项字符串strcpy(s,p+n);              return (int)strlen(p+n);}strncpy(s,p+n,q-p-n); s[q-p-n]='\0';    //在p+n后面找到“,”位置为q,则选项序号要转为的字符串为p+n到q前return (int)(q-p-n);
}
static int str2enum(const char *str, const char *comment, int *val)
{const char *p;char s[32];for (p=comment;;p++) {if (!(p=strstr(p,str))) break;if (*(p-1)!=':') continue;for (p-=2;'0'<=*p&&*p<='9';p--) ;return sscanf(p+1,"%d",val)==1;}sprintf(s,"%.30s:",str);if ((p=strstr(comment,s))) { /* number */return sscanf(p,"%d",val)==1;}return 0;
}
4.searchopt():根据选项名找选项

在opt_t数组中根据配置选项名找对应选项,找到了返回对应指针。

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():把字符串转为对应的opt值

传入字符串,根据选项内容格式,把字符串转为对应的opt值。

6.opt2str():把opt值转为字符串(value)
extern int str2opt(opt_t *opt, const char *str)
{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;
}
7.opt2buf():把opt转为字符串(keyword=value # comment)
extern int opt2buf(const opt_t *opt, char *buff)
{char *p=buff;int n;trace(3,"opt2buf : name=%s\n",opt->name);p+=sprintf(p,"%-18s =",opt->name);p+=opt2str(opt,p);if (*opt->comment) {if ((n=(int)(buff+30-p))>0) p+=sprintf(p,"%*s",n,"");p+=sprintf(p," # (%s)",opt->comment);}return (int)(p-buff);
}
8.loadopts():从文件中加载选项信息

之后还要用getsysopts()函数。

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)) {   //循环用fgets读取文件,每次读buff-1=2048个字符,到buff中n++;chop(buff);     //去除fgets带来的/0if (buff[0]=='\0') continue; //如果没有内容,直接进行下一次循环if (!(p=strstr(buff,"="))) {    //如果找不到=,就输出错误fprintf(stderr,"invalid option %s (%s:%d)\n",buff,file,n);continue;}*p++='\0';chop(buff); //去除#后的注释if (!(opt=searchopt(buff,opts))) continue;  //在opt_t数组中根据配置选项名找对应选项if (!str2opt(opt,p)) {  //传入字符串,根据选项内容格式,把字符串转为对应的opt值fprintf(stderr,"invalid option value %s (%s:%d)\n",buff,file,n);continue;}}fclose(fp);     //关闭文件return 1;
}
9.saveopts():保存选项信息到文件

之后还要用setsysopts()函数。

extern int saveopts(const char *file, const char *mode, const char *comment,const opt_t *opts)
{FILE *fp;char buff[2048];int i;trace(3,"saveopts: file=%s mode=%s\n",file,mode);if (!(fp=fopen(file,mode))) {trace(1,"saveopts: options file open error (%s)\n",file);return 0;}if (comment) fprintf(fp,"# %s\n\n",comment);for (i=0;*opts[i].name;i++) {opt2buf(opts+i,buff);fprintf(fp,"%s\n",buff);}fclose(fp);return 1;
}
10.resetsysopts():重置选项到默认。
extern void resetsysopts(void)
{int i,j;trace(3,"resetsysopts:\n");prcopt_=prcopt_default;solopt_=solopt_default;filopt_.satantp[0]='\0';filopt_.rcvantp[0]='\0';filopt_.stapos [0]='\0';filopt_.geoid  [0]='\0';filopt_.dcb    [0]='\0';filopt_.blq    [0]='\0';filopt_.solstat[0]='\0';filopt_.trace  [0]='\0';for (i=0;i<2;i++) antpostype_[i]=0;elmask_=15.0;elmaskar_=0.0;elmaskhold_=0.0;for (i=0;i<2;i++) for (j=0;j<3;j++) {antpos_[i][j]=0.0;}exsats_[0] ='\0';
}
11.buff2sysopts():选项缓冲区转选项结构体

把选项缓冲区中antpostype_ ,elmask_,elmaskar_,elmaskhold_ ,antpos_ ,exsats_ ,snrmask_ 中的值转到antpostype_ prcopt_ 等结构体中。

12.sysopts2buff():选项结构体转选项缓冲区
static void buff2sysopts(void)
{double pos[3],*rr;char buff[1024],*p,*id;int i,j,sat,*ps;prcopt_.elmin     =elmask_    *D2R;prcopt_.elmaskar  =elmaskar_  *D2R;prcopt_.elmaskhold=elmaskhold_*D2R;for (i=0;i<2;i++) {ps=i==0?&prcopt_.rovpos:&prcopt_.refpos;rr=i==0?prcopt_.ru:prcopt_.rb;if (antpostype_[i]==0) { /* lat/lon/hgt */*ps=0;pos[0]=antpos_[i][0]*D2R;pos[1]=antpos_[i][1]*D2R;pos[2]=antpos_[i][2];pos2ecef(pos,rr);}else if (antpostype_[i]==1) { /* xyz-ecef */*ps=0;rr[0]=antpos_[i][0];rr[1]=antpos_[i][1];rr[2]=antpos_[i][2];}else *ps=antpostype_[i]-1;}/* excluded satellites */for (i=0;i<MAXSAT;i++) prcopt_.exsats[i]=0;if (exsats_[0]!='\0') {strcpy(buff,exsats_);for (p=strtok(buff," ");p;p=strtok(NULL," ")) {if (*p=='+') id=p+1; else id=p;if (!(sat=satid2no(id))) continue;prcopt_.exsats[sat-1]=*p=='+'?2:1;}}/* snrmask */for (i=0;i<NFREQ;i++) {for (j=0;j<9;j++) prcopt_.snrmask.mask[i][j]=0.0;strcpy(buff,snrmask_[i]);for (p=strtok(buff,","),j=0;p&&j<9;p=strtok(NULL,",")) {prcopt_.snrmask.mask[i][j++]=atof(p);}}/* number of frequency (4:L1+L5) */if (prcopt_.nf==4) {prcopt_.nf=3;prcopt_.freqopt=1;}
}
static void sysopts2buff(void)
{double pos[3],*rr;char id[32],*p;int i,j,sat,*ps;elmask_    =prcopt_.elmin     *R2D;elmaskar_  =prcopt_.elmaskar  *R2D;elmaskhold_=prcopt_.elmaskhold*R2D;for (i=0;i<2;i++) {ps=i==0?&prcopt_.rovpos:&prcopt_.refpos;rr=i==0?prcopt_.ru:prcopt_.rb;if (*ps==0) {antpostype_[i]=0;ecef2pos(rr,pos);antpos_[i][0]=pos[0]*R2D;antpos_[i][1]=pos[1]*R2D;antpos_[i][2]=pos[2];}else antpostype_[i]=*ps+1;}/* excluded satellites */exsats_[0]='\0';for (sat=1,p=exsats_;sat<=MAXSAT&&p-exsats_<(int)sizeof(exsats_)-32;sat++) {if (prcopt_.exsats[sat-1]) {satno2id(sat,id);p+=sprintf(p,"%s%s%s",p==exsats_?"":" ",prcopt_.exsats[sat-1]==2?"+":"",id);}}/* snrmask */for (i=0;i<NFREQ;i++) {snrmask_[i][0]='\0';p=snrmask_[i];for (j=0;j<9;j++) {p+=sprintf(p,"%s%.0f",j>0?",":"",prcopt_.snrmask.mask[i][j]);}}/* number of frequency (4:L1+L5) */if (prcopt_.nf==3&&prcopt_.freqopt==1) {prcopt_.nf=4;prcopt_.freqopt=0;}
}
13.getsysopts():获取配置选项

opt_t转到porcopt_t/solopt_t/filopt_t ,先用loadopts()函数从文件中读。

14.setsysopts():保存配置选项

先用saveopts()函数。

extern void getsysopts(prcopt_t *popt, solopt_t *sopt, filopt_t *fopt)
{trace(3,"getsysopts:\n");buff2sysopts();if (popt) *popt=prcopt_;if (sopt) *sopt=solopt_;if (fopt) *fopt=filopt_;
}
extern void setsysopts(const prcopt_t *prcopt, const solopt_t *solopt,const filopt_t *filopt)
{trace(3,"setsysopts:\n");resetsysopts();if (prcopt) prcopt_=*prcopt;if (solopt) solopt_=*solopt;if (filopt) filopt_=*filopt;sysopts2buff();
}

五、Trace

在rtklib.h中加入 #define TRACE,启用trace ,不定义着将trace函数全赋空值,如下:

extern void traceopen(const char *file) {}
extern void traceclose(void) {}
extern void tracelevel(int level) {}
extern void trace   (int level, const char *format, ...) {}
extern void tracet  (int level, const char *format, ...) {}
extern void tracemat(int level, const double *A, int n, int m, int p, int q) {}
extern void traceobs(int level, const obsd_t *obs, int n) {}
extern void tracenav(int level, const nav_t *nav) {}
extern void tracegnav(int level, const nav_t *nav) {}
extern void tracehnav(int level, const nav_t *nav) {}
extern void tracepeph(int level, const nav_t *nav) {}
extern void tracepclk(int level, const nav_t *nav) {}
extern void traceb  (int level, const uint8_t *p, int n) {}

1、rtkcmn.c关于trace的静态全局变量

static FILE *fp_trace=NULL;     //trace的文件指针
static char file_trace[1024];   //trace文件名
static int level_trace=0;       //trace等级(1-5),等级越高输出的信息越多
static uint32_t tick_trace=0;   //以毫米计的系统时间,在tracet()中用到:fprintf(fp_trace,"%d %9.3f: ",level,(tickget()-tick_trace)/1000.0);
static gtime_t time_trace={0};  //打开trace的时间,获取的系统时间,并转为GPST
static lock_t lock_trace;       //trace的进程锁

2、Trace相关函数

1.trace():将传入的trace格式化字符串写入trace文件
extern void trace(int level, const char *format, ...)
{va_list ap;//如果trace等级小于1,写入错误信息到屏幕stderr/* print error message to stderr */if (level<=1) {va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap);}//如果fp_trace为空,或当前trace操作等级高于设置的level_trace,直接返回if (!fp_trace||level>level_trace) return;traceswap();        //如果需要,分文件fprintf(fp_trace,"%d ",level);  //先写入trace等级va_start(ap,format); vfprintf(fp_trace,format,ap); va_end(ap);  //再写入传入的trace格式化字符串fflush(fp_trace);   //缓冲区内容写入文件,清空文件缓冲区
}
2.tracet():写入带秒数的trace格式字符串

相比于trace多写入了trace开始后的秒数(ms级精度)

extern void tracet(int level, const char *format, ...)
{va_list ap;if (!fp_trace||level>level_trace) return;traceswap();fprintf(fp_trace,"%d %9.3f: ",level,(tickget()-tick_trace)/1000.0); //相比于trace,多写入了trace开始后的秒数va_start(ap,format); vfprintf(fp_trace,format,ap); va_end(ap);fflush(fp_trace);
}
3.traceclose():关闭trace文件描述符,将文件指针置空
extern void traceclose(void)
{if (fp_trace&&fp_trace!=stderr) fclose(fp_trace);   //关闭trace文件描述符fp_trace=NULL;      //将文件指针置空file_trace[0]='\0';
}
4.traceopen():创建或打开trace文件
  1. 调用utc2gpst(timeget()) 获取系统时间time,赋值给time_trace。
  2. 调用reppath() 替换传入trace路径的替换符。
  3. 以读的方式创建trace文件,创建失败就用stderr当trace文件。
  4. 调用tickget() ,获取以毫米计的系统时间赋值给tick_trace,
  5. 调用initlock()初始化lock_trace 。
extern void traceopen(const char *file)
{gtime_t time=utc2gpst(timeget());   //获取系统时间,并转为GPSTchar path[1024];reppath(file,path,time,"","");      //替换file替换到path[]//以w方式打开文件,文件不存则创建,存在则重写,返回文件描述符fp_trace,失败就指向stderrif (!*path||!(fp_trace=fopen(path,"w"))) fp_trace=stderr;      strcpy(file_trace,file);tick_trace=tickget();time_trace=time;initlock(&lock_trace);
}
5.tracelevel():将传入的trace等级赋值给level_trace
extern void tracelevel(int level)
{level_trace=level;
}
6.traceswap():根据时间分trace文件
static void traceswap(void)
{gtime_t time=utc2gpst(timeget());   //获取系统时间char path[1024];lock(&lock_trace);  //上锁//如果当前系统时间,如果当前时间的周内秒和当前trace文件的time_trace差距小于一天,直接returnif ((int)(time2gpst(time      ,NULL)/INT_SWAP_TRAC)==(int)(time2gpst(time_trace,NULL)/INT_SWAP_TRAC)) {unlock(&lock_trace);    //解锁,returnreturn;}//如果差别大,创建一个新的trace文件time_trace=time;    if (!reppath(file_trace,path,time,"","")) {unlock(&lock_trace);return;}if (fp_trace) fclose(fp_trace);if (!(fp_trace=fopen(path,"w"))) {fp_trace=stderr;}unlock(&lock_trace);    //解锁
}
7.tracemat():写入矩阵

调用matfprint(),将矩阵写入文件,列优先顺序

extern void matfprint(const double A[], int n, int m, int p, int q, FILE *fp)
{int i,j;for (i=0;i<n;i++) { //列for (j=0;j<m;j++)   //行fprintf(fp," %*.*f",p,q,A[i+j*n]);fprintf(fp,"\n");   //换行}
}
8.traceobs():写入obsd_t

遍历obsd_t数组obs,输出信息

typedef struct {        /* observation data record */gtime_t time;       /* receiver sampling time (GPST) */uint8_t sat,rcv;    /* satellite/receiver number */uint16_t SNR[NFREQ+NEXOBS]; /* signal strength (0.001 dBHz) */  //信噪比uint8_t  LLI[NFREQ+NEXOBS]; /* loss of lock indicator */        //周跳uint8_t 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;
extern void traceobs(int level, const obsd_t *obs, int n)
{char str[64],id[16];int i;if (!fp_trace||level>level_trace) return;   for (i=0;i<n;i++) {time2str(obs[i].time,str,3);    //时间satno2id(obs[i].sat,id);        //卫星ID(Gnn、Cnn、Rnn。。。)fprintf(fp_trace," (%2d) %s %-3s rcv%d %13.3f %13.3f %13.3f %13.3f %d %d %d %d %3.1f %3.1f\n",i+1,str,id,obs[i].rcv,obs[i].L[0],obs[i].L[1],obs[i].P[0],obs[i].P[1],obs[i].LLI[0],obs[i].LLI[1],obs[i].code[0],obs[i].code[1],obs[i].SNR[0]*SNR_UNIT,obs[i].SNR[1]*SNR_UNIT);}fflush(fp_trace);
}
9.tracenav():写入导航电文

写入nav->ephnav->ion_gps/ion_gal/ion_bds电离层信息、星历数据的的信息。

  • tracegnav():写入nav->geph星历信息。

  • tracehnav():写入nav->seph信息。

  • tracepeph() 写入nav->peph 精密星历信息

  • tracepclk():写入nav->pclk 精密钟差信息

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 */eph_t *eph;         /* GPS/QZS/GAL/BDS/IRN 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 */erp_t  erp;         /* earth rotation parameters */double utc_gps[8];  /* GPS delta-UTC parameters {A0,A1,Tot,WNt,dt_LS,WN_LSF,DN,dt_LSF} */double utc_glo[8];  /* GLONASS UTC time parameters {tau_C,tau_GPS} */double utc_gal[8];  /* Galileo UTC parameters */double utc_qzs[8];  /* QZS UTC parameters */double utc_cmp[8];  /* BeiDou UTC parameters */double utc_irn[9];  /* IRNSS UTC parameters {A0,A1,Tot,...,dt_LSF,A2} */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} */double ion_irn[8];  /* IRNSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */int glo_fcn[32];    /* GLONASS FCN + 8 */double cbias[MAXSAT][3]; /* satellite DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */double rbias[MAXRCV][2][3]; /* receiver DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */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 */
} nav_t;
10.traceb():写入buff缓冲区数据

在skytraq.c和ublox.c中被调用。

extern void traceb(int level, const uint8_t *p, int n)
{int i;if (!fp_trace||level>level_trace) return;for (i=0;i<n;i++) fprintf(fp_trace,"%02X%s",*p++,i%8==7?" ":"");fprintf(fp_trace,"\n");
}

更多推荐

RTKLIB源码阅读(四)后处理主函数、rnx2rtkp.c、main函数参数、配置选项、Option文件读取、Trace输出

本文发布于:2024-02-07 04:29:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1753578.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   源码   选项   后处理   参数

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!