kopia lustrzana https://github.com/projecthorus/radiosonde_auto_rx
				
				
				
			
		
			
				
	
	
		
			1477 wiersze
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			1477 wiersze
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
 | 
						|
/*
 | 
						|
  Quellen:
 | 
						|
           - IS-GPS-200H  (bis C: ICD-GPS-200):
 | 
						|
             http://www.gps.gov/technical/icwg/
 | 
						|
           - Borre: http://kom.aau.dk/~borre
 | 
						|
           - Essential GNSS Project (hier und da etwas unklar)
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
#define  PI  (3.1415926535897932384626433832795)
 | 
						|
 | 
						|
#define  RELATIVISTIC_CLOCK_CORRECTION   (-4.442807633e-10)  // combined constant defined in IS-GPS-200     [s]/[sqrt(m)]
 | 
						|
#define  GRAVITY_CONSTANT                (3.986005e14)       // gravity constant defined on IS-GPS-200      [m^3/s^2]
 | 
						|
#define  EARTH_ROTATION_RATE             (7.2921151467e-05)  // IS-GPS-200                                  [rad/s]
 | 
						|
#define  SECONDS_IN_WEEK                 (604800.0)          // [s]
 | 
						|
#define  LIGHTSPEED                      (299792458.0)       // light speed constant defined in IS-GPS-200  [m/s]
 | 
						|
 | 
						|
#define  RANGE_ESTIMATE                  (0.072)             // approx. GPS-Sat range 0.072s*299792458m/s=21585057m
 | 
						|
#define  RANGERATE_ESTIMATE              (0.000)             //
 | 
						|
 | 
						|
#define EARTH_a      (6378137.0)
 | 
						|
#define EARTH_b      (6356752.31424518)
 | 
						|
#define EARTH_a2_b2  (EARTH_a*EARTH_a - EARTH_b*EARTH_b)
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    ui16_t prn;
 | 
						|
    ui16_t week;
 | 
						|
    ui32_t toa;
 | 
						|
    char   epoch[20];
 | 
						|
    double toe;
 | 
						|
    double toc;
 | 
						|
    double e;
 | 
						|
    double delta_n;
 | 
						|
    double delta_i;
 | 
						|
    double i0;
 | 
						|
    double OmegaDot;
 | 
						|
    double sqrta;
 | 
						|
    double Omega0;
 | 
						|
    double w;
 | 
						|
    double M0;
 | 
						|
    double tgd;
 | 
						|
    double idot;
 | 
						|
    double cuc;
 | 
						|
    double cus;
 | 
						|
    double crc;
 | 
						|
    double crs;
 | 
						|
    double cic;
 | 
						|
    double cis;
 | 
						|
    double af0;
 | 
						|
    double af1;
 | 
						|
    double af2;
 | 
						|
    int gpsweek;
 | 
						|
    ui16_t svn;
 | 
						|
    ui8_t  ura;
 | 
						|
    ui8_t  health;
 | 
						|
    ui8_t  conf;
 | 
						|
} EPHEM_t;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    ui32_t tow;
 | 
						|
    double pseudorange;
 | 
						|
    double pseudorate;
 | 
						|
    double clock_corr;
 | 
						|
    double clock_drift;
 | 
						|
    double X;
 | 
						|
    double Y;
 | 
						|
    double Z;
 | 
						|
    double vX;
 | 
						|
    double vY;
 | 
						|
    double vZ;
 | 
						|
    int ephhr;
 | 
						|
    double PR;
 | 
						|
    double ephtime;
 | 
						|
    int prn;
 | 
						|
    ui8_t status;
 | 
						|
} SAT_t;
 | 
						|
 | 
						|
typedef struct {double X; double Y; double Z;} LOC_t;
 | 
						|
 | 
						|
typedef struct {double  X;  double Y;  double Z;
 | 
						|
                double vX; double vY; double vZ;} VEL_t;
 | 
						|
 | 
						|
static void GPS_SatellitePositionVelocity_Ephem(
 | 
						|
                const unsigned short , const double , EPHEM_t ,
 | 
						|
                double* , double* , double* , double* , double* ,
 | 
						|
                double* , double* , double* );
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
static int ecef2elli(double X, double Y, double Z, double *lat, double *lon, double *alt) {
 | 
						|
    double ea2 = EARTH_a2_b2 / (EARTH_a*EARTH_a),
 | 
						|
           eb2 = EARTH_a2_b2 / (EARTH_b*EARTH_b);
 | 
						|
    double phi, lam, R, p, t;
 | 
						|
    double sint, cost;
 | 
						|
 | 
						|
    lam = atan2( Y , X );
 | 
						|
 | 
						|
    p = sqrt( X*X + Y*Y );
 | 
						|
    t = atan2( Z*EARTH_a , p*EARTH_b );
 | 
						|
 | 
						|
    sint = sin(t);
 | 
						|
    cost = cos(t);
 | 
						|
 | 
						|
    phi = atan2( Z + eb2 * EARTH_b * sint*sint*sint ,
 | 
						|
                 p - ea2 * EARTH_a * cost*cost*cost );
 | 
						|
 | 
						|
    R = EARTH_a / sqrt( 1 - ea2*sin(phi)*sin(phi) );
 | 
						|
    *alt = p / cos(phi) - R;
 | 
						|
 | 
						|
    *lat = phi*180.0/PI;
 | 
						|
    *lon = lam*180.0/PI;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static double dist(double X1, double Y1, double Z1, double X2, double Y2, double Z2) {
 | 
						|
    return sqrt( (X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1) + (Z2-Z1)*(Z2-Z1) );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void rotZ(double x1, double y1, double z1, double angle, double *x2, double *y2, double *z2) {
 | 
						|
    double cosa = cos(angle);
 | 
						|
    double sina = sin(angle);
 | 
						|
    *x2 =  cosa * x1 + sina * y1;
 | 
						|
    *y2 = -sina * x1 + cosa * y1;
 | 
						|
    *z2 = z1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
int read_SEMalmanac(FILE *fp, EPHEM_t *alm) {
 | 
						|
    int l, j;
 | 
						|
    char buf[64];
 | 
						|
    unsigned n, week, toa, ui;
 | 
						|
    double dbl;
 | 
						|
 | 
						|
    l = fscanf(fp, "%u", &n);    if (l != 1) return -1;
 | 
						|
    l = fscanf(fp, "%s", buf);   if (l != 1) return -1;
 | 
						|
    l = fscanf(fp, "%u", &week); if (l != 1) return -1;
 | 
						|
    l = fscanf(fp, "%u", &toa);  if (l != 1) return -1;
 | 
						|
 | 
						|
    for (j = 1; j <= n; j++) {
 | 
						|
        //memset(&ephem, 0, sizeof(ephem));
 | 
						|
 | 
						|
        alm[j].week = (ui16_t)week;
 | 
						|
        alm[j].toa  = (ui32_t)toa;
 | 
						|
        alm[j].toe  = (double)toa;
 | 
						|
        alm[j].toc  = alm[j].toe;
 | 
						|
 | 
						|
        l = fscanf(fp, "%u", &ui);    if (l != 1) return -1;  alm[j].prn = (ui16_t)ui;
 | 
						|
        l = fscanf(fp, "%u", &ui);    if (l != 1) return -2;  alm[j].svn = (ui16_t)ui;
 | 
						|
        l = fscanf(fp, "%u", &ui);    if (l != 1) return -3;  alm[j].ura = (ui8_t)ui;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -4;  alm[j].e = dbl;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -5;  alm[j].delta_i = dbl;
 | 
						|
                                                              alm[j].i0 = (0.30 + alm[j].delta_i) * PI;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -6;  alm[j].OmegaDot = dbl * PI;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -7;  alm[j].sqrta = dbl;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -6;  alm[j].Omega0 = dbl * PI;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -8;  alm[j].w = dbl * PI;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -9;  alm[j].M0 = dbl * PI;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -10; alm[j].af0 = dbl;
 | 
						|
        l = fscanf(fp, "%lf", &dbl);  if (l != 1) return -11; alm[j].af1 = dbl;
 | 
						|
                                                              alm[j].af2 = 0;
 | 
						|
                                                              alm[j].crc = 0;
 | 
						|
                                                              alm[j].crs = 0;
 | 
						|
                                                              alm[j].cuc = 0;
 | 
						|
                                                              alm[j].cus = 0;
 | 
						|
                                                              alm[j].cic = 0;
 | 
						|
                                                              alm[j].cis = 0;
 | 
						|
                                                              alm[j].tgd = 0;
 | 
						|
                                                              alm[j].idot = 0;
 | 
						|
                                                              alm[j].delta_n = 0;
 | 
						|
        l = fscanf(fp, "%u", &ui);    if (l != 1) return -12; alm[j].health = (ui8_t)ui;
 | 
						|
        l = fscanf(fp, "%u", &ui);    if (l != 1) return -13; alm[j].conf = (ui8_t)ui;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
EPHEM_t *read_RNXpephs(FILE *fp) {
 | 
						|
    int l, i, n;
 | 
						|
    char buffer[83];
 | 
						|
    char buf[64], str[20];
 | 
						|
    char *pbuf;
 | 
						|
    unsigned ui;
 | 
						|
    double dbl;
 | 
						|
    int c;
 | 
						|
    EPHEM_t ephem = {}, *te = NULL;
 | 
						|
    int count = 0;
 | 
						|
    long fpos;
 | 
						|
 | 
						|
    do {  // header-Zeilen: 80 Zeichen
 | 
						|
        pbuf = fgets(buffer, 82, fp);   // max 82-1 Zeichen + '\0'
 | 
						|
        buffer[82] = '\0';  // doppelt haelt besser
 | 
						|
    } while ( pbuf  &&  !strstr(buffer, "END OF HEADER") );
 | 
						|
 | 
						|
    if (pbuf == NULL) return NULL;
 | 
						|
    fpos = ftell(fp);
 | 
						|
 | 
						|
    count = 0;
 | 
						|
    while (count >= 0) {  // data-Zeilen: 79 Zeichen
 | 
						|
        pbuf = fgets(buffer, 82, fp); if (pbuf == 0) break;
 | 
						|
        strncpy(str, buffer, 3);
 | 
						|
        str[3] = '\0';
 | 
						|
        sscanf(str, "%d", &ui);
 | 
						|
        if (ui < 33) count++;
 | 
						|
        for (i = 0; i < 7; i++) {
 | 
						|
            pbuf = fgets(buffer, 82, fp); if (pbuf == 0) break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    //printf("Ephemerides: %d\n", count);
 | 
						|
 | 
						|
    fseek(fp, fpos, SEEK_SET);
 | 
						|
 | 
						|
    te = calloc( count+1, sizeof(ephem) ); // calloc( 1, sizeof(ephem) );
 | 
						|
    if (te == NULL) return NULL;
 | 
						|
 | 
						|
    n = 0;
 | 
						|
 | 
						|
    while (count > 0) {  // brdc/hour-rinex sollte nur Daten von einem Tag enthalten
 | 
						|
 | 
						|
        //memset(&ephem, 0, sizeof(ephem));
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;  sscanf(buf, "%d", &ui);
 | 
						|
        ephem.prn = ui;
 | 
						|
 | 
						|
        for (i = 0; i < 16; i++) ephem.epoch[i] = '0';
 | 
						|
        ephem.epoch[16] = '\0';
 | 
						|
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  buf[19] = 0;
 | 
						|
 | 
						|
        for (i = 0; i < 6; i++) {
 | 
						|
            c = buf[3*i  ]; if (c == ' ') c = '0'; str[2*i  ] = c;
 | 
						|
            c = buf[3*i+1]; if (c == ' ') c = '0'; str[2*i+1] = c;
 | 
						|
        }
 | 
						|
        str[12] = buf[17];
 | 
						|
        str[13] = buf[18];
 | 
						|
        str[14] = '\0';
 | 
						|
 | 
						|
        strncpy(ephem.epoch  , "20", 2);  // vorausgesetzt 21.Jhd; Datum steht auch im Header
 | 
						|
        strncpy(ephem.epoch+2, str, 15);
 | 
						|
        ephem.epoch[16] = '\0';
 | 
						|
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.af0 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.af1 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.af2 = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.iode = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.crs = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.delta_n = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.M0 = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.cuc = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.e = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.cus = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.sqrta = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.toe = dbl;
 | 
						|
                                                                                                                                    ephem.toc = ephem.toe;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.cic = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.Omega0 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.cis = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.i0 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.crc = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.w = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.OmegaDot = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.idot = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.codeL2 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.gpsweek = (int)dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.iodc = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.sva = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.svh = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); ephem.tgd = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.iodc = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;
 | 
						|
 | 
						|
        l = fread(buf,  3, 1, fp);    if (l != 1) break;  buf[ 3] = 0;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.ttom = dbl;
 | 
						|
        pbuf = fgets(buffer, 82, fp);
 | 
						|
     /* // die letzten beiden Felder (spare) sind manchmal leer (statt 0.00); manchmal fehlt sogar das drittletzte Feld
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.fit = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.spare1 = dbl;
 | 
						|
        l = fread(buf, 19, 1, fp);    if (l != 1) break;  if (buf[15] == 'D') buf[15] = 'E'; buf[19] = 0; sscanf(buf, "%lf", &dbl); //ephem.spare2 = dbl;
 | 
						|
        if ((c=fgetc(fp)) == EOF) break;  */
 | 
						|
 | 
						|
        ephem.week = 1; // ephem.gpsweek
 | 
						|
 | 
						|
        te[n] = ephem;
 | 
						|
        n += 1;
 | 
						|
 | 
						|
          //tmp = realloc( te, (count+1) * sizeof(ephem) );
 | 
						|
          //if (tmp == NULL) break;
 | 
						|
          //te = tmp;
 | 
						|
 | 
						|
        if (pbuf == NULL) break;
 | 
						|
    }
 | 
						|
 | 
						|
    te[n].prn = 0;
 | 
						|
 | 
						|
 | 
						|
    return te;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
static int trace_invert(double mat[4][4], double trinv[4])  // trace-invert
 | 
						|
/* selected elements from 4x4 matrix inversion */
 | 
						|
{
 | 
						|
    // Find all NECESSARY 2x2 subdeterminants
 | 
						|
    double Det2_12_01 = mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0];
 | 
						|
    double Det2_12_02 = mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0];
 | 
						|
    //double Det2_12_03 = mat[1][0]*mat[2][3] - mat[1][3]*mat[2][0];
 | 
						|
    double Det2_12_12 = mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1];
 | 
						|
    //double Det2_12_13 = mat[1][1]*mat[2][3] - mat[1][3]*mat[2][1];
 | 
						|
    //double Det2_12_23 = mat[1][2]*mat[2][3] - mat[1][3]*mat[2][2];
 | 
						|
    double Det2_13_01 = mat[1][0] * mat[3][1] - mat[1][1] * mat[3][0];
 | 
						|
    //double Det2_13_02 = mat[1][0]*mat[3][2] - mat[1][2]*mat[3][0];
 | 
						|
    double Det2_13_03 = mat[1][0] * mat[3][3] - mat[1][3] * mat[3][0];
 | 
						|
    //double Det2_13_12 = mat[1][1]*mat[3][2] - mat[1][2]*mat[3][1];
 | 
						|
    double Det2_13_13 = mat[1][1] * mat[3][3] - mat[1][3] * mat[3][1];
 | 
						|
    //double Det2_13_23 = mat[1][2]*mat[3][3] - mat[1][3]*mat[3][2];
 | 
						|
    double Det2_23_01 = mat[2][0] * mat[3][1] - mat[2][1] * mat[3][0];
 | 
						|
    double Det2_23_02 = mat[2][0] * mat[3][2] - mat[2][2] * mat[3][0];
 | 
						|
    double Det2_23_03 = mat[2][0] * mat[3][3] - mat[2][3] * mat[3][0];
 | 
						|
    double Det2_23_12 = mat[2][1] * mat[3][2] - mat[2][2] * mat[3][1];
 | 
						|
    double Det2_23_13 = mat[2][1] * mat[3][3] - mat[2][3] * mat[3][1];
 | 
						|
    double Det2_23_23 = mat[2][2] * mat[3][3] - mat[2][3] * mat[3][2];
 | 
						|
 | 
						|
    // Find all NECESSARY 3x3 subdeterminants
 | 
						|
    double Det3_012_012 = mat[0][0] * Det2_12_12 - mat[0][1] * Det2_12_02 + mat[0][2] * Det2_12_01;
 | 
						|
    //double Det3_012_013 = mat[0][0]*Det2_12_13 - mat[0][1]*Det2_12_03 + mat[0][3]*Det2_12_01;
 | 
						|
    //double Det3_012_023 = mat[0][0]*Det2_12_23 - mat[0][2]*Det2_12_03 + mat[0][3]*Det2_12_02;
 | 
						|
    //double Det3_012_123 = mat[0][1]*Det2_12_23 - mat[0][2]*Det2_12_13 + mat[0][3]*Det2_12_12;
 | 
						|
    //double Det3_013_012 = mat[0][0]*Det2_13_12 - mat[0][1]*Det2_13_02 + mat[0][2]*Det2_13_01;
 | 
						|
    double Det3_013_013 = mat[0][0] * Det2_13_13 - mat[0][1] * Det2_13_03 + mat[0][3] * Det2_13_01;
 | 
						|
    //double Det3_013_023 = mat[0][0]*Det2_13_23 - mat[0][2]*Det2_13_03 + mat[0][3]*Det2_13_02;
 | 
						|
    //double Det3_013_123 = mat[0][1]*Det2_13_23 - mat[0][2]*Det2_13_13 + mat[0][3]*Det2_13_12;
 | 
						|
    //double Det3_023_012 = mat[0][0]*Det2_23_12 - mat[0][1]*Det2_23_02 + mat[0][2]*Det2_23_01;
 | 
						|
    //double Det3_023_013 = mat[0][0]*Det2_23_13 - mat[0][1]*Det2_23_03 + mat[0][3]*Det2_23_01;
 | 
						|
    double Det3_023_023 = mat[0][0] * Det2_23_23 - mat[0][2] * Det2_23_03 + mat[0][3] * Det2_23_02;
 | 
						|
    //double Det3_023_123 = mat[0][1]*Det2_23_23 - mat[0][2]*Det2_23_13 + mat[0][3]*Det2_23_12;
 | 
						|
    double Det3_123_012 = mat[1][0] * Det2_23_12 - mat[1][1] * Det2_23_02 + mat[1][2] * Det2_23_01;
 | 
						|
    double Det3_123_013 = mat[1][0] * Det2_23_13 - mat[1][1] * Det2_23_03 + mat[1][3] * Det2_23_01;
 | 
						|
    double Det3_123_023 = mat[1][0] * Det2_23_23 - mat[1][2] * Det2_23_03 + mat[1][3] * Det2_23_02;
 | 
						|
    double Det3_123_123 = mat[1][1] * Det2_23_23 - mat[1][2] * Det2_23_13 + mat[1][3] * Det2_23_12;
 | 
						|
 | 
						|
    // Find the 4x4 determinant
 | 
						|
    static double det;
 | 
						|
    det = mat[0][0] * Det3_123_123
 | 
						|
	    - mat[0][1] * Det3_123_023
 | 
						|
	    + mat[0][2] * Det3_123_013
 | 
						|
	    - mat[0][3] * Det3_123_012;
 | 
						|
 | 
						|
    // Very small determinants probably reflect floating-point fuzz near zero
 | 
						|
    if (fabs(det) < 0.0001)
 | 
						|
	return -1;
 | 
						|
 | 
						|
    //inv[0][0] = Det3_123_123 / det;
 | 
						|
    //inv[0][1] = -Det3_023_123 / det;
 | 
						|
    //inv[0][2] =  Det3_013_123 / det;
 | 
						|
    //inv[0][3] = -Det3_012_123 / det;
 | 
						|
 | 
						|
    //inv[1][0] = -Det3_123_023 / det;
 | 
						|
    //inv[1][1] = Det3_023_023 / det;
 | 
						|
    //inv[1][2] = -Det3_013_023 / det;
 | 
						|
    //inv[1][3] =  Det3_012_023 / det;
 | 
						|
 | 
						|
    //inv[2][0] =  Det3_123_013 / det;
 | 
						|
    //inv[2][1] = -Det3_023_013 / det;
 | 
						|
    //inv[2][2] = Det3_013_013 / det;
 | 
						|
    //inv[2][3] = -Det3_012_013 / det;
 | 
						|
 | 
						|
    //inv[3][0] = -Det3_123_012 / det;
 | 
						|
    //inv[3][1] =  Det3_023_012 / det;
 | 
						|
    //inv[3][2] = -Det3_013_012 / det;
 | 
						|
    //inv[3][3] = Det3_012_012 / det;
 | 
						|
 | 
						|
    trinv[0] = Det3_123_123 / det;
 | 
						|
 | 
						|
    trinv[1] = Det3_023_023 / det;
 | 
						|
    trinv[2] = Det3_013_013 / det;
 | 
						|
    trinv[3] = Det3_012_012 / det;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int calc_DOPn(int n, SAT_t satss[], double pos_ecef[3], double DOP[4]) {
 | 
						|
    int i, j, k;
 | 
						|
    double norm[n], satpos[n][3];
 | 
						|
    double SATS[n][4], AtA[4][4];
 | 
						|
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
        satpos[i][0] = satss[i].X-pos_ecef[0];
 | 
						|
        satpos[i][1] = satss[i].Y-pos_ecef[1];
 | 
						|
        satpos[i][2] = satss[i].Z-pos_ecef[2];
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
        norm[i] = sqrt( satpos[i][0]*satpos[i][0] + satpos[i][1]*satpos[i][1] + satpos[i][2]*satpos[i][2] );
 | 
						|
        for (j = 0; j < 3; j++) {
 | 
						|
            SATS[i][j] = satpos[i][j] / norm[i];
 | 
						|
        }
 | 
						|
        SATS[i][3] = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        for (j = 0; j < 4; j++) {
 | 
						|
            AtA[i][j] = 0.0;
 | 
						|
            for (k = 0; k < n; k++) {
 | 
						|
                AtA[i][j] += SATS[k][i]*SATS[k][j];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return trace_invert(AtA, DOP);
 | 
						|
}
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
static int rotE(SAT_t sat, double *x, double *y, double *z) {
 | 
						|
    // Erdrotation ECEF-ECI,  0.070s*299792458m/s=20985472m, 0.072s*299792458m/s=21585057m
 | 
						|
    double range = sat.PR/LIGHTSPEED;
 | 
						|
    if (range < 19e6  ||  range > 30e6) range = 21e6;
 | 
						|
    rotZ(sat.X, sat.Y, sat.Z, EARTH_ROTATION_RATE*(range/LIGHTSPEED), x, y, z);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static double lorentz(double a[4], double b[4]) {
 | 
						|
    return a[0]*b[0] + a[1]*b[1] +a[2]*b[2] - a[3]*b[3];
 | 
						|
}
 | 
						|
 | 
						|
static int matrix_invert(double mat[4][4], double inv[4][4])
 | 
						|
{
 | 
						|
    // 2x2 subdeterminants
 | 
						|
    double Det2_12_01 = mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0];
 | 
						|
    double Det2_12_02 = mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0];
 | 
						|
    double Det2_12_03 = mat[1][0] * mat[2][3] - mat[1][3] * mat[2][0];
 | 
						|
    double Det2_12_12 = mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1];
 | 
						|
    double Det2_12_13 = mat[1][1] * mat[2][3] - mat[1][3] * mat[2][1];
 | 
						|
    double Det2_12_23 = mat[1][2] * mat[2][3] - mat[1][3] * mat[2][2];
 | 
						|
    double Det2_13_01 = mat[1][0] * mat[3][1] - mat[1][1] * mat[3][0];
 | 
						|
    double Det2_13_02 = mat[1][0] * mat[3][2] - mat[1][2] * mat[3][0];
 | 
						|
    double Det2_13_03 = mat[1][0] * mat[3][3] - mat[1][3] * mat[3][0];
 | 
						|
    double Det2_13_12 = mat[1][1] * mat[3][2] - mat[1][2] * mat[3][1];
 | 
						|
    double Det2_13_13 = mat[1][1] * mat[3][3] - mat[1][3] * mat[3][1];
 | 
						|
    double Det2_13_23 = mat[1][2] * mat[3][3] - mat[1][3] * mat[3][2];
 | 
						|
    double Det2_23_01 = mat[2][0] * mat[3][1] - mat[2][1] * mat[3][0];
 | 
						|
    double Det2_23_02 = mat[2][0] * mat[3][2] - mat[2][2] * mat[3][0];
 | 
						|
    double Det2_23_03 = mat[2][0] * mat[3][3] - mat[2][3] * mat[3][0];
 | 
						|
    double Det2_23_12 = mat[2][1] * mat[3][2] - mat[2][2] * mat[3][1];
 | 
						|
    double Det2_23_13 = mat[2][1] * mat[3][3] - mat[2][3] * mat[3][1];
 | 
						|
    double Det2_23_23 = mat[2][2] * mat[3][3] - mat[2][3] * mat[3][2];
 | 
						|
 | 
						|
    // 3x3 subdeterminants
 | 
						|
    double Det3_012_012 = mat[0][0] * Det2_12_12 - mat[0][1] * Det2_12_02 + mat[0][2] * Det2_12_01;
 | 
						|
    double Det3_012_013 = mat[0][0] * Det2_12_13 - mat[0][1] * Det2_12_03 + mat[0][3] * Det2_12_01;
 | 
						|
    double Det3_012_023 = mat[0][0] * Det2_12_23 - mat[0][2] * Det2_12_03 + mat[0][3] * Det2_12_02;
 | 
						|
    double Det3_012_123 = mat[0][1] * Det2_12_23 - mat[0][2] * Det2_12_13 + mat[0][3] * Det2_12_12;
 | 
						|
    double Det3_013_012 = mat[0][0] * Det2_13_12 - mat[0][1] * Det2_13_02 + mat[0][2] * Det2_13_01;
 | 
						|
    double Det3_013_013 = mat[0][0] * Det2_13_13 - mat[0][1] * Det2_13_03 + mat[0][3] * Det2_13_01;
 | 
						|
    double Det3_013_023 = mat[0][0] * Det2_13_23 - mat[0][2] * Det2_13_03 + mat[0][3] * Det2_13_02;
 | 
						|
    double Det3_013_123 = mat[0][1] * Det2_13_23 - mat[0][2] * Det2_13_13 + mat[0][3] * Det2_13_12;
 | 
						|
    double Det3_023_012 = mat[0][0] * Det2_23_12 - mat[0][1] * Det2_23_02 + mat[0][2] * Det2_23_01;
 | 
						|
    double Det3_023_013 = mat[0][0] * Det2_23_13 - mat[0][1] * Det2_23_03 + mat[0][3] * Det2_23_01;
 | 
						|
    double Det3_023_023 = mat[0][0] * Det2_23_23 - mat[0][2] * Det2_23_03 + mat[0][3] * Det2_23_02;
 | 
						|
    double Det3_023_123 = mat[0][1] * Det2_23_23 - mat[0][2] * Det2_23_13 + mat[0][3] * Det2_23_12;
 | 
						|
    double Det3_123_012 = mat[1][0] * Det2_23_12 - mat[1][1] * Det2_23_02 + mat[1][2] * Det2_23_01;
 | 
						|
    double Det3_123_013 = mat[1][0] * Det2_23_13 - mat[1][1] * Det2_23_03 + mat[1][3] * Det2_23_01;
 | 
						|
    double Det3_123_023 = mat[1][0] * Det2_23_23 - mat[1][2] * Det2_23_03 + mat[1][3] * Det2_23_02;
 | 
						|
    double Det3_123_123 = mat[1][1] * Det2_23_23 - mat[1][2] * Det2_23_13 + mat[1][3] * Det2_23_12;
 | 
						|
 | 
						|
    // 4x4 determinant
 | 
						|
    static double det;
 | 
						|
    det = mat[0][0] * Det3_123_123
 | 
						|
	    - mat[0][1] * Det3_123_023
 | 
						|
	    + mat[0][2] * Det3_123_013
 | 
						|
	    - mat[0][3] * Det3_123_012;
 | 
						|
 | 
						|
    // Very small determinants probably reflect floating-point fuzz near zero
 | 
						|
    if (fabs(det) < 0.0001)
 | 
						|
	return -1;
 | 
						|
 | 
						|
    inv[0][0] =  Det3_123_123 / det;
 | 
						|
    inv[0][1] = -Det3_023_123 / det;
 | 
						|
    inv[0][2] =  Det3_013_123 / det;
 | 
						|
    inv[0][3] = -Det3_012_123 / det;
 | 
						|
 | 
						|
    inv[1][0] = -Det3_123_023 / det;
 | 
						|
    inv[1][1] =  Det3_023_023 / det;
 | 
						|
    inv[1][2] = -Det3_013_023 / det;
 | 
						|
    inv[1][3] =  Det3_012_023 / det;
 | 
						|
 | 
						|
    inv[2][0] =  Det3_123_013 / det;
 | 
						|
    inv[2][1] = -Det3_023_013 / det;
 | 
						|
    inv[2][2] =  Det3_013_013 / det;
 | 
						|
    inv[2][3] = -Det3_012_013 / det;
 | 
						|
 | 
						|
    inv[3][0] = -Det3_123_012 / det;
 | 
						|
    inv[3][1] =  Det3_023_012 / det;
 | 
						|
    inv[3][2] = -Det3_013_012 / det;
 | 
						|
    inv[3][3] =  Det3_012_012 / det;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int NAV_bancroft1(int N, SAT_t sats[], double pos_ecef[3], double *cc) {
 | 
						|
 | 
						|
    int i, j, k;
 | 
						|
    double B[N][4], BtB[4][4], BBinv[4][4], BBB[4][N];
 | 
						|
    double a[N], Be[4], Ba[4];
 | 
						|
 | 
						|
    double q0, q1, q2, p, q, sq, x1, x2;
 | 
						|
    double Lsg1[4], Lsg2[4];
 | 
						|
 | 
						|
    double tmp1, tmp2;
 | 
						|
    double X, Y, Z;
 | 
						|
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        rotZ(sats[i].X, sats[i].Y, sats[i].Z, EARTH_ROTATION_RATE*RANGE_ESTIMATE, B[i], B[i]+1, B[i]+2);
 | 
						|
        B[i][3] = sats[i].pseudorange + sats[i].clock_corr;
 | 
						|
    }
 | 
						|
 | 
						|
    if (N == 4) {
 | 
						|
        matrix_invert(B, BBB);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < 4; j++) {
 | 
						|
                BtB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < N; k++) {
 | 
						|
                    BtB[i][j] += B[k][i]*B[k][j];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        matrix_invert(BtB, BBinv);
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < N; j++) {
 | 
						|
                BBB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < 4; k++) {
 | 
						|
                    BBB[i][j] += BBinv[i][k]*B[j][k];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Be[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Be[i] += BBB[i][k]*1.0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        a[i] = 0.5 * lorentz(B[i], B[i]);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Ba[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Ba[i] += BBB[i][k]*a[k];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    q2 = lorentz(Be, Be);
 | 
						|
    q1 = lorentz(Ba, Be)-1;
 | 
						|
    q0 = lorentz(Ba, Ba);
 | 
						|
 | 
						|
    if (q2 == 0) return -2;
 | 
						|
 | 
						|
    p = q1/q2;
 | 
						|
    q = q0/q2;
 | 
						|
 | 
						|
    sq = p*p - q;
 | 
						|
    if (sq < 0) return -2;
 | 
						|
 | 
						|
    x1 = -p + sqrt(sq);
 | 
						|
    x2 = -p - sqrt(sq);
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Lsg1[i] = x1*Be[i]+Ba[i];
 | 
						|
        Lsg2[i] = x2*Be[i]+Ba[i];
 | 
						|
    }
 | 
						|
    Lsg1[3] = -Lsg1[3];
 | 
						|
    Lsg2[3] = -Lsg2[3];
 | 
						|
 | 
						|
 | 
						|
    tmp1 = sqrt( Lsg1[0]*Lsg1[0] + Lsg1[1]*Lsg1[1] + Lsg1[2]*Lsg1[2] );
 | 
						|
    tmp2 = sqrt( Lsg2[0]*Lsg2[0] + Lsg2[1]*Lsg2[1] + Lsg2[2]*Lsg2[2] );
 | 
						|
 | 
						|
    tmp1 = fabs( tmp1 - 6371000.0 );
 | 
						|
    tmp2 = fabs( tmp2 - 6371000.0 );
 | 
						|
 | 
						|
    if (tmp1 < tmp2) {
 | 
						|
        X = Lsg1[0]; Y = Lsg1[1]; Z = Lsg1[2]; *cc = Lsg1[3];
 | 
						|
    } else {
 | 
						|
        X = Lsg2[0]; Y = Lsg2[1]; Z = Lsg2[2]; *cc = Lsg2[3];
 | 
						|
    }
 | 
						|
    pos_ecef[0] = X;
 | 
						|
    pos_ecef[1] = Y;
 | 
						|
    pos_ecef[2] = Z;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int NAV_bancroft2(int N, SAT_t sats[], double pos_ecef[3], double *cc) {
 | 
						|
 | 
						|
    int i, j, k;
 | 
						|
    double B[N][4], BtB[4][4], BBinv[4][4], BBB[4][N];
 | 
						|
    double a[N], Be[4], Ba[4];
 | 
						|
 | 
						|
    double q0, q1, q2, p, q, sq, x1, x2;
 | 
						|
    double Lsg1[4], Lsg2[4];
 | 
						|
 | 
						|
    double tmp1, tmp2;
 | 
						|
    double X, Y, Z;
 | 
						|
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        rotE(sats[i], B[i], B[i]+1, B[i]+2);
 | 
						|
        B[i][3] = sats[i].PR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (N == 4) {
 | 
						|
        matrix_invert(B, BBB);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < 4; j++) {
 | 
						|
                BtB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < N; k++) {
 | 
						|
                    BtB[i][j] += B[k][i]*B[k][j];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        matrix_invert(BtB, BBinv);
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < N; j++) {
 | 
						|
                BBB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < 4; k++) {
 | 
						|
                    BBB[i][j] += BBinv[i][k]*B[j][k];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Be[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Be[i] += BBB[i][k]*1.0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        a[i] = 0.5 * lorentz(B[i], B[i]);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Ba[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Ba[i] += BBB[i][k]*a[k];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    q2 = lorentz(Be, Be);
 | 
						|
    q1 = lorentz(Ba, Be)-1;
 | 
						|
    q0 = lorentz(Ba, Ba);
 | 
						|
 | 
						|
    if (q2 == 0) return -2;
 | 
						|
 | 
						|
    p = q1/q2;
 | 
						|
    q = q0/q2;
 | 
						|
 | 
						|
    sq = p*p - q;
 | 
						|
    if (sq < 0) return -2;
 | 
						|
 | 
						|
    x1 = -p + sqrt(sq);
 | 
						|
    x2 = -p - sqrt(sq);
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Lsg1[i] = x1*Be[i]+Ba[i];
 | 
						|
        Lsg2[i] = x2*Be[i]+Ba[i];
 | 
						|
    }
 | 
						|
    Lsg1[3] = -Lsg1[3];
 | 
						|
    Lsg2[3] = -Lsg2[3];
 | 
						|
 | 
						|
 | 
						|
    tmp1 = sqrt( Lsg1[0]*Lsg1[0] + Lsg1[1]*Lsg1[1] + Lsg1[2]*Lsg1[2] );
 | 
						|
    tmp2 = sqrt( Lsg2[0]*Lsg2[0] + Lsg2[1]*Lsg2[1] + Lsg2[2]*Lsg2[2] );
 | 
						|
 | 
						|
    tmp1 = fabs( tmp1 - 6371000.0 );
 | 
						|
    tmp2 = fabs( tmp2 - 6371000.0 );
 | 
						|
 | 
						|
    if (tmp1 < tmp2) {
 | 
						|
        X = Lsg1[0]; Y = Lsg1[1]; Z = Lsg1[2]; *cc = Lsg1[3];
 | 
						|
    } else {
 | 
						|
        X = Lsg2[0]; Y = Lsg2[1]; Z = Lsg2[2]; *cc = Lsg2[3];
 | 
						|
    }
 | 
						|
    pos_ecef[0] = X;
 | 
						|
    pos_ecef[1] = Y;
 | 
						|
    pos_ecef[2] = Z;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
int NAV_bancroft3(int N, SAT_t sats[], double pos_ecef1[3], double *cc1 , double pos_ecef2[3], double *cc2) {
 | 
						|
 | 
						|
    int i, j, k;
 | 
						|
    double B[N][4], BtB[4][4], BBinv[4][4], BBB[4][N];
 | 
						|
    double a[N], Be[4], Ba[4];
 | 
						|
 | 
						|
    double q0, q1, q2, p, q, sq, x1, x2;
 | 
						|
    double Lsg1[4], Lsg2[4];
 | 
						|
 | 
						|
    double tmp1, tmp2;
 | 
						|
    double X1, Y1, Z1;
 | 
						|
    double X2, Y2, Z2;
 | 
						|
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {  // Test: nicht hier rotieren, sondern spaeter Lsg rotieren...
 | 
						|
        rotZ(sats[i].X, sats[i].Y, sats[i].Z, 0.0, B[i], B[i]+1, B[i]+2);
 | 
						|
        //B[i][3] = sats[i].PR;
 | 
						|
        B[i][3] = sats[i].pseudorange + sats[i].clock_corr;
 | 
						|
    }
 | 
						|
 | 
						|
    if (N == 4) {
 | 
						|
        matrix_invert(B, BBB);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < 4; j++) {
 | 
						|
                BtB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < N; k++) {
 | 
						|
                    BtB[i][j] += B[k][i]*B[k][j];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        matrix_invert(BtB, BBinv);
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < N; j++) {
 | 
						|
                BBB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < 4; k++) {
 | 
						|
                    BBB[i][j] += BBinv[i][k]*B[j][k];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Be[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Be[i] += BBB[i][k]*1.0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        a[i] = 0.5 * lorentz(B[i], B[i]);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Ba[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Ba[i] += BBB[i][k]*a[k];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    q2 = lorentz(Be, Be);
 | 
						|
    q1 = lorentz(Ba, Be)-1;
 | 
						|
    q0 = lorentz(Ba, Ba);
 | 
						|
 | 
						|
    if (q2 == 0) return -2;
 | 
						|
 | 
						|
    p = q1/q2;
 | 
						|
    q = q0/q2;
 | 
						|
 | 
						|
    sq = p*p - q;
 | 
						|
    if (sq < 0) return -2;
 | 
						|
 | 
						|
    x1 = -p + sqrt(sq);
 | 
						|
    x2 = -p - sqrt(sq);
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Lsg1[i] = x1*Be[i]+Ba[i];
 | 
						|
        Lsg2[i] = x2*Be[i]+Ba[i];
 | 
						|
    }
 | 
						|
    Lsg1[3] = -Lsg1[3];
 | 
						|
    Lsg2[3] = -Lsg2[3];
 | 
						|
 | 
						|
 | 
						|
    tmp1 = sqrt( Lsg1[0]*Lsg1[0] + Lsg1[1]*Lsg1[1] + Lsg1[2]*Lsg1[2] );
 | 
						|
    tmp2 = sqrt( Lsg2[0]*Lsg2[0] + Lsg2[1]*Lsg2[1] + Lsg2[2]*Lsg2[2] );
 | 
						|
 | 
						|
    tmp1 = tmp1 - 6371000.0;
 | 
						|
    tmp2 = tmp2 - 6371000.0;
 | 
						|
 | 
						|
    if ( fabs(tmp1) < fabs(tmp2) ) {
 | 
						|
        X1 = Lsg1[0]; Y1 = Lsg1[1]; Z1 = Lsg1[2]; *cc1 = Lsg1[3];
 | 
						|
        X2 = Lsg2[0]; Y2 = Lsg2[1]; Z2 = Lsg2[2]; *cc2 = Lsg2[3];
 | 
						|
    } else {
 | 
						|
        X1 = Lsg2[0]; Y1 = Lsg2[1]; Z1 = Lsg2[2]; *cc1 = Lsg2[3];
 | 
						|
        X2 = Lsg1[0]; Y2 = Lsg1[1]; Z2 = Lsg1[2]; *cc2 = Lsg1[3];
 | 
						|
    }
 | 
						|
 | 
						|
    rotZ(X1, Y1, Z1, EARTH_ROTATION_RATE*RANGE_ESTIMATE, pos_ecef1, pos_ecef1+1, pos_ecef1+2);
 | 
						|
    rotZ(X2, Y2, Z2, EARTH_ROTATION_RATE*RANGE_ESTIMATE, pos_ecef2, pos_ecef2+1, pos_ecef2+2);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
 | 
						|
static double NAV_relVel(LOC_t loc, VEL_t vel) {
 | 
						|
    double d;
 | 
						|
    double x,y,z;
 | 
						|
    double norm;
 | 
						|
 | 
						|
    x = vel.X-loc.X;
 | 
						|
    y = vel.Y-loc.Y;
 | 
						|
    z = vel.Z-loc.Z;
 | 
						|
    norm = sqrt(x*x+y*y+z*z);
 | 
						|
    x /= norm;
 | 
						|
    y /= norm;
 | 
						|
    z /= norm;
 | 
						|
 | 
						|
    d = vel.vX*x + vel.vY*y + vel.vZ*z;
 | 
						|
 | 
						|
    return d;
 | 
						|
}
 | 
						|
 | 
						|
int NAV_LinP(int N, SAT_t satv[], double pos_ecef[3], double dt,
 | 
						|
                    double dpos_ecef[3], double *cc) {
 | 
						|
 | 
						|
    int i, j, k;
 | 
						|
    double B[N][4], Binv[4][N], BtB[4][4], BBinv[4][4];
 | 
						|
    double a[N], Ba[N];
 | 
						|
 | 
						|
    double X, Y, Z;
 | 
						|
    double norm[N];
 | 
						|
    double range, obs_range, prox_range;
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
 | 
						|
        range = dist( pos_ecef[0], pos_ecef[1], pos_ecef[2], satv[i].X, satv[i].Y, satv[i].Z );
 | 
						|
        range /= LIGHTSPEED;
 | 
						|
        if (range < 0.06  ||  range > 0.1) range = RANGE_ESTIMATE;
 | 
						|
        rotZ(satv[i].X, satv[i].Y, satv[i].Z, EARTH_ROTATION_RATE*range, B[i], B[i]+1, B[i]+2);
 | 
						|
        //rotZ(satv[i].X, satv[i].Y, satv[i].Z, 0.0, B[i], B[i]+1, B[i]+2); // est. RANGE_RATE = 0.0
 | 
						|
 | 
						|
        X = B[i][0]-pos_ecef[0];
 | 
						|
        Y = B[i][1]-pos_ecef[1];
 | 
						|
        Z = B[i][2]-pos_ecef[2];
 | 
						|
        norm[i] = sqrt(X*X+Y*Y+Z*Z);
 | 
						|
 | 
						|
        B[i][0] = X/norm[i];
 | 
						|
        B[i][1] = Y/norm[i];
 | 
						|
        B[i][2] = Z/norm[i];
 | 
						|
 | 
						|
        B[i][3] = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (N == 4) {
 | 
						|
        matrix_invert(B, Binv);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < 4; j++) {
 | 
						|
                BtB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < N; k++) {
 | 
						|
                    BtB[i][j] += B[k][i]*B[k][j];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        matrix_invert(BtB, BBinv);
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < N; j++) {
 | 
						|
                Binv[i][j] = 0.0;
 | 
						|
                for (k = 0; k < 4; k++) {
 | 
						|
                    Binv[i][j] += BBinv[i][k]*B[j][k];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        obs_range = satv[i].pseudorange + satv[i].clock_corr; //satv[i].PR;
 | 
						|
        prox_range = norm[i] - dt;
 | 
						|
        a[i] = prox_range - obs_range;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Ba[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Ba[i] += Binv[i][k]*a[k];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    dpos_ecef[0] = Ba[0];
 | 
						|
    dpos_ecef[1] = Ba[1];
 | 
						|
    dpos_ecef[2] = Ba[2];
 | 
						|
 | 
						|
    *cc = Ba[3];
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int NAV_LinV(int N, SAT_t satv[], double pos_ecef[3],
 | 
						|
                    double vel_ecef[3], double dt,
 | 
						|
                    double dvel_ecef[3], double *cc) {
 | 
						|
 | 
						|
    int i, j, k;
 | 
						|
    double B[N][4], Binv[4][N], BtB[4][4], BBinv[4][4];
 | 
						|
    double a[N], Ba[N];
 | 
						|
 | 
						|
    double X, Y, Z;
 | 
						|
    double norm[N];
 | 
						|
    double v_proj;
 | 
						|
    double obs_rate, prox_rate;
 | 
						|
    LOC_t loc;
 | 
						|
    VEL_t vel;
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    loc.X = pos_ecef[0];
 | 
						|
    loc.Y = pos_ecef[1];
 | 
						|
    loc.Z = pos_ecef[2];
 | 
						|
 | 
						|
    if (N < 4 || N > 12) return -1;
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        rotZ(satv[i].X, satv[i].Y, satv[i].Z, EARTH_ROTATION_RATE*RANGE_ESTIMATE, B[i], B[i]+1, B[i]+2);
 | 
						|
        //rotZ(satv[i].X, satv[i].Y, satv[i].Z, 0.0, B[i], B[i]+1, B[i]+2); // est. RANGE_RATE = 0.0
 | 
						|
 | 
						|
        X = B[i][0]-pos_ecef[0];
 | 
						|
        Y = B[i][1]-pos_ecef[1];
 | 
						|
        Z = B[i][2]-pos_ecef[2];
 | 
						|
        norm[i] = sqrt(X*X+Y*Y+Z*Z);
 | 
						|
        B[i][0] = X/norm[i];
 | 
						|
        B[i][1] = Y/norm[i];
 | 
						|
        B[i][2] = Z/norm[i];
 | 
						|
 | 
						|
        // SatSpeed = sqrt( satv[i].vX*satv[i].vX + satv[i].vY*satv[i].vY + satv[i].vZ*satv[i].vZ );
 | 
						|
 | 
						|
        B[i][3] = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (N == 4) {
 | 
						|
        matrix_invert(B, Binv);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < 4; j++) {
 | 
						|
                BtB[i][j] = 0.0;
 | 
						|
                for (k = 0; k < N; k++) {
 | 
						|
                    BtB[i][j] += B[k][i]*B[k][j];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        matrix_invert(BtB, BBinv);
 | 
						|
        for (i = 0; i < 4; i++) {
 | 
						|
            for (j = 0; j < N; j++) {
 | 
						|
                Binv[i][j] = 0.0;
 | 
						|
                for (k = 0; k < 4; k++) {
 | 
						|
                    Binv[i][j] += BBinv[i][k]*B[j][k];
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    for (i = 0; i < N; i++) {
 | 
						|
        obs_rate = satv[i].pseudorate; // + satv[i].clock_drift;
 | 
						|
        vel.X = satv[i].X;
 | 
						|
        vel.Y = satv[i].Y;
 | 
						|
        vel.Z = satv[i].Z;
 | 
						|
        vel.vX = satv[i].vX - vel_ecef[0];
 | 
						|
        vel.vY = satv[i].vY - vel_ecef[1];
 | 
						|
        vel.vZ = satv[i].vZ - vel_ecef[2];
 | 
						|
        v_proj = NAV_relVel(loc, vel);
 | 
						|
        prox_rate = v_proj - dt;
 | 
						|
        a[i] = prox_rate - obs_rate;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < 4; i++) {
 | 
						|
        Ba[i] = 0.0;
 | 
						|
        for (k = 0; k < N; k++) {
 | 
						|
            Ba[i] += Binv[i][k]*a[k];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    dvel_ecef[0] = Ba[0];
 | 
						|
    dvel_ecef[1] = Ba[1];
 | 
						|
    dvel_ecef[2] = Ba[2];
 | 
						|
 | 
						|
    *cc = Ba[3];
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
// -------------------------------------------------------------
 | 
						|
 | 
						|
#define GPS_WEEK1024  1
 | 
						|
#define WEEKSEC       604800
 | 
						|
 | 
						|
 | 
						|
int gps_satpos_alm(rs_data_t *rs_data, EPHEM_t alm[], double t, SAT_t *sat) {
 | 
						|
    double X, Y, Z, vX, vY, vZ;
 | 
						|
    int i, j;
 | 
						|
    int week,
 | 
						|
        rollover = 0;
 | 
						|
    double cl_corr, cl_drift;
 | 
						|
 | 
						|
    for (i = 0; i < 12; i++) {
 | 
						|
        if (sat[i].prn == 0) continue;
 | 
						|
        for (j = 1; j < 33; j++) {
 | 
						|
            if (alm[j].prn == sat[i].prn) break;
 | 
						|
        }
 | 
						|
        if (j == 33) {
 | 
						|
            // Sat not found
 | 
						|
            // fprintf(stderr, "[SEM: PRN %02d not found]\n", sat[i].prn);
 | 
						|
            sat[i].prn = 0;
 | 
						|
        }
 | 
						|
 | 
						|
            // Woche hat 604800 sec
 | 
						|
            if      (t-alm[j].toa >  WEEKSEC/2) rollover = +1;
 | 
						|
            else if (t-alm[j].toa < -WEEKSEC/2) rollover = -1;
 | 
						|
            else rollover = 0;
 | 
						|
            week = alm[j].week - rollover;
 | 
						|
            /*if (j == 1)*/ (rs_data->GPS).week = week + GPS_WEEK1024*1024;
 | 
						|
 | 
						|
            GPS_SatellitePositionVelocity_Ephem(
 | 
						|
                    week, t, alm[j],
 | 
						|
                    &cl_corr, &cl_drift, &X, &Y, &Z, &vX, &vY, &vZ
 | 
						|
            );
 | 
						|
 | 
						|
            sat[i].clock_drift = cl_drift;
 | 
						|
            sat[i].vX = vX;
 | 
						|
            sat[i].vY = vY;
 | 
						|
            sat[i].vZ = vZ;
 | 
						|
 | 
						|
            sat[i].X = X;
 | 
						|
            sat[i].Y = Y;
 | 
						|
            sat[i].Z = Z;
 | 
						|
            sat[i].clock_corr = cl_corr;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int gps_satpos_rnx(rs_data_t *rs_data, EPHEM_t *eph, double t, SAT_t *sat) {
 | 
						|
    double X, Y, Z, vX, vY, vZ;
 | 
						|
    int i;
 | 
						|
    int week,
 | 
						|
        rollover = 0;
 | 
						|
    double cl_corr, cl_drift;
 | 
						|
    double tdiff, td;
 | 
						|
    int count, count0, satfound;
 | 
						|
 | 
						|
    for (i = 0; i < 12; i++) {
 | 
						|
        if (sat[i].prn == 0) continue;
 | 
						|
 | 
						|
        count = count0 = 0;
 | 
						|
        satfound = 0;
 | 
						|
 | 
						|
        // Woche hat 604800 sec
 | 
						|
        tdiff = WEEKSEC;
 | 
						|
 | 
						|
        while (eph[count].prn > 0) {
 | 
						|
 | 
						|
            if (eph[count].prn == sat[i].prn) {
 | 
						|
 | 
						|
                satfound += 1;
 | 
						|
 | 
						|
                if      (t - eph[count].toe >  WEEKSEC/2) rollover = +1;
 | 
						|
                else if (t - eph[count].toe < -WEEKSEC/2) rollover = -1;
 | 
						|
                else rollover = 0;
 | 
						|
                td = fabs( t - eph[count].toe - rollover*WEEKSEC);
 | 
						|
 | 
						|
                if ( td < tdiff ) {
 | 
						|
                    tdiff = td;
 | 
						|
                    week = eph[count].week - rollover;
 | 
						|
                    (rs_data->GPS).week = eph[count].gpsweek - rollover;
 | 
						|
                    count0 = count;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            count += 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if ( satfound )
 | 
						|
        {
 | 
						|
            GPS_SatellitePositionVelocity_Ephem(
 | 
						|
                    week, t, eph[count0],
 | 
						|
                    &cl_corr, &cl_drift, &X, &Y, &Z, &vX, &vY, &vZ
 | 
						|
            );
 | 
						|
            sat[i].clock_drift = cl_drift;
 | 
						|
            sat[i].vX = vX;
 | 
						|
            sat[i].vY = vY;
 | 
						|
            sat[i].vZ = vZ;
 | 
						|
 | 
						|
            sat[i].X = X;
 | 
						|
            sat[i].Y = Y;
 | 
						|
            sat[i].Z = Z;
 | 
						|
            sat[i].clock_corr = cl_corr;
 | 
						|
            sat[i].ephtime = eph[count0].toe;
 | 
						|
        }
 | 
						|
        // test: rnx_data(PRN) expired (> 4 hrs)
 | 
						|
        else {
 | 
						|
            // Sat not found
 | 
						|
            // fprintf(stdout, "[RNX: PRN %02d not found]\n", sat[i].prn);
 | 
						|
            sat[i].prn = 0;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------------------------------------------------------------- */
 | 
						|
 | 
						|
//         - IS-GPS-200H  (bis C: ICD-GPS-200):
 | 
						|
//           http://www.gps.gov/technical/icwg/
 | 
						|
//         - Borre: http://kom.aau.dk/~borre
 | 
						|
//         - Essential GNSS Project (hier und da etwas unklar)
 | 
						|
 | 
						|
// -------------------------------------------------------------
 | 
						|
//
 | 
						|
// Satellite Position and Velocity
 | 
						|
//
 | 
						|
 | 
						|
static void GPS_SatelliteClockDriftCorrection(
 | 
						|
  const unsigned short transmission_gpsweek,   // GPS week when signal was transmit (0-1024+)            [weeks]
 | 
						|
  const double         transmission_gpstow,    // GPS time of week when signal was transmit              [s]
 | 
						|
  const unsigned short ephem_week,             // ephemeris: GPS week (0-1024+)                          [weeks]
 | 
						|
  const double         toe,                    // ephemeris: time of week                                [s]
 | 
						|
  const double         toc,                    // ephemeris: clock reference time of week                [s]
 | 
						|
  const double         af0,                    // ephemeris: polynomial clock correction coefficient     [s],
 | 
						|
  const double         af1,                    // ephemeris: polynomial clock correction coefficient     [s/s],
 | 
						|
  const double         af2,                    // ephemeris: polynomial clock correction coefficient     [s/s^2]
 | 
						|
  const double         ecc,                    // ephemeris: eccentricity of satellite orbit             []
 | 
						|
  const double         sqrta,                  // ephemeris: square root of the semi-major axis of orbit [m^(1/2)]
 | 
						|
  const double         delta_n,                // ephemeris: mean motion difference from computed value  [rad]
 | 
						|
  const double         m0,                     // ephemeris: mean anomaly at reference time              [rad]
 | 
						|
  const double         tgd,                    // ephemeris: group delay differential between L1 and L2  [s]
 | 
						|
  double*  clock_correction,                   // ephemeris: satellite clock correction                  [m]
 | 
						|
  double*  clock_drift )                       // ephemeris: satellite clock drift correction            [m/s]
 | 
						|
{
 | 
						|
    int j;
 | 
						|
 | 
						|
    double tot;    // time of transmission (including gps week) [s]
 | 
						|
    double tk;     // time from ephemeris reference epoch       [s]
 | 
						|
    double tc;     // time from clock reference epoch           [s]
 | 
						|
    double d_tr;   // relativistic correction term              [s]
 | 
						|
    double d_tsv;  // SV PRN code phase time offset             [s]
 | 
						|
    double a;      // semi-major axis of orbit                  [m]
 | 
						|
    double n;      // corrected mean motion                     [rad/s]
 | 
						|
    double M;      // mean anomaly,                             [rad]
 | 
						|
    double E;      // eccentric anomaly                         [rad]
 | 
						|
 | 
						|
    // compute the times from the reference epochs
 | 
						|
    tot = transmission_gpsweek*SECONDS_IN_WEEK + transmission_gpstow;
 | 
						|
    tk  = tot - (ephem_week*SECONDS_IN_WEEK + toe);
 | 
						|
    tc  = tot - (ephem_week*SECONDS_IN_WEEK + toc);
 | 
						|
 | 
						|
    // compute the corrected mean motion term
 | 
						|
    a = sqrta*sqrta;
 | 
						|
    n = sqrt( GRAVITY_CONSTANT / (a*a*a) ); //  mean motion
 | 
						|
    n += delta_n; // corrected mean motion
 | 
						|
 | 
						|
    // Kepler-Gleichung  M = E - e sin(E)
 | 
						|
    M = m0 + n*tk; // mean anomaly
 | 
						|
    E = M;                         // f(E) = M + e sin(E)  hat Fixpunkt fuer e < 1,
 | 
						|
    for( j = 0; j < 7; j++ ) {     // da |f'(E)|=|e cos(E)|<1.
 | 
						|
        E = M + ecc * sin(E);      // waehle Startwert E_1 = M, E_{k+1} = f(E_k)
 | 
						|
    }                              // konvergiert langsam gegen E_0 = f(E_0)
 | 
						|
 | 
						|
    // relativistic correction
 | 
						|
    d_tr = RELATIVISTIC_CLOCK_CORRECTION * ecc * sqrta * sin(E); // [s]
 | 
						|
    d_tr *= LIGHTSPEED;
 | 
						|
 | 
						|
    // clock correction
 | 
						|
    d_tsv = af0 + af1*tc + af2*tc*tc; // [s]
 | 
						|
 | 
						|
    // L1 only
 | 
						|
    d_tsv -= tgd; // [s]
 | 
						|
 | 
						|
    // clock correction
 | 
						|
    *clock_correction = d_tsv*LIGHTSPEED + d_tr; // [m]
 | 
						|
 | 
						|
    // clock drift
 | 
						|
    *clock_drift = (af1 + 2.0*af2*tc) * LIGHTSPEED; // [m/s]
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void GPS_ComputeSatellitePositionVelocity(
 | 
						|
  const unsigned short transmission_gpsweek,  // GPS week when signal was transmit (0-1024+)                            [weeks]
 | 
						|
  const double         transmission_gpstow,   // GPS time of week when signal was transmit                              [s]
 | 
						|
  const unsigned short ephem_week,            // ephemeris: GPS week (0-1024+)                                          [weeks]
 | 
						|
  const double         toe,                   // ephemeris: time of week                                                [s]
 | 
						|
  const double         m0,                    // ephemeris: mean anomaly at reference time                              [rad]
 | 
						|
  const double         delta_n,               // ephemeris: mean motion difference from computed value                  [rad]
 | 
						|
  const double         ecc,                   // ephemeris: eccentricity                                                []
 | 
						|
  const double         sqrta,                 // ephemeris: square root of the semi-major axis                          [m^(1/2)]
 | 
						|
  const double         omega0,                // ephemeris: longitude of ascending node of orbit plane at weekly epoch  [rad]
 | 
						|
  const double         i0,                    // ephemeris: inclination angle at reference time                         [rad]
 | 
						|
  const double         w,                     // ephemeris: argument of perigee                                         [rad]
 | 
						|
  const double         omegadot,              // ephemeris: rate of right ascension                                     [rad/s]
 | 
						|
  const double         idot,                  // ephemeris: rate of inclination angle                                   [rad/s]
 | 
						|
  const double         cuc,                   // ephemeris: cos harmonic correction term to the argument of latitude    [rad]
 | 
						|
  const double         cus,                   // ephemeris: sin harmonic correction term to the argument of latitude    [rad]
 | 
						|
  const double         crc,                   // ephemeris: cos harmonic correction term to the orbit radius            [m]
 | 
						|
  const double         crs,                   // ephemeris: sin harmonic correction term to the orbit radius            [m]
 | 
						|
  const double         cic,                   // ephemeris: cos harmonic correction term to the angle of inclination    [rad]
 | 
						|
  const double         cis,                   // ephemeris: sin harmonic correction term to the angle of inclination    [rad]
 | 
						|
  double* x,                                  // satellite x            [m]
 | 
						|
  double* y,                                  // satellite y            [m]
 | 
						|
  double* z,                                  // satellite z            [m]
 | 
						|
  double* vx,                                 // satellite velocity x   [m/s]
 | 
						|
  double* vy,                                 // satellite velocity y   [m/s]
 | 
						|
  double* vz )                                // satellite velocity z   [m/s]
 | 
						|
{
 | 
						|
    int j;
 | 
						|
 | 
						|
    double tot;        // time of transmission (including gps week) [s]
 | 
						|
    double tk;         // time from ephemeris reference epoch       [s]
 | 
						|
    double a;          // semi-major axis of orbit                  [m]
 | 
						|
    double n;          // corrected mean motion                     [rad/s]
 | 
						|
    double M;          // mean anomaly,                             [rad]
 | 
						|
    double E;          // eccentric anomaly                         [rad]
 | 
						|
    double v;          // true anomaly                              [rad]
 | 
						|
    double u;          // argument of latitude, corrected           [rad]
 | 
						|
    double r;          // radius in the orbital plane               [m]
 | 
						|
    double i;          // orbital inclination                       [rad]
 | 
						|
    double cos2u;      // cos(2*u)                                  []
 | 
						|
    double sin2u;      // sin(2*u)                                  []
 | 
						|
    double d_u;        // argument of latitude correction           [rad]
 | 
						|
    double d_r;        // radius correction                         [m]
 | 
						|
    double d_i;        // inclination correction                    [rad]
 | 
						|
    double x_op;       // x position in the orbital plane           [m]
 | 
						|
    double y_op;       // y position in the orbital plane           [m]
 | 
						|
    double omegak;     // corrected longitude of the ascending node [rad]
 | 
						|
    double cos_omegak; // cos(omegak)
 | 
						|
    double sin_omegak; // sin(omegak)
 | 
						|
    double cosu;       // cos(u)
 | 
						|
    double sinu;       // sin(u)
 | 
						|
    double cosi;       // cos(i)
 | 
						|
    double sini;       // sin(i)
 | 
						|
    double cosE;       // cos(E)
 | 
						|
    double sinE;       // sin(E)
 | 
						|
 | 
						|
 | 
						|
    // compute the times from the reference epochs
 | 
						|
    tot = transmission_gpsweek*SECONDS_IN_WEEK + transmission_gpstow;
 | 
						|
    tk  = tot - (ephem_week*SECONDS_IN_WEEK + toe);
 | 
						|
 | 
						|
    // compute the corrected mean motion term
 | 
						|
    a = sqrta*sqrta;
 | 
						|
    n = sqrt( GRAVITY_CONSTANT / (a*a*a) ); // computed mean motion
 | 
						|
    n += delta_n; // corrected mean motion
 | 
						|
 | 
						|
    // Kepler-Gleichung  M = E - e sin(E)
 | 
						|
    M = m0 + n*tk; // mean anomaly
 | 
						|
    E = M;                         // f(E) = M + e sin(E)  hat Fixpunkt fuer e < 1,
 | 
						|
    for( j = 0; j < 7; j++ ) {     // da |f'(E)|=|e cos(E)|<1.
 | 
						|
        E = M + ecc * sin(E);      // waehle Startwert E_1 = M, E_{k+1} = f(E_k)
 | 
						|
    }                              // konvergiert langsam gegen E_0 = f(E_0)
 | 
						|
 | 
						|
    cosE = cos(E);
 | 
						|
    sinE = sin(E);
 | 
						|
 | 
						|
    // true anomaly
 | 
						|
    v = atan2( (sqrt(1.0 - ecc*ecc)*sinE),  (cosE - ecc) );
 | 
						|
    // argument of latitude
 | 
						|
    u = v + w;
 | 
						|
    // radius in orbital plane
 | 
						|
    r = a * (1.0 - ecc * cos(E));
 | 
						|
    // orbital inclination
 | 
						|
    i = i0;
 | 
						|
 | 
						|
    // second harmonic perturbations
 | 
						|
    //
 | 
						|
    cos2u = cos(2.0*u);
 | 
						|
    sin2u = sin(2.0*u);
 | 
						|
    // argument of latitude correction
 | 
						|
    d_u = cuc * cos2u  +  cus * sin2u;
 | 
						|
    // radius correction
 | 
						|
    d_r = crc * cos2u  +  crs * sin2u;
 | 
						|
    // correction to inclination
 | 
						|
    d_i = cic * cos2u  +  cis * sin2u;
 | 
						|
 | 
						|
    // corrected argument of latitude
 | 
						|
    u += d_u;
 | 
						|
    // corrected radius
 | 
						|
    r += d_r;
 | 
						|
    // corrected inclination
 | 
						|
    i += d_i + idot * tk;
 | 
						|
 | 
						|
    // positions in orbital plane
 | 
						|
    cosu = cos(u);
 | 
						|
    sinu = sin(u);
 | 
						|
    x_op = r * cosu;
 | 
						|
    y_op = r * sinu;
 | 
						|
 | 
						|
 | 
						|
    omegak = omega0 + omegadot*tk - EARTH_ROTATION_RATE*(tk + toe);
 | 
						|
    // fuer Bestimmung der Satellitenposition in ECEF, range=0;
 | 
						|
    // fuer GPS-Loesung (Sats in ECI) Erdrotation hinzuziehen:
 | 
						|
    // rotZ(EARTH_ROTATION_RATE*0.072), 0.072s*299792458m/s=21585057m
 | 
						|
 | 
						|
    // compute the WGS84 ECEF coordinates,
 | 
						|
    // vector r with components x & y is now rotated using, R3(-omegak)*R1(-i)
 | 
						|
    cos_omegak = cos(omegak);
 | 
						|
    sin_omegak = sin(omegak);
 | 
						|
    cosi = cos(i);
 | 
						|
    sini = sin(i);
 | 
						|
 | 
						|
    *x = x_op * cos_omegak - y_op * sin_omegak * cosi;
 | 
						|
    *y = x_op * sin_omegak + y_op * cos_omegak * cosi;
 | 
						|
    *z = y_op * sini;
 | 
						|
 | 
						|
 | 
						|
  // Satellite Velocity Computations are below
 | 
						|
  // see Reference
 | 
						|
  // Remodi, B. M (2004). GPS Tool Box: Computing satellite velocities using the broadcast ephemeris.
 | 
						|
  // GPS Solutions. Volume 8(3), 2004. pp. 181-183
 | 
						|
  //
 | 
						|
  // example source code was available at [http://www.ngs.noaa.gov/gps-toolbox/bc_velo/bc_velo.c]
 | 
						|
 | 
						|
  // recomputed the cos and sin of the corrected argument of latitude
 | 
						|
 | 
						|
  double omegadotk;  // corrected rate of right ascension         [rad/s]
 | 
						|
  double edot;       // edot = n/(1.0 - ecc*cos(E)),              [rad/s]
 | 
						|
  double vdot;       // d/dt of true anomaly                      [rad/s]
 | 
						|
  double udot;       // d/dt of argument of latitude              [rad/s]
 | 
						|
  double idotdot;    // d/dt of the rate of the inclination angle [rad/s^2]
 | 
						|
  double rdot;       // d/dt of the radius in the orbital plane   [m/s]
 | 
						|
  double tmpa;       // temp
 | 
						|
  double tmpb;       // temp
 | 
						|
  double vx_op;      // x velocity in the orbital plane           [m/s]
 | 
						|
  double vy_op;      // y velocity in the orbital plane           [m/s]
 | 
						|
 | 
						|
  cos2u = cos(2.0*u);
 | 
						|
  sin2u = sin(2.0*u);
 | 
						|
 | 
						|
  edot  = n / (1.0 - ecc*cosE);
 | 
						|
  vdot  = sinE*edot*(1.0 + ecc*cos(v)) / ( sin(v)*(1.0-ecc*cosE) );
 | 
						|
  udot  = vdot + 2.0*(cus*cos2u - cuc*sin2u)*vdot;
 | 
						|
  rdot  = a*ecc*sinE*n/(1.0-ecc*cosE) + 2.0*(crs*cos2u - crc*sin2u)*vdot;
 | 
						|
  idotdot = idot + (cis*cos2u - cic*sin2u)*2.0*vdot;
 | 
						|
 | 
						|
  vx_op = rdot*cosu - y_op*udot;
 | 
						|
  vy_op = rdot*sinu + x_op*udot;
 | 
						|
 | 
						|
                                               // corrected rate of right ascension including similarily as above,
 | 
						|
                                               //  for omegak, compensation for the Sagnac effect
 | 
						|
  omegadotk =  omegadot - EARTH_ROTATION_RATE  /* - EARTH_ROTATION_RATE*RANGERATE_ESTIMATE/LIGHTSPEED */ ;
 | 
						|
 | 
						|
  tmpa = vx_op - y_op*cosi*omegadotk;
 | 
						|
  tmpb = x_op*omegadotk + vy_op*cosi - y_op*sini*idotdot;
 | 
						|
 | 
						|
  *vx = tmpa * cos_omegak - tmpb * sin_omegak;
 | 
						|
  *vy = tmpa * sin_omegak + tmpb * cos_omegak;
 | 
						|
  *vz = vy_op*sini + y_op*cosi*idotdot;
 | 
						|
}
 | 
						|
 | 
						|
static void GPS_SatellitePositionVelocity_Ephem(
 | 
						|
  const unsigned short gpsweek,      // gps week of signal transmission (0-1024+)            [week]
 | 
						|
  const double         gpstow,       // time of week of signal transmission  (gpstow-psr/c)  [s]
 | 
						|
  EPHEM_t ephem,
 | 
						|
  double* clock_correction,   // clock correction for this satellite for this epoch           [m]
 | 
						|
  double* clock_drift,        // clock correction for this satellite for this epoch           [m]
 | 
						|
  double* satX,               // satellite X position WGS84 ECEF                              [m]
 | 
						|
  double* satY,               // satellite Y position WGS84 ECEF                              [m]
 | 
						|
  double* satZ,               // satellite Z position WGS84 ECEF                              [m]
 | 
						|
  double* satvX,              // satellite X velocity WGS84 ECEF                              [m]
 | 
						|
  double* satvY,              // satellite Y velocity WGS84 ECEF                              [m]
 | 
						|
  double* satvZ               // satellite Z velocity WGS84 ECEF                              [m]
 | 
						|
  )
 | 
						|
{
 | 
						|
    double tow;               // user time of week adjusted with the clock corrections [s]
 | 
						|
    double x;                 // sat X position [m]
 | 
						|
    double y;                 // sat Y position [m]
 | 
						|
    double z;                 // sat Z position [m]
 | 
						|
    double vx;                // sat vX velocity [m]
 | 
						|
    double vy;                // sat VY velocity [m]
 | 
						|
    double vz;                // sat VZ velocity [m]
 | 
						|
    unsigned short week;      // user week adjusted with the clock correction if needed [week]
 | 
						|
 | 
						|
 | 
						|
    x = y = z = 0.0;
 | 
						|
 | 
						|
    GPS_SatelliteClockDriftCorrection( gpsweek, gpstow,
 | 
						|
        ephem.week, ephem.toe, ephem.toc, ephem.af0,
 | 
						|
        ephem.af1, ephem.af2, ephem.e, ephem.sqrta,
 | 
						|
        ephem.delta_n, ephem.M0, ephem.tgd, clock_correction, clock_drift );
 | 
						|
 | 
						|
 | 
						|
    // adjust for week rollover
 | 
						|
    week = gpsweek;
 | 
						|
    tow = gpstow + (*clock_correction)/LIGHTSPEED;
 | 
						|
    if ( tow < 0.0 ) {
 | 
						|
        tow += SECONDS_IN_WEEK;
 | 
						|
        week--;
 | 
						|
    }
 | 
						|
    if ( tow > SECONDS_IN_WEEK ) {
 | 
						|
        tow -= SECONDS_IN_WEEK;
 | 
						|
        week++;
 | 
						|
    }
 | 
						|
 | 
						|
    //range = 0.072s*299792458m/s=21585057m
 | 
						|
    GPS_ComputeSatellitePositionVelocity( week, tow,
 | 
						|
        ephem.week, ephem.toe, ephem.M0, ephem.delta_n, ephem.e, ephem.sqrta,
 | 
						|
        ephem.Omega0, ephem.i0, ephem.w, ephem.OmegaDot, ephem.idot,
 | 
						|
        ephem.cuc, ephem.cus, ephem.crc, ephem.crs, ephem.cic, ephem.cis,
 | 
						|
        &x, &y, &z, &vx, &vy, &vz );
 | 
						|
 | 
						|
    *satX = x;
 | 
						|
    *satY = y;
 | 
						|
    *satZ = z;
 | 
						|
    *satvX = vx;
 | 
						|
    *satvY = vy;
 | 
						|
    *satvZ = vz;
 | 
						|
 | 
						|
}
 | 
						|
 |