diff --git a/src/algorithms/PVT/libs/gpx_printer.cc b/src/algorithms/PVT/libs/gpx_printer.cc index 3a8661e6d..1949bb7dc 100644 --- a/src/algorithms/PVT/libs/gpx_printer.cc +++ b/src/algorithms/PVT/libs/gpx_printer.cc @@ -1,6 +1,6 @@ /*! * \file gpx_printer.cc - * \brief Interface of a class that prints PVT information to a gpx file + * \brief Implementation of a class that prints PVT information to a gpx file * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc index 30193cb32..8a160dc54 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.cc @@ -38,6 +38,7 @@ #include "GPS_L1_CA.h" #include "configuration_interface.h" #include "gnss_sdr_flags.h" +#include "acq_conf.h" using google::LogMessage; @@ -49,29 +50,35 @@ GpsL1CaPcpsAcquisitionFineDoppler::GpsL1CaPcpsAcquisitionFineDoppler( std::string default_dump_filename = "./data/acquisition.dat"; DLOG(INFO) << "role " << role; + Acq_Conf acq_parameters = Acq_Conf(); item_type_ = configuration->property(role + ".item_type", default_item_type); long fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + acq_parameters.fs_in = fs_in_; dump_ = configuration->property(role + ".dump", false); + acq_parameters.dump = dump_; dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename); + acq_parameters.dump_filename = dump_filename_; doppler_max_ = configuration->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; - doppler_min_ = configuration->property(role + ".doppler_min", -doppler_max_); + acq_parameters.doppler_max = doppler_max_; sampled_ms_ = configuration->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms_; max_dwells_ = configuration->property(role + ".max_dwells", 1); + acq_parameters.max_dwells = max_dwells_; + + acq_parameters.blocking_on_standby = configuration->property(role + ".blocking_on_standby", false); //--- Find number of samples per spreading code ------------------------- vector_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); - + acq_parameters.samples_per_ms = vector_length_; code_ = new gr_complex[vector_length_]; if (item_type_.compare("gr_complex") == 0) { item_size_ = sizeof(gr_complex); - acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(max_dwells_, sampled_ms_, - doppler_max_, doppler_min_, fs_in_, vector_length_, - dump_, dump_filename_); + acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(acq_parameters); } else { diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h index 74bcd28a4..13e4357fe 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fine_doppler.h @@ -131,7 +131,6 @@ private: float threshold_; int doppler_max_; unsigned int doppler_step_; - int doppler_min_; unsigned int sampled_ms_; int max_dwells_; long fs_in_; diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc index c9b31b134..7e1ffa903 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.cc @@ -40,46 +40,43 @@ #include #include // std::rotate, std::fill_n #include +#include using google::LogMessage; -pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) +pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc(const Acq_Conf &conf_) { return pcps_acquisition_fine_doppler_cc_sptr( - new pcps_acquisition_fine_doppler_cc(max_dwells, sampled_ms, doppler_max, doppler_min, - fs_in, samples_per_ms, dump, dump_filename)); + new pcps_acquisition_fine_doppler_cc(conf_)); } -pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc( - int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, - long fs_in, int samples_per_ms, bool dump, - std::string dump_filename) : gr::block("pcps_acquisition_fine_doppler_cc", - gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, sizeof(gr_complex))) +pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(const Acq_Conf &conf_) + : gr::block("pcps_acquisition_fine_doppler_cc", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(0, 0, sizeof(gr_complex))) { this->message_port_register_out(pmt::mp("events")); + acq_parameters = conf_; d_sample_counter = 0; // SAMPLE COUNTER d_active = false; - d_fs_in = fs_in; - d_samples_per_ms = samples_per_ms; - d_sampled_ms = sampled_ms; - d_config_doppler_max = doppler_max; - d_config_doppler_min = doppler_min; + d_fs_in = conf_.fs_in; + d_samples_per_ms = conf_.samples_per_ms; + d_sampled_ms = conf_.sampled_ms; + d_config_doppler_max = conf_.doppler_max; + d_config_doppler_min = -conf_.doppler_max; d_fft_size = d_sampled_ms * d_samples_per_ms; // HS Acquisition - d_max_dwells = max_dwells; + d_max_dwells = conf_.max_dwells; d_gnuradio_forecast_samples = d_fft_size; - d_input_power = 0.0; d_state = 0; d_carrier = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); d_fft_codes = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); d_magnitude = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment())); + d_10_ms_buffer = static_cast(volk_gnsssdr_malloc(10 * d_samples_per_ms * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + // Direct FFT d_fft_if = new gr::fft::fft_complex(d_fft_size, true); @@ -87,10 +84,10 @@ pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc( d_ifft = new gr::fft::fft_complex(d_fft_size, false); // For dumping samples into a file - d_dump = dump; - d_dump_filename = dump_filename; + d_dump = conf_.dump; + d_dump_filename = conf_.dump_filename; - d_doppler_resolution = 0; + d_n_samples_in_buffer = 0; d_threshold = 0; d_num_doppler_points = 0; d_doppler_step = 0; @@ -102,9 +99,28 @@ pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc( d_test_statistics = 0; d_well_count = 0; d_channel = 0; + d_positive_acq = 0; + d_dump_number = 0; + d_dump_channel = 0; // this implementation can only produce dumps in channel 0 + //todo: migrate config parameters to the unified acquisition config class } +// Finds next power of two +// for n. If n itself is a +// power of two then returns n +unsigned int pcps_acquisition_fine_doppler_cc::nextPowerOf2(unsigned int n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; +} + void pcps_acquisition_fine_doppler_cc::set_doppler_step(unsigned int doppler_step) { d_doppler_step = doppler_step; @@ -138,12 +154,9 @@ pcps_acquisition_fine_doppler_cc::~pcps_acquisition_fine_doppler_cc() volk_gnsssdr_free(d_carrier); volk_gnsssdr_free(d_fft_codes); volk_gnsssdr_free(d_magnitude); + volk_gnsssdr_free(d_10_ms_buffer); delete d_ifft; delete d_fft_if; - if (d_dump) - { - d_dump_file.close(); - } free_grid_memory(); } @@ -167,8 +180,12 @@ void pcps_acquisition_fine_doppler_cc::init() d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; d_gnss_synchro->Acq_samplestamp_samples = 0; - d_input_power = 0.0; d_state = 0; + + if (d_dump) + { + grid_ = arma::fmat(d_fft_size, d_num_doppler_points, arma::fill::zeros); + } } @@ -187,6 +204,7 @@ void pcps_acquisition_fine_doppler_cc::reset_grid() d_well_count = 0; for (int i = 0; i < d_num_doppler_points; i++) { + //todo: use memset here for (unsigned int j = 0; j < d_fft_size; j++) { d_grid_data[i][j] = 0.0; @@ -215,52 +233,71 @@ void pcps_acquisition_fine_doppler_cc::update_carrier_wipeoff() } -double pcps_acquisition_fine_doppler_cc::search_maximum() +double pcps_acquisition_fine_doppler_cc::compute_CAF() { - float magt = 0.0; - float fft_normalization_factor; + float firstPeak = 0.0; int index_doppler = 0; uint32_t tmp_intex_t = 0; uint32_t index_time = 0; + // Look for correlation peaks in the results ============================== + // Find the highest peak and compare it to the second highest peak + // The second peak is chosen not closer than 1 chip to the highest peak + //--- Find the correlation peak and the carrier frequency -------------- for (int i = 0; i < d_num_doppler_points; i++) { volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_grid_data[i], d_fft_size); - if (d_grid_data[i][tmp_intex_t] > magt) + if (d_grid_data[i][tmp_intex_t] > firstPeak) { - magt = d_grid_data[i][tmp_intex_t]; - //std::cout<(d_fft_size) * static_cast(d_fft_size); - magt = magt / (fft_normalization_factor * fft_normalization_factor); + + // -- - Find 1 chip wide code phase exclude range around the peak + uint32_t samplesPerChip = ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(this->d_fs_in)); + int32_t excludeRangeIndex1 = index_time - samplesPerChip; + int32_t excludeRangeIndex2 = index_time + samplesPerChip; + + // -- - Correct code phase exclude range if the range includes array boundaries + if (excludeRangeIndex1 < 0) + { + excludeRangeIndex1 = d_fft_size + excludeRangeIndex1; + } + else if (excludeRangeIndex2 >= static_cast(d_fft_size)) + { + excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size; + } + + int32_t idx = excludeRangeIndex1; + do + { + d_grid_data[index_doppler][idx] = 0.0; + idx++; + if (idx == static_cast(d_fft_size)) idx = 0; + } + while (idx != excludeRangeIndex2); + + //--- Find the second highest correlation peak in the same freq. bin --- + volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_grid_data[index_doppler], d_fft_size); + float secondPeak = d_grid_data[index_doppler][tmp_intex_t]; // 5- Compute the test statistics and compare to the threshold - d_test_statistics = magt / (d_input_power * std::sqrt(d_well_count)); + d_test_statistics = firstPeak / secondPeak; // 4- record the maximum peak and the associated synchronization parameters d_gnss_synchro->Acq_delay_samples = static_cast(index_time); d_gnss_synchro->Acq_doppler_hz = static_cast(index_doppler * d_doppler_step + d_config_doppler_min); d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - // Record results to file if required - if (d_dump) - { - std::stringstream filename; - std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write - filename.str(""); - filename << "../data/test_statistics_" << d_gnss_synchro->System - << "_" << d_gnss_synchro->Signal << "_sat_" - << d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat"; - d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary); - d_dump_file.write(reinterpret_cast(d_grid_data[index_doppler]), n); //write directly |abs(x)|^2 in this Doppler bin? - d_dump_file.close(); - } - return d_test_statistics; } @@ -308,10 +345,9 @@ int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_cons d_ifft->execute(); // save the grid matrix delay file - volk_32fc_magnitude_squared_32f(p_tmp_vector, d_ifft->get_outbuf(), d_fft_size); - const float *old_vector = d_grid_data[doppler_index]; - volk_32f_x2_add_32f(d_grid_data[doppler_index], old_vector, p_tmp_vector, d_fft_size); + //accumulate grid values + volk_32f_x2_add_32f(d_grid_data[doppler_index], d_grid_data[doppler_index], p_tmp_vector, d_fft_size); } volk_gnsssdr_free(p_tmp_vector); @@ -319,18 +355,21 @@ int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_cons } -int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star &input_items) +int pcps_acquisition_fine_doppler_cc::estimate_Doppler() { // Direct FFT - int zero_padding_factor = 2; - int fft_size_extended = d_fft_size * zero_padding_factor; + int zero_padding_factor = 8; + int prn_replicas = 10; + int signal_samples = prn_replicas * d_fft_size; + //int fft_size_extended = nextPowerOf2(signal_samples * zero_padding_factor); + int fft_size_extended = signal_samples * zero_padding_factor; gr::fft::fft_complex *fft_operator = new gr::fft::fft_complex(fft_size_extended, true); //zero padding the entire vector std::fill_n(fft_operator->get_inbuf(), fft_size_extended, gr_complex(0.0, 0.0)); //1. generate local code aligned with the acquisition code phase estimation - gr_complex *code_replica = static_cast(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment())); + gr_complex *code_replica = static_cast(volk_gnsssdr_malloc(signal_samples * sizeof(gr_complex), volk_gnsssdr_get_alignment())); gps_l1_ca_code_gen_complex_sampled(code_replica, d_gnss_synchro->PRN, d_fs_in, 0); @@ -342,10 +381,13 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star std::rotate(code_replica, code_replica + (d_fft_size - shift_index), code_replica + d_fft_size - 1); } + for (int n = 0; n < prn_replicas - 1; n++) + { + memcpy(&code_replica[(n + 1) * d_fft_size], code_replica, d_fft_size * sizeof(gr_complex)); + } //2. Perform code wipe-off - const gr_complex *in = reinterpret_cast(input_items[0]); //Get the input samples pointer - volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), in, code_replica, d_fft_size); + volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), d_10_ms_buffer, code_replica, signal_samples); // 3. Perform the FFT (zero padded!) fft_operator->execute(); @@ -380,40 +422,12 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star if (std::abs(fftFreqBins[tmp_index_freq] - d_gnss_synchro->Acq_doppler_hz) < 1000) { d_gnss_synchro->Acq_doppler_hz = static_cast(fftFreqBins[tmp_index_freq]); - //std::cout<<"FFT maximum present at "<PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write(reinterpret_cast(code_replica), n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); - // - // filename.str(""); - // filename << "../data/signal_prn_" << d_gnss_synchro->PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write(reinterpret_cast(in), n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); - // - // - // n = sizeof(float) * (fft_size_extended); - // filename.str(""); - // filename << "../data/fft_prn_" << d_gnss_synchro->PRN << ".dat"; - // d_dump_file.open(filename.str().c_str(), std::ios::out - // | std::ios::binary); - // d_dump_file.write(reinterpret_cast(p_tmp_vector), n); //write directly |abs(x)|^2 in this Doppler bin? - // d_dump_file.close(); } // free memory!! @@ -423,6 +437,12 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star return d_fft_size; } +// Called by gnuradio to enable drivers, etc for i/o devices. +bool pcps_acquisition_fine_doppler_cc::start() +{ + d_sample_counter = 0; + return true; +} int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, @@ -442,29 +462,33 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, * S5. Negative_Acq: Send message and stop acq -> S0 */ + int samples_remaining; switch (d_state) { case 0: // S0. StandBy - //DLOG(INFO) <<"S0"<= d_max_dwells) { d_state = 2; } + d_sample_counter += d_fft_size; // sample counter + consume_each(d_fft_size); break; case 2: // Compute test statistics and decide - //DLOG(INFO) <<"S2"< d_threshold) { d_state = 3; //perform fine doppler estimation @@ -473,15 +497,35 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, { d_state = 5; //negative acquisition } + d_n_samples_in_buffer = 0; + // Record results to file if required + if (d_dump and d_channel == d_dump_channel) + { + dump_results(d_fft_size); + } + d_sample_counter += d_fft_size; // sample counter + consume_each(d_fft_size); break; case 3: // Fine doppler estimation - //DLOG(INFO) <<"S3"< noutput_items) + { + memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast(input_items[0]), noutput_items * sizeof(gr_complex)); + d_n_samples_in_buffer += noutput_items; + d_sample_counter += noutput_items; // sample counter + consume_each(noutput_items); + } + else + { + memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast(input_items[0]), samples_remaining * sizeof(gr_complex)); + estimate_Doppler(); //disabled in repo + d_sample_counter += samples_remaining; // sample counter + consume_each(samples_remaining); + d_state = 4; + } break; case 4: // Positive_Acq - //DLOG(INFO) <<"S4"<System << " " << d_gnss_synchro->PRN; DLOG(INFO) << "sample_stamp " << d_sample_counter; @@ -489,15 +533,18 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, DLOG(INFO) << "test statistics threshold " << d_threshold; DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - + d_positive_acq = 1; d_active = false; // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += noutput_items; // sample counter + consume_each(noutput_items); + } break; case 5: // Negative_Acq - //DLOG(INFO) <<"S5"<System << " " << d_gnss_synchro->PRN; DLOG(INFO) << "sample_stamp " << d_sample_counter; @@ -505,20 +552,103 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items, DLOG(INFO) << "test statistics threshold " << d_threshold; DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples; DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz; - DLOG(INFO) << "input signal power " << d_input_power; - + d_positive_acq = 0; d_active = false; // Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += noutput_items; // sample counter + consume_each(noutput_items); + } break; default: d_state = 0; + if (!acq_parameters.blocking_on_standby) + { + d_sample_counter += noutput_items; // sample counter + consume_each(noutput_items); + } break; } - - //DLOG(INFO)<<"d_sample_counter="<System); + filename.append("_"); + filename.append(1, d_gnss_synchro->Signal[0]); + filename.append(1, d_gnss_synchro->Signal[1]); + filename.append("_ch_"); + filename.append(std::to_string(d_channel)); + filename.append("_"); + filename.append(std::to_string(d_dump_number)); + filename.append("_sat_"); + filename.append(std::to_string(d_gnss_synchro->PRN)); + filename.append(".mat"); + + mat_t *matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT73); + if (matfp == NULL) + { + std::cout << "Unable to create or open Acquisition dump file" << std::endl; + d_dump = false; + } + else + { + size_t dims[2] = {static_cast(effective_fft_size), static_cast(d_num_doppler_points)}; + matvar_t *matvar = Mat_VarCreate("acq_grid", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, grid_.memptr(), 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + dims[0] = static_cast(1); + dims[1] = static_cast(1); + matvar = Mat_VarCreate("doppler_max", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_config_doppler_max, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("doppler_step", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_doppler_step, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("d_positive_acq", MAT_C_INT32, MAT_T_INT32, 1, dims, &d_positive_acq, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + float aux = static_cast(d_gnss_synchro->Acq_doppler_hz); + matvar = Mat_VarCreate("acq_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + aux = static_cast(d_gnss_synchro->Acq_delay_samples); + matvar = Mat_VarCreate("acq_delay_samples", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("test_statistic", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_test_statistics, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("threshold", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_threshold, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + aux = 0.0; + matvar = Mat_VarCreate("input_power", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("sample_counter", MAT_C_UINT64, MAT_T_UINT64, 1, dims, &d_sample_counter, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_gnss_synchro->PRN, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + + Mat_Close(matfp); + } } diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h index d34121910..7788e12d6 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fine_doppler_cc.h @@ -1,8 +1,9 @@ /*! * \file pcps_acquisition_fine_doppler_acquisition_cc.h * \brief This class implements a Parallel Code Phase Search Acquisition with multi-dwells and fine Doppler estimation + * for GPS L1 C/A signal * - * Acquisition strategy (Kay Borre book + CFAR threshold). + * Acquisition strategy (Kay Borre book). *
    *
  1. Compute the input signal power estimation *
  2. Doppler serial search loop @@ -49,11 +50,13 @@ #define GNSS_SDR_PCPS_ACQUISITION_FINE_DOPPLER_CC_H_ #include "gnss_synchro.h" +#include "acq_conf.h" #include #include #include #include #include +#include class pcps_acquisition_fine_doppler_cc; @@ -61,46 +64,33 @@ typedef boost::shared_ptr pcps_acquisition_fine_doppler_cc_sptr; pcps_acquisition_fine_doppler_cc_sptr -pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long fs_in, int samples_per_ms, - bool dump, std::string dump_filename); +pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_); /*! * \brief This class implements a Parallel Code Phase Search Acquisition. * - * Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver", - * Algorithm 1, for a pseudocode description of this implementation. */ class pcps_acquisition_fine_doppler_cc : public gr::block { private: friend pcps_acquisition_fine_doppler_cc_sptr - pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); - - pcps_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms, - int doppler_max, int doppler_min, long fs_in, - int samples_per_ms, bool dump, - std::string dump_filename); - - void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift, - int doppler_offset); + pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_); + pcps_acquisition_fine_doppler_cc(const Acq_Conf& conf_); int compute_and_accumulate_grid(gr_vector_const_void_star& input_items); - int estimate_Doppler(gr_vector_const_void_star& input_items); + int estimate_Doppler(); float estimate_input_power(gr_vector_const_void_star& input_items); - double search_maximum(); + double compute_CAF(); void reset_grid(); void update_carrier_wipeoff(); void free_grid_memory(); + bool start(); + Acq_Conf acq_parameters; long d_fs_in; int d_samples_per_ms; int d_max_dwells; - unsigned int d_doppler_resolution; int d_gnuradio_forecast_samples; float d_threshold; std::string d_satellite_str; @@ -114,6 +104,7 @@ private: unsigned long int d_sample_counter; gr_complex* d_carrier; gr_complex* d_fft_codes; + gr_complex* d_10_ms_buffer; float* d_magnitude; float** d_grid_data; @@ -124,17 +115,23 @@ private: Gnss_Synchro* d_gnss_synchro; unsigned int d_code_phase; float d_doppler_freq; - float d_input_power; float d_test_statistics; - std::ofstream d_dump_file; + int d_positive_acq; + int d_state; bool d_active; int d_well_count; + int d_n_samples_in_buffer; bool d_dump; unsigned int d_channel; std::string d_dump_filename; + arma::fmat grid_; + long int d_dump_number; + unsigned int d_dump_channel; + + public: /*! * \brief Default destructor. @@ -187,6 +184,7 @@ public: inline void set_channel(unsigned int channel) { d_channel = channel; + d_dump_channel = d_channel; } /*! @@ -222,6 +220,14 @@ public: gr_vector_void_star& output_items); void forecast(int noutput_items, gr_vector_int& ninput_items_required); + + /*! + * \brief Obtains the next power of 2 greater or equal to the input parameter + * \param n - Integer value to obtain the next power of 2. + */ + unsigned int nextPowerOf2(unsigned int n); + + void dump_results(int effective_fft_size); }; #endif /* pcps_acquisition_fine_doppler_cc*/ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4eebaa950..62d75f86c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -19,4 +19,4 @@ add_subdirectory(system_parameters) add_subdirectory(libs) add_subdirectory(receiver) - +add_subdirectory(monitor) diff --git a/src/core/monitor/CMakeLists.txt b/src/core/monitor/CMakeLists.txt new file mode 100644 index 000000000..545e8641e --- /dev/null +++ b/src/core/monitor/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) +# +# This file is part of GNSS-SDR. +# +# GNSS-SDR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GNSS-SDR is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNSS-SDR. If not, see . +# + + +set(CORE_MONITOR_LIBS_SOURCES + gnss_synchro_monitor.cc + gnss_synchro_udp_sink.cc +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/core/system_parameters + ${GLOG_INCLUDE_DIRS} + ${GFlags_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +file(GLOB CORE_MONITOR_LIBS_HEADERS "*.h") +list(SORT CORE_MONITOR_LIBS_HEADERS) +add_library(core_monitor_lib ${CORE_MONITOR_LIBS_SOURCES} ${CORE_MONITOR_LIBS_HEADERS}) +source_group(Headers FILES ${CORE_MONITOR_LIBS_HEADERS}) +target_link_libraries(core_monitor_lib ${Boost_LIBRARIES}) diff --git a/src/core/monitor/gnss_synchro_monitor.cc b/src/core/monitor/gnss_synchro_monitor.cc new file mode 100644 index 000000000..bde09ef69 --- /dev/null +++ b/src/core/monitor/gnss_synchro_monitor.cc @@ -0,0 +1,92 @@ +/*! + * \file gnss_synchro_monitor.cc + * \brief Interface of a Position Velocity and Time computation block + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_synchro_monitor.h" +#include "gnss_synchro.h" +#include +#include +#include + + +using google::LogMessage; + + +gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses) +{ + return gnss_synchro_monitor_sptr(new gnss_synchro_monitor(n_channels, + output_rate_ms, + udp_port, + udp_addresses)); +} + + +gnss_synchro_monitor::gnss_synchro_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses) : gr::sync_block("gnss_synchro_monitor", + gr::io_signature::make(n_channels, n_channels, sizeof(Gnss_Synchro)), + gr::io_signature::make(0, 0, 0)) +{ + d_output_rate_ms = output_rate_ms; + d_nchannels = n_channels; + + udp_sink_ptr = std::unique_ptr(new Gnss_Synchro_Udp_Sink(udp_addresses, udp_port)); +} + + +gnss_synchro_monitor::~gnss_synchro_monitor() +{ +} + + +int gnss_synchro_monitor::work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items __attribute__((unused))) +{ + const Gnss_Synchro** in = reinterpret_cast(&input_items[0]); // Get the input buffer pointer + for (int epoch = 0; epoch < noutput_items; epoch++) + { + // ############ 1. READ PSEUDORANGES #### + for (unsigned int i = 0; i < d_nchannels; i++) + { + //if (in[i][epoch].Flag_valid_pseudorange) + // { + // } + //todo: send the gnss_synchro objects + + std::vector stocks; + stocks.push_back(in[i][epoch]); + udp_sink_ptr->write_gnss_synchro(stocks); + } + } + return noutput_items; +} diff --git a/src/core/monitor/gnss_synchro_monitor.h b/src/core/monitor/gnss_synchro_monitor.h new file mode 100644 index 000000000..36b6f1e3a --- /dev/null +++ b/src/core/monitor/gnss_synchro_monitor.h @@ -0,0 +1,81 @@ +/*! + * \file gnss_synchro_monitor.h + * \brief Interface of a Position Velocity and Time computation block + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GNSS_SYNCHRO_MONITOR_H +#define GNSS_SDR_GNSS_SYNCHRO_MONITOR_H + + +#include "gnss_synchro_udp_sink.h" +#include +#include +#include +#include + + +class gnss_synchro_monitor; + +typedef boost::shared_ptr gnss_synchro_monitor_sptr; + +gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int n_channels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + +/*! + * \brief This class implements a block that computes the PVT solution with Galileo E1 signals + */ +class gnss_synchro_monitor : public gr::sync_block +{ +private: + friend gnss_synchro_monitor_sptr gnss_synchro_make_monitor(unsigned int nchannels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + + unsigned int d_nchannels; + + int d_output_rate_ms; + + std::unique_ptr udp_sink_ptr; + + +public: + gnss_synchro_monitor(unsigned int nchannels, + int output_rate_ms, + int udp_port, + std::vector udp_addresses); + + ~gnss_synchro_monitor(); //!< Default destructor + + int work(int noutput_items, gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +#endif diff --git a/src/core/monitor/gnss_synchro_udp_sink.cc b/src/core/monitor/gnss_synchro_udp_sink.cc new file mode 100644 index 000000000..52b53b260 --- /dev/null +++ b/src/core/monitor/gnss_synchro_udp_sink.cc @@ -0,0 +1,69 @@ +/*! + * \file gnss_synchro_udp_sink.cc + * \brief Implementation of a class that sends serialized Gnss_Synchro + * objects over udp to one or multiple endponits + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include "gnss_synchro_udp_sink.h" +#include +#include +#include +#include + +Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(std::vector addresses, const unsigned short& port) : socket{io_service} +{ + for (auto address : addresses) + { + boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), port); + endpoints.push_back(endpoint); + } +} + +bool Gnss_Synchro_Udp_Sink::write_gnss_synchro(std::vector stocks) +{ + std::ostringstream archive_stream; + boost::archive::binary_oarchive oa{archive_stream}; + oa << stocks; + std::string outbound_data = archive_stream.str(); + + for (auto endpoint : endpoints) + { + socket.open(endpoint.protocol(), error); + socket.connect(endpoint, error); + + try + { + socket.send(boost::asio::buffer(outbound_data)); + } + catch (boost::system::system_error const& e) + { + return false; + } + } + return true; +} diff --git a/src/core/monitor/gnss_synchro_udp_sink.h b/src/core/monitor/gnss_synchro_udp_sink.h new file mode 100644 index 000000000..cf3cfc91d --- /dev/null +++ b/src/core/monitor/gnss_synchro_udp_sink.h @@ -0,0 +1,53 @@ +/*! + * \file gnss_synchro_udp_sink.h + * \brief Interface of a class that sends serialized Gnss_Synchro objects + * over udp to one or multiple endponits + * \author Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#ifndef GNSS_SYNCHRO_UDP_SINK_H_ +#define GNSS_SYNCHRO_UDP_SINK_H_ + +#include +#include "gnss_synchro.h" + +class Gnss_Synchro_Udp_Sink +{ +public: + Gnss_Synchro_Udp_Sink(std::vector addresses, const unsigned short &port); + bool write_gnss_synchro(std::vector stocks); + +private: + boost::asio::io_service io_service; + boost::asio::ip::udp::socket socket; + boost::system::error_code error; + std::vector endpoints; + std::vector stocks; +}; + + +#endif /* GNSS_SYNCHRO_UDP_SINK_H_ */ diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index 7be920a47..46a13614e 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -111,6 +111,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core/libs/supl ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl + ${CMAKE_SOURCE_DIR}/src/core/monitor ${CMAKE_SOURCE_DIR}/src/algorithms/libs ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/libs ${CMAKE_SOURCE_DIR}/src/algorithms/signal_source/adapters @@ -178,4 +179,5 @@ target_link_libraries(gnss_rx ${Boost_LIBRARIES} pvt_adapters pvt_lib rx_core_lib + core_monitor_lib ) diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index ab9589658..b5b978d9f 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -4,6 +4,7 @@ * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Luis Esteve, 2012. luis(at)epsilon-formacion.com * Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * ------------------------------------------------------------------------- * @@ -496,6 +497,25 @@ void GNSSFlowgraph::connect() return; } + // GNSS SYNCHRO MONITOR + if (enable_monitor_) + { + try + { + for (unsigned int i = 0; i < channels_count_; i++) + { + top_block_->connect(observables_->get_right_block(), i, GnssSynchroMonitor_, i); + } + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect observables to Monitor block"; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; + } + } + // Activate acquisition in enabled channels for (unsigned int i = 0; i < channels_count_; i++) { @@ -1091,6 +1111,25 @@ void GNSSFlowgraph::init() set_channels_state(); applied_actions_ = 0; DLOG(INFO) << "Blocks instantiated. " << channels_count_ << " channels."; + + /* + * Instantiate the receiver monitor block, if required + */ + enable_monitor_ = configuration_->property("Monitor.enable_monitor", false); + + std::vector udp_addr_vec; + + std::string address_string = configuration_->property("Monitor.client_addresses", std::string("127.0.0.1")); + //todo: split the string in substrings using the separator and fill the address vector. + udp_addr_vec.push_back(address_string); + + if (enable_monitor_) + { + GnssSynchroMonitor_ = gr::basic_block_sptr(new gnss_synchro_monitor(channels_count_, + configuration_->property("Monitor.output_rate_ms", 1), + configuration_->property("Monitor.udp_port", 1234), + udp_addr_vec)); + } } diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index 5da90cd1f..00a6ced4e 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -4,6 +4,7 @@ * \author Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Luis Esteve, 2011. luis(at)epsilon-formacion.com * Carles Fernandez-Prades, 2014. cfernandez(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * * It contains a signal source, * a signal conditioner, a set of channels, an observables block and a pvt. @@ -39,6 +40,7 @@ #include "GPS_L1_CA.h" #include "gnss_signal.h" #include "gnss_sdr_sample_counter.h" +#include "gnss_synchro_monitor.h" #include #include #include @@ -185,6 +187,9 @@ private: std::vector channels_state_; std::mutex signal_list_mutex; + + bool enable_monitor_; + gr::basic_block_sptr GnssSynchroMonitor_; }; #endif /*GNSS_SDR_GNSS_FLOWGRAPH_H_*/ diff --git a/src/core/system_parameters/gnss_synchro.h b/src/core/system_parameters/gnss_synchro.h index 922420bc4..6e240c0c3 100644 --- a/src/core/system_parameters/gnss_synchro.h +++ b/src/core/system_parameters/gnss_synchro.h @@ -4,6 +4,7 @@ * \author * Luis Esteve, 2012. luis(at)epsilon-formacion.com * Javier Arribas, 2012. jarribas(at)cttc.es + * Álvaro Cebrián Juan, 2018. acebrianjuan(at)gmail.com * ------------------------------------------------------------------------- * * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) @@ -73,6 +74,44 @@ public: double RX_time; //!< Set by Observables processing block bool Flag_valid_pseudorange; //!< Set by Observables processing block double interp_TOW_ms; //!< Set by Observables processing block + + + /*! + * \brief This member function is necessary to serialize and restore + * Gnss_Synchro objects from a byte stream. + */ + template + void serialize(Archive& ar, const unsigned int version) + { + // Satellite and signal info + ar& System; + ar& Signal; + ar& PRN; + ar& Channel_ID; + ar& Acq_delay_samples; + ar& Acq_doppler_hz; + ar& Acq_samplestamp_samples; + ar& Flag_valid_acquisition; + //Tracking + ar& fs; + ar& Prompt_I; + ar& Prompt_Q; + ar& CN0_dB_hz; + ar& Carrier_Doppler_hz; + ar& Carrier_phase_rads; + ar& Code_phase_samples; + ar& Tracking_sample_counter; + ar& Flag_valid_symbol_output; + ar& correlation_length_ms; + //Telemetry Decoder + ar& Flag_valid_word; + ar& TOW_at_current_symbol_ms; + // Observables + ar& Pseudorange_m; + ar& RX_time; + ar& Flag_valid_pseudorange; + ar& interp_TOW_ms; + } }; #endif diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f24dcd8cc..54b3ac685 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -307,6 +307,7 @@ set(LIST_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/core/libs/supl ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl + ${CMAKE_SOURCE_DIR}/src/core/monitor ${CMAKE_SOURCE_DIR}/src/algorithms/libs ${CMAKE_SOURCE_DIR}/src/algorithms/libs/rtklib ${CMAKE_SOURCE_DIR}/src/algorithms/data_type_adapter/adapters diff --git a/src/tests/common-files/gnuplot_i.h b/src/tests/common-files/gnuplot_i.h index afafef972..7d8b58106 100644 --- a/src/tests/common-files/gnuplot_i.h +++ b/src/tests/common-files/gnuplot_i.h @@ -218,6 +218,7 @@ public: const std::string &labely = "y", const std::string &labelz = "z"); + /// destructor: needed to delete temporary files ~Gnuplot(); @@ -246,6 +247,9 @@ public: /// sets terminal type to terminal_std Gnuplot &showonscreen(); // window output is set by default (win/x11/aqua) + /// sets terminal type to unknown (disable the screen output) + Gnuplot &disablescreen(); + /// saves a gnuplot session to a postscript file, filename without extension Gnuplot &savetops(const std::string &filename = "gnuplot_output"); @@ -1195,6 +1199,17 @@ Gnuplot &Gnuplot::set_smooth(const std::string &stylestr) } +//------------------------------------------------------------------------------ +// +// Disable screen output +// +Gnuplot &Gnuplot::disablescreen() +{ + cmd("set output"); + cmd("set terminal unknown"); + return *this; +} + //------------------------------------------------------------------------------ // // sets terminal type to windows / x11 @@ -2090,19 +2105,19 @@ std::string Gnuplot::create_tmpfile(std::ofstream &tmp) throw GnuplotException(except.str()); } - // int mkstemp(char *name); - // shall replace the contents of the string pointed to by "name" by a unique - // filename, and return a file descriptor for the file open for reading and - // writing. Otherwise, -1 shall be returned if no suitable file could be - // created. The string in template should look like a filename with six - // trailing 'X' s; mkstemp() replaces each 'X' with a character from the - // portable filename character set. The characters are chosen such that the - // resulting name does not duplicate the name of an existing file at the - // time of a call to mkstemp() +// int mkstemp(char *name); +// shall replace the contents of the string pointed to by "name" by a unique +// filename, and return a file descriptor for the file open for reading and +// writing. Otherwise, -1 shall be returned if no suitable file could be +// created. The string in template should look like a filename with six +// trailing 'X' s; mkstemp() replaces each 'X' with a character from the +// portable filename character set. The characters are chosen such that the +// resulting name does not duplicate the name of an existing file at the +// time of a call to mkstemp() - // - // open temporary files for output - // +// +// open temporary files for output +// #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) if (_mktemp(name) == NULL) diff --git a/src/tests/common-files/tracking_tests_flags.h b/src/tests/common-files/tracking_tests_flags.h index bed99d3d7..dc54da91e 100644 --- a/src/tests/common-files/tracking_tests_flags.h +++ b/src/tests/common-files/tracking_tests_flags.h @@ -36,7 +36,8 @@ // Input signal configuration DEFINE_bool(enable_external_signal_file, false, "Use an external signal file capture instead of the software-defined signal generator"); -DEFINE_string(signal_file, std::string("gps_l1_capture.dat"), "Path of the external signal capture file"); +DEFINE_int32(external_signal_acquisition_threshold, 2.0, "Threshold for satellite acquisition when external file is used"); +DEFINE_string(signal_file, std::string("signal_out.bin"), "Path of the external signal capture file"); DEFINE_double(CN0_dBHz_start, std::numeric_limits::infinity(), "Enable noise generator and set the CN0 start sweep value [dB-Hz]"); DEFINE_double(CN0_dBHz_stop, std::numeric_limits::infinity(), "Enable noise generator and set the CN0 stop sweep value [dB-Hz]"); DEFINE_double(CN0_dB_step, 3.0, "Noise generator CN0 sweep step value [dB]"); @@ -52,13 +53,13 @@ DEFINE_double(DLL_bw_hz_step, 0.25, "DLL Wide configuration sweep step value [Hz DEFINE_double(PLL_narrow_bw_hz, 5.0, "PLL Narrow configuration value [Hz]"); DEFINE_double(DLL_narrow_bw_hz, 0.75, "DLL Narrow configuration value [Hz]"); -DEFINE_double(Acq_Doppler_error_hz_start, 500.0, "Acquisition Doppler error start sweep value [Hz]"); -DEFINE_double(Acq_Doppler_error_hz_stop, -500.0, "Acquisition Doppler error stop sweep value [Hz]"); -DEFINE_double(Acq_Doppler_error_hz_step, -50.0, "Acquisition Doppler error sweep step value [Hz]"); +DEFINE_double(acq_Doppler_error_hz_start, 1000.0, "Acquisition Doppler error start sweep value [Hz]"); +DEFINE_double(acq_Doppler_error_hz_stop, -1000.0, "Acquisition Doppler error stop sweep value [Hz]"); +DEFINE_double(acq_Doppler_error_hz_step, -50.0, "Acquisition Doppler error sweep step value [Hz]"); -DEFINE_double(Acq_Delay_error_chips_start, 2.0, "Acquisition Code Delay error start sweep value [Hz]"); -DEFINE_double(Acq_Delay_error_chips_stop, -2.0, "Acquisition Code Delay error stop sweep value [Hz]"); -DEFINE_double(Acq_Delay_error_chips_step, -0.1, "Acquisition Code Delay error sweep step value [Hz]"); +DEFINE_double(acq_Delay_error_chips_start, 2.0, "Acquisition Code Delay error start sweep value [Chips]"); +DEFINE_double(acq_Delay_error_chips_stop, -2.0, "Acquisition Code Delay error stop sweep value [Chips]"); +DEFINE_double(acq_Delay_error_chips_step, -0.1, "Acquisition Code Delay error sweep step value [Chips]"); DEFINE_int32(plot_detail_level, 0, "Specify the desired plot detail (0,1,2): 0 - Minimum plots (default) 2 - Plot all tracking parameters"); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_pull-in_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_pull-in_test.cc index 4122f54c6..e449fa2e0 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_pull-in_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_pull-in_test.cc @@ -44,6 +44,7 @@ #include "GPS_L1_CA.h" #include "gnss_block_factory.h" #include "tracking_interface.h" +#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" #include "in_memory_configuration.h" #include "tracking_true_obs_reader.h" #include "tracking_dump_reader.h" @@ -52,7 +53,59 @@ #include "test_flags.h" #include "tracking_tests_flags.h" -// ######## GNURADIO BLOCK MESSAGE RECEVER ######### + +// ######## GNURADIO ACQUISITION BLOCK MESSAGE RECEVER ######### +class Acquisition_msg_rx; + +typedef boost::shared_ptr Acquisition_msg_rx_sptr; + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + + +class Acquisition_msg_rx : public gr::block +{ +private: + friend Acquisition_msg_rx_sptr Acquisition_msg_rx_make(); + void msg_handler_events(pmt::pmt_t msg); + Acquisition_msg_rx(); + +public: + int rx_message; + ~Acquisition_msg_rx(); //!< Default destructor +}; + + +Acquisition_msg_rx_sptr Acquisition_msg_rx_make() +{ + return Acquisition_msg_rx_sptr(new Acquisition_msg_rx()); +} + + +void Acquisition_msg_rx::msg_handler_events(pmt::pmt_t msg) +{ + try + { + long int message = pmt::to_long(msg); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_acquisition Bad cast!\n"; + rx_message = 0; + } +} + + +Acquisition_msg_rx::Acquisition_msg_rx() : gr::block("Acquisition_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) +{ + this->message_port_register_in(pmt::mp("events")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&Acquisition_msg_rx::msg_handler_events, this, _1)); + rx_message = 0; +} + + +Acquisition_msg_rx::~Acquisition_msg_rx() {} +// ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER ######### class GpsL1CADllPllTrackingPullInTest_msg_rx; typedef boost::shared_ptr GpsL1CADllPllTrackingPullInTest_msg_rx_sptr; @@ -88,7 +141,7 @@ void GpsL1CADllPllTrackingPullInTest_msg_rx::msg_handler_events(pmt::pmt_t msg) } catch (boost::bad_any_cast& e) { - LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + LOG(WARNING) << "msg_handler_tracking Bad cast!"; rx_message = 0; } } @@ -124,7 +177,11 @@ public: 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; + std::string filename_raw_data = FLAGS_signal_file; + + std::map doppler_measurements_map; + std::map code_delay_measurements_map; + std::map acq_samplestamp_map; int configure_generator(double CN0_dBHz, int file_idx); int generate_signal(); @@ -165,6 +222,7 @@ public: double DLL_narrow_bw_hz, int extend_correlation_symbols); + bool acquire_GPS_L1CA_signal(int SV_ID); gr::top_block_sptr top_block; std::shared_ptr factory; std::shared_ptr config; @@ -187,10 +245,10 @@ int GpsL1CADllPllTrackingPullInTest::configure_generator(double CN0_dBHz, int fi { 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 + std::to_string(file_idx); // 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] - p6 = std::string("-CN0_dBHz=") + std::to_string(CN0_dBHz); // Signal generator CN0 + p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output + p4 = std::string("-sig_out_file=") + FLAGS_signal_file + std::to_string(file_idx); // 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] + p6 = std::string("-CN0_dBHz=") + std::to_string(CN0_dBHz); // Signal generator CN0 return 0; } @@ -259,20 +317,130 @@ void GpsL1CADllPllTrackingPullInTest::configure_receiver( } +bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID) +{ + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) + gr::top_block_sptr top_block; + top_block = gr::make_top_block("Acquisition test"); + + // Satellite signal definition + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.Channel_ID = 0; + tmp_gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + tmp_gnss_synchro.PRN = SV_ID; + + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + + config->set_property("Acquisition.max_dwells", "10"); + config->set_property("Acquisition.dump", "true"); + GNSSBlockFactory block_factory; + GpsL1CaPcpsAcquisitionFineDoppler* acquisition; + acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(config.get(), "Acquisition", 1, 1); + + acquisition->set_channel(1); + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); + acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000)); + acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500)); + + boost::shared_ptr msg_rx; + try + { + msg_rx = Acquisition_msg_rx_make(); + } + catch (const std::exception& e) + { + std::cout << "Failure connecting the message port system: " << e.what() << std::endl; + exit(0); + } + + gr::blocks::file_source::sptr file_source; + std::string file = FLAGS_signal_file; + const char* file_name = file.c_str(); + file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); + gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); + gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); + top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); + top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0); + top_block->msg_connect(acquisition->get_left_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + // 5. Run the flowgraph + // Get visible GPS satellites (positive acquisitions with Doppler measurements) + // record startup time + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + start = std::chrono::system_clock::now(); + + bool start_msg = true; + + doppler_measurements_map.clear(); + code_delay_measurements_map.clear(); + acq_samplestamp_map.clear(); + + for (unsigned int PRN = 1; PRN < 33; PRN++) + { + tmp_gnss_synchro.PRN = PRN; + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->init(); + acquisition->set_local_code(); + acquisition->reset(); + msg_rx->rx_message = 0; + top_block->run(); + if (start_msg == true) + { + std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; + std::cout << "Searching for GPS Satellites in L1 band..." << std::endl; + std::cout << "["; + start_msg = false; + } + while (msg_rx->rx_message == 0) + { + usleep(100000); + } + if (msg_rx->rx_message == 1) + { + std::cout << " " << PRN << " "; + doppler_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_doppler_hz)); + code_delay_measurements_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_delay_samples)); + acq_samplestamp_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_samplestamp_samples)); + } + else + { + std::cout << " . "; + } + top_block->stop(); + file_source->seek(0, 0); + std::cout.flush(); + } + std::cout << "]" << std::endl; + + // report the elapsed time + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + std::cout << "Total signal acquisition run time " + << elapsed_seconds.count() + << " [seconds]" << std::endl; + return true; +} + TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) { //************************************************* - //***** STEP 2: Prepare the parameters sweep ****** + //***** STEP 1: Prepare the parameters sweep ****** //************************************************* - std::vector acq_doppler_error_hz_values; + std::vector + acq_doppler_error_hz_values; std::vector> acq_delay_error_chips_values; //vector of vector - for (double doppler_hz = FLAGS_Acq_Doppler_error_hz_start; doppler_hz >= FLAGS_Acq_Doppler_error_hz_stop; doppler_hz = doppler_hz + FLAGS_Acq_Doppler_error_hz_step) + for (double doppler_hz = FLAGS_acq_Doppler_error_hz_start; doppler_hz >= FLAGS_acq_Doppler_error_hz_stop; doppler_hz = doppler_hz + FLAGS_acq_Doppler_error_hz_step) { acq_doppler_error_hz_values.push_back(doppler_hz); std::vector tmp_vector; //Code Delay Sweep - for (double code_delay_chips = FLAGS_Acq_Delay_error_chips_start; code_delay_chips >= FLAGS_Acq_Delay_error_chips_stop; code_delay_chips = code_delay_chips + FLAGS_Acq_Delay_error_chips_step) + for (double code_delay_chips = FLAGS_acq_Delay_error_chips_start; code_delay_chips >= FLAGS_acq_Delay_error_chips_stop; code_delay_chips = code_delay_chips + FLAGS_acq_Delay_error_chips_step) { tmp_vector.push_back(code_delay_chips); } @@ -280,26 +448,37 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) } - //********************************************* - //***** STEP 3: Generate the input signal ***** - //********************************************* + //*********************************************************** + //***** STEP 2: Generate the input signal (if required) ***** + //*********************************************************** std::vector generator_CN0_values; - if (FLAGS_CN0_dBHz_start == FLAGS_CN0_dBHz_stop) + if (FLAGS_enable_external_signal_file) { - generator_CN0_values.push_back(FLAGS_CN0_dBHz_start); + generator_CN0_values.push_back(999); // an external input signal capture is selected, no CN0 information available } else { - for (double cn0 = FLAGS_CN0_dBHz_start; cn0 > FLAGS_CN0_dBHz_stop; cn0 = cn0 - FLAGS_CN0_dB_step) + if (FLAGS_CN0_dBHz_start == FLAGS_CN0_dBHz_stop) { - generator_CN0_values.push_back(cn0); + generator_CN0_values.push_back(FLAGS_CN0_dBHz_start); + } + else + { + for (double cn0 = FLAGS_CN0_dBHz_start; cn0 > FLAGS_CN0_dBHz_stop; cn0 = cn0 - FLAGS_CN0_dB_step) + { + generator_CN0_values.push_back(cn0); + } } } // use generator or use an external capture file if (FLAGS_enable_external_signal_file) { - //todo: create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + //create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + ASSERT_EQ(acquire_GPS_L1CA_signal(FLAGS_test_satellite_PRN), true); + bool found_satellite = doppler_measurements_map.find(FLAGS_test_satellite_PRN) != doppler_measurements_map.end(); + EXPECT_TRUE(found_satellite) << "Error: satellite SV: " << FLAGS_test_satellite_PRN << " is not acquired"; + if (!found_satellite) return; } else { @@ -326,6 +505,10 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) //***** Obtain the initial signal sinchronization parameters (emulating an acquisition) **** //****************************************************************************************** int test_satellite_PRN = 0; + double true_acq_doppler_hz = 0.0; + double true_acq_delay_samples = 0.0; + unsigned long int acq_samplestamp_samples = 0; + tracking_true_obs_reader true_obs_data; if (!FLAGS_enable_external_signal_file) { @@ -341,14 +524,23 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) << "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) + " is not available?"; std::cout << "Testing satellite PRN=" << test_satellite_PRN << std::endl; - std::cout << "True Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz << " rue Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << std::endl; + std::cout << "True Initial Doppler " << true_obs_data.doppler_l1_hz << " [Hz], true Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << "[Chips]" << std::endl; + true_acq_doppler_hz = true_obs_data.doppler_l1_hz; + true_acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * static_cast(baseband_sampling_freq) * GPS_L1_CA_CODE_PERIOD; + acq_samplestamp_samples = 0; } else { - //todo: Simulate a perfect acquisition for the external capture file + true_acq_doppler_hz = doppler_measurements_map.find(FLAGS_test_satellite_PRN)->second; + true_acq_delay_samples = code_delay_measurements_map.find(FLAGS_test_satellite_PRN)->second; + acq_samplestamp_samples = 0; + std::cout << "Estimated Initial Doppler " << true_acq_doppler_hz + << " [Hz], estimated Initial code delay " << true_acq_delay_samples << " [Samples]" + << " Acquisition SampleStamp is " << acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second << std::endl; } //CN0 LOOP std::vector> pull_in_results_v_v; + for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++) { std::vector pull_in_results_v; @@ -356,23 +548,18 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) { for (unsigned int current_acq_code_error_idx = 0; current_acq_code_error_idx < acq_delay_error_chips_values.at(current_acq_doppler_error_idx).size(); current_acq_code_error_idx++) { + gnss_synchro.Acq_samplestamp_samples = acq_samplestamp_samples; //simulate a Doppler error in acquisition - double acq_doppler_hz = true_obs_data.doppler_l1_hz + acq_doppler_error_hz_values.at(current_acq_doppler_error_idx); + gnss_synchro.Acq_doppler_hz = true_acq_doppler_hz + acq_doppler_error_hz_values.at(current_acq_doppler_error_idx); //simulate Code Delay error in acquisition - double acq_delay_samples; - acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * static_cast(baseband_sampling_freq) * GPS_L1_CA_CODE_PERIOD; - acq_delay_samples += (acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) / GPS_L1_CA_CODE_RATE_HZ) * static_cast(baseband_sampling_freq); + gnss_synchro.Acq_delay_samples = true_acq_delay_samples + (acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) / GPS_L1_CA_CODE_RATE_HZ) * static_cast(baseband_sampling_freq); //create flowgraph top_block = gr::make_top_block("Tracking test"); std::shared_ptr trk_ = factory->GetBlock(config, "Tracking_1C", implementation, 1, 1); std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); - boost::shared_ptr msg_rx = GpsL1CADllPllTrackingPullInTest_msg_rx_make(); - gnss_synchro.Acq_delay_samples = acq_delay_samples; - gnss_synchro.Acq_doppler_hz = acq_doppler_hz; - gnss_synchro.Acq_samplestamp_samples = 0; ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); @@ -386,8 +573,16 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) tracking->connect(top_block); }) << "Failure connecting tracking to the top_block."; + std::string file; ASSERT_NO_THROW({ - std::string file = "./" + filename_raw_data + std::to_string(current_cn0_idx); + if (!FLAGS_enable_external_signal_file) + { + file = "./" + filename_raw_data + std::to_string(current_cn0_idx); + } + else + { + file = FLAGS_signal_file; + } const char* file_name = file.c_str(); gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false); gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); @@ -396,6 +591,8 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0); top_block->connect(tracking->get_right_block(), 0, sink, 0); top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); + + file_source->seek(acq_samplestamp_samples, 0); }) << "Failure connecting the blocks of tracking test."; @@ -420,7 +617,7 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) //******************************** //***** STEP 7: Plot results ***** //******************************** - if (FLAGS_plot_gps_l1_tracking_test == true) + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) { //load the measured values tracking_dump_reader trk_dump; @@ -465,7 +662,7 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) const std::string gnuplot_executable(FLAGS_gnuplot_executable); if (gnuplot_executable.empty()) { - std::cout << "WARNING: Although the flag plot_gps_l1_tracking_test has been set to TRUE," << std::endl; + std::cout << "WARNING: Although the flag show_plots has been set to TRUE," << std::endl; std::cout << "gnuplot has not been found in your system." << std::endl; std::cout << "Test results will not be plotted." << std::endl; } @@ -479,11 +676,19 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) Gnuplot::set_GNUPlotPath(gnuplot_path); unsigned int decimate = static_cast(FLAGS_plot_decimate); - if (FLAGS_plot_detail_level >= 2) + if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) { Gnuplot g1("linespoints"); - if (FLAGS_show_plots) g1.showonscreen(); // window output - g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " Hz" + "GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g1.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g1.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g1.set_grid(); g1.set_xlabel("Time [s]"); g1.set_ylabel("Correlators' output"); @@ -496,8 +701,16 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) //g1.savetopdf("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx)), 18); Gnuplot g2("points"); - if (FLAGS_show_plots) g2.showonscreen(); // window output - g2.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " Hz" + "GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g2.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g2.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g2.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g2.set_grid(); g2.set_xlabel("Inphase"); g2.set_ylabel("Quadrature"); @@ -507,7 +720,14 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) //g2.savetopdf("Constellation", 18); Gnuplot g3("linespoints"); - g3.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + if (!FLAGS_enable_external_signal_file) + { + g3.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + else + { + g3.set_title("D_e=" + std::to_string(acq_doppler_error_hz_values.at(current_acq_doppler_error_idx)) + " [Hz] " + "T_e= " + std::to_string(acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx)) + " [Chips] PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } g3.set_grid(); g3.set_xlabel("Time [s]"); g3.set_ylabel("Reported CN0 [dB-Hz]"); @@ -519,7 +739,7 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) g3.set_legend(); //g3.savetops("CN0_output"); //g3.savetopdf("CN0_output", 18); - if (FLAGS_show_plots) g3.showonscreen(); // window output + g3.showonscreen(); // window output } } catch (const GnuplotException& ge) @@ -553,21 +773,45 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults) pull_in_result_mesh = pull_in_results_v_v.at(current_cn0_idx); //plot grid Gnuplot g4("points palette pointsize 2 pointtype 7"); + if (FLAGS_show_plots) + { + g4.showonscreen(); // window output + } + else + { + g4.disablescreen(); + } g4.cmd("set palette defined ( 0 \"black\", 1 \"green\" )"); g4.cmd("set key off"); g4.cmd("set view map"); - std::string title("Tracking Pull-in result grid at CN0:" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + " dB-Hz, PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " Hz."); + std::string title; + if (!FLAGS_enable_external_signal_file) + { + title = std::string("Tracking Pull-in result grid at CN0:" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + " [dB-Hz], PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz]."); + } + else + { + title = std::string("Tracking Pull-in result grid, PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + } + g4.set_title(title); g4.set_grid(); g4.set_xlabel("Acquisition Doppler error [Hz]"); g4.set_ylabel("Acquisition Code Delay error [Chips]"); - + g4.cmd("set cbrange[0:1]"); g4.plot_xyz(doppler_error_mesh, code_delay_error_mesh, pull_in_result_mesh); g4.set_legend(); - g4.savetops("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx))))); - g4.savetopdf("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))), 12); - if (FLAGS_show_plots) g4.showonscreen(); // window output + if (!FLAGS_enable_external_signal_file) + { + g4.savetops("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx))))); + g4.savetopdf("trk_pull_in_grid_" + std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))), 12); + } + else + { + g4.savetops("trk_pull_in_grid_external_file"); + g4.savetopdf("trk_pull_in_grid_external_file", 12); + } } } diff --git a/src/utils/front-end-cal/CMakeLists.txt b/src/utils/front-end-cal/CMakeLists.txt index 03d6bc956..81ecf1e54 100644 --- a/src/utils/front-end-cal/CMakeLists.txt +++ b/src/utils/front-end-cal/CMakeLists.txt @@ -33,6 +33,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks + ${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs ${CMAKE_SOURCE_DIR}/src/algorithms/libs ${GLOG_INCLUDE_DIRS} ${GFlags_INCLUDE_DIRS} diff --git a/src/utils/front-end-cal/main.cc b/src/utils/front-end-cal/main.cc index 52ab62218..69b6c6e97 100644 --- a/src/utils/front-end-cal/main.cc +++ b/src/utils/front-end-cal/main.cc @@ -144,8 +144,6 @@ FrontEndCal_msg_rx::FrontEndCal_msg_rx() : gr::block("FrontEndCal_msg_rx", gr::i FrontEndCal_msg_rx::~FrontEndCal_msg_rx() {} - - void wait_message() { while (!stop) @@ -353,13 +351,14 @@ int main(int argc, char** argv) gnss_synchro->PRN = 1; long fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000); + configuration->set_property("Acquisition.max_dwells", "10"); GNSSBlockFactory block_factory; acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(configuration.get(), "Acquisition", 1, 1); acquisition->set_channel(1); acquisition->set_gnss_synchro(gnss_synchro); - acquisition->set_threshold(configuration->property("Acquisition.threshold", 0.0)); + acquisition->set_threshold(configuration->property("Acquisition.threshold", 2.0)); acquisition->set_doppler_max(configuration->property("Acquisition.doppler_max", 10000)); acquisition->set_doppler_step(configuration->property("Acquisition.doppler_step", 250));