2018-09-13 14:36:21 +00:00
/*!
2019-02-28 20:45:30 +00:00
* \ file hybrid_observables_test_fpga . cc
2018-09-13 14:36:21 +00:00
* \ brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking
* implementation based on some input parameters .
2019-12-21 16:49:01 +00:00
* \ authors < ul >
* < li > Marc Majoral , 2019. mmajoral ( at ) cttc . cat
* < li > Javier Arribas , 2018. jarribas ( at ) cttc . es
* < / ul >
2018-09-13 14:36:21 +00:00
*
*
2020-07-28 14:57:15 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-09-13 14:36:21 +00:00
*
2020-12-30 12:35:06 +00:00
* GNSS - SDR is a Global Navigation Satellite System software - defined receiver .
2018-09-13 14:36:21 +00:00
* This file is part of GNSS - SDR .
*
2020-12-30 12:35:06 +00:00
* Copyright ( C ) 2012 - 2020 ( see AUTHORS file for a list of contributors )
2020-02-08 00:20:02 +00:00
* SPDX - License - Identifier : GPL - 3.0 - or - later
2018-09-13 14:36:21 +00:00
*
2020-07-28 14:57:15 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2018-09-13 14:36:21 +00:00
*/
# include "GPS_L1_CA.h"
2019-12-16 17:44:22 +00:00
# include "GPS_L5.h"
# include "Galileo_E1.h"
# include "Galileo_E5a.h"
# include "acquisition_msg_rx.h"
2019-12-21 12:25:17 +00:00
# include "fpga_switch.h"
# include "galileo_e1_pcps_ambiguous_acquisition_fpga.h"
# include "galileo_e5a_pcps_acquisition_fpga.h"
2018-09-13 14:36:21 +00:00
# include "gnss_block_factory.h"
# include "gnss_block_interface.h"
2019-02-27 16:27:31 +00:00
# include "gnss_satellite.h"
2022-12-19 19:55:06 +00:00
# include "gnss_sdr_fpga_sample_counter.h"
2018-09-13 14:36:21 +00:00
# include "gnss_synchro.h"
2019-02-27 16:27:31 +00:00
# include "gnuplot_i.h"
2019-12-21 12:25:17 +00:00
# include "gps_l1_ca_dll_pll_tracking_fpga.h"
# include "gps_l1_ca_pcps_acquisition_fpga.h"
# include "gps_l5i_pcps_acquisition_fpga.h"
2018-09-13 14:36:21 +00:00
# include "hybrid_observables.h"
2019-02-27 16:27:31 +00:00
# include "in_memory_configuration.h"
# include "observable_tests_flags.h"
# include "observables_dump_reader.h"
2018-09-13 14:36:21 +00:00
# include "signal_generator_flags.h"
2019-02-27 16:27:31 +00:00
# include "telemetry_decoder_interface.h"
2018-09-13 14:36:21 +00:00
# include "test_flags.h"
2019-02-27 16:27:31 +00:00
# include "tlm_dump_reader.h"
# include "tracking_dump_reader.h"
# include "tracking_interface.h"
2018-09-13 14:36:21 +00:00
# include "tracking_tests_flags.h"
2019-02-27 16:27:31 +00:00
# include "tracking_true_obs_reader.h"
# include "true_observables_reader.h"
# include <armadillo>
2019-12-16 17:44:22 +00:00
# include <boost/lexical_cast.hpp>
2019-02-27 16:27:31 +00:00
# include <gnuradio/blocks/file_source.h>
# include <gnuradio/blocks/interleaved_char_to_complex.h>
# include <gnuradio/blocks/null_sink.h>
2019-12-16 17:44:22 +00:00
# include <gnuradio/filter/firdes.h>
2019-02-27 16:27:31 +00:00
# include <gnuradio/top_block.h>
# include <gtest/gtest.h>
# include <matio.h>
2021-10-30 03:43:22 +00:00
# include <pmt/pmt.h>
2019-02-27 16:27:31 +00:00
# include <chrono>
2019-12-16 17:44:22 +00:00
# include <cmath>
2019-02-27 16:27:31 +00:00
# include <exception>
2022-08-26 07:14:58 +00:00
# include <iomanip>
2019-12-21 12:25:17 +00:00
# include <pthread.h>
2019-02-27 16:27:31 +00:00
# include <unistd.h>
2019-02-28 20:45:30 +00:00
# include <utility>
2021-10-30 03:43:22 +00:00
2022-07-05 11:46:58 +00:00
# if GNSSTK_USES_GPSTK_NAMESPACE
2022-07-10 17:19:37 +00:00
# include <gpstk/GPSWeekSecond.hpp>
2022-07-05 11:46:58 +00:00
# include <gpstk/Rinex3ObsBase.hpp>
# include <gpstk/Rinex3ObsData.hpp>
# include <gpstk/Rinex3ObsHeader.hpp>
# include <gpstk/Rinex3ObsStream.hpp>
# include <gpstk/RinexUtilities.hpp>
namespace gnsstk = gpstk ;
# else
2022-07-10 17:19:37 +00:00
# include <gnsstk/GPSWeekSecond.hpp>
2022-07-05 11:46:58 +00:00
# include <gnsstk/Rinex3ObsBase.hpp>
# include <gnsstk/Rinex3ObsData.hpp>
# include <gnsstk/Rinex3ObsHeader.hpp>
# include <gnsstk/Rinex3ObsStream.hpp>
# include <gnsstk/RinexUtilities.hpp>
# endif
2020-04-26 06:41:49 +00:00
# if HAS_GENERIC_LAMBDA
# else
2020-06-06 21:41:38 +00:00
# include <boost/bind/bind.hpp>
2020-04-26 06:41:49 +00:00
# endif
2021-10-30 03:43:22 +00:00
2019-12-16 17:44:22 +00:00
# ifdef GR_GREATER_38
# include <gnuradio/filter/fir_filter_blk.h>
# else
# include <gnuradio/filter/fir_filter_ccf.h>
# endif
2020-11-03 19:51:57 +00:00
2021-10-30 03:43:22 +00:00
# if PMT_USES_BOOST_ANY
namespace wht = boost ;
# else
namespace wht = std ;
# endif
2018-09-13 14:36:21 +00:00
class HybridObservablesTest_msg_rx_Fpga ;
2020-11-03 19:51:57 +00:00
using HybridObservablesTest_msg_rx_Fpga_sptr = gnss_shared_ptr < HybridObservablesTest_msg_rx_Fpga > ;
2018-09-13 14:36:21 +00:00
HybridObservablesTest_msg_rx_Fpga_sptr HybridObservablesTest_msg_rx_Fpga_make ( ) ;
class HybridObservablesTest_msg_rx_Fpga : public gr : : block
{
private :
friend HybridObservablesTest_msg_rx_Fpga_sptr HybridObservablesTest_msg_rx_Fpga_make ( ) ;
2020-08-03 06:13:21 +00:00
void msg_handler_channel_events ( const pmt : : pmt_t msg ) ;
2018-09-13 14:36:21 +00:00
HybridObservablesTest_msg_rx_Fpga ( ) ;
public :
int rx_message ;
~ HybridObservablesTest_msg_rx_Fpga ( ) ; //!< Default destructor
} ;
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
HybridObservablesTest_msg_rx_Fpga_sptr HybridObservablesTest_msg_rx_Fpga_make ( )
{
return HybridObservablesTest_msg_rx_Fpga_sptr ( new HybridObservablesTest_msg_rx_Fpga ( ) ) ;
}
2020-05-18 20:50:34 +00:00
2020-08-03 06:13:21 +00:00
void HybridObservablesTest_msg_rx_Fpga : : msg_handler_channel_events ( const pmt : : pmt_t msg )
2018-09-13 14:36:21 +00:00
{
try
{
2019-02-28 20:45:30 +00:00
int64_t message = pmt : : to_long ( std : : move ( msg ) ) ;
2018-09-13 14:36:21 +00:00
rx_message = message ;
}
2021-10-30 03:43:22 +00:00
catch ( const wht : : bad_any_cast & e )
2018-09-13 14:36:21 +00:00
{
2020-08-03 06:13:21 +00:00
LOG ( WARNING ) < < " msg_handler_channel_events Bad any_cast: " < < e . what ( ) ;
2018-09-13 14:36:21 +00:00
rx_message = 0 ;
}
}
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
HybridObservablesTest_msg_rx_Fpga : : HybridObservablesTest_msg_rx_Fpga ( ) : gr : : block ( " HybridObservablesTest_msg_rx " , gr : : io_signature : : make ( 0 , 0 , 0 ) , gr : : io_signature : : make ( 0 , 0 , 0 ) )
{
this - > message_port_register_in ( pmt : : mp ( " events " ) ) ;
2020-04-26 06:41:49 +00:00
this - > set_msg_handler ( pmt : : mp ( " events " ) ,
# if HAS_GENERIC_LAMBDA
2020-08-03 06:13:21 +00:00
[ this ] ( auto & & PH1 ) { msg_handler_channel_events ( PH1 ) ; } ) ;
2020-04-26 06:41:49 +00:00
# else
2020-06-12 22:32:40 +00:00
# if USE_BOOST_BIND_PLACEHOLDERS
2020-08-03 06:13:21 +00:00
boost : : bind ( & HybridObservablesTest_msg_rx_Fpga : : msg_handler_channel_events , this , boost : : placeholders : : _1 ) ) ;
2020-05-18 20:50:34 +00:00
# else
2020-08-03 06:13:21 +00:00
boost : : bind ( & HybridObservablesTest_msg_rx_Fpga : : msg_handler_channel_events , this , _1 ) ) ;
2020-05-18 20:50:34 +00:00
# endif
2020-04-26 06:41:49 +00:00
# endif
2018-09-13 14:36:21 +00:00
rx_message = 0 ;
}
2020-05-18 20:50:34 +00:00
2019-02-28 20:45:30 +00:00
HybridObservablesTest_msg_rx_Fpga : : ~ HybridObservablesTest_msg_rx_Fpga ( ) = default ;
2018-09-13 14:36:21 +00:00
class HybridObservablesTest_tlm_msg_rx_Fpga ;
2020-05-18 20:50:34 +00:00
2020-04-02 11:23:20 +00:00
using HybridObservablesTest_tlm_msg_rx_Fpga_sptr = std : : shared_ptr < HybridObservablesTest_tlm_msg_rx_Fpga > ;
2018-09-13 14:36:21 +00:00
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
HybridObservablesTest_tlm_msg_rx_Fpga_sptr HybridObservablesTest_tlm_msg_rx_Fpga_make ( ) ;
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
class HybridObservablesTest_tlm_msg_rx_Fpga : public gr : : block
{
private :
friend HybridObservablesTest_tlm_msg_rx_Fpga_sptr HybridObservablesTest_tlm_msg_rx_Fpga_make ( ) ;
2020-08-03 06:13:21 +00:00
void msg_handler_channel_events ( const pmt : : pmt_t msg ) ;
2018-09-13 14:36:21 +00:00
HybridObservablesTest_tlm_msg_rx_Fpga ( ) ;
public :
int rx_message ;
~ HybridObservablesTest_tlm_msg_rx_Fpga ( ) ; //!< Default destructor
} ;
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
HybridObservablesTest_tlm_msg_rx_Fpga_sptr HybridObservablesTest_tlm_msg_rx_Fpga_make ( )
{
return HybridObservablesTest_tlm_msg_rx_Fpga_sptr ( new HybridObservablesTest_tlm_msg_rx_Fpga ( ) ) ;
}
2020-05-18 20:50:34 +00:00
2020-08-03 06:13:21 +00:00
void HybridObservablesTest_tlm_msg_rx_Fpga : : msg_handler_channel_events ( const pmt : : pmt_t msg )
2018-09-13 14:36:21 +00:00
{
try
{
2019-02-28 20:45:30 +00:00
int64_t message = pmt : : to_long ( std : : move ( msg ) ) ;
2018-09-13 14:36:21 +00:00
rx_message = message ;
}
2021-10-30 03:43:22 +00:00
catch ( const wht : : bad_any_cast & e )
2018-09-13 14:36:21 +00:00
{
2020-08-03 06:13:21 +00:00
LOG ( WARNING ) < < " msg_handler_channel_events Bad any_cast: " < < e . what ( ) ;
2018-09-13 14:36:21 +00:00
rx_message = 0 ;
}
}
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
HybridObservablesTest_tlm_msg_rx_Fpga : : HybridObservablesTest_tlm_msg_rx_Fpga ( ) : gr : : block ( " HybridObservablesTest_tlm_msg_rx_Fpga " , gr : : io_signature : : make ( 0 , 0 , 0 ) , gr : : io_signature : : make ( 0 , 0 , 0 ) )
{
this - > message_port_register_in ( pmt : : mp ( " events " ) ) ;
2020-08-03 06:13:21 +00:00
this - > set_msg_handler ( pmt : : mp ( " events " ) , boost : : bind ( & HybridObservablesTest_tlm_msg_rx_Fpga : : msg_handler_channel_events , this , boost : : placeholders : : _1 ) ) ;
2018-09-13 14:36:21 +00:00
rx_message = 0 ;
}
2020-05-18 20:50:34 +00:00
2019-02-28 20:45:30 +00:00
HybridObservablesTest_tlm_msg_rx_Fpga : : ~ HybridObservablesTest_tlm_msg_rx_Fpga ( ) = default ;
2018-09-13 14:36:21 +00:00
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
class HybridObservablesTestFpga : public : : testing : : Test
{
public :
std : : string generator_binary ;
std : : string p1 ;
std : : string p2 ;
std : : string p3 ;
std : : string p4 ;
std : : string p5 ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
std : : string implementation = FLAGS_trk_test_implementation ;
const int baseband_sampling_freq = FLAGS_fs_gen_sps ;
std : : string filename_rinex_obs = FLAGS_filename_rinex_obs ;
std : : string filename_raw_data = FLAGS_filename_raw_data ;
2024-04-29 06:27:33 +00:00
# else
std : : string implementation = absl : : GetFlag ( FLAGS_trk_test_implementation ) ;
const int baseband_sampling_freq = absl : : GetFlag ( FLAGS_fs_gen_sps ) ;
std : : string filename_rinex_obs = absl : : GetFlag ( FLAGS_filename_rinex_obs ) ;
std : : string filename_raw_data = absl : : GetFlag ( FLAGS_filename_raw_data ) ;
# endif
2018-09-13 14:36:21 +00:00
int configure_generator ( ) ;
int generate_signal ( ) ;
bool save_mat_xy ( std : : vector < double > & x , std : : vector < double > & y , std : : string filename ) ;
void check_results_carrier_phase (
arma : : mat & true_ch0 ,
arma : : vec & true_tow_s ,
arma : : mat & measured_ch0 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
void check_results_carrier_phase_double_diff (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
void check_results_carrier_doppler ( arma : : mat & true_ch0 ,
arma : : vec & true_tow_s ,
arma : : mat & measured_ch0 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
void check_results_carrier_doppler_double_diff (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
void check_results_code_pseudorange (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
void check_results_duplicated_satellite (
arma : : mat & measured_sat1 ,
arma : : mat & measured_sat2 ,
int ch_id ,
const std : : string & data_title ) ;
2018-09-13 14:36:21 +00:00
HybridObservablesTestFpga ( )
{
factory = std : : make_shared < GNSSBlockFactory > ( ) ;
config = std : : make_shared < InMemoryConfiguration > ( ) ;
item_size = sizeof ( gr_complex ) ;
}
2019-02-28 20:45:30 +00:00
~ HybridObservablesTestFpga ( ) = default ;
2018-09-13 14:36:21 +00:00
bool ReadRinexObs ( std : : vector < arma : : mat > * obs_vec , Gnss_Synchro gnss ) ;
bool acquire_signal ( ) ;
void configure_receiver (
double PLL_wide_bw_hz ,
double DLL_wide_bw_hz ,
double PLL_narrow_bw_hz ,
double DLL_narrow_bw_hz ,
2019-12-16 17:44:22 +00:00
int extend_correlation_symbols ,
uint32_t smoother_length ,
bool high_dyn ) ;
2018-09-13 14:36:21 +00:00
gr : : top_block_sptr top_block ;
std : : shared_ptr < GNSSBlockFactory > factory ;
std : : shared_ptr < InMemoryConfiguration > config ;
Gnss_Synchro gnss_synchro_master ;
std : : vector < Gnss_Synchro > gnss_synchro_vec ;
size_t item_size ;
2019-06-28 23:28:30 +00:00
pthread_mutex_t mutex_obs_test = PTHREAD_MUTEX_INITIALIZER ;
2019-12-16 17:44:22 +00:00
static const int32_t TEST_OBS_SKIP_SAMPLES = 1024 ;
2019-12-30 16:50:41 +00:00
static constexpr float DMA_SIGNAL_SCALING_FACTOR = 8.0 ;
2018-09-13 14:36:21 +00:00
} ;
2020-05-18 20:50:34 +00:00
2018-09-13 14:36:21 +00:00
int HybridObservablesTestFpga : : configure_generator ( )
{
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
// Configure signal generator
generator_binary = FLAGS_generator_binary ;
p1 = std : : string ( " -rinex_nav_file= " ) + FLAGS_rinex_nav_file ;
if ( FLAGS_dynamic_position . empty ( ) )
{
p2 = std : : string ( " -static_position= " ) + FLAGS_static_position + std : : string ( " , " ) + std : : to_string ( FLAGS_duration * 10 ) ;
}
else
{
p2 = std : : string ( " -obs_pos_file= " ) + std : : string ( FLAGS_dynamic_position ) ;
}
p3 = std : : string ( " -rinex_obs_file= " ) + FLAGS_filename_rinex_obs ; // RINEX 2.10 observation file output
p4 = std : : string ( " -sig_out_file= " ) + FLAGS_filename_raw_data ; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
2019-08-18 23:29:04 +00:00
p5 = std : : string ( " -sampling_freq= " ) + std : : to_string ( baseband_sampling_freq ) ; // Baseband sampling frequency [MSps]
2024-04-29 06:27:33 +00:00
# else
// Configure signal generator
generator_binary = absl : : GetFlag ( FLAGS_generator_binary ) ;
p1 = std : : string ( " -rinex_nav_file= " ) + absl : : GetFlag ( FLAGS_rinex_nav_file ) ;
if ( absl : : GetFlag ( FLAGS_dynamic_position ) . empty ( ) )
{
p2 = std : : string ( " -static_position= " ) + absl : : GetFlag ( FLAGS_static_position ) + std : : string ( " , " ) + std : : to_string ( absl : : GetFlag ( FLAGS_duration ) * 10 ) ;
}
else
{
p2 = std : : string ( " -obs_pos_file= " ) + std : : string ( absl : : GetFlag ( FLAGS_dynamic_position ) ) ;
}
p3 = std : : string ( " -rinex_obs_file= " ) + absl : : GetFlag ( FLAGS_filename_rinex_obs ) ; // RINEX 2.10 observation file output
p4 = std : : string ( " -sig_out_file= " ) + absl : : GetFlag ( FLAGS_filename_raw_data ) ; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
p5 = std : : string ( " -sampling_freq= " ) + std : : to_string ( baseband_sampling_freq ) ; // Baseband sampling frequency [MSps]
# endif
2018-09-13 14:36:21 +00:00
return 0 ;
}
int HybridObservablesTestFpga : : generate_signal ( )
{
int child_status ;
2019-02-28 20:45:30 +00:00
char * const parmList [ ] = { & generator_binary [ 0 ] , & generator_binary [ 0 ] , & p1 [ 0 ] , & p2 [ 0 ] , & p3 [ 0 ] , & p4 [ 0 ] , & p5 [ 0 ] , nullptr } ;
2018-09-13 14:36:21 +00:00
int pid ;
if ( ( pid = fork ( ) ) = = - 1 )
2019-12-30 17:43:46 +00:00
{
perror ( " fork err " ) ;
}
2018-09-13 14:36:21 +00:00
else if ( pid = = 0 )
{
execv ( & generator_binary [ 0 ] , parmList ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " Return not expected. Must be an execv err. \n " ;
2018-09-13 14:36:21 +00:00
std : : terminate ( ) ;
}
waitpid ( pid , & child_status , 0 ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " Signal and Observables RINEX and RAW files created. \n " ;
2018-09-13 14:36:21 +00:00
return 0 ;
}
2020-05-18 20:50:34 +00:00
2019-12-16 17:44:22 +00:00
struct DMA_handler_args_obs_test
{
std : : string file ;
int32_t nsamples_tx ;
int32_t skip_used_samples ;
unsigned int freq_band ; // 0 for GPS L1/ Galileo E1, 1 for GPS L5/Galileo E5
2019-12-30 16:50:41 +00:00
float scaling_factor ;
2019-12-16 17:44:22 +00:00
} ;
2020-05-18 20:50:34 +00:00
2019-12-16 17:44:22 +00:00
struct acquisition_handler_args_obs_test
{
2019-12-30 17:43:46 +00:00
std : : shared_ptr < AcquisitionInterface > acquisition ;
2019-12-16 17:44:22 +00:00
} ;
2018-09-13 14:36:21 +00:00
2020-05-18 20:50:34 +00:00
2019-12-16 17:44:22 +00:00
void * handler_acquisition_obs_test ( void * arguments )
2018-09-13 14:36:21 +00:00
{
2019-12-30 17:43:46 +00:00
// the acquisition is a blocking function so we have to
// create a thread
auto * args = ( struct acquisition_handler_args_obs_test * ) arguments ;
args - > acquisition - > reset ( ) ;
return nullptr ;
2019-12-16 17:44:22 +00:00
}
2020-05-18 20:50:34 +00:00
2019-12-16 17:44:22 +00:00
void * handler_DMA_obs_test ( void * arguments )
{
2019-12-30 17:43:46 +00:00
const int MAX_INPUT_SAMPLES_TOTAL = 16384 ;
2019-12-16 17:44:22 +00:00
2019-12-30 17:43:46 +00:00
auto * args = ( struct DMA_handler_args_obs_test * ) arguments ;
2019-12-16 17:44:22 +00:00
2019-12-30 17:43:46 +00:00
std : : string Filename = args - > file ; // input filename
int32_t skip_used_samples = args - > skip_used_samples ;
int32_t nsamples_tx = args - > nsamples_tx ;
2019-12-16 17:44:22 +00:00
std : : vector < int8_t > input_samples ( MAX_INPUT_SAMPLES_TOTAL * 2 ) ;
std : : vector < int8_t > input_samples_dma ( MAX_INPUT_SAMPLES_TOTAL * 2 * 2 ) ;
bool file_completed = false ;
int32_t nsamples_remaining ;
int32_t nsamples_block_size ;
unsigned int dma_index ;
int tx_fd ; // DMA descriptor
std : : ifstream infile ;
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
infile . exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ;
try
2018-09-13 14:36:21 +00:00
{
2019-12-16 17:44:22 +00:00
infile . open ( Filename , std : : ios : : binary ) ;
2018-09-13 14:36:21 +00:00
}
2019-12-30 17:43:46 +00:00
catch ( const std : : ifstream : : failure & e )
2018-09-13 14:36:21 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Exception opening file " < < Filename < < ' \n ' ;
2019-12-16 17:44:22 +00:00
return nullptr ;
2018-09-13 14:36:21 +00:00
}
2022-06-02 19:41:19 +00:00
// *************************************************************************
2019-12-16 17:44:22 +00:00
// Open DMA device
2022-06-02 19:41:19 +00:00
// *************************************************************************
2019-12-16 17:44:22 +00:00
tx_fd = open ( " /dev/loop_tx " , O_WRONLY ) ;
if ( tx_fd < 0 )
2018-09-13 14:36:21 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cout < < " Cannot open loop device \n " ;
2019-12-16 17:44:22 +00:00
return nullptr ;
2018-09-13 14:36:21 +00:00
}
2019-12-16 17:44:22 +00:00
2024-04-29 06:27:33 +00:00
// *************************************************************************
// Open input file
// *************************************************************************
2019-12-16 17:44:22 +00:00
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
uint32_t skip_samples = static_cast < uint32_t > ( FLAGS_skip_samples ) ;
2024-04-29 06:27:33 +00:00
# else
uint32_t skip_samples = static_cast < uint32_t > ( absl : : GetFlag ( FLAGS_skip_samples ) ) ;
# endif
2019-12-30 17:43:46 +00:00
if ( skip_samples + skip_used_samples > 0 )
{
try
{
infile . ignore ( ( skip_samples + skip_used_samples ) * 2 ) ;
}
catch ( const std : : ifstream : : failure & e )
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Exception reading file " < < Filename < < ' \n ' ;
2019-12-30 17:43:46 +00:00
}
}
nsamples_remaining = nsamples_tx ;
nsamples_block_size = 0 ;
2019-12-16 17:44:22 +00:00
while ( file_completed = = false )
2018-09-13 14:36:21 +00:00
{
2019-12-16 17:44:22 +00:00
dma_index = 0 ;
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
if ( nsamples_remaining > MAX_INPUT_SAMPLES_TOTAL )
2019-12-30 17:43:46 +00:00
{
nsamples_block_size = MAX_INPUT_SAMPLES_TOTAL ;
}
2019-12-16 17:44:22 +00:00
else
2019-12-30 17:43:46 +00:00
{
nsamples_block_size = nsamples_remaining ;
}
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
try
{
// 2 bytes per complex sample
infile . read ( reinterpret_cast < char * > ( input_samples . data ( ) ) , nsamples_block_size * 2 ) ;
}
catch ( const std : : ifstream : : failure & e )
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Exception reading file " < < Filename < < ' \n ' ;
2019-12-30 17:43:46 +00:00
}
for ( int index0 = 0 ; index0 < ( nsamples_block_size * 2 ) ; index0 + = 2 )
{
if ( args - > freq_band = = 0 )
2019-12-16 17:44:22 +00:00
{
2019-12-30 17:43:46 +00:00
// channel 1 (queue 1) -> E5/L5
input_samples_dma [ dma_index ] = 0 ;
input_samples_dma [ dma_index + 1 ] = 0 ;
// channel 0 (queue 0) -> E1/L1
input_samples_dma [ dma_index + 2 ] = static_cast < int8_t > ( input_samples [ index0 ] * args - > scaling_factor ) ;
input_samples_dma [ dma_index + 3 ] = static_cast < int8_t > ( input_samples [ index0 + 1 ] * args - > scaling_factor ) ;
2019-12-16 17:44:22 +00:00
}
2019-12-30 17:43:46 +00:00
else
2019-12-16 17:44:22 +00:00
{
2019-12-30 17:43:46 +00:00
// channel 1 (queue 1) -> E5/L5
input_samples_dma [ dma_index ] = static_cast < int8_t > ( input_samples [ index0 ] * args - > scaling_factor ) ;
input_samples_dma [ dma_index + 1 ] = static_cast < int8_t > ( input_samples [ index0 + 1 ] * args - > scaling_factor ) ;
// channel 0 (queue 0) -> E1/L1
input_samples_dma [ dma_index + 2 ] = 0 ;
input_samples_dma [ dma_index + 3 ] = 0 ;
2019-12-16 17:44:22 +00:00
}
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
dma_index + = 4 ;
}
2018-09-13 14:36:21 +00:00
2020-07-07 16:53:50 +00:00
// std::cout << "DMA: sending nsamples_block_size = " << nsamples_block_size << " samples\n";
2019-12-30 17:43:46 +00:00
if ( write ( tx_fd , input_samples_dma . data ( ) , ( int ) ( nsamples_block_size * 4 ) ) ! = ( int ) ( nsamples_block_size * 4 ) )
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Error: DMA could not send all the required samples \n " ;
2019-12-30 17:43:46 +00:00
}
2019-02-27 16:27:31 +00:00
2019-12-30 17:43:46 +00:00
// Throttle the DMA
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ;
2019-02-27 16:27:31 +00:00
2019-12-16 17:44:22 +00:00
nsamples_remaining - = nsamples_block_size ;
2019-02-27 16:27:31 +00:00
2019-12-16 17:44:22 +00:00
if ( nsamples_remaining = = 0 )
{
file_completed = true ;
}
}
try
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
infile . close ( ) ;
2019-02-27 16:27:31 +00:00
}
2019-12-30 17:43:46 +00:00
catch ( const std : : ifstream : : failure & e )
2019-12-16 17:44:22 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Exception closing files " < < Filename < < ' \n ' ;
2019-12-16 17:44:22 +00:00
}
try
2019-08-17 12:59:20 +00:00
{
2019-12-30 17:43:46 +00:00
close ( tx_fd ) ;
2019-08-17 12:59:20 +00:00
}
2019-12-30 17:43:46 +00:00
catch ( const std : : ifstream : : failure & e )
2019-02-27 16:27:31 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cerr < < " Exception closing loop device \n " ;
2019-02-27 16:27:31 +00:00
}
2019-12-30 17:43:46 +00:00
return nullptr ;
2019-12-16 17:44:22 +00:00
}
2018-11-13 16:22:08 +00:00
2019-12-16 17:44:22 +00:00
// When using the FPGA the acquisition class calls the states
// of the channel finite state machine directly. This is done
// in order to reduce the latency of the receiver when going
// from acquisition to tracking. In order to execute the
// acquisition in the unit tests we need to create a derived
// class of the channel finite state machine. Some of the states
// of the channel state machine are modified here, in order to
// simplify the instantiation of the acquisition class in the
// unit test.
2019-12-30 17:43:46 +00:00
class ChannelFsm_obs_test : public ChannelFsm
2019-12-16 17:44:22 +00:00
{
public :
2019-12-30 17:43:46 +00:00
bool Event_valid_acquisition ( ) override
{
acquisition_successful = true ;
return true ;
}
2019-12-16 17:44:22 +00:00
2019-12-30 17:43:46 +00:00
bool Event_failed_acquisition_repeat ( ) override
{
acquisition_successful = false ;
return true ;
}
2019-02-27 16:27:31 +00:00
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
bool Event_failed_acquisition_no_repeat ( ) override
{
acquisition_successful = false ;
return true ;
}
2019-12-16 17:44:22 +00:00
2019-12-30 17:43:46 +00:00
bool Event_check_test_result ( )
{
return acquisition_successful ;
}
2019-12-16 17:44:22 +00:00
2019-12-30 17:43:46 +00:00
void Event_clear_test_result ( )
{
acquisition_successful = false ;
}
2019-12-16 17:44:22 +00:00
private :
2019-12-30 17:43:46 +00:00
bool acquisition_successful ;
2019-12-16 17:44:22 +00:00
} ;
2018-09-13 14:36:21 +00:00
2020-02-11 20:47:13 +00:00
2018-09-13 14:36:21 +00:00
bool HybridObservablesTestFpga : : acquire_signal ( )
{
2019-12-16 17:44:22 +00:00
pthread_t thread_DMA , thread_acquisition ;
2018-09-13 14:36:21 +00:00
// 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m)
2019-08-18 23:29:04 +00:00
int SV_ID = 1 ; // initial sv id
2018-11-13 16:22:08 +00:00
2019-12-16 17:44:22 +00:00
// fsm
std : : shared_ptr < ChannelFsm_obs_test > channel_fsm_ ;
channel_fsm_ = std : : make_shared < ChannelFsm_obs_test > ( ) ;
bool acquisition_successful ;
2018-09-13 14:36:21 +00:00
// Satellite signal definition
Gnss_Synchro tmp_gnss_synchro ;
tmp_gnss_synchro . Channel_ID = 0 ;
2020-02-11 20:47:13 +00:00
2018-09-13 14:36:21 +00:00
config - > set_property ( " GNSS-SDR.internal_fs_sps " , std : : to_string ( baseband_sampling_freq ) ) ;
2018-11-13 16:22:08 +00:00
2019-02-15 09:12:20 +00:00
std : : shared_ptr < AcquisitionInterface > acquisition ;
2018-09-13 14:36:21 +00:00
std : : string System_and_Signal ;
2019-12-16 17:44:22 +00:00
std : : string signal ;
2019-02-15 09:12:20 +00:00
struct DMA_handler_args_obs_test args ;
2019-12-16 17:44:22 +00:00
struct acquisition_handler_args_obs_test args_acq ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
std : : string file = FLAGS_signal_file ;
2024-04-29 06:27:33 +00:00
# else
std : : string file = absl : : GetFlag ( FLAGS_signal_file ) ;
# endif
2019-12-30 17:43:46 +00:00
args . file = file ; // DMA file configuration
2019-12-16 17:44:22 +00:00
// instantiate the FPGA switch and set the
// switch position to DMA.
std : : shared_ptr < Fpga_Switch > switch_fpga ;
2024-07-15 17:10:00 +00:00
switch_fpga = std : : make_shared < Fpga_Switch > ( ) ;
2019-12-30 17:43:46 +00:00
switch_fpga - > set_switch_position ( 0 ) ; // set switch position to DMA
2019-02-15 09:12:20 +00:00
2019-08-18 23:29:04 +00:00
// create the correspondign acquisition block according to the desired tracking signal
2024-08-08 20:30:45 +00:00
if ( implementation = = " GPS_L1_CA_DLL_PLL_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
2019-12-30 17:43:46 +00:00
tmp_gnss_synchro . System = ' G ' ;
signal = " 1C " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( tmp_gnss_synchro . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
tmp_gnss_synchro . PRN = SV_ID ;
System_and_Signal = " GPS L1 CA " ;
2019-12-16 17:44:22 +00:00
acquisition = std : : make_shared < GpsL1CaPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
args . freq_band = 0 ; // frequency band on which the DMA has to transfer the samples
2018-09-13 14:36:21 +00:00
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E1_DLL_PLL_VEML_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
2019-12-30 17:43:46 +00:00
tmp_gnss_synchro . System = ' E ' ;
signal = " 1B " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( tmp_gnss_synchro . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
tmp_gnss_synchro . PRN = SV_ID ;
System_and_Signal = " Galileo E1B " ;
2019-12-16 17:44:22 +00:00
acquisition = std : : make_shared < GalileoE1PcpsAmbiguousAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
args . freq_band = 0 ; // frequency band on which the DMA has to transfer the samples
2018-09-13 14:36:21 +00:00
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E5a_DLL_PLL_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
2019-12-30 17:43:46 +00:00
tmp_gnss_synchro . System = ' E ' ;
signal = " 5X " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( tmp_gnss_synchro . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
tmp_gnss_synchro . PRN = SV_ID ;
System_and_Signal = " Galileo E5a " ;
2019-12-16 17:44:22 +00:00
acquisition = std : : make_shared < GalileoE5aPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
args . freq_band = 1 ; // frequency band on which the DMA has to transfer the samples
2018-09-13 14:36:21 +00:00
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " GPS_L5_DLL_PLL_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
2019-12-30 17:43:46 +00:00
tmp_gnss_synchro . System = ' G ' ;
signal = " L5 " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( tmp_gnss_synchro . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
tmp_gnss_synchro . PRN = SV_ID ;
System_and_Signal = " GPS L5I " ;
2019-12-16 17:44:22 +00:00
acquisition = std : : make_shared < GpsL5iPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
2018-09-13 14:36:21 +00:00
2019-12-30 17:43:46 +00:00
args . freq_band = 1 ; // frequency band on which the DMA has to transfer the samples
2018-09-13 14:36:21 +00:00
}
else
{
std : : cout < < " The test can not run with the selected tracking implementation \n " ;
throw ( std : : exception ( ) ) ;
}
2019-12-16 17:44:22 +00:00
acquisition - > set_gnss_synchro ( & tmp_gnss_synchro ) ;
acquisition - > set_channel_fsm ( channel_fsm_ ) ;
2019-02-15 09:12:20 +00:00
acquisition - > set_channel ( 0 ) ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
acquisition - > set_doppler_max ( config - > property ( " Acquisition.doppler_max " , FLAGS_external_signal_acquisition_doppler_max_hz ) ) ;
acquisition - > set_doppler_step ( config - > property ( " Acquisition.doppler_step " , FLAGS_external_signal_acquisition_doppler_step_hz ) ) ;
acquisition - > set_doppler_center ( 0 ) ;
2019-02-15 09:12:20 +00:00
acquisition - > set_threshold ( config - > property ( " Acquisition.threshold " , FLAGS_external_signal_acquisition_threshold ) ) ;
2024-04-29 06:27:33 +00:00
# else
acquisition - > set_doppler_max ( config - > property ( " Acquisition.doppler_max " , absl : : GetFlag ( FLAGS_external_signal_acquisition_doppler_max_hz ) ) ) ;
acquisition - > set_doppler_step ( config - > property ( " Acquisition.doppler_step " , absl : : GetFlag ( FLAGS_external_signal_acquisition_doppler_step_hz ) ) ) ;
acquisition - > set_doppler_center ( 0 ) ;
acquisition - > set_threshold ( config - > property ( " Acquisition.threshold " , absl : : GetFlag ( FLAGS_external_signal_acquisition_threshold ) ) ) ;
# endif
2018-09-13 14:36:21 +00:00
std : : chrono : : time_point < std : : chrono : : system_clock > start , end ;
std : : chrono : : duration < double > elapsed_seconds ;
start = std : : chrono : : system_clock : : now ( ) ;
bool start_msg = true ;
unsigned int MAX_PRN_IDX = 0 ;
switch ( tmp_gnss_synchro . System )
{
case ' G ' :
MAX_PRN_IDX = 33 ;
break ;
case ' E ' :
MAX_PRN_IDX = 37 ;
break ;
default :
MAX_PRN_IDX = 33 ;
}
2019-12-16 17:44:22 +00:00
// number of samples that the DMA has to transfer
2019-02-27 16:27:31 +00:00
unsigned int nsamples_to_transfer ;
2024-08-08 20:30:45 +00:00
if ( implementation = = " GPS_L1_CA_DLL_PLL_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
2019-08-31 09:37:29 +00:00
nsamples_to_transfer = static_cast < unsigned int > ( std : : round ( static_cast < double > ( baseband_sampling_freq ) / ( GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS ) ) ) ;
2019-02-27 16:27:31 +00:00
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E1_DLL_PLL_VEML_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
2019-08-31 09:37:29 +00:00
nsamples_to_transfer = static_cast < unsigned int > ( std : : round ( static_cast < double > ( baseband_sampling_freq ) / ( GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS ) ) ) ;
2019-02-27 16:27:31 +00:00
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E5a_DLL_PLL_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
2019-08-31 09:37:29 +00:00
nsamples_to_transfer = static_cast < unsigned int > ( std : : round ( static_cast < double > ( baseband_sampling_freq ) / ( GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS ) ) ) ;
2019-02-27 16:27:31 +00:00
}
2024-08-08 20:30:45 +00:00
else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0))
2019-02-27 16:27:31 +00:00
{
2019-08-31 09:37:29 +00:00
nsamples_to_transfer = static_cast < unsigned int > ( std : : round ( static_cast < double > ( baseband_sampling_freq ) / ( GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS ) ) ) ;
2019-02-27 16:27:31 +00:00
}
2019-01-31 14:36:11 +00:00
2019-12-30 16:50:41 +00:00
// set the scaling factor
args . scaling_factor = DMA_SIGNAL_SCALING_FACTOR ;
2019-02-27 16:27:31 +00:00
for ( unsigned int PRN = 1 ; PRN < MAX_PRN_IDX ; PRN + + )
{
tmp_gnss_synchro . PRN = PRN ;
2019-01-31 14:36:11 +00:00
2019-12-30 17:43:46 +00:00
channel_fsm_ - > Event_clear_test_result ( ) ;
2019-12-16 17:44:22 +00:00
2019-02-27 16:27:31 +00:00
acquisition - > stop_acquisition ( ) ; // reset the whole system including the sample counters
acquisition - > init ( ) ;
acquisition - > set_local_code ( ) ;
2019-01-31 14:36:11 +00:00
2024-08-08 20:30:45 +00:00
if ( ( implementation = = " GPS_L1_CA_DLL_PLL_Tracking_FPGA " ) or ( implementation = = " Galileo_E1_DLL_PLL_VEML_Tracking_FPGA " ) )
2019-02-27 16:27:31 +00:00
{
2019-12-30 17:43:46 +00:00
// Skip the first TEST_OBS_SKIP_SAMPLES samples
2019-12-16 17:44:22 +00:00
args . skip_used_samples = 0 ;
2019-12-30 17:43:46 +00:00
args . nsamples_tx = TEST_OBS_SKIP_SAMPLES ; // limit is between 645 and 650 samples
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
// create DMA child process
2019-08-18 10:54:16 +00:00
if ( pthread_create ( & thread_DMA , nullptr , handler_DMA_obs_test , reinterpret_cast < void * > ( & args ) ) < 0 )
2019-02-27 16:27:31 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cout < < " ERROR cannot create DMA Process \n " ;
2019-02-27 16:27:31 +00:00
}
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
pthread_join ( thread_DMA , nullptr ) ;
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
args . skip_used_samples = TEST_OBS_SKIP_SAMPLES ;
2019-02-27 16:27:31 +00:00
}
else
{
args . skip_used_samples = 0 ;
}
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
// Configure the DMA to send the required samples to perform an acquisition
args . nsamples_tx = nsamples_to_transfer ;
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
// run the acquisition. The acquisition must run in a separate thread because it is a blocking function
args_acq . acquisition = acquisition ;
2019-02-04 14:01:50 +00:00
2019-12-16 17:44:22 +00:00
if ( pthread_create ( & thread_acquisition , nullptr , handler_acquisition_obs_test , reinterpret_cast < void * > ( & args_acq ) ) < 0 )
{
2020-07-07 16:53:50 +00:00
std : : cout < < " ERROR cannot create acquisition Process \n " ;
2019-12-16 17:44:22 +00:00
}
2019-01-31 14:36:11 +00:00
2019-02-27 16:27:31 +00:00
if ( start_msg = = true )
{
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2020-07-07 16:53:50 +00:00
std : : cout < < " Reading external signal file: " < < FLAGS_signal_file < < ' \n ' ;
2024-04-29 06:27:33 +00:00
# else
std : : cout < < " Reading external signal file: " < < absl : : GetFlag ( FLAGS_signal_file ) < < ' \n ' ;
# endif
2020-07-07 16:53:50 +00:00
std : : cout < < " Searching for " < < System_and_Signal < < " Satellites... \n " ;
2019-02-27 16:27:31 +00:00
std : : cout < < " [ " ;
start_msg = false ;
}
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
// wait to give time for the acquisition thread to set up the acquisition HW accelerator in the FPGA
usleep ( 1000000 ) ;
2019-01-31 14:36:11 +00:00
2019-12-16 17:44:22 +00:00
// create DMA child process
if ( pthread_create ( & thread_DMA , nullptr , handler_DMA_obs_test , reinterpret_cast < void * > ( & args ) ) < 0 )
2019-02-27 16:27:31 +00:00
{
2020-07-07 16:53:50 +00:00
std : : cout < < " ERROR cannot create DMA Process \n " ;
2019-02-27 16:27:31 +00:00
}
2018-11-16 17:28:02 +00:00
2019-12-16 17:44:22 +00:00
// wait until the acquisition is finished
pthread_join ( thread_acquisition , nullptr ) ;
// wait for the child DMA process to finish
pthread_join ( thread_DMA , nullptr ) ;
acquisition_successful = channel_fsm_ - > Event_check_test_result ( ) ;
if ( acquisition_successful )
2019-02-27 16:27:31 +00:00
{
std : : cout < < " " < < PRN < < " " ;
2018-11-16 17:28:02 +00:00
2019-02-27 16:27:31 +00:00
gnss_synchro_vec . push_back ( tmp_gnss_synchro ) ;
}
else
{
std : : cout < < " . " ;
}
2019-01-31 14:36:11 +00:00
2019-02-27 16:27:31 +00:00
std : : cout . flush ( ) ;
}
2019-12-16 17:44:22 +00:00
2020-07-07 16:53:50 +00:00
std : : cout < < " ] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout < < " ------------------------------------------- \n " ;
for ( auto & x : gnss_synchro_vec )
{
std : : cout < < " DETECTED SATELLITE " < < System_and_Signal
< < " PRN: " < < x . PRN
< < " with Doppler: " < < x . Acq_doppler_hz
< < " [Hz], code phase: " < < x . Acq_delay_samples
< < " [samples] at signal SampleStamp " < < x . Acq_samplestamp_samples < < " \n " ;
}
// report the elapsed time
end = std : : chrono : : system_clock : : now ( ) ;
elapsed_seconds = end - start ;
std : : cout < < " Total signal acquisition run time "
< < elapsed_seconds . count ( )
2020-07-07 16:53:50 +00:00
< < " [seconds] \n " ;
2019-02-28 20:45:30 +00:00
if ( ! gnss_synchro_vec . empty ( ) )
2018-09-13 14:36:21 +00:00
{
return true ;
}
else
{
return false ;
}
}
void HybridObservablesTestFpga : : configure_receiver (
double PLL_wide_bw_hz ,
double DLL_wide_bw_hz ,
double PLL_narrow_bw_hz ,
double DLL_narrow_bw_hz ,
2019-12-16 17:44:22 +00:00
int extend_correlation_symbols ,
uint32_t smoother_length ,
bool high_dyn )
2018-09-13 14:36:21 +00:00
{
config = std : : make_shared < InMemoryConfiguration > ( ) ;
2019-12-16 17:44:22 +00:00
if ( high_dyn )
{
config - > set_property ( " Tracking.high_dyn " , " true " ) ;
}
else
{
config - > set_property ( " Tracking.high_dyn " , " false " ) ;
}
2018-09-13 14:36:21 +00:00
config - > set_property ( " Tracking.implementation " , implementation ) ;
config - > set_property ( " Tracking.pll_bw_hz " , std : : to_string ( PLL_wide_bw_hz ) ) ;
config - > set_property ( " Tracking.dll_bw_hz " , std : : to_string ( DLL_wide_bw_hz ) ) ;
config - > set_property ( " Tracking.extend_correlation_symbols " , std : : to_string ( extend_correlation_symbols ) ) ;
config - > set_property ( " Tracking.pll_bw_narrow_hz " , std : : to_string ( PLL_narrow_bw_hz ) ) ;
config - > set_property ( " Tracking.dll_bw_narrow_hz " , std : : to_string ( DLL_narrow_bw_hz ) ) ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
config - > set_property ( " Tracking.fll_bw_hz " , std : : to_string ( FLAGS_fll_bw_hz ) ) ;
config - > set_property ( " Tracking.enable_fll_pull_in " , FLAGS_enable_fll_pull_in ? " true " : " false " ) ;
config - > set_property ( " Tracking.enable_fll_steady_state " , FLAGS_enable_fll_steady_state ? " true " : " false " ) ;
2024-04-29 06:27:33 +00:00
# else
config - > set_property ( " Tracking.fll_bw_hz " , std : : to_string ( absl : : GetFlag ( FLAGS_fll_bw_hz ) ) ) ;
config - > set_property ( " Tracking.enable_fll_pull_in " , absl : : GetFlag ( FLAGS_enable_fll_pull_in ) ? " true " : " false " ) ;
config - > set_property ( " Tracking.enable_fll_steady_state " , absl : : GetFlag ( FLAGS_enable_fll_steady_state ) ? " true " : " false " ) ;
# endif
2019-12-16 17:44:22 +00:00
config - > set_property ( " Tracking.smoother_length " , std : : to_string ( smoother_length ) ) ;
config - > set_property ( " Tracking.dump " , " true " ) ;
config - > set_property ( " Tracking.dump_filename " , " ./tracking_ch_ " ) ;
2018-09-13 14:36:21 +00:00
config - > set_property ( " Observables.implementation " , " Hybrid_Observables " ) ;
config - > set_property ( " Observables.dump " , " true " ) ;
config - > set_property ( " TelemetryDecoder.dump " , " true " ) ;
gnss_synchro_master . Channel_ID = 0 ;
config - > set_property ( " GNSS-SDR.internal_fs_sps " , std : : to_string ( baseband_sampling_freq ) ) ;
std : : string System_and_Signal ;
2024-08-08 20:30:45 +00:00
if ( implementation = = " GPS_L1_CA_DLL_PLL_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
gnss_synchro_master . System = ' G ' ;
std : : string signal = " 1C " ;
System_and_Signal = " GPS L1 CA " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( gnss_synchro_master . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
config - > set_property ( " Tracking.early_late_space_chips " , " 0.5 " ) ;
2019-12-16 17:44:22 +00:00
config - > set_property ( " Tracking.early_late_space_narrow_chips " , " 0.1 " ) ;
2018-09-13 14:36:21 +00:00
config - > set_property ( " TelemetryDecoder.implementation " , " GPS_L1_CA_Telemetry_Decoder " ) ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E1_DLL_PLL_VEML_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
gnss_synchro_master . System = ' E ' ;
std : : string signal = " 1B " ;
System_and_Signal = " Galileo E1B " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( gnss_synchro_master . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
config - > set_property ( " Tracking.early_late_space_chips " , " 0.15 " ) ;
2019-12-16 17:44:22 +00:00
config - > set_property ( " Tracking.very_early_late_space_chips " , " 0.5 " ) ;
2018-09-13 14:36:21 +00:00
config - > set_property ( " Tracking.early_late_space_narrow_chips " , " 0.15 " ) ;
2019-12-16 17:44:22 +00:00
config - > set_property ( " Tracking.very_early_late_space_narrow_chips " , " 0.5 " ) ;
2018-09-13 14:36:21 +00:00
config - > set_property ( " Tracking.track_pilot " , " true " ) ;
config - > set_property ( " TelemetryDecoder.implementation " , " Galileo_E1B_Telemetry_Decoder " ) ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E5a_DLL_PLL_Tracking_FPGA " ) // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0)
2018-09-13 14:36:21 +00:00
{
gnss_synchro_master . System = ' E ' ;
std : : string signal = " 5X " ;
System_and_Signal = " Galileo E5a " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( gnss_synchro_master . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
config - > set_property ( " Tracking.early_late_space_chips " , " 0.5 " ) ;
2019-02-25 11:10:50 +00:00
config - > set_property ( " Tracking.track_pilot " , " true " ) ;
2019-12-16 17:44:22 +00:00
2018-09-13 14:36:21 +00:00
config - > set_property ( " TelemetryDecoder.implementation " , " Galileo_E5a_Telemetry_Decoder " ) ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " GPS_L5_DLL_PLL_Tracking_FPGA " )
2018-09-13 14:36:21 +00:00
{
gnss_synchro_master . System = ' G ' ;
std : : string signal = " L5 " ;
System_and_Signal = " GPS L5I " ;
const char * str = signal . c_str ( ) ; // get a C style null terminated string
std : : memcpy ( static_cast < void * > ( gnss_synchro_master . Signal ) , str , 3 ) ; // copy string into synchro char array: 2 char + null
config - > set_property ( " Tracking.early_late_space_chips " , " 0.5 " ) ;
2019-02-25 11:10:50 +00:00
config - > set_property ( " Tracking.track_pilot " , " true " ) ;
2018-09-13 14:36:21 +00:00
config - > set_property ( " TelemetryDecoder.implementation " , " GPS_L5_Telemetry_Decoder " ) ;
}
else
{
std : : cout < < " The test can not run with the selected tracking implementation \n " ;
throw ( std : : exception ( ) ) ;
}
std : : cout < < " ***************************************** \n " ;
std : : cout < < " *** Tracking configuration parameters *** \n " ;
std : : cout < < " ***************************************** \n " ;
std : : cout < < " Signal: " < < System_and_Signal < < " \n " ;
std : : cout < < " implementation: " < < config - > property ( " Tracking.implementation " , std : : string ( " undefined " ) ) < < " \n " ;
std : : cout < < " pll_bw_hz: " < < config - > property ( " Tracking.pll_bw_hz " , 0.0 ) < < " Hz \n " ;
std : : cout < < " dll_bw_hz: " < < config - > property ( " Tracking.dll_bw_hz " , 0.0 ) < < " Hz \n " ;
2019-12-16 17:44:22 +00:00
std : : cout < < " fll_bw_hz: " < < config - > property ( " Tracking.fll_bw_hz " , 0.0 ) < < " Hz \n " ;
std : : cout < < " enable_fll_pull_in: " < < config - > property ( " Tracking.enable_fll_pull_in " , false ) < < " \n " ;
std : : cout < < " enable_fll_steady_state: " < < config - > property ( " Tracking.enable_fll_steady_state " , false ) < < " \n " ;
2018-09-13 14:36:21 +00:00
std : : cout < < " pll_bw_narrow_hz: " < < config - > property ( " Tracking.pll_bw_narrow_hz " , 0.0 ) < < " Hz \n " ;
std : : cout < < " dll_bw_narrow_hz: " < < config - > property ( " Tracking.dll_bw_narrow_hz " , 0.0 ) < < " Hz \n " ;
std : : cout < < " extend_correlation_symbols: " < < config - > property ( " Tracking.extend_correlation_symbols " , 0 ) < < " Symbols \n " ;
2019-12-16 17:44:22 +00:00
std : : cout < < " high_dyn: " < < config - > property ( " Tracking.high_dyn " , false ) < < " \n " ;
std : : cout < < " smoother_length: " < < config - > property ( " Tracking.smoother_length " , 0 ) < < " \n " ;
2018-09-13 14:36:21 +00:00
std : : cout < < " ***************************************** \n " ;
std : : cout < < " ***************************************** \n " ;
}
2019-08-17 12:41:32 +00:00
2018-09-13 14:36:21 +00:00
void HybridObservablesTestFpga : : check_results_carrier_phase (
arma : : mat & true_ch0 ,
arma : : vec & true_tow_s ,
arma : : mat & measured_ch0 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// 1. True value interpolation to match the measurement times
2018-09-13 14:36:21 +00:00
double t0 = measured_ch0 ( 0 , 0 ) ;
int size1 = measured_ch0 . col ( 0 ) . n_rows ;
double t1 = measured_ch0 ( size1 - 1 , 0 ) ;
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
arma : : vec true_ch0_phase_interp ;
arma : : interp1 ( true_tow_s , true_ch0 . col ( 3 ) , t , true_ch0_phase_interp ) ;
arma : : vec meas_ch0_phase_interp ;
arma : : interp1 ( measured_ch0 . col ( 0 ) , measured_ch0 . col ( 3 ) , t , meas_ch0_phase_interp ) ;
2019-08-18 23:29:04 +00:00
// 2. RMSE
2018-09-13 14:36:21 +00:00
arma : : vec err_ch0_cycles ;
2019-08-18 23:29:04 +00:00
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
2018-09-13 14:36:21 +00:00
err_ch0_cycles = meas_ch0_phase_interp - true_ch0_phase_interp - meas_ch0_phase_interp ( 0 ) + true_ch0_phase_interp ( 0 ) ;
arma : : vec err2_ch0 = arma : : square ( err_ch0_cycles ) ;
double rmse_ch0 = sqrt ( arma : : mean ( err2_ch0 ) ) ;
2019-08-18 23:29:04 +00:00
// 3. Mean err and variance
2018-09-13 14:36:21 +00:00
double error_mean_ch0 = arma : : mean ( err_ch0_cycles ) ;
double error_var_ch0 = arma : : var ( err_ch0_cycles ) ;
// 4. Peaks
double max_error_ch0 = arma : : max ( err_ch0_cycles ) ;
double min_error_ch0 = arma : : min ( err_ch0_cycles ) ;
2019-08-18 23:29:04 +00:00
// 5. report
2018-09-13 14:36:21 +00:00
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Accumulated Carrier phase RMSE = "
< < rmse_ch0 < < " , mean = " < < error_mean_ch0
< < " , stdev = " < < sqrt ( error_var_ch0 )
< < " (max,min) = " < < max_error_ch0
< < " , " < < min_error_ch0
2020-07-07 16:53:50 +00:00
< < " [cycles] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout . precision ( ss ) ;
2019-08-18 23:29:04 +00:00
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2018-09-13 14:36:21 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Accumulated Carrier phase error [cycles] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Carrier Phase error [cycles] " ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
std : : vector < double > error_vec ( err_ch0_cycles . colptr ( 0 ) , err_ch0_cycles . colptr ( 0 ) + err_ch0_cycles . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , error_vec ,
" Carrier Phase error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " Carrier_phase_error " ) ;
g3 . showonscreen ( ) ; // window output
}
2019-08-18 23:29:04 +00:00
// check results against the test tolerance
2018-09-13 14:36:21 +00:00
ASSERT_LT ( rmse_ch0 , 0.25 ) ;
ASSERT_LT ( error_mean_ch0 , 0.2 ) ;
ASSERT_GT ( error_mean_ch0 , - 0.2 ) ;
ASSERT_LT ( error_var_ch0 , 0.5 ) ;
ASSERT_LT ( max_error_ch0 , 0.5 ) ;
ASSERT_GT ( min_error_ch0 , - 0.5 ) ;
}
void HybridObservablesTestFpga : : check_results_carrier_phase_double_diff (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// 1. True value interpolation to match the measurement times
2018-09-13 14:36:21 +00:00
double t0 = std : : max ( measured_ch0 ( 0 , 0 ) , measured_ch1 ( 0 , 0 ) ) ;
int size1 = measured_ch0 . col ( 0 ) . n_rows ;
int size2 = measured_ch1 . col ( 0 ) . n_rows ;
double t1 = std : : min ( measured_ch0 ( size1 - 1 , 0 ) , measured_ch1 ( size2 - 1 , 0 ) ) ;
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
arma : : vec true_ch0_carrier_phase_interp ;
arma : : vec true_ch1_carrier_phase_interp ;
arma : : interp1 ( true_tow_ch0_s , true_ch0 . col ( 3 ) , t , true_ch0_carrier_phase_interp ) ;
arma : : interp1 ( true_tow_ch1_s , true_ch1 . col ( 3 ) , t , true_ch1_carrier_phase_interp ) ;
arma : : vec meas_ch0_carrier_phase_interp ;
arma : : vec meas_ch1_carrier_phase_interp ;
arma : : interp1 ( measured_ch0 . col ( 0 ) , measured_ch0 . col ( 3 ) , t , meas_ch0_carrier_phase_interp ) ;
arma : : interp1 ( measured_ch1 . col ( 0 ) , measured_ch1 . col ( 3 ) , t , meas_ch1_carrier_phase_interp ) ;
// generate double difference accumulated carrier phases
2019-08-18 23:29:04 +00:00
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
2018-09-13 14:36:21 +00:00
arma : : vec delta_true_carrier_phase_cycles = ( true_ch0_carrier_phase_interp - true_ch0_carrier_phase_interp ( 0 ) ) - ( true_ch1_carrier_phase_interp - true_ch1_carrier_phase_interp ( 0 ) ) ;
arma : : vec delta_measured_carrier_phase_cycles = ( meas_ch0_carrier_phase_interp - meas_ch0_carrier_phase_interp ( 0 ) ) - ( meas_ch1_carrier_phase_interp - meas_ch1_carrier_phase_interp ( 0 ) ) ;
2019-08-18 23:29:04 +00:00
// 2. RMSE
2018-09-13 14:36:21 +00:00
arma : : vec err ;
err = delta_measured_carrier_phase_cycles - delta_true_carrier_phase_cycles ;
arma : : vec err2 = arma : : square ( err ) ;
double rmse = sqrt ( arma : : mean ( err2 ) ) ;
2019-08-18 23:29:04 +00:00
// 3. Mean err and variance
2018-09-13 14:36:21 +00:00
double error_mean = arma : : mean ( err ) ;
double error_var = arma : : var ( err ) ;
// 4. Peaks
double max_error = arma : : max ( err ) ;
double min_error = arma : : min ( err ) ;
2019-08-18 23:29:04 +00:00
// 5. report
2018-09-13 14:36:21 +00:00
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Double diff Carrier Phase RMSE = "
< < rmse < < " , mean = " < < error_mean
< < " , stdev = " < < sqrt ( error_var )
< < " (max,min) = " < < max_error
< < " , " < < min_error
2020-07-07 16:53:50 +00:00
< < " [Cycles] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout . precision ( ss ) ;
2019-08-18 23:29:04 +00:00
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2018-09-13 14:36:21 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Double diff Carrier Phase error [Cycles] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Double diff Carrier Phase error [Cycles] " ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
std : : vector < double > range_error_m ( err . colptr ( 0 ) , err . colptr ( 0 ) + err . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , range_error_m ,
" Double diff Carrier Phase error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " double_diff_carrier_phase_error " ) ;
g3 . showonscreen ( ) ; // window output
}
2019-08-18 23:29:04 +00:00
// check results against the test tolerance
2018-09-13 14:36:21 +00:00
ASSERT_LT ( rmse , 0.25 ) ;
ASSERT_LT ( error_mean , 0.2 ) ;
ASSERT_GT ( error_mean , - 0.2 ) ;
ASSERT_LT ( error_var , 0.5 ) ;
ASSERT_LT ( max_error , 0.5 ) ;
ASSERT_GT ( min_error , - 0.5 ) ;
}
void HybridObservablesTestFpga : : check_results_carrier_doppler_double_diff (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// 1. True value interpolation to match the measurement times
2018-09-13 14:36:21 +00:00
double t0 = std : : max ( measured_ch0 ( 0 , 0 ) , measured_ch1 ( 0 , 0 ) ) ;
int size1 = measured_ch0 . col ( 0 ) . n_rows ;
int size2 = measured_ch1 . col ( 0 ) . n_rows ;
double t1 = std : : min ( measured_ch0 ( size1 - 1 , 0 ) , measured_ch1 ( size2 - 1 , 0 ) ) ;
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
arma : : vec true_ch0_carrier_doppler_interp ;
arma : : vec true_ch1_carrier_doppler_interp ;
arma : : interp1 ( true_tow_ch0_s , true_ch0 . col ( 2 ) , t , true_ch0_carrier_doppler_interp ) ;
arma : : interp1 ( true_tow_ch1_s , true_ch1 . col ( 2 ) , t , true_ch1_carrier_doppler_interp ) ;
arma : : vec meas_ch0_carrier_doppler_interp ;
arma : : vec meas_ch1_carrier_doppler_interp ;
arma : : interp1 ( measured_ch0 . col ( 0 ) , measured_ch0 . col ( 2 ) , t , meas_ch0_carrier_doppler_interp ) ;
arma : : interp1 ( measured_ch1 . col ( 0 ) , measured_ch1 . col ( 2 ) , t , meas_ch1_carrier_doppler_interp ) ;
// generate double difference carrier Doppler
arma : : vec delta_true_carrier_doppler_cycles = true_ch0_carrier_doppler_interp - true_ch1_carrier_doppler_interp ;
arma : : vec delta_measured_carrier_doppler_cycles = meas_ch0_carrier_doppler_interp - meas_ch1_carrier_doppler_interp ;
2019-08-18 23:29:04 +00:00
// 2. RMSE
2018-09-13 14:36:21 +00:00
arma : : vec err ;
err = delta_measured_carrier_doppler_cycles - delta_true_carrier_doppler_cycles ;
arma : : vec err2 = arma : : square ( err ) ;
double rmse = sqrt ( arma : : mean ( err2 ) ) ;
2019-08-18 23:29:04 +00:00
// 3. Mean err and variance
2018-09-13 14:36:21 +00:00
double error_mean = arma : : mean ( err ) ;
double error_var = arma : : var ( err ) ;
// 4. Peaks
double max_error = arma : : max ( err ) ;
double min_error = arma : : min ( err ) ;
2019-08-18 23:29:04 +00:00
// 5. report
2018-09-13 14:36:21 +00:00
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Double diff Carrier Doppler RMSE = "
< < rmse < < " , mean = " < < error_mean
< < " , stdev = " < < sqrt ( error_var )
< < " (max,min) = " < < max_error
< < " , " < < min_error
2020-07-07 16:53:50 +00:00
< < " [Hz] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout . precision ( ss ) ;
2024-04-29 06:27:33 +00:00
// plots
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2018-09-13 14:36:21 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Double diff Carrier Doppler error [Hz] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Double diff Carrier Doppler error [Hz] " ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
std : : vector < double > range_error_m ( err . colptr ( 0 ) , err . colptr ( 0 ) + err . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , range_error_m ,
" Double diff Carrier Doppler error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " double_diff_carrier_doppler_error " ) ;
g3 . showonscreen ( ) ; // window output
}
2019-08-18 23:29:04 +00:00
// check results against the test tolerance
2018-09-13 14:36:21 +00:00
ASSERT_LT ( error_mean , 5 ) ;
ASSERT_GT ( error_mean , - 5 ) ;
2019-08-18 23:29:04 +00:00
// assuming PLL BW=35
2018-09-13 14:36:21 +00:00
ASSERT_LT ( error_var , 200 ) ;
ASSERT_LT ( max_error , 70 ) ;
ASSERT_GT ( min_error , - 70 ) ;
ASSERT_LT ( rmse , 30 ) ;
}
void HybridObservablesTestFpga : : check_results_carrier_doppler (
arma : : mat & true_ch0 ,
arma : : vec & true_tow_s ,
arma : : mat & measured_ch0 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// 1. True value interpolation to match the measurement times
2018-09-13 14:36:21 +00:00
double t0 = measured_ch0 ( 0 , 0 ) ;
int size1 = measured_ch0 . col ( 0 ) . n_rows ;
double t1 = measured_ch0 ( size1 - 1 , 0 ) ;
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
arma : : vec true_ch0_doppler_interp ;
arma : : interp1 ( true_tow_s , true_ch0 . col ( 2 ) , t , true_ch0_doppler_interp ) ;
arma : : vec meas_ch0_doppler_interp ;
arma : : interp1 ( measured_ch0 . col ( 0 ) , measured_ch0 . col ( 2 ) , t , meas_ch0_doppler_interp ) ;
2019-08-18 23:29:04 +00:00
// 2. RMSE
2018-09-13 14:36:21 +00:00
arma : : vec err_ch0_hz ;
2019-08-18 23:29:04 +00:00
// compute error
2018-09-13 14:36:21 +00:00
err_ch0_hz = meas_ch0_doppler_interp - true_ch0_doppler_interp ;
arma : : vec err2_ch0 = arma : : square ( err_ch0_hz ) ;
double rmse_ch0 = sqrt ( arma : : mean ( err2_ch0 ) ) ;
2019-08-18 23:29:04 +00:00
// 3. Mean err and variance
2018-09-13 14:36:21 +00:00
double error_mean_ch0 = arma : : mean ( err_ch0_hz ) ;
double error_var_ch0 = arma : : var ( err_ch0_hz ) ;
// 4. Peaks
double max_error_ch0 = arma : : max ( err_ch0_hz ) ;
double min_error_ch0 = arma : : min ( err_ch0_hz ) ;
2019-08-18 23:29:04 +00:00
// 5. report
2018-09-13 14:36:21 +00:00
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Carrier Doppler RMSE = "
< < rmse_ch0 < < " , mean = " < < error_mean_ch0
< < " , stdev = " < < sqrt ( error_var_ch0 )
< < " (max,min) = " < < max_error_ch0
< < " , " < < min_error_ch0
2020-07-07 16:53:50 +00:00
< < " [Hz] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout . precision ( ss ) ;
2019-08-18 23:29:04 +00:00
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2018-09-13 14:36:21 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Carrier Doppler error [Hz] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Carrier Doppler error [Hz] " ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
std : : vector < double > error_vec ( err_ch0_hz . colptr ( 0 ) , err_ch0_hz . colptr ( 0 ) + err_ch0_hz . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , error_vec ,
" Carrier Doppler error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " Carrier_doppler_error " ) ;
g3 . showonscreen ( ) ; // window output
}
2019-08-18 23:29:04 +00:00
// check results against the test tolerance
2018-09-13 14:36:21 +00:00
ASSERT_LT ( error_mean_ch0 , 5 ) ;
ASSERT_GT ( error_mean_ch0 , - 5 ) ;
2019-08-18 23:29:04 +00:00
// assuming PLL BW=35
2018-09-13 14:36:21 +00:00
ASSERT_LT ( error_var_ch0 , 200 ) ;
ASSERT_LT ( max_error_ch0 , 70 ) ;
ASSERT_GT ( min_error_ch0 , - 70 ) ;
ASSERT_LT ( rmse_ch0 , 30 ) ;
}
2020-02-11 20:47:13 +00:00
2019-12-16 17:44:22 +00:00
void HybridObservablesTestFpga : : check_results_duplicated_satellite (
arma : : mat & measured_sat1 ,
arma : : mat & measured_sat2 ,
int ch_id ,
const std : : string & data_title )
{
// 1. True value interpolation to match the measurement times
// define the common measured time interval
double t0_sat1 = measured_sat1 ( 0 , 0 ) ;
int size1 = measured_sat1 . col ( 0 ) . n_rows ;
double t1_sat1 = measured_sat1 ( size1 - 1 , 0 ) ;
double t0_sat2 = measured_sat2 ( 0 , 0 ) ;
int size2 = measured_sat2 . col ( 0 ) . n_rows ;
double t1_sat2 = measured_sat2 ( size2 - 1 , 0 ) ;
double t0 ;
double t1 ;
if ( t0_sat1 > t0_sat2 )
{
t0 = t0_sat1 ;
}
else
{
t0 = t0_sat2 ;
}
if ( t1_sat1 > t1_sat2 )
{
t1 = t1_sat2 ;
}
else
{
t1 = t1_sat1 ;
}
if ( ( t1 - t0 ) > 0 )
{
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
// conversion between arma::vec and std:vector
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
// Doppler
arma : : vec meas_sat1_doppler_interp ;
arma : : interp1 ( measured_sat1 . col ( 0 ) , measured_sat1 . col ( 2 ) , t , meas_sat1_doppler_interp ) ;
arma : : vec meas_sat2_doppler_interp ;
arma : : interp1 ( measured_sat2 . col ( 0 ) , measured_sat2 . col ( 2 ) , t , meas_sat2_doppler_interp ) ;
// Carrier Phase
arma : : vec meas_sat1_carrier_phase_interp ;
arma : : vec meas_sat2_carrier_phase_interp ;
arma : : interp1 ( measured_sat1 . col ( 0 ) , measured_sat1 . col ( 3 ) , t , meas_sat1_carrier_phase_interp ) ;
arma : : interp1 ( measured_sat2 . col ( 0 ) , measured_sat2 . col ( 3 ) , t , meas_sat2_carrier_phase_interp ) ;
// generate double difference accumulated carrier phases
// compute error without the accumulated carrier phase offsets (which depends on the receiver starting time)
arma : : vec delta_measured_carrier_phase_cycles = ( meas_sat1_carrier_phase_interp - meas_sat1_carrier_phase_interp ( 0 ) ) - ( meas_sat2_carrier_phase_interp - meas_sat2_carrier_phase_interp ( 0 ) ) ;
// Pseudoranges
arma : : vec meas_sat1_dist_interp ;
arma : : vec meas_sat2_dist_interp ;
arma : : interp1 ( measured_sat1 . col ( 0 ) , measured_sat1 . col ( 4 ) , t , meas_sat1_dist_interp ) ;
arma : : interp1 ( measured_sat2 . col ( 0 ) , measured_sat2 . col ( 4 ) , t , meas_sat2_dist_interp ) ;
// generate delta pseudoranges
arma : : vec delta_measured_dist_m = meas_sat1_dist_interp - meas_sat2_dist_interp ;
// Carrier Doppler error
// 2. RMSE
arma : : vec err_ch0_hz ;
// compute error
err_ch0_hz = meas_sat1_doppler_interp - meas_sat2_doppler_interp ;
// save matlab file for further analysis
std : : vector < double > tmp_vector_common_time_s ( t . colptr ( 0 ) ,
t . colptr ( 0 ) + t . n_rows ) ;
std : : vector < double > tmp_vector_err_ch0_hz ( err_ch0_hz . colptr ( 0 ) ,
err_ch0_hz . colptr ( 0 ) + err_ch0_hz . n_rows ) ;
save_mat_xy ( tmp_vector_common_time_s , tmp_vector_err_ch0_hz , std : : string ( " measured_doppler_error_ch_ " + std : : to_string ( ch_id ) ) ) ;
// compute statistics
arma : : vec err2_ch0 = arma : : square ( err_ch0_hz ) ;
double rmse_ch0 = sqrt ( arma : : mean ( err2_ch0 ) ) ;
// 3. Mean err and variance
double error_mean_ch0 = arma : : mean ( err_ch0_hz ) ;
double error_var_ch0 = arma : : var ( err_ch0_hz ) ;
// 4. Peaks
double max_error_ch0 = arma : : max ( err_ch0_hz ) ;
double min_error_ch0 = arma : : min ( err_ch0_hz ) ;
// 5. report
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Carrier Doppler RMSE = "
< < rmse_ch0 < < " , mean = " < < error_mean_ch0
< < " , stdev = " < < sqrt ( error_var_ch0 )
< < " (max,min) = " < < max_error_ch0
< < " , " < < min_error_ch0
2020-07-07 16:53:50 +00:00
< < " [Hz] \n " ;
2019-12-16 17:44:22 +00:00
std : : cout . precision ( ss ) ;
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2019-12-16 17:44:22 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Carrier Doppler error [Hz] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Carrier Doppler error [Hz] " ) ;
// conversion between arma::vec and std:vector
std : : vector < double > error_vec ( err_ch0_hz . colptr ( 0 ) , err_ch0_hz . colptr ( 0 ) + err_ch0_hz . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , error_vec ,
" Carrier Doppler error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " Carrier_doppler_error " ) ;
g3 . showonscreen ( ) ; // window output
}
// check results against the test tolerance
EXPECT_LT ( error_mean_ch0 , 5 ) ;
EXPECT_GT ( error_mean_ch0 , - 5 ) ;
// assuming PLL BW=35
EXPECT_LT ( error_var_ch0 , 250 ) ;
EXPECT_LT ( max_error_ch0 , 100 ) ;
EXPECT_GT ( min_error_ch0 , - 100 ) ;
EXPECT_LT ( rmse_ch0 , 30 ) ;
// Carrier Phase error
// 2. RMSE
arma : : vec err_carrier_phase ;
err_carrier_phase = delta_measured_carrier_phase_cycles ;
// save matlab file for further analysis
std : : vector < double > tmp_vector_err_carrier_phase ( err_carrier_phase . colptr ( 0 ) ,
err_carrier_phase . colptr ( 0 ) + err_carrier_phase . n_rows ) ;
save_mat_xy ( tmp_vector_common_time_s , tmp_vector_err_carrier_phase , std : : string ( " measured_carrier_phase_error_ch_ " + std : : to_string ( ch_id ) ) ) ;
arma : : vec err2_carrier_phase = arma : : square ( err_carrier_phase ) ;
double rmse_carrier_phase = sqrt ( arma : : mean ( err2_carrier_phase ) ) ;
// 3. Mean err and variance
double error_mean_carrier_phase = arma : : mean ( err_carrier_phase ) ;
double error_var_carrier_phase = arma : : var ( err_carrier_phase ) ;
// 4. Peaks
double max_error_carrier_phase = arma : : max ( err_carrier_phase ) ;
double min_error_carrier_phase = arma : : min ( err_carrier_phase ) ;
// 5. report
ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Carrier Phase RMSE = "
< < rmse_carrier_phase < < " , mean = " < < error_mean_carrier_phase
< < " , stdev = " < < sqrt ( error_var_carrier_phase )
< < " (max,min) = " < < max_error_carrier_phase
< < " , " < < min_error_carrier_phase
2020-07-07 16:53:50 +00:00
< < " [Cycles] \n " ;
2019-12-16 17:44:22 +00:00
std : : cout . precision ( ss ) ;
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2019-12-16 17:44:22 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Carrier Phase error [Cycles] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Carrier Phase error [Cycles] " ) ;
// conversion between arma::vec and std:vector
std : : vector < double > range_error_m ( err_carrier_phase . colptr ( 0 ) , err_carrier_phase . colptr ( 0 ) + err_carrier_phase . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , range_error_m ,
" Carrier Phase error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " duplicated_satellite_carrier_phase_error " ) ;
g3 . showonscreen ( ) ; // window output
}
// check results against the test tolerance
EXPECT_LT ( rmse_carrier_phase , 0.25 ) ;
EXPECT_LT ( error_mean_carrier_phase , 0.2 ) ;
EXPECT_GT ( error_mean_carrier_phase , - 0.2 ) ;
EXPECT_LT ( error_var_carrier_phase , 0.5 ) ;
EXPECT_LT ( max_error_carrier_phase , 0.5 ) ;
EXPECT_GT ( min_error_carrier_phase , - 0.5 ) ;
// Pseudorange error
// 2. RMSE
arma : : vec err_pseudorange ;
err_pseudorange = delta_measured_dist_m ;
// save matlab file for further analysis
std : : vector < double > tmp_vector_err_pseudorange ( err_pseudorange . colptr ( 0 ) ,
err_pseudorange . colptr ( 0 ) + err_pseudorange . n_rows ) ;
save_mat_xy ( tmp_vector_common_time_s , tmp_vector_err_pseudorange , std : : string ( " measured_pr_error_ch_ " + std : : to_string ( ch_id ) ) ) ;
arma : : vec err2_pseudorange = arma : : square ( err_pseudorange ) ;
double rmse_pseudorange = sqrt ( arma : : mean ( err2_pseudorange ) ) ;
// 3. Mean err and variance
double error_mean_pseudorange = arma : : mean ( err_pseudorange ) ;
double error_var_pseudorange = arma : : var ( err_pseudorange ) ;
// 4. Peaks
double max_error_pseudorange = arma : : max ( err_pseudorange ) ;
double min_error_pseudorange = arma : : min ( err_pseudorange ) ;
// 5. report
ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Pseudorange RMSE = "
< < rmse_pseudorange < < " , mean = " < < error_mean_pseudorange
< < " , stdev = " < < sqrt ( error_var_pseudorange )
< < " (max,min) = " < < max_error_pseudorange
< < " , " < < min_error_pseudorange
2020-07-07 16:53:50 +00:00
< < " [meters] \n " ;
2019-12-16 17:44:22 +00:00
std : : cout . precision ( ss ) ;
// plots
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2019-12-16 17:44:22 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Pseudorange error [m] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Pseudorange error [m] " ) ;
// conversion between arma::vec and std:vector
std : : vector < double > range_error_m ( err_pseudorange . colptr ( 0 ) , err_pseudorange . colptr ( 0 ) + err_pseudorange . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , range_error_m ,
" Pseudorrange error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " duplicated_satellite_pseudorrange_error " ) ;
g3 . showonscreen ( ) ; // window output
}
// check results against the test tolerance
EXPECT_LT ( rmse_pseudorange , 3.0 ) ;
EXPECT_LT ( error_mean_pseudorange , 1.0 ) ;
EXPECT_GT ( error_mean_pseudorange , - 1.0 ) ;
EXPECT_LT ( error_var_pseudorange , 10.0 ) ;
EXPECT_LT ( max_error_pseudorange , 15.0 ) ;
EXPECT_GT ( min_error_pseudorange , - 15.0 ) ;
}
}
2019-08-17 12:41:32 +00:00
2018-09-13 14:36:21 +00:00
bool HybridObservablesTestFpga : : save_mat_xy ( std : : vector < double > & x , std : : vector < double > & y , std : : string filename )
{
try
{
// WRITE MAT FILE
mat_t * matfp ;
matvar_t * matvar ;
filename . append ( " .mat " ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " save_mat_xy write " < < filename < < ' \n ' ;
2019-02-28 20:45:30 +00:00
matfp = Mat_CreateVer ( filename . c_str ( ) , nullptr , MAT_FT_MAT5 ) ;
if ( reinterpret_cast < int64_t * > ( matfp ) ! = nullptr )
2018-09-13 14:36:21 +00:00
{
size_t dims [ 2 ] = { 1 , x . size ( ) } ;
matvar = Mat_VarCreate ( " x " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , & x [ 0 ] , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " y " , MAT_C_DOUBLE , MAT_T_DOUBLE , 2 , dims , & y [ 0 ] , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
}
else
{
2020-07-07 16:53:50 +00:00
std : : cout < < " save_mat_xy: error creating file \n " ;
2018-09-13 14:36:21 +00:00
}
Mat_Close ( matfp ) ;
return true ;
}
catch ( const std : : exception & ex )
{
2020-07-07 16:53:50 +00:00
std : : cout < < " save_mat_xy: " < < ex . what ( ) < < ' \n ' ;
2018-09-13 14:36:21 +00:00
return false ;
}
}
2019-08-17 12:41:32 +00:00
2018-09-13 14:36:21 +00:00
void HybridObservablesTestFpga : : check_results_code_pseudorange (
arma : : mat & true_ch0 ,
arma : : mat & true_ch1 ,
arma : : vec & true_tow_ch0_s ,
arma : : vec & true_tow_ch1_s ,
arma : : mat & measured_ch0 ,
arma : : mat & measured_ch1 ,
2019-02-28 20:45:30 +00:00
const std : : string & data_title )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// 1. True value interpolation to match the measurement times
2018-09-13 14:36:21 +00:00
double t0 = std : : max ( measured_ch0 ( 0 , 0 ) , measured_ch1 ( 0 , 0 ) ) ;
int size1 = measured_ch0 . col ( 0 ) . n_rows ;
int size2 = measured_ch1 . col ( 0 ) . n_rows ;
double t1 = std : : min ( measured_ch0 ( size1 - 1 , 0 ) , measured_ch1 ( size2 - 1 , 0 ) ) ;
arma : : vec t = arma : : linspace < arma : : vec > ( t0 , t1 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
arma : : vec t_from_start = arma : : linspace < arma : : vec > ( 0 , t1 - t0 , floor ( ( t1 - t0 ) * 1e3 ) ) ;
std : : vector < double > time_vector ( t_from_start . colptr ( 0 ) , t_from_start . colptr ( 0 ) + t_from_start . n_rows ) ;
arma : : vec true_ch0_dist_interp ;
arma : : vec true_ch1_dist_interp ;
arma : : interp1 ( true_tow_ch0_s , true_ch0 . col ( 1 ) , t , true_ch0_dist_interp ) ;
arma : : interp1 ( true_tow_ch1_s , true_ch1 . col ( 1 ) , t , true_ch1_dist_interp ) ;
arma : : vec meas_ch0_dist_interp ;
arma : : vec meas_ch1_dist_interp ;
arma : : interp1 ( measured_ch0 . col ( 0 ) , measured_ch0 . col ( 4 ) , t , meas_ch0_dist_interp ) ;
arma : : interp1 ( measured_ch1 . col ( 0 ) , measured_ch1 . col ( 4 ) , t , meas_ch1_dist_interp ) ;
// generate delta pseudoranges
arma : : vec delta_true_dist_m = true_ch0_dist_interp - true_ch1_dist_interp ;
arma : : vec delta_measured_dist_m = meas_ch0_dist_interp - meas_ch1_dist_interp ;
2019-08-18 23:29:04 +00:00
// 2. RMSE
2018-09-13 14:36:21 +00:00
arma : : vec err ;
err = delta_measured_dist_m - delta_true_dist_m ;
arma : : vec err2 = arma : : square ( err ) ;
double rmse = sqrt ( arma : : mean ( err2 ) ) ;
2019-08-18 23:29:04 +00:00
// 3. Mean err and variance
2018-09-13 14:36:21 +00:00
double error_mean = arma : : mean ( err ) ;
double error_var = arma : : var ( err ) ;
// 4. Peaks
double max_error = arma : : max ( err ) ;
double min_error = arma : : min ( err ) ;
2019-08-18 23:29:04 +00:00
// 5. report
2018-09-13 14:36:21 +00:00
std : : streamsize ss = std : : cout . precision ( ) ;
std : : cout < < std : : setprecision ( 10 ) < < data_title < < " Double diff Pseudorange RMSE = "
< < rmse < < " , mean = " < < error_mean
< < " , stdev = " < < sqrt ( error_var )
< < " (max,min) = " < < max_error
< < " , " < < min_error
2020-07-07 16:53:50 +00:00
< < " [meters] \n " ;
2018-09-13 14:36:21 +00:00
std : : cout . precision ( ss ) ;
2024-04-29 06:27:33 +00:00
// plots
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_show_plots )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_show_plots ) )
# endif
2018-09-13 14:36:21 +00:00
{
Gnuplot g3 ( " linespoints " ) ;
g3 . set_title ( data_title + " Double diff Pseudorange error [m] " ) ;
g3 . set_grid ( ) ;
g3 . set_xlabel ( " Time [s] " ) ;
g3 . set_ylabel ( " Double diff Pseudorange error [m] " ) ;
2019-08-18 23:29:04 +00:00
// conversion between arma::vec and std:vector
2018-09-13 14:36:21 +00:00
std : : vector < double > range_error_m ( err . colptr ( 0 ) , err . colptr ( 0 ) + err . n_rows ) ;
g3 . cmd ( " set key box opaque " ) ;
g3 . plot_xy ( time_vector , range_error_m ,
" Double diff Pseudorrange error " ) ;
g3 . set_legend ( ) ;
g3 . savetops ( data_title + " double_diff_pseudorrange_error " ) ;
g3 . showonscreen ( ) ; // window output
}
2019-08-18 23:29:04 +00:00
// check results against the test tolerance
2018-09-13 14:36:21 +00:00
ASSERT_LT ( rmse , 3.0 ) ;
ASSERT_LT ( error_mean , 1.0 ) ;
ASSERT_GT ( error_mean , - 1.0 ) ;
ASSERT_LT ( error_var , 10.0 ) ;
ASSERT_LT ( max_error , 10.0 ) ;
ASSERT_GT ( min_error , - 10.0 ) ;
}
2019-08-17 12:41:32 +00:00
2018-09-13 14:36:21 +00:00
bool HybridObservablesTestFpga : : ReadRinexObs ( std : : vector < arma : : mat > * obs_vec , Gnss_Synchro gnss )
{
// Open and read reference RINEX observables file
try
{
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2022-07-05 11:46:58 +00:00
gnsstk : : Rinex3ObsStream r_ref ( FLAGS_filename_rinex_obs ) ;
2024-04-29 06:27:33 +00:00
# else
gnsstk : : Rinex3ObsStream r_ref ( absl : : GetFlag ( FLAGS_filename_rinex_obs ) ) ;
# endif
2018-09-13 14:36:21 +00:00
r_ref . exceptions ( std : : ios : : failbit ) ;
2022-07-05 11:46:58 +00:00
gnsstk : : Rinex3ObsData r_ref_data ;
gnsstk : : Rinex3ObsHeader r_ref_header ;
2018-09-13 14:36:21 +00:00
2022-07-05 11:46:58 +00:00
gnsstk : : RinexDatum dataobj ;
2018-09-13 14:36:21 +00:00
r_ref > > r_ref_header ;
std : : vector < bool > first_row ;
2022-07-05 11:46:58 +00:00
gnsstk : : SatID prn ;
2018-09-13 14:36:21 +00:00
for ( unsigned int n = 0 ; n < gnss_synchro_vec . size ( ) ; n + + )
{
first_row . push_back ( true ) ;
obs_vec - > push_back ( arma : : zeros < arma : : mat > ( 1 , 4 ) ) ;
}
while ( r_ref > > r_ref_data )
{
for ( unsigned int n = 0 ; n < gnss_synchro_vec . size ( ) ; n + + )
{
int myprn = gnss_synchro_vec . at ( n ) . PRN ;
switch ( gnss . System )
{
case ' G ' :
2020-12-02 13:27:59 +00:00
# if OLD_GPSTK
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatID : : systemGPS ) ;
2020-12-02 13:27:59 +00:00
# else
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatelliteSystem : : GPS ) ;
2020-12-02 13:27:59 +00:00
# endif
2018-09-13 14:36:21 +00:00
break ;
case ' E ' :
2020-12-02 13:27:59 +00:00
# if OLD_GPSTK
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatID : : systemGalileo ) ;
2020-12-02 13:27:59 +00:00
# else
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatelliteSystem : : Galileo ) ;
2020-12-02 13:27:59 +00:00
# endif
2018-09-13 14:36:21 +00:00
break ;
default :
2020-12-02 13:27:59 +00:00
# if OLD_GPSTK
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatID : : systemGPS ) ;
2020-12-02 13:27:59 +00:00
# else
2022-07-05 11:46:58 +00:00
prn = gnsstk : : SatID ( myprn , gnsstk : : SatelliteSystem : : GPS ) ;
2020-12-02 13:27:59 +00:00
# endif
2018-09-13 14:36:21 +00:00
}
2022-07-05 11:46:58 +00:00
gnsstk : : CommonTime time = r_ref_data . time ;
2022-07-10 17:19:37 +00:00
# if GNSSTK_OLDER_THAN_9
2022-07-05 11:46:58 +00:00
double sow ( static_cast < gnsstk : : GPSWeekSecond > ( time ) . sow ) ;
2022-07-10 17:19:37 +00:00
# else
gnsstk : : GPSWeekSecond gws ( time ) ;
double sow ( gws . getSOW ( ) ) ;
# endif
2018-09-13 14:36:21 +00:00
2019-02-28 20:45:30 +00:00
auto pointer = r_ref_data . obs . find ( prn ) ;
2018-09-13 14:36:21 +00:00
if ( pointer = = r_ref_data . obs . end ( ) )
{
// PRN not present; do nothing
}
else
{
if ( first_row . at ( n ) = = false )
{
2019-08-18 23:29:04 +00:00
// insert next column
2018-09-13 14:36:21 +00:00
obs_vec - > at ( n ) . insert_rows ( obs_vec - > at ( n ) . n_rows , 1 ) ;
}
else
{
first_row . at ( n ) = false ;
}
if ( strcmp ( " 1C \0 " , gnss . Signal ) = = 0 )
{
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 0 ) = sow ;
dataobj = r_ref_data . getObs ( prn , " C1C " , r_ref_header ) ;
2019-08-18 23:29:04 +00:00
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 1 ) = dataobj . data ; // C1C P1 (psudorange L1)
2018-09-13 14:36:21 +00:00
dataobj = r_ref_data . getObs ( prn , " D1C " , r_ref_header ) ;
2019-08-18 23:29:04 +00:00
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 2 ) = dataobj . data ; // D1C Carrier Doppler
2018-09-13 14:36:21 +00:00
dataobj = r_ref_data . getObs ( prn , " L1C " , r_ref_header ) ;
2019-08-18 23:29:04 +00:00
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 3 ) = dataobj . data ; // L1C Carrier Phase
2018-09-13 14:36:21 +00:00
}
else if ( strcmp ( " 1B \0 " , gnss . Signal ) = = 0 )
{
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 0 ) = sow ;
dataobj = r_ref_data . getObs ( prn , " C1B " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 1 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " D1B " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 2 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " L1B " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 3 ) = dataobj . data ;
}
2019-08-18 23:29:04 +00:00
else if ( strcmp ( " 2S \0 " , gnss . Signal ) = = 0 ) // L2M
2018-09-13 14:36:21 +00:00
{
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 0 ) = sow ;
dataobj = r_ref_data . getObs ( prn , " C2S " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 1 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " D2S " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 2 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " L2S " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 3 ) = dataobj . data ;
}
else if ( strcmp ( " L5 \0 " , gnss . Signal ) = = 0 )
{
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 0 ) = sow ;
dataobj = r_ref_data . getObs ( prn , " C5I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 1 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " D5I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 2 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " L5I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 3 ) = dataobj . data ;
}
2019-12-16 17:44:22 +00:00
else if ( strcmp ( " 5X \0 " , gnss . Signal ) = = 0 ) // Simulator gives RINEX with E5a+E5b. Doppler and accumulated Carrier phase WILL differ
2018-09-13 14:36:21 +00:00
{
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 0 ) = sow ;
dataobj = r_ref_data . getObs ( prn , " C8I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 1 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " D8I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 2 ) = dataobj . data ;
dataobj = r_ref_data . getObs ( prn , " L8I " , r_ref_header ) ;
obs_vec - > at ( n ) ( obs_vec - > at ( n ) . n_rows - 1 , 3 ) = dataobj . data ;
}
else
{
2020-07-07 16:53:50 +00:00
std : : cout < < " ReadRinexObs unknown signal requested: " < < gnss . Signal < < ' \n ' ;
2018-09-13 14:36:21 +00:00
return false ;
}
}
}
} // end while
2020-02-23 01:43:17 +00:00
} // End of 'try' block
2019-12-16 17:44:22 +00:00
2022-07-05 11:46:58 +00:00
catch ( const gnsstk : : FFStreamError & e )
2018-09-13 14:36:21 +00:00
{
std : : cout < < e ;
return false ;
}
2022-07-05 11:46:58 +00:00
catch ( const gnsstk : : Exception & e )
2018-09-13 14:36:21 +00:00
{
std : : cout < < e ;
return false ;
}
catch ( const std : : exception & e )
{
std : : cout < < " Exception: " < < e . what ( ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " unknown error. I don't feel so well... \n " ;
2018-09-13 14:36:21 +00:00
return false ;
}
2020-07-07 16:53:50 +00:00
std : : cout < < " ReadRinexObs info: \n " ;
2019-12-16 17:44:22 +00:00
2018-09-13 14:36:21 +00:00
for ( unsigned int n = 0 ; n < gnss_synchro_vec . size ( ) ; n + + )
{
2020-07-07 16:53:50 +00:00
std : : cout < < " SAT PRN " < < gnss_synchro_vec . at ( n ) . PRN < < " RINEX epoch read: " < < obs_vec - > at ( n ) . n_rows < < ' \n ' ;
2018-09-13 14:36:21 +00:00
}
return true ;
}
2019-08-17 12:41:32 +00:00
2018-09-13 14:36:21 +00:00
TEST_F ( HybridObservablesTestFpga , ValidationOfResults )
{
2019-02-27 16:27:31 +00:00
// pointer to the DMA thread that sends the samples to the acquisition engine
pthread_t thread_DMA ;
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
struct DMA_handler_args_obs_test args ;
2018-09-13 14:36:21 +00:00
// Configure the signal generator
configure_generator ( ) ;
// Generate signal raw signal samples and observations RINEX file
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_disable_generator = = false )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_disable_generator ) = = false )
# endif
2018-09-13 14:36:21 +00:00
{
generate_signal ( ) ;
}
2019-02-27 12:30:09 +00:00
2018-09-13 14:36:21 +00:00
std : : chrono : : time_point < std : : chrono : : system_clock > start , end ;
std : : chrono : : duration < double > elapsed_seconds ( 0 ) ;
2024-04-29 06:27:33 +00:00
// use generator or use an external capture file
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( FLAGS_enable_external_signal_file )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_enable_external_signal_file ) )
# endif
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters
2018-09-13 14:36:21 +00:00
ASSERT_EQ ( acquire_signal ( ) , true ) ;
}
else
{
Gnss_Synchro tmp_gnss_synchro ;
tmp_gnss_synchro . System = ' G ' ;
std : : string signal = " 1C " ;
signal . copy ( tmp_gnss_synchro . Signal , 2 , 0 ) ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
std : : istringstream ss ( FLAGS_test_satellite_PRN_list ) ;
2024-04-29 06:27:33 +00:00
# else
std : : istringstream ss ( absl : : GetFlag ( FLAGS_test_satellite_PRN_list ) ) ;
# endif
2018-09-13 14:36:21 +00:00
std : : string token ;
while ( std : : getline ( ss , token , ' , ' ) )
{
tmp_gnss_synchro . PRN = boost : : lexical_cast < int > ( token ) ;
gnss_synchro_vec . push_back ( tmp_gnss_synchro ) ;
}
}
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
configure_receiver ( FLAGS_PLL_bw_hz_start ,
FLAGS_DLL_bw_hz_start ,
FLAGS_PLL_narrow_bw_hz ,
FLAGS_DLL_narrow_bw_hz ,
2019-12-16 17:44:22 +00:00
FLAGS_extend_correlation_symbols ,
FLAGS_smoother_length ,
FLAGS_high_dyn ) ;
2024-04-29 06:27:33 +00:00
# else
configure_receiver ( absl : : GetFlag ( FLAGS_PLL_bw_hz_start ) ,
absl : : GetFlag ( FLAGS_DLL_bw_hz_start ) ,
absl : : GetFlag ( FLAGS_PLL_narrow_bw_hz ) ,
absl : : GetFlag ( FLAGS_DLL_narrow_bw_hz ) ,
absl : : GetFlag ( FLAGS_extend_correlation_symbols ) ,
absl : : GetFlag ( FLAGS_smoother_length ) ,
absl : : GetFlag ( FLAGS_high_dyn ) ) ;
# endif
2018-09-13 14:36:21 +00:00
2019-02-28 20:45:30 +00:00
for ( auto & n : gnss_synchro_vec )
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// setup the signal synchronization, simulating an acquisition
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2018-09-13 14:36:21 +00:00
if ( ! FLAGS_enable_external_signal_file )
2024-04-29 06:27:33 +00:00
# else
if ( ! absl : : GetFlag ( FLAGS_enable_external_signal_file ) )
# endif
2018-09-13 14:36:21 +00:00
{
2019-08-18 23:29:04 +00:00
// based on true observables metadata (for custom sdr generator)
// open true observables log file written by the simulator or based on provided RINEX obs
2019-02-25 18:21:00 +00:00
std : : vector < std : : shared_ptr < Tracking_True_Obs_Reader > > true_reader_vec ;
2019-08-18 23:29:04 +00:00
// read true data from the generator logs
2019-02-25 18:21:00 +00:00
true_reader_vec . push_back ( std : : make_shared < Tracking_True_Obs_Reader > ( ) ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " Loading true observable data for PRN " < < n . PRN < < ' \n ' ;
2018-09-13 14:36:21 +00:00
std : : string true_obs_file = std : : string ( " ./gps_l1_ca_obs_prn " ) ;
2019-02-28 20:45:30 +00:00
true_obs_file . append ( std : : to_string ( n . PRN ) ) ;
2018-09-13 14:36:21 +00:00
true_obs_file . append ( " .dat " ) ;
ASSERT_NO_THROW ( {
if ( true_reader_vec . back ( ) - > open_obs_file ( true_obs_file ) = = false )
{
throw std : : exception ( ) ;
} ;
} ) < < " Failure opening true observables file " ;
// load acquisition data based on the first epoch of the true observations
ASSERT_NO_THROW ( {
if ( true_reader_vec . back ( ) - > read_binary_obs ( ) = = false )
{
throw std : : exception ( ) ;
} ;
} ) < < " Failure reading true observables file " ;
2019-08-18 23:29:04 +00:00
// restart the epoch counter
2018-09-13 14:36:21 +00:00
true_reader_vec . back ( ) - > restart ( ) ;
std : : cout < < " Initial Doppler [Hz]= " < < true_reader_vec . back ( ) - > doppler_l1_hz < < " Initial code delay [Chips]= "
2020-07-07 16:53:50 +00:00
< < true_reader_vec . back ( ) - > prn_delay_chips < < ' \n ' ;
2019-08-31 09:37:29 +00:00
n . Acq_delay_samples = ( GPS_L1_CA_CODE_LENGTH_CHIPS - true_reader_vec . back ( ) - > prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS ) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD_S ;
2019-02-28 20:45:30 +00:00
n . Acq_doppler_hz = true_reader_vec . back ( ) - > doppler_l1_hz ;
n . Acq_samplestamp_samples = 0 ;
2018-09-13 14:36:21 +00:00
}
else
{
2019-08-18 23:29:04 +00:00
// based on the signal acquisition process
2019-02-28 20:45:30 +00:00
std : : cout < < " Estimated Initial Doppler " < < n . Acq_doppler_hz
< < " [Hz], estimated Initial code delay " < < n . Acq_delay_samples < < " [Samples] "
2020-07-07 16:53:50 +00:00
< < " Acquisition SampleStamp is " < < n . Acq_samplestamp_samples < < ' \n ' ;
2020-02-11 20:47:13 +00:00
// n.Acq_samplestamp_samples = 0;
2018-09-13 14:36:21 +00:00
}
}
2019-12-16 17:44:22 +00:00
// We need to reset the HW again in order to reset the sample counter.
// The HW is reset by sending a command to the acquisition HW accelerator
// In order to send the reset command to the HW we instantiate the acquisition module.
2019-02-27 16:27:31 +00:00
std : : shared_ptr < AcquisitionInterface > acquisition ;
2019-02-15 09:12:20 +00:00
2019-12-30 16:50:41 +00:00
// set the scaling factor
args . scaling_factor = DMA_SIGNAL_SCALING_FACTOR ;
2019-12-16 17:44:22 +00:00
2019-02-04 14:01:50 +00:00
// reset the HW to clear the sample counters: the acquisition constructor generates a reset
2024-08-08 20:30:45 +00:00
if ( implementation = = " GPS_L1_CA_DLL_PLL_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
acquisition = std : : make_shared < GpsL1CaPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
args . freq_band = 0 ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E1_DLL_PLL_VEML_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
acquisition = std : : make_shared < GalileoE1PcpsAmbiguousAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
args . freq_band = 0 ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " Galileo_E5a_DLL_PLL_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
acquisition = std : : make_shared < GalileoE5aPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
args . freq_band = 1 ;
}
2024-08-08 20:30:45 +00:00
else if ( implementation = = " GPS_L5_DLL_PLL_Tracking_FPGA " )
2019-02-27 16:27:31 +00:00
{
acquisition = std : : make_shared < GpsL5iPcpsAcquisitionFpga > ( config . get ( ) , " Acquisition " , 0 , 0 ) ;
args . freq_band = 1 ;
}
else
{
std : : cout < < " The test can not run with the selected tracking implementation \n " ;
throw ( std : : exception ( ) ) ;
}
2019-02-04 14:01:50 +00:00
2019-12-16 17:44:22 +00:00
acquisition - > stop_acquisition ( ) ; // reset the whole system including the sample counters
2018-09-13 14:36:21 +00:00
std : : vector < std : : shared_ptr < TrackingInterface > > tracking_ch_vec ;
std : : vector < std : : shared_ptr < TelemetryDecoderInterface > > tlm_ch_vec ;
std : : vector < gr : : blocks : : null_sink : : sptr > null_sink_vec ;
for ( unsigned int n = 0 ; n < gnss_synchro_vec . size ( ) ; n + + )
{
2019-08-17 12:41:32 +00:00
// set channels ids
2018-09-13 14:36:21 +00:00
gnss_synchro_vec . at ( n ) . Channel_ID = n ;
2019-08-17 12:41:32 +00:00
// create the tracking channels and create the telemetry decoders
2020-07-13 13:17:15 +00:00
std : : shared_ptr < GNSSBlockInterface > trk_ = factory - > GetBlock ( config . get ( ) , " Tracking " , 1 , 1 ) ;
2018-09-13 14:36:21 +00:00
tracking_ch_vec . push_back ( std : : dynamic_pointer_cast < TrackingInterface > ( trk_ ) ) ;
2020-07-13 13:17:15 +00:00
std : : shared_ptr < GNSSBlockInterface > tlm_ = factory - > GetBlock ( config . get ( ) , " TelemetryDecoder " , 1 , 1 ) ;
2018-09-13 14:36:21 +00:00
tlm_ch_vec . push_back ( std : : dynamic_pointer_cast < TelemetryDecoderInterface > ( tlm_ ) ) ;
2019-08-18 23:29:04 +00:00
// create null sinks for observables output
2018-09-13 14:36:21 +00:00
null_sink_vec . push_back ( gr : : blocks : : null_sink : : make ( sizeof ( Gnss_Synchro ) ) ) ;
ASSERT_NO_THROW ( {
tlm_ch_vec . back ( ) - > set_channel ( gnss_synchro_vec . at ( n ) . Channel_ID ) ;
switch ( gnss_synchro_master . System )
{
case ' G ' :
tlm_ch_vec . back ( ) - > set_satellite ( Gnss_Satellite ( std : : string ( " GPS " ) , gnss_synchro_vec . at ( n ) . PRN ) ) ;
break ;
case ' E ' :
tlm_ch_vec . back ( ) - > set_satellite ( Gnss_Satellite ( std : : string ( " Galileo " ) , gnss_synchro_vec . at ( n ) . PRN ) ) ;
break ;
default :
tlm_ch_vec . back ( ) - > set_satellite ( Gnss_Satellite ( std : : string ( " GPS " ) , gnss_synchro_vec . at ( n ) . PRN ) ) ;
}
} ) < < " Failure setting gnss_synchro. " ;
ASSERT_NO_THROW ( {
tracking_ch_vec . back ( ) - > set_channel ( gnss_synchro_vec . at ( n ) . Channel_ID ) ;
} ) < < " Failure setting channel. " ;
ASSERT_NO_THROW ( {
tracking_ch_vec . back ( ) - > set_gnss_synchro ( & gnss_synchro_vec . at ( n ) ) ;
} ) < < " Failure setting gnss_synchro. " ;
}
2019-02-27 16:27:31 +00:00
top_block = gr : : make_top_block ( " Telemetry_Decoder test " ) ;
2020-04-02 21:59:35 +00:00
auto dummy_msg_rx_trk = HybridObservablesTest_msg_rx_Fpga_make ( ) ;
auto dummy_tlm_msg_rx = HybridObservablesTest_tlm_msg_rx_Fpga_make ( ) ;
2019-08-18 23:29:04 +00:00
// Observables
2019-02-27 16:27:31 +00:00
std : : shared_ptr < ObservablesInterface > observables ( new HybridObservables ( config . get ( ) , " Observables " , tracking_ch_vec . size ( ) + 1 , tracking_ch_vec . size ( ) ) ) ;
2018-09-13 14:36:21 +00:00
2019-02-28 20:45:30 +00:00
for ( auto & n : tracking_ch_vec )
2019-02-27 16:27:31 +00:00
{
ASSERT_NO_THROW ( {
2019-02-28 20:45:30 +00:00
n - > connect ( top_block ) ;
2019-02-27 16:27:31 +00:00
} ) < < " Failure connecting tracking to the top_block. " ;
}
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
std : : string file ;
2019-02-04 14:01:50 +00:00
2019-02-27 16:27:31 +00:00
ASSERT_NO_THROW ( {
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-02-27 16:27:31 +00:00
if ( ! FLAGS_enable_external_signal_file )
{
file = " ./ " + filename_raw_data ;
}
else
{
file = FLAGS_signal_file ;
}
2024-04-29 06:27:33 +00:00
# else
if ( ! absl : : GetFlag ( FLAGS_enable_external_signal_file ) )
{
file = " ./ " + filename_raw_data ;
}
else
{
file = absl : : GetFlag ( FLAGS_signal_file ) ;
}
# endif
2019-02-27 16:27:31 +00:00
int observable_interval_ms = 20 ;
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
double fs = static_cast < double > ( config - > property ( " GNSS-SDR.internal_fs_sps " , 0 ) ) ;
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
gnss_sdr_fpga_sample_counter_sptr ch_out_fpga_sample_counter ;
ch_out_fpga_sample_counter = gnss_sdr_make_fpga_sample_counter ( fs , observable_interval_ms ) ;
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
for ( unsigned int n = 0 ; n < tracking_ch_vec . size ( ) ; n + + )
{
2019-08-18 23:29:04 +00:00
// top_block->connect(gr_interleaved_char_to_complex, 0, tracking_ch_vec.at(n)->get_left_block(), 0);
2019-02-27 16:27:31 +00:00
top_block - > connect ( tracking_ch_vec . at ( n ) - > get_right_block ( ) , 0 , tlm_ch_vec . at ( n ) - > get_left_block ( ) , 0 ) ;
top_block - > connect ( tlm_ch_vec . at ( n ) - > get_right_block ( ) , 0 , observables - > get_left_block ( ) , n ) ;
top_block - > msg_connect ( tracking_ch_vec . at ( n ) - > get_right_block ( ) , pmt : : mp ( " events " ) , dummy_msg_rx_trk , pmt : : mp ( " events " ) ) ;
top_block - > connect ( observables - > get_right_block ( ) , n , null_sink_vec . at ( n ) , 0 ) ;
}
2019-08-18 23:29:04 +00:00
// connect sample counter and timmer to the last channel in observables block (extra channel)
top_block - > connect ( ch_out_fpga_sample_counter , 0 , observables - > get_left_block ( ) , tracking_ch_vec . size ( ) ) ; // extra port for the sample counter pulse
2019-02-27 16:27:31 +00:00
} ) < < " Failure connecting the blocks. " ;
2019-02-04 14:01:50 +00:00
2019-12-16 17:44:22 +00:00
top_block - > start ( ) ;
2019-02-04 14:01:50 +00:00
2019-12-30 17:43:46 +00:00
usleep ( 1000000 ) ; // give time for the system to start before receiving the start tracking command.
2019-02-04 14:01:50 +00:00
2019-02-28 20:45:30 +00:00
for ( auto & n : tracking_ch_vec )
2019-02-27 16:27:31 +00:00
{
2019-02-28 20:45:30 +00:00
n - > start_tracking ( ) ;
2019-02-27 16:27:31 +00:00
}
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
// wait to give time for the acquisition thread to set up the tracking process
usleep ( 1000000 ) ;
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
args . file = file ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
args . nsamples_tx = baseband_sampling_freq * FLAGS_duration ;
2024-04-29 06:27:33 +00:00
# else
args . nsamples_tx = baseband_sampling_freq * absl : : GetFlag ( FLAGS_duration ) ;
# endif
2019-12-16 17:44:22 +00:00
args . skip_used_samples = 0 ;
if ( pthread_create ( & thread_DMA , nullptr , handler_DMA_obs_test , reinterpret_cast < void * > ( & args ) ) < 0 )
{
2020-07-07 16:53:50 +00:00
std : : cout < < " ERROR cannot create DMA Process \n " ;
2019-12-16 17:44:22 +00:00
}
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
EXPECT_NO_THROW ( {
start = std : : chrono : : system_clock : : now ( ) ;
} ) < < " Failure running the top_block. " ;
2018-09-13 14:36:21 +00:00
2019-02-27 16:27:31 +00:00
// wait for the child DMA process to finish
2019-02-28 20:45:30 +00:00
pthread_join ( thread_DMA , nullptr ) ;
2018-09-13 14:36:21 +00:00
2019-12-16 17:44:22 +00:00
// stop the top block
2019-02-27 16:27:31 +00:00
top_block - > stop ( ) ;
2018-11-16 17:28:02 +00:00
2019-12-16 17:44:22 +00:00
// stop the tracking process:
for ( auto & n : tracking_ch_vec )
{
ASSERT_NO_THROW ( {
n - > stop_tracking ( ) ;
} ) < < " Failure connecting tracking to the top_block. " ;
}
2019-02-27 16:27:31 +00:00
acquisition - > stop_acquisition ( ) ;
2018-11-16 17:28:02 +00:00
2019-12-16 17:44:22 +00:00
EXPECT_NO_THROW ( {
end = std : : chrono : : system_clock : : now ( ) ;
elapsed_seconds = end - start ;
} ) < < " Failure running the top_block. " ;
2018-09-13 14:36:21 +00:00
2019-08-17 12:41:32 +00:00
// check results
2019-02-27 16:27:31 +00:00
// Matrices for storing columnwise true GPS time, Range, Doppler and Carrier phase
std : : vector < arma : : mat > true_obs_vec ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-02-27 16:27:31 +00:00
if ( ! FLAGS_enable_external_signal_file )
2024-04-29 06:27:33 +00:00
# else
if ( ! absl : : GetFlag ( FLAGS_enable_external_signal_file ) )
# endif
2019-02-27 16:27:31 +00:00
{
2019-08-17 12:41:32 +00:00
// load the true values
2019-02-27 16:27:31 +00:00
True_Observables_Reader true_observables ;
ASSERT_NO_THROW ( {
if ( true_observables . open_obs_file ( std : : string ( " ./obs_out.bin " ) ) = = false )
{
throw std : : exception ( ) ;
}
} ) < < " Failure opening true observables file " ;
2019-02-28 20:45:30 +00:00
auto nepoch = static_cast < unsigned int > ( true_observables . num_epochs ( ) ) ;
2019-02-27 16:27:31 +00:00
2020-07-07 16:53:50 +00:00
std : : cout < < " True observation epochs = " < < nepoch < < ' \n ' ;
2019-02-27 16:27:31 +00:00
true_observables . restart ( ) ;
int64_t epoch_counter = 0 ;
for ( unsigned int n = 0 ; n < tracking_ch_vec . size ( ) ; n + + )
{
true_obs_vec . push_back ( arma : : zeros < arma : : mat > ( nepoch , 4 ) ) ;
}
ASSERT_NO_THROW ( {
while ( true_observables . read_binary_obs ( ) )
{
for ( unsigned int n = 0 ; n < true_obs_vec . size ( ) ; n + + )
{
if ( round ( true_observables . prn [ n ] ) ! = gnss_synchro_vec . at ( n ) . PRN )
{
std : : cout < < " True observables SV PRN does not match measured ones: "
2020-07-07 16:53:50 +00:00
< < round ( true_observables . prn [ n ] ) < < " vs. " < < gnss_synchro_vec . at ( n ) . PRN < < ' \n ' ;
2019-02-27 16:27:31 +00:00
throw std : : exception ( ) ;
}
true_obs_vec . at ( n ) ( epoch_counter , 0 ) = true_observables . gps_time_sec [ n ] ;
true_obs_vec . at ( n ) ( epoch_counter , 1 ) = true_observables . dist_m [ n ] ;
true_obs_vec . at ( n ) ( epoch_counter , 2 ) = true_observables . doppler_l1_hz [ n ] ;
true_obs_vec . at ( n ) ( epoch_counter , 3 ) = true_observables . acc_carrier_phase_l1_cycles [ n ] ;
}
epoch_counter + + ;
}
} ) ;
}
else
{
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-30 17:43:46 +00:00
if ( ! FLAGS_duplicated_satellites_test )
2024-04-29 06:27:33 +00:00
# else
if ( ! absl : : GetFlag ( FLAGS_duplicated_satellites_test ) )
# endif
2019-12-30 17:43:46 +00:00
{
ASSERT_EQ ( ReadRinexObs ( & true_obs_vec , gnss_synchro_master ) , true )
< < " Failure reading RINEX file " ;
}
2019-02-27 16:27:31 +00:00
}
2019-08-17 12:41:32 +00:00
// read measured values
2019-02-27 16:27:31 +00:00
Observables_Dump_Reader estimated_observables ( tracking_ch_vec . size ( ) ) ;
ASSERT_NO_THROW ( {
if ( estimated_observables . open_obs_file ( std : : string ( " ./observables.dat " ) ) = = false )
{
throw std : : exception ( ) ;
}
} ) < < " Failure opening dump observables file " ;
2019-02-28 20:45:30 +00:00
auto nepoch = static_cast < unsigned int > ( estimated_observables . num_epochs ( ) ) ;
2020-07-07 16:53:50 +00:00
std : : cout < < " Measured observations epochs = " < < nepoch < < ' \n ' ;
2019-02-27 16:27:31 +00:00
// Matrices for storing columnwise measured RX_time, TOW, Doppler, Carrier phase and Pseudorange
std : : vector < arma : : mat > measured_obs_vec ;
std : : vector < int64_t > epoch_counters_vec ;
for ( unsigned int n = 0 ; n < tracking_ch_vec . size ( ) ; n + + )
{
measured_obs_vec . push_back ( arma : : zeros < arma : : mat > ( nepoch , 5 ) ) ;
epoch_counters_vec . push_back ( 0 ) ;
}
estimated_observables . restart ( ) ;
while ( estimated_observables . read_binary_obs ( ) )
{
for ( unsigned int n = 0 ; n < measured_obs_vec . size ( ) ; n + + )
{
if ( static_cast < bool > ( estimated_observables . valid [ n ] ) )
{
measured_obs_vec . at ( n ) ( epoch_counters_vec . at ( n ) , 0 ) = estimated_observables . RX_time [ n ] ;
measured_obs_vec . at ( n ) ( epoch_counters_vec . at ( n ) , 1 ) = estimated_observables . TOW_at_current_symbol_s [ n ] ;
measured_obs_vec . at ( n ) ( epoch_counters_vec . at ( n ) , 2 ) = estimated_observables . Carrier_Doppler_hz [ n ] ;
measured_obs_vec . at ( n ) ( epoch_counters_vec . at ( n ) , 3 ) = estimated_observables . Acc_carrier_phase_hz [ n ] ;
measured_obs_vec . at ( n ) ( epoch_counters_vec . at ( n ) , 4 ) = estimated_observables . Pseudorange_m [ n ] ;
epoch_counters_vec . at ( n ) + + ;
}
}
}
2019-08-17 12:41:32 +00:00
// Cut measurement tail zeros
2019-02-27 16:27:31 +00:00
arma : : uvec index ;
2019-02-28 20:45:30 +00:00
for ( auto & n : measured_obs_vec )
2019-02-27 16:27:31 +00:00
{
2019-02-28 20:45:30 +00:00
index = arma : : find ( n . col ( 0 ) > 0.0 , 1 , " last " ) ;
if ( ( ! index . empty ( ) ) and index ( 0 ) < ( nepoch - 1 ) )
2019-02-27 16:27:31 +00:00
{
2019-02-28 20:45:30 +00:00
n . shed_rows ( index ( 0 ) + 1 , nepoch - 1 ) ;
2019-02-27 16:27:31 +00:00
}
}
2024-04-29 06:27:33 +00:00
// Cut measurement initial transitory of the measurements
# if USE_GLOG_AND_GFLAGS
2019-02-27 16:27:31 +00:00
double initial_transitory_s = FLAGS_skip_obs_transitory_s ;
2024-04-29 06:27:33 +00:00
# else
double initial_transitory_s = absl : : GetFlag ( FLAGS_skip_obs_transitory_s ) ;
# endif
2019-02-27 16:27:31 +00:00
for ( unsigned int n = 0 ; n < measured_obs_vec . size ( ) ; n + + )
{
index = arma : : find ( measured_obs_vec . at ( n ) . col ( 0 ) > = ( measured_obs_vec . at ( n ) ( 0 , 0 ) + initial_transitory_s ) , 1 , " first " ) ;
2019-02-28 20:45:30 +00:00
if ( ( ! index . empty ( ) ) and ( index ( 0 ) > 0 ) )
2019-02-27 16:27:31 +00:00
{
measured_obs_vec . at ( n ) . shed_rows ( 0 , index ( 0 ) ) ;
}
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( ! FLAGS_duplicated_satellites_test )
2024-04-29 06:27:33 +00:00
# else
if ( ! absl : : GetFlag ( FLAGS_duplicated_satellites_test ) )
# endif
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
index = arma : : find ( measured_obs_vec . at ( n ) . col ( 0 ) > = true_obs_vec . at ( n ) ( 0 , 0 ) , 1 , " first " ) ;
if ( ( ! index . empty ( ) ) and ( index ( 0 ) > 0 ) )
{
measured_obs_vec . at ( n ) . shed_rows ( 0 , index ( 0 ) ) ;
}
2019-02-27 16:27:31 +00:00
}
}
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( FLAGS_duplicated_satellites_test )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_duplicated_satellites_test ) )
# endif
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
// special test mode for duplicated satellites
std : : vector < unsigned int > prn_pairs ;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
std : : stringstream ss ( FLAGS_duplicated_satellites_prns ) ;
2024-04-29 06:27:33 +00:00
# else
std : : stringstream ss ( absl : : GetFlag ( FLAGS_duplicated_satellites_prns ) ) ;
# endif
2019-12-16 17:44:22 +00:00
unsigned int i ;
while ( ss > > i )
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
prn_pairs . push_back ( i ) ;
if ( ss . peek ( ) = = ' , ' )
{
ss . ignore ( ) ;
}
}
if ( prn_pairs . size ( ) % 2 ! = 0 )
{
std : : cout < < " Test settings error: duplicated_satellites_prns are even \n " ;
2019-02-27 16:27:31 +00:00
}
else
{
2019-12-16 17:44:22 +00:00
for ( unsigned int n = 0 ; n < prn_pairs . size ( ) ; n = n + 2 )
{
int sat1_ch_id = - 1 ;
int sat2_ch_id = - 1 ;
for ( unsigned int ch = 0 ; ch < measured_obs_vec . size ( ) ; ch + + )
{
if ( epoch_counters_vec . at ( ch ) > 100 ) // discard non-valid channels
{
if ( gnss_synchro_vec . at ( ch ) . PRN = = prn_pairs . at ( n ) )
{
sat1_ch_id = ch ;
}
if ( gnss_synchro_vec . at ( ch ) . PRN = = prn_pairs . at ( n + 1 ) )
{
sat2_ch_id = ch ;
}
}
}
if ( sat1_ch_id ! = - 1 and sat2_ch_id ! = - 1 )
{
// compute single differences for the duplicated satellite
check_results_duplicated_satellite (
measured_obs_vec . at ( sat1_ch_id ) ,
measured_obs_vec . at ( sat2_ch_id ) ,
sat1_ch_id ,
" Duplicated sat [CH " + std : : to_string ( sat1_ch_id ) + " , " + std : : to_string ( sat2_ch_id ) + " ] PRNs " + std : : to_string ( gnss_synchro_vec . at ( sat1_ch_id ) . PRN ) + " , " + std : : to_string ( gnss_synchro_vec . at ( sat2_ch_id ) . PRN ) + " " ) ;
}
else
{
std : : cout < < " Satellites PRNs " < < prn_pairs . at ( n ) < < " and " < < prn_pairs . at ( n ) < < " not found \n " ;
}
}
2019-02-27 16:27:31 +00:00
}
}
2019-12-16 17:44:22 +00:00
else
{
// normal mode
2019-02-27 16:27:31 +00:00
2019-12-16 17:44:22 +00:00
// Correct the clock error using true values (it is not possible for a receiver to correct
// the receiver clock offset error at the observables level because it is required the
// decoding of the ephemeris data and solve the PVT equations)
2019-02-27 16:27:31 +00:00
2019-12-16 17:44:22 +00:00
// Find the reference satellite (the nearest) and compute the receiver time offset at observable level
double min_pr = std : : numeric_limits < double > : : max ( ) ;
unsigned int min_pr_ch_id = 0 ;
for ( unsigned int n = 0 ; n < measured_obs_vec . size ( ) ; n + + )
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
if ( epoch_counters_vec . at ( n ) > 100 ) // discard non-valid channels
2019-02-27 16:27:31 +00:00
{
2019-12-16 17:44:22 +00:00
{
if ( measured_obs_vec . at ( n ) ( 0 , 4 ) < min_pr )
{
min_pr = measured_obs_vec . at ( n ) ( 0 , 4 ) ;
min_pr_ch_id = n ;
}
}
2019-02-27 16:27:31 +00:00
}
else
{
2019-12-16 17:44:22 +00:00
std : : cout < < " PRN " < < gnss_synchro_vec . at ( n ) . PRN < < " has NO observations! \n " ;
2019-02-27 16:27:31 +00:00
}
}
2019-12-16 17:44:22 +00:00
arma : : vec receiver_time_offset_ref_channel_s ;
arma : : uvec index2 ;
index2 = arma : : find ( true_obs_vec . at ( min_pr_ch_id ) . col ( 0 ) > = measured_obs_vec . at ( min_pr_ch_id ) . col ( 0 ) ( 0 ) , 1 , " first " ) ;
if ( ( ! index2 . empty ( ) ) and ( index2 ( 0 ) > 0 ) )
{
2020-07-05 18:20:02 +00:00
receiver_time_offset_ref_channel_s = ( true_obs_vec . at ( min_pr_ch_id ) . col ( 1 ) ( index2 ( 0 ) ) - measured_obs_vec . at ( min_pr_ch_id ) . col ( 4 ) ( 0 ) ) / SPEED_OF_LIGHT_M_S ;
2020-07-07 16:53:50 +00:00
std : : cout < < " Ref. channel initial Receiver time offset " < < receiver_time_offset_ref_channel_s ( 0 ) * 1e3 < < " [ms] \n " ;
2019-12-16 17:44:22 +00:00
}
2019-02-27 16:27:31 +00:00
else
{
2019-12-16 17:44:22 +00:00
ASSERT_NO_THROW (
throw std : : exception ( ) ; )
< < " Error finding observation time epoch in the reference data " ;
}
for ( unsigned int n = 0 ; n < measured_obs_vec . size ( ) ; n + + )
{
// debug save to .mat
std : : vector < double > tmp_vector_x ( true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y ( true_obs_vec . at ( n ) . col ( 1 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 1 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 1 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x , tmp_vector_y , std : : string ( " true_pr_ch_ " + std : : to_string ( n ) ) ) ;
std : : vector < double > tmp_vector_x2 ( measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y2 ( measured_obs_vec . at ( n ) . col ( 4 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 4 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 4 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x2 , tmp_vector_y2 , std : : string ( " measured_pr_ch_ " + std : : to_string ( n ) ) ) ;
std : : vector < double > tmp_vector_x3 ( true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y3 ( true_obs_vec . at ( n ) . col ( 2 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 2 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 2 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x3 , tmp_vector_y3 , std : : string ( " true_doppler_ch_ " + std : : to_string ( n ) ) ) ;
std : : vector < double > tmp_vector_x4 ( measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y4 ( measured_obs_vec . at ( n ) . col ( 2 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 2 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 2 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x4 , tmp_vector_y4 , std : : string ( " measured_doppler_ch_ " + std : : to_string ( n ) ) ) ;
std : : vector < double > tmp_vector_x5 ( true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y5 ( true_obs_vec . at ( n ) . col ( 3 ) . colptr ( 0 ) ,
true_obs_vec . at ( n ) . col ( 3 ) . colptr ( 0 ) + true_obs_vec . at ( n ) . col ( 3 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x5 , tmp_vector_y5 , std : : string ( " true_cp_ch_ " + std : : to_string ( n ) ) ) ;
std : : vector < double > tmp_vector_x6 ( measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 0 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 0 ) . n_rows ) ;
std : : vector < double > tmp_vector_y6 ( measured_obs_vec . at ( n ) . col ( 3 ) . colptr ( 0 ) ,
measured_obs_vec . at ( n ) . col ( 3 ) . colptr ( 0 ) + measured_obs_vec . at ( n ) . col ( 3 ) . n_rows ) ;
save_mat_xy ( tmp_vector_x6 , tmp_vector_y6 , std : : string ( " measured_cp_ch_ " + std : : to_string ( n ) ) ) ;
if ( epoch_counters_vec . at ( n ) > 100 ) // discard non-valid channels
{
arma : : vec true_TOW_ref_ch_s = true_obs_vec . at ( min_pr_ch_id ) . col ( 0 ) - receiver_time_offset_ref_channel_s ( 0 ) ;
arma : : vec true_TOW_ch_s = true_obs_vec . at ( n ) . col ( 0 ) - receiver_time_offset_ref_channel_s ( 0 ) ;
// Compare measured observables
if ( min_pr_ch_id ! = n )
{
check_results_code_pseudorange ( true_obs_vec . at ( n ) ,
true_obs_vec . at ( min_pr_ch_id ) ,
true_TOW_ch_s ,
true_TOW_ref_ch_s ,
measured_obs_vec . at ( n ) ,
measured_obs_vec . at ( min_pr_ch_id ) ,
" [CH " + std : : to_string ( n ) + " ] PRN " + std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) + " " ) ;
// Do not compare E5a with E5 RINEX due to the Doppler frequency discrepancy caused by the different center frequencies
// E5a_fc=1176.45e6, E5b_fc=1207.14e6, E5_fc=1191.795e6;
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( strcmp ( " 5X \0 " , gnss_synchro_vec . at ( n ) . Signal ) ! = 0 or FLAGS_compare_with_5X )
2024-04-29 06:27:33 +00:00
# else
if ( strcmp ( " 5X \0 " , gnss_synchro_vec . at ( n ) . Signal ) ! = 0 or absl : : GetFlag ( FLAGS_compare_with_5X ) )
# endif
2019-12-16 17:44:22 +00:00
{
check_results_carrier_phase_double_diff ( true_obs_vec . at ( n ) ,
true_obs_vec . at ( min_pr_ch_id ) ,
true_TOW_ch_s ,
true_TOW_ref_ch_s ,
measured_obs_vec . at ( n ) ,
measured_obs_vec . at ( min_pr_ch_id ) ,
" [CH " + std : : to_string ( n ) + " ] PRN " + std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) + " " ) ;
check_results_carrier_doppler_double_diff ( true_obs_vec . at ( n ) ,
true_obs_vec . at ( min_pr_ch_id ) ,
true_TOW_ch_s ,
true_TOW_ref_ch_s ,
measured_obs_vec . at ( n ) ,
measured_obs_vec . at ( min_pr_ch_id ) ,
" [CH " + std : : to_string ( n ) + " ] PRN " + std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) + " " ) ;
}
}
else
{
2020-07-07 16:53:50 +00:00
std : : cout < < " [CH " < < std : : to_string ( n ) < < " ] PRN " < < std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) < < " is the reference satellite \n " ;
2019-12-16 17:44:22 +00:00
}
2024-04-29 06:27:33 +00:00
# if USE_GLOG_AND_GFLAGS
2019-12-16 17:44:22 +00:00
if ( FLAGS_compute_single_diffs )
2024-04-29 06:27:33 +00:00
# else
if ( absl : : GetFlag ( FLAGS_compute_single_diffs ) )
# endif
2019-12-16 17:44:22 +00:00
{
check_results_carrier_phase ( true_obs_vec . at ( n ) ,
true_TOW_ch_s ,
measured_obs_vec . at ( n ) ,
" [CH " + std : : to_string ( n ) + " ] PRN " + std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) + " " ) ;
check_results_carrier_doppler ( true_obs_vec . at ( n ) ,
true_TOW_ch_s ,
measured_obs_vec . at ( n ) ,
" [CH " + std : : to_string ( n ) + " ] PRN " + std : : to_string ( gnss_synchro_vec . at ( n ) . PRN ) + " " ) ;
}
}
else
{
std : : cout < < " PRN " < < gnss_synchro_vec . at ( n ) . PRN < < " has NO observations! \n " ;
}
2019-02-27 16:27:31 +00:00
}
}
2020-07-07 16:53:50 +00:00
std : : cout < < " Test completed in " < < elapsed_seconds . count ( ) < < " [s] \n " ;
2018-09-13 14:36:21 +00:00
}