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"
2018-11-05 14:39:56 +00:00
# include "rtklib_solution.h"
2017-04-20 14:10:12 +00:00
# include "GPS_L1_CA.h"
# include "Galileo_E1.h"
2018-03-26 13:06:14 +00:00
# include "GLONASS_L1_L2_CA.h"
2018-10-31 13:56:59 +00:00
# include <matio.h>
2018-02-26 02:15:53 +00:00
# include <glog/logging.h>
2018-12-03 18:01:47 +00:00
# include <utility>
2017-04-20 14:10:12 +00:00
using google : : LogMessage ;
2018-12-02 04:29:11 +00:00
rtklib_solver : : rtklib_solver ( int nchannels , std : : string dump_filename , bool flag_dump_to_file , bool flag_dump_to_mat , const rtk_t & rtk )
2017-04-20 14:10:12 +00:00
{
// init empty ephemeris for all the available GNSS channels
d_nchannels = nchannels ;
2018-12-03 18:01:47 +00:00
d_dump_filename = std : : move ( dump_filename ) ;
2017-04-20 14:10:12 +00:00
d_flag_dump_enabled = flag_dump_to_file ;
2018-10-31 13:56:59 +00:00
d_flag_dump_mat_enabled = flag_dump_to_mat ;
2017-04-20 14:10:12 +00:00
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-12-08 17:49:31 +00:00
for ( double & 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 } ;
2018-11-07 15:03:45 +00:00
ssat_t ssat0 = { 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 } } } , { { } , { } } } ;
2018-12-08 17:49:31 +00:00
for ( auto & i : pvt_ssat )
2018-11-07 15:03:45 +00:00
{
2018-12-03 17:03:25 +00:00
i = ssat0 ;
2018-11-07 15:03:45 +00:00
}
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
}
2018-10-31 13:56:59 +00:00
catch ( const std : : ifstream : : failure & e )
2018-03-03 01:03:39 +00:00
{
2018-08-29 16:53:03 +00:00
LOG ( WARNING ) < < " Exception opening RTKLIB 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
}
}
2018-10-31 13:56:59 +00:00
bool rtklib_solver : : save_matfile ( )
{
// READ DUMP FILE
std : : string dump_filename = d_dump_filename ;
std : : ifstream : : pos_type size ;
int32_t number_of_double_vars = 21 ;
int32_t number_of_uint32_vars = 2 ;
int32_t number_of_uint8_vars = 3 ;
int32_t number_of_float_vars = 2 ;
int32_t epoch_size_bytes = sizeof ( double ) * number_of_double_vars +
sizeof ( uint32_t ) * number_of_uint32_vars +
sizeof ( uint8_t ) * number_of_uint8_vars +
sizeof ( float ) * number_of_float_vars ;
std : : ifstream dump_file ;
std : : cout < < " Generating .mat file for " < < dump_filename < < std : : endl ;
dump_file . exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ;
try
{
dump_file . open ( dump_filename . c_str ( ) , std : : ios : : binary | std : : ios : : ate ) ;
}
catch ( const std : : ifstream : : failure & e )
{
std : : cerr < < " Problem opening dump file: " < < e . what ( ) < < std : : endl ;
return false ;
}
// count number of epochs and rewind
int64_t num_epoch = 0LL ;
if ( dump_file . is_open ( ) )
{
size = dump_file . tellg ( ) ;
num_epoch = static_cast < int64_t > ( size ) / static_cast < int64_t > ( epoch_size_bytes ) ;
dump_file . seekg ( 0 , std : : ios : : beg ) ;
}
else
{
return false ;
}
2018-12-03 15:25:11 +00:00
auto * TOW_at_current_symbol_ms = new uint32_t [ num_epoch ] ;
auto * week = new uint32_t [ num_epoch ] ;
auto * RX_time = new double [ num_epoch ] ;
auto * user_clk_offset = new double [ num_epoch ] ;
auto * pos_x = new double [ num_epoch ] ;
auto * pos_y = new double [ num_epoch ] ;
auto * pos_z = new double [ num_epoch ] ;
auto * vel_x = new double [ num_epoch ] ;
auto * vel_y = new double [ num_epoch ] ;
auto * vel_z = new double [ num_epoch ] ;
auto * cov_xx = new double [ num_epoch ] ;
auto * cov_yy = new double [ num_epoch ] ;
auto * cov_zz = new double [ num_epoch ] ;
auto * cov_xy = new double [ num_epoch ] ;
auto * cov_yz = new double [ num_epoch ] ;
auto * cov_zx = new double [ num_epoch ] ;
auto * latitude = new double [ num_epoch ] ;
auto * longitude = new double [ num_epoch ] ;
auto * height = new double [ num_epoch ] ;
auto * valid_sats = new uint8_t [ num_epoch ] ;
auto * solution_status = new uint8_t [ num_epoch ] ;
auto * solution_type = new uint8_t [ num_epoch ] ;
auto * AR_ratio_factor = new float [ num_epoch ] ;
auto * AR_ratio_threshold = new float [ num_epoch ] ;
auto * gdop = new double [ num_epoch ] ;
auto * pdop = new double [ num_epoch ] ;
auto * hdop = new double [ num_epoch ] ;
auto * vdop = new double [ num_epoch ] ;
2018-10-31 13:56:59 +00:00
try
{
if ( dump_file . is_open ( ) )
{
for ( int64_t i = 0 ; i < num_epoch ; i + + )
{
dump_file . read ( reinterpret_cast < char * > ( & TOW_at_current_symbol_ms [ i ] ) , sizeof ( uint32_t ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & week [ i ] ) , sizeof ( uint32_t ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & RX_time [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & user_clk_offset [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & pos_x [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & pos_y [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & pos_z [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & vel_x [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & vel_y [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & vel_z [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_xx [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_yy [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_zz [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_xy [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_yz [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & cov_zx [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & latitude [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & longitude [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & height [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & valid_sats [ i ] ) , sizeof ( uint8_t ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & solution_status [ i ] ) , sizeof ( uint8_t ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & solution_type [ i ] ) , sizeof ( uint8_t ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & AR_ratio_factor [ i ] ) , sizeof ( float ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & AR_ratio_threshold [ i ] ) , sizeof ( float ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & gdop [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & pdop [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & hdop [ i ] ) , sizeof ( double ) ) ;
dump_file . read ( reinterpret_cast < char * > ( & vdop [ i ] ) , sizeof ( double ) ) ;
}
}
dump_file . close ( ) ;
}
catch ( const std : : ifstream : : failure & e )
{
std : : cerr < < " Problem reading dump file: " < < e . what ( ) < < std : : endl ;
delete [ ] TOW_at_current_symbol_ms ;
delete [ ] week ;
delete [ ] RX_time ;
delete [ ] user_clk_offset ;
delete [ ] pos_x ;
delete [ ] pos_y ;
delete [ ] pos_z ;
delete [ ] vel_x ;
delete [ ] vel_y ;
delete [ ] vel_z ;
delete [ ] cov_xx ;
delete [ ] cov_yy ;
delete [ ] cov_zz ;
delete [ ] cov_xy ;
delete [ ] cov_yz ;
delete [ ] cov_zx ;
delete [ ] latitude ;
delete [ ] longitude ;
delete [ ] height ;
delete [ ] valid_sats ;
delete [ ] solution_status ;
delete [ ] solution_type ;
delete [ ] AR_ratio_factor ;
delete [ ] AR_ratio_threshold ;
delete [ ] gdop ;
delete [ ] pdop ;
delete [ ] hdop ;
delete [ ] vdop ;
return false ;
}
// WRITE MAT FILE
mat_t * matfp ;
matvar_t * matvar ;
std : : string filename = dump_filename ;
filename . erase ( filename . length ( ) - 4 , 4 ) ;
filename . append ( " .mat " ) ;
2018-12-03 09:05:47 +00:00
matfp = Mat_CreateVer ( filename . c_str ( ) , nullptr , MAT_FT_MAT73 ) ;
if ( reinterpret_cast < int64_t * > ( matfp ) ! = nullptr )
2018-10-31 13:56:59 +00:00
{
size_t dims [ 2 ] = { 1 , static_cast < size_t > ( num_epoch ) } ;
matvar = Mat_VarCreate ( " TOW_at_current_symbol_ms " , MAT_C_UINT32 , MAT_T_UINT32 , 2 , dims , TOW_at_current_symbol_ms , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " week " , MAT_C_UINT32 , MAT_T_UINT32 , 2 , dims , week , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " RX_time " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , RX_time , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " user_clk_offset " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , user_clk_offset , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " pos_x " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , pos_x , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " pos_y " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , pos_y , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " pos_z " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , pos_z , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " vel_x " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , vel_x , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " vel_y " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , vel_y , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " vel_z " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , vel_z , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_xx " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_xx , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_yy " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_yy , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_zz " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_zz , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_xy " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_xy , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_yz " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_yz , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " cov_zx " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , cov_zx , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " latitude " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , latitude , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " longitude " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , longitude , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " height " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , height , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " valid_sats " , MAT_C_UINT8 , MAT_T_UINT8 , 2 , dims , valid_sats , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " solution_status " , MAT_C_UINT8 , MAT_T_UINT8 , 2 , dims , solution_status , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " solution_type " , MAT_C_UINT8 , MAT_T_UINT8 , 2 , dims , solution_type , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " AR_ratio_factor " , MAT_C_SINGLE , MAT_T_SINGLE , 2 , dims , AR_ratio_factor , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " AR_ratio_threshold " , MAT_C_SINGLE , MAT_T_SINGLE , 2 , dims , AR_ratio_threshold , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " gdop " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , gdop , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " pdop " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , pdop , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " hdop " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , hdop , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " vdop " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , vdop , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
}
Mat_Close ( matfp ) ;
delete [ ] TOW_at_current_symbol_ms ;
delete [ ] week ;
delete [ ] RX_time ;
delete [ ] user_clk_offset ;
delete [ ] pos_x ;
delete [ ] pos_y ;
delete [ ] pos_z ;
delete [ ] vel_x ;
delete [ ] vel_y ;
delete [ ] vel_z ;
delete [ ] cov_xx ;
delete [ ] cov_yy ;
delete [ ] cov_zz ;
delete [ ] cov_xy ;
delete [ ] cov_yz ;
delete [ ] cov_zx ;
delete [ ] latitude ;
delete [ ] longitude ;
delete [ ] height ;
delete [ ] valid_sats ;
delete [ ] solution_status ;
delete [ ] solution_type ;
delete [ ] AR_ratio_factor ;
delete [ ] AR_ratio_threshold ;
delete [ ] gdop ;
delete [ ] pdop ;
delete [ ] hdop ;
delete [ ] vdop ;
return true ;
}
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
}
2018-10-31 13:56:59 +00:00
catch ( const std : : exception & ex )
2018-03-03 01:03:39 +00:00
{
2018-08-29 16:53:03 +00:00
LOG ( WARNING ) < < " Exception in destructor closing the RTKLIB dump file " < < ex . what ( ) ;
2018-03-03 01:03:39 +00:00
}
2017-08-15 23:01:59 +00:00
}
2018-10-31 13:56:59 +00:00
if ( d_flag_dump_mat_enabled )
{
save_matfile ( ) ;
}
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-10-31 13:56:59 +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 ) ;
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 1C " )
2018-06-08 09:01:29 +00:00
{
band1 = true ;
}
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 2S " )
2018-06-08 09:01:29 +00:00
{
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
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 1B " )
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 ( ) )
{
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-12-02 14:42:38 +00:00
if ( sig_ = = " 5X " )
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-12-03 15:25:11 +00:00
auto default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
2018-03-03 01:03:39 +00:00
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 ) ;
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 1C " )
2018-03-03 01:03:39 +00:00
{
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)
2018-12-02 14:42:38 +00:00
if ( ( sig_ = = " 2S " ) 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-12-03 15:25:11 +00:00
auto default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
2018-03-03 01:03:39 +00:00
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-12-02 14:42:38 +00:00
if ( sig_ = = " L5 " )
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 ( ) )
{
// 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-12-03 15:25:11 +00:00
auto default_code_ = static_cast < unsigned char > ( CODE_NONE ) ;
2018-03-03 01:03:39 +00:00
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
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 1G " )
2018-03-03 01:03:39 +00:00
{
// 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
2018-12-02 14:42:38 +00:00
if ( sig_ = = " 2G " )
2018-03-03 01:03:39 +00:00
{
// 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 ;
2018-12-08 17:49:31 +00:00
for ( auto & i : nav_data . lam )
2017-08-15 23:01:59 +00:00
{
2018-12-03 17:03:25 +00:00
i [ 0 ] = SPEED_OF_LIGHT / FREQ1 ; // L1/E1
i [ 1 ] = SPEED_OF_LIGHT / FREQ2 ; // L2
i [ 2 ] = SPEED_OF_LIGHT / FREQ5 ; // L5/E5
2017-08-15 23:01:59 +00:00
}
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-11-07 18:33:54 +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-11-07 18:33:54 +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-11-07 18:33:54 +00:00
pvt_ssat [ i ] = rtk_ . ssat [ i ] ;
2018-11-07 15:03:45 +00:00
if ( rtk_ . ssat [ i ] . vs = = 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 ;
2018-12-08 17:49:31 +00:00
for ( auto & i : rtk_ . ssat )
2018-05-07 12:34:53 +00:00
{
2018-12-03 17:03:25 +00:00
if ( i . vs = = 1 )
2018-05-07 12:34:53 +00:00
{
2018-12-03 17:03:25 +00:00
azel [ 2 * index_aux ] = i . azel [ 0 ] ;
azel [ 2 * index_aux + 1 ] = i . azel [ 1 ] ;
2018-05-07 12:34:53 +00:00
index_aux + + ;
}
}
2018-11-05 14:39:56 +00:00
if ( index_aux > 0 ) dops ( index_aux , azel . data ( ) , 0.0 , dop_ ) ;
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-11-06 13:39:57 +00:00
//compute Ground speed and COG
double ground_speed_ms = 0.0 ;
double pos [ 3 ] ;
double enuv [ 3 ] ;
ecef2pos ( pvt_sol . rr , pos ) ;
ecef2enu ( pos , & pvt_sol . rr [ 3 ] , enuv ) ;
this - > set_speed_over_ground ( norm_rtk ( enuv , 2 ) ) ;
double new_cog ;
if ( ground_speed_ms > = 1.0 )
{
new_cog = atan2 ( enuv [ 0 ] , enuv [ 1 ] ) * R2D ;
if ( new_cog < 0.0 ) new_cog + = 360.0 ;
this - > set_course_over_ground ( new_cog ) ;
}
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 ) ;
2018-11-08 16:13:11 +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-08-29 16:53:03 +00:00
uint32_t tmp_uint32 ;
// TOW
tmp_uint32 = gnss_observables_map . begin ( ) - > second . TOW_at_current_symbol_ms ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_uint32 ) , sizeof ( uint32_t ) ) ;
2018-08-29 16:53:03 +00:00
// WEEK
tmp_uint32 = adjgpsweek ( nav_data . eph [ 0 ] . week ) ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_uint32 ) , sizeof ( uint32_t ) ) ;
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 ;
2018-10-31 13:56:59 +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 ) ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-08-29 16:53:03 +00:00
// ECEF POS X,Y,X [m] + ECEF VEL X,Y,X [m/s] (6 x double)
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 0 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 1 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 2 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 3 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 4 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . rr [ 5 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-08-29 16:53:03 +00:00
2018-09-01 14:53:27 +00:00
// position variance/covariance (m^2) {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} (6 x double)
tmp_double = pvt_sol . qr [ 0 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . qr [ 1 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . qr [ 2 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . qr [ 3 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . qr [ 4 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-09-01 14:53:27 +00:00
tmp_double = pvt_sol . qr [ 5 ] ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-08-29 16:53:03 +00:00
2017-08-15 23:01:59 +00:00
// GEO user position Latitude [deg]
2018-08-29 16:53:03 +00:00
tmp_double = get_latitude ( ) ;
2018-10-31 13:56:59 +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]
2018-08-29 16:53:03 +00:00
tmp_double = get_longitude ( ) ;
2018-10-31 13:56:59 +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]
2018-08-29 16:53:03 +00:00
tmp_double = get_height ( ) ;
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & tmp_double ) , sizeof ( double ) ) ;
2018-08-29 16:53:03 +00:00
// NUMBER OF VALID SATS
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & pvt_sol . ns ) , sizeof ( uint8_t ) ) ;
2018-08-29 16:53:03 +00:00
// RTKLIB solution status
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & pvt_sol . stat ) , sizeof ( uint8_t ) ) ;
2018-08-29 16:53:03 +00:00
// RTKLIB solution type (0:xyz-ecef,1:enu-baseline)
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & pvt_sol . type ) , sizeof ( uint8_t ) ) ;
2018-09-01 14:53:27 +00:00
// AR ratio factor for validation
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & pvt_sol . ratio ) , sizeof ( float ) ) ;
2018-09-01 14:53:27 +00:00
// AR ratio threshold for validation
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & pvt_sol . thres ) , sizeof ( float ) ) ;
2018-08-29 16:53:03 +00:00
2018-08-31 08:03:35 +00:00
// GDOP / PDOP/ HDOP/ VDOP
2018-10-31 13:56:59 +00:00
d_dump_file . write ( reinterpret_cast < char * > ( & dop_ [ 0 ] ) , sizeof ( double ) ) ;
d_dump_file . write ( reinterpret_cast < char * > ( & dop_ [ 1 ] ) , sizeof ( double ) ) ;
d_dump_file . write ( reinterpret_cast < char * > ( & dop_ [ 2 ] ) , sizeof ( double ) ) ;
d_dump_file . write ( reinterpret_cast < char * > ( & dop_ [ 3 ] ) , sizeof ( double ) ) ;
2018-03-03 01:03:39 +00:00
}
2018-10-31 13:56:59 +00:00
catch ( const std : : ifstream : : failure & e )
2018-03-03 01:03:39 +00:00
{
2018-08-29 16:53:03 +00:00
LOG ( WARNING ) < < " Exception writing RTKLIB 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
}