2017-04-20 14:10:12 +00:00
|
|
|
/*!
|
|
|
|
* \file rtklib_ephemeris.cc
|
|
|
|
* \brief satellite ephemeris and clock functions
|
|
|
|
* \authors <ul>
|
|
|
|
* <li> 2007-2013, T. Takasu
|
|
|
|
* <li> 2017, Javier Arribas
|
|
|
|
* <li> 2017, Carles Fernandez
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
* This is a derived work from RTKLIB http://www.rtklib.com/
|
|
|
|
* The original source code at https://github.com/tomojitakasu/RTKLIB is
|
|
|
|
* released under the BSD 2-clause license with an additional exclusive clause
|
|
|
|
* that does not apply here. This additional clause is reproduced below:
|
|
|
|
*
|
|
|
|
* " The software package includes some companion executive binaries or shared
|
|
|
|
* libraries necessary to execute APs on Windows. These licenses succeed to the
|
|
|
|
* original ones of these software. "
|
|
|
|
*
|
|
|
|
* Neither the executive binaries nor the shared libraries are required by, used
|
|
|
|
* or included in GNSS-SDR.
|
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
* Copyright (C) 2007-2013, T. Takasu
|
|
|
|
* Copyright (C) 2017, Javier Arribas
|
|
|
|
* Copyright (C) 2017, Carles Fernandez
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are
|
|
|
|
* met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2017-04-21 09:34:23 +00:00
|
|
|
*
|
2017-04-23 19:10:32 +00:00
|
|
|
*----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
|
|
|
|
#include "rtklib_ephemeris.h"
|
2018-12-09 21:00:09 +00:00
|
|
|
#include "rtklib_preceph.h"
|
2017-04-24 22:48:13 +00:00
|
|
|
#include "rtklib_rtkcmn.h"
|
|
|
|
#include "rtklib_sbas.h"
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2017-04-21 09:34:23 +00:00
|
|
|
/* constants ------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
const double RE_GLO = 6378136.0; /* radius of earth (m) ref [2] */
|
|
|
|
const double MU_GPS = 3.9860050e14; /* gravitational constant ref [1] */
|
|
|
|
const double MU_GLO = 3.9860044e14; /* gravitational constant ref [2] */
|
|
|
|
const double MU_GAL = 3.986004418e14; /* earth gravitational constant ref [7] */
|
|
|
|
const double MU_BDS = 3.986004418e14; /* earth gravitational constant ref [9] */
|
|
|
|
const double J2_GLO = 1.0826257e-3; /* 2nd zonal harmonic of geopot ref [2] */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
const double OMGE_GLO = 7.292115e-5; /* earth angular velocity (rad/s) ref [2] */
|
|
|
|
const double OMGE_GAL = 7.2921151467e-5; /* earth angular velocity (rad/s) ref [7] */
|
|
|
|
const double OMGE_BDS = 7.292115e-5; /* earth angular velocity (rad/s) ref [9] */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2017-04-21 09:34:23 +00:00
|
|
|
const double SIN_5 = -0.0871557427476582; /* sin(-5.0 deg) */
|
2018-03-03 01:03:39 +00:00
|
|
|
const double COS_5 = 0.9961946980917456; /* cos(-5.0 deg) */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
const double ERREPH_GLO = 5.0; /* error of glonass ephemeris (m) */
|
|
|
|
const double TSTEP = 60.0; /* integration step glonass ephemeris (s) */
|
|
|
|
const double RTOL_KEPLER = 1e-13; /* relative tolerance for Kepler equation */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2019-07-20 10:55:46 +00:00
|
|
|
const double DEFURASSR = 0.15; /* default accuracy of ssr corr (m) */
|
2018-03-03 01:03:39 +00:00
|
|
|
const double MAXECORSSR = 10.0; /* max orbit correction of ssr (m) */
|
|
|
|
const double MAXCCORSSR = 1e-6 * SPEED_OF_LIGHT; /* max clock correction of ssr (m) */
|
|
|
|
const double MAXAGESSR = 90.0; /* max age of ssr orbit and clock (s) */
|
|
|
|
const double MAXAGESSR_HRCLK = 10.0; /* max age of ssr high-rate clock (s) */
|
|
|
|
const double STD_BRDCCLK = 30.0; /* error of broadcast clock (m) */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
const int MAX_ITER_KEPLER = 30; /* max number of iteration of Kelpler */
|
2017-04-20 14:10:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* variance by ura ephemeris (ref [1] 20.3.3.3.1.1) --------------------------*/
|
|
|
|
double var_uraeph(int ura)
|
|
|
|
{
|
2017-04-21 09:34:23 +00:00
|
|
|
const double ura_value[] = {
|
2018-03-03 01:03:39 +00:00
|
|
|
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,
|
|
|
|
3072.0, 6144.0};
|
2017-06-06 16:27:54 +00:00
|
|
|
return ura < 0 || 14 < ura ? std::pow(6144.0, 2.0) : std::pow(ura_value[ura], 2.0);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* variance by ura ssr (ref [4]) ---------------------------------------------*/
|
|
|
|
double var_urassr(int ura)
|
|
|
|
{
|
2017-04-21 14:14:46 +00:00
|
|
|
double std_;
|
2019-02-11 20:13:02 +00:00
|
|
|
if (ura <= 0)
|
|
|
|
{
|
|
|
|
return std::pow(DEFURASSR, 2.0);
|
|
|
|
}
|
|
|
|
if (ura >= 63)
|
|
|
|
{
|
|
|
|
return std::pow(5.4665, 2.0);
|
|
|
|
}
|
2017-04-22 10:50:04 +00:00
|
|
|
std_ = (std::pow((ura >> 3) & 7, 2.0) * (1.0 + (ura & 7) / 4.0) - 1.0) * 1e-3;
|
|
|
|
return std::pow(std_, 2.0);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* almanac to satellite position and clock bias --------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite position and clock bias with almanac (gps, galileo, qzss)
|
|
|
|
* args : gtime_t time I time (gpst)
|
|
|
|
* alm_t *alm I almanac
|
|
|
|
* double *rs O satellite position (ecef) {x,y,z} (m)
|
|
|
|
* double *dts O satellite clock bias (s)
|
|
|
|
* return : none
|
|
|
|
* notes : see ref [1],[7],[8]
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
void alm2pos(gtime_t time, const alm_t *alm, double *rs, double *dts)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double tk;
|
|
|
|
double M;
|
|
|
|
double E;
|
|
|
|
double Ek;
|
|
|
|
double sinE;
|
|
|
|
double cosE;
|
|
|
|
double u;
|
|
|
|
double r;
|
|
|
|
double i;
|
|
|
|
double O;
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double sinO;
|
|
|
|
double cosO;
|
|
|
|
double cosi;
|
|
|
|
double mu;
|
2017-04-20 14:10:12 +00:00
|
|
|
int n;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "alm2pos : time=%s sat=%2d\n", time_str(time, 3), alm->sat);
|
|
|
|
|
2019-05-08 12:55:14 +00:00
|
|
|
tk = timediffweekcrossover(time, alm->toa);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
if (alm->A <= 0.0)
|
|
|
|
{
|
|
|
|
rs[0] = rs[1] = rs[2] = *dts = 0.0;
|
|
|
|
return;
|
|
|
|
}
|
2018-12-03 09:05:47 +00:00
|
|
|
mu = satsys(alm->sat, nullptr) == SYS_GAL ? MU_GAL : MU_GPS;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
M = alm->M0 + sqrt(mu / (alm->A * alm->A * alm->A)) * tk;
|
|
|
|
for (n = 0, E = M, Ek = 0.0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++)
|
|
|
|
{
|
|
|
|
Ek = E;
|
2017-04-21 14:14:46 +00:00
|
|
|
E -= (E - alm->e * sin(E) - M) / (1.0 - alm->e * cos(E));
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
if (n >= MAX_ITER_KEPLER)
|
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
trace(2, "alm2pos: kepler iteration overflow sat=%2d\n", alm->sat);
|
2017-04-21 09:34:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
sinE = sin(E);
|
|
|
|
cosE = cos(E);
|
|
|
|
u = atan2(sqrt(1.0 - alm->e * alm->e) * sinE, cosE - alm->e) + alm->omg;
|
2018-03-03 01:03:39 +00:00
|
|
|
r = alm->A * (1.0 - alm->e * cosE);
|
2017-04-21 09:34:23 +00:00
|
|
|
i = alm->i0;
|
|
|
|
O = alm->OMG0 + (alm->OMGd - DEFAULT_OMEGA_EARTH_DOT) * tk - DEFAULT_OMEGA_EARTH_DOT * alm->toas;
|
|
|
|
x = r * cos(u);
|
|
|
|
y = r * sin(u);
|
|
|
|
sinO = sin(O);
|
|
|
|
cosO = cos(O);
|
|
|
|
cosi = cos(i);
|
|
|
|
rs[0] = x * cosO - y * cosi * sinO;
|
|
|
|
rs[1] = x * sinO + y * cosi * cosO;
|
|
|
|
rs[2] = y * sin(i);
|
|
|
|
*dts = alm->f0 + alm->f1 * tk;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* broadcast ephemeris to satellite clock bias ---------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite clock bias with broadcast ephemeris (gps, galileo, qzss)
|
|
|
|
* args : gtime_t time I time by satellite clock (gpst)
|
|
|
|
* eph_t *eph I broadcast ephemeris
|
|
|
|
* return : satellite clock bias (s) without relativeity correction
|
|
|
|
* notes : see ref [1],[7],[8]
|
|
|
|
* satellite clock does not include relativity correction and tdg
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
double eph2clk(gtime_t time, const eph_t *eph)
|
|
|
|
{
|
|
|
|
double t;
|
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "eph2clk : time=%s sat=%2d\n", time_str(time, 3), eph->sat);
|
|
|
|
|
2019-05-08 12:55:14 +00:00
|
|
|
t = timediffweekcrossover(time, eph->toc);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
t -= eph->f0 + eph->f1 * t + eph->f2 * t * t;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
return eph->f0 + eph->f1 * t + eph->f2 * t * t;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* broadcast ephemeris to satellite position and clock bias --------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite position and clock bias with broadcast ephemeris (gps,
|
|
|
|
* galileo, qzss)
|
|
|
|
* args : gtime_t time I time (gpst)
|
|
|
|
* eph_t *eph I broadcast ephemeris
|
|
|
|
* double *rs O satellite position (ecef) {x,y,z} (m)
|
|
|
|
* double *dts O satellite clock bias (s)
|
|
|
|
* double *var O satellite position and clock variance (m^2)
|
|
|
|
* return : none
|
|
|
|
* notes : see ref [1],[7],[8]
|
|
|
|
* satellite clock includes relativity correction without code bias
|
|
|
|
* (tgd or bgd)
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts,
|
2018-03-03 01:03:39 +00:00
|
|
|
double *var)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double tk;
|
|
|
|
double M;
|
|
|
|
double E;
|
|
|
|
double Ek;
|
|
|
|
double sinE;
|
|
|
|
double cosE;
|
|
|
|
double u;
|
|
|
|
double r;
|
|
|
|
double i;
|
|
|
|
double O;
|
|
|
|
double sin2u;
|
|
|
|
double cos2u;
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double sinO;
|
|
|
|
double cosO;
|
|
|
|
double cosi;
|
|
|
|
double mu;
|
|
|
|
double omge;
|
|
|
|
double xg;
|
|
|
|
double yg;
|
|
|
|
double zg;
|
|
|
|
double sino;
|
|
|
|
double coso;
|
|
|
|
int n;
|
|
|
|
int sys;
|
|
|
|
int prn;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "eph2pos : time=%s sat=%2d\n", time_str(time, 3), eph->sat);
|
|
|
|
|
|
|
|
if (eph->A <= 0.0)
|
|
|
|
{
|
|
|
|
rs[0] = rs[1] = rs[2] = *dts = *var = 0.0;
|
|
|
|
return;
|
|
|
|
}
|
2019-05-08 12:55:14 +00:00
|
|
|
tk = timediffweekcrossover(time, eph->toe);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
switch ((sys = satsys(eph->sat, &prn)))
|
2018-03-03 01:03:39 +00:00
|
|
|
{
|
|
|
|
case SYS_GAL:
|
|
|
|
mu = MU_GAL;
|
|
|
|
omge = OMGE_GAL;
|
|
|
|
break;
|
|
|
|
case SYS_BDS:
|
|
|
|
mu = MU_BDS;
|
|
|
|
omge = OMGE_BDS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mu = MU_GPS;
|
|
|
|
omge = DEFAULT_OMEGA_EARTH_DOT;
|
|
|
|
break;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
M = eph->M0 + (sqrt(mu / (eph->A * eph->A * eph->A)) + eph->deln) * tk;
|
|
|
|
|
|
|
|
for (n = 0, E = M, Ek = 0.0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++)
|
|
|
|
{
|
|
|
|
Ek = E;
|
|
|
|
E -= (E - eph->e * sin(E) - M) / (1.0 - eph->e * cos(E));
|
|
|
|
}
|
|
|
|
if (n >= MAX_ITER_KEPLER)
|
|
|
|
{
|
|
|
|
trace(2, "eph2pos: kepler iteration overflow sat=%2d\n", eph->sat);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sinE = sin(E);
|
|
|
|
cosE = cos(E);
|
|
|
|
|
|
|
|
trace(4, "kepler: sat=%2d e=%8.5f n=%2d del=%10.3e\n", eph->sat, eph->e, n, E - Ek);
|
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
u = atan2(sqrt(1.0 - eph->e * eph->e) * sinE, cosE - eph->e) + eph->omg;
|
2017-04-21 09:34:23 +00:00
|
|
|
r = eph->A * (1.0 - eph->e * cosE);
|
|
|
|
i = eph->i0 + eph->idot * tk;
|
2018-03-03 01:03:39 +00:00
|
|
|
sin2u = sin(2.0 * u);
|
|
|
|
cos2u = cos(2.0 * u);
|
2017-04-21 09:34:23 +00:00
|
|
|
u += eph->cus * sin2u + eph->cuc * cos2u;
|
|
|
|
r += eph->crs * sin2u + eph->crc * cos2u;
|
|
|
|
i += eph->cis * sin2u + eph->cic * cos2u;
|
|
|
|
x = r * cos(u);
|
|
|
|
y = r * sin(u);
|
|
|
|
cosi = cos(i);
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* beidou geo satellite (ref [9]) */
|
2017-04-21 09:34:23 +00:00
|
|
|
if (sys == SYS_BDS && prn <= 5)
|
|
|
|
{
|
|
|
|
O = eph->OMG0 + eph->OMGd * tk - omge * eph->toes;
|
|
|
|
sinO = sin(O);
|
|
|
|
cosO = cos(O);
|
|
|
|
xg = x * cosO - y * cosi * sinO;
|
|
|
|
yg = x * sinO + y * cosi * cosO;
|
|
|
|
zg = y * sin(i);
|
|
|
|
sino = sin(omge * tk);
|
|
|
|
coso = cos(omge * tk);
|
2018-03-03 01:03:39 +00:00
|
|
|
rs[0] = xg * coso + yg * sino * COS_5 + zg * sino * SIN_5;
|
2017-04-21 09:34:23 +00:00
|
|
|
rs[1] = -xg * sino + yg * coso * COS_5 + zg * coso * SIN_5;
|
|
|
|
rs[2] = -yg * SIN_5 + zg * COS_5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
O = eph->OMG0 + (eph->OMGd - omge) * tk - omge * eph->toes;
|
|
|
|
sinO = sin(O);
|
|
|
|
cosO = cos(O);
|
|
|
|
rs[0] = x * cosO - y * cosi * sinO;
|
2018-03-03 01:03:39 +00:00
|
|
|
rs[1] = x * sinO + y * cosi * cosO;
|
2017-04-21 09:34:23 +00:00
|
|
|
rs[2] = y * sin(i);
|
|
|
|
}
|
2019-05-08 12:55:14 +00:00
|
|
|
tk = timediffweekcrossover(time, eph->toc);
|
2017-04-21 09:34:23 +00:00
|
|
|
*dts = eph->f0 + eph->f1 * tk + eph->f2 * tk * tk;
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* relativity correction */
|
2018-03-03 01:03:39 +00:00
|
|
|
*dts -= 2.0 * sqrt(mu * eph->A) * eph->e * sinE / std::pow(SPEED_OF_LIGHT, 2.0);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* position and clock error variance */
|
2017-04-21 09:34:23 +00:00
|
|
|
*var = var_uraeph(eph->sva);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* glonass orbit differential equations --------------------------------------*/
|
|
|
|
void deq(const double *x, double *xdot, const double *acc)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double a;
|
|
|
|
double b;
|
|
|
|
double c;
|
|
|
|
double r2 = dot(x, x, 3);
|
|
|
|
double r3 = r2 * sqrt(r2);
|
|
|
|
double omg2 = std::pow(OMGE_GLO, 2.0);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
if (r2 <= 0.0)
|
|
|
|
{
|
|
|
|
xdot[0] = xdot[1] = xdot[2] = xdot[3] = xdot[4] = xdot[5] = 0.0;
|
|
|
|
return;
|
|
|
|
}
|
2017-04-20 14:10:12 +00:00
|
|
|
/* ref [2] A.3.1.2 with bug fix for xdot[4],xdot[5] */
|
2017-04-22 10:50:04 +00:00
|
|
|
a = 1.5 * J2_GLO * MU_GLO * std::pow(RE_GLO, 2.0) / r2 / r3; /* 3/2*J2*mu*Ae^2/r^5 */
|
2018-03-03 01:03:39 +00:00
|
|
|
b = 5.0 * x[2] * x[2] / r2; /* 5*z^2/r^2 */
|
|
|
|
c = -MU_GLO / r3 - a * (1.0 - b); /* -mu/r^3-a(1-b) */
|
2017-04-21 09:34:23 +00:00
|
|
|
xdot[0] = x[3];
|
2018-03-03 01:03:39 +00:00
|
|
|
xdot[1] = x[4];
|
|
|
|
xdot[2] = x[5];
|
2017-04-21 09:34:23 +00:00
|
|
|
xdot[3] = (c + omg2) * x[0] + 2.0 * OMGE_GLO * x[4] + acc[0];
|
|
|
|
xdot[4] = (c + omg2) * x[1] - 2.0 * OMGE_GLO * x[3] + acc[1];
|
|
|
|
xdot[5] = (c - 2.0 * a) * x[2] + acc[2];
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* glonass position and velocity by numerical integration --------------------*/
|
|
|
|
void glorbit(double t, double *x, const double *acc)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double k1[6];
|
|
|
|
double k2[6];
|
|
|
|
double k3[6];
|
|
|
|
double k4[6];
|
|
|
|
double w[6];
|
2017-04-20 14:10:12 +00:00
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2018-03-03 01:03:39 +00:00
|
|
|
deq(x, k1, acc);
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
w[i] = x[i] + k1[i] * t / 2.0;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
deq(w, k2, acc);
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
w[i] = x[i] + k2[i] * t / 2.0;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
deq(w, k3, acc);
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
w[i] = x[i] + k3[i] * t;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
deq(w, k4, acc);
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
x[i] += (k1[i] + 2.0 * k2[i] + 2.0 * k3[i] + k4[i]) * t / 6.0;
|
|
|
|
}
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* glonass ephemeris to satellite clock bias -----------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite clock bias with glonass ephemeris
|
|
|
|
* args : gtime_t time I time by satellite clock (gpst)
|
|
|
|
* geph_t *geph I glonass ephemeris
|
|
|
|
* return : satellite clock bias (s)
|
|
|
|
* notes : see ref [2]
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
double geph2clk(gtime_t time, const geph_t *geph)
|
|
|
|
{
|
|
|
|
double t;
|
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "geph2clk: time=%s sat=%2d\n", time_str(time, 3), geph->sat);
|
|
|
|
|
|
|
|
t = timediff(time, geph->toe);
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2017-04-21 14:14:46 +00:00
|
|
|
t -= -geph->taun + geph->gamn * t;
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
2017-04-21 14:14:46 +00:00
|
|
|
return -geph->taun + geph->gamn * t;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* glonass ephemeris to satellite position and clock bias ----------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite position and clock bias with glonass ephemeris
|
|
|
|
* args : gtime_t time I time (gpst)
|
|
|
|
* geph_t *geph I glonass ephemeris
|
|
|
|
* double *rs O satellite position {x,y,z} (ecef) (m)
|
|
|
|
* double *dts O satellite clock bias (s)
|
|
|
|
* double *var O satellite position and clock variance (m^2)
|
|
|
|
* return : none
|
|
|
|
* notes : see ref [2]
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
void geph2pos(gtime_t time, const geph_t *geph, double *rs, double *dts,
|
2018-03-03 01:03:39 +00:00
|
|
|
double *var)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double t;
|
|
|
|
double tt;
|
|
|
|
double x[6];
|
2017-04-20 14:10:12 +00:00
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "geph2pos: time=%s sat=%2d\n", time_str(time, 3), geph->sat);
|
|
|
|
|
|
|
|
t = timediff(time, geph->toe);
|
|
|
|
|
2017-04-21 14:14:46 +00:00
|
|
|
*dts = -geph->taun + geph->gamn * t;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-21 14:14:46 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
2017-04-21 09:34:23 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
x[i] = geph->pos[i];
|
|
|
|
x[i + 3] = geph->vel[i];
|
2017-04-21 14:14:46 +00:00
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
for (tt = t < 0.0 ? -TSTEP : TSTEP; fabs(t) > 1e-9; t -= tt)
|
2017-04-21 09:34:23 +00:00
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (fabs(t) < TSTEP)
|
|
|
|
{
|
|
|
|
tt = t;
|
|
|
|
}
|
2017-04-21 14:14:46 +00:00
|
|
|
glorbit(tt, x, geph->acc);
|
|
|
|
}
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
rs[i] = x[i];
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-22 10:50:04 +00:00
|
|
|
*var = std::pow(ERREPH_GLO, 2.0);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* sbas ephemeris to satellite clock bias --------------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite clock bias with sbas ephemeris
|
|
|
|
* args : gtime_t time I time by satellite clock (gpst)
|
|
|
|
* seph_t *seph I sbas ephemeris
|
|
|
|
* return : satellite clock bias (s)
|
|
|
|
* notes : see ref [3]
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
double seph2clk(gtime_t time, const seph_t *seph)
|
|
|
|
{
|
|
|
|
double t;
|
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "seph2clk: time=%s sat=%2d\n", time_str(time, 3), seph->sat);
|
|
|
|
|
2019-05-08 12:55:14 +00:00
|
|
|
t = timediffweekcrossover(time, seph->t0);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
t -= seph->af0 + seph->af1 * t;
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
return seph->af0 + seph->af1 * t;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* sbas ephemeris to satellite position and clock bias -------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite position and clock bias with sbas ephemeris
|
|
|
|
* args : gtime_t time I time (gpst)
|
|
|
|
* seph_t *seph I sbas ephemeris
|
|
|
|
* double *rs O satellite position {x,y,z} (ecef) (m)
|
|
|
|
* double *dts O satellite clock bias (s)
|
|
|
|
* double *var O satellite position and clock variance (m^2)
|
|
|
|
* return : none
|
|
|
|
* notes : see ref [3]
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
void seph2pos(gtime_t time, const seph_t *seph, double *rs, double *dts,
|
2018-03-03 01:03:39 +00:00
|
|
|
double *var)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
|
|
|
double t;
|
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "seph2pos: time=%s sat=%2d\n", time_str(time, 3), seph->sat);
|
|
|
|
|
2019-05-08 12:55:14 +00:00
|
|
|
t = timediffweekcrossover(time, seph->t0);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
rs[i] = seph->pos[i] + seph->vel[i] * t + seph->acc[i] * t * t / 2.0;
|
|
|
|
}
|
|
|
|
*dts = seph->af0 + seph->af1 * t;
|
|
|
|
|
|
|
|
*var = var_uraeph(seph->sva);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2019-07-20 10:55:46 +00:00
|
|
|
/* select ephemeris --------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
eph_t *seleph(gtime_t time, int sat, int iode, const nav_t *nav)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double t;
|
|
|
|
double tmax;
|
|
|
|
double tmin;
|
|
|
|
int i;
|
|
|
|
int j = -1;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "seleph : time=%s sat=%2d iode=%d\n", time_str(time, 3), sat, iode);
|
|
|
|
|
2018-12-03 09:05:47 +00:00
|
|
|
switch (satsys(sat, nullptr))
|
2018-03-03 01:03:39 +00:00
|
|
|
{
|
|
|
|
case SYS_QZS:
|
|
|
|
tmax = MAXDTOE_QZS + 1.0;
|
|
|
|
break;
|
|
|
|
case SYS_GAL:
|
|
|
|
tmax = MAXDTOE_GAL + 1.0;
|
|
|
|
break;
|
|
|
|
case SYS_BDS:
|
|
|
|
tmax = MAXDTOE_BDS + 1.0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tmax = MAXDTOE + 1.0;
|
|
|
|
break;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
tmin = tmax + 1.0;
|
|
|
|
|
|
|
|
for (i = 0; i < nav->n; i++)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (nav->eph[i].sat != sat)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iode >= 0 && nav->eph[i].iode != iode)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-05-08 12:55:14 +00:00
|
|
|
if ((t = fabs(timediffweekcrossover(nav->eph[i].toe, time))) > tmax)
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iode >= 0)
|
|
|
|
{
|
|
|
|
return nav->eph + i;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (t <= tmin)
|
|
|
|
{
|
|
|
|
j = i;
|
|
|
|
tmin = t;
|
|
|
|
} /* toe closest to time */
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (iode >= 0 || j < 0)
|
2017-04-21 09:34:23 +00:00
|
|
|
{
|
|
|
|
trace(3, "no broadcast ephemeris: %s sat=%2d iode=%3d\n", time_str(time, 0),
|
2018-03-03 01:03:39 +00:00
|
|
|
sat, iode);
|
2018-12-03 09:05:47 +00:00
|
|
|
return nullptr;
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
return nav->eph + j;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2019-07-20 10:55:46 +00:00
|
|
|
/* select glonass ephemeris ------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
geph_t *selgeph(gtime_t time, int sat, int iode, const nav_t *nav)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double t;
|
|
|
|
double tmax = MAXDTOE_GLO;
|
|
|
|
double tmin = tmax + 1.0;
|
|
|
|
int i;
|
|
|
|
int j = -1;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "selgeph : time=%s sat=%2d iode=%2d\n", time_str(time, 3), sat, iode);
|
|
|
|
|
|
|
|
for (i = 0; i < nav->ng; i++)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (nav->geph[i].sat != sat)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iode >= 0 && nav->geph[i].iode != iode)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((t = fabs(timediff(nav->geph[i].toe, time))) > tmax)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (iode >= 0)
|
|
|
|
{
|
|
|
|
return nav->geph + i;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (t <= tmin)
|
|
|
|
{
|
|
|
|
j = i;
|
|
|
|
tmin = t;
|
|
|
|
} /* toe closest to time */
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
if (iode >= 0 || j < 0)
|
|
|
|
{
|
|
|
|
trace(3, "no glonass ephemeris : %s sat=%2d iode=%2d\n", time_str(time, 0),
|
2018-03-03 01:03:39 +00:00
|
|
|
sat, iode);
|
2018-12-03 09:05:47 +00:00
|
|
|
return nullptr;
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
return nav->geph + j;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2019-07-20 10:55:46 +00:00
|
|
|
/* select sbas ephemeris ---------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
seph_t *selseph(gtime_t time, int sat, const nav_t *nav)
|
|
|
|
{
|
2019-08-12 22:19:31 +00:00
|
|
|
double t;
|
|
|
|
double tmax = MAXDTOE_SBS;
|
|
|
|
double tmin = tmax + 1.0;
|
|
|
|
int i;
|
|
|
|
int j = -1;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "selseph : time=%s sat=%2d\n", time_str(time, 3), sat);
|
|
|
|
|
|
|
|
for (i = 0; i < nav->ns; i++)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (nav->seph[i].sat != sat)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2019-05-08 12:55:14 +00:00
|
|
|
if ((t = fabs(timediffweekcrossover(nav->seph[i].t0, time))) > tmax)
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
if (t <= tmin)
|
|
|
|
{
|
|
|
|
j = i;
|
|
|
|
tmin = t;
|
|
|
|
} /* toe closest to time */
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
if (j < 0)
|
|
|
|
{
|
|
|
|
trace(3, "no sbas ephemeris : %s sat=%2d\n", time_str(time, 0), sat);
|
2018-12-03 09:05:47 +00:00
|
|
|
return nullptr;
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
return nav->seph + j;
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite clock with broadcast ephemeris ----------------------------------*/
|
|
|
|
int ephclk(gtime_t time, gtime_t teph, int sat, const nav_t *nav,
|
2018-03-03 01:03:39 +00:00
|
|
|
double *dts)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
eph_t *eph;
|
2017-04-20 14:10:12 +00:00
|
|
|
geph_t *geph;
|
|
|
|
seph_t *seph;
|
|
|
|
int sys;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "ephclk : time=%s sat=%2d\n", time_str(time, 3), sat);
|
|
|
|
|
2018-12-03 09:05:47 +00:00
|
|
|
sys = satsys(sat, nullptr);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(eph = seleph(teph, sat, -1, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
*dts = eph2clk(time, eph);
|
|
|
|
}
|
|
|
|
else if (sys == SYS_GLO)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(geph = selgeph(teph, sat, -1, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
*dts = geph2clk(time, geph);
|
|
|
|
}
|
|
|
|
else if (sys == SYS_SBS)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(seph = selseph(teph, sat, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
*dts = seph2clk(time, seph);
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
else
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite position and clock by broadcast ephemeris -----------------------*/
|
|
|
|
int ephpos(gtime_t time, gtime_t teph, int sat, const nav_t *nav,
|
2018-03-03 01:03:39 +00:00
|
|
|
int iode, double *rs, double *dts, double *var, int *svh)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2018-03-03 01:03:39 +00:00
|
|
|
eph_t *eph;
|
2017-04-20 14:10:12 +00:00
|
|
|
geph_t *geph;
|
|
|
|
seph_t *seph;
|
2019-08-12 22:19:31 +00:00
|
|
|
double rst[3];
|
|
|
|
double dtst[1];
|
|
|
|
double tt = 1e-3;
|
|
|
|
int i;
|
|
|
|
int sys;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "ephpos : time=%s sat=%2d iode=%d\n", time_str(time, 3), sat, iode);
|
|
|
|
|
2018-12-03 09:05:47 +00:00
|
|
|
sys = satsys(sat, nullptr);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
*svh = -1;
|
|
|
|
|
|
|
|
if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(eph = seleph(teph, sat, iode, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
eph2pos(time, eph, rs, dts, var);
|
|
|
|
time = timeadd(time, tt);
|
|
|
|
eph2pos(time, eph, rst, dtst, var);
|
|
|
|
*svh = eph->svh;
|
|
|
|
}
|
|
|
|
else if (sys == SYS_GLO)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(geph = selgeph(teph, sat, iode, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
geph2pos(time, geph, rs, dts, var);
|
|
|
|
time = timeadd(time, tt);
|
|
|
|
geph2pos(time, geph, rst, dtst, var);
|
|
|
|
*svh = geph->svh;
|
|
|
|
}
|
|
|
|
else if (sys == SYS_SBS)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(seph = selseph(teph, sat, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
seph2pos(time, seph, rs, dts, var);
|
|
|
|
time = timeadd(time, tt);
|
|
|
|
seph2pos(time, seph, rst, dtst, var);
|
|
|
|
*svh = seph->svh;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
else
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite velocity and clock drift by differential approx */
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
rs[i + 3] = (rst[i] - rs[i]) / tt;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
dts[1] = (dtst[0] - dts[0]) / tt;
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite position and clock with sbas correction -------------------------*/
|
|
|
|
int satpos_sbas(gtime_t time, gtime_t teph, int sat, const nav_t *nav,
|
2018-03-03 01:03:39 +00:00
|
|
|
double *rs, double *dts, double *var, int *svh)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
|
|
|
const sbssatp_t *sbs;
|
|
|
|
int i;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "satpos_sbas: time=%s sat=%2d\n", time_str(time, 3), sat);
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* search sbas satellite correciton */
|
2017-04-21 09:34:23 +00:00
|
|
|
for (i = 0; i < nav->sbssat.nsat; i++)
|
|
|
|
{
|
|
|
|
sbs = nav->sbssat.sat + i;
|
2019-02-11 20:13:02 +00:00
|
|
|
if (sbs->sat == sat)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
if (i >= nav->sbssat.nsat)
|
|
|
|
{
|
|
|
|
trace(2, "no sbas correction for orbit: %s sat=%2d\n", time_str(time, 0), sat);
|
|
|
|
ephpos(time, teph, sat, nav, -1, rs, dts, var, svh);
|
|
|
|
*svh = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-03-25 17:47:28 +00:00
|
|
|
/* satellite position and clock by broadcast ephemeris */
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!ephpos(time, teph, sat, nav, sbs->lcorr.iode, rs, dts, var, svh))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* sbas satellite correction (long term and fast) */
|
2019-02-11 20:13:02 +00:00
|
|
|
if (sbssatcorr(time, sat, nav, rs, dts, var))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
*svh = -1;
|
2017-04-20 14:10:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite position and clock with ssr correction --------------------------*/
|
|
|
|
int satpos_ssr(gtime_t time, gtime_t teph, int sat, const nav_t *nav,
|
2018-03-03 01:03:39 +00:00
|
|
|
int opt, double *rs, double *dts, double *var, int *svh)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
|
|
|
const ssr_t *ssr;
|
|
|
|
eph_t *eph;
|
2019-08-12 22:19:31 +00:00
|
|
|
double t1;
|
|
|
|
double t2;
|
|
|
|
double t3;
|
|
|
|
double er[3];
|
|
|
|
double ea[3];
|
|
|
|
double ec[3];
|
|
|
|
double rc[3];
|
|
|
|
double deph[3];
|
|
|
|
double dclk;
|
|
|
|
double dant[3] = {0};
|
|
|
|
double tk;
|
|
|
|
int i;
|
|
|
|
int sys;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(4, "satpos_ssr: time=%s sat=%2d\n", time_str(time, 3), sat);
|
|
|
|
|
|
|
|
ssr = nav->ssr + sat - 1;
|
|
|
|
|
|
|
|
if (!ssr->t0[0].time)
|
|
|
|
{
|
|
|
|
trace(2, "no ssr orbit correction: %s sat=%2d\n", time_str(time, 0), sat);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!ssr->t0[1].time)
|
|
|
|
{
|
|
|
|
trace(2, "no ssr clock correction: %s sat=%2d\n", time_str(time, 0), sat);
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-20 14:10:12 +00:00
|
|
|
/* inconsistency between orbit and clock correction */
|
2017-04-21 09:34:23 +00:00
|
|
|
if (ssr->iod[0] != ssr->iod[1])
|
|
|
|
{
|
|
|
|
trace(2, "inconsist ssr correction: %s sat=%2d iod=%d %d\n",
|
2018-03-03 01:03:39 +00:00
|
|
|
time_str(time, 0), sat, ssr->iod[0], ssr->iod[1]);
|
2017-04-21 09:34:23 +00:00
|
|
|
*svh = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-05-08 12:55:14 +00:00
|
|
|
t1 = timediffweekcrossover(time, ssr->t0[0]);
|
|
|
|
t2 = timediffweekcrossover(time, ssr->t0[1]);
|
|
|
|
t3 = timediffweekcrossover(time, ssr->t0[2]);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* ssr orbit and clock correction (ref [4]) */
|
2017-04-21 09:34:23 +00:00
|
|
|
if (fabs(t1) > MAXAGESSR || fabs(t2) > MAXAGESSR)
|
|
|
|
{
|
|
|
|
trace(2, "age of ssr error: %s sat=%2d t=%.0f %.0f\n", time_str(time, 0),
|
2018-03-03 01:03:39 +00:00
|
|
|
sat, t1, t2);
|
2017-04-21 09:34:23 +00:00
|
|
|
*svh = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-02-11 20:13:02 +00:00
|
|
|
if (ssr->udi[0] >= 1.0)
|
|
|
|
{
|
|
|
|
t1 -= ssr->udi[0] / 2.0;
|
|
|
|
}
|
|
|
|
if (ssr->udi[1] >= 1.0)
|
|
|
|
{
|
|
|
|
t2 -= ssr->udi[0] / 2.0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2019-02-11 20:13:02 +00:00
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
deph[i] = ssr->deph[i] + ssr->ddeph[i] * t1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
dclk = ssr->dclk[0] + ssr->dclk[1] * t2 + ssr->dclk[2] * t2 * t2;
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* ssr highrate clock correction (ref [4]) */
|
2017-04-21 09:34:23 +00:00
|
|
|
if (ssr->iod[0] == ssr->iod[2] && ssr->t0[2].time && fabs(t3) < MAXAGESSR_HRCLK)
|
|
|
|
{
|
|
|
|
dclk += ssr->hrclk;
|
|
|
|
}
|
2017-05-04 07:19:57 +00:00
|
|
|
if (norm_rtk(deph, 3) > MAXECORSSR || fabs(dclk) > MAXCCORSSR)
|
2017-04-21 09:34:23 +00:00
|
|
|
{
|
|
|
|
trace(3, "invalid ssr correction: %s deph=%.1f dclk=%.1f\n",
|
2018-03-03 01:03:39 +00:00
|
|
|
time_str(time, 0), norm_rtk(deph, 3), dclk);
|
2017-04-21 09:34:23 +00:00
|
|
|
*svh = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2018-03-25 17:47:28 +00:00
|
|
|
/* satellite position and clock by broadcast ephemeris */
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!ephpos(time, teph, sat, nav, ssr->iode, rs, dts, var, svh))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite clock for gps, galileo and qzss */
|
2018-12-03 09:05:47 +00:00
|
|
|
sys = satsys(sat, nullptr);
|
2017-04-21 09:34:23 +00:00
|
|
|
if (sys == SYS_GPS || sys == SYS_GAL || sys == SYS_QZS || sys == SYS_BDS)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!(eph = seleph(teph, sat, ssr->iode, nav)))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
/* satellite clock by clock parameters */
|
2019-05-08 12:55:14 +00:00
|
|
|
tk = timediffweekcrossover(time, eph->toc);
|
2018-03-03 01:03:39 +00:00
|
|
|
dts[0] = eph->f0 + eph->f1 * tk + eph->f2 * tk * tk;
|
|
|
|
dts[1] = eph->f1 + 2.0 * eph->f2 * tk;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
/* relativity correction */
|
|
|
|
dts[0] -= 2.0 * dot(rs, rs + 3, 3) / SPEED_OF_LIGHT / SPEED_OF_LIGHT;
|
|
|
|
}
|
2017-04-20 14:10:12 +00:00
|
|
|
/* radial-along-cross directions in ecef */
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!normv3(rs + 3, ea))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
cross3(rs, rs + 3, rc);
|
|
|
|
if (!normv3(rc, ec))
|
|
|
|
{
|
|
|
|
*svh = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
cross3(ea, ec, er);
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite antenna offset correction */
|
2017-04-21 09:34:23 +00:00
|
|
|
if (opt)
|
|
|
|
{
|
|
|
|
satantoff(time, rs, sat, nav, dant);
|
|
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
rs[i] += -(er[i] * deph[0] + ea[i] * deph[1] + ec[i] * deph[2]) + dant[i];
|
|
|
|
}
|
|
|
|
/* t_corr = t_sv - (dts(brdc) + dclk(ssr) / SPEED_OF_LIGHT) (ref [10] eq.3.12-7) */
|
|
|
|
dts[0] += dclk / SPEED_OF_LIGHT;
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* variance by ssr ura */
|
2017-04-21 09:34:23 +00:00
|
|
|
*var = var_urassr(ssr->ura);
|
|
|
|
|
|
|
|
trace(5, "satpos_ssr: %s sat=%2d deph=%6.3f %6.3f %6.3f er=%6.3f %6.3f %6.3f dclk=%6.3f var=%6.3f\n",
|
2018-03-03 01:03:39 +00:00
|
|
|
time_str(time, 2), sat, deph[0], deph[1], deph[2], er[0], er[1], er[2], dclk, *var);
|
2017-04-21 09:34:23 +00:00
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite position and clock ------------------------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite position, velocity and clock
|
|
|
|
* args : gtime_t time I time (gpst)
|
|
|
|
* gtime_t teph I time to select ephemeris (gpst)
|
|
|
|
* int sat I satellite number
|
|
|
|
* nav_t *nav I navigation data
|
|
|
|
* int ephopt I ephemeris option (EPHOPT_???)
|
|
|
|
* double *rs O sat position and velocity (ecef)
|
|
|
|
* {x,y,z,vx,vy,vz} (m|m/s)
|
|
|
|
* double *dts O sat clock {bias,drift} (s|s/s)
|
|
|
|
* double *var O sat position and clock error variance (m^2)
|
|
|
|
* int *svh O sat health flag (-1:correction not available)
|
|
|
|
* return : status (1:ok,0:error)
|
|
|
|
* notes : satellite position is referenced to antenna phase center
|
|
|
|
* satellite clock does not include code bias correction (tgd or bgd)
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
int satpos(gtime_t time, gtime_t teph, int sat, int ephopt,
|
2018-03-03 01:03:39 +00:00
|
|
|
const nav_t *nav, double *rs, double *dts, double *var,
|
|
|
|
int *svh)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2017-04-21 09:34:23 +00:00
|
|
|
trace(4, "satpos : time=%s sat=%2d ephopt=%d\n", time_str(time, 3), sat, ephopt);
|
|
|
|
|
|
|
|
*svh = 0;
|
|
|
|
|
|
|
|
switch (ephopt)
|
2018-03-03 01:03:39 +00:00
|
|
|
{
|
|
|
|
case EPHOPT_BRDC:
|
|
|
|
return ephpos(time, teph, sat, nav, -1, rs, dts, var, svh);
|
|
|
|
case EPHOPT_SBAS:
|
|
|
|
return satpos_sbas(time, teph, sat, nav, rs, dts, var, svh);
|
|
|
|
case EPHOPT_SSRAPC:
|
|
|
|
return satpos_ssr(time, teph, sat, nav, 0, rs, dts, var, svh);
|
|
|
|
case EPHOPT_SSRCOM:
|
|
|
|
return satpos_ssr(time, teph, sat, nav, 1, rs, dts, var, svh);
|
|
|
|
case EPHOPT_PREC:
|
|
|
|
if (!peph2pos(time, sat, nav, 1, rs, dts, var))
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
else
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
2018-03-03 01:03:39 +00:00
|
|
|
//TODO: enable lex
|
|
|
|
//case EPHOPT_LEX :
|
|
|
|
// if (!lexeph2pos(time, sat, nav, rs, dts, var)) break; else return 1;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
*svh = -1;
|
2017-04-20 14:10:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
|
2017-04-20 14:10:12 +00:00
|
|
|
/* satellite positions and clocks ----------------------------------------------
|
2017-04-21 09:34:23 +00:00
|
|
|
* compute satellite positions, velocities and clocks
|
|
|
|
* args : gtime_t teph I time to select ephemeris (gpst)
|
|
|
|
* obsd_t *obs I observation data
|
|
|
|
* int n I number of observation data
|
|
|
|
* nav_t *nav I navigation data
|
|
|
|
* int ephopt I ephemeris option (EPHOPT_???)
|
|
|
|
* double *rs O satellite positions and velocities (ecef)
|
|
|
|
* double *dts O satellite clocks
|
|
|
|
* double *var O sat position and clock error variances (m^2)
|
|
|
|
* int *svh O sat health flag (-1:correction not available)
|
|
|
|
* return : none
|
|
|
|
* notes : rs [(0:2)+i*6]= obs[i] sat position {x,y,z} (m)
|
|
|
|
* rs [(3:5)+i*6]= obs[i] sat velocity {vx,vy,vz} (m/s)
|
|
|
|
* dts[(0:1)+i*2]= obs[i] sat clock {bias,drift} (s|s/s)
|
|
|
|
* var[i] = obs[i] sat position and clock error variance (m^2)
|
|
|
|
* svh[i] = obs[i] sat health flag
|
|
|
|
* if no navigation data, set 0 to rs[], dts[], var[] and svh[]
|
|
|
|
* satellite position and clock are values at signal transmission time
|
|
|
|
* satellite position is referenced to antenna phase center
|
|
|
|
* satellite clock does not include code bias correction (tgd or bgd)
|
|
|
|
* any pseudorange and broadcast ephemeris are always needed to get
|
|
|
|
* signal transmission time
|
|
|
|
*-----------------------------------------------------------------------------*/
|
2017-04-20 14:10:12 +00:00
|
|
|
void satposs(gtime_t teph, const obsd_t *obs, int n, const nav_t *nav,
|
2018-03-03 01:03:39 +00:00
|
|
|
int ephopt, double *rs, double *dts, double *var, int *svh)
|
2017-04-20 14:10:12 +00:00
|
|
|
{
|
2017-04-21 09:34:23 +00:00
|
|
|
gtime_t time[MAXOBS] = {};
|
2019-08-12 22:19:31 +00:00
|
|
|
double dt;
|
|
|
|
double pr;
|
|
|
|
int i;
|
|
|
|
int j;
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
trace(3, "satposs : teph=%s n=%d ephopt=%d\n", time_str(teph, 3), n, ephopt);
|
|
|
|
|
|
|
|
for (i = 0; i < n && i < MAXOBS; i++)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
for (j = 0; j < 6; j++)
|
|
|
|
{
|
|
|
|
rs[j + i * 6] = 0.0;
|
|
|
|
}
|
|
|
|
for (j = 0; j < 2; j++)
|
|
|
|
{
|
|
|
|
dts[j + i * 2] = 0.0;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
var[i] = 0.0;
|
|
|
|
svh[i] = 0;
|
|
|
|
|
|
|
|
/* search any pseudorange */
|
2018-03-03 01:03:39 +00:00
|
|
|
for (j = 0, pr = 0.0; j < NFREQ; j++)
|
2019-02-11 20:13:02 +00:00
|
|
|
{
|
|
|
|
if ((pr = obs[i].P[j]) != 0.0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
|
|
|
|
if (j >= NFREQ)
|
|
|
|
{
|
|
|
|
trace(2, "no pseudorange %s sat=%2d\n", time_str(obs[i].time, 3), obs[i].sat);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* transmission time by satellite clock */
|
|
|
|
time[i] = timeadd(obs[i].time, -pr / SPEED_OF_LIGHT);
|
|
|
|
|
|
|
|
/* satellite clock bias by broadcast ephemeris */
|
|
|
|
if (!ephclk(time[i], teph, obs[i].sat, nav, &dt))
|
|
|
|
{
|
|
|
|
trace(3, "no broadcast clock %s sat=%2d\n", time_str(time[i], 3), obs[i].sat);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
time[i] = timeadd(time[i], -dt);
|
|
|
|
|
|
|
|
/* satellite position and clock at transmission time */
|
|
|
|
if (!satpos(time[i], teph, obs[i].sat, ephopt, nav, rs + i * 6, dts + i * 2, var + i,
|
|
|
|
svh + i))
|
|
|
|
{
|
|
|
|
trace(3, "no ephemeris %s sat=%2d\n", time_str(time[i], 3), obs[i].sat);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* if no precise clock available, use broadcast clock instead */
|
|
|
|
if (dts[i * 2] == 0.0)
|
|
|
|
{
|
2019-02-11 20:13:02 +00:00
|
|
|
if (!ephclk(time[i], teph, obs[i].sat, nav, dts + i * 2))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-21 09:34:23 +00:00
|
|
|
dts[1 + i * 2] = 0.0;
|
2017-04-22 10:50:04 +00:00
|
|
|
*var = std::pow(STD_BRDCCLK, 2.0);
|
2017-04-21 09:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < n && i < MAXOBS; i++)
|
|
|
|
{
|
|
|
|
trace(4, "%s sat=%2d rs=%13.3f %13.3f %13.3f dts=%12.3f var=%7.3f svh=%02X\n",
|
2018-03-03 01:03:39 +00:00
|
|
|
time_str(time[i], 6), obs[i].sat, rs[i * 6], rs[1 + i * 6], rs[2 + i * 6],
|
|
|
|
dts[i * 2] * 1e9, var[i], svh[i]);
|
2017-04-20 14:10:12 +00:00
|
|
|
}
|
|
|
|
}
|