├── README.md ├── manual └── B2bLIB User manual.pdf ├── src ├── B2bLIB.c ├── B2bLIB.h ├── B2bMSG.h ├── binex.c ├── convgpx.c ├── convkml.c ├── convrnx.c ├── crescent.c ├── datum.c ├── download.c ├── ephemeris.c ├── geoid.c ├── gis.c ├── ionex.c ├── javad.c ├── lambda.c ├── novatel.c ├── nvs.c ├── options.c ├── pntpos.c ├── postpos.c ├── ppp.c ├── ppp_ar.c ├── preceph.c ├── rcvraw.c ├── rinex.c ├── rnx2rtkp.c ├── rt17.c ├── rtcm.c ├── rtcm2.c ├── rtcm3.c ├── rtcm3e.c ├── rtkcmn.c ├── rtklib.h ├── rtkpos.c ├── rtksvr.c ├── sbas.c ├── septentrio.c ├── skytraq.c ├── solution.c ├── ss2.c ├── stream.c ├── streamsvr.c ├── tides.c ├── tle.c └── ublox.c └── testdata ├── ClkCorr20240824.zip ├── DcbCorr20240824.zip ├── OrbCorr20240824.zip ├── PPPB2b.conf ├── PrnMask20240824.zip ├── WUH22370.zip └── brd42370.zip /README.md: -------------------------------------------------------------------------------- 1 | # B2bLIB 2 | To facilitate user research and application of the PPP-B2b service, a C/C++ decoding package named B2bLIB has been developed. This package is designed to seamlessly integrate with the widely used GNSS software RTKLIB. The B2bLIB is structured into two main components: message decoding and message processing. 3 | -------------------------------------------------------------------------------- /manual/B2bLIB User manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/manual/B2bLIB User manual.pdf -------------------------------------------------------------------------------- /src/B2bLIB.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/src/B2bLIB.c -------------------------------------------------------------------------------- /src/B2bLIB.h: -------------------------------------------------------------------------------- 1 | #include "./rtklib.h" 2 | 3 | 4 | /* B2bLIB function */ 5 | extern int satSlot2Sat(int SatSlot); 6 | extern int sat2Slot(int sat); 7 | extern int add_eph(nav_t* nav, const eph_t* eph); 8 | extern initB2b(nav_t* navs); 9 | extern void readB2bType1(FILE* fp, b2bsat_t* b2bsat, b2bsat_t* b2bsat_pre, gtime_t obstime); 10 | extern void readB2bType2(FILE* fp, b2bsat_t* b2bsat, gtime_t obstime); 11 | extern void readB2bType3(FILE* fp, b2bsat_t* b2bsat, gtime_t obstime); 12 | extern void readB2bType4(FILE* fp, b2bsat_t* b2bsat, gtime_t obstime); 13 | extern int readRinex4Nav(const char* file, nav_t* nav); 14 | extern int satpos_B2b(gtime_t time, gtime_t teph, int sat, const nav_t* nav, 15 | double* rs, double* dts, double* var, int* svh); 16 | extern int ephpos_B2b(gtime_t time, gtime_t teph, int sat, const nav_t* nav, 17 | int iode, double* rs, double* dts, double* var, int* svh); 18 | extern eph_t* selB2beph(gtime_t time, int sat, int iodn, const nav_t* nav); 19 | extern void eph2pos_CNAV(gtime_t time, const eph_t* eph, double* rs, double* dts, 20 | double* var); 21 | extern double varUraB2b(double* ura); 22 | extern int ephpos(gtime_t time, gtime_t teph, int sat, const nav_t* nav, 23 | int iode, double* rs, double* dts, double* var, int* svh); 24 | extern double var_uraeph(int ura); 25 | extern double prange_dualfrequency(const obsd_t* obs, const nav_t* nav, double* var, 26 | const double* dantr, const double* dants, const prcopt_t* opt); 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/B2bMSG.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //GCC 3 | #define MaskBDS 63 // Number of BDS masks 4 | #define MaskGPS 37 // Number of GPS masks 5 | #define MaskGAL 37 // Number of Galileo masks 6 | #define MaskGLO 37 // Number of GLONASS masks 7 | #define MaskNSAT (MaskBDS+MaskGPS+MaskGAL+MaskGLO) // Total satellite masks in B2b_Type1 8 | #define NMODESINGAL 16 // Number of signal tracking modes 9 | #define NINB2bTYPE 86400 // Number of B2b_Type messages per second (one per second) 10 | #define NSAT 168 // max satellite number (1 to MAXSAT) 11 | 12 | 13 | // Incremental parameters for B2b message types 14 | #define MAXORBITCOR 6+1 // Max orbit corrections per Type2 message (+1 to prevent overflow) 15 | #define MAXCLOCKCOR 23 // Max clock corrections per Type4 message 16 | 17 | // Validity periods for B2b corrections 18 | #define MAXAGEB2b 96.0 // Max age of B2b orbit/URA corrections (seconds) 19 | #define MAXAGEB2b_CBIAS 86400 // Max age of B2b code bias corrections (seconds) 20 | #define MAXAGEB2b_CLOCK 12.0 // Max age of B2b clock corrections (seconds) 21 | 22 | // Reference semi-major axes for BDS satellites 23 | #define ArefMEO_BDS 27906100 // Reference semi-major axis (A) for BDS MEO satellites 24 | #define ArefIGSOGEO_BDS 42162200 // Reference semi-major axis (A) for BDS GEO/IGSO satellites 25 | 26 | 27 | typedef struct { /* B2b message type */ 28 | int week, tow; /* reception time (GPS week, time of week) */ 29 | int prn; /* B2b satellite PRN number */ 30 | int type; /* message type */ 31 | int iB2b; /* index within all messages */ 32 | unsigned char msg[61]; /* B2b message (486 bits) */ 33 | } b2bmsg_t; 34 | 35 | typedef struct { /* B2b messages container type */ 36 | int n, nmax; /* current number of messages / max allocated */ 37 | b2bmsg_t* msgs; /* array of B2b messages */ 38 | } b2b_t; 39 | 40 | typedef struct { /* B2b Type1 - Satellite slot information */ 41 | double TodBDT; /* BDT time of day (TOD) */ 42 | gtime_t t0; /* Reference time (GPST) */ 43 | int IodSsr; /* SSR Issue of Data for Type1 */ 44 | int Iodp; /* Issue of Data for phase */ 45 | int iB2b; /* Index in message sequence */ 46 | } B2bType1_t; 47 | 48 | typedef struct { /* B2b Type2 - Orbit correction */ 49 | double TodBDT; /* BDT time of day (TOD) */ 50 | gtime_t t0; /* Reference time (GPST) */ 51 | int IodSsr; /* SSR Issue of Data */ 52 | int IODN; /* Issue of Data for navigation */ 53 | int IodCorr; /* Issue of Data for correction */ 54 | double OrbCorr[3]; /* Orbit corrections: 0:Radial, 1:Along-track, 2:Cross-track */ 55 | double UraClass; /* URA classification */ 56 | double UraValue; /* URA value (m) */ 57 | int iB2b; /* Index in message sequence */ 58 | } B2bType2_t; 59 | 60 | typedef struct { /* B2b Type3 - DCB correction */ 61 | int IodSsr; /* SSR Issue of Data */ 62 | double TodBDT; /* BDT time of day (TOD) */ 63 | gtime_t t0; /* Reference time (GPST) */ 64 | int iB2b; /* Index in message sequence */ 65 | double SatDCB[NMODESINGAL]; /* Satellite DCB corrections: 66 | 0: B1I L1C/A G1C/A; 1: B1C(D) L1_P G1_P E1_B; 67 | 2: B1C(P) G2C/A E1C; 3: null; 68 | 4: B2a(D) L1C(P) E5aQ; 5: B2a(P) L1C(D+P) E5aI; 69 | 6: null; 7: B2b_I L2C(L) E5b_Q; 70 | 8: B2b_Q L2C(M+L) E5b_Q; 9: null; 71 | 10: null; 11: L5I E6_C; 72 | 12: B3I L5_Q; 13: L5_I+Q */ 73 | } B2bType3_t; 74 | 75 | typedef struct { /* B2b Type4 - Clock correction */ 76 | int Iodp; /* Issue of Data for phase */ 77 | int IodSsr; /* SSR Issue of Data */ 78 | double TodBDT; /* BDT time of day (TOD) */ 79 | gtime_t t0; /* Reference time (GPST) */ 80 | double C0; /* Clock correction parameter */ 81 | int IodCorr; /* Issue of Data for correction */ 82 | int iB2b; /* Index in message sequence */ 83 | } B2bType4_t; 84 | 85 | typedef struct { /* B2b correction for current epoch */ 86 | int sat; /* Satellite index */ 87 | B2bType1_t b2btype1;/* Type1 correction data */ 88 | B2bType2_t b2btype2;/* Type2 correction data */ 89 | B2bType3_t b2btype3;/* Type3 correction data */ 90 | B2bType4_t b2btype4;/* Type4 correction data */ 91 | } b2bsatp_t; 92 | 93 | typedef struct { /* B2b satellite corrections container */ 94 | int nsat; /* Number of satellites */ 95 | int SatSlot[MaskNSAT]; /* Satellite slot numbers: 96 | 0-62: BDS; 63-99: GPS; 97 | 100-136: Galileo; 137-173: GLONASS */ 98 | b2bsatp_t b2bsats[MAXSAT]; /* Array of satellite corrections */ 99 | } b2bsat_t; 100 | -------------------------------------------------------------------------------- /src/convgpx.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * convgpx.c : gpx converter 3 | * 4 | * Copyright (C) 2016 by T.TAKASU, All rights reserved. 5 | * 6 | * references : 7 | * [1] GPX The GPS Exchange Format http://www.topografix.com/gpx.asp 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2016/06/11 1.0 new 11 | * 2016/09/18 1.1 modify labels according GPX specs 12 | *-----------------------------------------------------------------------------*/ 13 | #include "rtklib.h" 14 | 15 | /* constants -----------------------------------------------------------------*/ 16 | 17 | #define HEADXML "\n" 18 | #define HEADGPX "\n" 19 | #define TAILGPX "" 20 | 21 | static const char *XMLNS="http://www.topografix.com/GPX/1/1"; 22 | 23 | /* output waypoint -----------------------------------------------------------*/ 24 | static void outpoint(FILE *fp, gtime_t time, const double *pos, 25 | const char *label, int stat, int outalt, int outtime) 26 | { 27 | /* fix, float, sbas and ppp are rtklib extentions to GPX */ 28 | const char *fix_label[]={"fix","float","sbas","dgps","3d","ppp"}; 29 | double ep[6]; 30 | 31 | fprintf(fp,"\n",pos[0]*R2D,pos[1]*R2D); 32 | if (outalt) { 33 | fprintf(fp," %.4f\n",pos[2]-(outalt==2?geoidh(pos):0.0)); 34 | } 35 | if (outtime) { 36 | if (outtime==2) time=gpst2utc(time); 37 | else if (outtime==3) time=timeadd(gpst2utc(time),9*3600.0); 38 | time2epoch(time,ep); 39 | fprintf(fp," \n", 40 | ep[0],ep[1],ep[2],ep[3],ep[4],ep[5]); 41 | } 42 | if (outalt==2) { 43 | fprintf(fp," %.4f\n",geoidh(pos)); 44 | } 45 | if (stat>=1&&stat<=6) { 46 | fprintf(fp," %s\n",fix_label[stat-1]); 47 | } 48 | if (*label) { 49 | fprintf(fp," %s\n",label); 50 | } 51 | fprintf(fp,"\n"); 52 | } 53 | /* output track --------------------------------------------------------------*/ 54 | static void outtrack(FILE *fp, const solbuf_t *solbuf, int outalt, int outtime) 55 | { 56 | gtime_t time; 57 | double pos[3],ep[6]; 58 | int i; 59 | 60 | fprintf(fp,"\n"); 61 | fprintf(fp," \n"); 62 | for (i=0;in;i++) { 63 | ecef2pos(solbuf->data[i].rr,pos); 64 | fprintf(fp," \n",pos[0]*R2D, 65 | pos[1]*R2D); 66 | if (outalt) { 67 | fprintf(fp," %.4f\n",pos[2]-(outalt==2?geoidh(pos):0.0)); 68 | } 69 | if (outtime) { 70 | time=solbuf->data[i].time; 71 | if (outtime==2) time=gpst2utc(time); 72 | else if (outtime==3) time=timeadd(gpst2utc(time),9*3600.0); 73 | time2epoch(time,ep); 74 | fprintf(fp," \n", 75 | ep[0],ep[1],ep[2],ep[3],ep[4],ep[5]); 76 | } 77 | if (outalt==2) { 78 | fprintf(fp," %.4f\n",geoidh(pos)); 79 | } 80 | fprintf(fp," \n"); 81 | } 82 | fprintf(fp," \n"); 83 | fprintf(fp,"\n"); 84 | } 85 | /* save gpx file -------------------------------------------------------------*/ 86 | static int savegpx(const char *file, const solbuf_t *solbuf, int outtrk, 87 | int outpnt, int outalt, int outtime) 88 | { 89 | FILE *fp; 90 | double pos[3]; 91 | int i; 92 | 93 | if (!(fp=fopen(file,"w"))) { 94 | fprintf(stderr,"file open error : %s\n",file); 95 | return 0; 96 | } 97 | fprintf(fp,HEADXML); 98 | fprintf(fp,HEADGPX,"RTKLIB " VER_RTKLIB,XMLNS); 99 | 100 | /* output waypoint */ 101 | if (outpnt) { 102 | for (i=0;in;i++) { 103 | ecef2pos(solbuf->data[i].rr,pos); 104 | outpoint(fp,solbuf->data[i].time,pos,"",solbuf->data[i].stat,outalt, 105 | outtime); 106 | } 107 | } 108 | /* output waypoint of ref position */ 109 | if (norm(solbuf->rb,3)>0.0) { 110 | ecef2pos(solbuf->rb,pos); 111 | outpoint(fp,solbuf->data[0].time,pos,"Reference Position",0,outalt,0); 112 | } 113 | /* output track */ 114 | if (outtrk) { 115 | outtrack(fp,solbuf,outalt,outtime); 116 | } 117 | fprintf(fp,"%s\n",TAILGPX); 118 | fclose(fp); 119 | return 1; 120 | } 121 | /* convert to GPX file --------------------------------------------------------- 122 | * convert solutions to GPX file [1] 123 | * args : char *infile I input solutions file 124 | * char *outfile I output google earth kml file ("":.kml) 125 | * gtime_t ts,te I start/end time (gpst) 126 | * int tint I time interval (s) (0.0:all) 127 | * int qflg I quality flag (0:all) 128 | * double *offset I add offset {east,north,up} (m) 129 | * int outtrk I output track (0:off,1:on) 130 | * int outpnt I output waypoint (0:off,1:on) 131 | * int outalt I output altitude (0:off,1:elipsoidal,2:geodetic) 132 | * int outtime I output time (0:off,1:gpst,2:utc,3:jst) 133 | * return : status (0:ok,-1:file read,-2:file format,-3:no data,-4:file write) 134 | *-----------------------------------------------------------------------------*/ 135 | extern int convgpx(const char *infile, const char *outfile, gtime_t ts, 136 | gtime_t te, double tint, int qflg, double *offset, 137 | int outtrk, int outpnt, int outalt, int outtime) 138 | { 139 | solbuf_t solbuf={0}; 140 | double rr[3]={0},pos[3],dr[3]; 141 | int i,j; 142 | char *p,file[1024]; 143 | 144 | trace(3,"convgpx : infile=%s outfile=%s\n",infile,outfile); 145 | 146 | if (!*outfile) { 147 | if ((p=strrchr(infile,'.'))) { 148 | strncpy(file,infile,p-infile); 149 | strcpy(file+(p-infile),".gpx"); 150 | } 151 | else sprintf(file,"%s.gpx",infile); 152 | } 153 | else strcpy(file,outfile); 154 | 155 | /* read solution file */ 156 | if (!readsolt((char **)&infile,1,ts,te,tint,qflg,&solbuf)) return -1; 157 | 158 | /* mean position */ 159 | for (i=0;i<3;i++) { 160 | for (j=0;j0.0) { 170 | for (i=0;i<3;i++) solbuf.rb[i]+=dr[i]; 171 | } 172 | /* save gpx file */ 173 | return savegpx(file,&solbuf,outtrk,outpnt,outalt,outtime)?0:-4; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /src/convkml.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * convkml.c : google earth kml converter 3 | * 4 | * Copyright (C) 2007-2017 by T.TAKASU, All rights reserved. 5 | * 6 | * references : 7 | * [1] Open Geospatial Consortium Inc., OGC 07-147r2, OGC(R) KML, 2008-04-14 8 | * 9 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 10 | * history : 2007/01/20 1.0 new 11 | * 2007/03/15 1.1 modify color sequence 12 | * 2007/04/03 1.2 add geodetic height option 13 | * support input of NMEA GGA sentence 14 | * delete altitude info for track 15 | * add time stamp option 16 | * separate readsol.c file 17 | * 2009/01/19 1.3 fix bug on display mark with by-q-flag option 18 | * 2010/05/10 1.4 support api readsolt() change 19 | * 2010/08/14 1.5 fix bug on readsolt() (2.4.0_p3) 20 | * 2017/06/10 1.6 support wild-card in input file 21 | *-----------------------------------------------------------------------------*/ 22 | #include "rtklib.h" 23 | 24 | /* constants -----------------------------------------------------------------*/ 25 | 26 | #define SIZP 0.2 /* mark size of rover positions */ 27 | #define SIZR 0.3 /* mark size of reference position */ 28 | #define TINT 60.0 /* time label interval (sec) */ 29 | 30 | static const char *head1=""; 31 | static const char *head2=""; 32 | static const char *mark="http://maps.google.com/mapfiles/kml/pal2/icon18.png"; 33 | 34 | /* output track --------------------------------------------------------------*/ 35 | static void outtrack(FILE *f, const solbuf_t *solbuf, const char *color, 36 | int outalt, int outtime) 37 | { 38 | double pos[3]; 39 | int i; 40 | 41 | fprintf(f,"\n"); 42 | fprintf(f,"Rover Track\n"); 43 | fprintf(f,"\n"); 48 | fprintf(f,"\n"); 49 | if (outalt) fprintf(f,"absolute\n"); 50 | fprintf(f,"\n"); 51 | for (i=0;in;i++) { 52 | ecef2pos(solbuf->data[i].rr,pos); 53 | if (outalt==0) pos[2]=0.0; 54 | else if (outalt==2) pos[2]-=geoidh(pos); 55 | fprintf(f,"%13.9f,%12.9f,%5.3f\n",pos[1]*R2D,pos[0]*R2D,pos[2]); 56 | } 57 | fprintf(f,"\n"); 58 | fprintf(f,"\n"); 59 | fprintf(f,"\n"); 60 | } 61 | /* output point --------------------------------------------------------------*/ 62 | static void outpoint(FILE *fp, gtime_t time, const double *pos, 63 | const char *label, int style, int outalt, int outtime) 64 | { 65 | double ep[6],alt=0.0; 66 | char str[256]=""; 67 | 68 | fprintf(fp,"\n"); 69 | if (*label) fprintf(fp,"%s\n",label); 70 | fprintf(fp,"#P%d\n",style); 71 | if (outtime) { 72 | if (outtime==2) time=gpst2utc(time); 73 | else if (outtime==3) time=timeadd(gpst2utc(time),9*3600.0); 74 | time2epoch(time,ep); 75 | if (!*label&&fmod(ep[5]+0.005,TINT)<0.01) { 76 | sprintf(str,"%02.0f:%02.0f",ep[3],ep[4]); 77 | fprintf(fp,"%s\n",str); 78 | } 79 | sprintf(str,"%04.0f-%02.0f-%02.0fT%02.0f:%02.0f:%05.2fZ", 80 | ep[0],ep[1],ep[2],ep[3],ep[4],ep[5]); 81 | fprintf(fp,"%s\n",str); 82 | } 83 | fprintf(fp,"\n"); 84 | if (outalt) { 85 | fprintf(fp,"1\n"); 86 | fprintf(fp,"absolute\n"); 87 | alt=pos[2]-(outalt==2?geoidh(pos):0.0); 88 | } 89 | fprintf(fp,"%13.9f,%12.9f,%5.3f\n",pos[1]*R2D, 90 | pos[0]*R2D,alt); 91 | fprintf(fp,"\n"); 92 | fprintf(fp,"\n"); 93 | } 94 | /* save kml file -------------------------------------------------------------*/ 95 | static int savekml(const char *file, const solbuf_t *solbuf, int tcolor, 96 | int pcolor, int outalt, int outtime) 97 | { 98 | FILE *fp; 99 | double pos[3]; 100 | int i,qcolor[]={0,1,2,5,4,3,0}; 101 | char *color[]={ 102 | "ffffffff","ff008800","ff00aaff","ff0000ff","ff00ffff","ffff00ff" 103 | }; 104 | if (!(fp=fopen(file,"w"))) { 105 | fprintf(stderr,"file open error : %s\n",file); 106 | return 0; 107 | } 108 | fprintf(fp,"%s\n%s\n",head1,head2); 109 | fprintf(fp,"\n"); 110 | for (i=0;i<6;i++) { 111 | fprintf(fp,"\n"); 118 | } 119 | if (tcolor>0) { 120 | outtrack(fp,solbuf,color[tcolor-1],outalt,outtime); 121 | } 122 | if (pcolor>0) { 123 | fprintf(fp,"\n"); 124 | fprintf(fp," Rover Position\n"); 125 | for (i=0;in;i++) { 126 | ecef2pos(solbuf->data[i].rr,pos); 127 | outpoint(fp,solbuf->data[i].time,pos,"", 128 | pcolor==5?qcolor[solbuf->data[i].stat]:pcolor-1,outalt,outtime); 129 | } 130 | fprintf(fp,"\n"); 131 | } 132 | if (norm(solbuf->rb,3)>0.0) { 133 | ecef2pos(solbuf->rb,pos); 134 | outpoint(fp,solbuf->data[0].time,pos,"Reference Position",0,outalt,0); 135 | } 136 | fprintf(fp,"\n"); 137 | fprintf(fp,"\n"); 138 | fclose(fp); 139 | return 1; 140 | } 141 | /* convert to google earth kml file -------------------------------------------- 142 | * convert solutions to google earth kml file 143 | * args : char *infile I input solutions file (wild-card (*) is expanded) 144 | * char *outfile I output google earth kml file ("":.kml) 145 | * gtime_t ts,te I start/end time (gpst) 146 | * int tint I time interval (s) (0.0:all) 147 | * int qflg I quality flag (0:all) 148 | * double *offset I add offset {east,north,up} (m) 149 | * int tcolor I track color 150 | * (0:none,1:white,2:green,3:orange,4:red,5:yellow) 151 | * int pcolor I point color 152 | * (0:none,1:white,2:green,3:orange,4:red,5:by qflag) 153 | * int outalt I output altitude (0:off,1:elipsoidal,2:geodetic) 154 | * int outtime I output time (0:off,1:gpst,2:utc,3:jst) 155 | * return : status (0:ok,-1:file read,-2:file format,-3:no data,-4:file write) 156 | * notes : see ref [1] for google earth kml file format 157 | *-----------------------------------------------------------------------------*/ 158 | extern int convkml(const char *infile, const char *outfile, gtime_t ts, 159 | gtime_t te, double tint, int qflg, double *offset, 160 | int tcolor, int pcolor, int outalt, int outtime) 161 | { 162 | solbuf_t solbuf={0}; 163 | double rr[3]={0},pos[3],dr[3]; 164 | int i,j,nfile,stat; 165 | char *p,file[1024],*files[MAXEXFILE]={0}; 166 | 167 | trace(3,"convkml : infile=%s outfile=%s\n",infile,outfile); 168 | 169 | /* expand wild-card of infile */ 170 | for (i=0;i=0;i--) free(files[i]); 173 | return -4; 174 | } 175 | } 176 | if ((nfile=expath(infile,files,MAXEXFILE))<=0) { 177 | for (i=0;i0.0) { 209 | for (i=0;i<3;i++) solbuf.rb[i]+=dr[i]; 210 | } 211 | /* save kml file */ 212 | return savekml(file,&solbuf,tcolor,pcolor,outalt,outtime)?0:-4; 213 | } 214 | -------------------------------------------------------------------------------- /src/datum.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * datum.c : datum transformation 3 | * 4 | * Copyright (C) 2007 by T.TAKASU, All rights reserved. 5 | * 6 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 7 | * history : 2007/02/08 1.0 new 8 | *-----------------------------------------------------------------------------*/ 9 | #include "rtklib.h" 10 | 11 | #define MAXPRM 400000 /* max number of parameter records */ 12 | 13 | typedef struct { /* datum trans parameter type */ 14 | int code; /* mesh code */ 15 | float db,dl; /* difference of latitude/longitude (sec) */ 16 | } tprm_t; 17 | 18 | static tprm_t *prm=NULL; /* datum trans parameter table */ 19 | static int n=0; /* datum trans parameter table size */ 20 | 21 | /* compare datum trans parameters --------------------------------------------*/ 22 | static int cmpprm(const void *p1, const void *p2) 23 | { 24 | tprm_t *q1=(tprm_t *)p1,*q2=(tprm_t *)p2; 25 | return q1->code-q2->code; 26 | } 27 | /* search datum trans parameter ----------------------------------------------*/ 28 | static int searchprm(double lat, double lon) 29 | { 30 | int i,j,k,n1,m1,n2,m2,code; 31 | 32 | lon-=6000.0; 33 | n1=(int)(lat/40.0); lat-=n1*40.0; 34 | m1=(int)(lon/60.0); lon-=m1*60.0; 35 | n2=(int)(lat/5.0); lat-=n2*5.0; 36 | m2=(int)(lon/7.5); lon-=m2*7.5; 37 | code=n1*1000000+m1*10000+n2*1000+m2*100+(int)(lat/0.5)*10+(int)(lon/0.75); 38 | 39 | for (i=0,j=n-1;i:error) 68 | * notes : parameters file shall comply with GSI TKY2JGD.par 69 | *-----------------------------------------------------------------------------*/ 70 | extern int loaddatump(const char *file) 71 | { 72 | FILE *fp; 73 | char buff[256]; 74 | 75 | if (n>0) return 0; /* already loaded */ 76 | 77 | if (!(fp=fopen(file,"r"))) { 78 | fprintf(stderr,"%s : datum prm file open error : %s\n",__FILE__,file); 79 | return -1; 80 | } 81 | if (!(prm=(tprm_t *)malloc(sizeof(tprm_t)*MAXPRM))) { 82 | fprintf(stderr,"%s : memory allocation error\n",__FILE__); 83 | return -1; 84 | } 85 | while (fgets(buff,sizeof(buff),fp)&&n=3) n++; 87 | } 88 | fclose(fp); 89 | qsort(prm,n,sizeof(tprm_t),cmpprm); /* sort parameter table */ 90 | return 0; 91 | } 92 | /* tokyo datum to JGD2000 datum ------------------------------------------------ 93 | * transform position in Tokyo datum to JGD2000 datum 94 | * args : double *pos I position in Tokyo datum {lat,lon,h} (rad,m) 95 | * O position in JGD2000 datum {lat,lon,h} (rad,m) 96 | * return : status (0:ok,0>:error,out of range) 97 | * notes : before calling, call loaddatump() to set parameter table 98 | *-----------------------------------------------------------------------------*/ 99 | extern int tokyo2jgd(double *pos) 100 | { 101 | double post[2],dpos[2]; 102 | 103 | post[0]=pos[0]; 104 | post[1]=pos[1]; 105 | if (dlatdlon(post,dpos)) return -1; 106 | pos[0]=post[0]+dpos[0]; 107 | pos[1]=post[1]+dpos[1]; 108 | return 0; 109 | } 110 | /* JGD2000 datum to Tokyo datum ------------------------------------------------ 111 | * transform position in JGD2000 datum to Tokyo datum 112 | * args : double *pos I position in JGD2000 datum {lat,lon,h} (rad,m) 113 | * O position in Tokyo datum {lat,lon,h} (rad,m) 114 | * return : status (0:ok,0>:error,out of range) 115 | * notes : before calling, call loaddatump() to set parameter table 116 | *-----------------------------------------------------------------------------*/ 117 | extern int jgd2tokyo(double *pos) 118 | { 119 | double posj[2],dpos[2]; 120 | int i; 121 | 122 | posj[0]=pos[0]; 123 | posj[1]=pos[1]; 124 | for (i=0;i<2;i++) { 125 | if (dlatdlon(pos,dpos)) return -1; 126 | pos[0]=posj[0]-dpos[0]; 127 | pos[1]=posj[1]-dpos[1]; 128 | } 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /src/gis.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * gis.c: GIS data functions 3 | * 4 | * Copyright (C) 2016 by T.TAKASU, All rights reserved. 5 | * 6 | * references: 7 | * [1] ESRI Shapefile Technical Description, An ESRI White Paper, July, 1998 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2016/06/10 1.0 new 11 | * 2016/07/31 1.1 add boundary of polyline and polygon 12 | *-----------------------------------------------------------------------------*/ 13 | #include "rtklib.h" 14 | 15 | #define SHAPE_CODE 9994 /* shapefile code */ 16 | 17 | /* get integer big-endian ----------------------------------------------------*/ 18 | static int I4_B(uint8_t *buff) 19 | { 20 | int i,val=0; 21 | uint8_t *p=buff,*q=(uint8_t *)&val+3; 22 | 23 | for (i=0;i<4;i++) { 24 | *q--=*p++; 25 | } 26 | return val; 27 | } 28 | /* get integer little-endian -------------------------------------------------*/ 29 | static int I4_L(uint8_t *buff) 30 | { 31 | int val; 32 | 33 | memcpy(&val,buff,4); 34 | return val; 35 | } 36 | /* get double little-endian --------------------------------------------------*/ 37 | static double D8_L(uint8_t *buff) 38 | { 39 | double val; 40 | 41 | memcpy(&val,buff,8); 42 | return val; 43 | } 44 | /* read shapefile header -----------------------------------------------------*/ 45 | static int read_shape_head(FILE *fp) 46 | { 47 | uint8_t buff[128]; 48 | 49 | if (fread(buff,100,1,fp)!=1) { 50 | return -1; 51 | } 52 | if (I4_B(buff)!=SHAPE_CODE) { 53 | return -1; 54 | } 55 | return I4_L(buff+32); 56 | } 57 | /* initialize boundary -------------------------------------------------------*/ 58 | static void init_bound(double *bound) 59 | { 60 | bound[0]= PI/2.0; 61 | bound[1]=-PI/2.0; 62 | bound[2]= PI; 63 | bound[3]=-PI; 64 | } 65 | /* update boundary -----------------------------------------------------------*/ 66 | static void update_bound(const double *pos, double *bound) 67 | { 68 | if (pos[0]bound[1]) bound[1]=pos[0]; 70 | if (pos[1]bound[3]) bound[3]=pos[1]; 72 | } 73 | /* add gis data --------------------------------------------------------------*/ 74 | static int gis_add(gisd_t **p, int type, void *data) 75 | { 76 | gisd_t *new_data; 77 | 78 | if (!(new_data=(gisd_t *)malloc(sizeof(gisd_t)))) { 79 | return 0; 80 | } 81 | new_data->next=*p; 82 | new_data->type=type; 83 | new_data->data=data; 84 | *p=new_data; 85 | return 1; 86 | } 87 | /* read point data -----------------------------------------------------------*/ 88 | static int read_pnt(FILE *fp, double *bound, gisd_t **p) 89 | { 90 | gis_pnt_t *pnt; 91 | double pos[3]={0}; 92 | uint8_t buff[16]; 93 | 94 | if (fread(buff,16,1,fp)!=1) { 95 | return 0; 96 | } 97 | if (!(pnt=(gis_pnt_t *)malloc(sizeof(gis_pnt_t)))) { 98 | return 0; 99 | } 100 | pos[0]=D8_L(buff+8)*D2R; 101 | pos[1]=D8_L(buff )*D2R; 102 | update_bound(pos,bound); 103 | pos2ecef(pos,pnt->pos); 104 | 105 | return gis_add(p,1,pnt); 106 | } 107 | /* read multi-point data ------------------------------------------------------*/ 108 | static int read_mpnt(FILE *fp, double *bound, gisd_t **p) 109 | { 110 | uint8_t buff[36]; 111 | int i,np; 112 | 113 | if (fread(buff,36,1,fp)!=1) { 114 | return 0; 115 | } 116 | np=I4_L(buff+32); 117 | 118 | for (i=0;ipos=(double *)malloc(sizeof(double)*nr*3))) { 154 | free(poly); 155 | free(part); 156 | return 0; 157 | } 158 | init_bound(poly->bound); 159 | 160 | for (j=n=0;jpos); 163 | free(poly); 164 | free(part); 165 | return 0; 166 | } 167 | pos[0]=D8_L(buff+8)*D2R; 168 | pos[1]=D8_L(buff )*D2R; 169 | if (pos[0]<-1E16||pos[1]<-1E16) { 170 | continue; 171 | } 172 | update_bound(pos,poly->bound); 173 | update_bound(pos,bound); 174 | pos2ecef(pos,poly->pos+n*3); 175 | n++; 176 | } 177 | poly->npnt=n; 178 | if (!gis_add(p,2,(void *)poly)) { 179 | free(poly->pos); 180 | free(poly); 181 | free(part); 182 | return 0; 183 | } 184 | } 185 | free(part); 186 | return 1; 187 | } 188 | /* read polygon data ---------------------------------------------------------*/ 189 | static int read_polygon(FILE *fp, double *bound, gisd_t **p) 190 | { 191 | gis_polygon_t *polygon; 192 | double pos[3]={0}; 193 | uint8_t buff[40]; 194 | int i,j,nt,np,nr,n,*part; 195 | 196 | if (fread(buff,40,1,fp)!=1) { 197 | return 0; 198 | } 199 | nt=I4_L(buff+32); 200 | np=I4_L(buff+36); 201 | 202 | if (!(part=(int *)malloc(sizeof(int)*nt))) { 203 | return 0; 204 | } 205 | for (i=0;ipos=(double *)malloc(sizeof(double)*nr*3))) { 217 | free(polygon); 218 | free(part); 219 | return 0; 220 | } 221 | init_bound(polygon->bound); 222 | 223 | for (j=n=0;jpos); 226 | free(polygon); 227 | free(part); 228 | return 0; 229 | } 230 | pos[0]=D8_L(buff+8)*D2R; 231 | pos[1]=D8_L(buff )*D2R; 232 | if (pos[0]<-1E16||pos[1]<-1E16) { 233 | continue; 234 | } 235 | update_bound(pos,polygon->bound); 236 | update_bound(pos,bound); 237 | pos2ecef(pos,polygon->pos+n*3); 238 | n++; 239 | } 240 | polygon->npnt=n; 241 | if (!gis_add(p,3,(void *)polygon)) { 242 | free(polygon->pos); 243 | free(polygon); 244 | free(part); 245 | return 0; 246 | } 247 | } 248 | free(part); 249 | return 1; 250 | } 251 | /* read shapefile records ----------------------------------------------------*/ 252 | static int gis_read_record(FILE *fp, FILE *fp_idx, int type, double *bound, 253 | gisd_t **data) 254 | { 255 | gisd_t *p,*next; 256 | uint8_t buff[16]; 257 | int i,off,num,len1,len2,typ2; 258 | 259 | for (i=0;fread(buff,1,8,fp_idx)==8;i++) { 260 | off =I4_B(buff )*2; 261 | len1=I4_B(buff+4)*2; 262 | 263 | if (fseek(fp,(long)off,SEEK_SET)<0||fread(buff,12,1,fp)!=1) { 264 | return 0; 265 | } 266 | num =I4_B(buff ); 267 | len2=I4_B(buff+4)*2; 268 | typ2=I4_L(buff+8); 269 | 270 | if (num!=i+1||len1!=len2||type!=typ2) { 271 | trace(2,"shapefile record error n=%d %d len=%d %d type=%d %d\n", 272 | i+1,num,len1,len2,type,typ2); 273 | continue; 274 | } 275 | if (type==1) { /* point */ 276 | read_pnt(fp,bound,data); 277 | } 278 | else if (type==8) { /* multi-point */ 279 | read_mpnt(fp,bound,data); 280 | } 281 | else if (type==3) { /* polyline */ 282 | read_poly(fp,bound,data); 283 | } 284 | else if (type==5) { /* polygon */ 285 | read_polygon(fp,bound,data); 286 | } 287 | else { /* skip record */ 288 | for (i=0;inext; 296 | p->next=*data; 297 | *data=p; 298 | } 299 | return 1; 300 | } 301 | /* read gis data from shapefile ------------------------------------------------ 302 | * read gis data from shapefile (ref [1]) 303 | * args : char *file I shapefile 304 | * gis_t *gis IO GIS data 305 | * return : status (0:error) 306 | * notes : only support point, multipoint, polyline and polygon. 307 | * only support lat-lon for map projection. 308 | *-----------------------------------------------------------------------------*/ 309 | extern int gis_read(const char *file, gis_t *gis, int layer) 310 | { 311 | FILE *fp,*fp_idx; 312 | char path[1024],*p,*q; 313 | int type1=0,type2=0; 314 | 315 | trace(3,"gis_read file=%s layer=%d\n",file,layer); 316 | 317 | strcpy(path,file); 318 | 319 | if ((p=strrchr(path,'.'))) { 320 | sprintf(p,".shx"); 321 | } 322 | else { 323 | sprintf(path+strlen(path),".shx"); 324 | } 325 | if (!(fp=fopen(file,"rb"))) { /* shapefile */ 326 | trace(2,"shapefile open error: %s\n",file); 327 | return 0; 328 | } 329 | if (!(fp_idx=fopen(path,"rb"))) { /* index file */ 330 | fclose(fp); 331 | trace(2,"shapefile index open error: %s\n",path); 332 | return 0; 333 | } 334 | /* read header */ 335 | if ((type1=read_shape_head(fp))<0||(type2=read_shape_head(fp_idx))<0|| 336 | type1!=type2) { 337 | trace(2,"shapefile header error: %s type=%d %d\n",file,type1,type2); 338 | fclose(fp); 339 | fclose(fp_idx); 340 | return 0; 341 | } 342 | init_bound(gis->bound); 343 | 344 | /* read records */ 345 | if (!gis_read_record(fp,fp_idx,type1,gis->bound,gis->data+layer)) { 346 | fclose(fp); 347 | fclose(fp_idx); 348 | return 0; 349 | } 350 | fclose(fp); 351 | fclose(fp_idx); 352 | gis->name[layer][0]='\0'; 353 | gis->flag[layer]=1; 354 | return 1; 355 | } 356 | /* free gis-data --------------------------------------------------------------- 357 | * free and initialize gis data 358 | * args : gis_t *gis IO gis data 359 | * return : none 360 | *-----------------------------------------------------------------------------*/ 361 | extern void gis_free(gis_t *gis) 362 | { 363 | gisd_t *data,*next; 364 | int i; 365 | 366 | for (i=0;idata[i];data;data=next) { 368 | next=data->next; 369 | if (data->type==2) { 370 | free(((gis_poly_t *)data->data)->pos); 371 | } 372 | else if (data->type==3) { 373 | free(((gis_polygon_t *)data->data)->pos); 374 | } 375 | free(data); 376 | } 377 | gis->data[i]=NULL; 378 | gis->name[i][0]='\0'; 379 | gis->flag[i]=0; 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/ionex.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * ionex.c : ionex functions 3 | * 4 | * Copyright (C) 2011-2013 by T.TAKASU, All rights reserved. 5 | * 6 | * references: 7 | * [1] S.Schear, W.Gurtner and J.Feltens, IONEX: The IONosphere Map EXchange 8 | * Format Version 1, February 25, 1998 9 | * [2] S.Schaer, R.Markus, B.Gerhard and A.S.Timon, Daily Global Ionosphere 10 | * Maps based on GPS Carrier Phase Data Routinely producted by CODE 11 | * Analysis Center, Proceeding of the IGS Analysis Center Workshop, 1996 12 | * 13 | * version : $Revision:$ $Date:$ 14 | * history : 2011/03/29 1.0 new 15 | * 2013/03/05 1.1 change api readtec() 16 | * fix problem in case of lat>85deg or lat<-85deg 17 | * 2014/02/22 1.2 fix problem on compiled as C++ 18 | *-----------------------------------------------------------------------------*/ 19 | #include "rtklib.h" 20 | 21 | #define SQR(x) ((x)*(x)) 22 | #define VAR_NOTEC SQR(30.0) /* variance of no tec */ 23 | #define MIN_EL 0.0 /* min elevation angle (rad) */ 24 | #define MIN_HGT -1000.0 /* min user height (m) */ 25 | 26 | /* get index -----------------------------------------------------------------*/ 27 | static int getindex(double value, const double *range) 28 | { 29 | if (range[2]==0.0) return 0; 30 | if (range[1]>0.0&&(valuent>=nav->ntmax) { 61 | nav->ntmax+=256; 62 | if (!(nav_tec=(tec_t *)realloc(nav->tec,sizeof(tec_t)*nav->ntmax))) { 63 | trace(1,"readionex malloc error ntmax=%d\n",nav->ntmax); 64 | free(nav->tec); nav->tec=NULL; nav->nt=nav->ntmax=0; 65 | return NULL; 66 | } 67 | nav->tec=nav_tec; 68 | } 69 | p=nav->tec+nav->nt; 70 | p->time=time0; 71 | p->rb=rb; 72 | for (i=0;i<3;i++) { 73 | p->ndata[i]=ndata[i]; 74 | p->lats[i]=lats[i]; 75 | p->lons[i]=lons[i]; 76 | p->hgts[i]=hgts[i]; 77 | } 78 | n=ndata[0]*ndata[1]*ndata[2]; 79 | 80 | if (!(p->data=(double *)malloc(sizeof(double)*n))|| 81 | !(p->rms =(float *)malloc(sizeof(float )*n))) { 82 | return NULL; 83 | } 84 | for (i=0;idata[i]=0.0; 86 | p->rms [i]=0.0f; 87 | } 88 | nav->nt++; 89 | return p; 90 | } 91 | /* read ionex dcb aux data ----------------------------------------------------*/ 92 | static void readionexdcb(FILE *fp, double *dcb, double *rms) 93 | { 94 | int i,sat; 95 | char buff[1024],id[32],*label; 96 | 97 | trace(3,"readionexdcb:\n"); 98 | 99 | for (i=0;int-1;i>=0;i--) { 205 | if (fabs(timediff(time,nav->tec[i].time))>=1.0) continue; 206 | p=nav->tec+i; 207 | break; 208 | } 209 | } 210 | else if (p) p->time=time; 211 | } 212 | else if (strstr(label,"LAT/LON1/LON2/DLON/H")==label&&p) { 213 | lat =str2num(buff, 2,6); 214 | lon[0]=str2num(buff, 8,6); 215 | lon[1]=str2num(buff,14,6); 216 | lon[2]=str2num(buff,20,6); 217 | hgt =str2num(buff,26,6); 218 | 219 | i=getindex(lat,p->lats); 220 | k=getindex(hgt,p->hgts); 221 | n=nitem(lon); 222 | 223 | for (m=0;mlons); 227 | if ((index=dataindex(i,j,k,p->ndata))<0) continue; 228 | 229 | if ((x=str2num(buff,m%16*5,5))==9999.0) continue; 230 | 231 | if (type==1) p->data[index]=x*pow(10.0,nexp); 232 | else p->rms[index]=(float)(x*pow(10.0,nexp)); 233 | } 234 | } 235 | } 236 | return 1; 237 | } 238 | /* combine tec grid data -----------------------------------------------------*/ 239 | static void combtec(nav_t *nav) 240 | { 241 | tec_t tmp; 242 | int i,j,n=0; 243 | 244 | trace(3,"combtec : nav->nt=%d\n",nav->nt); 245 | 246 | for (i=0;int-1;i++) { 247 | for (j=i+1;jnt;j++) { 248 | if (timediff(nav->tec[j].time,nav->tec[i].time)<0.0) { 249 | tmp=nav->tec[i]; 250 | nav->tec[i]=nav->tec[j]; 251 | nav->tec[j]=tmp; 252 | } 253 | } 254 | } 255 | for (i=0;int;i++) { 256 | if (i>0&&timediff(nav->tec[i].time,nav->tec[n-1].time)==0.0) { 257 | free(nav->tec[n-1].data); 258 | free(nav->tec[n-1].rms ); 259 | nav->tec[n-1]=nav->tec[i]; 260 | continue; 261 | } 262 | nav->tec[n++]=nav->tec[i]; 263 | } 264 | nav->nt=n; 265 | 266 | trace(4,"combtec : nav->nt=%d\n",nav->nt); 267 | } 268 | /* read ionex tec grid file ---------------------------------------------------- 269 | * read ionex ionospheric tec grid file 270 | * args : char *file I ionex tec grid file 271 | * (wind-card * is expanded) 272 | * nav_t *nav IO navigation data 273 | * nav->nt, nav->ntmax and nav->tec are modified 274 | * int opt I read option (1: no clear of tec data,0:clear) 275 | * return : none 276 | * notes : see ref [1] 277 | *-----------------------------------------------------------------------------*/ 278 | extern void readtec(const char *file, nav_t *nav, int opt) 279 | { 280 | FILE *fp; 281 | double lats[3]={0},lons[3]={0},hgts[3]={0},rb=0.0,nexp=-1.0; 282 | double dcb[MAXSAT]={0},rms[MAXSAT]={0}; 283 | int i,n; 284 | char *efiles[MAXEXFILE]; 285 | 286 | trace(3,"readtec : file=%s\n",file); 287 | 288 | /* clear of tec grid data option */ 289 | if (!opt) { 290 | free(nav->tec); nav->tec=NULL; nav->nt=nav->ntmax=0; 291 | } 292 | for (i=0;i=0;i--) free(efiles[i]); 295 | return; 296 | } 297 | } 298 | /* expand wild card in file path */ 299 | n=expath(file,efiles,MAXEXFILE); 300 | 301 | for (i=0;int>0) combtec(nav); 320 | 321 | /* P1-P2 dcb */ 322 | for (i=0;icbias[i][0]=CLIGHT*dcb[i]*1E-9; /* ns->m */ 324 | } 325 | } 326 | /* interpolate tec grid data -------------------------------------------------*/ 327 | static int interptec(const tec_t *tec, int k, const double *posp, double *value, 328 | double *rms) 329 | { 330 | double dlat,dlon,a,b,d[4]={0},r[4]={0}; 331 | int i,j,n,index; 332 | 333 | trace(3,"interptec: k=%d posp=%.2f %.2f\n",k,posp[0]*R2D,posp[1]*R2D); 334 | *value=*rms=0.0; 335 | 336 | if (tec->lats[2]==0.0||tec->lons[2]==0.0) return 0; 337 | 338 | dlat=posp[0]*R2D-tec->lats[0]; 339 | dlon=posp[1]*R2D-tec->lons[0]; 340 | if (tec->lons[2]>0.0) dlon-=floor( dlon/360)*360.0; /* 0<=dlon<360 */ 341 | else dlon+=floor(-dlon/360)*360.0; /* -360lats[2]; 344 | b=dlon/tec->lons[2]; 345 | i=(int)floor(a); a-=i; 346 | j=(int)floor(b); b-=j; 347 | 348 | /* get gridded tec data */ 349 | for (n=0;n<4;n++) { 350 | if ((index=dataindex(i+(n%2),j+(n<2?0:1),k,tec->ndata))<0) continue; 351 | d[n]=tec->data[index]; 352 | r[n]=tec->rms [index]; 353 | } 354 | if (d[0]>0.0&&d[1]>0.0&&d[2]>0.0&&d[3]>0.0) { 355 | 356 | /* bilinear interpolation (inside of grid) */ 357 | *value=(1.0-a)*(1.0-b)*d[0]+a*(1.0-b)*d[1]+(1.0-a)*b*d[2]+a*b*d[3]; 358 | *rms =(1.0-a)*(1.0-b)*r[0]+a*(1.0-b)*r[1]+(1.0-a)*b*r[2]+a*b*r[3]; 359 | } 360 | /* nearest-neighbour extrapolation (outside of grid) */ 361 | else if (a<=0.5&&b<=0.5&&d[0]>0.0) {*value=d[0]; *rms=r[0];} 362 | else if (a> 0.5&&b<=0.5&&d[1]>0.0) {*value=d[1]; *rms=r[1];} 363 | else if (a<=0.5&&b> 0.5&&d[2]>0.0) {*value=d[2]; *rms=r[2];} 364 | else if (a> 0.5&&b> 0.5&&d[3]>0.0) {*value=d[3]; *rms=r[3];} 365 | else { 366 | i=0; 367 | for (n=0;n<4;n++) if (d[n]>0.0) {i++; *value+=d[n]; *rms+=r[n];} 368 | if(i==0) return 0; 369 | *value/=i; *rms/=i; 370 | } 371 | return 1; 372 | } 373 | /* ionosphere delay by tec grid data -----------------------------------------*/ 374 | static int iondelay(gtime_t time, const tec_t *tec, const double *pos, 375 | const double *azel, int opt, double *delay, double *var) 376 | { 377 | const double fact=40.30E16/FREQ1/FREQ1; /* tecu->L1 iono (m) */ 378 | double fs,posp[3]={0},vtec,rms,hion,rp; 379 | int i; 380 | 381 | trace(3,"iondelay: time=%s pos=%.1f %.1f azel=%.1f %.1f\n",time_str(time,0), 382 | pos[0]*R2D,pos[1]*R2D,azel[0]*R2D,azel[1]*R2D); 383 | 384 | *delay=*var=0.0; 385 | 386 | for (i=0;indata[2];i++) { /* for a layer */ 387 | 388 | hion=tec->hgts[0]+tec->hgts[2]*i; 389 | 390 | /* ionospheric pierce point position */ 391 | fs=ionppp(pos,azel,tec->rb,hion,posp); 392 | 393 | if (opt&2) { 394 | /* modified single layer mapping function (M-SLM) ref [2] */ 395 | rp=tec->rb/(tec->rb+hion)*sin(0.9782*(PI/2.0-azel[1])); 396 | fs=1.0/sqrt(1.0-rp*rp); 397 | } 398 | if (opt&1) { 399 | /* earth rotation correction (sun-fixed coordinate) */ 400 | posp[1]+=2.0*PI*timediff(time,tec->time)/86400.0; 401 | } 402 | /* interpolate tec grid data */ 403 | if (!interptec(tec,i,posp,&vtec,&rms)) return 0; 404 | 405 | *delay+=fact*fs*vtec; 406 | *var+=fact*fact*fs*fs*rms*rms; 407 | } 408 | trace(4,"iondelay: delay=%7.2f std=%6.2f\n",*delay,sqrt(*var)); 409 | 410 | return 1; 411 | } 412 | /* ionosphere model by tec grid data ------------------------------------------- 413 | * compute ionospheric delay by tec grid data 414 | * args : gtime_t time I time (gpst) 415 | * nav_t *nav I navigation data 416 | * double *pos I receiver position {lat,lon,h} (rad,m) 417 | * double *azel I azimuth/elevation angle {az,el} (rad) 418 | * int opt I model option 419 | * bit0: 0:earth-fixed,1:sun-fixed 420 | * bit1: 0:single-layer,1:modified single-layer 421 | * double *delay O ionospheric delay (L1) (m) 422 | * double *var O ionospheric dealy (L1) variance (m^2) 423 | * return : status (1:ok,0:error) 424 | * notes : before calling the function, read tec grid data by calling readtec() 425 | * return ok with delay=0 and var=VAR_NOTEC if elnt;i++) { 442 | if (timediff(nav->tec[i].time,time)>0.0) break; 443 | } 444 | if (i==0||i>=nav->nt) { 445 | trace(2,"%s: tec grid out of period\n",time_str(time,0)); 446 | return 0; 447 | } 448 | if ((tt=timediff(nav->tec[i].time,nav->tec[i-1].time))==0.0) { 449 | trace(2,"tec grid time interval error\n"); 450 | return 0; 451 | } 452 | /* ionospheric delay by tec grid data */ 453 | stat[0]=iondelay(time,nav->tec+i-1,pos,azel,opt,dels ,vars ); 454 | stat[1]=iondelay(time,nav->tec+i ,pos,azel,opt,dels+1,vars+1); 455 | 456 | if (!stat[0]&&!stat[1]) { 457 | trace(2,"%s: tec grid out of area pos=%6.2f %7.2f azel=%6.1f %5.1f\n", 458 | time_str(time,0),pos[0]*R2D,pos[1]*R2D,azel[0]*R2D,azel[1]*R2D); 459 | return 0; 460 | } 461 | if (stat[0]&&stat[1]) { /* linear interpolation by time */ 462 | a=timediff(time,nav->tec[i-1].time)/tt; 463 | *delay=dels[0]*(1.0-a)+dels[1]*a; 464 | *var =vars[0]*(1.0-a)+vars[1]*a; 465 | } 466 | else if (stat[0]) { /* nearest-neighbour extrapolation by time */ 467 | *delay=dels[0]; 468 | *var =vars[0]; 469 | } 470 | else { 471 | *delay=dels[1]; 472 | *var =vars[1]; 473 | } 474 | trace(3,"iontec : delay=%5.2f std=%5.2f\n",*delay,sqrt(*var)); 475 | return 1; 476 | } 477 | -------------------------------------------------------------------------------- /src/lambda.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * lambda.c : integer ambiguity resolution 3 | * 4 | * Copyright (C) 2007-2008 by T.TAKASU, All rights reserved. 5 | * 6 | * reference : 7 | * [1] P.J.G.Teunissen, The least-square ambiguity decorrelation adjustment: 8 | * a method for fast GPS ambiguity estimation, J.Geodesy, Vol.70, 65-82, 9 | * 1995 10 | * [2] X.-W.Chang, X.Yang, T.Zhou, MLAMBDA: A modified LAMBDA method for 11 | * integer least-squares estimation, J.Geodesy, Vol.79, 552-565, 2005 12 | * 13 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ 14 | * history : 2007/01/13 1.0 new 15 | * 2015/05/31 1.1 add api lambda_reduction(), lambda_search() 16 | *-----------------------------------------------------------------------------*/ 17 | #include "rtklib.h" 18 | 19 | /* constants/macros ----------------------------------------------------------*/ 20 | 21 | #define LOOPMAX 10000 /* maximum count of search loop */ 22 | 23 | #define SGN(x) ((x)<=0.0?-1.0:1.0) 24 | #define ROUND(x) (floor((x)+0.5)) 25 | #define SWAP(x,y) do {double tmp_; tmp_=x; x=y; y=tmp_;} while (0) 26 | 27 | /* LD factorization (Q=L'*diag(D)*L) -----------------------------------------*/ 28 | static int LD(int n, const double *Q, double *L, double *D) 29 | { 30 | int i,j,k,info=0; 31 | double a,*A=mat(n,n); 32 | 33 | memcpy(A,Q,sizeof(double)*n*n); 34 | for (i=n-1;i>=0;i--) { 35 | if ((D[i]=A[i+i*n])<=0.0) {info=-1; break;} 36 | a=sqrt(D[i]); 37 | for (j=0;j<=i;j++) L[i+j*n]=A[i+j*n]/a; 38 | for (j=0;j<=i-1;j++) for (k=0;k<=j;k++) A[j+k*n]-=L[i+k*n]*L[i+j*n]; 39 | for (j=0;j<=i;j++) L[i+j*n]/=L[i+i*n]; 40 | } 41 | free(A); 42 | if (info) fprintf(stderr,"%s : LD factorization error\n",__FILE__); 43 | return info; 44 | } 45 | /* integer gauss transformation ----------------------------------------------*/ 46 | static void gauss(int n, double *L, double *Z, int i, int j) 47 | { 48 | int k,mu; 49 | 50 | if ((mu=(int)ROUND(L[i+j*n]))!=0) { 51 | for (k=i;k=0) { 81 | if (j<=k) for (i=j+1;is[imax]) imax=nn; 114 | for (i=0;i=LOOPMAX) { 146 | fprintf(stderr,"%s : search loop count overflow\n",__FILE__); 147 | return -1; 148 | } 149 | return 0; 150 | } 151 | /* lambda/mlambda integer least-square estimation ------------------------------ 152 | * integer least-square estimation. reduction is performed by lambda (ref.[1]), 153 | * and search by mlambda (ref.[2]). 154 | * args : int n I number of float parameters 155 | * int m I number of fixed solutions 156 | * double *a I float parameters (n x 1) 157 | * double *Q I covariance matrix of float parameters (n x n) 158 | * double *F O fixed solutions (n x m) 159 | * double *s O sum of squared residulas of fixed solutions (1 x m) 160 | * return : status (0:ok,other:error) 161 | * notes : matrix stored by column-major order (fortran convension) 162 | *-----------------------------------------------------------------------------*/ 163 | extern int lambda(int n, int m, const double *a, const double *Q, double *F, 164 | double *s) 165 | { 166 | int info; 167 | double *L,*D,*Z,*z,*E; 168 | 169 | if (n<=0||m<=0) return -1; 170 | L=zeros(n,n); D=mat(n,1); Z=eye(n); z=mat(n,1); E=mat(n,m); 171 | 172 | /* LD factorization */ 173 | if (!(info=LD(n,Q,L,D))) { 174 | 175 | /* lambda reduction */ 176 | reduction(n,L,D,Z); 177 | matmul("TN",n,1,n,1.0,Z,a,0.0,z); /* z=Z'*a */ 178 | 179 | /* mlambda search */ 180 | if (!(info=search(n,m,L,D,z,E,s))) { 181 | 182 | info=solve("T",Z,E,n,m,F); /* F=Z'\E */ 183 | } 184 | } 185 | free(L); free(D); free(Z); free(z); free(E); 186 | return info; 187 | } 188 | /* lambda reduction ------------------------------------------------------------ 189 | * reduction by lambda (ref [1]) for integer least square 190 | * args : int n I number of float parameters 191 | * double *Q I covariance matrix of float parameters (n x n) 192 | * double *Z O lambda reduction matrix (n x n) 193 | * return : status (0:ok,other:error) 194 | *-----------------------------------------------------------------------------*/ 195 | extern int lambda_reduction(int n, const double *Q, double *Z) 196 | { 197 | double *L,*D; 198 | int i,j,info; 199 | 200 | if (n<=0) return -1; 201 | 202 | L=zeros(n,n); D=mat(n,1); 203 | 204 | for (i=0;i (signed char *) 22 | * 2020/07/10 1.8 suppress warnings 23 | * 2020/11/30 1.9 use integer type in stdint.h 24 | *-----------------------------------------------------------------------------*/ 25 | #include "rtklib.h" 26 | 27 | #define NVSSYNC 0x10 /* nvs message sync code 1 */ 28 | #define NVSENDMSG 0x03 /* nvs message sync code 1 */ 29 | #define NVSCFG 0x06 /* nvs message cfg-??? */ 30 | 31 | #define ID_XF5RAW 0xf5 /* nvs msg id: raw measurement data */ 32 | #define ID_X4AIONO 0x4a /* nvs msg id: gps ionospheric data */ 33 | #define ID_X4BTIME 0x4b /* nvs msg id: GPS/GLONASS/UTC timescale data */ 34 | #define ID_XF7EPH 0xf7 /* nvs msg id: subframe buffer */ 35 | #define ID_XE5BIT 0xe5 /* nvs msg id: bit information */ 36 | 37 | #define ID_XD7ADVANCED 0xd7 /* */ 38 | #define ID_X02RATEPVT 0x02 /* */ 39 | #define ID_XF4RATERAW 0xf4 /* */ 40 | #define ID_XD7SMOOTH 0xd7 /* */ 41 | #define ID_XD5BIT 0xd5 /* */ 42 | 43 | /* get fields (little-endian) ------------------------------------------------*/ 44 | #define U1(p) (*((uint8_t *)(p))) 45 | #define I1(p) (*((int8_t *)(p))) 46 | static uint16_t U2(uint8_t *p) {uint16_t u; memcpy(&u,p,2); return u;} 47 | static uint32_t U4(uint8_t *p) {uint32_t u; memcpy(&u,p,4); return u;} 48 | static int16_t I2(uint8_t *p) {int16_t i; memcpy(&i,p,2); return i;} 49 | static int32_t I4(uint8_t *p) {int32_t i; memcpy(&i,p,4); return i;} 50 | static float R4(uint8_t *p) {float r; memcpy(&r,p,4); return r;} 51 | static double R8(uint8_t *p) {double r; memcpy(&r,p,8); return r;} 52 | 53 | /* ura values (ref [3] 20.3.3.3.1.1) -----------------------------------------*/ 54 | static const double ura_eph[]={ 55 | 2.4,3.4,4.85,6.85,9.65,13.65,24.0,48.0,96.0,192.0,384.0,768.0,1536.0, 56 | 3072.0,6144.0,0.0 57 | }; 58 | /* ura value (m) to ura index ------------------------------------------------*/ 59 | static int uraindex(double value) 60 | { 61 | int i; 62 | for (i=0;i<15;i++) if (ura_eph[i]>=value) break; 63 | return i; 64 | } 65 | /* decode NVS xf5-raw: raw measurement data ----------------------------------*/ 66 | static int decode_xf5raw(raw_t *raw) 67 | { 68 | gtime_t time; 69 | double tadj=0.0,toff=0.0,tn; 70 | int dTowInt; 71 | double dTowUTC, dTowGPS, dTowFrac, L1, P1, D1; 72 | double gpsutcTimescale; 73 | uint8_t rcvTimeScaleCorr, sys, carrNo; 74 | int i,j,prn,sat,n=0,nsat,week; 75 | uint8_t *p=raw->buff+2; 76 | char *q,tstr[32],flag; 77 | 78 | trace(4,"decode_xf5raw: len=%d\n",raw->len); 79 | 80 | /* time tag adjustment option (-TADJ) */ 81 | if ((q=strstr(raw->opt,"-tadj"))) { 82 | sscanf(q,"-TADJ=%lf",&tadj); 83 | } 84 | dTowUTC =R8(p); 85 | week = U2(p+8); 86 | gpsutcTimescale = R8(p+10); 87 | /* glonassutcTimescale = R8(p+18); */ 88 | rcvTimeScaleCorr = I1(p+26); 89 | 90 | /* check gps week range */ 91 | if (week>=4096) { 92 | trace(2,"nvs xf5raw obs week error: week=%d\n",week); 93 | return -1; 94 | } 95 | week=adjgpsweek(week); 96 | 97 | if ((raw->len - 31)%30) { 98 | 99 | /* Message length is not correct: there could be an error in the stream */ 100 | trace(2,"nvs xf5raw len=%d seems not be correct\n",raw->len); 101 | return -1; 102 | } 103 | nsat = (raw->len - 31)/30; 104 | 105 | dTowGPS = dTowUTC + gpsutcTimescale; 106 | 107 | /* Tweak pseudoranges to allow Rinex to represent the NVS time of measure */ 108 | dTowInt = 10.0*floor((dTowGPS/10.0)+0.5); 109 | dTowFrac = dTowGPS - (double) dTowInt; 110 | time=gpst2time(week, dTowInt*0.001); 111 | 112 | /* time tag adjustment */ 113 | if (tadj>0.0) { 114 | tn=time2gpst(time,&week)/tadj; 115 | toff=(tn-floor(tn+0.5))*tadj; 116 | time=timeadd(time,-toff); 117 | } 118 | /* check time tag jump and output warning */ 119 | if (raw->time.time&&fabs(timediff(time,raw->time))>86400.0) { 120 | time2str(time,tstr,3); 121 | trace(2,"nvs xf5raw time tag jump warning: time=%s\n",tstr); 122 | } 123 | if (fabs(timediff(time,raw->time))<=1e-3) { 124 | time2str(time,tstr,3); 125 | trace(2,"nvs xf5raw time tag duplicated: time=%s\n",tstr); 126 | return 0; 127 | } 128 | for (i=0,p+=27;(iobs.data[n].time = time; 130 | sys = (U1(p)==1)?SYS_GLO:((U1(p)==2)?SYS_GPS:((U1(p)==4)?SYS_SBS:SYS_NONE)); 131 | prn = U1(p+1); 132 | if (sys == SYS_SBS) prn += 120; /* Correct this */ 133 | if (!(sat=satno(sys,prn))) { 134 | trace(2,"nvs xf5raw satellite number error: sys=%d prn=%d\n",sys,prn); 135 | continue; 136 | } 137 | carrNo = I1(p+2); 138 | L1 = R8(p+ 4); 139 | P1 = R8(p+12); 140 | D1 = R8(p+20); 141 | 142 | /* check range error */ 143 | if (L1<-1E10||L1>1E10||P1<-1E10||P1>1E10||D1<-1E5||D1>1E5) { 144 | trace(2,"nvs xf5raw obs range error: sat=%2d L1=%12.5e P1=%12.5e D1=%12.5e\n", 145 | sat,L1,P1,D1); 146 | continue; 147 | } 148 | raw->obs.data[n].SNR[0]=(uint16_t)(I1(p+3)/SNR_UNIT+0.5); 149 | if (sys==SYS_GLO) { 150 | raw->obs.data[n].L[0] = L1 - toff*(FREQ1_GLO+DFRQ1_GLO*carrNo); 151 | } else { 152 | raw->obs.data[n].L[0] = L1 - toff*FREQ1; 153 | } 154 | raw->obs.data[n].P[0] = (P1-dTowFrac)*CLIGHT*0.001 - toff*CLIGHT; /* in ms, needs to be converted */ 155 | raw->obs.data[n].D[0] = (float)D1; 156 | 157 | /* set LLI if meas flag 4 (carrier phase present) off -> on */ 158 | flag=U1(p+28); 159 | raw->obs.data[n].LLI[0]=(flag&0x08)&&!(raw->halfc[sat-1][0]&0x08)?1:0; 160 | raw->halfc[sat-1][0]=flag; 161 | 162 | raw->obs.data[n].code[0] = CODE_L1C; 163 | raw->obs.data[n].sat = sat; 164 | 165 | for (j=1;jobs.data[n].L[j]=raw->obs.data[n].P[j]=0.0; 167 | raw->obs.data[n].D[j]=0.0; 168 | raw->obs.data[n].SNR[j]=raw->obs.data[n].LLI[j]=0; 169 | raw->obs.data[n].code[j]=CODE_NONE; 170 | } 171 | n++; 172 | } 173 | raw->time=time; 174 | raw->obs.n=n; 175 | return 1; 176 | } 177 | /* decode ephemeris ----------------------------------------------------------*/ 178 | static int decode_gpsephem(int sat, raw_t *raw) 179 | { 180 | eph_t eph={0}; 181 | uint8_t *puiTmp = (raw->buff)+2; 182 | uint16_t week; 183 | double toc; 184 | 185 | trace(4,"decode_ephem: sat=%2d\n",sat); 186 | 187 | eph.crs = R4(&puiTmp[ 2]); 188 | eph.deln = R4(&puiTmp[ 6]) * 1e+3; 189 | eph.M0 = R8(&puiTmp[ 10]); 190 | eph.cuc = R4(&puiTmp[ 18]); 191 | eph.e = R8(&puiTmp[ 22]); 192 | eph.cus = R4(&puiTmp[ 30]); 193 | eph.A = pow(R8(&puiTmp[ 34]), 2); 194 | eph.toes = R8(&puiTmp[ 42]) * 1e-3; 195 | eph.cic = R4(&puiTmp[ 50]); 196 | eph.OMG0 = R8(&puiTmp[ 54]); 197 | eph.cis = R4(&puiTmp[ 62]); 198 | eph.i0 = R8(&puiTmp[ 66]); 199 | eph.crc = R4(&puiTmp[ 74]); 200 | eph.omg = R8(&puiTmp[ 78]); 201 | eph.OMGd = R8(&puiTmp[ 86]) * 1e+3; 202 | eph.idot = R8(&puiTmp[ 94]) * 1e+3; 203 | eph.tgd[0] = R4(&puiTmp[102]) * 1e-3; 204 | toc = R8(&puiTmp[106]) * 1e-3; 205 | eph.f2 = R4(&puiTmp[114]) * 1e+3; 206 | eph.f1 = R4(&puiTmp[118]); 207 | eph.f0 = R4(&puiTmp[122]) * 1e-3; 208 | eph.sva = uraindex(I2(&puiTmp[126])); 209 | eph.iode = I2(&puiTmp[128]); 210 | eph.iodc = I2(&puiTmp[130]); 211 | eph.code = I2(&puiTmp[132]); 212 | eph.flag = I2(&puiTmp[134]); 213 | week = I2(&puiTmp[136]); 214 | eph.fit = 0; 215 | 216 | if (week>=4096) { 217 | trace(2,"nvs gps ephemeris week error: sat=%2d week=%d\n",sat,week); 218 | return -1; 219 | } 220 | eph.week=adjgpsweek(week); 221 | eph.toe=gpst2time(eph.week,eph.toes); 222 | eph.toc=gpst2time(eph.week,toc); 223 | eph.ttr=raw->time; 224 | 225 | if (!strstr(raw->opt,"-EPHALL")) { 226 | if (eph.iode==raw->nav.eph[sat-1].iode) return 0; /* unchanged */ 227 | } 228 | eph.sat=sat; 229 | raw->nav.eph[sat-1]=eph; 230 | raw->ephsat=sat; 231 | raw->ephset=0; 232 | return 2; 233 | } 234 | /* adjust daily rollover of time ---------------------------------------------*/ 235 | static gtime_t adjday(gtime_t time, double tod) 236 | { 237 | double ep[6],tod_p; 238 | time2epoch(time,ep); 239 | tod_p=ep[3]*3600.0+ep[4]*60.0+ep[5]; 240 | if (todtod_p+43200.0) tod-=86400.0; 242 | ep[3]=ep[4]=ep[5]=0.0; 243 | return timeadd(epoch2time(ep),tod); 244 | } 245 | /* decode gloephem -----------------------------------------------------------*/ 246 | static int decode_gloephem(int sat, raw_t *raw) 247 | { 248 | geph_t geph={0}; 249 | uint8_t *p=(raw->buff)+2; 250 | int prn,tk,tb; 251 | 252 | if (raw->len>=93) { 253 | prn =I1(p+ 1); 254 | geph.frq =I1(p+ 2); 255 | geph.pos[0]=R8(p+ 3); 256 | geph.pos[1]=R8(p+11); 257 | geph.pos[2]=R8(p+19); 258 | geph.vel[0]=R8(p+27) * 1e+3; 259 | geph.vel[1]=R8(p+35) * 1e+3; 260 | geph.vel[2]=R8(p+43) * 1e+3; 261 | geph.acc[0]=R8(p+51) * 1e+6; 262 | geph.acc[1]=R8(p+59) * 1e+6; 263 | geph.acc[2]=R8(p+67) * 1e+6; 264 | tb = R8(p+75) * 1e-3; 265 | tk = tb; 266 | geph.gamn =R4(p+83); 267 | geph.taun =R4(p+87) * 1e-3; 268 | geph.age =I2(p+91); 269 | } 270 | else { 271 | trace(2,"nvs NE length error: len=%d\n",raw->len); 272 | return -1; 273 | } 274 | if (!(geph.sat=satno(SYS_GLO,prn))) { 275 | trace(2,"nvs NE satellite error: prn=%d\n",prn); 276 | return -1; 277 | } 278 | if (raw->time.time==0) return 0; 279 | 280 | geph.iode=(tb/900)&0x7F; 281 | geph.toe=utc2gpst(adjday(raw->time,tb-10800.0)); 282 | geph.tof=utc2gpst(adjday(raw->time,tk-10800.0)); 283 | #if 0 284 | /* check illegal ephemeris by toe */ 285 | tt=timediff(raw->time,geph.toe); 286 | if (fabs(tt)>3600.0) { 287 | trace(3,"nvs NE illegal toe: prn=%2d tt=%6.0f\n",prn,tt); 288 | return 0; 289 | } 290 | #endif 291 | #if 0 292 | /* check illegal ephemeris by frequency number consistency */ 293 | if (raw->nav.geph[prn-MINPRNGLO].toe.time&& 294 | geph.frq!=raw->nav.geph[prn-MINPRNGLO].frq) { 295 | trace(2,"nvs NE illegal freq change: prn=%2d frq=%2d->%2d\n",prn, 296 | raw->nav.geph[prn-MINPRNGLO].frq,geph.frq); 297 | return -1; 298 | } 299 | if (!strstr(raw->opt,"-EPHALL")) { 300 | if (fabs(timediff(geph.toe,raw->nav.geph[prn-MINPRNGLO].toe))<1.0&& 301 | geph.svh==raw->nav.geph[prn-MINPRNGLO].svh) return 0; 302 | } 303 | #endif 304 | raw->nav.geph[prn-1]=geph; 305 | raw->ephsat=geph.sat; 306 | raw->ephset=0; 307 | 308 | return 2; 309 | } 310 | /* decode NVS ephemerides in clear -------------------------------------------*/ 311 | static int decode_xf7eph(raw_t *raw) 312 | { 313 | int prn,sat,sys; 314 | uint8_t *p=raw->buff; 315 | 316 | trace(4,"decode_xf7eph: len=%d\n",raw->len); 317 | 318 | if ((raw->len)<93) { 319 | trace(2,"nvs xf7eph length error: len=%d\n",raw->len); 320 | return -1; 321 | } 322 | sys = (U1(p+2)==1)?SYS_GPS:((U1(p+2)==2)?SYS_GLO:SYS_NONE); 323 | prn = U1(p+3); 324 | if (!(sat=satno(sys==1?SYS_GPS:SYS_GLO,prn))) { 325 | trace(2,"nvs xf7eph satellite number error: prn=%d\n",prn); 326 | return -1; 327 | } 328 | if (sys==SYS_GPS) { 329 | return decode_gpsephem(sat,raw); 330 | } 331 | else if (sys==SYS_GLO) { 332 | return decode_gloephem(sat,raw); 333 | } 334 | return 0; 335 | } 336 | /* decode NVS rxm-sfrb: subframe buffer --------------------------------------*/ 337 | static int decode_xe5bit(raw_t *raw) 338 | { 339 | int prn; 340 | int iBlkStartIdx, iExpLen, iIdx; 341 | uint32_t words[10]; 342 | uint8_t uiDataBlocks, uiDataType; 343 | uint8_t *p=raw->buff; 344 | 345 | trace(4,"decode_xe5bit: len=%d\n",raw->len); 346 | 347 | p += 2; /* Discard preamble and message identifier */ 348 | uiDataBlocks = U1(p); 349 | 350 | if (uiDataBlocks>=16) { 351 | trace(2,"nvs xf5bit message error: data blocks %u\n", uiDataBlocks); 352 | return -1; 353 | } 354 | iBlkStartIdx = 1; 355 | for (iIdx = 0; iIdx < uiDataBlocks; iIdx++) { 356 | iExpLen = (iBlkStartIdx+10); 357 | if ((raw->len) < iExpLen) { 358 | trace(2,"nvs xf5bit message too short (expected at least %d)\n", iExpLen); 359 | return -1; 360 | } 361 | uiDataType = U1(p+iBlkStartIdx+1); 362 | 363 | switch (uiDataType) { 364 | case 1: /* Glonass */ 365 | iBlkStartIdx += 19; 366 | break; 367 | case 2: /* GPS */ 368 | iBlkStartIdx += 47; 369 | break; 370 | case 4: /* SBAS */ 371 | prn = U1(p+(iBlkStartIdx+2)) + 120; 372 | 373 | /* sat = satno(SYS_SBS, prn); */ 374 | /* sys = satsys(sat,&prn); */ 375 | memset(words, 0, 10*sizeof(uint32_t)); 376 | for (iIdx=0, iBlkStartIdx+=7; iIdx<10; iIdx++, iBlkStartIdx+=4) { 377 | words[iIdx]=U4(p+iBlkStartIdx); 378 | } 379 | words[7] >>= 6; 380 | return sbsdecodemsg(raw->time,prn,words,&raw->sbsmsg) ? 3 : 0; 381 | default: 382 | trace(2,"nvs xf5bit SNS type unknown (got %d)\n", uiDataType); 383 | return -1; 384 | } 385 | } 386 | return 0; 387 | } 388 | /* decode NVS x4aiono --------------------------------------------------------*/ 389 | static int decode_x4aiono(raw_t *raw) 390 | { 391 | uint8_t *p=raw->buff+2; 392 | 393 | trace(4,"decode_x4aiono: len=%d\n", raw->len); 394 | 395 | raw->nav.ion_gps[0] = R4(p ); 396 | raw->nav.ion_gps[1] = R4(p+ 4); 397 | raw->nav.ion_gps[2] = R4(p+ 8); 398 | raw->nav.ion_gps[3] = R4(p+12); 399 | raw->nav.ion_gps[4] = R4(p+16); 400 | raw->nav.ion_gps[5] = R4(p+20); 401 | raw->nav.ion_gps[6] = R4(p+24); 402 | raw->nav.ion_gps[7] = R4(p+28); 403 | 404 | return 9; 405 | } 406 | /* decode NVS x4btime --------------------------------------------------------*/ 407 | static int decode_x4btime(raw_t *raw) 408 | { 409 | uint8_t *p=raw->buff+2; 410 | 411 | trace(4,"decode_x4btime: len=%d\n", raw->len); 412 | 413 | raw->nav.utc_gps[1] = R8(p ); 414 | raw->nav.utc_gps[0] = R8(p+ 8); 415 | raw->nav.utc_gps[2] = I4(p+16); 416 | raw->nav.utc_gps[3] = I2(p+20); 417 | raw->nav.utc_gps[4] = I1(p+22); 418 | 419 | return 9; 420 | } 421 | /* decode NVS raw message ----------------------------------------------------*/ 422 | static int decode_nvs(raw_t *raw) 423 | { 424 | int type=U1(raw->buff+1); 425 | 426 | trace(3,"decode_nvs: type=%02x len=%d\n",type,raw->len); 427 | 428 | sprintf(raw->msgtype,"NVS: type=%2d len=%3d",type,raw->len); 429 | 430 | switch (type) { 431 | case ID_XF5RAW: return decode_xf5raw (raw); 432 | case ID_XF7EPH: return decode_xf7eph (raw); 433 | case ID_XE5BIT: return decode_xe5bit (raw); 434 | case ID_X4AIONO: return decode_x4aiono(raw); 435 | case ID_X4BTIME: return decode_x4btime(raw); 436 | default: break; 437 | } 438 | return 0; 439 | } 440 | /* input NVS raw message from stream ------------------------------------------- 441 | * fetch next NVS raw data and input a message from stream 442 | * args : raw_t *raw IO receiver raw data control struct 443 | * uint8_t data I stream data (1 byte) 444 | * return : status (-1: error message, 0: no message, 1: input observation data, 445 | * 2: input ephemeris, 3: input sbas message, 446 | * 9: input ion/utc parameter) 447 | * 448 | * notes : to specify input options, set raw->opt to the following option 449 | * strings separated by spaces. 450 | * 451 | * -EPHALL : input all ephemerides 452 | * -TADJ=tint : adjust time tags to multiples of tint (sec) 453 | * 454 | *-----------------------------------------------------------------------------*/ 455 | extern int input_nvs(raw_t *raw, uint8_t data) 456 | { 457 | trace(5,"input_nvs: data=%02x\n",data); 458 | 459 | /* synchronize frame */ 460 | if ((raw->nbyte==0) && (data==NVSSYNC)) { 461 | 462 | /* Search a 0x10 */ 463 | raw->buff[0] = data; 464 | raw->nbyte=1; 465 | return 0; 466 | } 467 | if ((raw->nbyte==1) && (data != NVSSYNC) && (data != NVSENDMSG)) { 468 | 469 | /* Discard double 0x10 and 0x10 0x03 at beginning of frame */ 470 | raw->buff[1]=data; 471 | raw->nbyte=2; 472 | raw->flag=0; 473 | return 0; 474 | } 475 | /* This is all done to discard a double 0x10 */ 476 | if (data==NVSSYNC) raw->flag = (raw->flag +1) % 2; 477 | if ((data!=NVSSYNC) || (raw->flag)) { 478 | 479 | /* Store the new byte */ 480 | raw->buff[(raw->nbyte++)] = data; 481 | } 482 | /* Detect ending sequence */ 483 | if ((data==NVSENDMSG) && (raw->flag)) { 484 | raw->len = raw->nbyte; 485 | raw->nbyte = 0; 486 | 487 | /* Decode NVS raw message */ 488 | return decode_nvs(raw); 489 | } 490 | if (raw->nbyte == MAXRAWLEN) { 491 | trace(2,"nvs message size error: len=%d\n",raw->nbyte); 492 | raw->nbyte=0; 493 | return -1; 494 | } 495 | return 0; 496 | } 497 | /* input NVS raw message from file --------------------------------------------- 498 | * fetch next NVS raw data and input a message from file 499 | * args : raw_t *raw IO receiver raw data control struct 500 | * FILE *fp I file pointer 501 | * return : status(-2: end of file, -1...9: same as above) 502 | *-----------------------------------------------------------------------------*/ 503 | extern int input_nvsf(raw_t *raw, FILE *fp) 504 | { 505 | int i,data, odd=0; 506 | 507 | trace(4,"input_nvsf:\n"); 508 | 509 | /* synchronize frame */ 510 | for (i=0;;i++) { 511 | if ((data=fgetc(fp))==EOF) return -2; 512 | 513 | /* Search a 0x10 */ 514 | if (data==NVSSYNC) { 515 | 516 | /* Store the frame begin */ 517 | raw->buff[0] = data; 518 | if ((data=fgetc(fp))==EOF) return -2; 519 | 520 | /* Discard double 0x10 and 0x10 0x03 */ 521 | if ((data != NVSSYNC) && (data != NVSENDMSG)) { 522 | raw->buff[1]=data; 523 | break; 524 | } 525 | } 526 | if (i>=4096) return 0; 527 | } 528 | raw->nbyte = 2; 529 | for (i=0;;i++) { 530 | if ((data=fgetc(fp))==EOF) return -2; 531 | if (data==NVSSYNC) odd=(odd+1)%2; 532 | if ((data!=NVSSYNC) || odd) { 533 | 534 | /* Store the new byte */ 535 | raw->buff[(raw->nbyte++)] = data; 536 | } 537 | /* Detect ending sequence */ 538 | if ((data==NVSENDMSG) && odd) break; 539 | if (i>=4096) return 0; 540 | } 541 | raw->len = raw->nbyte; 542 | if ((raw->len) > MAXRAWLEN) { 543 | trace(2,"nvs length error: len=%d\n",raw->len); 544 | return -1; 545 | } 546 | /* decode nvs raw message */ 547 | return decode_nvs(raw); 548 | } 549 | /* generate NVS binary message ------------------------------------------------- 550 | * generate NVS binary message from message string 551 | * args : char *msg I message string 552 | * "RESTART [arg...]" system reset 553 | * "CFG-SERI [arg...]" configure serial port property 554 | * "CFG-FMT [arg...]" configure output message format 555 | * "CFG-RATE [arg...]" configure binary measurement output rates 556 | * uint8_t *buff O binary message 557 | * return : length of binary message (0: error) 558 | * note : see reference [1][2] for details. 559 | *-----------------------------------------------------------------------------*/ 560 | extern int gen_nvs(const char *msg, uint8_t *buff) 561 | { 562 | uint8_t *q=buff; 563 | char mbuff[1024],*args[32],*p; 564 | uint32_t byte; 565 | int iRate,n,narg=0; 566 | uint8_t ui100Ms; 567 | 568 | trace(4,"gen_nvs: msg=%s\n",msg); 569 | 570 | strcpy(mbuff,msg); 571 | for (p=strtok(mbuff," ");p&&narg<32;p=strtok(NULL," ")) { 572 | args[narg++]=p; 573 | } 574 | if (narg<1) { 575 | return 0; 576 | } 577 | *q++=NVSSYNC; /* DLE */ 578 | 579 | if (!strcmp(args[0],"CFG-PVTRATE")) { 580 | *q++=ID_XD7ADVANCED; 581 | *q++=ID_X02RATEPVT; 582 | if (narg>1) { 583 | iRate = atoi(args[1]); 584 | *q++ = (uint8_t) iRate; 585 | } 586 | } 587 | else if (!strcmp(args[0],"CFG-RAWRATE")) { 588 | *q++=ID_XF4RATERAW; 589 | if (narg>1) { 590 | iRate = atoi(args[1]); 591 | switch(iRate) { 592 | case 2: ui100Ms = 5; break; 593 | case 5: ui100Ms = 2; break; 594 | case 10: ui100Ms = 1; break; 595 | default: ui100Ms = 10; break; 596 | } 597 | *q++ = ui100Ms; 598 | } 599 | } 600 | else if (!strcmp(args[0],"CFG-SMOOTH")) { 601 | *q++=ID_XD7SMOOTH; 602 | *q++ = 0x03; 603 | *q++ = 0x01; 604 | *q++ = 0x00; 605 | } 606 | else if (!strcmp(args[0],"CFG-BINR")) { 607 | for (n=1;(nsnrmaskena 14 | * pos1-snrmask1,2,3 15 | * 2013/03/11 1.3 add pos1-posopt1,2,3,4,5,pos2-syncsol 16 | * misc-rnxopt1,2,pos1-snrmask_r,_b,_L1,_L2,_L5 17 | * 2014/10/21 1.4 add pos2-bdsarmode 18 | * 2015/02/20 1.4 add ppp-fixed as pos1-posmode option 19 | * 2015/05/10 1.5 add pos2-arthres1,2,3,4 20 | * 2015/05/31 1.6 add pos2-armaxiter, pos1-posopt6 21 | * add selection precise for pos1-pospot3 22 | * 2015/11/26 1.7 modify pos1-frequency 4:l1+l2+l5+l6 -> l1+l5 23 | * 2015/12/05 1.8 add misc-pppopt 24 | * 2016/06/10 1.9 add ant2-maxaveep,ant2-initrst 25 | * 2016/07/31 1.10 add out-outsingle,out-maxsolstd 26 | * 2017/06/14 1.11 add out-outvel 27 | * 2020/11/30 1.12 change options pos1-frequency, pos1-ionoopt, 28 | * pos1-tropopt, pos1-sateph, pos1-navsys, 29 | * pos2-gloarmode, 30 | *-----------------------------------------------------------------------------*/ 31 | #include "rtklib.h" 32 | 33 | /* system options buffer -----------------------------------------------------*/ 34 | static prcopt_t prcopt_; 35 | static solopt_t solopt_; 36 | static filopt_t filopt_; 37 | static int antpostype_[2]; 38 | static double elmask_,elmaskar_,elmaskhold_; 39 | static double antpos_[2][3]; 40 | static char exsats_[1024]; 41 | static char snrmask_[NFREQ][1024]; 42 | 43 | /* system options table ------------------------------------------------------*/ 44 | #define SWTOPT "0:off,1:on" 45 | #define MODOPT "0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed" 46 | #define FRQOPT "1:l1,2:l1+2,3:l1+2+3,4:l1+2+3+4,5:l1+2+3+4+5" 47 | #define TYPOPT "0:forward,1:backward,2:combined" 48 | #define IONOPT "0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc" 49 | #define TRPOPT "0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad" 50 | #define EPHOPT "0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom,5:brdc+B2b" 51 | #define NAVOPT "1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic" 52 | #define GAROPT "0:off,1:on" 53 | #define SOLOPT "0:llh,1:xyz,2:enu,3:nmea" 54 | #define TSYOPT "0:gpst,1:utc,2:jst" 55 | #define TFTOPT "0:tow,1:hms" 56 | #define DFTOPT "0:deg,1:dms" 57 | #define HGTOPT "0:ellipsoidal,1:geodetic" 58 | #define GEOOPT "0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000" 59 | #define STAOPT "0:all,1:single" 60 | #define STSOPT "0:off,1:state,2:residual" 61 | #define ARMOPT "0:off,1:continuous,2:instantaneous,3:fix-and-hold" 62 | #define POSOPT "0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw" 63 | #define TIDEOPT "0:off,1:on,2:otl" 64 | #define PHWOPT "0:off,1:on,2:precise" 65 | 66 | EXPORT opt_t sysopts[]={ 67 | {"pos1-posmode", 3, (void *)&prcopt_.mode, MODOPT }, 68 | {"pos1-frequency", 3, (void *)&prcopt_.nf, FRQOPT }, 69 | {"pos1-soltype", 3, (void *)&prcopt_.soltype, TYPOPT }, 70 | {"pos1-elmask", 1, (void *)&elmask_, "deg" }, 71 | {"pos1-snrmask_r", 3, (void *)&prcopt_.snrmask.ena[0],SWTOPT}, 72 | {"pos1-snrmask_b", 3, (void *)&prcopt_.snrmask.ena[1],SWTOPT}, 73 | {"pos1-snrmask_L1", 2, (void *)snrmask_[0], "" }, 74 | {"pos1-snrmask_L2", 2, (void *)snrmask_[1], "" }, 75 | {"pos1-snrmask_L5", 2, (void *)snrmask_[2], "" }, 76 | {"pos1-dynamics", 3, (void *)&prcopt_.dynamics, SWTOPT }, 77 | {"pos1-tidecorr", 3, (void *)&prcopt_.tidecorr, TIDEOPT}, 78 | {"pos1-ionoopt", 3, (void *)&prcopt_.ionoopt, IONOPT }, 79 | {"pos1-tropopt", 3, (void *)&prcopt_.tropopt, TRPOPT }, 80 | {"pos1-sateph", 3, (void *)&prcopt_.sateph, EPHOPT }, 81 | {"pos1-posopt1", 3, (void *)&prcopt_.posopt[0], SWTOPT }, 82 | {"pos1-posopt2", 3, (void *)&prcopt_.posopt[1], SWTOPT }, 83 | {"pos1-posopt3", 3, (void *)&prcopt_.posopt[2], PHWOPT }, 84 | {"pos1-posopt4", 3, (void *)&prcopt_.posopt[3], SWTOPT }, 85 | {"pos1-posopt5", 3, (void *)&prcopt_.posopt[4], SWTOPT }, 86 | {"pos1-posopt6", 3, (void *)&prcopt_.posopt[5], SWTOPT }, 87 | {"pos1-exclsats", 2, (void *)exsats_, "prn ..."}, 88 | {"pos1-navsys", 0, (void *)&prcopt_.navsys, NAVOPT }, 89 | 90 | {"pos2-armode", 3, (void *)&prcopt_.modear, ARMOPT }, 91 | {"pos2-gloarmode", 3, (void *)&prcopt_.glomodear, GAROPT }, 92 | {"pos2-bdsarmode", 3, (void *)&prcopt_.bdsmodear, SWTOPT }, 93 | {"pos2-arthres", 1, (void *)&prcopt_.thresar[0], "" }, 94 | {"pos2-arthres1", 1, (void *)&prcopt_.thresar[1], "" }, 95 | {"pos2-arthres2", 1, (void *)&prcopt_.thresar[2], "" }, 96 | {"pos2-arthres3", 1, (void *)&prcopt_.thresar[3], "" }, 97 | {"pos2-arthres4", 1, (void *)&prcopt_.thresar[4], "" }, 98 | {"pos2-arlockcnt", 0, (void *)&prcopt_.minlock, "" }, 99 | {"pos2-arelmask", 1, (void *)&elmaskar_, "deg" }, 100 | {"pos2-arminfix", 0, (void *)&prcopt_.minfix, "" }, 101 | {"pos2-armaxiter", 0, (void *)&prcopt_.armaxiter, "" }, 102 | {"pos2-elmaskhold", 1, (void *)&elmaskhold_, "deg" }, 103 | {"pos2-aroutcnt", 0, (void *)&prcopt_.maxout, "" }, 104 | {"pos2-maxage", 1, (void *)&prcopt_.maxtdiff, "s" }, 105 | {"pos2-syncsol", 3, (void *)&prcopt_.syncsol, SWTOPT }, 106 | {"pos2-slipthres", 1, (void *)&prcopt_.thresslip, "m" }, 107 | {"pos2-rejionno", 1, (void *)&prcopt_.maxinno, "m" }, 108 | {"pos2-rejgdop", 1, (void *)&prcopt_.maxgdop, "" }, 109 | {"pos2-niter", 0, (void *)&prcopt_.niter, "" }, 110 | {"pos2-baselen", 1, (void *)&prcopt_.baseline[0],"m" }, 111 | {"pos2-basesig", 1, (void *)&prcopt_.baseline[1],"m" }, 112 | 113 | {"out-solformat", 3, (void *)&solopt_.posf, SOLOPT }, 114 | {"out-outhead", 3, (void *)&solopt_.outhead, SWTOPT }, 115 | {"out-outopt", 3, (void *)&solopt_.outopt, SWTOPT }, 116 | {"out-outvel", 3, (void *)&solopt_.outvel, SWTOPT }, 117 | {"out-timesys", 3, (void *)&solopt_.times, TSYOPT }, 118 | {"out-timeform", 3, (void *)&solopt_.timef, TFTOPT }, 119 | {"out-timendec", 0, (void *)&solopt_.timeu, "" }, 120 | {"out-degform", 3, (void *)&solopt_.degf, DFTOPT }, 121 | {"out-fieldsep", 2, (void *) solopt_.sep, "" }, 122 | {"out-outsingle", 3, (void *)&prcopt_.outsingle, SWTOPT }, 123 | {"out-maxsolstd", 1, (void *)&solopt_.maxsolstd, "m" }, 124 | {"out-height", 3, (void *)&solopt_.height, HGTOPT }, 125 | {"out-geoid", 3, (void *)&solopt_.geoid, GEOOPT }, 126 | {"out-solstatic", 3, (void *)&solopt_.solstatic, STAOPT }, 127 | {"out-nmeaintv1", 1, (void *)&solopt_.nmeaintv[0],"s" }, 128 | {"out-nmeaintv2", 1, (void *)&solopt_.nmeaintv[1],"s" }, 129 | {"out-outstat", 3, (void *)&solopt_.sstat, STSOPT }, 130 | 131 | {"stats-eratio1", 1, (void *)&prcopt_.eratio[0], "" }, 132 | {"stats-eratio2", 1, (void *)&prcopt_.eratio[1], "" }, 133 | {"stats-errphase", 1, (void *)&prcopt_.err[1], "m" }, 134 | {"stats-errphaseel",1, (void *)&prcopt_.err[2], "m" }, 135 | {"stats-errphasebl",1, (void *)&prcopt_.err[3], "m/10km"}, 136 | {"stats-errdoppler",1, (void *)&prcopt_.err[4], "Hz" }, 137 | {"stats-stdbias", 1, (void *)&prcopt_.std[0], "m" }, 138 | {"stats-stdiono", 1, (void *)&prcopt_.std[1], "m" }, 139 | {"stats-stdtrop", 1, (void *)&prcopt_.std[2], "m" }, 140 | {"stats-prnaccelh", 1, (void *)&prcopt_.prn[3], "m/s^2"}, 141 | {"stats-prnaccelv", 1, (void *)&prcopt_.prn[4], "m/s^2"}, 142 | {"stats-prnbias", 1, (void *)&prcopt_.prn[0], "m" }, 143 | {"stats-prniono", 1, (void *)&prcopt_.prn[1], "m" }, 144 | {"stats-prntrop", 1, (void *)&prcopt_.prn[2], "m" }, 145 | {"stats-prnpos", 1, (void *)&prcopt_.prn[5], "m" }, 146 | {"stats-clkstab", 1, (void *)&prcopt_.sclkstab, "s/s" }, 147 | 148 | {"ant1-postype", 3, (void *)&antpostype_[0], POSOPT }, 149 | {"ant1-pos1", 1, (void *)&antpos_[0][0], "deg|m"}, 150 | {"ant1-pos2", 1, (void *)&antpos_[0][1], "deg|m"}, 151 | {"ant1-pos3", 1, (void *)&antpos_[0][2], "m|m" }, 152 | {"ant1-anttype", 2, (void *)prcopt_.anttype[0], "" }, 153 | {"ant1-antdele", 1, (void *)&prcopt_.antdel[0][0],"m" }, 154 | {"ant1-antdeln", 1, (void *)&prcopt_.antdel[0][1],"m" }, 155 | {"ant1-antdelu", 1, (void *)&prcopt_.antdel[0][2],"m" }, 156 | 157 | {"ant2-postype", 3, (void *)&antpostype_[1], POSOPT }, 158 | {"ant2-pos1", 1, (void *)&antpos_[1][0], "deg|m"}, 159 | {"ant2-pos2", 1, (void *)&antpos_[1][1], "deg|m"}, 160 | {"ant2-pos3", 1, (void *)&antpos_[1][2], "m|m" }, 161 | {"ant2-anttype", 2, (void *)prcopt_.anttype[1], "" }, 162 | {"ant2-antdele", 1, (void *)&prcopt_.antdel[1][0],"m" }, 163 | {"ant2-antdeln", 1, (void *)&prcopt_.antdel[1][1],"m" }, 164 | {"ant2-antdelu", 1, (void *)&prcopt_.antdel[1][2],"m" }, 165 | {"ant2-maxaveep", 0, (void *)&prcopt_.maxaveep ,"" }, 166 | {"ant2-initrst", 3, (void *)&prcopt_.initrst, SWTOPT }, 167 | 168 | {"misc-timeinterp", 3, (void *)&prcopt_.intpref, SWTOPT }, 169 | {"misc-sbasatsel", 0, (void *)&prcopt_.sbassatsel, "0:all"}, 170 | {"misc-rnxopt1", 2, (void *)prcopt_.rnxopt[0], "" }, 171 | {"misc-rnxopt2", 2, (void *)prcopt_.rnxopt[1], "" }, 172 | {"misc-pppopt", 2, (void *)prcopt_.pppopt, "" }, 173 | 174 | {"file-satantfile", 2, (void *)&filopt_.satantp, "" }, 175 | {"file-rcvantfile", 2, (void *)&filopt_.rcvantp, "" }, 176 | {"file-staposfile", 2, (void *)&filopt_.stapos, "" }, 177 | {"file-geoidfile", 2, (void *)&filopt_.geoid, "" }, 178 | {"file-ionofile", 2, (void *)&filopt_.iono, "" }, 179 | {"file-dcbfile", 2, (void *)&filopt_.dcb, "" }, 180 | {"file-eopfile", 2, (void *)&filopt_.eop, "" }, 181 | {"file-blqfile", 2, (void *)&filopt_.blq, "" }, 182 | {"file-tempdir", 2, (void *)&filopt_.tempdir, "" }, 183 | {"file-geexefile", 2, (void *)&filopt_.geexe, "" }, 184 | {"file-solstatfile",2, (void *)&filopt_.solstat, "" }, 185 | {"file-tracefile", 2, (void *)&filopt_.trace, "" }, 186 | 187 | {"",0,NULL,""} /* terminator */ 188 | }; 189 | /* discard space characters at tail ------------------------------------------*/ 190 | static void chop(char *str) 191 | { 192 | char *p; 193 | if ((p=strchr(str,'#'))) *p='\0'; /* comment */ 194 | for (p=str+strlen(str)-1;p>=str&&!isgraph((int)*p);p--) *p='\0'; 195 | } 196 | /* enum to string ------------------------------------------------------------*/ 197 | static int enum2str(char *s, const char *comment, int val) 198 | { 199 | char str[32],*p,*q; 200 | int n; 201 | 202 | n=sprintf(str,"%d:",val); 203 | if (!(p=strstr(comment,str))) { 204 | return sprintf(s,"%d",val); 205 | } 206 | if (!(q=strchr(p+n,','))&&!(q=strchr(p+n,')'))) { 207 | strcpy(s,p+n); 208 | return (int)strlen(p+n); 209 | } 210 | strncpy(s,p+n,q-p-n); s[q-p-n]='\0'; 211 | return (int)(q-p-n); 212 | } 213 | /* string to enum ------------------------------------------------------------*/ 214 | static int str2enum(const char *str, const char *comment, int *val) 215 | { 216 | const char *p; 217 | char s[32]; 218 | 219 | for (p=comment;;p++) { 220 | if (!(p=strstr(p,str))) break; 221 | if (*(p-1)!=':') continue; 222 | for (p-=2;'0'<=*p&&*p<='9';p--) ; 223 | return sscanf(p+1,"%d",val)==1; 224 | } 225 | sprintf(s,"%.30s:",str); 226 | if ((p=strstr(comment,s))) { /* number */ 227 | return sscanf(p,"%d",val)==1; 228 | } 229 | return 0; 230 | } 231 | /* search option --------------------------------------------------------------- 232 | * search option record 233 | * args : char *name I option name 234 | * opt_t *opts I options table 235 | * (terminated with table[i].name="") 236 | * return : option record (NULL: not found) 237 | *-----------------------------------------------------------------------------*/ 238 | extern opt_t *searchopt(const char *name, const opt_t *opts) 239 | { 240 | int i; 241 | 242 | trace(3,"searchopt: name=%s\n",name); 243 | 244 | for (i=0;*opts[i].name;i++) { 245 | if (strstr(opts[i].name,name)) return (opt_t *)(opts+i); 246 | } 247 | return NULL; 248 | } 249 | /* string to option value ------------------------------------------------------ 250 | * convert string to option value 251 | * args : opt_t *opt O option 252 | * char *str I option value string 253 | * return : status (1:ok,0:error) 254 | *-----------------------------------------------------------------------------*/ 255 | extern int str2opt(opt_t *opt, const char *str) 256 | { 257 | switch (opt->format) { 258 | case 0: *(int *)opt->var=atoi(str); break; 259 | case 1: *(double *)opt->var=atof(str); break; 260 | case 2: strcpy((char *)opt->var,str); break; 261 | case 3: return str2enum(str,opt->comment,(int *)opt->var); 262 | default: return 0; 263 | } 264 | return 1; 265 | } 266 | /* option value to string ------------------------------------------------------ 267 | * convert option value to string 268 | * args : opt_t *opt I option 269 | * char *str O option value string 270 | * return : length of output string 271 | *-----------------------------------------------------------------------------*/ 272 | extern int opt2str(const opt_t *opt, char *str) 273 | { 274 | char *p=str; 275 | 276 | trace(3,"opt2str : name=%s\n",opt->name); 277 | 278 | switch (opt->format) { 279 | case 0: p+=sprintf(p,"%d" ,*(int *)opt->var); break; 280 | case 1: p+=sprintf(p,"%.15g",*(double*)opt->var); break; 281 | case 2: p+=sprintf(p,"%s" , (char *)opt->var); break; 282 | case 3: p+=enum2str(p,opt->comment,*(int *)opt->var); break; 283 | } 284 | return (int)(p-str); 285 | } 286 | /* option to string ------------------------------------------------------------- 287 | * convert option to string (keyword=value # comment) 288 | * args : opt_t *opt I option 289 | * char *buff O option string 290 | * return : length of output string 291 | *-----------------------------------------------------------------------------*/ 292 | extern int opt2buf(const opt_t *opt, char *buff) 293 | { 294 | char *p=buff; 295 | int n; 296 | 297 | trace(3,"opt2buf : name=%s\n",opt->name); 298 | 299 | p+=sprintf(p,"%-18s =",opt->name); 300 | p+=opt2str(opt,p); 301 | if (*opt->comment) { 302 | if ((n=(int)(buff+30-p))>0) p+=sprintf(p,"%*s",n,""); 303 | p+=sprintf(p," # (%s)",opt->comment); 304 | } 305 | return (int)(p-buff); 306 | } 307 | /* load options ---------------------------------------------------------------- 308 | * load options from file 309 | * args : char *file I options file 310 | * opt_t *opts IO options table 311 | * (terminated with table[i].name="") 312 | * return : status (1:ok,0:error) 313 | *-----------------------------------------------------------------------------*/ 314 | extern int loadopts(const char *file, opt_t *opts) 315 | { 316 | FILE *fp; 317 | opt_t *opt; 318 | char buff[2048],*p; 319 | int n=0; 320 | 321 | trace(3,"loadopts: file=%s\n",file); 322 | 323 | if (!(fp=fopen(file,"r"))) { 324 | trace(1,"loadopts: options file open error (%s)\n",file); 325 | return 0; 326 | } 327 | while (fgets(buff,sizeof(buff),fp)) { 328 | n++; 329 | chop(buff); 330 | 331 | if (buff[0]=='\0') continue; 332 | 333 | if (!(p=strstr(buff,"="))) { 334 | fprintf(stderr,"invalid option %s (%s:%d)\n",buff,file,n); 335 | continue; 336 | } 337 | *p++='\0'; 338 | chop(buff); 339 | if (!(opt=searchopt(buff,opts))) continue; 340 | 341 | if (!str2opt(opt,p)) { 342 | fprintf(stderr,"invalid option value %s (%s:%d)\n",buff,file,n); 343 | continue; 344 | } 345 | } 346 | fclose(fp); 347 | 348 | return 1; 349 | } 350 | /* save options to file -------------------------------------------------------- 351 | * save options to file 352 | * args : char *file I options file 353 | * char *mode I write mode ("w":overwrite,"a":append); 354 | * char *comment I header comment (NULL: no comment) 355 | * opt_t *opts I options table 356 | * (terminated with table[i].name="") 357 | * return : status (1:ok,0:error) 358 | *-----------------------------------------------------------------------------*/ 359 | extern int saveopts(const char *file, const char *mode, const char *comment, 360 | const opt_t *opts) 361 | { 362 | FILE *fp; 363 | char buff[2048]; 364 | int i; 365 | 366 | trace(3,"saveopts: file=%s mode=%s\n",file,mode); 367 | 368 | if (!(fp=fopen(file,mode))) { 369 | trace(1,"saveopts: options file open error (%s)\n",file); 370 | return 0; 371 | } 372 | if (comment) fprintf(fp,"# %s\n\n",comment); 373 | 374 | for (i=0;*opts[i].name;i++) { 375 | opt2buf(opts+i,buff); 376 | fprintf(fp,"%s\n",buff); 377 | } 378 | fclose(fp); 379 | return 1; 380 | } 381 | /* system options buffer to options ------------------------------------------*/ 382 | static void buff2sysopts(void) 383 | { 384 | double pos[3],*rr; 385 | char buff[1024],*p,*id; 386 | int i,j,sat,*ps; 387 | 388 | prcopt_.elmin =elmask_ *D2R; 389 | prcopt_.elmaskar =elmaskar_ *D2R; 390 | prcopt_.elmaskhold=elmaskhold_*D2R; 391 | 392 | for (i=0;i<2;i++) { 393 | ps=i==0?&prcopt_.rovpos:&prcopt_.refpos; 394 | rr=i==0?prcopt_.ru:prcopt_.rb; 395 | 396 | if (antpostype_[i]==0) { /* lat/lon/hgt */ 397 | *ps=0; 398 | pos[0]=antpos_[i][0]*D2R; 399 | pos[1]=antpos_[i][1]*D2R; 400 | pos[2]=antpos_[i][2]; 401 | pos2ecef(pos,rr); 402 | } 403 | else if (antpostype_[i]==1) { /* xyz-ecef */ 404 | *ps=0; 405 | rr[0]=antpos_[i][0]; 406 | rr[1]=antpos_[i][1]; 407 | rr[2]=antpos_[i][2]; 408 | } 409 | else *ps=antpostype_[i]-1; 410 | } 411 | /* excluded satellites */ 412 | for (i=0;i0?",":"",prcopt_.snrmask.mask[i][j]); 474 | } 475 | } 476 | /* number of frequency (4:L1+L5) */ 477 | if (prcopt_.nf==3&&prcopt_.freqopt==1) { 478 | prcopt_.nf=4; 479 | prcopt_.freqopt=0; 480 | } 481 | } 482 | /* reset system options to default --------------------------------------------- 483 | * reset system options to default 484 | * args : none 485 | * return : none 486 | *-----------------------------------------------------------------------------*/ 487 | extern void resetsysopts(void) 488 | { 489 | int i,j; 490 | 491 | trace(3,"resetsysopts:\n"); 492 | 493 | prcopt_=prcopt_default; 494 | solopt_=solopt_default; 495 | filopt_.satantp[0]='\0'; 496 | filopt_.rcvantp[0]='\0'; 497 | filopt_.stapos [0]='\0'; 498 | filopt_.geoid [0]='\0'; 499 | filopt_.dcb [0]='\0'; 500 | filopt_.blq [0]='\0'; 501 | filopt_.solstat[0]='\0'; 502 | filopt_.trace [0]='\0'; 503 | for (i=0;i<2;i++) antpostype_[i]=0; 504 | elmask_=15.0; 505 | elmaskar_=0.0; 506 | elmaskhold_=0.0; 507 | for (i=0;i<2;i++) for (j=0;j<3;j++) { 508 | antpos_[i][j]=0.0; 509 | } 510 | exsats_[0] ='\0'; 511 | } 512 | /* get system options ---------------------------------------------------------- 513 | * get system options 514 | * args : prcopt_t *popt IO processing options (NULL: no output) 515 | * solopt_t *sopt IO solution options (NULL: no output) 516 | * folopt_t *fopt IO file options (NULL: no output) 517 | * return : none 518 | * notes : to load system options, use loadopts() before calling the function 519 | *-----------------------------------------------------------------------------*/ 520 | extern void getsysopts(prcopt_t *popt, solopt_t *sopt, filopt_t *fopt) 521 | { 522 | trace(3,"getsysopts:\n"); 523 | 524 | buff2sysopts(); 525 | if (popt) *popt=prcopt_; 526 | if (sopt) *sopt=solopt_; 527 | if (fopt) *fopt=filopt_; 528 | } 529 | /* set system options ---------------------------------------------------------- 530 | * set system options 531 | * args : prcopt_t *prcopt I processing options (NULL: default) 532 | * solopt_t *solopt I solution options (NULL: default) 533 | * filopt_t *filopt I file options (NULL: default) 534 | * return : none 535 | * notes : to save system options, use saveopts() after calling the function 536 | *-----------------------------------------------------------------------------*/ 537 | extern void setsysopts(const prcopt_t *prcopt, const solopt_t *solopt, 538 | const filopt_t *filopt) 539 | { 540 | trace(3,"setsysopts:\n"); 541 | 542 | resetsysopts(); 543 | if (prcopt) prcopt_=*prcopt; 544 | if (solopt) solopt_=*solopt; 545 | if (filopt) filopt_=*filopt; 546 | sysopts2buff(); 547 | } 548 | -------------------------------------------------------------------------------- /src/ppp_ar.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * ppp_ar.c : ppp ambiguity resolution 3 | * 4 | * reference : 5 | * [1] H.Okumura, C-gengo niyoru saishin algorithm jiten (in Japanese), 6 | * Software Technology, 1991 7 | * 8 | * Copyright (C) 2012-2015 by T.TAKASU, All rights reserved. 9 | * 10 | * version : $Revision:$ $Date:$ 11 | * history : 2013/03/11 1.0 new 12 | * 2016/05/10 1.1 delete codes 13 | *-----------------------------------------------------------------------------*/ 14 | #include "rtklib.h" 15 | 16 | /* ambiguity resolution in ppp -----------------------------------------------*/ 17 | extern int ppp_ar(rtk_t *rtk, const obsd_t *obs, int n, int *exc, 18 | const nav_t *nav, const double *azel, double *x, double *P) 19 | { 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/rnx2rtkp.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rnx2rtkp.c : read rinex obs/nav files and compute receiver positions 3 | * 4 | * Copyright (C) 2007-2016 by T.TAKASU, All rights reserved. 5 | * 6 | * version : $Revision: 1.1 $ $Date: 2008/07/17 21:55:16 $ 7 | * history : 2007/01/16 1.0 new 8 | * 2007/03/15 1.1 add library mode 9 | * 2007/05/08 1.2 separate from postpos.c 10 | * 2009/01/20 1.3 support rtklib 2.2.0 api 11 | * 2009/12/12 1.4 support glonass 12 | * add option -h, -a, -l, -x 13 | * 2010/01/28 1.5 add option -k 14 | * 2010/08/12 1.6 add option -y implementation (2.4.0_p1) 15 | * 2014/01/27 1.7 fix bug on default output time format 16 | * 2015/05/15 1.8 -r or -l options for fixed or ppp-fixed mode 17 | * 2015/06/12 1.9 output patch level in header 18 | * 2016/09/07 1.10 add option -sys 19 | *-----------------------------------------------------------------------------*/ 20 | #include 21 | #include "rtklib.h" 22 | #include "B2bLIB.h" 23 | 24 | 25 | #define PROGNAME "rnx2rtkp" /* program name */ 26 | #define MAXFILE 16 /* max number of input files */ 27 | extern nav_t navs; 28 | /* help text -----------------------------------------------------------------*/ 29 | static const char *help[]={ 30 | "", 31 | " usage: rnx2rtkp [option]... file file [...]", 32 | "", 33 | " Read RINEX OBS/NAV/GNAV/HNAV/CLK, SP3, SBAS message log files and ccompute ", 34 | " receiver (rover) positions and output position solutions.", 35 | " The first RINEX OBS file shall contain receiver (rover) observations. For the", 36 | " relative mode, the second RINEX OBS file shall contain reference", 37 | " (base station) receiver observations. At least one RINEX NAV/GNAV/HNAV", 38 | " file shall be included in input files. To use SP3 precise ephemeris, specify", 39 | " the path in the files. The extension of the SP3 file shall be .sp3 or .eph.", 40 | " All of the input file paths can include wild-cards (*). To avoid command", 41 | " line deployment of wild-cards, use \"...\" for paths with wild-cards.", 42 | " Command line options are as follows ([]:default). With -k option, the", 43 | " processing options are input from the configuration file. In this case,", 44 | " command line options precede options in the configuration file.", 45 | "", 46 | " -? print help", 47 | " -k file input options from configuration file [off]", 48 | " -o file set output file [stdout]", 49 | " -ts ds ts start day/time (ds=y/m/d ts=h:m:s) [obs start time]", 50 | " -te de te end day/time (de=y/m/d te=h:m:s) [obs end time]", 51 | " -ti tint time interval (sec) [all]", 52 | " -p mode mode (0:single,1:dgps,2:kinematic,3:static,4:moving-base,", 53 | " 5:fixed,6:ppp-kinematic,7:ppp-static) [2]", 54 | " -m mask elevation mask angle (deg) [15]", 55 | " -sys s[,s...] nav system(s) (s=G:GPS,R:GLO,E:GAL,J:QZS,C:BDS,I:IRN) [G|R]", 56 | " -f freq number of frequencies for relative mode (1:L1,2:L1+L2,3:L1+L2+L5) [2]", 57 | " -v thres validation threshold for integer ambiguity (0.0:no AR) [3.0]", 58 | " -b backward solutions [off]", 59 | " -c forward/backward combined solutions [off]", 60 | " -i instantaneous integer ambiguity resolution [off]", 61 | " -h fix and hold for integer ambiguity resolution [off]", 62 | " -e output x/y/z-ecef position [latitude/longitude/height]", 63 | " -a output e/n/u-baseline [latitude/longitude/height]", 64 | " -n output NMEA-0183 GGA sentence [off]", 65 | " -g output latitude/longitude in the form of ddd mm ss.ss' [ddd.ddd]", 66 | " -t output time in the form of yyyy/mm/dd hh:mm:ss.ss [sssss.ss]", 67 | " -u output time in utc [gpst]", 68 | " -d col number of decimals in time [3]", 69 | " -s sep field separator [' ']", 70 | " -r x y z reference (base) receiver ecef pos (m) [average of single pos]", 71 | " rover receiver ecef pos (m) for fixed or ppp-fixed mode", 72 | " -l lat lon hgt reference (base) receiver latitude/longitude/height (deg/m)", 73 | " rover latitude/longitude/height for fixed or ppp-fixed mode", 74 | " -y level output soltion status (0:off,1:states,2:residuals) [0]", 75 | " -x level debug trace level (0:off) [0]" 76 | }; 77 | /* show message --------------------------------------------------------------*/ 78 | extern int showmsg(const char *format, ...) 79 | { 80 | va_list arg; 81 | va_start(arg,format); vfprintf(stderr,format,arg); va_end(arg); 82 | fprintf(stderr,"\r"); 83 | return 0; 84 | } 85 | extern void settspan(gtime_t ts, gtime_t te) {} 86 | extern void settime(gtime_t time) {} 87 | 88 | /* print help ----------------------------------------------------------------*/ 89 | static void printhelp(void) 90 | { 91 | int i; 92 | for (i=0;i<(int)(sizeof(help)/sizeof(*help));i++) fprintf(stderr,"%s\n",help[i]); 93 | exit(0); 94 | } 95 | 96 | 97 | /* rnx2rtkp main -------------------------------------------------------------*/ 98 | int main(int argc, char **argv) 99 | { 100 | prcopt_t prcopt=prcopt_default; 101 | solopt_t solopt=solopt_default; 102 | filopt_t filopt={""}; 103 | gtime_t ts={0},te={0}; 104 | double tint=0.0,es[]={2000,1,1,0,0,0},ee[]={2000,12,31,23,59,59},pos[3]; 105 | int i,j,n,ret; 106 | char *infile[MAXFILE],*outfile="",*p, rinex4NavfilePath[256]; 107 | 108 | prcopt.mode =PMODE_KINEMA; 109 | prcopt.navsys=0; 110 | prcopt.refpos=1; 111 | prcopt.glomodear=1; 112 | solopt.timef=0; 113 | sprintf(solopt.prog ,"%s ver.%s %s",PROGNAME,VER_RTKLIB,PATCH_LEVEL); 114 | sprintf(filopt.trace,"%s.trace",PROGNAME); 115 | 116 | //GCC Set RINEX 4.0 broadcast ephemeris file path 117 | strcpy(rinex4NavfilePath, "../../testdata/brd42370.24p"); 118 | //GCC Read the RINEX 4.0 broadcast ephemeris 119 | if (!readRinex4Nav(rinex4NavfilePath, &navs)) 120 | { 121 | fprintf(stderr, "READ Rinex4nav Ephemeris ERROR\n"); fflush(stderr); 122 | } 123 | 124 | /* Load options from configuration file */ 125 | for (i=1;i rtk_crc24q() 37 | * 2018/10/10 1.10 fix bug on initializing rtcm struct 38 | * add rtcm option -GALINAV, -GALFNAV 39 | * 2018/11/05 1.11 add notes for api gen_rtcm3() 40 | * 2020/11/30 1.12 modify API gen_rtcm3() 41 | * support NavIC/IRNSS MSM and ephemeris (ref [17]) 42 | * allocate double size of ephemeris buffer to support 43 | * multiple ephemeris sets in init_rtcm() 44 | * delete references [2]-[6],[8],[9],[11]-[14] 45 | * update reference [17] 46 | * use integer types in stdint.h 47 | *-----------------------------------------------------------------------------*/ 48 | #include "rtklib.h" 49 | 50 | /* function prototypes -------------------------------------------------------*/ 51 | extern int decode_rtcm2(rtcm_t *rtcm); 52 | extern int decode_rtcm3(rtcm_t *rtcm); 53 | extern int encode_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync); 54 | 55 | /* constants -----------------------------------------------------------------*/ 56 | 57 | #define RTCM2PREAMB 0x66 /* rtcm ver.2 frame preamble */ 58 | #define RTCM3PREAMB 0xD3 /* rtcm ver.3 frame preamble */ 59 | 60 | /* initialize rtcm control ----------------------------------------------------- 61 | * initialize rtcm control struct and reallocate memory for observation and 62 | * ephemeris buffer in rtcm control struct 63 | * args : rtcm_t *raw IO rtcm control struct 64 | * return : status (1:ok,0:memory allocation error) 65 | *-----------------------------------------------------------------------------*/ 66 | extern int init_rtcm(rtcm_t *rtcm) 67 | { 68 | gtime_t time0={0}; 69 | obsd_t data0={{0}}; 70 | eph_t eph0 ={0,-1,-1}; 71 | geph_t geph0={0,-1}; 72 | ssr_t ssr0={{{0}}}; 73 | int i,j; 74 | 75 | trace(3,"init_rtcm:\n"); 76 | 77 | rtcm->staid=rtcm->stah=rtcm->seqno=rtcm->outtype=0; 78 | rtcm->time=rtcm->time_s=time0; 79 | rtcm->sta.name[0]=rtcm->sta.marker[0]='\0'; 80 | rtcm->sta.antdes[0]=rtcm->sta.antsno[0]='\0'; 81 | rtcm->sta.rectype[0]=rtcm->sta.recver[0]=rtcm->sta.recsno[0]='\0'; 82 | rtcm->sta.antsetup=rtcm->sta.itrf=rtcm->sta.deltype=0; 83 | for (i=0;i<3;i++) { 84 | rtcm->sta.pos[i]=rtcm->sta.del[i]=0.0; 85 | } 86 | rtcm->sta.hgt=0.0; 87 | rtcm->dgps=NULL; 88 | for (i=0;issr[i]=ssr0; 90 | } 91 | rtcm->msg[0]=rtcm->msgtype[0]=rtcm->opt[0]='\0'; 92 | for (i=0;i<6;i++) rtcm->msmtype[i][0]='\0'; 93 | rtcm->obsflag=rtcm->ephsat=0; 94 | for (i=0;icp[i][j]=0.0; 96 | rtcm->lock[i][j]=rtcm->loss[i][j]=0; 97 | rtcm->lltime[i][j]=time0; 98 | } 99 | rtcm->nbyte=rtcm->nbit=rtcm->len=0; 100 | rtcm->word=0; 101 | for (i=0;i<100;i++) rtcm->nmsg2[i]=0; 102 | for (i=0;i<400;i++) rtcm->nmsg3[i]=0; 103 | 104 | rtcm->obs.data=NULL; 105 | rtcm->nav.eph =NULL; 106 | rtcm->nav.geph=NULL; 107 | 108 | /* reallocate memory for observation and ephemeris buffer */ 109 | if (!(rtcm->obs.data=(obsd_t *)malloc(sizeof(obsd_t)*MAXOBS))|| 110 | !(rtcm->nav.eph =(eph_t *)malloc(sizeof(eph_t )*MAXSAT*2))|| 111 | !(rtcm->nav.geph=(geph_t *)malloc(sizeof(geph_t)*MAXPRNGLO))) { 112 | free_rtcm(rtcm); 113 | return 0; 114 | } 115 | rtcm->obs.n=0; 116 | rtcm->nav.n=MAXSAT*2; 117 | rtcm->nav.ng=MAXPRNGLO; 118 | for (i=0;iobs.data[i]=data0; 119 | for (i=0;inav.eph [i]=eph0; 120 | for (i=0;inav.geph[i]=geph0; 121 | return 1; 122 | } 123 | /* free rtcm control ---------------------------------------------------------- 124 | * free observation and ephemeris buffer in rtcm control struct 125 | * args : rtcm_t *raw IO rtcm control struct 126 | * return : none 127 | *-----------------------------------------------------------------------------*/ 128 | extern void free_rtcm(rtcm_t *rtcm) 129 | { 130 | trace(3,"free_rtcm:\n"); 131 | 132 | /* free memory for observation and ephemeris buffer */ 133 | free(rtcm->obs.data); rtcm->obs.data=NULL; rtcm->obs.n=0; 134 | free(rtcm->nav.eph ); rtcm->nav.eph =NULL; rtcm->nav.n=0; 135 | free(rtcm->nav.geph); rtcm->nav.geph=NULL; rtcm->nav.ng=0; 136 | } 137 | /* input RTCM 2 message from stream -------------------------------------------- 138 | * fetch next RTCM 2 message and input a message from byte stream 139 | * args : rtcm_t *rtcm IO rtcm control struct 140 | * uint8_t data I stream data (1 byte) 141 | * return : status (-1: error message, 0: no message, 1: input observation data, 142 | * 2: input ephemeris, 5: input station pos/ant parameters, 143 | * 6: input time parameter, 7: input dgps corrections, 144 | * 9: input special message) 145 | * notes : before firstly calling the function, time in rtcm control struct has 146 | * to be set to the approximate time within 1/2 hour in order to resolve 147 | * ambiguity of time in rtcm messages. 148 | * supported msgs RTCM ver.2: 1,3,9,14,16,17,18,19,22 149 | * refer [1] for RTCM ver.2 150 | *-----------------------------------------------------------------------------*/ 151 | extern int input_rtcm2(rtcm_t *rtcm, uint8_t data) 152 | { 153 | uint8_t preamb; 154 | int i; 155 | 156 | trace(5,"input_rtcm2: data=%02x\n",data); 157 | 158 | if ((data&0xC0)!=0x40) return 0; /* ignore if upper 2bit != 01 */ 159 | 160 | for (i=0;i<6;i++,data>>=1) { /* decode 6-of-8 form */ 161 | rtcm->word=(rtcm->word<<1)+(data&1); 162 | 163 | /* synchronize frame */ 164 | if (rtcm->nbyte==0) { 165 | preamb=(uint8_t)(rtcm->word>>22); 166 | if (rtcm->word&0x40000000) preamb^=0xFF; /* decode preamble */ 167 | if (preamb!=RTCM2PREAMB) continue; 168 | 169 | /* check parity */ 170 | if (!decode_word(rtcm->word,rtcm->buff)) continue; 171 | rtcm->nbyte=3; rtcm->nbit=0; 172 | continue; 173 | } 174 | if (++rtcm->nbit<30) continue; else rtcm->nbit=0; 175 | 176 | /* check parity */ 177 | if (!decode_word(rtcm->word,rtcm->buff+rtcm->nbyte)) { 178 | trace(2,"rtcm2 partity error: i=%d word=%08x\n",i,rtcm->word); 179 | rtcm->nbyte=0; rtcm->word&=0x3; 180 | continue; 181 | } 182 | rtcm->nbyte+=3; 183 | if (rtcm->nbyte==6) rtcm->len=(rtcm->buff[5]>>3)*3+6; 184 | if (rtcm->nbytelen) continue; 185 | rtcm->nbyte=0; rtcm->word&=0x3; 186 | 187 | /* decode rtcm2 message */ 188 | return decode_rtcm2(rtcm); 189 | } 190 | return 0; 191 | } 192 | /* input RTCM 3 message from stream -------------------------------------------- 193 | * fetch next RTCM 3 message and input a message from byte stream 194 | * args : rtcm_t *rtcm IO rtcm control struct 195 | * uint8_t data I stream data (1 byte) 196 | * return : status (-1: error message, 0: no message, 1: input observation data, 197 | * 2: input ephemeris, 5: input station pos/ant parameters, 198 | * 10: input ssr messages) 199 | * notes : before firstly calling the function, time in rtcm control struct has 200 | * to be set to the approximate time within 1/2 week in order to resolve 201 | * ambiguity of time in rtcm messages. 202 | * 203 | * to specify input options, set rtcm->opt to the following option 204 | * strings separated by spaces. 205 | * 206 | * -EPHALL : input all ephemerides (default: only new) 207 | * -STA=nnn : input only message with STAID=nnn (default: all) 208 | * -GLss : select signal ss for GPS MSM (ss=1C,1P,...) 209 | * -RLss : select signal ss for GLO MSM (ss=1C,1P,...) 210 | * -ELss : select signal ss for GAL MSM (ss=1C,1B,...) 211 | * -JLss : select signal ss for QZS MSM (ss=1C,2C,...) 212 | * -CLss : select signal ss for BDS MSM (ss=2I,7I,...) 213 | * -ILss : select signal ss for IRN MSM (ss=5A,9A,...) 214 | * -GALINAV : select I/NAV for Galileo ephemeris (default: all) 215 | * -GALFNAV : select F/NAV for Galileo ephemeris (default: all) 216 | * 217 | * supported RTCM 3 messages (ref [7][10][15][16][17][18]) 218 | * 219 | * TYPE : GPS GLONASS Galileo QZSS BDS SBAS NavIC 220 | * ---------------------------------------------------------------------- 221 | * OBS COMP L1 : 1001~ 1009~ - - - - - 222 | * FULL L1 : 1002 1010 - - - - - 223 | * COMP L1L2: 1003~ 1011~ - - - - - 224 | * FULL L1L2: 1004 1012 - - - - - 225 | * 226 | * NAV : 1019 1020 1045** 1044 1042 - 1041 227 | * - - 1046** - 63* - - 228 | * 229 | * MSM 1 : 1071~ 1081~ 1091~ 1111~ 1121~ 1101~ 1131~ 230 | * 2 : 1072~ 1082~ 1092~ 1112~ 1122~ 1102~ 1132~ 231 | * 3 : 1073~ 1083~ 1093~ 1113~ 1123~ 1103~ 1133~ 232 | * 4 : 1074 1084 1094 1114 1124 1104 1134 233 | * 5 : 1075 1085 1095 1115 1125 1105 1135 234 | * 6 : 1076 1086 1096 1116 1126 1106 1136 235 | * 7 : 1077 1087 1097 1117 1127 1107 1137 236 | * 237 | * SSR ORBIT : 1057 1063 1240* 1246* 1258* - - 238 | * CLOCK : 1058 1064 1241* 1247* 1259* - - 239 | * CODE BIAS: 1059 1065 1242* 1248* 1260* - - 240 | * OBT/CLK : 1060 1066 1243* 1249* 1261* - - 241 | * URA : 1061 1067 1244* 1250* 1262* - - 242 | * HR-CLOCK : 1062 1068 1245* 1251* 1263* - - 243 | * PHAS BIAS: 11* - 12* 13* 14* - - 244 | * 245 | * ANT/RCV INFO : 1007 1008 1033 246 | * STA POSITION : 1005 1006 247 | * 248 | * PROPRIETARY : 4076 (IGS) 249 | * ---------------------------------------------------------------------- 250 | * (* draft, ** 1045:F/NAV,1046:I/NAV, ~ only encode) 251 | * 252 | * for MSM observation data with multiple signals for a frequency, 253 | * a signal is selected according to internal priority. to select 254 | * a specified signal, use the input options. 255 | * 256 | * RTCM 3 message format: 257 | * +----------+--------+-----------+--------------------+----------+ 258 | * | preamble | 000000 | length | data message | parity | 259 | * +----------+--------+-----------+--------------------+----------+ 260 | * |<-- 8 --->|<- 6 -->|<-- 10 --->|<--- length x 8 --->|<-- 24 -->| 261 | * 262 | *-----------------------------------------------------------------------------*/ 263 | extern int input_rtcm3(rtcm_t *rtcm, uint8_t data) 264 | { 265 | trace(5,"input_rtcm3: data=%02x\n",data); 266 | 267 | /* synchronize frame */ 268 | if (rtcm->nbyte==0) { 269 | if (data!=RTCM3PREAMB) return 0; 270 | rtcm->buff[rtcm->nbyte++]=data; 271 | return 0; 272 | } 273 | rtcm->buff[rtcm->nbyte++]=data; 274 | 275 | if (rtcm->nbyte==3) { 276 | rtcm->len=getbitu(rtcm->buff,14,10)+3; /* length without parity */ 277 | } 278 | if (rtcm->nbyte<3||rtcm->nbytelen+3) return 0; 279 | rtcm->nbyte=0; 280 | 281 | /* check parity */ 282 | if (rtk_crc24q(rtcm->buff,rtcm->len)!=getbitu(rtcm->buff,rtcm->len*8,24)) { 283 | trace(2,"rtcm3 parity error: len=%d\n",rtcm->len); 284 | return 0; 285 | } 286 | /* decode rtcm3 message */ 287 | return decode_rtcm3(rtcm); 288 | } 289 | /* input RTCM 2 message from file ---------------------------------------------- 290 | * fetch next RTCM 2 message and input a messsage from file 291 | * args : rtcm_t *rtcm IO rtcm control struct 292 | * FILE *fp I file pointer 293 | * return : status (-2: end of file, -1...10: same as above) 294 | * notes : same as above 295 | *-----------------------------------------------------------------------------*/ 296 | extern int input_rtcm2f(rtcm_t *rtcm, FILE *fp) 297 | { 298 | int i,data=0,ret; 299 | 300 | trace(4,"input_rtcm2f: data=%02x\n",data); 301 | 302 | for (i=0;i<4096;i++) { 303 | if ((data=fgetc(fp))==EOF) return -2; 304 | if ((ret=input_rtcm2(rtcm,(uint8_t)data))) return ret; 305 | } 306 | return 0; /* return at every 4k bytes */ 307 | } 308 | /* input RTCM 3 message from file ---------------------------------------------- 309 | * fetch next RTCM 3 message and input a messsage from file 310 | * args : rtcm_t *rtcm IO rtcm control struct 311 | * FILE *fp I file pointer 312 | * return : status (-2: end of file, -1...10: same as above) 313 | * notes : same as above 314 | *-----------------------------------------------------------------------------*/ 315 | extern int input_rtcm3f(rtcm_t *rtcm, FILE *fp) 316 | { 317 | int i,data=0,ret; 318 | 319 | trace(4,"input_rtcm3f: data=%02x\n",data); 320 | 321 | for (i=0;i<4096;i++) { 322 | if ((data=fgetc(fp))==EOF) return -2; 323 | if ((ret=input_rtcm3(rtcm,(uint8_t)data))) return ret; 324 | } 325 | return 0; /* return at every 4k bytes */ 326 | } 327 | /* generate RTCM 2 message ----------------------------------------------------- 328 | * generate RTCM 2 message 329 | * args : rtcm_t *rtcm IO rtcm control struct 330 | * int type I message type 331 | * int sync I sync flag (1:another message follows) 332 | * return : status (1:ok,0:error) 333 | *-----------------------------------------------------------------------------*/ 334 | extern int gen_rtcm2(rtcm_t *rtcm, int type, int sync) 335 | { 336 | trace(4,"gen_rtcm2: type=%d sync=%d\n",type,sync); 337 | 338 | rtcm->nbit=rtcm->len=rtcm->nbyte=0; 339 | 340 | /* not yet implemented */ 341 | 342 | return 0; 343 | } 344 | /* generate RTCM 3 message ----------------------------------------------------- 345 | * generate RTCM 3 message 346 | * args : rtcm_t *rtcm IO rtcm control struct 347 | * int type I message type 348 | * int subtype I message subtype 349 | * int sync I sync flag (1:another message follows) 350 | * return : status (1:ok,0:error) 351 | * notes : For rtcm 3 msm, the {nsat} x {nsig} in rtcm->obs should not exceed 352 | * 64. If {nsat} x {nsig} of the input obs data exceeds 64, separate 353 | * them to multiple ones and call gen_rtcm3() multiple times as user 354 | * responsibility. 355 | * ({nsat} = number of valid satellites, {nsig} = number of signals in 356 | * the obs data) 357 | *-----------------------------------------------------------------------------*/ 358 | extern int gen_rtcm3(rtcm_t *rtcm, int type, int subtype, int sync) 359 | { 360 | uint32_t crc; 361 | int i=0; 362 | 363 | trace(4,"gen_rtcm3: type=%d subtype=%d sync=%d\n",type,subtype,sync); 364 | 365 | rtcm->nbit=rtcm->len=rtcm->nbyte=0; 366 | 367 | /* set preamble and reserved */ 368 | setbitu(rtcm->buff,i, 8,RTCM3PREAMB); i+= 8; 369 | setbitu(rtcm->buff,i, 6,0 ); i+= 6; 370 | setbitu(rtcm->buff,i,10,0 ); i+=10; 371 | 372 | /* encode rtcm 3 message body */ 373 | if (!encode_rtcm3(rtcm,type,subtype,sync)) return 0; 374 | 375 | /* padding to align 8 bit boundary */ 376 | for (i=rtcm->nbit;i%8;i++) { 377 | setbitu(rtcm->buff,i,1,0); 378 | } 379 | /* message length (header+data) (bytes) */ 380 | if ((rtcm->len=i/8)>=3+1024) { 381 | trace(2,"generate rtcm 3 message length error len=%d\n",rtcm->len-3); 382 | rtcm->nbit=rtcm->len=0; 383 | return 0; 384 | } 385 | /* message length without header and parity */ 386 | setbitu(rtcm->buff,14,10,rtcm->len-3); 387 | 388 | /* crc-24q */ 389 | crc=rtk_crc24q(rtcm->buff,rtcm->len); 390 | setbitu(rtcm->buff,i,24,crc); 391 | 392 | /* length total (bytes) */ 393 | rtcm->nbyte=rtcm->len+3; 394 | 395 | return 1; 396 | } 397 | -------------------------------------------------------------------------------- /src/rtcm2.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * rtcm2.c : rtcm ver.2 message functions 3 | * 4 | * Copyright (C) 2009-2014 by T.TAKASU, All rights reserved. 5 | * 6 | * references : 7 | * see rtcm.c 8 | * 9 | * version : $Revision:$ $Date:$ 10 | * history : 2011/11/28 1.0 separated from rtcm.c 11 | * 2014/10/21 1.1 fix problem on week rollover in rtcm 2 type 14 12 | *-----------------------------------------------------------------------------*/ 13 | #include "rtklib.h" 14 | 15 | /* adjust hourly rollover of rtcm 2 time -------------------------------------*/ 16 | static void adjhour(rtcm_t *rtcm, double zcnt) 17 | { 18 | double tow,hour,sec; 19 | int week; 20 | 21 | /* if no time, get cpu time */ 22 | if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); 23 | tow=time2gpst(rtcm->time,&week); 24 | hour=floor(tow/3600.0); 25 | sec=tow-hour*3600.0; 26 | if (zcntsec+1800.0) zcnt-=3600.0; 28 | rtcm->time=gpst2time(week,hour*3600+zcnt); 29 | } 30 | /* get observation data index ------------------------------------------------*/ 31 | static int obsindex(obs_t *obs, gtime_t time, int sat) 32 | { 33 | int i,j; 34 | 35 | for (i=0;in;i++) { 36 | if (obs->data[i].sat==sat) return i; /* field already exists */ 37 | } 38 | if (i>=MAXOBS) return -1; /* overflow */ 39 | 40 | /* add new field */ 41 | obs->data[i].time=time; 42 | obs->data[i].sat=sat; 43 | for (j=0;jdata[i].L[j]=obs->data[i].P[j]=0.0; 45 | obs->data[i].D[j]=0.0; 46 | obs->data[i].SNR[j]=obs->data[i].LLI[j]=obs->data[i].code[j]=0; 47 | } 48 | obs->n++; 49 | return i; 50 | } 51 | /* decode type 1/9: differential gps correction/partial correction set -------*/ 52 | static int decode_type1(rtcm_t *rtcm) 53 | { 54 | int i=48,fact,udre,prn,sat,iod; 55 | double prc,rrc; 56 | 57 | trace(4,"decode_type1: len=%d\n",rtcm->len); 58 | 59 | while (i+40<=rtcm->len*8) { 60 | fact=getbitu(rtcm->buff,i, 1); i+= 1; 61 | udre=getbitu(rtcm->buff,i, 2); i+= 2; 62 | prn =getbitu(rtcm->buff,i, 5); i+= 5; 63 | prc =getbits(rtcm->buff,i,16); i+=16; 64 | rrc =getbits(rtcm->buff,i, 8); i+= 8; 65 | iod =getbits(rtcm->buff,i, 8); i+= 8; 66 | if (prn==0) prn=32; 67 | if (prc==0x80000000||rrc==0xFFFF8000) { 68 | trace(2,"rtcm2 1 prc/rrc indicates satellite problem: prn=%d\n",prn); 69 | continue; 70 | } 71 | if (rtcm->dgps) { 72 | sat=satno(SYS_GPS,prn); 73 | rtcm->dgps[sat-1].t0=rtcm->time; 74 | rtcm->dgps[sat-1].prc=prc*(fact?0.32:0.02); 75 | rtcm->dgps[sat-1].rrc=rrc*(fact?0.032:0.002); 76 | rtcm->dgps[sat-1].iod=iod; 77 | rtcm->dgps[sat-1].udre=udre; 78 | } 79 | } 80 | return 7; 81 | } 82 | /* decode type 3: reference station parameter --------------------------------*/ 83 | static int decode_type3(rtcm_t *rtcm) 84 | { 85 | int i=48; 86 | 87 | trace(4,"decode_type3: len=%d\n",rtcm->len); 88 | 89 | if (i+96<=rtcm->len*8) { 90 | rtcm->sta.pos[0]=getbits(rtcm->buff,i,32)*0.01; i+=32; 91 | rtcm->sta.pos[1]=getbits(rtcm->buff,i,32)*0.01; i+=32; 92 | rtcm->sta.pos[2]=getbits(rtcm->buff,i,32)*0.01; 93 | } 94 | else { 95 | trace(2,"rtcm2 3 length error: len=%d\n",rtcm->len); 96 | return -1; 97 | } 98 | return 5; 99 | } 100 | /* decode type 14: gps time of week ------------------------------------------*/ 101 | static int decode_type14(rtcm_t *rtcm) 102 | { 103 | double zcnt; 104 | int i=48,week,hour,leaps; 105 | 106 | trace(4,"decode_type14: len=%d\n",rtcm->len); 107 | 108 | zcnt=getbitu(rtcm->buff,24,13); 109 | if (i+24<=rtcm->len*8) { 110 | week =getbitu(rtcm->buff,i,10); i+=10; 111 | hour =getbitu(rtcm->buff,i, 8); i+= 8; 112 | leaps=getbitu(rtcm->buff,i, 6); 113 | } 114 | else { 115 | trace(2,"rtcm2 14 length error: len=%d\n",rtcm->len); 116 | return -1; 117 | } 118 | week=adjgpsweek(week); 119 | rtcm->time=gpst2time(week,hour*3600.0+zcnt*0.6); 120 | rtcm->nav.utc_gps[4]=leaps; 121 | return 6; 122 | } 123 | /* decode type 16: gps special message ---------------------------------------*/ 124 | static int decode_type16(rtcm_t *rtcm) 125 | { 126 | int i=48,n=0; 127 | 128 | trace(4,"decode_type16: len=%d\n",rtcm->len); 129 | 130 | while (i+8<=rtcm->len*8&&n<90) { 131 | rtcm->msg[n++]=getbitu(rtcm->buff,i,8); i+=8; 132 | } 133 | rtcm->msg[n]='\0'; 134 | 135 | trace(3,"rtcm2 16 message: %s\n",rtcm->msg); 136 | return 9; 137 | } 138 | /* decode type 17: gps ephemerides -------------------------------------------*/ 139 | static int decode_type17(rtcm_t *rtcm) 140 | { 141 | eph_t eph={0}; 142 | double toc,sqrtA; 143 | int i=48,week,prn,sat; 144 | 145 | trace(4,"decode_type17: len=%d\n",rtcm->len); 146 | 147 | if (i+480<=rtcm->len*8) { 148 | week =getbitu(rtcm->buff,i,10); i+=10; 149 | eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; 150 | eph.iode =getbitu(rtcm->buff,i, 8); i+= 8; 151 | toc =getbitu(rtcm->buff,i,16)*16.0; i+=16; 152 | eph.f1 =getbits(rtcm->buff,i,16)*P2_43; i+=16; 153 | eph.f2 =getbits(rtcm->buff,i, 8)*P2_55; i+= 8; 154 | eph.crs =getbits(rtcm->buff,i,16)*P2_5; i+=16; 155 | eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; 156 | eph.cuc =getbits(rtcm->buff,i,16)*P2_29; i+=16; 157 | eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; 158 | eph.cus =getbits(rtcm->buff,i,16); i+=16; 159 | sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; 160 | eph.toes =getbitu(rtcm->buff,i,16); i+=16; 161 | eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; 162 | eph.cic =getbits(rtcm->buff,i,16)*P2_29; i+=16; 163 | eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; 164 | eph.cis =getbits(rtcm->buff,i,16)*P2_29; i+=16; 165 | eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; 166 | eph.crc =getbits(rtcm->buff,i,16)*P2_5; i+=16; 167 | eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; 168 | eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; 169 | eph.iodc =getbitu(rtcm->buff,i,10); i+=10; 170 | eph.f0 =getbits(rtcm->buff,i,22)*P2_31; i+=22; 171 | prn =getbitu(rtcm->buff,i, 5); i+= 5+3; 172 | eph.tgd[0]=getbits(rtcm->buff,i, 8)*P2_31; i+= 8; 173 | eph.code =getbitu(rtcm->buff,i, 2); i+= 2; 174 | eph.sva =getbitu(rtcm->buff,i, 4); i+= 4; 175 | eph.svh =getbitu(rtcm->buff,i, 6); i+= 6; 176 | eph.flag =getbitu(rtcm->buff,i, 1); 177 | } 178 | else { 179 | trace(2,"rtcm2 17 length error: len=%d\n",rtcm->len); 180 | return -1; 181 | } 182 | if (prn==0) prn=32; 183 | sat=satno(SYS_GPS,prn); 184 | eph.sat=sat; 185 | eph.week=adjgpsweek(week); 186 | eph.toe=gpst2time(eph.week,eph.toes); 187 | eph.toc=gpst2time(eph.week,toc); 188 | eph.ttr=rtcm->time; 189 | eph.A=sqrtA*sqrtA; 190 | rtcm->nav.eph[sat-1]=eph; 191 | rtcm->ephset=0; 192 | rtcm->ephsat=sat; 193 | return 2; 194 | } 195 | /* decode type 18: rtk uncorrected carrier-phase -----------------------------*/ 196 | static int decode_type18(rtcm_t *rtcm) 197 | { 198 | gtime_t time; 199 | double usec,cp,tt; 200 | int i=48,index,freq,sync=1,code,sys,prn,sat,loss; 201 | 202 | trace(4,"decode_type18: len=%d\n",rtcm->len); 203 | 204 | if (i+24<=rtcm->len*8) { 205 | freq=getbitu(rtcm->buff,i, 2); i+= 2+2; 206 | usec=getbitu(rtcm->buff,i,20); i+=20; 207 | } 208 | else { 209 | trace(2,"rtcm2 18 length error: len=%d\n",rtcm->len); 210 | return -1; 211 | } 212 | if (freq&0x1) { 213 | trace(2,"rtcm2 18 not supported frequency: freq=%d\n",freq); 214 | return -1; 215 | } 216 | freq>>=1; 217 | 218 | while (i+48<=rtcm->len*8&&rtcm->obs.nbuff,i, 1); i+= 1; 220 | code=getbitu(rtcm->buff,i, 1); i+= 1; 221 | sys =getbitu(rtcm->buff,i, 1); i+= 1; 222 | prn =getbitu(rtcm->buff,i, 5); i+= 5+3; 223 | loss=getbitu(rtcm->buff,i, 5); i+= 5; 224 | cp =getbits(rtcm->buff,i,32); i+=32; 225 | if (prn==0) prn=32; 226 | if (!(sat=satno(sys?SYS_GLO:SYS_GPS,prn))) { 227 | trace(2,"rtcm2 18 satellite number error: sys=%d prn=%d\n",sys,prn); 228 | continue; 229 | } 230 | time=timeadd(rtcm->time,usec*1E-6); 231 | if (sys) time=utc2gpst(time); /* convert glonass time to gpst */ 232 | 233 | tt=timediff(rtcm->obs.data[0].time,time); 234 | if (rtcm->obsflag||fabs(tt)>1E-9) { 235 | rtcm->obs.n=rtcm->obsflag=0; 236 | } 237 | if ((index=obsindex(&rtcm->obs,time,sat))>=0) { 238 | rtcm->obs.data[index].L[freq]=-cp/256.0; 239 | rtcm->obs.data[index].LLI[freq]=rtcm->loss[sat-1][freq]!=loss; 240 | rtcm->obs.data[index].code[freq]= 241 | !freq?(code?CODE_L1P:CODE_L1C):(code?CODE_L2P:CODE_L2C); 242 | rtcm->loss[sat-1][freq]=loss; 243 | } 244 | } 245 | rtcm->obsflag=!sync; 246 | return sync?0:1; 247 | } 248 | /* decode type 19: rtk uncorrected pseudorange -------------------------------*/ 249 | static int decode_type19(rtcm_t *rtcm) 250 | { 251 | gtime_t time; 252 | double usec,pr,tt; 253 | int i=48,index,freq,sync=1,code,sys,prn,sat; 254 | 255 | trace(4,"decode_type19: len=%d\n",rtcm->len); 256 | 257 | if (i+24<=rtcm->len*8) { 258 | freq=getbitu(rtcm->buff,i, 2); i+= 2+2; 259 | usec=getbitu(rtcm->buff,i,20); i+=20; 260 | } 261 | else { 262 | trace(2,"rtcm2 19 length error: len=%d\n",rtcm->len); 263 | return -1; 264 | } 265 | if (freq&0x1) { 266 | trace(2,"rtcm2 19 not supported frequency: freq=%d\n",freq); 267 | return -1; 268 | } 269 | freq>>=1; 270 | 271 | while (i+48<=rtcm->len*8&&rtcm->obs.nbuff,i, 1); i+= 1; 273 | code=getbitu(rtcm->buff,i, 1); i+= 1; 274 | sys =getbitu(rtcm->buff,i, 1); i+= 1; 275 | prn =getbitu(rtcm->buff,i, 5); i+= 5+8; 276 | pr =getbitu(rtcm->buff,i,32); i+=32; 277 | if (prn==0) prn=32; 278 | if (!(sat=satno(sys?SYS_GLO:SYS_GPS,prn))) { 279 | trace(2,"rtcm2 19 satellite number error: sys=%d prn=%d\n",sys,prn); 280 | continue; 281 | } 282 | time=timeadd(rtcm->time,usec*1E-6); 283 | if (sys) time=utc2gpst(time); /* convert glonass time to gpst */ 284 | 285 | tt=timediff(rtcm->obs.data[0].time,time); 286 | if (rtcm->obsflag||fabs(tt)>1E-9) { 287 | rtcm->obs.n=rtcm->obsflag=0; 288 | } 289 | if ((index=obsindex(&rtcm->obs,time,sat))>=0) { 290 | rtcm->obs.data[index].P[freq]=pr*0.02; 291 | rtcm->obs.data[index].code[freq]= 292 | !freq?(code?CODE_L1P:CODE_L1C):(code?CODE_L2P:CODE_L2C); 293 | } 294 | } 295 | rtcm->obsflag=!sync; 296 | return sync?0:1; 297 | } 298 | /* decode type 22: extended reference station parameter ----------------------*/ 299 | static int decode_type22(rtcm_t *rtcm) 300 | { 301 | double del[2][3]={{0}},hgt=0.0; 302 | int i=48,j,noh; 303 | 304 | trace(4,"decode_type22: len=%d\n",rtcm->len); 305 | 306 | if (i+24<=rtcm->len*8) { 307 | del[0][0]=getbits(rtcm->buff,i,8)/25600.0; i+=8; 308 | del[0][1]=getbits(rtcm->buff,i,8)/25600.0; i+=8; 309 | del[0][2]=getbits(rtcm->buff,i,8)/25600.0; i+=8; 310 | } 311 | else { 312 | trace(2,"rtcm2 22 length error: len=%d\n",rtcm->len); 313 | return -1; 314 | } 315 | if (i+24<=rtcm->len*8) { 316 | i+=5; noh=getbits(rtcm->buff,i,1); i+=1; 317 | hgt=noh?0.0:getbitu(rtcm->buff,i,18)/25600.0; 318 | i+=18; 319 | } 320 | if (i+24<=rtcm->len*8) { 321 | del[1][0]=getbits(rtcm->buff,i,8)/1600.0; i+=8; 322 | del[1][1]=getbits(rtcm->buff,i,8)/1600.0; i+=8; 323 | del[1][2]=getbits(rtcm->buff,i,8)/1600.0; 324 | } 325 | rtcm->sta.deltype=1; /* xyz */ 326 | for (j=0;j<3;j++) rtcm->sta.del[j]=del[0][j]; 327 | rtcm->sta.hgt=hgt; 328 | return 5; 329 | } 330 | /* decode type 23: antenna type definition record ----------------------------*/ 331 | static int decode_type23(rtcm_t *rtcm) 332 | { 333 | return 0; 334 | } 335 | /* decode type 24: antenna reference point (arp) -----------------------------*/ 336 | static int decode_type24(rtcm_t *rtcm) 337 | { 338 | return 0; 339 | } 340 | /* decode type 31: differential glonass correction ---------------------------*/ 341 | static int decode_type31(rtcm_t *rtcm) 342 | { 343 | return 0; 344 | } 345 | /* decode type 32: differential glonass reference station parameters ---------*/ 346 | static int decode_type32(rtcm_t *rtcm) 347 | { 348 | return 0; 349 | } 350 | /* decode type 34: glonass partial differential correction set ---------------*/ 351 | static int decode_type34(rtcm_t *rtcm) 352 | { 353 | return 0; 354 | } 355 | /* decode type 36: glonass special message -----------------------------------*/ 356 | static int decode_type36(rtcm_t *rtcm) 357 | { 358 | return 0; 359 | } 360 | /* decode type 37: gnss system time offset -----------------------------------*/ 361 | static int decode_type37(rtcm_t *rtcm) 362 | { 363 | return 0; 364 | } 365 | /* decode type 59: proprietary message ---------------------------------------*/ 366 | static int decode_type59(rtcm_t *rtcm) 367 | { 368 | return 0; 369 | } 370 | /* decode rtcm ver.2 message -------------------------------------------------*/ 371 | extern int decode_rtcm2(rtcm_t *rtcm) 372 | { 373 | double zcnt; 374 | int staid,seqno,stah,ret=0,type=getbitu(rtcm->buff,8,6); 375 | 376 | trace(3,"decode_rtcm2: type=%2d len=%3d\n",type,rtcm->len); 377 | 378 | if ((zcnt=getbitu(rtcm->buff,24,13)*0.6)>=3600.0) { 379 | trace(2,"rtcm2 modified z-count error: zcnt=%.1f\n",zcnt); 380 | return -1; 381 | } 382 | adjhour(rtcm,zcnt); 383 | staid=getbitu(rtcm->buff,14,10); 384 | seqno=getbitu(rtcm->buff,37, 3); 385 | stah =getbitu(rtcm->buff,45, 3); 386 | if (seqno-rtcm->seqno!=1&&seqno-rtcm->seqno!=-7) { 387 | trace(2,"rtcm2 message outage: seqno=%d->%d\n",rtcm->seqno,seqno); 388 | } 389 | rtcm->seqno=seqno; 390 | rtcm->stah =stah; 391 | 392 | if (rtcm->outtype) { 393 | sprintf(rtcm->msgtype,"RTCM %2d (%4d) zcnt=%7.1f staid=%3d seqno=%d", 394 | type,rtcm->len,zcnt,staid,seqno); 395 | } 396 | if (type==3||type==22||type==23||type==24) { 397 | if (rtcm->staid!=0&&staid!=rtcm->staid) { 398 | trace(2,"rtcm2 station id changed: %d->%d\n",rtcm->staid,staid); 399 | } 400 | rtcm->staid=staid; 401 | } 402 | if (rtcm->staid!=0&&staid!=rtcm->staid) { 403 | trace(2,"rtcm2 station id invalid: %d %d\n",staid,rtcm->staid); 404 | return -1; 405 | } 406 | switch (type) { 407 | case 1: ret=decode_type1 (rtcm); break; 408 | case 3: ret=decode_type3 (rtcm); break; 409 | case 9: ret=decode_type1 (rtcm); break; 410 | case 14: ret=decode_type14(rtcm); break; 411 | case 16: ret=decode_type16(rtcm); break; 412 | case 17: ret=decode_type17(rtcm); break; 413 | case 18: ret=decode_type18(rtcm); break; 414 | case 19: ret=decode_type19(rtcm); break; 415 | case 22: ret=decode_type22(rtcm); break; 416 | case 23: ret=decode_type23(rtcm); break; /* not supported */ 417 | case 24: ret=decode_type24(rtcm); break; /* not supported */ 418 | case 31: ret=decode_type31(rtcm); break; /* not supported */ 419 | case 32: ret=decode_type32(rtcm); break; /* not supported */ 420 | case 34: ret=decode_type34(rtcm); break; /* not supported */ 421 | case 36: ret=decode_type36(rtcm); break; /* not supported */ 422 | case 37: ret=decode_type37(rtcm); break; /* not supported */ 423 | case 59: ret=decode_type59(rtcm); break; /* not supported */ 424 | } 425 | if (ret>=0) { 426 | if (1<=type&&type<=99) rtcm->nmsg2[type]++; else rtcm->nmsg2[0]++; 427 | } 428 | return ret; 429 | } 430 | -------------------------------------------------------------------------------- /src/rtklib.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/src/rtklib.h -------------------------------------------------------------------------------- /src/ss2.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * ss2.c : superstar II receiver dependent functions 3 | * 4 | * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. 5 | * 6 | * reference: 7 | * [1] NovAtel, OM-20000086 Superstar II Firmware Reference Manual, 2005 8 | * 9 | * version : $Revision: 1.2 $ $Date: 2008/07/14 00:05:05 $ 10 | * history : 2008/05/18 1.0 new 11 | * 2008/06/16 1.2 separate common functions to rcvcmn.c 12 | * 2009/04/01 1.3 fix bug on decode #21 message 13 | * 2010/08/20 1.4 fix problem with minus value of time slew in #23 14 | * (2.4.0_p5) 15 | * 2011/05/27 1.5 fix problem with ARM compiler 16 | * 2013/02/23 1.6 fix memory access violation problem on arm 17 | * 2020/11/30 1.7 use integer type in stdint.h 18 | *-----------------------------------------------------------------------------*/ 19 | #include "rtklib.h" 20 | 21 | #define SS2SOH 0x01 /* ss2 start of header */ 22 | 23 | #define ID_SS2LLH 20 /* ss2 message ID#20 navigation data (user) */ 24 | #define ID_SS2ECEF 21 /* ss2 message ID#21 navigation data (ecef) */ 25 | #define ID_SS2EPH 22 /* ss2 message ID#22 ephemeris data */ 26 | #define ID_SS2RAW 23 /* ss2 message ID#23 measurement block */ 27 | #define ID_SS2SBAS 67 /* ss2 message ID#67 sbas data */ 28 | 29 | /* get/set fields (little-endian) --------------------------------------------*/ 30 | #define U1(p) (*((uint8_t *)(p))) 31 | static uint16_t U2(uint8_t *p) {uint16_t u; memcpy(&u,p,2); return u;} 32 | static uint32_t U4(uint8_t *p) {uint32_t u; memcpy(&u,p,4); return u;} 33 | static double R8(uint8_t *p) {double r; memcpy(&r,p,8); return r;} 34 | 35 | /* checksum ------------------------------------------------------------------*/ 36 | static int chksum(const uint8_t *buff, int len) 37 | { 38 | int i; 39 | uint16_t sum=0; 40 | 41 | for (i=0;i>8)==buff[len-1]&&(sum&0xFF)==buff[len-2]; 43 | } 44 | /* adjust week ---------------------------------------------------------------*/ 45 | static int adjweek(raw_t *raw, double sec) 46 | { 47 | double tow; 48 | int week; 49 | 50 | if (raw->time.time==0) return 0; 51 | tow=time2gpst(raw->time,&week); 52 | if (sectow+302400.0) sec-=604800.0; 54 | raw->time=gpst2time(week,sec); 55 | return 1; 56 | } 57 | /* decode id#20 navigation data (user) ---------------------------------------*/ 58 | static int decode_ss2llh(raw_t *raw) 59 | { 60 | double ep[6]; 61 | uint8_t *p=raw->buff+4; 62 | 63 | trace(4,"decode_ss2llh: len=%d\n",raw->len); 64 | 65 | if (raw->len!=77) { 66 | trace(2,"ss2 id#20 length error: len=%d\n",raw->len); 67 | return -1; 68 | } 69 | ep[3]=U1(p ); ep[4]=U1(p+ 1); ep[5]=R8(p+ 2); 70 | ep[2]=U1(p+10); ep[1]=U1(p+11); ep[0]=U2(p+12); 71 | raw->time=utc2gpst(epoch2time(ep)); 72 | return 0; 73 | } 74 | /* decode id#21 navigation data (ecef) ---------------------------------------*/ 75 | static int decode_ss2ecef(raw_t *raw) 76 | { 77 | uint8_t *p=raw->buff+4; 78 | 79 | trace(4,"decode_ss2ecef: len=%d\n",raw->len); 80 | 81 | if (raw->len!=85) { 82 | trace(2,"ss2 id#21 length error: len=%d\n",raw->len); 83 | return -1; 84 | } 85 | raw->time=gpst2time(U2(p+8),R8(p)); 86 | return 0; 87 | } 88 | /* decode id#23 measurement block --------------------------------------------*/ 89 | static int decode_ss2meas(raw_t *raw) 90 | { 91 | const double freqif=1.405396825E6,tslew=1.75E-7; 92 | double tow,slew,code,icp,d; 93 | int i,j,n,prn,sat,nobs; 94 | uint8_t *p=raw->buff+4; 95 | uint32_t sc; 96 | 97 | trace(4,"decode_ss2meas: len=%d\n",raw->len); 98 | 99 | nobs=U1(p+2); 100 | if (17+nobs*11!=raw->len) { 101 | trace(2,"ss2 id#23 message length error: len=%d\n",raw->len); 102 | return -1; 103 | } 104 | tow=floor(R8(p+3)*1000.0+0.5)/1000.0; /* rounded by 1ms */ 105 | if (!adjweek(raw,tow)) { 106 | trace(2,"ss2 id#23 message time adjustment error\n"); 107 | return -1; 108 | } 109 | /* time slew defined as uchar (ref [1]) but minus value appears in some f/w */ 110 | slew=*(char *)(p)*tslew; 111 | 112 | raw->icpc+=4.5803-freqif*slew-FREQ1*(slew-1E-6); /* phase correction */ 113 | 114 | for (i=n=0,p+=11;iobs.data[n].time=raw->time; 121 | raw->obs.data[n].sat=sat; 122 | code=(tow-floor(tow))-(double)(U4(p+2))/2095104000.0; 123 | raw->obs.data[n].P[0]=CLIGHT*(code+(code<0.0?1.0:0.0)); 124 | icp=(double)(U4(p+6)>>2)/1024.0+raw->off[sat-1]; /* unwrap */ 125 | if (fabs(icp-raw->icpp[sat-1])>524288.0) { 126 | d=icp>raw->icpp[sat-1]?-1048576.0:1048576.0; 127 | raw->off[sat-1]+=d; icp+=d; 128 | } 129 | raw->icpp[sat-1]=icp; 130 | raw->obs.data[n].L[0]=icp+raw->icpc; 131 | raw->obs.data[n].D[0]=0.0; 132 | raw->obs.data[n].SNR[0]=(uint16_t)(U1(p+1)*0.25/SNR_UNIT+0.5); 133 | sc=U1(p+10); 134 | raw->obs.data[n].LLI[0]=(int)((uint8_t)sc-(uint8_t)raw->lockt[sat-1][0])>0; 135 | raw->obs.data[n].LLI[0]|=U1(p+6)&1?2:0; 136 | raw->obs.data[n].code[0]=CODE_L1C; 137 | raw->lockt[sat-1][0]=sc; 138 | 139 | for (j=1;jobs.data[n].L[j]=raw->obs.data[n].P[j]=0.0; 141 | raw->obs.data[n].D[j]=0.0; 142 | raw->obs.data[n].SNR[j]=raw->obs.data[n].LLI[j]=0; 143 | raw->obs.data[n].code[j]=CODE_NONE; 144 | } 145 | n++; 146 | } 147 | raw->obs.n=n; 148 | return 1; 149 | } 150 | /* decode id#22 ephemeris data ------------------------------------------------*/ 151 | static int decode_ss2eph(raw_t *raw) 152 | { 153 | eph_t eph={0}; 154 | uint32_t tow; 155 | uint8_t *p=raw->buff+4,buff[90]={0}; 156 | int i,j,prn,sat; 157 | 158 | trace(4,"decode_ss2eph: len=%d\n",raw->len); 159 | 160 | if (raw->len!=79) { 161 | trace(2,"ss2 id#22 length error: len=%d\n",raw->len); 162 | return -1; 163 | } 164 | prn=(U4(p)&0x1F)+1; 165 | if (!(sat=satno(SYS_GPS,prn))) { 166 | trace(2,"ss2 id#22 satellite number error: prn=%d\n",prn); 167 | return -1; 168 | } 169 | if (raw->time.time==0) { 170 | trace(2,"ss2 id#22 week number unknown error\n"); 171 | return -1; 172 | } 173 | tow=(uint32_t)(time2gpst(raw->time,NULL)/6.0); 174 | for (i=0;i<3;i++) { 175 | buff[30*i+3]=(uint8_t)(tow>>9); /* add tow + subframe id */ 176 | buff[30*i+4]=(uint8_t)(tow>>1); 177 | buff[30*i+5]=(uint8_t)(((tow&1)<<7)+((i+1)<<2)); 178 | for (j=0;j<24;j++) buff[30*i+6+j]=p[1+24*i+j]; 179 | } 180 | if (!decode_frame(buff,&eph,NULL,NULL,NULL)) { 181 | trace(2,"ss2 id#22 subframe error: prn=%d\n",prn); 182 | return -1; 183 | } 184 | if (!strstr(raw->opt,"-EPHALL")) { 185 | if (eph.iode==raw->nav.eph[sat-1].iode) return 0; /* unchanged */ 186 | } 187 | eph.sat=sat; 188 | eph.ttr=raw->time; 189 | raw->nav.eph[sat-1]=eph; 190 | raw->ephsat=sat; 191 | raw->ephset=0; 192 | return 2; 193 | } 194 | /* decode id#67 sbas data ----------------------------------------------------*/ 195 | static int decode_ss2sbas(raw_t *raw) 196 | { 197 | gtime_t time; 198 | int i,prn; 199 | uint8_t *p=raw->buff+4; 200 | 201 | trace(4,"decode_ss2sbas: len=%d\n",raw->len); 202 | 203 | if (raw->len!=54) { 204 | trace(2,"ss2 id#67 length error: len=%d\n",raw->len); 205 | return -1; 206 | } 207 | prn=U4(p+12); 208 | if (prnsbsmsg.week=U4(p); 213 | raw->sbsmsg.tow=(int)R8(p+4); 214 | time=gpst2time(raw->sbsmsg.week,raw->sbsmsg.tow); 215 | raw->sbsmsg.prn=prn; 216 | for (i=0;i<29;i++) raw->sbsmsg.msg[i]=p[16+i]; 217 | return 3; 218 | } 219 | /* decode superstar 2 raw message --------------------------------------------*/ 220 | static int decode_ss2(raw_t *raw) 221 | { 222 | uint8_t *p=raw->buff; 223 | int type=U1(p+1); 224 | 225 | trace(3,"decode_ss2: type=%2d\n",type); 226 | 227 | if (!chksum(raw->buff,raw->len)) { 228 | trace(2,"ss2 message checksum error: type=%d len=%d\n",type,raw->len); 229 | return -1; 230 | } 231 | if (raw->outtype) { 232 | sprintf(raw->msgtype,"SS2 %2d (%4d):",type,raw->len); 233 | } 234 | switch (type) { 235 | case ID_SS2LLH : return decode_ss2llh (raw); 236 | case ID_SS2ECEF: return decode_ss2ecef(raw); 237 | case ID_SS2RAW : return decode_ss2meas(raw); 238 | case ID_SS2EPH : return decode_ss2eph (raw); 239 | case ID_SS2SBAS: return decode_ss2sbas(raw); 240 | } 241 | return 0; 242 | } 243 | /* sync code -----------------------------------------------------------------*/ 244 | static int sync_ss2(uint8_t *buff, uint8_t data) 245 | { 246 | buff[0]=buff[1]; buff[1]=buff[2]; buff[2]=data; 247 | return buff[0]==SS2SOH&&(buff[1]^buff[2])==0xFF; 248 | } 249 | /* input superstar 2 raw message from stream ----------------------------------- 250 | * input next superstar 2 raw message from stream 251 | * args : raw_t *raw IO receiver raw data control struct 252 | * uint8_t data I stream data (1 byte) 253 | * return : status (-1: error message, 0: no message, 1: input observation data, 254 | * 2: input ephemeris, 3: input sbas message, 255 | * 9: input ion/utc parameter) 256 | * notes : needs #20 or #21 message to get proper week number of #23 raw 257 | * observation data 258 | *-----------------------------------------------------------------------------*/ 259 | extern int input_ss2(raw_t *raw, uint8_t data) 260 | { 261 | trace(5,"input_ss2: data=%02x\n",data); 262 | 263 | /* synchronize frame */ 264 | if (raw->nbyte==0) { 265 | if (!sync_ss2(raw->buff,data)) return 0; 266 | raw->nbyte=3; 267 | return 0; 268 | } 269 | raw->buff[raw->nbyte++]=data; 270 | 271 | if (raw->nbyte==4) { 272 | if ((raw->len=U1(raw->buff+3)+6)>MAXRAWLEN) { 273 | trace(2,"ss2 length error: len=%d\n",raw->len); 274 | raw->nbyte=0; 275 | return -1; 276 | } 277 | } 278 | if (raw->nbyte<4||raw->nbytelen) return 0; 279 | raw->nbyte=0; 280 | 281 | /* decode superstar 2 raw message */ 282 | return decode_ss2(raw); 283 | } 284 | /* input superstar 2 raw message from file ------------------------------------- 285 | * input next superstar 2 raw message from file 286 | * args : raw_t *raw IO receiver raw data control struct 287 | * FILE *fp I file pointer 288 | * return : status(-2: end of file, -1...9: same as above) 289 | *-----------------------------------------------------------------------------*/ 290 | extern int input_ss2f(raw_t *raw, FILE *fp) 291 | { 292 | int i,data; 293 | 294 | trace(4,"input_ss2f:\n"); 295 | 296 | /* synchronize frame */ 297 | if (raw->nbyte==0) { 298 | for (i=0;;i++) { 299 | if ((data=fgetc(fp))==EOF) return -2; 300 | if (sync_ss2(raw->buff,(uint8_t)data)) break; 301 | if (i>=4096) return 0; 302 | } 303 | } 304 | if (fread(raw->buff+3,1,1,fp)<1) return -2; 305 | raw->nbyte=4; 306 | 307 | if ((raw->len=U1(raw->buff+3)+6)>MAXRAWLEN) { 308 | trace(2,"ss2 length error: len=%d\n",raw->len); 309 | raw->nbyte=0; 310 | return -1; 311 | } 312 | if (fread(raw->buff+4,1,raw->len-4,fp)<(size_t)(raw->len-4)) return -2; 313 | raw->nbyte=0; 314 | 315 | /* decode superstar 2 raw message */ 316 | return decode_ss2(raw); 317 | } 318 | -------------------------------------------------------------------------------- /src/tides.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * tides.c : tidal displacement corrections 3 | * 4 | * Copyright (C) 2015-2017 by T.TAKASU, All rights reserved. 5 | * 6 | * options : -DIERS_MODEL use IERS tide model 7 | * 8 | * references : 9 | * [1] D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 10 | * [2] D.D.McCarthy and G.Petit, IERS Technical Note 32, IERS Conventions 11 | * 2003, November 2003 12 | * [3] D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, 13 | * Space Technology Library, 2004 14 | * [4] J.Kouba, A Guide to using International GNSS Service (IGS) products, 15 | * May 2009 16 | * [5] G.Petit and B.Luzum (eds), IERS Technical Note No. 36, IERS 17 | * Conventions (2010), 2010 18 | * 19 | * version : $Revision:$ $Date:$ 20 | * history : 2015/05/10 1.0 separated from ppp.c 21 | * 2015/06/11 1.1 fix bug on computing days in tide_oload() (#128) 22 | * 2017/04/11 1.2 fix bug on calling geterp() in timdedisp() 23 | *-----------------------------------------------------------------------------*/ 24 | #include "rtklib.h" 25 | 26 | #define SQR(x) ((x)*(x)) 27 | 28 | #define AS2R (D2R/3600.0) /* arc sec to radian */ 29 | #define GME 3.986004415E+14 /* earth gravitational constant */ 30 | #define GMS 1.327124E+20 /* sun gravitational constant */ 31 | #define GMM 4.902801E+12 /* moon gravitational constant */ 32 | 33 | /* function prototypes -------------------------------------------------------*/ 34 | #ifdef IERS_MODEL 35 | extern int dehanttideinel_(double *xsta, int *year, int *mon, int *day, 36 | double *fhr, double *xsun, double *xmon, 37 | double *dxtide); 38 | #endif 39 | 40 | /* solar/lunar tides (ref [2] 7) ---------------------------------------------*/ 41 | #ifndef IERS_MODEL 42 | static void tide_pl(const double *eu, const double *rp, double GMp, 43 | const double *pos, double *dr) 44 | { 45 | const double H3=0.292,L3=0.015; 46 | double r,ep[3],latp,lonp,p,K2,K3,a,H2,L2,dp,du,cosp,sinl,cosl; 47 | int i; 48 | 49 | trace(4,"tide_pl : pos=%.3f %.3f\n",pos[0]*R2D,pos[1]*R2D); 50 | 51 | if ((r=norm(rp,3))<=0.0) return; 52 | 53 | for (i=0;i<3;i++) ep[i]=rp[i]/r; 54 | 55 | K2=GMp/GME*SQR(RE_WGS84)*SQR(RE_WGS84)/(r*r*r); 56 | K3=K2*RE_WGS84/r; 57 | latp=asin(ep[2]); lonp=atan2(ep[1],ep[0]); 58 | cosp=cos(latp); sinl=sin(pos[0]); cosl=cos(pos[0]); 59 | 60 | /* step1 in phase (degree 2) */ 61 | p=(3.0*sinl*sinl-1.0)/2.0; 62 | H2=0.6078-0.0006*p; 63 | L2=0.0847+0.0002*p; 64 | a=dot(ep,eu,3); 65 | dp=K2*3.0*L2*a; 66 | du=K2*(H2*(1.5*a*a-0.5)-3.0*L2*a*a); 67 | 68 | /* step1 in phase (degree 3) */ 69 | dp+=K3*L3*(7.5*a*a-1.5); 70 | du+=K3*(H3*(2.5*a*a*a-1.5*a)-L3*(7.5*a*a-1.5)*a); 71 | 72 | /* step1 out-of-phase (only radial) */ 73 | du+=3.0/4.0*0.0025*K2*sin(2.0*latp)*sin(2.0*pos[0])*sin(pos[1]-lonp); 74 | du+=3.0/4.0*0.0022*K2*cosp*cosp*cosl*cosl*sin(2.0*(pos[1]-lonp)); 75 | 76 | dr[0]=dp*ep[0]+du*eu[0]; 77 | dr[1]=dp*ep[1]+du*eu[1]; 78 | dr[2]=dp*ep[2]+du*eu[2]; 79 | 80 | trace(5,"tide_pl : dr=%.3f %.3f %.3f\n",dr[0],dr[1],dr[2]); 81 | } 82 | /* displacement by solid earth tide (ref [2] 7) ------------------------------*/ 83 | static void tide_solid(const double *rsun, const double *rmoon, 84 | const double *pos, const double *E, double gmst, int opt, 85 | double *dr) 86 | { 87 | double dr1[3],dr2[3],eu[3],du,dn,sinl,sin2l; 88 | 89 | trace(3,"tide_solid: pos=%.3f %.3f opt=%d\n",pos[0]*R2D,pos[1]*R2D,opt); 90 | 91 | /* step1: time domain */ 92 | eu[0]=E[2]; eu[1]=E[5]; eu[2]=E[8]; 93 | tide_pl(eu,rsun, GMS,pos,dr1); 94 | tide_pl(eu,rmoon,GMM,pos,dr2); 95 | 96 | /* step2: frequency domain, only K1 radial */ 97 | sin2l=sin(2.0*pos[0]); 98 | du=-0.012*sin2l*sin(gmst+pos[1]); 99 | 100 | dr[0]=dr1[0]+dr2[0]+du*E[2]; 101 | dr[1]=dr1[1]+dr2[1]+du*E[5]; 102 | dr[2]=dr1[2]+dr2[2]+du*E[8]; 103 | 104 | /* eliminate permanent deformation */ 105 | if (opt&8) { 106 | sinl=sin(pos[0]); 107 | du=0.1196*(1.5*sinl*sinl-0.5); 108 | dn=0.0247*sin2l; 109 | dr[0]+=du*E[2]+dn*E[1]; 110 | dr[1]+=du*E[5]+dn*E[4]; 111 | dr[2]+=du*E[8]+dn*E[7]; 112 | } 113 | trace(5,"tide_solid: dr=%.3f %.3f %.3f\n",dr[0],dr[1],dr[2]); 114 | } 115 | #endif /* !IERS_MODEL */ 116 | 117 | /* displacement by ocean tide loading (ref [2] 7) ----------------------------*/ 118 | static void tide_oload(gtime_t tut, const double *odisp, double *denu) 119 | { 120 | const double args[][5]={ 121 | {1.40519E-4, 2.0,-2.0, 0.0, 0.00}, /* M2 */ 122 | {1.45444E-4, 0.0, 0.0, 0.0, 0.00}, /* S2 */ 123 | {1.37880E-4, 2.0,-3.0, 1.0, 0.00}, /* N2 */ 124 | {1.45842E-4, 2.0, 0.0, 0.0, 0.00}, /* K2 */ 125 | {0.72921E-4, 1.0, 0.0, 0.0, 0.25}, /* K1 */ 126 | {0.67598E-4, 1.0,-2.0, 0.0,-0.25}, /* O1 */ 127 | {0.72523E-4,-1.0, 0.0, 0.0,-0.25}, /* P1 */ 128 | {0.64959E-4, 1.0,-3.0, 1.0,-0.25}, /* Q1 */ 129 | {0.53234E-5, 0.0, 2.0, 0.0, 0.00}, /* Mf */ 130 | {0.26392E-5, 0.0, 1.0,-1.0, 0.00}, /* Mm */ 131 | {0.03982E-5, 2.0, 0.0, 0.0, 0.00} /* Ssa */ 132 | }; 133 | const double ep1975[]={1975,1,1,0,0,0}; 134 | double ep[6],fday,days,t,t2,t3,a[5],ang,dp[3]={0}; 135 | int i,j; 136 | 137 | trace(3,"tide_oload:\n"); 138 | 139 | /* angular argument: see subroutine arg.f for reference [1] */ 140 | time2epoch(tut,ep); 141 | fday=ep[3]*3600.0+ep[4]*60.0+ep[5]; 142 | ep[3]=ep[4]=ep[5]=0.0; 143 | days=timediff(epoch2time(ep),epoch2time(ep1975))/86400.0+1.0; 144 | t=(27392.500528+1.000000035*days)/36525.0; 145 | t2=t*t; t3=t2*t; 146 | 147 | a[0]=fday; 148 | a[1]=(279.69668+36000.768930485*t+3.03E-4*t2)*D2R; /* H0 */ 149 | a[2]=(270.434358+481267.88314137*t-0.001133*t2+1.9E-6*t3)*D2R; /* S0 */ 150 | a[3]=(334.329653+4069.0340329577*t-0.010325*t2-1.2E-5*t3)*D2R; /* P0 */ 151 | a[4]=2.0*PI; 152 | 153 | /* displacements by 11 constituents */ 154 | for (i=0;i<11;i++) { 155 | ang=0.0; 156 | for (j=0;j<5;j++) ang+=a[j]*args[i][j]; 157 | for (j=0;j<3;j++) dp[j]+=odisp[j+i*6]*cos(ang-odisp[j+3+i*6]*D2R); 158 | } 159 | denu[0]=-dp[1]; 160 | denu[1]=-dp[2]; 161 | denu[2]= dp[0]; 162 | 163 | trace(5,"tide_oload: denu=%.3f %.3f %.3f\n",denu[0],denu[1],denu[2]); 164 | } 165 | /* iers mean pole (ref [7] eq.7.25) ------------------------------------------*/ 166 | static void iers_mean_pole(gtime_t tut, double *xp_bar, double *yp_bar) 167 | { 168 | const double ep2000[]={2000,1,1,0,0,0}; 169 | double y,y2,y3; 170 | 171 | y=timediff(tut,epoch2time(ep2000))/86400.0/365.25; 172 | 173 | if (y<3653.0/365.25) { /* until 2010.0 */ 174 | y2=y*y; y3=y2*y; 175 | *xp_bar= 55.974+1.8243*y+0.18413*y2+0.007024*y3; /* (mas) */ 176 | *yp_bar=346.346+1.7896*y-0.10729*y2-0.000908*y3; 177 | } 178 | else { /* after 2010.0 */ 179 | *xp_bar= 23.513+7.6141*y; /* (mas) */ 180 | *yp_bar=358.891-0.6287*y; 181 | } 182 | } 183 | /* displacement by pole tide (ref [7] eq.7.26) --------------------------------*/ 184 | static void tide_pole(gtime_t tut, const double *pos, const double *erpv, 185 | double *denu) 186 | { 187 | double xp_bar,yp_bar,m1,m2,cosl,sinl; 188 | 189 | trace(3,"tide_pole: pos=%.3f %.3f\n",pos[0]*R2D,pos[1]*R2D); 190 | 191 | /* iers mean pole (mas) */ 192 | iers_mean_pole(tut,&xp_bar,&yp_bar); 193 | 194 | /* ref [7] eq.7.24 */ 195 | m1= erpv[0]/AS2R-xp_bar*1E-3; /* (as) */ 196 | m2=-erpv[1]/AS2R+yp_bar*1E-3; 197 | 198 | /* sin(2*theta) = sin(2*phi), cos(2*theta)=-cos(2*phi) */ 199 | cosl=cos(pos[1]); 200 | sinl=sin(pos[1]); 201 | denu[0]= 9E-3*sin(pos[0]) *(m1*sinl-m2*cosl); /* de= Slambda (m) */ 202 | denu[1]= -9E-3*cos(2.0*pos[0])*(m1*cosl+m2*sinl); /* dn=-Stheta (m) */ 203 | denu[2]=-33E-3*sin(2.0*pos[0])*(m1*cosl+m2*sinl); /* du= Sr (m) */ 204 | 205 | trace(5,"tide_pole : denu=%.3f %.3f %.3f\n",denu[0],denu[1],denu[2]); 206 | } 207 | /* tidal displacement ---------------------------------------------------------- 208 | * displacements by earth tides 209 | * args : gtime_t tutc I time in utc 210 | * double *rr I site position (ecef) (m) 211 | * int opt I options (or of the followings) 212 | * 1: solid earth tide 213 | * 2: ocean tide loading 214 | * 4: pole tide 215 | * 8: elimate permanent deformation 216 | * double *erp I earth rotation parameters (NULL: not used) 217 | * double *odisp I ocean loading parameters (NULL: not used) 218 | * odisp[0+i*6]: consituent i amplitude radial(m) 219 | * odisp[1+i*6]: consituent i amplitude west (m) 220 | * odisp[2+i*6]: consituent i amplitude south (m) 221 | * odisp[3+i*6]: consituent i phase radial (deg) 222 | * odisp[4+i*6]: consituent i phase west (deg) 223 | * odisp[5+i*6]: consituent i phase south (deg) 224 | * (i=0:M2,1:S2,2:N2,3:K2,4:K1,5:O1,6:P1,7:Q1, 225 | * 8:Mf,9:Mm,10:Ssa) 226 | * double *dr O displacement by earth tides (ecef) (m) 227 | * return : none 228 | * notes : see ref [1], [2] chap 7 229 | * see ref [4] 5.2.1, 5.2.2, 5.2.3 230 | * ver.2.4.0 does not use ocean loading and pole tide corrections 231 | *-----------------------------------------------------------------------------*/ 232 | extern void tidedisp(gtime_t tutc, const double *rr, int opt, const erp_t *erp, 233 | const double *odisp, double *dr) 234 | { 235 | gtime_t tut; 236 | double pos[2],E[9],drt[3],denu[3],rs[3],rm[3],gmst,erpv[5]={0}; 237 | int i; 238 | #ifdef IERS_MODEL 239 | double ep[6],fhr; 240 | int year,mon,day; 241 | #endif 242 | 243 | trace(3,"tidedisp: tutc=%s\n",time_str(tutc,0)); 244 | 245 | if (erp) { 246 | geterp(erp,utc2gpst(tutc),erpv); 247 | } 248 | tut=timeadd(tutc,erpv[2]); 249 | 250 | dr[0]=dr[1]=dr[2]=0.0; 251 | 252 | if (norm(rr,3)<=0.0) return; 253 | 254 | pos[0]=asin(rr[2]/norm(rr,3)); 255 | pos[1]=atan2(rr[1],rr[0]); 256 | xyz2enu(pos,E); 257 | 258 | if (opt&1) { /* solid earth tides */ 259 | 260 | /* sun and moon position in ecef */ 261 | sunmoonpos(tutc,erpv,rs,rm,&gmst); 262 | 263 | #ifdef IERS_MODEL 264 | time2epoch(tutc,ep); 265 | year=(int)ep[0]; 266 | mon =(int)ep[1]; 267 | day =(int)ep[2]; 268 | fhr =ep[3]+ep[4]/60.0+ep[5]/3600.0; 269 | 270 | /* call DEHANTTIDEINEL */ 271 | dehanttideinel_((double *)rr,&year,&mon,&day,&fhr,rs,rm,drt); 272 | #else 273 | tide_solid(rs,rm,pos,E,gmst,opt,drt); 274 | #endif 275 | for (i=0;i<3;i++) dr[i]+=drt[i]; 276 | } 277 | if ((opt&2)&&odisp) { /* ocean tide loading */ 278 | tide_oload(tut,odisp,denu); 279 | matmul("TN",3,1,3,1.0,E,denu,0.0,drt); 280 | for (i=0;i<3;i++) dr[i]+=drt[i]; 281 | } 282 | if ((opt&4)&&erp) { /* pole tide */ 283 | tide_pole(tut,pos,erpv,denu); 284 | matmul("TN",3,1,3,1.0,E,denu,0.0,drt); 285 | for (i=0;i<3;i++) dr[i]+=drt[i]; 286 | } 287 | trace(5,"tidedisp: dr=%.3f %.3f %.3f\n",dr[0],dr[1],dr[2]); 288 | } 289 | -------------------------------------------------------------------------------- /src/tle.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------------ 2 | * tle.c: NORAD TLE (two line element) functions 3 | * 4 | * Copyright (C) 2012-2020 by T.TAKASU, All rights reserved. 5 | * 6 | * references: 7 | * [1] F.R.Hoots and R.L.Roehrich, Spacetrack report No.3, Models for 8 | * propagation of NORAD element sets, December 1980 9 | * [2] D.A.Vallado, P.Crawford, R.Hujsak and T.S.Kelso, Revisiting 10 | * Spacetrack Report #3, AIAA 2006-6753, 2006 11 | * [3] CelesTrak (http://www.celestrak.com) 12 | * 13 | * version : $Revision:$ $Date:$ 14 | * history : 2012/11/01 1.0 new 15 | * 2013/01/25 1.1 fix bug on binary search 16 | * 2014/08/26 1.2 fix bug on tle_pos() to get tle by satid or desig 17 | * 2020/11/30 1.3 fix problem on duplicated names in a satellite 18 | *-----------------------------------------------------------------------------*/ 19 | #include "rtklib.h" 20 | 21 | /* SGP4 model propagator by STR#3 (ref [1] sec.6,11) -------------------------*/ 22 | 23 | #define DE2RA 0.174532925E-1 24 | #define E6A 1.E-6 25 | #define PIO2 1.57079633 26 | #define QO 120.0 27 | #define SO 78.0 28 | #define TOTHRD 0.66666667 29 | #define TWOPI 6.2831853 30 | #define X3PIO2 4.71238898 31 | #define XJ2 1.082616E-3 32 | #define XJ3 -0.253881E-5 33 | #define XJ4 -1.65597E-6 34 | #define XKE 0.743669161E-1 35 | #define XKMPER 6378.135 36 | #define XMNPDA 1440.0 37 | #define AE 1.0 38 | #define CK2 5.413080E-4 /* = 0.5*XJ2*AE*AE */ 39 | #define CK4 0.62098875E-6 /* = -0.375*XJ4*AE*AE*AE*AE */ 40 | #define QOMS2T 1.88027916E-9 /* = pow((QO-SO)*AE/XKMPER,4.0) */ 41 | #define S 1.01222928 /* = AE*(1.0+SO/XKMPER) */ 42 | 43 | static void SGP4_STR3(double tsince, const tled_t *data, double *rs) 44 | { 45 | double xnodeo,omegao,xmo,eo,xincl,xno,xndt2o,xndd6o,bstar; 46 | double a1,cosio,theta2,x3thm1,eosq,betao2,betao,del1,ao,delo,xnodp,aodp,s4; 47 | double qoms24,perige,pinvsq,tsi,eta,etasq,eeta,psisq,coef,coef1,c1,c2,c3,c4; 48 | double c5,sinio,a3ovk2,x1mth2,theta4,xmdot,x1m5th,omgdot,xhdot1,xnodot; 49 | double omgcof,xmcof,xnodcf,t2cof,xlcof,aycof,delmo,sinmo,x7thm1,c1sq,d2,d3; 50 | double d4,t3cof,t4cof,t5cof,xmdf,omgadf,xnoddf,omega,xmp,tsq,xnode,delomg; 51 | double delm,tcube,tfour,a,e,xl,beta,xn,axn,xll,aynl,xlt,ayn,capu,sinepw; 52 | double cosepw,epw,ecose,esine,elsq,pl,r,rdot,rfdot,betal,cosu,sinu,u,sin2u; 53 | double cos2u,rk,uk,xnodek,xinck,rdotk,rfdotk,sinuk,cosuk,sinik,cosik,sinnok; 54 | double cosnok,xmx,xmy,ux,uy,uz,vx,vy,vz,x,y,z,xdot,ydot,zdot; 55 | double temp,temp1,temp2,temp3,temp4,temp5,temp6,tempa,tempe,templ; 56 | int i,isimp; 57 | 58 | xnodeo=data->OMG*DE2RA; 59 | omegao=data->omg*DE2RA; 60 | xmo=data->M*DE2RA; 61 | xincl=data->inc*DE2RA; 62 | temp=TWOPI/XMNPDA/XMNPDA; 63 | xno=data->n*temp*XMNPDA; 64 | xndt2o=data->ndot*temp; 65 | xndd6o=data->nddot*temp/XMNPDA; 66 | bstar=data->bstar/AE; 67 | eo=data->ecc; 68 | /* 69 | * recover original mean motion (xnodp) and semimajor axis (aodp) 70 | * from input elements 71 | */ 72 | a1=pow(XKE/xno,TOTHRD); 73 | cosio=cos(xincl); 74 | theta2=cosio*cosio; 75 | x3thm1=3.0*theta2-1.0; 76 | eosq=eo*eo; 77 | betao2=1.0-eosq; 78 | betao=sqrt(betao2); 79 | del1=1.5*CK2*x3thm1/(a1*a1*betao*betao2); 80 | ao=a1*(1.0-del1*(0.5*TOTHRD+del1*(1.0+134.0/81.0*del1))); 81 | delo=1.5*CK2*x3thm1/(ao*ao*betao*betao2); 82 | xnodp=xno/(1.0+delo); 83 | aodp=ao/(1.0-delo); 84 | /* 85 | * initialization 86 | * for perigee less than 220 kilometers, the isimp flag is set and 87 | * the equations are truncated to linear variation in sqrt a and 88 | * quadratic variation in mean anomaly. also, the c3 term, the 89 | * delta omega term, and the delta m term are dropped. 90 | */ 91 | isimp=0; 92 | if ((aodp*(1.0-eo)/AE)<(220.0/XKMPER+AE)) isimp=1; 93 | 94 | /* for perigee below 156 km, the values of s and qoms2t are altered */ 95 | s4=S; 96 | qoms24=QOMS2T; 97 | perige=(aodp*(1.0-eo)-AE)*XKMPER; 98 | if (perige<156.0) { 99 | s4=perige-78.0; 100 | if (perige<=98.0) s4=20.0; 101 | qoms24=pow((120.0-s4)*AE/XKMPER,4.0); 102 | s4=s4/XKMPER+AE; 103 | } 104 | pinvsq=1.0/(aodp*aodp*betao2*betao2); 105 | tsi=1.0/(aodp-s4); 106 | eta=aodp*eo*tsi; 107 | etasq=eta*eta; 108 | eeta=eo*eta; 109 | psisq=fabs(1.0-etasq); 110 | coef=qoms24*pow(tsi,4.0); 111 | coef1=coef/pow(psisq,3.5); 112 | c2=coef1*xnodp*(aodp*(1.0+1.5*etasq+eeta*(4.0+etasq))+0.75* 113 | CK2*tsi/psisq*x3thm1*(8.0+3.0*etasq*(8.0+etasq))); 114 | c1=bstar*c2; 115 | sinio=sin(xincl); 116 | a3ovk2=-XJ3/CK2*pow(AE,3.0); 117 | c3=coef*tsi*a3ovk2*xnodp*AE*sinio/eo; 118 | x1mth2=1.0-theta2; 119 | c4=2.0*xnodp*coef1*aodp*betao2*(eta* 120 | (2.0+0.5*etasq)+eo*(0.5+2.0*etasq)-2.0*CK2*tsi/ 121 | (aodp*psisq)*(-3.0*x3thm1*(1.0-2.0*eeta+etasq* 122 | (1.5-0.5*eeta))+0.75*x1mth2*(2.0*etasq-eeta* 123 | (1.0+etasq))*cos(2.0*omegao))); 124 | c5=2.0*coef1*aodp*betao2*(1.0+2.75*(etasq+eeta)+eeta*etasq); 125 | theta4=theta2*theta2; 126 | temp1=3.0*CK2*pinvsq*xnodp; 127 | temp2=temp1*CK2*pinvsq; 128 | temp3=1.25*CK4*pinvsq*pinvsq*xnodp; 129 | xmdot=xnodp+0.5*temp1*betao*x3thm1+0.0625*temp2*betao* 130 | (13.0-78.0*theta2+137.0*theta4); 131 | x1m5th=1.0-5.0*theta2; 132 | omgdot=-0.5*temp1*x1m5th+0.0625*temp2*(7.0-114.0*theta2+ 133 | 395.0*theta4)+temp3*(3.0-36.0*theta2+49.0*theta4); 134 | xhdot1=-temp1*cosio; 135 | xnodot=xhdot1+(0.5*temp2*(4.0-19.0*theta2)+2.0*temp3*(3.0- 136 | 7.0*theta2))*cosio; 137 | omgcof=bstar*c3*cos(omegao); 138 | xmcof=-TOTHRD*coef*bstar*AE/eeta; 139 | xnodcf=3.5*betao2*xhdot1*c1; 140 | t2cof=1.5*c1; 141 | xlcof=0.125*a3ovk2*sinio*(3.0+5.0*cosio)/(1.0+cosio); 142 | aycof=0.25*a3ovk2*sinio; 143 | delmo=pow(1.0+eta*cos(xmo),3.0); 144 | sinmo=sin(xmo); 145 | x7thm1=7.0*theta2-1.0; 146 | 147 | if (isimp!=1) { 148 | c1sq=c1*c1; 149 | d2=4.0*aodp*tsi*c1sq; 150 | temp=d2*tsi*c1/3.0; 151 | d3=(17.0*aodp+s4)*temp; 152 | d4=0.5*temp*aodp*tsi*(221.0*aodp+31.0*s4)*c1; 153 | t3cof=d2+2.0*c1sq; 154 | t4cof=0.25*(3.0*d3+c1*(12.0*d2+10.0*c1sq)); 155 | t5cof=0.2*(3.0*d4+12.0*c1*d3+6.0*d2*d2+15.0*c1sq*(2.0*d2+c1sq)); 156 | } 157 | else { 158 | d2=d3=d4=t3cof=t4cof=t5cof=0.0; 159 | } 160 | /* update for secular gravity and atmospheric drag */ 161 | xmdf=xmo+xmdot*tsince; 162 | omgadf=omegao+omgdot*tsince; 163 | xnoddf=xnodeo+xnodot*tsince; 164 | omega=omgadf; 165 | xmp=xmdf; 166 | tsq=tsince*tsince; 167 | xnode=xnoddf+xnodcf*tsq; 168 | tempa=1.0-c1*tsince; 169 | tempe=bstar*c4*tsince; 170 | templ=t2cof*tsq; 171 | if (isimp==1) { 172 | delomg=omgcof*tsince; 173 | delm=xmcof*(pow(1.0+eta*cos(xmdf),3.0)-delmo); 174 | temp=delomg+delm; 175 | xmp=xmdf+temp; 176 | omega=omgadf-temp; 177 | tcube=tsq*tsince; 178 | tfour=tsince*tcube; 179 | tempa=tempa-d2*tsq-d3*tcube-d4*tfour; 180 | tempe=tempe+bstar*c5*(sin(xmp)-sinmo); 181 | templ=templ+t3cof*tcube+tfour*(t4cof+tsince*t5cof); 182 | } 183 | a=aodp*pow(tempa,2.0); 184 | e=eo-tempe; 185 | xl=xmp+omega+xnode+xnodp*templ; 186 | beta=sqrt(1.0-e*e); 187 | xn=XKE/pow(a,1.5); 188 | 189 | /* long period periodics */ 190 | axn=e*cos(omega); 191 | temp=1.0/(a*beta*beta); 192 | xll=temp*xlcof*axn; 193 | aynl=temp*aycof; 194 | xlt=xl+xll; 195 | ayn=e*sin(omega)+aynl; 196 | 197 | /* solve keplers equation */ 198 | capu=fmod(xlt-xnode,TWOPI); 199 | temp2=capu; 200 | for (i=0;i<10;i++) { 201 | sinepw=sin(temp2); 202 | cosepw=cos(temp2); 203 | temp3=axn*sinepw; 204 | temp4=ayn*cosepw; 205 | temp5=axn*cosepw; 206 | temp6=ayn*sinepw; 207 | epw=(capu-temp4+temp3-temp2)/(1.0-temp5-temp6)+temp2; 208 | if (fabs(epw-temp2)<=E6A) break; 209 | temp2=epw; 210 | } 211 | /* short period preliminary quantities */ 212 | ecose=temp5+temp6; 213 | esine=temp3-temp4; 214 | elsq=axn*axn+ayn*ayn; 215 | temp=1.0-elsq; 216 | pl=a*temp; 217 | r=a*(1.0-ecose); 218 | temp1=1.0/r; 219 | rdot=XKE*sqrt(a)*esine*temp1; 220 | rfdot=XKE*sqrt(pl)*temp1; 221 | temp2=a*temp1; 222 | betal=sqrt(temp); 223 | temp3=1.0/(1.0+betal); 224 | cosu=temp2*(cosepw-axn+ayn*esine*temp3); 225 | sinu=temp2*(sinepw-ayn-axn*esine*temp3); 226 | u=atan2(sinu,cosu); 227 | sin2u=2.0*sinu*cosu; 228 | cos2u=2.0*cosu*cosu-1.0; 229 | temp=1.0/pl; 230 | temp1=CK2*temp; 231 | temp2=temp1*temp; 232 | 233 | /* update for short periodics */ 234 | rk=r*(1.0-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u; 235 | uk=u-0.25*temp2*x7thm1*sin2u; 236 | xnodek=xnode+1.5*temp2*cosio*sin2u; 237 | xinck=xincl+1.5*temp2*cosio*sinio*cos2u; 238 | rdotk=rdot-xn*temp1*x1mth2*sin2u; 239 | rfdotk=rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1); 240 | 241 | /* orientation vectors */ 242 | sinuk=sin(uk); 243 | cosuk=cos(uk); 244 | sinik=sin(xinck); 245 | cosik=cos(xinck); 246 | sinnok=sin(xnodek); 247 | cosnok=cos(xnodek); 248 | xmx=-sinnok*cosik; 249 | xmy=cosnok*cosik; 250 | ux=xmx*sinuk+cosnok*cosuk; 251 | uy=xmy*sinuk+sinnok*cosuk; 252 | uz=sinik*sinuk; 253 | vx=xmx*cosuk-cosnok*sinuk; 254 | vy=xmy*cosuk-sinnok*sinuk; 255 | vz=sinik*cosuk; 256 | 257 | /* position and velocity */ 258 | x=rk*ux; 259 | y=rk*uy; 260 | z=rk*uz; 261 | xdot=rdotk*ux+rfdotk*vx; 262 | ydot=rdotk*uy+rfdotk*vy; 263 | zdot=rdotk*uz+rfdotk*vz; 264 | 265 | rs[0]=x*XKMPER/AE*1E3; /* (m) */ 266 | rs[1]=y*XKMPER/AE*1E3; 267 | rs[2]=z*XKMPER/AE*1E3; 268 | rs[3]=xdot*XKMPER/AE*XMNPDA/86400.0*1E3; /* (m/s) */ 269 | rs[4]=ydot*XKMPER/AE*XMNPDA/86400.0*1E3; 270 | rs[5]=zdot*XKMPER/AE*XMNPDA/86400.0*1E3; 271 | } 272 | /* drop spaces at string tail ------------------------------------------------*/ 273 | static void chop(char *buff) 274 | { 275 | int i; 276 | for (i=strlen(buff)-1;i>=0;i--) { 277 | if (buff[i]==' '||buff[i]=='\r'||buff[i]=='\n') buff[i]='\0'; 278 | else break; 279 | } 280 | } 281 | /* test TLE line checksum ----------------------------------------------------*/ 282 | static int checksum(const char *buff) 283 | { 284 | int i,cs=0; 285 | 286 | if (strlen(buff)<69) return 0; 287 | 288 | for (i=0;i<68;i++) { 289 | if ('0'<=buff[i]&&buff[i]<='9') cs+=(int)(buff[i]-'0'); 290 | else if (buff[i]=='-') cs+=1; 291 | } 292 | return (int)(buff[68]-'0')==cs%10; 293 | } 294 | /* decode TLE line 1 ---------------------------------------------------------*/ 295 | static int decode_line1(const char *buff, tled_t *data) 296 | { 297 | double year,doy,nddot,exp1,bstar,exp2,ep[6]={2000,1,1}; 298 | 299 | strncpy(data->satno,buff+2,5); /* satellite number */ 300 | data->satno[5]='\0'; 301 | chop(data->satno); 302 | 303 | data->satclass=buff[7]; /* satellite classification */ 304 | strncpy(data->desig,buff+9,8); /* international designator */ 305 | data->desig[8]='\0'; 306 | chop(data->desig); 307 | 308 | year =str2num(buff,18, 2); /* epoch year */ 309 | doy =str2num(buff,20,12); /* epoch day of year */ 310 | data->ndot=str2num(buff,33,10); /* 1st time derivative of n */ 311 | nddot =str2num(buff,44, 6); /* 2nd time derivative of n */ 312 | exp1 =str2num(buff,50, 2); 313 | bstar =str2num(buff,53, 6); /* Bstar drag term */ 314 | exp2 =str2num(buff,59, 2); 315 | data->etype=(int)str2num(buff,62,1); /* ephemeris type */ 316 | data->eleno=(int)str2num(buff,64,4); /* ephemeris number */ 317 | data->nddot=nddot*1E-5*pow(10.0,exp1); 318 | data->bstar=bstar*1E-5*pow(10.0,exp2); 319 | 320 | ep[0]=year+(year<57.0?2000.0:1900.0); 321 | data->epoch=timeadd(epoch2time(ep),(doy-1.0)*86400.0); 322 | 323 | data->inc=data->OMG=data->ecc=data->omg=data->M=data->n=0.0; 324 | data->rev=0; 325 | return 1; 326 | } 327 | /* decode TLE line 2 ---------------------------------------------------------*/ 328 | static int decode_line2(const char *buff, tled_t *data) 329 | { 330 | char satno[16]; 331 | 332 | strncpy(satno,buff+2,5); /* satellite number */ 333 | satno[5]='\0'; 334 | chop(satno); 335 | 336 | data->inc=str2num(buff, 8, 8); /* inclination (deg) */ 337 | data->OMG=str2num(buff,17, 8); /* RAAN (deg) */ 338 | data->ecc=str2num(buff,26, 7)*1E-7; /* eccentricity */ 339 | data->omg=str2num(buff,34, 8); /* argument of perigee (deg) */ 340 | data->M =str2num(buff,43, 8); /* mean anomaly (deg) */ 341 | data->n =str2num(buff,52,11); /* mean motion (rev/day) */ 342 | data->rev=(int)str2num(buff,63,5); /* revolution number */ 343 | 344 | if (strcmp(satno,data->satno)) { 345 | trace(2,"tle satno mismatch: %s %s\n",data->satno,satno); 346 | return 0; 347 | } 348 | if (data->n<=0.0||data->ecc<0.0) { 349 | trace(2,"tle data error: %s\n",satno); 350 | return 0; 351 | } 352 | return 1; 353 | } 354 | /* add TLE data --------------------------------------------------------------*/ 355 | static int add_data(tle_t *tle, const tled_t *data) 356 | { 357 | tled_t *tle_data; 358 | 359 | if (tle->n>=tle->nmax) { 360 | tle->nmax=tle->nmax<=0?1024:tle->nmax*2; 361 | 362 | if (!(tle_data=(tled_t *)realloc(tle->data,sizeof(tled_t)*tle->nmax))) { 363 | trace(1,"tle malloc error\n"); 364 | free(tle->data); tle->data=NULL; tle->n=tle->nmax=0; 365 | return 0; 366 | } 367 | tle->data=tle_data; 368 | } 369 | tle->data[tle->n++]=*data; 370 | return 1; 371 | } 372 | /* compare TLE data by satellite name ----------------------------------------*/ 373 | static int cmp_tle_data(const void *p1, const void *p2) 374 | { 375 | const tled_t *q1=(const tled_t *)p1,*q2=(const tled_t *)p2; 376 | return strcmp(q1->name,q2->name); 377 | } 378 | /* read TLE file --------------------------------------------------------------- 379 | * read NORAD TLE (two line element) data file (ref [2],[3]) 380 | * args : char *file I NORAD TLE data file 381 | * tle_t *tle O TLE data 382 | * return : status (1:ok,0:error) 383 | * notes : before calling the function, the TLE data should be initialized. 384 | * the file should be in a two line (only TLE) or three line (satellite 385 | * name + TLE) format. 386 | * the characters after # in a line are treated as comments. 387 | *-----------------------------------------------------------------------------*/ 388 | extern int tle_read(const char *file, tle_t *tle) 389 | { 390 | FILE *fp; 391 | tled_t data={{0}}; 392 | char *p,buff[256]; 393 | int line=0; 394 | 395 | if (!(fp=fopen(file,"r"))) { 396 | trace(2,"tle file open error: %s\n",file); 397 | return 0; 398 | } 399 | while (fgets(buff,sizeof(buff),fp)) { 400 | 401 | /* delete comments */ 402 | if ((p=strchr(buff,'#'))) *p='\0'; 403 | chop(buff); 404 | 405 | if (buff[0]=='1'&&checksum(buff)) { 406 | 407 | /* decode TLE line 1 */ 408 | if (decode_line1(buff,&data)) line=1; 409 | } 410 | else if (line==1&&buff[0]=='2'&&checksum(buff)) { 411 | 412 | /* decode TLE line 2 */ 413 | if (!decode_line2(buff,&data)) continue; 414 | 415 | /* add TLE data */ 416 | if (!add_data(tle,&data)) { 417 | fclose(fp); 418 | return 0; 419 | } 420 | data.name[0]='\0'; 421 | data.alias[0]='\0'; 422 | } 423 | else if (buff[0]) { 424 | 425 | /* satellite name in three line format */ 426 | strcpy(data.alias,buff); 427 | 428 | /* omit words in parentheses */ 429 | if ((p=strchr(data.alias,'('))) *p='\0'; 430 | chop(data.alias); 431 | line=0; 432 | } 433 | } 434 | fclose(fp); 435 | 436 | /* sort tle data by satellite name */ 437 | if (tle->n>0) qsort(tle->data,tle->n,sizeof(tled_t),cmp_tle_data); 438 | return 1; 439 | } 440 | /* read TLE satellite name file ------------------------------------------------ 441 | * read TLE satellite name file 442 | * args : char *file I TLE satellite name file 443 | * tle_t *tle IO TLE data 444 | * return : status (1:ok,0:error) 445 | * notes : before calling the function, call tle_read() to read tle table 446 | * the TLE satellite name file contains the following record as a text 447 | * line. strings after # are treated as comments. 448 | * 449 | * name satno [desig [# comment]] 450 | * 451 | * name : satellite name 452 | * satno: satellite catalog number 453 | * desig: international designator (optional) 454 | *-----------------------------------------------------------------------------*/ 455 | extern int tle_name_read(const char *file, tle_t *tle) 456 | { 457 | FILE *fp; 458 | tled_t data; 459 | char *p,buff[256],name[256],satno[256],desig[256]; 460 | int i; 461 | 462 | if (!(fp=fopen(file,"r"))) { 463 | trace(2,"tle satellite name file open error: %s\n",file); 464 | return 0; 465 | } 466 | while (fgets(buff,sizeof(buff),fp)) { 467 | 468 | if ((p=strchr(buff,'#'))) *p='\0'; 469 | 470 | desig[0]='\0'; 471 | 472 | if (sscanf(buff,"%s %s %s",name,satno,desig)<2) continue; 473 | satno[5]='\0'; 474 | 475 | for (i=0;in;i++) { 476 | if (!strcmp(tle->data[i].satno,satno)|| 477 | !strcmp(tle->data[i].desig,desig)) break; 478 | } 479 | if (i>=tle->n) { 480 | trace(4,"no tle data: satno=%s desig=%s\n",satno,desig); 481 | continue; 482 | } 483 | if (!*tle->data[i].name) { 484 | strncpy(tle->data[i].name,name,31); 485 | tle->data[i].name[31]='\0'; 486 | } 487 | else { 488 | data=tle->data[i]; 489 | strncpy(data.name,name,31); 490 | data.name[31]='\0'; 491 | if (!add_data(tle,&data)) { 492 | break; 493 | } 494 | } 495 | } 496 | fclose(fp); 497 | 498 | /* sort tle data by satellite name */ 499 | if (tle->n>0) qsort(tle->data,tle->n,sizeof(tled_t),cmp_tle_data); 500 | return 1; 501 | } 502 | /* satellite position and velocity with TLE data ------------------------------- 503 | * compute satellite position and velocity in ECEF with TLE data 504 | * args : gtime_t time I time (GPST) 505 | * char *name I satellite name ("": not specified) 506 | * char *satno I satellite catalog number ("": not specified) 507 | * char *desig I international designaor ("": not specified) 508 | * tle_t *tle I TLE data 509 | * erp_t *erp I EOP data (NULL: not used) 510 | * double *rs O sat position/velocity {x,y,z,vx,vy,vz} (m,m/s) 511 | * return : status (1:ok,0:error) 512 | * notes : the coordinates of the position and velocity are ECEF (ITRF) 513 | * if erp == NULL, polar motion and ut1-utc are neglected 514 | *-----------------------------------------------------------------------------*/ 515 | extern int tle_pos(gtime_t time, const char *name, const char *satno, 516 | const char *desig, const tle_t *tle, const erp_t *erp, 517 | double *rs) 518 | { 519 | gtime_t tutc; 520 | double tsince,rs_tle[6],rs_pef[6],gmst; 521 | double R1[9]={0},R2[9]={0},R3[9]={0},W[9],erpv[5]={0}; 522 | int i=0,j,k,stat=1; 523 | 524 | /* binary search by satellite name */ 525 | if (*name) { 526 | for (i=j=0,k=tle->n-1;j<=k;) { 527 | i=(j+k)/2; 528 | if (!(stat=strcmp(name,tle->data[i].name))) break; 529 | if (stat<0) k=i-1; else j=i+1; 530 | } 531 | } 532 | /* serial search by catalog no or international designator */ 533 | if (stat&&(*satno||*desig)) { 534 | for (i=0;in;i++) { 535 | if (!strcmp(tle->data[i].satno,satno)|| 536 | !strcmp(tle->data[i].desig,desig)) break; 537 | } 538 | if (in) stat=0; 539 | } 540 | if (stat) { 541 | trace(4,"no tle data: name=%s satno=%s desig=%s\n",name,satno,desig); 542 | return 0; 543 | } 544 | tutc=gpst2utc(time); 545 | 546 | /* time since epoch (min) */ 547 | tsince=timediff(tutc,tle->data[i].epoch)/60.0; 548 | 549 | /* SGP4 model propagator by STR#3 */ 550 | SGP4_STR3(tsince,tle->data+i,rs_tle); 551 | 552 | /* erp values */ 553 | if (erp) geterp(erp,time,erpv); 554 | 555 | /* GMST (rad) */ 556 | gmst=utc2gmst(tutc,erpv[2]); 557 | 558 | /* TEME (true equator, mean eqinox) -> ECEF (ref [2] IID, Appendix C) */ 559 | R1[0]=1.0; R1[4]=R1[8]=cos(-erpv[1]); R1[7]=sin(-erpv[1]); R1[5]=-R1[7]; 560 | R2[4]=1.0; R2[0]=R2[8]=cos(-erpv[0]); R2[2]=sin(-erpv[0]); R2[6]=-R2[2]; 561 | R3[8]=1.0; R3[0]=R3[4]=cos(gmst); R3[3]=sin(gmst); R3[1]=-R3[3]; 562 | matmul("NN",3,1,3,1.0,R3,rs_tle ,0.0,rs_pef ); 563 | matmul("NN",3,1,3,1.0,R3,rs_tle+3,0.0,rs_pef+3); 564 | rs_pef[3]+=OMGE*rs_pef[1]; 565 | rs_pef[4]-=OMGE*rs_pef[0]; 566 | matmul("NN",3,3,3,1.0,R1,R2,0.0,W); 567 | matmul("NN",3,1,3,1.0,W,rs_pef ,0.0,rs ); 568 | matmul("NN",3,1,3,1.0,W,rs_pef+3,0.0,rs+3); 569 | return 1; 570 | } 571 | -------------------------------------------------------------------------------- /testdata/ClkCorr20240824.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/ClkCorr20240824.zip -------------------------------------------------------------------------------- /testdata/DcbCorr20240824.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/DcbCorr20240824.zip -------------------------------------------------------------------------------- /testdata/OrbCorr20240824.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/OrbCorr20240824.zip -------------------------------------------------------------------------------- /testdata/PPPB2b.conf: -------------------------------------------------------------------------------- 1 | # rtkpost options (2021/05/16 11:53:14, v.2.4.3 b34) 2 | 3 | pos1-posmode =ppp-static # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed) 4 | pos1-frequency =l1+2 # (1:l1,2:l1+2,3:l1+2+3,4:l1+2+3+4,5:l1+2+3+4+5) 5 | pos1-soltype =forward # (0:forward,1:backward,2:combined) 6 | pos1-elmask =7 # (deg) 7 | pos1-snrmask_r =off # (0:off,1:on) 8 | pos1-snrmask_b =off # (0:off,1:on) 9 | pos1-snrmask_L1 =0,0,0,0,0,0,0,0,0 10 | pos1-snrmask_L2 =0,0,0,0,0,0,0,0,0 11 | pos1-snrmask_L5 =0,0,0,0,0,0,0,0,0 12 | pos1-dynamics =off # (0:off,1:on) 13 | pos1-tidecorr =off # (0:off,1:on,2:otl) 14 | pos1-ionoopt =dual-freq # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc) 15 | pos1-tropopt =est-ztd # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad) 16 | pos1-sateph =brdc+B2b # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom,5:brdc+B2b) 17 | pos1-posopt1 =off # (0:off,1:on) 18 | pos1-posopt2 =off # (0:off,1:on) 19 | pos1-posopt3 =off # (0:off,1:on,2:precise) 20 | pos1-posopt4 =off # (0:off,1:on) 21 | pos1-posopt5 =off # (0:off,1:on) 22 | pos1-posopt6 =off # (0:off,1:on) 23 | pos1-exclsats = # (prn ...) 24 | pos1-navsys =33 # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic) 25 | pos2-armode =fix-and-hold # (0:off,1:continuous,2:instantaneous,3:fix-and-hold) 26 | pos2-gloarmode =off # (0:off,1:on) 27 | pos2-bdsarmode =on # (0:off,1:on) 28 | pos2-arthres =3.0 29 | pos2-arthres1 =0.9999 30 | pos2-arthres2 =0.25s 31 | pos2-arthres3 =0.1 32 | pos2-arthres4 =0.05 33 | pos2-arlockcnt =0 34 | pos2-arelmask =0 # (deg) 35 | pos2-arminfix =10 36 | pos2-armaxiter =1 37 | pos2-elmaskhold =0 # (deg) 38 | pos2-aroutcnt =5 39 | pos2-maxage =5 # (s) 40 | pos2-syncsol =off # (0:off,1:on) 41 | pos2-slipthres =0.05 # (m) 42 | pos2-rejionno =40 # (m) 43 | pos2-rejgdop =30 44 | pos2-niter =1 45 | pos2-baselen =0 # (m) 46 | pos2-basesig =0 # (m) 47 | out-solformat =xyz # (0:llh,1:xyz,2:enu,3:nmea) 48 | out-outhead =on # (0:off,1:on) 49 | out-outopt =on # (0:off,1:on) 50 | out-outvel =off # (0:off,1:on) 51 | out-timesys =utc # (0:gpst,1:utc,2:jst) 52 | out-timeform =hms # (0:tow,1:hms) 53 | out-timendec =3 54 | out-degform =deg # (0:deg,1:dms) 55 | out-fieldsep = 56 | out-outsingle =off # (0:off,1:on) 57 | out-maxsolstd =0 # (m) 58 | out-height =ellipsoidal # (0:ellipsoidal,1:geodetic) 59 | out-geoid =internal # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000) 60 | out-solstatic =all # (0:all,1:single) 61 | out-nmeaintv1 =0 # (s) 62 | out-nmeaintv2 =0 # (s) 63 | out-outstat =off # (0:off,1:state,2:residual) 64 | stats-eratio1 =1000 65 | stats-eratio2 =1000 66 | stats-errphase =0.003 # (m) 67 | stats-errphaseel =0.003 # (m) 68 | stats-errphasebl =0 # (m/10km) 69 | stats-errdoppler =1 # (Hz) 70 | stats-stdbias =30 # (m) 71 | stats-stdiono =0.03 # (m) 72 | stats-stdtrop =0.3 # (m) 73 | stats-prnaccelh =10 # (m/s^2) 74 | stats-prnaccelv =10 # (m/s^2) 75 | stats-prnbias =0.0001 # (m) 76 | stats-prniono =0.001 # (m) 77 | stats-prntrop =0.0001 # (m) 78 | stats-prnpos =0 # (m) 79 | stats-clkstab =5e-12 # (s/s) 80 | ant1-postype =single # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 81 | ant1-pos1 =0 # (deg|m) 82 | ant1-pos2 =0 # (deg|m) 83 | ant1-pos3 =0 # (m|m) 84 | ant1-anttype = 85 | ant1-antdele =0 # (m) 86 | ant1-antdeln =0 # (m) 87 | ant1-antdelu =0 # (m) 88 | ant2-postype =rinexhead # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw) 89 | ant2-pos1 = # (deg|m) 90 | ant2-pos2 = # (deg|m) 91 | ant2-pos3 = # (m|m) 92 | ant2-anttype = 93 | ant2-antdele =0 # (m) 94 | ant2-antdeln =0 # (m) 95 | ant2-antdelu =0 # (m) 96 | ant2-maxaveep =0 97 | ant2-initrst =off # (0:off,1:on) 98 | misc-timeinterp =off # (0:off,1:on) 99 | misc-sbasatsel =0 # (0:all) 100 | misc-rnxopt1 = 101 | misc-rnxopt2 = 102 | misc-pppopt = 103 | 104 | file-tempdir = 105 | file-geexefile = 106 | file-solstatfile = 107 | file-tracefile = 108 | -------------------------------------------------------------------------------- /testdata/PrnMask20240824.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/PrnMask20240824.zip -------------------------------------------------------------------------------- /testdata/WUH22370.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/WUH22370.zip -------------------------------------------------------------------------------- /testdata/brd42370.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GCCProTeam/B2bLIB/e4ebfd8965810614fa22846b7defdff0901b13e5/testdata/brd42370.zip --------------------------------------------------------------------------------