2017-04-20 14:10:12 +00:00
/*!
* \ file rtklib_solver . cc
* \ brief PVT solver based on rtklib library functions adapted to the GNSS - SDR
* data flow and structures
* \ authors < ul >
* < li > 2017 , Javier Arribas
* < li > 2017 , Carles Fernandez
* < li > 2007 - 2013 , T . Takasu
* < / 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
2017-05-08 19:30:41 +00:00
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2017-04-20 14:10:12 +00:00
2017-04-25 15:50:25 +00:00
# include "rtklib_solver.h"
2017-04-20 14:10:12 +00:00
# include "rtklib_conversions.h"
# include "GPS_L1_CA.h"
# include "Galileo_E1.h"
2018-03-26 13:06:14 +00:00
# include "GLONASS_L1_L2_CA.h"
2018-02-26 02:15:53 +00:00
# include <glog/logging.h>
2017-04-25 15:50:25 +00:00
2017-04-20 14:10:12 +00:00
using google : : LogMessage ;
2018-03-03 01:03:39 +00:00
rtklib_solver : : rtklib_solver ( int nchannels , std : : string dump_filename , bool flag_dump_to_file , rtk_t & rtk )
2017-04-20 14:10:12 +00:00
{
// init empty ephemeris for all the available GNSS channels
d_nchannels = nchannels ;
d_dump_filename = dump_filename ;
d_flag_dump_enabled = flag_dump_to_file ;
count_valid_position = 0 ;
2017-08-16 10:45:00 +00:00
this - > set_averaging_flag ( false ) ;
2017-05-02 17:31:38 +00:00
rtk_ = rtk ;
2018-05-16 19:33:52 +00:00
for ( unsigned int i = 0 ; i < 4 ; i + + ) dop_ [ i ] = 0.0 ;
2018-03-03 01:03:39 +00:00
pvt_sol = { { 0 , 0 } , { 0 , 0 , 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 , 0 , 0 } , ' 0 ' , ' 0 ' , ' 0 ' , 0 , 0 , 0 } ;
2017-04-20 14:10:12 +00:00
// ############# ENABLE DATA FILE LOG #################
if ( d_flag_dump_enabled = = true )
{
2017-08-15 23:01:59 +00:00
if ( d_dump_file . is_open ( ) = = false )
{
try
2018-03-03 01:03:39 +00:00
{
2017-08-15 23:01:59 +00:00
d_dump_file . exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ;
d_dump_file . open ( d_dump_filename . c_str ( ) , std : : ios : : out | std : : ios : : binary ) ;
LOG ( INFO ) < < " PVT lib dump enabled Log file: " < < d_dump_filename . c_str ( ) ;
2018-03-03 01:03:39 +00:00
}
catch ( const std : : ifstream : : failure & e )
{
2017-08-15 23:01:59 +00:00
LOG ( WARNING ) < < " Exception opening PVT lib dump file " < < e . what ( ) ;
2018-03-03 01:03:39 +00:00
}
2017-08-15 23:01:59 +00:00
}
2017-04-20 14:10:12 +00:00
}
}
rtklib_solver : : ~ rtklib_solver ( )
{
2017-08-15 23:01:59 +00:00
if ( d_dump_file . is_open ( ) = = true )
{
try
2018-03-03 01:03:39 +00:00
{
2017-08-15 23:01:59 +00:00
d_dump_file . close ( ) ;
2018-03-03 01:03:39 +00:00
}
catch ( const std : : exception & ex )
{
2017-08-15 23:01:59 +00:00
LOG ( WARNING ) < < " Exception in destructor closing the dump file " < < ex . what ( ) ;
2018-03-03 01:03:39 +00:00
}
2017-08-15 23:01:59 +00:00
}
2017-04-20 14:10:12 +00:00
}
2017-05-08 19:30:41 +00:00
2018-05-07 07:13:45 +00:00
double rtklib_solver : : get_gdop ( ) const
{
return dop_ [ 0 ] ;
}
double rtklib_solver : : get_pdop ( ) const
{
return dop_ [ 1 ] ;
}
double rtklib_solver : : get_hdop ( ) const
{
return dop_ [ 2 ] ;
}
double rtklib_solver : : get_vdop ( ) const
{
return dop_ [ 3 ] ;
}
2018-06-02 10:55:00 +00:00
bool rtklib_solver : : get_PVT ( const std : : map < int , Gnss_Synchro > & gnss_observables_map , bool flag_averaging )
2017-04-20 14:10:12 +00:00
{
2018-03-03 01:03:39 +00:00
std : : map < int , Gnss_Synchro > : : const_iterator gnss_observables_iter ;
std : : map < int , Galileo_Ephemeris > : : const_iterator galileo_ephemeris_iter ;
std : : map < int , Gps_Ephemeris > : : const_iterator gps_ephemeris_iter ;
std : : map < int , Gps_CNAV_Ephemeris > : : const_iterator gps_cnav_ephemeris_iter ;
std : : map < int , Glonass_Gnav_Ephemeris > : : const_iterator glonass_gnav_ephemeris_iter ;
2017-10-19 19:22:55 +00:00
const Glonass_Gnav_Utc_Model gnav_utc = this - > glonass_gnav_utc_model ;
2017-04-20 14:10:12 +00:00
2017-08-16 10:45:00 +00:00
this - > set_averaging_flag ( flag_averaging ) ;
2017-04-20 14:10:12 +00:00
// ********************************************************************************
// ****** PREPARE THE DATA (SV EPHEMERIS AND OBSERVATIONS) ************************
// ********************************************************************************
2018-06-05 20:53:34 +00:00
int valid_obs = 0 ; // valid observations counter
int glo_valid_obs = 0 ; // GLONASS L1/L2 valid observations counter
2017-04-20 14:10:12 +00:00
obsd_t obs_data [ MAXOBS ] ;
2018-03-09 12:05:25 +00:00
eph_t eph_data [ MAXOBS ] ;
2017-07-24 05:57:54 +00:00
geph_t geph_data [ MAXOBS ] ;
2017-04-20 14:10:12 +00:00
2018-06-08 09:01:29 +00:00
// Workaround for NAV/CNAV clash problem
bool gps_dual_band = false ;
bool band1 = false ;
bool band2 = false ;
2018-03-09 12:05:25 +00:00
for ( gnss_observables_iter = gnss_observables_map . cbegin ( ) ;
gnss_observables_iter ! = gnss_observables_map . cend ( ) ;
2018-06-08 09:01:29 +00:00
+ + gnss_observables_iter )
{
switch ( gnss_observables_iter - > second . System )
{
case ' G ' :
{
std : : string sig_ ( gnss_observables_iter - > second . Signal ) ;
if ( sig_ . compare ( " 1C " ) = = 0 )
{
band1 = true ;
}
if ( sig_ . compare ( " 2S " ) = = 0 )
{
band2 = true ;
}
}
2018-08-07 17:59:44 +00:00
break ;
2018-06-08 09:01:29 +00:00
default :
{
}
}
}
if ( band1 = = true and band2 = = true ) gps_dual_band = true ;
for ( gnss_observables_iter = gnss_observables_map . cbegin ( ) ;
gnss_observables_iter ! = gnss_observables_map . cend ( ) ;
+ + gnss_observables_iter ) // CHECK INCONSISTENCY when combining GLONASS + other system
2017-05-12 15:58:04 +00:00
{
2018-03-03 01:03:39 +00:00
switch ( gnss_observables_iter - > second . System )
2017-04-20 14:10:12 +00:00
{
2018-03-03 01:03:39 +00:00
case ' E ' :
{
std : : string sig_ ( gnss_observables_iter - > second . Signal ) ;
// Galileo E1
if ( sig_ . compare ( " 1B " ) = = 0 )
{
// 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key
galileo_ephemeris_iter = galileo_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( galileo_ephemeris_iter ! = galileo_ephemeris_map . cend ( ) )
{
2018-06-05 20:53:34 +00:00
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
eph_data [ valid_obs ] = eph_to_rtklib ( galileo_ephemeris_iter - > second ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } , { } , { } , { } , { } } ;
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
galileo_ephemeris_iter - > second . WN_5 ,
0 ) ;
2018-03-03 01:03:39 +00:00
valid_obs + + ;
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
2017-08-15 23:01:59 +00:00
2017-08-29 06:16:07 +00:00
// Galileo E5
2018-03-03 01:03:39 +00:00
if ( sig_ . compare ( " 5X " ) = = 0 )
2017-08-29 06:16:07 +00:00
{
2018-03-03 01:03:39 +00:00
// 1 Gal - find the ephemeris for the current GALILEO SV observation. The SV PRN ID is the map key
galileo_ephemeris_iter = galileo_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( galileo_ephemeris_iter ! = galileo_ephemeris_map . cend ( ) )
{
bool found_E1_obs = false ;
for ( int i = 0 ; i < valid_obs ; i + + )
{
if ( eph_data [ i ] . sat = = ( static_cast < int > ( gnss_observables_iter - > second . PRN + NSATGPS + NSATGLO ) ) )
{
obs_data [ i + glo_valid_obs ] = insert_obs_to_rtklib ( obs_data [ i + glo_valid_obs ] ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
galileo_ephemeris_iter - > second . WN_5 ,
2018-06-05 20:53:34 +00:00
2 ) ; // Band 3 (L5/E5)
2018-03-03 01:03:39 +00:00
found_E1_obs = true ;
break ;
}
}
if ( ! found_E1_obs )
{
2018-06-05 20:53:34 +00:00
// insert Galileo E5 obs as new obs and also insert its ephemeris
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
eph_data [ valid_obs ] = eph_to_rtklib ( galileo_ephemeris_iter - > second ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
unsigned char default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } ,
{ default_code_ , default_code_ , default_code_ } ,
{ } , { 0.0 , 0.0 , 0.0 } , { } } ;
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
galileo_ephemeris_iter - > second . WN_5 ,
2018-06-05 20:53:34 +00:00
2 ) ; // Band 3 (L5/E5)
2018-03-03 01:03:39 +00:00
valid_obs + + ;
}
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
break ;
}
case ' G ' :
{
// GPS L1
// 1 GPS - find the ephemeris for the current GPS SV observation. The SV PRN ID is the map key
std : : string sig_ ( gnss_observables_iter - > second . Signal ) ;
if ( sig_ . compare ( " 1C " ) = = 0 )
{
gps_ephemeris_iter = gps_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( gps_ephemeris_iter ! = gps_ephemeris_map . cend ( ) )
{
2018-06-05 20:53:34 +00:00
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
eph_data [ valid_obs ] = eph_to_rtklib ( gps_ephemeris_iter - > second ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } , { } , { } , { } , { } } ;
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
gps_ephemeris_iter - > second . i_GPS_week ,
0 ) ;
2018-03-03 01:03:39 +00:00
valid_obs + + ;
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > first ;
}
}
2018-06-08 09:01:29 +00:00
// GPS L2 (todo: solve NAV/CNAV clash)
if ( ( sig_ . compare ( " 2S " ) = = 0 ) and ( gps_dual_band = = false ) )
2018-03-03 01:03:39 +00:00
{
gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( gps_cnav_ephemeris_iter ! = gps_cnav_ephemeris_map . cend ( ) )
{
// 1. Find the same satellite in GPS L1 band
gps_ephemeris_iter = gps_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( gps_ephemeris_iter ! = gps_ephemeris_map . cend ( ) )
{
2018-04-03 10:45:03 +00:00
/* By the moment, GPS L2 observables are not used in pseudorange computations if GPS L1 is available
2018-03-03 01:03:39 +00:00
// 2. If found, replace the existing GPS L1 ephemeris with the GPS L2 ephemeris
// (more precise!), and attach the L2 observation to the L1 observation in RTKLIB structure
for ( int i = 0 ; i < valid_obs ; i + + )
{
if ( eph_data [ i ] . sat = = static_cast < int > ( gnss_observables_iter - > second . PRN ) )
{
2018-03-12 09:51:06 +00:00
eph_data [ i ] = eph_to_rtklib ( gps_cnav_ephemeris_iter - > second ) ;
2018-03-03 01:03:39 +00:00
obs_data [ i + glo_valid_obs ] = insert_obs_to_rtklib ( obs_data [ i + glo_valid_obs ] ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
2018-03-09 12:05:25 +00:00
eph_data [ i ] . week ,
2018-06-05 20:53:34 +00:00
1 ) ; // Band 2 (L2)
2018-03-03 01:03:39 +00:00
break ;
}
}
2018-04-03 10:45:03 +00:00
*/
2018-03-03 01:03:39 +00:00
}
else
2018-03-12 09:51:06 +00:00
{
2018-03-03 01:03:39 +00:00
// 3. If not found, insert the GPS L2 ephemeris and the observation
2018-06-05 20:53:34 +00:00
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
eph_data [ valid_obs ] = eph_to_rtklib ( gps_cnav_ephemeris_iter - > second ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
unsigned char default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } ,
2017-11-30 15:04:20 +00:00
{ default_code_ , default_code_ , default_code_ } ,
{ } , { 0.0 , 0.0 , 0.0 } , { } } ;
2018-03-03 01:03:39 +00:00
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-08-15 23:01:59 +00:00
gnss_observables_iter - > second ,
gps_cnav_ephemeris_iter - > second . i_GPS_week ,
2018-06-05 20:53:34 +00:00
1 ) ; // Band 2 (L2)
2018-03-03 01:03:39 +00:00
valid_obs + + ;
}
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
2018-06-05 20:53:34 +00:00
// GPS L5
2018-03-03 01:03:39 +00:00
if ( sig_ . compare ( " L5 " ) = = 0 )
{
gps_cnav_ephemeris_iter = gps_cnav_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( gps_cnav_ephemeris_iter ! = gps_cnav_ephemeris_map . cend ( ) )
{
// 1. Find the same satellite in GPS L1 band
gps_ephemeris_iter = gps_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( gps_ephemeris_iter ! = gps_ephemeris_map . cend ( ) )
{
// 2. If found, replace the existing GPS L1 ephemeris with the GPS L5 ephemeris
// (more precise!), and attach the L5 observation to the L1 observation in RTKLIB structure
for ( int i = 0 ; i < valid_obs ; i + + )
{
if ( eph_data [ i ] . sat = = static_cast < int > ( gnss_observables_iter - > second . PRN ) )
{
eph_data [ i ] = eph_to_rtklib ( gps_cnav_ephemeris_iter - > second ) ;
obs_data [ i + glo_valid_obs ] = insert_obs_to_rtklib ( obs_data [ i ] ,
2017-11-30 15:04:20 +00:00
gnss_observables_iter - > second ,
gps_cnav_ephemeris_iter - > second . i_GPS_week ,
2018-06-05 20:53:34 +00:00
2 ) ; // Band 3 (L5)
2018-03-03 01:03:39 +00:00
break ;
}
}
}
else
{
// 3. If not found, insert the GPS L5 ephemeris and the observation
2018-06-05 20:53:34 +00:00
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
eph_data [ valid_obs ] = eph_to_rtklib ( gps_cnav_ephemeris_iter - > second ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
unsigned char default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } ,
2017-11-30 15:04:20 +00:00
{ default_code_ , default_code_ , default_code_ } ,
{ } , { 0.0 , 0.0 , 0.0 } , { } } ;
2018-03-03 01:03:39 +00:00
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-11-30 15:04:20 +00:00
gnss_observables_iter - > second ,
gps_cnav_ephemeris_iter - > second . i_GPS_week ,
2018-06-05 20:53:34 +00:00
2 ) ; // Band 3 (L5)
2018-03-03 01:03:39 +00:00
valid_obs + + ;
}
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
break ;
}
case ' R ' : //TODO This should be using rtk lib nomenclature
{
std : : string sig_ ( gnss_observables_iter - > second . Signal ) ;
// GLONASS GNAV L1
if ( sig_ . compare ( " 1G " ) = = 0 )
{
// 1 Glo - find the ephemeris for the current GLONASS SV observation. The SV Slot Number (PRN ID) is the map key
glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( glonass_gnav_ephemeris_iter ! = glonass_gnav_ephemeris_map . cend ( ) )
{
2018-06-05 20:53:34 +00:00
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
geph_data [ glo_valid_obs ] = eph_to_rtklib ( glonass_gnav_ephemeris_iter - > second , gnav_utc ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } , { } , { } , { } , { } } ;
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-12-02 12:48:45 +00:00
gnss_observables_iter - > second ,
glonass_gnav_ephemeris_iter - > second . d_WN ,
2018-06-05 20:53:34 +00:00
0 ) ; // Band 0 (L1)
2018-03-03 01:03:39 +00:00
glo_valid_obs + + ;
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
// GLONASS GNAV L2
if ( sig_ . compare ( " 2G " ) = = 0 )
{
// 1 GLONASS - find the ephemeris for the current GLONASS SV observation. The SV PRN ID is the map key
glonass_gnav_ephemeris_iter = glonass_gnav_ephemeris_map . find ( gnss_observables_iter - > second . PRN ) ;
if ( glonass_gnav_ephemeris_iter ! = glonass_gnav_ephemeris_map . cend ( ) )
{
bool found_L1_obs = false ;
for ( int i = 0 ; i < glo_valid_obs ; i + + )
{
if ( geph_data [ i ] . sat = = ( static_cast < int > ( gnss_observables_iter - > second . PRN + NSATGPS ) ) )
{
obs_data [ i + valid_obs ] = insert_obs_to_rtklib ( obs_data [ i + valid_obs ] ,
2017-12-02 12:48:45 +00:00
gnss_observables_iter - > second ,
glonass_gnav_ephemeris_iter - > second . d_WN ,
2018-03-03 01:03:39 +00:00
1 ) ; //Band 1 (L2)
found_L1_obs = true ;
break ;
}
}
if ( ! found_L1_obs )
{
2018-06-05 20:53:34 +00:00
// insert GLONASS GNAV L2 obs as new obs and also insert its ephemeris
// convert ephemeris from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
geph_data [ glo_valid_obs ] = eph_to_rtklib ( glonass_gnav_ephemeris_iter - > second , gnav_utc ) ;
2018-06-05 20:53:34 +00:00
// convert observation from GNSS-SDR class to RTKLIB structure
2018-03-03 01:03:39 +00:00
obsd_t newobs = { { 0 , 0 } , ' 0 ' , ' 0 ' , { } , { } , { } , { } , { } , { } } ;
obs_data [ valid_obs + glo_valid_obs ] = insert_obs_to_rtklib ( newobs ,
2017-12-02 12:48:45 +00:00
gnss_observables_iter - > second ,
glonass_gnav_ephemeris_iter - > second . d_WN ,
2018-06-05 20:53:34 +00:00
1 ) ; // Band 1 (L2)
2018-03-03 01:03:39 +00:00
glo_valid_obs + + ;
}
}
else // the ephemeris are not available for this SV
{
DLOG ( INFO ) < < " No ephemeris data for SV " < < gnss_observables_iter - > second . PRN ;
}
}
break ;
}
default :
DLOG ( INFO ) < < " Hybrid observables: Unknown GNSS " ;
2017-08-15 23:01:59 +00:00
break ;
2017-04-20 14:10:12 +00:00
}
}
2017-08-15 23:01:59 +00:00
// **********************************************************************
// ****** SOLVE PVT******************************************************
// **********************************************************************
2017-04-20 14:10:12 +00:00
2017-08-16 10:45:00 +00:00
this - > set_valid_position ( false ) ;
2018-03-08 17:05:22 +00:00
if ( ( valid_obs + glo_valid_obs ) > 3 )
2017-04-20 14:10:12 +00:00
{
2017-05-08 19:30:41 +00:00
int result = 0 ;
nav_t nav_data ;
nav_data . eph = eph_data ;
2017-10-10 14:40:05 +00:00
nav_data . geph = geph_data ;
2017-05-08 19:30:41 +00:00
nav_data . n = valid_obs ;
2017-10-11 14:22:45 +00:00
nav_data . ng = glo_valid_obs ;
2017-05-08 19:30:41 +00:00
for ( int i = 0 ; i < MAXSAT ; i + + )
2017-08-15 23:01:59 +00:00
{
nav_data . lam [ i ] [ 0 ] = SPEED_OF_LIGHT / FREQ1 ; /* L1/E1 */
nav_data . lam [ i ] [ 1 ] = SPEED_OF_LIGHT / FREQ2 ; /* L2 */
nav_data . lam [ i ] [ 2 ] = SPEED_OF_LIGHT / FREQ5 ; /* L5/E5 */
}
2017-04-20 14:10:12 +00:00
2017-10-11 14:22:45 +00:00
result = rtkpos ( & rtk_ , obs_data , valid_obs + glo_valid_obs , & nav_data ) ;
2018-01-23 23:52:09 +00:00
2018-03-03 01:03:39 +00:00
if ( result = = 0 )
2017-08-15 23:01:59 +00:00
{
2018-02-12 11:46:08 +00:00
LOG ( INFO ) < < " RTKLIB rtkpos error " ;
2017-12-20 15:12:08 +00:00
DLOG ( INFO ) < < " RTKLIB rtkpos error message: " < < rtk_ . errbuf ;
2018-03-03 01:03:39 +00:00
this - > set_time_offset_s ( 0.0 ) ; //reset rx time estimation
2017-08-16 10:45:00 +00:00
this - > set_num_valid_observations ( 0 ) ;
2017-08-15 23:01:59 +00:00
}
2017-05-08 19:30:41 +00:00
else
2017-08-15 23:01:59 +00:00
{
2018-03-03 01:03:39 +00:00
this - > set_num_valid_observations ( rtk_ . sol . ns ) ; //record the number of valid satellites used by the PVT solver
2017-08-15 23:01:59 +00:00
pvt_sol = rtk_ . sol ;
2018-05-07 12:34:53 +00:00
// DOP computation
unsigned int used_sats = 0 ;
2018-05-07 07:13:45 +00:00
for ( unsigned int i = 0 ; i < MAXSAT ; i + + )
{
2018-05-16 16:32:27 +00:00
if ( rtk_ . ssat [ i ] . vsat [ 0 ] = = 1 ) used_sats + + ;
2018-05-07 07:13:45 +00:00
}
2018-05-07 12:34:53 +00:00
2018-08-16 12:16:43 +00:00
std : : vector < double > azel ;
azel . reserve ( used_sats * 2 ) ;
2018-05-07 12:34:53 +00:00
unsigned int index_aux = 0 ;
for ( unsigned int i = 0 ; i < MAXSAT ; i + + )
{
2018-05-16 16:32:27 +00:00
if ( rtk_ . ssat [ i ] . vsat [ 0 ] = = 1 )
2018-05-07 12:34:53 +00:00
{
azel [ 2 * index_aux ] = rtk_ . ssat [ i ] . azel [ 0 ] ;
azel [ 2 * index_aux + 1 ] = rtk_ . ssat [ i ] . azel [ 1 ] ;
index_aux + + ;
}
}
2018-08-16 12:16:43 +00:00
if ( index_aux > 0 ) dops ( index_aux , azel . data ( ) , 0.0 , dop_ ) ;
2018-05-07 12:34:53 +00:00
2017-08-16 10:45:00 +00:00
this - > set_valid_position ( true ) ;
2017-08-15 23:01:59 +00:00
arma : : vec rx_position_and_time ( 4 ) ;
2018-06-05 20:53:34 +00:00
rx_position_and_time ( 0 ) = pvt_sol . rr [ 0 ] ; // [m]
rx_position_and_time ( 1 ) = pvt_sol . rr [ 1 ] ; // [m]
rx_position_and_time ( 2 ) = pvt_sol . rr [ 2 ] ; // [m]
2018-05-17 16:10:48 +00:00
//todo: fix this ambiguity in the RTKLIB units in receiver clock offset!
if ( rtk_ . opt . mode = = PMODE_SINGLE )
{
2018-06-05 20:53:34 +00:00
rx_position_and_time ( 3 ) = pvt_sol . dtr [ 0 ] ; // if the RTKLIB solver is set to SINGLE, the dtr is already expressed in [s]
2018-05-17 16:10:48 +00:00
}
else
{
2018-06-05 20:53:34 +00:00
rx_position_and_time ( 3 ) = pvt_sol . dtr [ 0 ] / GPS_C_m_s ; // the receiver clock offset is expressed in [meters], so we convert it into [s]
2018-05-17 16:10:48 +00:00
}
2018-03-03 01:03:39 +00:00
this - > set_rx_pos ( rx_position_and_time . rows ( 0 , 2 ) ) ; // save ECEF position for the next iteration
2018-05-17 16:10:48 +00:00
//observable fix:
//double offset_s = this->get_time_offset_s();
//this->set_time_offset_s(offset_s + (rx_position_and_time(3) / GPS_C_m_s)); // accumulate the rx time error for the next iteration [meters]->[seconds]
this - > set_time_offset_s ( rx_position_and_time ( 3 ) ) ;
2018-06-02 10:55:00 +00:00
DLOG ( INFO ) < < " RTKLIB Position at RX TOW = " < < gnss_observables_map . begin ( ) - > second . RX_time
< < " in ECEF (X,Y,Z,t[meters]) = " < < rx_position_and_time ;
2017-05-08 19:30:41 +00:00
2017-08-15 23:01:59 +00:00
boost : : posix_time : : ptime p_time ;
2018-06-07 10:23:26 +00:00
// gtime_t rtklib_utc_time = gpst2utc(pvt_sol.time); //Corrected RX Time (Non integer multiply of 1 ms of granularity)
// Uncorrected RX Time (integer multiply of 1 ms and the same observables time reported in RTCM and RINEX)
gtime_t rtklib_time = gpst2time ( adjgpsweek ( nav_data . eph [ 0 ] . week ) , gnss_observables_map . begin ( ) - > second . RX_time ) ;
gtime_t rtklib_utc_time = gpst2utc ( rtklib_time ) ;
2017-08-15 23:01:59 +00:00
p_time = boost : : posix_time : : from_time_t ( rtklib_utc_time . time ) ;
2018-06-15 15:20:01 +00:00
p_time + = boost : : posix_time : : microseconds ( static_cast < long > ( round ( rtklib_utc_time . sec * 1e6 ) ) ) ;
2017-08-16 10:45:00 +00:00
this - > set_position_UTC_time ( p_time ) ;
2017-08-15 23:01:59 +00:00
cart2geo ( static_cast < double > ( rx_position_and_time ( 0 ) ) , static_cast < double > ( rx_position_and_time ( 1 ) ) , static_cast < double > ( rx_position_and_time ( 2 ) ) , 4 ) ;
2017-05-08 19:30:41 +00:00
2017-08-15 23:01:59 +00:00
DLOG ( INFO ) < < " RTKLIB Position at " < < boost : : posix_time : : to_simple_string ( p_time )
2017-08-16 10:45:00 +00:00
< < " is Lat = " < < this - > get_latitude ( ) < < " [deg], Long = " < < this - > get_longitude ( )
2018-03-03 01:03:39 +00:00
< < " [deg], Height= " < < this - > get_height ( ) < < " [m] "
< < " RX time offset= " < < this - > get_time_offset_s ( ) < < " [s] " ;
2017-05-08 19:30:41 +00:00
2017-08-15 23:01:59 +00:00
// ######## LOG FILE #########
2018-03-03 01:03:39 +00:00
if ( d_flag_dump_enabled = = true )
2017-08-15 23:01:59 +00:00
{
// MULTIPLEXED FILE RECORDING - Record results to file
try
2018-03-03 01:03:39 +00:00
{
2017-08-15 23:01:59 +00:00
double tmp_double ;
2018-06-05 20:53:34 +00:00
// PVT GPS time
2018-06-02 10:55:00 +00:00
tmp_double = gnss_observables_map . begin ( ) - > second . RX_time ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// ECEF User Position East [m]
tmp_double = rx_position_and_time ( 0 ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// ECEF User Position North [m]
tmp_double = rx_position_and_time ( 1 ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// ECEF User Position Up [m]
tmp_double = rx_position_and_time ( 2 ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// User clock offset [s]
tmp_double = rx_position_and_time ( 3 ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// GEO user position Latitude [deg]
2017-08-16 10:45:00 +00:00
tmp_double = this - > get_latitude ( ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// GEO user position Longitude [deg]
2017-08-16 10:45:00 +00:00
tmp_double = this - > get_longitude ( ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2017-08-15 23:01:59 +00:00
// GEO user position Height [m]
2017-08-16 10:45:00 +00:00
tmp_double = this - > get_height ( ) ;
2017-08-19 07:16:10 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-03-03 01:03:39 +00:00
}
2017-08-15 23:01:59 +00:00
catch ( const std : : ifstream : : failure & e )
2018-03-03 01:03:39 +00:00
{
2017-08-15 23:01:59 +00:00
LOG ( WARNING ) < < " Exception writing PVT LS dump file " < < e . what ( ) ;
2018-03-03 01:03:39 +00:00
}
2017-08-15 23:01:59 +00:00
}
2018-03-03 01:03:39 +00:00
}
}
2018-03-08 17:05:22 +00:00
return is_valid_position ( ) ;
2018-03-03 01:03:39 +00:00
}