diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc index bf5f05c15..5da2cd5f8 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.cc @@ -1,12 +1,12 @@ /*! - * \file galileo_e1_pcps_ambiguous_acquisition.cc + * \file galileo_e1_pcps_ambiguous_acquisition_fpga.cc * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * Galileo E1 Signals - * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * Galileo E1 Signals for the FPGA + * \author Marc Majoral, 2019. mmajoral(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -34,8 +34,6 @@ #include "configuration_interface.h" #include "galileo_e1_signal_processing.h" #include "gnss_sdr_flags.h" -#include -#include #include @@ -50,75 +48,50 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( in_streams_(in_streams), out_streams_(out_streams) { - //printf("top acq constructor start\n"); pcpsconf_fpga_t acq_parameters; configuration_ = configuration; - std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./acquisition.mat"; + + std::string default_item_type = "cshort"; + std::string default_dump_filename = "./data/acquisition.dat"; DLOG(INFO) << "role " << role; - // item_type_ = configuration_->property(role + ".item_type", default_item_type); - int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); - acq_parameters.fs_in = fs_in; - //if_ = configuration_->property(role + ".if", 0); - //acq_parameters.freq = if_; - // dump_ = configuration_->property(role + ".dump", false); - // acq_parameters.dump = dump_; - // blocking_ = configuration_->property(role + ".blocking", true); - // acq_parameters.blocking = blocking_; + float downsampling_factor = configuration_->property(role + ".downsampling_factor", 4.0); + acq_parameters.downsampling_factor = downsampling_factor; + + fs_in = fs_in / downsampling_factor; + + acq_parameters.fs_in = fs_in; + doppler_max_ = configuration_->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; acq_parameters.doppler_max = doppler_max_; - //unsigned int sampled_ms = 4; - //acq_parameters.sampled_ms = sampled_ms; - unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 4); + uint32_t sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 4); acq_parameters.sampled_ms = sampled_ms; - // bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - // acq_parameters.bit_transition_flag = bit_transition_flag_; - // use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions - // acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; acquire_pilot_ = configuration_->property(role + ".acquire_pilot", false); //will be true in future versions - // max_dwells_ = configuration_->property(role + ".max_dwells", 1); - // acq_parameters.max_dwells = max_dwells_; - // dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - // acq_parameters.dump_filename = dump_filename_; //--- Find number of samples per spreading code (4 ms) ----------------- - auto code_length = static_cast(std::round(static_cast(fs_in) / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS))); - //acq_parameters.samples_per_code = code_length_; - //int samples_per_ms = static_cast(std::round(static_cast(fs_in_) * 0.001)); - //acq_parameters.samples_per_ms = samples_per_ms; - //unsigned int vector_length = sampled_ms * samples_per_ms; + auto code_length = static_cast(std::round(static_cast(fs_in) / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS))); - // if (bit_transition_flag_) - // { - // vector_length_ *= 2; - // } - - //printf("fs_in = %d\n", fs_in); - //printf("GALILEO_E1_B_CODE_LENGTH_CHIPS = %f\n", GALILEO_E1_B_CODE_LENGTH_CHIPS); - //printf("GALILEO_E1_CODE_CHIP_RATE_HZ = %f\n", GALILEO_E1_CODE_CHIP_RATE_HZ); - //printf("acq adapter code_length = %d\n", code_length); acq_parameters.code_length = code_length; // The FPGA can only use FFT lengths that are a power of two. - float nbits = ceilf(log2f((float)code_length)); - unsigned int nsamples_total = pow(2, nbits); - unsigned int vector_length = nsamples_total; - //printf("acq adapter nsamples_total (= vector_length) = %d\n", vector_length); - unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + float nbits = ceilf(log2f((float)code_length * 2)); + uint32_t nsamples_total = pow(2, nbits); + uint32_t select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + acq_parameters.select_queue_Fpga = select_queue_Fpga; std::string default_device_name = "/dev/uio0"; std::string device_name = configuration_->property(role + ".devicename", default_device_name); acq_parameters.device_name = device_name; acq_parameters.samples_per_ms = nsamples_total / sampled_ms; acq_parameters.samples_per_code = nsamples_total; + acq_parameters.excludelimit = static_cast(std::round(static_cast(fs_in) / GALILEO_E1_CODE_CHIP_RATE_HZ)); - // compute all the GALILEO E1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // compute all the GALILEO E1 PRN Codes (this is done only once in the class constructor in order to avoid re-computing the PRN codes every time // a channel is assigned) auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT auto* code = new std::complex[nsamples_total]; // buffer for the local code @@ -126,19 +99,12 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( d_all_fft_codes_ = new lv_16sc_t[nsamples_total * GALILEO_E1_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32 float max; // temporary maxima search - //int tmp_re, tmp_im; - - for (unsigned int PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++) + for (uint32_t PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++) { - //code_ = new gr_complex[vector_length_]; - bool cboc = false; // cboc is set to 0 when using the FPGA - //std::complex* code = new std::complex[code_length_]; - if (acquire_pilot_ == true) { - //printf("yes acquiring pilot!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1\n"); //set local signal generator to Galileo E1 pilot component (1C) char pilot_signal[3] = "1C"; galileo_e1_code_gen_complex_sampled(code, pilot_signal, @@ -151,53 +117,24 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( cboc, PRN, fs_in, 0, false); } - // for (unsigned int i = 0; i < sampled_ms / 4; i++) - // { - // //memcpy(&(code_[i * code_length_]), code, sizeof(gr_complex) * code_length_); - // memcpy(&(d_all_fft_codes_[i * code_length_]), code, sizeof(gr_complex) * code_length_); - // } + for (uint32_t s = code_length; s < 2 * code_length; s++) + { + code[s] = code[s - code_length]; + } - - // // debug - // char filename[25]; - // FILE *fid; - // sprintf(filename,"gal_prn%d.txt", PRN); - // fid = fopen(filename, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid, "%f\n", code[kk].real()); - // fprintf(fid, "%f\n", code[kk].imag()); - // } - // fclose(fid); - - - // // fill in zero padding - for (int s = code_length; s < nsamples_total; s++) + // fill in zero padding + for (uint32_t s = 2 * code_length; s < nsamples_total; s++) { code[s] = std::complex(0.0, 0.0); - //code[s] = 0; } memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer fft_if->execute(); // Run the FFT of local code volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values - // // debug - // char filename[25]; - // FILE *fid; - // sprintf(filename,"fft_gal_prn%d.txt", PRN); - // fid = fopen(filename, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid, "%f\n", fft_codes_padded[kk].real()); - // fprintf(fid, "%f\n", fft_codes_padded[kk].imag()); - // } - // fclose(fid); - - // normalize the code - max = 0; // initialize maximum value - for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + max = 0; // initialize maximum value + for (uint32_t i = 0; i < nsamples_total; i++) // search for maxima { if (std::abs(fft_codes_padded[i].real()) > max) { @@ -208,350 +145,135 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( max = std::abs(fft_codes_padded[i].imag()); } } - for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs { - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(4096*fft_codes_padded[i].real() * (pow(2, 3) - 1) / max)), - // static_cast(floor(4096*fft_codes_padded[i].imag() * (pow(2, 3) - 1) / max))); - // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(1024*fft_codes_padded[i].real() * (pow(2, 5) - 1) / max)), - // static_cast(floor(1024*fft_codes_padded[i].imag() * (pow(2, 5) - 1) / max))); - // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), - // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); - // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(16*fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), - // static_cast(floor(16*fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); - d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); - - // tmp_re = static_cast(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)); - // tmp_im = static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max)); - - // if (tmp_re > 127) - // { - // tmp_re = 127; - // } - // if (tmp_re < -128) - // { - // tmp_re = -128; - // } - // if (tmp_im > 127) - // { - // tmp_im = 127; - // } - // if (tmp_im < -128) - // { - // tmp_im = -128; - // } - // d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(tmp_re), static_cast(tmp_im)); - // + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max))); } - - // // debug - // char filename2[25]; - // FILE *fid2; - // sprintf(filename2,"fft_gal_prn%d_norm.txt", PRN); - // fid2 = fopen(filename2, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); - // } - // fclose(fid2); } - - // for (unsigned int PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++) - // { - // // debug - // char filename2[25]; - // FILE *fid2; - // sprintf(filename2,"fft_gal_prn%d_norm_last.txt", PRN); - // fid2 = fopen(filename2, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); - // } - // fclose(fid2); - // } - - //acq_parameters - acq_parameters.all_fft_codes = d_all_fft_codes_; + // reference for the FPGA FFT-IFFT attenuation factor + acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14); + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + channel_ = 0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + // temporary buffers that we can delete delete[] code; delete fft_if; delete[] fft_codes_padded; - - acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); - DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; - - // stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - // DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - - // if (item_type_.compare("cbyte") == 0) - // { - // cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); - // float_to_complex_ = gr::blocks::float_to_complex::make(); - // } - - channel_ = 0; - //threshold_ = 0.0; - doppler_step_ = 0; - gnss_synchro_ = nullptr; - //printf("top acq constructor end\n"); } GalileoE1PcpsAmbiguousAcquisitionFpga::~GalileoE1PcpsAmbiguousAcquisitionFpga() { - //printf("top acq destructor start\n"); - //delete[] code_; delete[] d_all_fft_codes_; - //printf("top acq destructor end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::stop_acquisition() { + // this command causes the SW to reset the HW. + acquisition_fpga_->reset_acquisition(); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_channel(unsigned int channel) { - //printf("top acq set channel start\n"); channel_ = channel; acquisition_fpga_->set_channel(channel_); - //printf("top acq set channel end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_threshold(float threshold) { - //printf("top acq set threshold start\n"); - // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. - // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. - - // float pfa = configuration_->property(role_ + boost::lexical_cast(channel_) + ".pfa", 0.0); - // - // if (pfa == 0.0) pfa = configuration_->property(role_ + ".pfa", 0.0); - // - // if (pfa == 0.0) - // { - // threshold_ = threshold; - // } - // else - // { - // threshold_ = calculate_threshold(pfa); - // } - DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; acquisition_fpga_->set_threshold(threshold); - // acquisition_fpga_->set_threshold(threshold_); - //printf("top acq set threshold end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_doppler_max(unsigned int doppler_max) { - //printf("top acq set doppler max start\n"); doppler_max_ = doppler_max; - acquisition_fpga_->set_doppler_max(doppler_max_); - //printf("top acq set doppler max end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_doppler_step(unsigned int doppler_step) { - //printf("top acq set doppler step start\n"); doppler_step_ = doppler_step; - acquisition_fpga_->set_doppler_step(doppler_step_); - //printf("top acq set doppler step end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { - //printf("top acq set gnss synchro start\n"); gnss_synchro_ = gnss_synchro; - acquisition_fpga_->set_gnss_synchro(gnss_synchro_); - //printf("top acq set gnss synchro end\n"); } signed int GalileoE1PcpsAmbiguousAcquisitionFpga::mag() { - // printf("top acq mag start\n"); return acquisition_fpga_->mag(); - //printf("top acq mag end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::init() { - // printf("top acq init start\n"); acquisition_fpga_->init(); - // printf("top acq init end\n"); - //set_local_code(); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_local_code() { - // printf("top acq set local code start\n"); - // bool cboc = configuration_->property( - // "Acquisition" + boost::lexical_cast(channel_) + ".cboc", false); - // - // std::complex* code = new std::complex[code_length_]; - // - // if (acquire_pilot_ == true) - // { - // //set local signal generator to Galileo E1 pilot component (1C) - // char pilot_signal[3] = "1C"; - // galileo_e1_code_gen_complex_sampled(code, pilot_signal, - // cboc, gnss_synchro_->PRN, fs_in_, 0, false); - // } - // else - // { - // galileo_e1_code_gen_complex_sampled(code, gnss_synchro_->Signal, - // cboc, gnss_synchro_->PRN, fs_in_, 0, false); - // } - // - // - // for (unsigned int i = 0; i < sampled_ms_ / 4; i++) - // { - // memcpy(&(code_[i * code_length_]), code, sizeof(gr_complex) * code_length_); - // } - - //acquisition_fpga_->set_local_code(code_); acquisition_fpga_->set_local_code(); - // delete[] code; - // printf("top acq set local code end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::reset() { - // printf("top acq reset start\n"); + // This command starts the acquisition process acquisition_fpga_->set_active(true); - // printf("top acq reset end\n"); } void GalileoE1PcpsAmbiguousAcquisitionFpga::set_state(int state) { - // printf("top acq set state start\n"); acquisition_fpga_->set_state(state); - // printf("top acq set state end\n"); } - -//float GalileoE1PcpsAmbiguousAcquisitionFpga::calculate_threshold(float pfa) -//{ -// unsigned int frequency_bins = 0; -// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) -// { -// frequency_bins++; -// } -// -// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; -// -// unsigned int ncells = vector_length_ * frequency_bins; -// double exponent = 1 / static_cast(ncells); -// double val = pow(1.0 - pfa, exponent); -// double lambda = double(vector_length_); -// boost::math::exponential_distribution mydist(lambda); -// float threshold = static_cast(quantile(mydist, val)); -// -// return threshold; -//} - - void GalileoE1PcpsAmbiguousAcquisitionFpga::connect(gr::top_block_sptr top_block) { - // printf("top acq connect\n"); - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); - // top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - // top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } - - // nothing to connect + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect } void GalileoE1PcpsAmbiguousAcquisitionFpga::disconnect(gr::top_block_sptr top_block) { - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // // Since a byte-based acq implementation is not available, - // // we just convert cshorts to gr_complex - // top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); - // top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - // top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } - - // nothing to disconnect - // printf("top acq disconnect\n"); + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect } gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisitionFpga::get_left_block() { - // printf("top acq get left block start\n"); - // if (item_type_.compare("gr_complex") == 0) - // { - // return stream_to_vector_; - // } - // else if (item_type_.compare("cshort") == 0) - // { - // return stream_to_vector_; - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // return cbyte_to_float_x2_; - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; return nullptr; - // } - // printf("top acq get left block end\n"); } gr::basic_block_sptr GalileoE1PcpsAmbiguousAcquisitionFpga::get_right_block() { - // printf("top acq get right block start\n"); return acquisition_fpga_; - // printf("top acq get right block end\n"); } diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h index 09391ddb8..2baf58e45 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h @@ -1,12 +1,12 @@ /*! - * \file galileo_e1_pcps_ambiguous_acquisition.h + * \file galileo_e1_pcps_ambiguous_acquisition_fpga.h * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for * Galileo E1 Signals - * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com + * \author Marc Majoral, 2019. mmajoral(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -60,22 +60,19 @@ public: inline std::string role() override { - // printf("top acq role\n"); return role_; } /*! - * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition" + * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga" */ inline std::string implementation() override { - // printf("top acq implementation\n"); return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"; } size_t item_size() override { - // printf("top acq item size\n"); size_t item_size = sizeof(lv_16sc_t); return item_size; } @@ -138,45 +135,33 @@ public: void set_state(int state) override; /*! - * \brief Stop running acquisition - */ + * \brief Stop running acquisition + */ void stop_acquisition() override; void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: ConfigurationInterface* configuration_; - //pcps_acquisition_sptr acquisition_; pcps_acquisition_fpga_sptr acquisition_fpga_; gr::blocks::stream_to_vector::sptr stream_to_vector_; gr::blocks::float_to_complex::sptr float_to_complex_; complex_byte_to_float_x2_sptr cbyte_to_float_x2_; - // size_t item_size_; - // std::string item_type_; - //unsigned int vector_length_; - //unsigned int code_length_; bool bit_transition_flag_; bool use_CFAR_algorithm_flag_; bool acquire_pilot_; - unsigned int channel_; - //float threshold_; - unsigned int doppler_max_; - unsigned int doppler_step_; - //unsigned int sampled_ms_; - unsigned int max_dwells_; - //long fs_in_; - //long if_; + uint32_t channel_; + uint32_t doppler_max_; + uint32_t doppler_step_; + uint32_t max_dwells_; bool dump_; bool blocking_; std::string dump_filename_; - //std::complex* code_; Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; unsigned int out_streams_; - //float calculate_threshold(float pfa); - // extra for the FPGA lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts }; diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc index 7c3e62961..0db1b9802 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.cc @@ -1,11 +1,12 @@ /*! - * \file galileo_e5a_pcps_acquisition.cc + * \file galileo_e5a_pcps_acquisition_fpga.cc * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * Galileo E5a data and pilot Signals - * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * Galileo E5a data and pilot Signals for the FPGA + * \author Marc Majoral, 2019. mmajoral(at)cttc.es + * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -48,39 +49,27 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf in_streams_(in_streams), out_streams_(out_streams) { - //printf("creating the E5A acquisition"); pcpsconf_fpga_t acq_parameters; configuration_ = configuration; - std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./acquisition.mat"; + std::string default_dump_filename = "../data/acquisition.dat"; DLOG(INFO) << "Role " << role; - //item_type_ = configuration_->property(role + ".item_type", default_item_type); - int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + + float downsampling_factor = configuration_->property(role + ".downsampling_factor", 1.0); + acq_parameters.downsampling_factor = downsampling_factor; + fs_in = fs_in / downsampling_factor; + acq_parameters.fs_in = fs_in; - //acq_parameters.freq = 0; - - //dump_ = configuration_->property(role + ".dump", false); - //acq_parameters.dump = dump_; doppler_max_ = configuration_->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; acq_parameters.doppler_max = doppler_max_; - unsigned int sampled_ms = 1; - //max_dwells_ = configuration_->property(role + ".max_dwells", 1); - //acq_parameters.max_dwells = max_dwells_; - //dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - //acq_parameters.dump_filename = dump_filename_; - //bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - //acq_parameters.bit_transition_flag = bit_transition_flag_; - //use_CFAR_ = configuration_->property(role + ".use_CFAR_algorithm", false); - //acq_parameters.use_CFAR_algorithm_flag = use_CFAR_; - //blocking_ = configuration_->property(role + ".blocking", true); - //acq_parameters.blocking = blocking_; - //--- Find number of samples per spreading code (1ms)------------------------- + + uint32_t sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + acq_parameters.sampled_ms = sampled_ms; acq_pilot_ = configuration_->property(role + ".acquire_pilot", false); acq_iq_ = configuration_->property(role + ".acquire_iq", false); @@ -89,14 +78,13 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf acq_pilot_ = false; } - auto code_length = static_cast(std::round(static_cast(fs_in) / GALILEO_E5A_CODE_CHIP_RATE_HZ * static_cast(GALILEO_E5A_CODE_LENGTH_CHIPS))); + auto code_length = static_cast(std::round(static_cast(fs_in) / GALILEO_E5A_CODE_CHIP_RATE_HZ * static_cast(GALILEO_E5A_CODE_LENGTH_CHIPS))); acq_parameters.code_length = code_length; + // The FPGA can only use FFT lengths that are a power of two. - float nbits = ceilf(log2f((float)code_length)); - unsigned int nsamples_total = pow(2, nbits); - unsigned int vector_length = nsamples_total; - unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); - //printf("select_queue_Fpga = %d\n", select_queue_Fpga); + float nbits = ceilf(log2f((float)code_length * 2)); + uint32_t nsamples_total = pow(2, nbits); + uint32_t select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); acq_parameters.select_queue_Fpga = select_queue_Fpga; std::string default_device_name = "/dev/uio0"; std::string device_name = configuration_->property(role + ".devicename", default_device_name); @@ -104,9 +92,9 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf acq_parameters.samples_per_ms = nsamples_total / sampled_ms; acq_parameters.samples_per_code = nsamples_total; - //vector_length_ = code_length_ * sampled_ms_; + acq_parameters.excludelimit = static_cast(ceil((1.0 / GALILEO_E5A_CODE_CHIP_RATE_HZ) * static_cast(acq_parameters.fs_in))); - // compute all the GALILEO E5 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time + // compute all the GALILEO E5 PRN Codes (this is done only once in the class constructor in order to avoid re-computing the PRN codes every time // a channel is assigned) auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT auto* code = new std::complex[nsamples_total]; // buffer for the local code @@ -114,12 +102,8 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf d_all_fft_codes_ = new lv_16sc_t[nsamples_total * GALILEO_E5A_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32 float max; // temporary maxima search - //printf("creating the E5A acquisition CONT"); - //printf("nsamples_total = %d\n", nsamples_total); - - for (unsigned int PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++) + for (uint32_t PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++) { - // gr_complex* code = new gr_complex[code_length_]; char signal_[3]; if (acq_iq_) @@ -135,22 +119,25 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf strcpy(signal_, "5I"); } - galileo_e5_a_code_gen_complex_sampled(code, signal_, PRN, fs_in, 0); + for (uint32_t s = code_length; s < 2 * code_length; s++) + { + code[s] = code[s - code_length]; + } + // fill in zero padding - for (int s = code_length; s < nsamples_total; s++) + for (uint32_t s = 2 * code_length; s < nsamples_total; s++) { code[s] = std::complex(0.0, 0.0); - //code[s] = 0; } memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer fft_if->execute(); // Run the FFT of local code volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values - max = 0; // initialize maximum value - for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + max = 0; // initialize maximum value + for (uint32_t i = 0; i < nsamples_total; i++) // search for maxima { if (std::abs(fft_codes_padded[i].real()) > max) { @@ -161,101 +148,55 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf max = std::abs(fft_codes_padded[i].imag()); } } - for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs { - d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max))); } } - acq_parameters.all_fft_codes = d_all_fft_codes_; + // reference for the FPGA FFT-IFFT attenuation factor + acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14); + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + channel_ = 0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + // temporary buffers that we can delete delete[] code; delete fft_if; delete[] fft_codes_padded; - - //code_ = new gr_complex[vector_length_]; - - // if (item_type_.compare("gr_complex") == 0) - // { - // item_size_ = sizeof(gr_complex); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // item_size_ = sizeof(lv_16sc_t); - // } - // else - // { - // item_size_ = sizeof(gr_complex); - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } - //acq_parameters.it_size = item_size_; - //acq_parameters.samples_per_code = code_length_; - //acq_parameters.samples_per_ms = code_length_; - //acq_parameters.sampled_ms = sampled_ms_; - //acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); - //acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); - //acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); - //acquisition_ = pcps_make_acquisition(acq_parameters); - //acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); - //DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; - - acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); - DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; - - //stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - channel_ = 0; - //threshold_ = 0.0; - doppler_step_ = 0; - gnss_synchro_ = nullptr; - //printf("creating the E5A acquisition end"); } GalileoE5aPcpsAcquisitionFpga::~GalileoE5aPcpsAcquisitionFpga() { - //delete[] code_; delete[] d_all_fft_codes_; } void GalileoE5aPcpsAcquisitionFpga::stop_acquisition() { + // this command causes the SW to reset the HW. + acquisition_fpga_->reset_acquisition(); } void GalileoE5aPcpsAcquisitionFpga::set_channel(unsigned int channel) { channel_ = channel; - //acquisition_->set_channel(channel_); acquisition_fpga_->set_channel(channel_); } void GalileoE5aPcpsAcquisitionFpga::set_threshold(float threshold) { - // float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - // - // if (pfa == 0.0) - // { - // pfa = configuration_->property(role_ + ".pfa", 0.0); - // } - // - // if (pfa == 0.0) - // { - // threshold_ = threshold; - // } - // - // else - // { - // threshold_ = calculate_threshold(pfa); - // } - DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; - - //acquisition_->set_threshold(threshold_); acquisition_fpga_->set_threshold(threshold); } @@ -263,7 +204,6 @@ void GalileoE5aPcpsAcquisitionFpga::set_threshold(float threshold) void GalileoE5aPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) { doppler_max_ = doppler_max; - //acquisition_->set_doppler_max(doppler_max_); acquisition_fpga_->set_doppler_max(doppler_max_); } @@ -271,7 +211,6 @@ void GalileoE5aPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) void GalileoE5aPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) { doppler_step_ = doppler_step; - //acquisition_->set_doppler_step(doppler_step_); acquisition_fpga_->set_doppler_step(doppler_step_); } @@ -279,132 +218,65 @@ void GalileoE5aPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) void GalileoE5aPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) { gnss_synchro_ = gnss_synchro; - //acquisition_->set_gnss_synchro(gnss_synchro_); acquisition_fpga_->set_gnss_synchro(gnss_synchro_); } signed int GalileoE5aPcpsAcquisitionFpga::mag() { - //return acquisition_->mag(); return acquisition_fpga_->mag(); } void GalileoE5aPcpsAcquisitionFpga::init() { - //acquisition_->init(); acquisition_fpga_->init(); } void GalileoE5aPcpsAcquisitionFpga::set_local_code() { - // gr_complex* code = new gr_complex[code_length_]; - // char signal_[3]; - // - // if (acq_iq_) - // { - // strcpy(signal_, "5X"); - // } - // else if (acq_pilot_) - // { - // strcpy(signal_, "5Q"); - // } - // else - // { - // strcpy(signal_, "5I"); - // } - // - // galileo_e5_a_code_gen_complex_sampled(code, signal_, gnss_synchro_->PRN, fs_in_, 0); - // - // for (unsigned int i = 0; i < sampled_ms_; i++) - // { - // memcpy(code_ + (i * code_length_), code, sizeof(gr_complex) * code_length_); - // } - - //acquisition_->set_local_code(code_); acquisition_fpga_->set_local_code(); - // delete[] code; } void GalileoE5aPcpsAcquisitionFpga::reset() { - //acquisition_->set_active(true); acquisition_fpga_->set_active(true); } -//float GalileoE5aPcpsAcquisitionFpga::calculate_threshold(float pfa) -//{ -// unsigned int frequency_bins = 0; -// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) -// { -// frequency_bins++; -// } -// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; -// unsigned int ncells = vector_length_ * frequency_bins; -// double exponent = 1 / static_cast(ncells); -// double val = pow(1.0 - pfa, exponent); -// double lambda = double(vector_length_); -// boost::math::exponential_distribution mydist(lambda); -// float threshold = static_cast(quantile(mydist, val)); -// -// return threshold; -//} - - void GalileoE5aPcpsAcquisitionFpga::set_state(int state) { - //acquisition_->set_state(state); acquisition_fpga_->set_state(state); } void GalileoE5aPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) { - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect } void GalileoE5aPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) { - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect } gr::basic_block_sptr GalileoE5aPcpsAcquisitionFpga::get_left_block() { - //return stream_to_vector_; return nullptr; } gr::basic_block_sptr GalileoE5aPcpsAcquisitionFpga::get_right_block() { - //return acquisition_; return acquisition_fpga_; } diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h index 79f0d2836..e2871e06f 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h @@ -1,11 +1,12 @@ /*! - * \file galileo_e5a_pcps_acquisition.h + * \file galileo_e5a_pcps_acquisition_fpga.h * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * Galileo E5a data and pilot Signals - * \author Antonio Ramos, 2018. antonio.ramos(at)cttc.es + * Galileo E5a data and pilot Signals for the FPGA + * \author Marc Majoral, 2019. mmajoral(at)cttc.es + * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -28,8 +29,8 @@ * ------------------------------------------------------------------------- */ -#ifndef GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ -#define GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ +#ifndef GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ +#define GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ #include "acquisition_interface.h" @@ -56,6 +57,9 @@ public: return role_; } + /*! + * \brief Returns "Galileo_E5a_Pcps_Acquisition_Fpga" + */ inline std::string implementation() override { return "Galileo_E5a_Pcps_Acquisition_Fpga"; @@ -125,16 +129,22 @@ public: */ void set_state(int state) override; + /*! + * \brief This function is only used in the unit tests + */ + void set_single_doppler_flag(unsigned int single_doppler_flag); + /*! * \brief Stop running acquisition */ void stop_acquisition() override; + /*! + * \brief Sets the resampler latency to account it in the acquisition code delay estimation + */ void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override{}; private: - //float calculate_threshold(float pfa); - ConfigurationInterface* configuration_; pcps_acquisition_fpga_sptr acquisition_fpga_; @@ -153,31 +163,25 @@ private: bool blocking_; bool acq_iq_; - unsigned int vector_length_; - unsigned int code_length_; - unsigned int channel_; - unsigned int doppler_max_; - unsigned int doppler_step_; - unsigned int sampled_ms_; - unsigned int max_dwells_; + uint32_t vector_length_; + uint32_t code_length_; + uint32_t channel_; + uint32_t doppler_max_; + uint32_t doppler_step_; + uint32_t sampled_ms_; + uint32_t max_dwells_; unsigned int in_streams_; unsigned int out_streams_; int64_t fs_in_; - float threshold_; - /* - std::complex* codeI_; - std::complex* codeQ_; - */ - gr_complex* code_; Gnss_Synchro* gnss_synchro_; - // extra for the FPGA lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts }; -#endif /* GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ */ + +#endif /* GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ */ diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc index 6ddfa4616..6884ba099 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.cc @@ -1,17 +1,15 @@ /*! * \file gps_l1_ca_pcps_acquisition_fpga.cc - * \brief Adapts a PCPS acquisition block to an FPGA AcquisitionInterface - * for GPS L1 C/A signals + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L1 C/A signals for the FPGA * \authors
    - *
  • Marc Majoral, 2018. mmajoral(at)cttc.es - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena(at)gmail.com + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -59,72 +57,67 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( { pcpsconf_fpga_t acq_parameters; configuration_ = configuration; - std::string default_item_type = "gr_complex"; + std::string default_item_type = "cshort"; DLOG(INFO) << "role " << role; int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); - //fs_in = fs_in/2.0; // downampling filter - //printf("####### DEBUG Acq: fs_in = %d\n", fs_in); + + float downsampling_factor = configuration_->property(role + ".downsampling_factor", 4.0); + acq_parameters.downsampling_factor = downsampling_factor; + + fs_in = fs_in / downsampling_factor; + acq_parameters.fs_in = fs_in; - acq_parameters.samples_per_code = static_cast(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast(acq_parameters.fs_in))); doppler_max_ = configuration_->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; acq_parameters.doppler_max = doppler_max_; - unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + uint32_t sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); acq_parameters.sampled_ms = sampled_ms; - auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); acq_parameters.code_length = code_length; // The FPGA can only use FFT lengths that are a power of two. - float nbits = ceilf(log2f((float)code_length)); - unsigned int nsamples_total = pow(2, nbits); - unsigned int vector_length = nsamples_total; - unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); + float nbits = ceilf(log2f((float)code_length * 2)); + uint32_t nsamples_total = pow(2, nbits); + uint32_t select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 0); acq_parameters.select_queue_Fpga = select_queue_Fpga; std::string default_device_name = "/dev/uio0"; std::string device_name = configuration_->property(role + ".devicename", default_device_name); acq_parameters.device_name = device_name; acq_parameters.samples_per_ms = nsamples_total / sampled_ms; acq_parameters.samples_per_code = nsamples_total; + acq_parameters.excludelimit = static_cast(std::round(static_cast(fs_in) / GPS_L1_CA_CODE_RATE_HZ)); // compute all the GPS L1 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time // a channel is assigned) - auto* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT + auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT // allocate memory to compute all the PRNs and compute all the possible codes auto* code = new std::complex[nsamples_total]; // buffer for the local code auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 float max; // temporary maxima search - for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++) { gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0); // generate PRN code + + for (uint32_t s = code_length; s < 2 * code_length; s++) + { + code[s] = code[s - code_length]; + } + // fill in zero padding - for (int s = code_length; s < nsamples_total; s++) + for (uint32_t s = 2 * code_length; s < nsamples_total; s++) { code[s] = std::complex(0.0, 0.0); - //code[s] = 0; } - int offset = 0; - memcpy(fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer + + memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer fft_if->execute(); // Run the FFT of local code volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values - - // // debug - // char filename[25]; - // FILE *fid; - // sprintf(filename,"fft_gps_prn%d.txt", PRN); - // fid = fopen(filename, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid, "%f\n", fft_codes_padded[kk].real()); - // fprintf(fid, "%f\n", fft_codes_padded[kk].imag()); - // } - // fclose(fid); - - max = 0; // initialize maximum value - for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + max = 0; // initialize maximum value + for (uint32_t i = 0; i < nsamples_total; i++) // search for maxima { if (std::abs(fft_codes_padded[i].real()) > max) { @@ -135,39 +128,18 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( max = std::abs(fft_codes_padded[i].imag()); } } - for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs { - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), - // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), - // static_cast(16*floor(fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - // static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); - d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max))); } - - - //// // debug - // char filename2[25]; - // FILE *fid2; - // sprintf(filename2,"fft_gps_prn%d_norm_new.txt", PRN); - // fid2 = fopen(filename2, "w"); - // for (unsigned int kk=0;kk< nsamples_total; kk++) - // { - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].real()); - // fprintf(fid2, "%d\n", d_all_fft_codes_[kk + nsamples_total * (PRN - 1)].imag()); - // } - // fclose(fid2); } //acq_parameters acq_parameters.all_fft_codes = d_all_fft_codes_; - // temporary buffers that we can delete - delete[] code; - delete fft_if; - delete[] fft_codes_padded; + // reference for the FPGA FFT-IFFT attenuation factor + acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14); acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; @@ -175,6 +147,11 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( channel_ = 0; doppler_step_ = 0; gnss_synchro_ = nullptr; + + // temporary buffers that we can delete + delete[] code; + delete fft_if; + delete[] fft_codes_padded; } @@ -186,6 +163,8 @@ GpsL1CaPcpsAcquisitionFpga::~GpsL1CaPcpsAcquisitionFpga() void GpsL1CaPcpsAcquisitionFpga::stop_acquisition() { + // this command causes the SW to reset the HW. + acquisition_fpga_->reset_acquisition(); } @@ -198,8 +177,6 @@ void GpsL1CaPcpsAcquisitionFpga::set_channel(unsigned int channel) void GpsL1CaPcpsAcquisitionFpga::set_threshold(float threshold) { - // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. - // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; acquisition_fpga_->set_threshold(threshold); } @@ -246,6 +223,7 @@ void GpsL1CaPcpsAcquisitionFpga::set_local_code() void GpsL1CaPcpsAcquisitionFpga::reset() { + // this function starts the acquisition process acquisition_fpga_->set_active(true); } @@ -255,15 +233,22 @@ void GpsL1CaPcpsAcquisitionFpga::set_state(int state) acquisition_fpga_->set_state(state); } + void GpsL1CaPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) { - // nothing to connect + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect } void GpsL1CaPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) { - // nothing to disconnect + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect } diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h index 015de1d39..e5310414c 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h @@ -1,17 +1,15 @@ /*! * \file gps_l1_ca_pcps_acquisition_fpga.h - * \brief Adapts a PCPS acquisition block that uses the FPGA to - * an AcquisitionInterface for GPS L1 C/A signals + * \brief Adapts a PCPS acquisition block to an AcquisitionInterface + * for GPS L1 C/A signals for the FPGA * \authors
    - *
  • Marc Majoral, 2018. mmajoral(at)cttc.es - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena(at)gmail.com + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -65,7 +63,7 @@ public: } /*! - * \brief Returns "GPS_L1_CA_PCPS_Acquisition" + * \brief Returns "GPS_L1_CA_PCPS_Acquisition_Fpga" */ inline std::string implementation() override { @@ -145,9 +143,9 @@ public: private: ConfigurationInterface* configuration_; pcps_acquisition_fpga_sptr acquisition_fpga_; - unsigned int channel_; - unsigned int doppler_max_; - unsigned int doppler_step_; + uint32_t channel_; + uint32_t doppler_max_; + uint32_t doppler_step_; Gnss_Synchro* gnss_synchro_; std::string role_; unsigned int in_streams_; diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc index 00fcb7624..41b35b509 100644 --- a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition.cc @@ -375,6 +375,8 @@ gr::basic_block_sptr GpsL2MPcpsAcquisition::get_right_block() { return acquisition_; } + + void GpsL2MPcpsAcquisition::set_resampler_latency(uint32_t latency_samples) { acquisition_->set_resampler_latency(latency_samples); diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc index 42358afc1..61f2caf88 100644 --- a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.cc @@ -1,14 +1,15 @@ /*! - * \file gps_l5i pcps_acquisition.cc + * \file gps_l5i pcps_acquisition_fpga.cc * \brief Adapts a PCPS acquisition block to an Acquisition Interface for - * GPS L5i signals + * GPS L5i signals for the FPGA * \authors
    - *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -52,87 +53,71 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga( in_streams_(in_streams), out_streams_(out_streams) { - //printf("L5 ACQ CLASS CREATED\n"); pcpsconf_fpga_t acq_parameters; configuration_ = configuration; - std::string default_item_type = "gr_complex"; - std::string default_dump_filename = "./acquisition.mat"; + std::string default_dump_filename = "./data/acquisition.dat"; LOG(INFO) << "role " << role; - //item_type_ = configuration_->property(role + ".item_type", default_item_type); - int64_t fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); int64_t fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + + float downsampling_factor = configuration_->property(role + ".downsampling_factor", 1.0); + acq_parameters.downsampling_factor = downsampling_factor; + + fs_in = fs_in / downsampling_factor; + acq_parameters.fs_in = fs_in; - //if_ = configuration_->property(role + ".if", 0); - //acq_parameters.freq = if_; - //dump_ = configuration_->property(role + ".dump", false); - //acq_parameters.dump = dump_; - //blocking_ = configuration_->property(role + ".blocking", true); - //acq_parameters.blocking = blocking_; doppler_max_ = configuration->property(role + ".doppler_max", 5000); if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max; acq_parameters.doppler_max = doppler_max_; - //acq_parameters.sampled_ms = 1; - unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); + uint32_t sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); acq_parameters.sampled_ms = sampled_ms; - //printf("L5 ACQ CLASS MID 0\n"); - - //bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false); - //acq_parameters.bit_transition_flag = bit_transition_flag_; - //use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions - //acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_; - //max_dwells_ = configuration_->property(role + ".max_dwells", 1); - //acq_parameters.max_dwells = max_dwells_; - //dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename); - //acq_parameters.dump_filename = dump_filename_; //--- Find number of samples per spreading code ------------------------- - auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L5I_CODE_RATE_HZ / static_cast(GPS_L5I_CODE_LENGTH_CHIPS)))); + auto code_length = static_cast(std::round(static_cast(fs_in) / (GPS_L5I_CODE_RATE_HZ / static_cast(GPS_L5I_CODE_LENGTH_CHIPS)))); acq_parameters.code_length = code_length; // The FPGA can only use FFT lengths that are a power of two. - float nbits = ceilf(log2f((float)code_length)); - unsigned int nsamples_total = pow(2, nbits); - unsigned int vector_length = nsamples_total; - unsigned int select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); + float nbits = ceilf(log2f((float)code_length * 2)); + uint32_t nsamples_total = pow(2, nbits); + uint32_t select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga", 1); acq_parameters.select_queue_Fpga = select_queue_Fpga; std::string default_device_name = "/dev/uio0"; std::string device_name = configuration_->property(role + ".devicename", default_device_name); acq_parameters.device_name = device_name; - acq_parameters.samples_per_ms = nsamples_total; + acq_parameters.samples_per_ms = nsamples_total / sampled_ms; acq_parameters.samples_per_code = nsamples_total; - //printf("L5 ACQ CLASS MID 01\n"); + + acq_parameters.excludelimit = static_cast(ceil((1.0 / GPS_L5I_CODE_RATE_HZ) * static_cast(acq_parameters.fs_in))); + // compute all the GPS L5 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time // a channel is assigned) - auto* fft_if = new gr::fft::fft_complex(vector_length, true); // Direct FFT - //printf("L5 ACQ CLASS MID 02\n"); - auto* code = new gr_complex[vector_length]; - //printf("L5 ACQ CLASS MID 03\n"); + auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT + auto* code = new gr_complex[nsamples_total]; auto* fft_codes_padded = static_cast(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); - //printf("L5 ACQ CLASS MID 04\n"); d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32 - //printf("L5 ACQ CLASS MID 1 vector_length = %d\n", vector_length); - float max; // temporary maxima search - for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++) { - //printf("L5 ACQ CLASS processing PRN = %d\n", PRN); gps_l5i_code_gen_complex_sampled(code, PRN, fs_in); - //printf("L5 ACQ CLASS processing PRN = %d (cont) \n", PRN); - // fill in zero padding - for (int s = code_length; s < nsamples_total; s++) + + for (uint32_t s = code_length; s < 2 * code_length; s++) { + code[s] = code[s - code_length]; + } + + for (uint32_t s = 2 * code_length; s < nsamples_total; s++) + { + // fill in zero padding code[s] = std::complex(0.0, 0.0); - //code[s] = 0; } memcpy(fft_if->get_inbuf(), code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer fft_if->execute(); // Run the FFT of local code volk_32fc_conjugate_32fc(fft_codes_padded, fft_if->get_outbuf(), nsamples_total); // conjugate values - max = 0; // initialize maximum value - for (unsigned int i = 0; i < nsamples_total; i++) // search for maxima + max = 0; // initialize maximum value + for (uint32_t i = 0; i < nsamples_total; i++) // search for maxima { if (std::abs(fft_codes_padded[i].real()) > max) { @@ -143,73 +128,30 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga( max = std::abs(fft_codes_padded[i].imag()); } } - for (unsigned int i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs + for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs { - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), - // static_cast(floor(256*fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), - // static_cast(16*floor(fft_codes_padded[i].imag() * (pow(2, 11) - 1) / max))); - //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - // static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); - d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), - static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); + d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)), + static_cast(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max))); } } - - //printf("L5 ACQ CLASS MID 2\n"); - //acq_parameters acq_parameters.all_fft_codes = d_all_fft_codes_; + // reference for the FPGA FFT-IFFT attenuation factor + acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14); + + acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); + DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; + + channel_ = 0; + doppler_step_ = 0; + gnss_synchro_ = nullptr; + // temporary buffers that we can delete delete[] code; delete fft_if; delete[] fft_codes_padded; - // vector_length_ = code_length_; - // - // if (bit_transition_flag_) - // { - // vector_length_ *= 2; - // } - // - // code_ = new gr_complex[vector_length_]; - // - // if (item_type_.compare("cshort") == 0) - // { - // item_size_ = sizeof(lv_16sc_t); - // } - // else - // { - // item_size_ = sizeof(gr_complex); - // } - // acq_parameters.samples_per_code = code_length_; - // acq_parameters.samples_per_ms = code_length_; - // acq_parameters.it_size = item_size_; - //acq_parameters.sampled_ms = 1; - // acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4); - // acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0); - // acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false); - // acquisition_fpga_ = pcps_make_acquisition(acq_parameters); - // DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; - - acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); - DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; - - // stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_); - // DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id() << ")"; - // - // if (item_type_.compare("cbyte") == 0) - // { - // cbyte_to_float_x2_ = make_complex_byte_to_float_x2(); - // float_to_complex_ = gr::blocks::float_to_complex::make(); - // } - - channel_ = 0; - // threshold_ = 0.0; - doppler_step_ = 0; - gnss_synchro_ = nullptr; - //printf("L5 ACQ CLASS FINISHED\n"); } @@ -222,6 +164,8 @@ GpsL5iPcpsAcquisitionFpga::~GpsL5iPcpsAcquisitionFpga() void GpsL5iPcpsAcquisitionFpga::stop_acquisition() { + // this command causes the SW to reset the HW. + acquisition_fpga_->reset_acquisition(); } @@ -234,25 +178,6 @@ void GpsL5iPcpsAcquisitionFpga::set_channel(unsigned int channel) void GpsL5iPcpsAcquisitionFpga::set_threshold(float threshold) { - // float pfa = configuration_->property(role_ + std::to_string(channel_) + ".pfa", 0.0); - // - // if (pfa == 0.0) - // { - // pfa = configuration_->property(role_ + ".pfa", 0.0); - // } - // if (pfa == 0.0) - // { - // threshold_ = threshold; - // } - // else - // { - // threshold_ = calculate_threshold(pfa); - // } - - // DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_; - - // the .pfa parameter and the threshold calculation is only used for the CFAR algorithm. - // We don't use the CFAR algorithm in the FPGA. Therefore the threshold is set as such. DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold; acquisition_fpga_->set_threshold(threshold); } @@ -303,103 +228,33 @@ void GpsL5iPcpsAcquisitionFpga::reset() acquisition_fpga_->set_active(true); } + void GpsL5iPcpsAcquisitionFpga::set_state(int state) { acquisition_fpga_->set_state(state); } -//float GpsL5iPcpsAcquisitionFpga::calculate_threshold(float pfa) -//{ -// //Calculate the threshold -// unsigned int frequency_bins = 0; -// for (int doppler = static_cast(-doppler_max_); doppler <= static_cast(doppler_max_); doppler += doppler_step_) -// { -// frequency_bins++; -// } -// DLOG(INFO) << "Channel " << channel_ << " Pfa = " << pfa; -// unsigned int ncells = vector_length_ * frequency_bins; -// double exponent = 1.0 / static_cast(ncells); -// double val = pow(1.0 - pfa, exponent); -// double lambda = double(vector_length_); -// boost::math::exponential_distribution mydist(lambda); -// float threshold = static_cast(quantile(mydist, val)); -// -// return threshold; -//} - - void GpsL5iPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) { - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // top_block->connect(cbyte_to_float_x2_, 0, float_to_complex_, 0); - // top_block->connect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - // top_block->connect(float_to_complex_, 0, stream_to_vector_, 0); - // top_block->connect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } - // nothing to connect + if (top_block) + { /* top_block is not null */ + }; + // Nothing to connect } void GpsL5iPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) { - // if (item_type_.compare("gr_complex") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cshort") == 0) - // { - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // // Since a byte-based acq implementation is not available, - // // we just convert cshorts to gr_complex - // top_block->disconnect(cbyte_to_float_x2_, 0, float_to_complex_, 0); - // top_block->disconnect(cbyte_to_float_x2_, 1, float_to_complex_, 1); - // top_block->disconnect(float_to_complex_, 0, stream_to_vector_, 0); - // top_block->disconnect(stream_to_vector_, 0, acquisition_fpga_, 0); - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // } - // nothing to disconnect + if (top_block) + { /* top_block is not null */ + }; + // Nothing to disconnect } gr::basic_block_sptr GpsL5iPcpsAcquisitionFpga::get_left_block() { - // if (item_type_.compare("gr_complex") == 0) - // { - // return stream_to_vector_; - // } - // else if (item_type_.compare("cshort") == 0) - // { - // return stream_to_vector_; - // } - // else if (item_type_.compare("cbyte") == 0) - // { - // return cbyte_to_float_x2_; - // } - // else - // { - // LOG(WARNING) << item_type_ << " unknown acquisition item type"; - // return nullptr; - // } return nullptr; } diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h index bc0a04c4c..8063edd62 100644 --- a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h @@ -1,14 +1,15 @@ /*! - * \file GPS_L5i_PCPS_Acquisition.h + * \file GPS_L5i_PCPS_Acquisition_fpga.h * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * GPS L5i signals + * GPS L5i signals for the FPGA * \authors
    - *
  • Javier Arribas, 2017. jarribas(at)cttc.es + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -66,11 +67,11 @@ public: } /*! - * \brief Returns "GPS_L5i_PCPS_Acquisition" + * \brief Returns "GPS_L5i_PCPS_Acquisition_Fpga" */ inline std::string implementation() override { - return "GPS_L5i_PCPS_Acquisition"; + return "GPS_L5i_PCPS_Acquisition_Fpga"; } inline size_t item_size() override @@ -144,24 +145,22 @@ public: private: ConfigurationInterface* configuration_; - //pcps_acquisition_sptr acquisition_; pcps_acquisition_fpga_sptr acquisition_fpga_; gr::blocks::stream_to_vector::sptr stream_to_vector_; gr::blocks::float_to_complex::sptr float_to_complex_; complex_byte_to_float_x2_sptr cbyte_to_float_x2_; size_t item_size_; std::string item_type_; - unsigned int vector_length_; - unsigned int code_length_; + uint32_t vector_length_; + uint32_t code_length_; bool bit_transition_flag_; bool use_CFAR_algorithm_flag_; - unsigned int channel_; + uint32_t channel_; float threshold_; - unsigned int doppler_max_; - unsigned int doppler_step_; - unsigned int max_dwells_; + uint32_t doppler_max_; + uint32_t doppler_step_; + uint32_t max_dwells_; int64_t fs_in_; - //long if_; bool dump_; bool blocking_; std::string dump_filename_; diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc index ffb4d2452..4c870542d 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.cc @@ -1,21 +1,14 @@ /*! * \file pcps_acquisition_fpga.cc - * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA - * - * Note: The CFAR algorithm is not implemented in the FPGA. - * Note 2: The bit transition flag is not implemented in the FPGA - * + * \brief This class implements a Parallel Code Phase Search Acquisition for the FPGA * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena@gmail.com - *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -33,7 +26,7 @@ * 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 . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -44,7 +37,6 @@ #include #include - #define AQ_DOWNSAMPLING_DELAY 40 // delay due to the downsampling filter in the acquisition using google::LogMessage; @@ -59,14 +51,12 @@ pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block( gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { - // printf("acq constructor start\n"); this->message_port_register_out(pmt::mp("events")); acq_parameters = std::move(conf_); d_sample_counter = 0ULL; // SAMPLE COUNTER d_active = false; d_state = 0; - //d_fft_size = acq_parameters.sampled_ms * acq_parameters.samples_per_ms; d_fft_size = acq_parameters.samples_per_code; d_mag = 0; d_input_power = 0.0; @@ -77,49 +67,30 @@ pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block( d_channel = 0U; d_gnss_synchro = nullptr; - //printf("zzzz acq_parameters.code_length = %d\n", acq_parameters.code_length); - //printf("zzzz acq_parameters.samples_per_ms = %d\n", acq_parameters.samples_per_ms); - //printf("zzzz d_fft_size = %d\n", d_fft_size); + d_downsampling_factor = acq_parameters.downsampling_factor; + d_select_queue_Fpga = acq_parameters.select_queue_Fpga; - // this one works we don't know why - // acquisition_fpga = std::make_shared - // (acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, acq_parameters.samples_per_ms, - // acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); + d_total_block_exp = acq_parameters.total_block_exp; - // this one is the one it should be but it doesn't work - acquisition_fpga = std::make_shared(acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, d_fft_size, - acq_parameters.fs_in, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); - - // acquisition_fpga = std::make_shared - // (acq_parameters.device_name, acq_parameters.samples_per_code, acq_parameters.doppler_max, acq_parameters.samples_per_code, - // acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes); - - // debug - //debug_d_max_absolute = 0.0; - //debug_d_input_power_absolute = 0.0; - // printf("acq constructor end\n"); + acquisition_fpga = std::make_shared(acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, d_fft_size, + acq_parameters.fs_in, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes, acq_parameters.excludelimit); } pcps_acquisition_fpga::~pcps_acquisition_fpga() { - // printf("acq destructor start\n"); acquisition_fpga->free(); - // printf("acq destructor end\n"); } void pcps_acquisition_fpga::set_local_code() { - // printf("acq set local code start\n"); acquisition_fpga->set_local_code(d_gnss_synchro->PRN); - // printf("acq set local code end\n"); } void pcps_acquisition_fpga::init() { - // printf("acq init start\n"); d_gnss_synchro->Flag_valid_acquisition = false; d_gnss_synchro->Flag_valid_symbol_output = false; d_gnss_synchro->Flag_valid_pseudorange = false; @@ -129,23 +100,21 @@ void pcps_acquisition_fpga::init() d_gnss_synchro->Acq_samplestamp_samples = 0; d_mag = 0.0; d_input_power = 0.0; - d_num_doppler_bins = static_cast(std::ceil(static_cast(static_cast(acq_parameters.doppler_max) - static_cast(-acq_parameters.doppler_max)) / static_cast(d_doppler_step))); + + d_num_doppler_bins = static_cast(std::ceil(static_cast(static_cast(acq_parameters.doppler_max) - static_cast(-acq_parameters.doppler_max)) / static_cast(d_doppler_step))) + 1; acquisition_fpga->init(); - // printf("acq init end\n"); } void pcps_acquisition_fpga::set_state(int32_t state) { - // printf("acq set state start\n"); d_state = state; if (d_state == 1) { d_gnss_synchro->Acq_delay_samples = 0.0; d_gnss_synchro->Acq_doppler_hz = 0.0; d_gnss_synchro->Acq_samplestamp_samples = 0; - //d_well_count = 0; d_mag = 0.0; d_input_power = 0.0; d_test_statistics = 0.0; @@ -158,14 +127,12 @@ void pcps_acquisition_fpga::set_state(int32_t state) { LOG(ERROR) << "State can only be set to 0 or 1"; } - // printf("acq set state end\n"); } void pcps_acquisition_fpga::send_positive_acquisition() { - // printf("acq send positive acquisition start\n"); - // 6.1- Declare positive acquisition using a message port + // Declare positive acquisition using a message port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL DLOG(INFO) << "positive acquisition" << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN @@ -178,15 +145,12 @@ void pcps_acquisition_fpga::send_positive_acquisition() << ", input signal power " << d_input_power; this->message_port_pub(pmt::mp("events"), pmt::from_long(1)); - // printf("acq send positive acquisition end\n"); } void pcps_acquisition_fpga::send_negative_acquisition() { - // printf("acq send negative acquisition start\n"); - // 6.2- Declare negative acquisition using a message port - //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL + // Declare negative acquisition using a message port DLOG(INFO) << "negative acquisition" << ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN << ", sample_stamp " << d_sample_counter @@ -198,23 +162,24 @@ void pcps_acquisition_fpga::send_negative_acquisition() << ", input signal power " << d_input_power; this->message_port_pub(pmt::mp("events"), pmt::from_long(2)); - // printf("acq send negative acquisition end\n"); } void pcps_acquisition_fpga::set_active(bool active) { - // printf("acq set active start\n"); d_active = active; // initialize acquisition algorithm uint32_t indext = 0U; - float magt = 0.0; - float fft_normalization_factor = static_cast(d_fft_size) * static_cast(d_fft_size); + float firstpeak = 0.0; + float secondpeak = 0.0; + uint32_t total_block_exp; d_input_power = 0.0; d_mag = 0.0; + int32_t doppler; + DLOG(INFO) << "Channel: " << d_channel << " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN << " ,sample stamp: " << d_sample_counter << ", threshold: " @@ -224,112 +189,57 @@ void pcps_acquisition_fpga::set_active(bool active) << ", use_CFAR_algorithm_flag: false"; uint64_t initial_sample; - float input_power_all = 0.0; - float input_power_computed = 0.0; - float temp_d_input_power; - - // loop through acquisition - /* - for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) - { - // doppler search steps - int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * doppler_index; - - //acquisition_fpga->set_phase_step(doppler_index); - acquisition_fpga->set_doppler_sweep_debug(1, doppler_index); - acquisition_fpga->run_acquisition(); // runs acquisition and waits until it is finished - acquisition_fpga->read_acquisition_results(&indext, &magt, - &initial_sample, &d_input_power, &d_doppler_index); - d_sample_counter = initial_sample; - - if (d_mag < magt) - { - d_mag = magt; - - temp_d_input_power = d_input_power; - - input_power_all = d_input_power / (d_fft_size - 1); - input_power_computed = (d_input_power - d_mag) / (d_fft_size - 1); - d_input_power = (d_input_power - d_mag) / (d_fft_size - 1); - - d_gnss_synchro->Acq_delay_samples = static_cast(indext % acq_parameters.samples_per_code); - d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; - - d_test_statistics = (d_mag / d_input_power); // correction_factor; - } - - // In the case of the FPGA the option of dumping the results of the acquisition to a file is not available - // because the IFFT vector is not available - } -*/ - - // debug - //acquisition_fpga->block_samples(); - - // run loop in hw - //printf("LAUNCH ACQ\n"); + acquisition_fpga->configure_acquisition(); acquisition_fpga->set_doppler_sweep(d_num_doppler_bins); + acquisition_fpga->write_local_code(); + acquisition_fpga->set_block_exp(d_total_block_exp); acquisition_fpga->run_acquisition(); - acquisition_fpga->read_acquisition_results(&indext, &magt, - &initial_sample, &d_input_power, &d_doppler_index); - //printf("READ ACQ RESULTS\n"); + acquisition_fpga->read_acquisition_results(&indext, &firstpeak, &secondpeak, &initial_sample, &d_input_power, &d_doppler_index, &total_block_exp); - // debug - //acquisition_fpga->unblock_samples(); + if (total_block_exp > d_total_block_exp) + { + // if the attenuation factor of the FPGA FFT-IFFT is smaller than the reference attenuation factor then we need to update the reference attenuation factor + std::cout << "changing blk exp..... d_total_block_exp = " << d_total_block_exp << " total_block_exp = " << total_block_exp << " chan = " << d_channel << std::endl; + d_total_block_exp = total_block_exp; + } - d_mag = magt; + doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * (d_doppler_index - 1); + if (secondpeak > 0) + { + d_test_statistics = firstpeak / secondpeak; + } + else + { + d_test_statistics = 0.0; + } - // debug - debug_d_max_absolute = magt; - debug_d_input_power_absolute = d_input_power; - debug_indext = indext; - debug_doppler_index = d_doppler_index; - - // temp_d_input_power = d_input_power; - - d_input_power = (d_input_power - d_mag) / (d_fft_size - 1); - int32_t doppler = -static_cast(acq_parameters.doppler_max) + d_doppler_step * d_doppler_index; - //d_gnss_synchro->Acq_delay_samples = static_cast(2*(indext % (2*acq_parameters.samples_per_code))); - d_gnss_synchro->Acq_delay_samples = static_cast(indext % acq_parameters.samples_per_code); d_gnss_synchro->Acq_doppler_hz = static_cast(doppler); d_sample_counter = initial_sample; - //d_gnss_synchro->Acq_samplestamp_samples = 2*d_sample_counter - 81; // delay due to the downsampling filter in the acquisition - //d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter - 40; // delay due to the downsampling filter in the acquisition - d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; // delay due to the downsampling filter in the acquisition - d_test_statistics = (d_mag / d_input_power); //* correction_factor; - // debug - // if (d_gnss_synchro->Acq_delay_samples > acq_parameters.code_length) - // { - // printf("d_gnss_synchro->Acq_samplestamp_samples = %d\n", d_gnss_synchro->Acq_samplestamp_samples); - // printf("d_gnss_synchro->Acq_delay_samples = %f\n", d_gnss_synchro->Acq_delay_samples); - // } - - // if (temp_d_input_power > debug_d_input_power_absolute) - // { - // debug_d_max_absolute = d_mag; - // debug_d_input_power_absolute = temp_d_input_power; - // } - // printf ("max debug_d_max_absolute = %f\n", debug_d_max_absolute); - // printf ("debug_d_input_power_absolute = %f\n", debug_d_input_power_absolute); - - // printf("&&&&& d_test_statistics = %f\n", d_test_statistics); - // printf("&&&&& debug_d_max_absolute =%f\n",debug_d_max_absolute); - // printf("&&&&& debug_d_input_power_absolute =%f\n",debug_d_input_power_absolute); - // printf("&&&&& debug_indext = %d\n",debug_indext); - // printf("&&&&& debug_doppler_index = %d\n",debug_doppler_index); + if (d_select_queue_Fpga == 0) + { + if (d_downsampling_factor > 1) + { + d_gnss_synchro->Acq_delay_samples = static_cast(d_downsampling_factor * (indext)); + d_gnss_synchro->Acq_samplestamp_samples = d_downsampling_factor * d_sample_counter - 44; //33; //41; //+ 81*0.5; // delay due to the downsampling filter in the acquisition + } + else + { + d_gnss_synchro->Acq_delay_samples = static_cast(indext); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; // delay due to the downsampling filter in the acquisition + } + } + else + { + d_gnss_synchro->Acq_delay_samples = static_cast(indext); + d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; // delay due to the downsampling filter in the acquisition + } if (d_test_statistics > d_threshold) { d_active = false; - // printf("##### d_test_statistics = %f\n", d_test_statistics); - // printf("##### debug_d_max_absolute =%f\n",debug_d_max_absolute); - // printf("##### debug_d_input_power_absolute =%f\n",debug_d_input_power_absolute); - // printf("##### initial_sample = %llu\n",initial_sample); - // printf("##### debug_doppler_index = %d\n",debug_doppler_index); send_positive_acquisition(); d_state = 0; // Positive acquisition } @@ -339,8 +249,6 @@ void pcps_acquisition_fpga::set_active(bool active) d_active = false; send_negative_acquisition(); } - - // printf("acq set active end\n"); } @@ -351,3 +259,16 @@ int pcps_acquisition_fpga::general_work(int noutput_items __attribute__((unused) // the general work is not used with the acquisition that uses the FPGA return noutput_items; } + + +void pcps_acquisition_fpga::reset_acquisition(void) +{ + // this function triggers a HW reset of the FPGA PL. + acquisition_fpga->reset_acquisition(); +} + + +void pcps_acquisition_fpga::read_fpga_total_scale_factor(uint32_t* total_scale_factor, uint32_t* fw_scale_factor) +{ + acquisition_fpga->read_fpga_total_scale_factor(total_scale_factor, fw_scale_factor); +} diff --git a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h index abf8f6b06..58f23928f 100644 --- a/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/gnuradio_blocks/pcps_acquisition_fpga.h @@ -1,36 +1,20 @@ /*! * \file pcps_acquisition_fpga.h - * \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA. + * \brief This class implements a Parallel Code Phase Search Acquisition for the FPGA * - * Note: The CFAR algorithm is not implemented in the FPGA. - * Note 2: The bit transition flag is not implemented in the FPGA - * - * Acquisition strategy (Kay Borre book + CFAR threshold). - *
    - *
  1. Compute the input signal power estimation - *
  2. Doppler serial search loop - *
  3. Perform the FFT-based circular convolution (parallel time search) - *
  4. Record the maximum peak and the associated synchronization parameters - *
  5. Compute the test statistics and compare to the threshold - *
  6. Declare positive or negative acquisition using a message queue - *
* * Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, * "A Software-Defined GPS and Galileo Receiver. A Single-Frequency * Approach", Birkhauser, 2007. pp 81-84 * * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat - *
  • Javier Arribas, 2011. jarribas(at)cttc.es - *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com - *
  • Marc Molina, 2013. marc.molina.pena@gmail.com - *
  • Cillian O'Driscoll, 2017. cillian(at)ieee.org - *
  • Antonio Ramos, 2017. antonio.ramos@cttc.es + *
  • Marc Majoral, 2019. mmajoral(at)cttc.es + *
  • Javier Arribas, 2019. jarribas(at)cttc.es *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -73,12 +57,14 @@ typedef struct uint32_t select_queue_Fpga; std::string device_name; lv_16sc_t* all_fft_codes; // memory that contains all the code ffts - + float downsampling_factor; + uint32_t total_block_exp; + uint32_t excludelimit; } pcpsconf_fpga_t; class pcps_acquisition_fpga; -typedef boost::shared_ptr pcps_acquisition_fpga_sptr; +using pcps_acquisition_fpga_sptr = boost::shared_ptr; pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_); @@ -102,6 +88,8 @@ private: void send_positive_acquisition(); + float first_vs_second_peak_statistic(uint32_t& indext, int32_t& doppler, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step); + pcpsconf_fpga_t acq_parameters; bool d_active; float d_threshold; @@ -116,13 +104,12 @@ private: uint32_t d_num_doppler_bins; uint64_t d_sample_counter; Gnss_Synchro* d_gnss_synchro; - std::shared_ptr acquisition_fpga; + std::shared_ptr acquisition_fpga; - // debug - float debug_d_max_absolute; - float debug_d_input_power_absolute; - int32_t debug_indext; - int32_t debug_doppler_index; + float d_downsampling_factor; + uint32_t d_select_queue_Fpga; + + uint32_t d_total_block_exp; public: ~pcps_acquisition_fpga(); @@ -134,9 +121,7 @@ public: */ inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { - // printf("acq set gnss synchro start\n"); d_gnss_synchro = p_gnss_synchro; - // printf("acq set gnss synchro end\n"); } /*! @@ -144,9 +129,7 @@ public: */ inline uint32_t mag() const { - // printf("acq dmag start\n"); return d_mag; - // printf("acq dmag end\n"); } /*! @@ -190,9 +173,7 @@ public: */ inline void set_threshold(float threshold) { - // printf("acq set threshold start\n"); d_threshold = threshold; - // printf("acq set threshold end\n"); } /*! @@ -201,10 +182,8 @@ public: */ inline void set_doppler_max(uint32_t doppler_max) { - // printf("acq set doppler max start\n"); acq_parameters.doppler_max = doppler_max; acquisition_fpga->set_doppler_max(doppler_max); - // printf("acq set doppler max end\n"); } /*! @@ -213,10 +192,8 @@ public: */ inline void set_doppler_step(uint32_t doppler_step) { - // printf("acq set doppler step start\n"); d_doppler_step = doppler_step; acquisition_fpga->set_doppler_step(doppler_step); - // printf("acq set doppler step end\n"); } /*! @@ -225,6 +202,16 @@ public: int general_work(int noutput_items, gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items); + + /*! + * \brief This funciton triggers a HW reset of the FPGA PL. + */ + void reset_acquisition(void); + + /*! + * \brief This funciton is only used for the unit tests + */ + void read_fpga_total_scale_factor(uint32_t* total_scale_factor, uint32_t* fw_scale_factor); }; #endif /* GNSS_SDR_PCPS_ACQUISITION_FPGA_H_*/ diff --git a/src/algorithms/acquisition/libs/fpga_acquisition.cc b/src/algorithms/acquisition/libs/fpga_acquisition.cc index 5618d072b..3b5419771 100644 --- a/src/algorithms/acquisition/libs/fpga_acquisition.cc +++ b/src/algorithms/acquisition/libs/fpga_acquisition.cc @@ -2,7 +2,7 @@ * \file fpga_acquisition.cc * \brief High optimized FPGA vector correlator class * \authors
    - *
  • Marc Majoral, 2018. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
* * Class that controls and executes a high optimized acquisition HW @@ -43,6 +43,7 @@ #include +// FPGA register parameters #define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map #define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31); #define RESET_ACQUISITION 2 // command to reset the multicorrelator @@ -56,57 +57,48 @@ #define SELECT_MSB 0XFF00 // value to select the most significant byte #define SELECT_16_BITS 0xFFFF // value to select 16 bits #define SHL_8_BITS 256 // value used to shift a value 8 bits to the left - -// 12-bits -//#define SELECT_LSBits 0x0FFF -//#define SELECT_MSBbits 0x00FFF000 -//#define SELECT_24_BITS 0x00FFFFFF -//#define SHL_12_BITS 4096 -// 16-bits -#define SELECT_LSBits 0x0FFFF -#define SELECT_MSBbits 0xFFFF0000 -#define SELECT_32_BITS 0xFFFFFFFF -#define SHL_16_BITS 65536 +#define SELECT_LSBits 0x000003FF // Select the 10 LSbits out of a 20-bit word +#define SELECT_MSBbits 0x000FFC00 // Select the 10 MSbits out of a 20-bit word +#define SELECT_ALL_CODE_BITS 0x000FFFFF // Select a 20 bit word +#define SHL_CODE_BITS 1024 // shift left by 10 bits -bool fpga_acquisition::init() +bool Fpga_Acquisition::init() { - // configure the acquisition with the main initialization values - fpga_acquisition::configure_acquisition(); return true; } -bool fpga_acquisition::set_local_code(uint32_t PRN) +bool Fpga_Acquisition::set_local_code(uint32_t PRN) { // select the code with the chosen PRN - fpga_acquisition::fpga_configure_acquisition_local_code( - &d_all_fft_codes[d_nsamples_total * (PRN - 1)]); - - //fpga_acquisition::fpga_configure_acquisition_local_code( - // &d_all_fft_codes[0]); - + d_PRN = PRN; return true; } -fpga_acquisition::fpga_acquisition(std::string device_name, +void Fpga_Acquisition::write_local_code() +{ + Fpga_Acquisition::fpga_configure_acquisition_local_code( + &d_all_fft_codes[d_nsamples_total * (d_PRN - 1)]); +} + + +Fpga_Acquisition::Fpga_Acquisition(std::string device_name, uint32_t nsamples, uint32_t doppler_max, uint32_t nsamples_total, int64_t fs_in, uint32_t sampled_ms, uint32_t select_queue, - lv_16sc_t *all_fft_codes) + lv_16sc_t *all_fft_codes, + uint32_t excludelimit) { - //printf("AAA- sampled_ms = %d\n ", sampled_ms); + uint32_t vector_length = nsamples_total; - uint32_t vector_length = nsamples_total; // * sampled_ms; - - //printf("AAA- vector_length = %d\n ", vector_length); // initial values d_device_name = std::move(device_name); - //d_freq = freq; d_fs_in = fs_in; d_vector_length = vector_length; + d_excludelimit = excludelimit; d_nsamples = nsamples; // number of samples not including padding d_select_queue = select_queue; d_nsamples_total = nsamples_total; @@ -116,6 +108,18 @@ fpga_acquisition::fpga_acquisition(std::string device_name, d_map_base = nullptr; // driver memory map d_all_fft_codes = all_fft_codes; + Fpga_Acquisition::reset_acquisition(); + Fpga_Acquisition::open_device(); + Fpga_Acquisition::fpga_acquisition_test_register(); + Fpga_Acquisition::close_device(); + + d_PRN = 0; + DLOG(INFO) << "Acquisition FPGA class created"; +} + + +void Fpga_Acquisition::open_device() +{ // open communication with HW accelerator if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1) { @@ -130,11 +134,29 @@ fpga_acquisition::fpga_acquisition(std::string device_name, LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; std::cout << "Acq: cannot map deviceio" << d_device_name << std::endl; } +} + +Fpga_Acquisition::~Fpga_Acquisition() = default; + + +bool Fpga_Acquisition::free() +{ + return true; +} + + +void Fpga_Acquisition::fpga_acquisition_test_register() +{ // sanity check : check test register uint32_t writeval = TEST_REG_SANITY_CHECK; uint32_t readval; - readval = fpga_acquisition::fpga_acquisition_test_register(writeval); + + // write value to test register + d_map_base[15] = writeval; + // read value from test register + readval = d_map_base[15]; + if (writeval != readval) { LOG(WARNING) << "Acquisition test register sanity check failed"; @@ -142,208 +164,115 @@ fpga_acquisition::fpga_acquisition(std::string device_name, else { LOG(INFO) << "Acquisition test register sanity check success!"; - //std::cout << "Acquisition test register sanity check success!" << std::endl; } - fpga_acquisition::reset_acquisition(); - DLOG(INFO) << "Acquisition FPGA class created"; } -fpga_acquisition::~fpga_acquisition() -{ - close_device(); -} - - -bool fpga_acquisition::free() -{ - return true; -} - - -uint32_t fpga_acquisition::fpga_acquisition_test_register(uint32_t writeval) -{ - uint32_t readval; - // write value to test register - d_map_base[15] = writeval; - // read value from test register - readval = d_map_base[15]; - // return read value - return readval; -} - - -void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) +void Fpga_Acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) { uint32_t local_code; uint32_t k, tmp, tmp2; uint32_t fft_data; - // clear memory address counter - //d_map_base[6] = LOCAL_CODE_CLEAR_MEM; d_map_base[9] = LOCAL_CODE_CLEAR_MEM; // write local code for (k = 0; k < d_vector_length; k++) { tmp = fft_local_code[k].real(); tmp2 = fft_local_code[k].imag(); - //tmp = k; - //tmp2 = k; - //local_code = (tmp & SELECT_LSB) | ((tmp2 * SHL_8_BITS) & SELECT_MSB); // put together the real part and the imaginary part - //fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_16_BITS); - //local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_12_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part - local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_16_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part - //fft_data = MEM_LOCAL_CODE_WR_ENABLE | (local_code & SELECT_24_BITS); - fft_data = local_code & SELECT_32_BITS; + local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part + fft_data = local_code & SELECT_ALL_CODE_BITS; d_map_base[6] = fft_data; - - - //printf("debug local code %d real = %d imag = %d local_code = %d fft_data = %d\n", k, tmp, tmp2, local_code, fft_data); - //printf("debug local code %d real = 0x%08X imag = 0x%08X local_code = 0x%08X fft_data = 0x%08X\n", k, tmp, tmp2, local_code, fft_data); } - //printf("d_vector_length = %d\n", d_vector_length); - //while(1); } -void fpga_acquisition::run_acquisition(void) +void Fpga_Acquisition::run_acquisition(void) { // enable interrupts int32_t reenable = 1; + int32_t disable_int = 0; write(d_fd, reinterpret_cast(&reenable), sizeof(int32_t)); - // launch the acquisition process - //printf("launchin acquisition ...\n"); - d_map_base[8] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process + // launch the acquisition process + d_map_base[8] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process int32_t irq_count; ssize_t nb; + // wait for interrupt nb = read(d_fd, &irq_count, sizeof(irq_count)); - //printf("interrupt received\n"); if (nb != sizeof(irq_count)) { - printf("acquisition module Read failed to retrieve 4 bytes!\n"); - printf("acquisition module Interrupt number %d\n", irq_count); + std::cout << "acquisition module Read failed to retrieve 4 bytes!" << std::endl; + std::cout << "acquisition module Interrupt number " << irq_count << std::endl; } + + write(d_fd, reinterpret_cast(&disable_int), sizeof(int32_t)); } -void fpga_acquisition::set_doppler_sweep(uint32_t num_sweeps) +void Fpga_Acquisition::set_block_exp(uint32_t total_block_exp) +{ + d_map_base[11] = total_block_exp; +} + + +void Fpga_Acquisition::set_doppler_sweep(uint32_t num_sweeps) { float phase_step_rad_real; float phase_step_rad_int_temp; int32_t phase_step_rad_int; - //int32_t doppler = static_cast(-d_doppler_max) + d_doppler_step * doppler_index; auto doppler = static_cast(-d_doppler_max); - //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) - // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); + // avoid saturation of the fixed point representation in the fpga // (only the positive value can saturate due to the 2's complement representation) - - //printf("AAA phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real); if (phase_step_rad_real >= 1.0) { phase_step_rad_real = MAX_PHASE_STEP_RAD; } - //printf("AAA phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real); phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - //printf("AAA writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int); d_map_base[3] = phase_step_rad_int; // repeat the calculation with the doppler step doppler = static_cast(d_doppler_step); phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); - //printf("AAA phase_step_rad_real for doppler step = %f\n", phase_step_rad_real); if (phase_step_rad_real >= 1.0) { phase_step_rad_real = MAX_PHASE_STEP_RAD; } - //printf("AAA phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real); phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - //printf("AAA writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int); d_map_base[4] = phase_step_rad_int; - //printf("AAA writing num sweeps to d map base 5 = %d\n", num_sweeps); - d_map_base[5] = num_sweeps; -} - -void fpga_acquisition::set_doppler_sweep_debug(uint32_t num_sweeps, uint32_t doppler_index) -{ - float phase_step_rad_real; - float phase_step_rad_int_temp; - int32_t phase_step_rad_int; - int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - //int32_t doppler = static_cast(-d_doppler_max); - //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); - float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); - // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing - // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) - // The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x) - // while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x) - phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); - // avoid saturation of the fixed point representation in the fpga - // (only the positive value can saturate due to the 2's complement representation) - - //printf("AAAh phase_step_rad_real for initial doppler = %f\n", phase_step_rad_real); - if (phase_step_rad_real >= 1.0) - { - phase_step_rad_real = MAX_PHASE_STEP_RAD; - } - //printf("AAAh phase_step_rad_real for initial doppler after checking = %f\n", phase_step_rad_real); - phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 - phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - //printf("AAAh writing phase_step_rad_int for initial doppler = %d to d map base 3\n", phase_step_rad_int); - d_map_base[3] = phase_step_rad_int; - - // repeat the calculation with the doppler step - doppler = static_cast(d_doppler_step); - phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); - phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); - //printf("AAAh phase_step_rad_real for doppler step = %f\n", phase_step_rad_real); - if (phase_step_rad_real >= 1.0) - { - phase_step_rad_real = MAX_PHASE_STEP_RAD; - } - //printf("AAAh phase_step_rad_real for doppler step after checking = %f\n", phase_step_rad_real); - phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 - phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - //printf("AAAh writing phase_step_rad_int for doppler step = %d to d map base 4\n", phase_step_rad_int); - d_map_base[4] = phase_step_rad_int; - //printf("AAAh writing num sweeps to d map base 5 = %d\n", num_sweeps); d_map_base[5] = num_sweeps; } -void fpga_acquisition::configure_acquisition() +void Fpga_Acquisition::configure_acquisition() { - //printf("AAA d_select_queue = %d\n", d_select_queue); + Fpga_Acquisition::open_device(); + d_map_base[0] = d_select_queue; - //printf("AAA writing d_vector_length = %d to d map base 1\n ", d_vector_length); d_map_base[1] = d_vector_length; - //printf("AAA writing d_nsamples = %d to d map base 2\n ", d_nsamples); d_map_base[2] = d_nsamples; - //printf("AAA writing LOG2 d_vector_length = %d to d map base 7\n ", (int)log2((float)d_vector_length)); d_map_base[7] = static_cast(log2(static_cast(d_vector_length))); // log2 FFTlength - //printf("acquisition debug vector length = %d\n", d_vector_length); - //printf("acquisition debug vector length = %d\n", (int)log2((float)d_vector_length)); + d_map_base[12] = d_excludelimit; } -void fpga_acquisition::set_phase_step(uint32_t doppler_index) +void Fpga_Acquisition::set_phase_step(uint32_t doppler_index) { float phase_step_rad_real; float phase_step_rad_int_temp; int32_t phase_step_rad_int; int32_t doppler = -static_cast(d_doppler_max) + d_doppler_step * doppler_index; - //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast(d_fs_in); float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast(d_fs_in); // The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing // The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi) @@ -352,73 +281,101 @@ void fpga_acquisition::set_phase_step(uint32_t doppler_index) phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2); // avoid saturation of the fixed point representation in the fpga // (only the positive value can saturate due to the 2's complement representation) - //printf("AAA+ phase_step_rad_real = %f\n", phase_step_rad_real); if (phase_step_rad_real >= 1.0) { phase_step_rad_real = MAX_PHASE_STEP_RAD; } - //printf("AAA+ phase_step_rad_real after checking = %f\n", phase_step_rad_real); phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2 phase_step_rad_int = static_cast(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings - //printf("writing phase_step_rad_int = %d to d_map_base 3\n", phase_step_rad_int); d_map_base[3] = phase_step_rad_int; } -void fpga_acquisition::read_acquisition_results(uint32_t *max_index, - float *max_magnitude, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index) +void Fpga_Acquisition::read_acquisition_results(uint32_t *max_index, + float *firstpeak, float *secondpeak, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index, uint32_t *total_blk_exp) { uint64_t initial_sample_tmp = 0; - uint32_t readval = 0; uint64_t readval_long = 0; uint64_t readval_long_shifted = 0; + readval = d_map_base[1]; initial_sample_tmp = readval; + readval_long = d_map_base[2]; - readval_long_shifted = readval_long << 32; // 2^32 + readval_long_shifted = readval_long << 32; // 2^32 + initial_sample_tmp = initial_sample_tmp + readval_long_shifted; // 2^32 - //printf("----------------------------------------------------------------> acq initial sample TOTAL = %llu\n", initial_sample_tmp); *initial_sample = initial_sample_tmp; - readval = d_map_base[6]; - *max_magnitude = static_cast(readval); - //printf("read max_magnitude dmap 2 = %d\n", readval); - readval = d_map_base[4]; - *power_sum = static_cast(readval); - //printf("read power sum dmap 4 = %d\n", readval); - readval = d_map_base[5]; // read doppler index - *doppler_index = readval; - //printf("read doppler_index dmap 5 = %d\n", readval); + readval = d_map_base[3]; + *firstpeak = static_cast(readval); + + readval = d_map_base[4]; + *secondpeak = static_cast(readval); + + readval = d_map_base[5]; *max_index = readval; - //printf("read max index dmap 3 = %d\n", readval); + + *power_sum = 0; + + readval = d_map_base[8]; + *total_blk_exp = readval; + + readval = d_map_base[7]; // read doppler index -- this read releases the interrupt line + *doppler_index = readval; + + readval = d_map_base[15]; // read dummy + + Fpga_Acquisition::close_device(); } -void fpga_acquisition::block_samples() +void Fpga_Acquisition::block_samples() { d_map_base[14] = 1; // block the samples } -void fpga_acquisition::unblock_samples() +void Fpga_Acquisition::unblock_samples() { d_map_base[14] = 0; // unblock the samples } -void fpga_acquisition::close_device() +void Fpga_Acquisition::close_device() { auto *aux = const_cast(d_map_base); if (munmap(static_cast(aux), PAGE_SIZE) == -1) { - printf("Failed to unmap memory uio\n"); + std::cout << "Failed to unmap memory uio" << std::endl; } close(d_fd); } -void fpga_acquisition::reset_acquisition(void) +void Fpga_Acquisition::reset_acquisition(void) { + Fpga_Acquisition::open_device(); d_map_base[8] = RESET_ACQUISITION; // writing a 2 to d_map_base[8] resets the multicorrelator + Fpga_Acquisition::close_device(); +} + + +// this function is only used for the unit tests +void Fpga_Acquisition::read_fpga_total_scale_factor(uint32_t *total_scale_factor, uint32_t *fw_scale_factor) +{ + uint32_t readval = 0; + readval = d_map_base[8]; + *total_scale_factor = readval; + + //readval = d_map_base[8]; + *fw_scale_factor = 0; +} + +void Fpga_Acquisition::read_result_valid(uint32_t *result_valid) +{ + uint32_t readval = 0; + readval = d_map_base[0]; + *result_valid = readval; } diff --git a/src/algorithms/acquisition/libs/fpga_acquisition.h b/src/algorithms/acquisition/libs/fpga_acquisition.h index c23e6b5d5..2be464c97 100644 --- a/src/algorithms/acquisition/libs/fpga_acquisition.h +++ b/src/algorithms/acquisition/libs/fpga_acquisition.h @@ -2,7 +2,7 @@ * \file fpga_acquisition.h * \brief High optimized FPGA vector correlator class * \authors
    - *
  • Marc Majoral, 2018. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
* * Class that controls and executes a high optimized acquisition HW @@ -10,7 +10,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -43,28 +43,28 @@ /*! * \brief Class that implements carrier wipe-off and correlators. */ -class fpga_acquisition +class Fpga_Acquisition { public: - fpga_acquisition(std::string device_name, + Fpga_Acquisition(std::string device_name, uint32_t nsamples, uint32_t doppler_max, uint32_t nsamples_total, int64_t fs_in, uint32_t sampled_ms, uint32_t select_queue, - lv_16sc_t *all_fft_codes); + lv_16sc_t *all_fft_codes, + uint32_t excludelimit); - ~fpga_acquisition(); + ~Fpga_Acquisition(); bool init(); bool set_local_code(uint32_t PRN); bool free(); void set_doppler_sweep(uint32_t num_sweeps); - void set_doppler_sweep_debug(uint32_t num_sweeps, uint32_t doppler_index); void run_acquisition(void); void set_phase_step(uint32_t doppler_index); - void read_acquisition_results(uint32_t *max_index, float *max_magnitude, - uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index); + void read_acquisition_results(uint32_t *max_index, float *firstpeak, float *secondpeak, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index, uint32_t *total_blk_exp); + void block_samples(); void unblock_samples(); @@ -86,6 +86,25 @@ public: d_doppler_step = doppler_step; } + /*! + * \brief Reset the FPGA PL. + */ + void reset_acquisition(void); + + /*! + * \brief read the scaling factor that has been used by the FFT-IFFT + */ + void read_fpga_total_scale_factor(uint32_t *total_scale_factor, uint32_t *fw_scale_factor); + + void set_block_exp(uint32_t total_block_exp); + + void write_local_code(void); + + void configure_acquisition(void); + + void close_device(); + void open_device(); + private: int64_t d_fs_in; // data related to the hardware module and the driver @@ -93,18 +112,18 @@ private: volatile uint32_t *d_map_base; // driver memory map lv_16sc_t *d_all_fft_codes; // memory that contains all the code ffts uint32_t d_vector_length; // number of samples incluing padding and number of ms - uint32_t d_nsamples_total; // number of samples including padding - uint32_t d_nsamples; // number of samples not including padding - uint32_t d_select_queue; // queue selection - std::string d_device_name; // HW device name - uint32_t d_doppler_max; // max doppler - uint32_t d_doppler_step; // doppler step + uint32_t d_excludelimit; + uint32_t d_nsamples_total; // number of samples including padding + uint32_t d_nsamples; // number of samples not including padding + uint32_t d_select_queue; // queue selection + std::string d_device_name; // HW device name + uint32_t d_doppler_max; // max doppler + uint32_t d_doppler_step; // doppler step + uint32_t d_PRN; // PRN // FPGA private functions - uint32_t fpga_acquisition_test_register(uint32_t writeval); + void fpga_acquisition_test_register(void); void fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]); - void configure_acquisition(); - void reset_acquisition(void); - void close_device(); + void read_result_valid(uint32_t *result_valid); }; #endif /* GNSS_SDR_FPGA_ACQUISITION_H_ */ diff --git a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc index 94eb8e294..dfe5d3e21 100644 --- a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc +++ b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.cc @@ -1,9 +1,9 @@ /*! * \file gnss_sdr_fpga_sample_counter.cc - * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \brief Simple block to report the current receiver time based on the output + * of the tracking or telemetry blocks * \author Javier Arribas 2018. jarribas(at)cttc.es * - * * ------------------------------------------------------------------------- * * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) @@ -53,10 +53,7 @@ gnss_sdr_fpga_sample_counter::gnss_sdr_fpga_sample_counter( set_max_noutput_items(1); interval_ms = _interval_ms; fs = _fs; - //printf("CREATOR fs = %f\n", fs); - //printf("CREATOR interval_ms = %" PRIu32 "\n", interval_ms); samples_per_output = std::round(fs * static_cast(interval_ms) / 1e3); - //printf("CREATOR samples_per_output = %" PRIu32 "\n", samples_per_output); //todo: Load here the hardware counter register with this amount of samples. It should produce an //interrupt every samples_per_output count. //The hardware timer must keep always interrupting the PS. It must not wait for the interrupt to @@ -122,7 +119,6 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( uint32_t counter = wait_for_interrupt_and_read_counter(); uint64_t samples_passed = 2 * static_cast(samples_per_output) - static_cast(counter); // ellapsed samples - //printf("============================================ interrupter : samples_passed = %" PRIu64 "\n", samples_passed); // Note: at this moment the sample counter is implemented as a sample counter that decreases to zero and then it is automatically // reloaded again and keeps counter. It is done in this way to minimize the logic in the FPGA and maximize the FPGA clock performance // (it takes less resources and latency in the FPGA to compare a number against a fixed value like zero than to compare it to a programmable @@ -137,10 +133,6 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( out[0].fs = fs; if ((current_T_rx_ms % report_interval_ms) == 0) { - //printf("time to print sample_counter = %" PRIu64 "\n", sample_counter); - //printf("time to print current Tx ms : %" PRIu64 "\n", current_T_rx_ms); - //printf("time to print report_interval_ms : %" PRIu32 "\n", report_interval_ms); - //printf("time to print %f\n", (current_T_rx_ms % report_interval_ms)); current_s++; if ((current_s % 60) == 0) { @@ -203,6 +195,7 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__(( return 1; } + uint32_t gnss_sdr_fpga_sample_counter::test_register(uint32_t writeval) { uint32_t readval; @@ -214,20 +207,14 @@ uint32_t gnss_sdr_fpga_sample_counter::test_register(uint32_t writeval) return readval; } + void gnss_sdr_fpga_sample_counter::configure_samples_per_output(uint32_t interval) { // note : the counter is a 48-bit value in the HW. - //printf("============================================ total counter - interrupted interval : %" PRIu32 "\n", interval); - //uint64_t temp_interval; - //temp_interval = (interval & static_cast(0xFFFFFFFF)); - //printf("LSW counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); - //map_base[0] = static_cast(temp_interval); map_base[0] = interval - 1; - //temp_interval = (interval >> 32) & static_cast(0xFFFFFFFF); - //printf("MSbits counter - interrupted interval : %" PRIu32 "\n", static_cast(temp_interval)); - //map_base[1] = static_cast(temp_interval); // writing the most significant bits also enables the interrupts } + void gnss_sdr_fpga_sample_counter::open_device() { // open communication with HW accelerator @@ -260,19 +247,20 @@ void gnss_sdr_fpga_sample_counter::open_device() } } + void gnss_sdr_fpga_sample_counter::close_device() { - //printf("=========================================== NOW closing device ...\n"); map_base[2] = 0; // disable the generation of the interrupt in the device auto *aux = const_cast(map_base); if (munmap(static_cast(aux), PAGE_SIZE) == -1) { - printf("Failed to unmap memory uio\n"); + std::cout << "Failed to unmap memory uio" << std::endl; } close(fd); } + uint32_t gnss_sdr_fpga_sample_counter::wait_for_interrupt_and_read_counter() { int32_t irq_count; @@ -284,18 +272,15 @@ uint32_t gnss_sdr_fpga_sample_counter::wait_for_interrupt_and_read_counter() write(fd, reinterpret_cast(&reenable), sizeof(int32_t)); // wait for interrupt - //printf("============================================ interrupter : going to wait for interupt\n"); nb = read(fd, &irq_count, sizeof(irq_count)); - //printf("============================================ interrupter : interrupt received\n"); - //printf("interrupt received\n"); if (nb != sizeof(irq_count)) { - printf("acquisition module Read failed to retrieve 4 bytes!\n"); - printf("acquisition module Interrupt number %d\n", irq_count); + std::cout << "FPGA sample counter module read failed to retrieve 4 bytes!" << std::endl; + std::cout << "FPGA sample counter module interrupt number " << irq_count << std::endl; } - // acknowledge the interrupt - map_base[1] = 0; // writing anything to reg 1 acknowledges the interrupt + // it is a rising edge interrupt, the interrupt does not need to be acknowledged + //map_base[1] = 0; // writing anything to reg 1 acknowledges the interrupt // add number of passed samples or read the current counter value for more accuracy counter = samples_per_output; //map_base[0]; diff --git a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h index 75b924e72..d19fc6dba 100644 --- a/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h +++ b/src/algorithms/libs/gnss_sdr_fpga_sample_counter.h @@ -1,6 +1,7 @@ /*! * \file gnss_sdr_fpga_sample_counter.h - * \brief Simple block to report the current receiver time based on the output of the tracking or telemetry blocks + * \brief Simple block to report the current receiver time based on the output + * of the tracking or telemetry blocks * \author Javier Arribas 2018. jarribas(at)cttc.es * * @@ -28,16 +29,18 @@ * * ------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_FPGA_sample_counter_H_ -#define GNSS_SDR_FPGA_sample_counter_H_ + +#ifndef GNSS_SDR_GNSS_SDR_FPGA_SAMPLE_COUNTER_H_ +#define GNSS_SDR_GNSS_SDR_FPGA_SAMPLE_COUNTER_H_ #include #include #include +#include class gnss_sdr_fpga_sample_counter; -typedef boost::shared_ptr gnss_sdr_fpga_sample_counter_sptr; +using gnss_sdr_fpga_sample_counter_sptr = boost::shared_ptr; gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms); @@ -66,9 +69,9 @@ private: uint32_t current_days; // Receiver time in days since the beginning of the run int32_t report_interval_ms; bool flag_enable_send_msg; - int32_t fd; // driver descriptor - volatile uint32_t *map_base; // driver memory map - std::string device_name = "/dev/uio26"; // HW device name + int32_t fd; // driver descriptor + volatile uint32_t *map_base; // driver memory map + std::string device_name = "/dev/uio2"; // HW device name public: friend gnss_sdr_fpga_sample_counter_sptr gnss_sdr_make_fpga_sample_counter(double _fs, int32_t _interval_ms); @@ -78,4 +81,4 @@ public: gr_vector_void_star &output_items); }; -#endif /*GNSS_SDR_FPGA_sample_counter_H_*/ +#endif // GNSS_SDR_GNSS_SDR_FPGA_SAMPLE_COUNTER_H_ diff --git a/src/algorithms/libs/gnss_sdr_time_counter.h b/src/algorithms/libs/gnss_sdr_time_counter.h index 870f6717c..dcf7ca018 100644 --- a/src/algorithms/libs/gnss_sdr_time_counter.h +++ b/src/algorithms/libs/gnss_sdr_time_counter.h @@ -37,7 +37,7 @@ class gnss_sdr_time_counter; -typedef boost::shared_ptr gnss_sdr_time_counter_sptr; +using gnss_sdr_time_counter_sptr = boost::shared_ptr; gnss_sdr_time_counter_sptr gnss_sdr_make_time_counter(); diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc index 5d989b956..0a09cc789 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc @@ -107,9 +107,9 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(ConfigurationInterface* configura } // turn switch to A/D position - std::string default_device_name = "/dev/uio13"; + std::string default_device_name = "/dev/uio1"; std::string device_name = configuration->property(role + ".devicename", default_device_name); - int switch_position = configuration->property(role + ".switch_position", 0); + int32_t switch_position = configuration->property(role + ".switch_position", 0); switch_fpga = std::make_shared(device_name); switch_fpga->set_switch_position(switch_position); if (in_stream_ > 0) diff --git a/src/algorithms/signal_source/libs/fpga_switch.cc b/src/algorithms/signal_source/libs/fpga_switch.cc index 3f1caec12..5dec90e55 100644 --- a/src/algorithms/signal_source/libs/fpga_switch.cc +++ b/src/algorithms/signal_source/libs/fpga_switch.cc @@ -2,7 +2,7 @@ * \file fpga_switch.cc * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2015. jarribas(at)cttc.es *
* @@ -43,7 +43,7 @@ // constants const size_t PAGE_SIZE = 0x10000; -const unsigned int TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; +const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; Fpga_Switch::Fpga_Switch(const std::string &device_name) { @@ -87,7 +87,7 @@ Fpga_Switch::~Fpga_Switch() } -void Fpga_Switch::set_switch_position(int switch_position) +void Fpga_Switch::set_switch_position(int32_t switch_position) { d_map_base[0] = switch_position; } diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h index f535bce7d..c6a67c5fc 100644 --- a/src/algorithms/signal_source/libs/fpga_switch.h +++ b/src/algorithms/signal_source/libs/fpga_switch.h @@ -2,7 +2,7 @@ * \file fpga_switch.h * \brief Switch that connects the HW accelerator queues to the analog front end or the DMA. * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2016. jarribas(at)cttc.es *
* @@ -46,7 +46,7 @@ class Fpga_Switch public: Fpga_Switch(const std::string& device_name); ~Fpga_Switch(); - void set_switch_position(int switch_position); + void set_switch_position(int32_t switch_position); private: int d_device_descriptor; // driver descriptor diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc index 7d8462ea3..1175d35d5 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.cc @@ -1,7 +1,8 @@ /*! - * \file galileo_e1_dll_pll_veml_tracking.cc + * \file galileo_e1_dll_pll_veml_tracking_fpga.cc * \brief Adapts a DLL+PLL VEML (Very Early Minus Late) tracking loop block - * to a TrackingInterface for Galileo E1 signals + * to a TrackingInterface for Galileo E1 signals for the FPGA + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com * * Code DLL + carrier PLL according to the algorithms described in: @@ -11,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -42,8 +43,6 @@ #include "gnss_sdr_flags.h" #include -//#define NUM_PRNs_GALILEO_E1 50 - using google::LogMessage; void GalileoE1DllPllVemlTrackingFpga::stop_tracking() @@ -54,14 +53,13 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga( ConfigurationInterface* configuration, const std::string& role, unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { - //dllpllconf_t trk_param; Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## std::string default_item_type = "gr_complex"; std::string item_type = configuration->property(role + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); trk_param_fpga.fs_in = fs_in; bool dump = configuration->property(role + ".dump", false); trk_param_fpga.dump = dump; @@ -80,7 +78,7 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga( trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz; float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25); trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; - int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + int32_t extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15); trk_param_fpga.early_late_space_chips = early_late_space_chips; float very_early_late_space_chips = configuration->property(role + ".very_early_late_space_chips", 0.6); @@ -107,18 +105,18 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga( trk_param_fpga.track_pilot = track_pilot; d_track_pilot = track_pilot; trk_param_fpga.extend_correlation_symbols = extend_correlation_symbols; - int vector_length = std::round(fs_in / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS)); + int32_t vector_length = std::round(fs_in / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS)); trk_param_fpga.vector_length = vector_length; trk_param_fpga.system = 'E'; char sig_[3] = "1B"; std::memcpy(trk_param_fpga.signal, sig_, 3); - int cn0_samples = configuration->property(role + ".cn0_samples", 20); + int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20); if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; trk_param_fpga.cn0_samples = cn0_samples; - int cn0_min = configuration->property(role + ".cn0_min", 25); + int32_t cn0_min = configuration->property(role + ".cn0_min", 25); if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; trk_param_fpga.cn0_min = cn0_min; - int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50); if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; trk_param_fpga.max_lock_fail = max_lock_fail; double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); @@ -129,63 +127,51 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga( std::string default_device_name = "/dev/uio"; std::string device_name = configuration->property(role + ".devicename", default_device_name); trk_param_fpga.device_name = device_name; - unsigned int device_base = configuration->property(role + ".device_base", 1); + uint32_t device_base = configuration->property(role + ".device_base", 15); trk_param_fpga.device_base = device_base; - //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 1); trk_param_fpga.multicorr_type = 1; // 0 -> 3 correlators, 1 -> 5 correlators //################# PRE-COMPUTE ALL THE CODES ################# - unsigned int code_samples_per_chip = 2; - d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * GALILEO_E1_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + uint32_t code_samples_per_chip = 2; + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * GALILEO_E1_NUMBER_OF_CODES * sizeof(int32_t), volk_gnsssdr_get_alignment())); float* ca_codes_f; float* data_codes_f; - if (trk_param_fpga.track_pilot) - { - d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * GALILEO_E1_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); - } - ca_codes_f = static_cast(volk_gnsssdr_malloc(static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); if (trk_param_fpga.track_pilot) { - data_codes_f = static_cast(volk_gnsssdr_malloc((static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * GALILEO_E1_NUMBER_OF_CODES * sizeof(int32_t), volk_gnsssdr_get_alignment())); + } + ca_codes_f = static_cast(volk_gnsssdr_malloc(static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); + + if (trk_param_fpga.track_pilot) + { + data_codes_f = static_cast(volk_gnsssdr_malloc((static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)) * code_samples_per_chip * sizeof(float), volk_gnsssdr_get_alignment())); } - //printf("pppppppp trk_param_fpga.track_pilot = %d\n", trk_param_fpga.track_pilot); - - //int kk; - - for (unsigned int PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++) + for (uint32_t PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++) { char data_signal[3] = "1B"; if (trk_param_fpga.track_pilot) { - //printf("yes tracking pilot !!!!!!!!!!!!!!!\n"); char pilot_signal[3] = "1C"; galileo_e1_code_gen_sinboc11_float(ca_codes_f, pilot_signal, PRN); galileo_e1_code_gen_sinboc11_float(data_codes_f, data_signal, PRN); - for (unsigned int s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++) + for (uint32_t s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++) { - d_ca_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); - d_data_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(data_codes_f[s]); - //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); + d_data_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(data_codes_f[s]); } - //printf("\n next \n"); - //scanf ("%d",&kk); } else { - //printf("no tracking pilot\n"); galileo_e1_code_gen_sinboc11_float(ca_codes_f, data_signal, PRN); - for (unsigned int s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++) + for (uint32_t s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++) { - d_ca_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); - //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast(ca_codes_f[s]); } - //printf("\n next \n"); - //scanf ("%d",&kk); } } @@ -216,7 +202,6 @@ GalileoE1DllPllVemlTrackingFpga::~GalileoE1DllPllVemlTrackingFpga() void GalileoE1DllPllVemlTrackingFpga::start_tracking() { - //tracking_->start_tracking(); tracking_fpga_sc->start_tracking(); } @@ -227,14 +212,12 @@ void GalileoE1DllPllVemlTrackingFpga::start_tracking() void GalileoE1DllPllVemlTrackingFpga::set_channel(unsigned int channel) { channel_ = channel; - //tracking_->set_channel(channel); tracking_fpga_sc->set_channel(channel); } void GalileoE1DllPllVemlTrackingFpga::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) { - //tracking_->set_gnss_synchro(p_gnss_synchro); tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); } @@ -259,13 +242,11 @@ void GalileoE1DllPllVemlTrackingFpga::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr GalileoE1DllPllVemlTrackingFpga::get_left_block() { - //return tracking_; return tracking_fpga_sc; } gr::basic_block_sptr GalileoE1DllPllVemlTrackingFpga::get_right_block() { - //return tracking_; return tracking_fpga_sc; } diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h index 794aa22d4..003aec195 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h @@ -1,7 +1,8 @@ /*! - * \file galileo_e1_dll_pll_veml_tracking.h + * \file galileo_e1_dll_pll_veml_tracking_fpga.h * \brief Adapts a DLL+PLL VEML (Very Early Minus Late) tracking loop block - * to a TrackingInterface for Galileo E1 signals + * to a TrackingInterface for Galileo E1 signals for the FPGA + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com * * Code DLL + carrier PLL according to the algorithms described in: @@ -11,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -63,7 +64,7 @@ public: return role_; } - //! Returns "Galileo_E1_DLL_PLL_VEML_Tracking" + //! Returns "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga" inline std::string implementation() override { return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga"; @@ -100,15 +101,14 @@ public: private: - //dll_pll_veml_tracking_sptr tracking_; dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; size_t item_size_; - unsigned int channel_; + uint32_t channel_; std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; - int* d_ca_codes; - int* d_data_codes; + uint32_t in_streams_; + uint32_t out_streams_; + int32_t* d_ca_codes; + int32_t* d_data_codes; bool d_track_pilot; }; diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc index b0e69c064..f66c967bd 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.cc @@ -1,19 +1,20 @@ /*! - * \file galileo_e5a_dll_pll_tracking.cc + * \file galileo_e5a_dll_pll_tracking_fpga.cc * \brief Adapts a code DLL + carrier PLL - * tracking block to a TrackingInterface for Galileo E5a signals + * tracking block to a TrackingInterface for Galileo E5a signals for the FPGA * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * Galileo E5a data and pilot Signals + * Galileo E5a data and pilot Signals for the FPGA * \author Marc Sales, 2014. marcsales92(at)gmail.com * \based on work from: *
    + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2011. jarribas(at)cttc.es *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -54,16 +55,13 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga( ConfigurationInterface *configuration, const std::string &role, unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { - //printf("creating the E5A tracking"); - - Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## std::string default_item_type = "gr_complex"; std::string item_type = configuration->property(role + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12000000); - int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12000000); + int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); trk_param_fpga.fs_in = fs_in; bool dump = configuration->property(role + ".dump", false); trk_param_fpga.dump = dump; @@ -84,9 +82,9 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga( trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); trk_param_fpga.early_late_space_chips = early_late_space_chips; - int vector_length = std::round(fs_in / (GALILEO_E5A_CODE_CHIP_RATE_HZ / GALILEO_E5A_CODE_LENGTH_CHIPS)); + int32_t vector_length = std::round(fs_in / (GALILEO_E5A_CODE_CHIP_RATE_HZ / GALILEO_E5A_CODE_LENGTH_CHIPS)); trk_param_fpga.vector_length = vector_length; - int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + int32_t extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; bool track_pilot = configuration->property(role + ".track_pilot", false); @@ -112,13 +110,13 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga( trk_param_fpga.system = 'E'; char sig_[3] = "5X"; std::memcpy(trk_param_fpga.signal, sig_, 3); - int cn0_samples = configuration->property(role + ".cn0_samples", 20); + int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20); if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; trk_param_fpga.cn0_samples = cn0_samples; - int cn0_min = configuration->property(role + ".cn0_min", 25); + int32_t cn0_min = configuration->property(role + ".cn0_min", 25); if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; trk_param_fpga.cn0_min = cn0_min; - int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50); if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; trk_param_fpga.max_lock_fail = max_lock_fail; double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); @@ -129,93 +127,53 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga( std::string default_device_name = "/dev/uio"; std::string device_name = configuration->property(role + ".devicename", default_device_name); trk_param_fpga.device_name = device_name; - unsigned int device_base = configuration->property(role + ".device_base", 1); + uint32_t device_base = configuration->property(role + ".device_base", 27); trk_param_fpga.device_base = device_base; - //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 1); trk_param_fpga.multicorr_type = 1; // 0 -> 3 correlators, 1 -> up to 5+1 correlators //################# PRE-COMPUTE ALL THE CODES ################# - unsigned int code_samples_per_chip = 1; - auto code_length_chips = static_cast(GALILEO_E5A_CODE_LENGTH_CHIPS); + uint32_t code_samples_per_chip = 1; + auto code_length_chips = static_cast(GALILEO_E5A_CODE_LENGTH_CHIPS); auto *aux_code = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex) * code_length_chips * code_samples_per_chip, volk_gnsssdr_get_alignment())); - float *tracking_code; - float *data_code; + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips) * code_samples_per_chip * GALILEO_E5A_NUMBER_OF_CODES * sizeof(int32_t), volk_gnsssdr_get_alignment())); if (trk_param_fpga.track_pilot) { - data_code = static_cast(volk_gnsssdr_malloc(code_samples_per_chip * code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); - } - tracking_code = static_cast(volk_gnsssdr_malloc(code_samples_per_chip * code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); - - d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips) * code_samples_per_chip * GALILEO_E5A_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); - - if (trk_param_fpga.track_pilot) - { - d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * code_samples_per_chip * GALILEO_E5A_NUMBER_OF_CODES * sizeof(int), volk_gnsssdr_get_alignment())); + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * code_samples_per_chip * GALILEO_E5A_NUMBER_OF_CODES * sizeof(int32_t), volk_gnsssdr_get_alignment())); } - for (unsigned int PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++) + for (uint32_t PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++) { - //galileo_e5_a_code_gen_complex_primary(aux_code, PRN, const_cast(trk_param_fpga.signal.c_str())); galileo_e5_a_code_gen_complex_primary(aux_code, PRN, const_cast(sig_)); if (trk_param_fpga.track_pilot) { - //d_secondary_code_string = const_cast(&Galileo_E5a_Q_SECONDARY_CODE[PRN - 1]); - for (unsigned int i = 0; i < code_length_chips; i++) + for (uint32_t s = 0; s < code_length_chips; s++) { - tracking_code[i] = aux_code[i].imag(); - data_code[i] = aux_code[i].real(); - } - for (unsigned int s = 0; s < code_length_chips; s++) - { - d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); - d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); - //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(aux_code[s].imag()); + d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(aux_code[s].real()); } } else { - for (unsigned int i = 0; i < code_length_chips; i++) + for (uint32_t s = 0; s < code_length_chips; s++) { - tracking_code[i] = aux_code[i].real(); - } - - for (unsigned int s = 0; s < code_length_chips; s++) - { - d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); - //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(aux_code[s].real()); } } } volk_gnsssdr_free(aux_code); - volk_gnsssdr_free(tracking_code); - if (trk_param_fpga.track_pilot) - { - volk_gnsssdr_free(data_code); - } trk_param_fpga.ca_codes = d_ca_codes; trk_param_fpga.data_codes = d_data_codes; trk_param_fpga.code_length_chips = code_length_chips; trk_param_fpga.code_samples_per_chip = code_samples_per_chip; // 2 sample per chip //################# MAKE TRACKING GNURadio object ################### tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); - // if (item_type.compare("gr_complex") == 0) - // { - // item_size_ = sizeof(gr_complex); - // tracking_ = dll_pll_veml_make_tracking(trk_param_fpga); - // } - // else - // { - // item_size_ = sizeof(gr_complex); - // LOG(WARNING) << item_type << " unknown tracking item type."; - // } channel_ = 0; - //DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")"; DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; } @@ -232,7 +190,6 @@ GalileoE5aDllPllTrackingFpga::~GalileoE5aDllPllTrackingFpga() void GalileoE5aDllPllTrackingFpga::start_tracking() { - //tracking_->start_tracking(); tracking_fpga_sc->start_tracking(); } @@ -242,16 +199,13 @@ void GalileoE5aDllPllTrackingFpga::start_tracking() */ void GalileoE5aDllPllTrackingFpga::set_channel(unsigned int channel) { - //printf("blabla channel = %d\n", channel); channel_ = channel; - //tracking_->set_channel(channel); tracking_fpga_sc->set_channel(channel); } void GalileoE5aDllPllTrackingFpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) { - //tracking_->set_gnss_synchro(p_gnss_synchro); tracking_fpga_sc->set_gnss_synchro(p_gnss_synchro); } @@ -276,13 +230,11 @@ void GalileoE5aDllPllTrackingFpga::disconnect(gr::top_block_sptr top_block) gr::basic_block_sptr GalileoE5aDllPllTrackingFpga::get_left_block() { - //return tracking_; return tracking_fpga_sc; } gr::basic_block_sptr GalileoE5aDllPllTrackingFpga::get_right_block() { - //return tracking_; return tracking_fpga_sc; } diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h index 49c52de5e..026069a51 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h @@ -1,19 +1,20 @@ /*! - * \file galileo_e5a_dll_pll_tracking.h + * \file galileo_e5a_dll_pll_tracking_fpga.h * \brief Adapts a code DLL + carrier PLL - * tracking block to a TrackingInterface for Galileo E5a signals + * tracking block to a TrackingInterface for Galileo E5a signals for the FPGA * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for - * Galileo E5a data and pilot Signals + * Galileo E5a data and pilot Signals for the FPGA * \author Marc Sales, 2014. marcsales92(at)gmail.com * \based on work from: *
    + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2011. jarribas(at)cttc.es *
  • Luis Esteve, 2012. luis(at)epsilon-formacion.com *
* * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -63,10 +64,10 @@ public: return role_; } - //! Returns "Galileo_E5a_DLL_PLL_Tracking" + //! Returns "Galileo_E5a_DLL_PLL_Tracking_Fpga" inline std::string implementation() override { - return "Galileo_E5a_DLL_PLL_Tracking"; + return "Galileo_E5a_DLL_PLL_Tracking_Fpga"; } inline size_t item_size() override @@ -99,14 +100,14 @@ public: private: dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; size_t item_size_; - unsigned int channel_; + uint32_t channel_; std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; + uint32_t in_streams_; + uint32_t out_streams_; - int* d_ca_codes; - int* d_data_codes; + int32_t* d_ca_codes; + int32_t* d_data_codes; bool d_track_pilot; }; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc index e81e7a905..10939dbe8 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.cc @@ -1,8 +1,8 @@ /*! * \file gps_l1_ca_dll_pll_tracking_fpga.cc * \brief Implementation of an adapter of a DLL+PLL tracking loop block - * for GPS L1 C/A to a TrackingInterface that uses the FPGA - * \author Marc Majoral, 2018, mmajoral(at)cttc.es + * for GPS L1 C/A to a TrackingInterface for the FPGA + * \author Marc Majoral, 2019, mmajoral(at)cttc.es * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Javier Arribas, 2011. jarribas(at)cttc.es * @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -60,10 +60,8 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - //std::string default_item_type = "gr_complex"; - //std::string item_type = configuration->property(role + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); + int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); trk_param_fpga.fs_in = fs_in; bool dump = configuration->property(role + ".dump", false); trk_param_fpga.dump = dump; @@ -86,9 +84,9 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( trk_param_fpga.early_late_space_chips = early_late_space_chips; float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.5); trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; - int vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); + int32_t vector_length = std::round(fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)); trk_param_fpga.vector_length = vector_length; - int symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); + int32_t symbols_extended_correlator = configuration->property(role + ".extend_correlation_symbols", 1); if (symbols_extended_correlator < 1) { symbols_extended_correlator = 1; @@ -115,13 +113,13 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( trk_param_fpga.system = 'G'; char sig_[3] = "1C"; std::memcpy(trk_param_fpga.signal, sig_, 3); - int cn0_samples = configuration->property(role + ".cn0_samples", 20); + int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20); if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; trk_param_fpga.cn0_samples = cn0_samples; - int cn0_min = configuration->property(role + ".cn0_min", 25); + int32_t cn0_min = configuration->property(role + ".cn0_min", 25); if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; trk_param_fpga.cn0_min = cn0_min; - int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50); if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; trk_param_fpga.max_lock_fail = max_lock_fail; double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); @@ -132,16 +130,15 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga( std::string default_device_name = "/dev/uio"; std::string device_name = configuration->property(role + ".devicename", default_device_name); trk_param_fpga.device_name = device_name; - unsigned int device_base = configuration->property(role + ".device_base", 1); + uint32_t device_base = configuration->property(role + ".device_base", 3); trk_param_fpga.device_base = device_base; - //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 0); trk_param_fpga.multicorr_type = 0; //multicorr_type : 0 -> 3 correlators, 1 -> 5 correlators //################# PRE-COMPUTE ALL THE CODES ################# - d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); - for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS * NUM_PRNs) * sizeof(int32_t), volk_gnsssdr_get_alignment())); + for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++) { - gps_l1_ca_code_gen_int(&d_ca_codes[(int(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0); + gps_l1_ca_code_gen_int(&d_ca_codes[(int32_t(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0); } trk_param_fpga.ca_codes = d_ca_codes; trk_param_fpga.code_length_chips = GPS_L1_CA_CODE_LENGTH_CHIPS; diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h index 5cc38f230..cd1b8415f 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h @@ -1,8 +1,8 @@ /*! * \file gps_l1_ca_dll_pll_tracking_fpga.h * \brief Interface of an adapter of a DLL+PLL tracking loop block - * for GPS L1 C/A to a TrackingInterface that uses the FPGA - * \author Marc Majoral, 2018. mmajoral(at)cttc.es + * for GPS L1 C/A to a TrackingInterface for the FPGA + * \author Marc Majoral, 2019, mmajoral(at)cttc.es * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com * Javier Arribas, 2011. jarribas(at)cttc.es * @@ -13,7 +13,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -101,11 +101,11 @@ public: private: dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; size_t item_size_; - unsigned int channel_; + uint32_t channel_; std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; - int* d_ca_codes; + uint32_t in_streams_; + uint32_t out_streams_; + int32_t* d_ca_codes; }; #endif // GNSS_SDR_GPS_L1_CA_DLL_PLL_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h index 7d36d1e74..e1a606f1f 100644 --- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h @@ -63,7 +63,7 @@ public: return role_; } - //! Returns "GPS_L2_M_DLL_PLL_Tracking" + //! Returns "GPS_L2_M_DLL_PLL_Tracking_Fpga" inline std::string implementation() override { return "GPS_L2_M_DLL_PLL_Tracking_Fpga"; diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc index c12009b43..764a69a97 100644 --- a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.cc @@ -2,6 +2,7 @@ * \file gps_l5_dll_pll_tracking.cc * \brief Interface of an adapter of a DLL+PLL tracking loop block * for GPS L5 to a TrackingInterface + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Javier Arribas, 2017. jarribas(at)cttc.es * * Code DLL + carrier PLL according to the algorithms described in: @@ -11,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -55,15 +56,11 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( ConfigurationInterface *configuration, const std::string &role, unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) { - //printf("L5 TRK CLASS CREATED\n"); - //dllpllconf_t trk_param; Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga(); DLOG(INFO) << "role " << role; //################# CONFIGURATION PARAMETERS ######################## - //std::string default_item_type = "gr_complex"; - //std::string item_type = configuration->property(role + ".item_type", default_item_type); - int fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000); - int fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); + int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12500000); + int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); trk_param_fpga.fs_in = fs_in; bool dump = configuration->property(role + ".dump", false); trk_param_fpga.dump = dump; @@ -84,9 +81,9 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz; float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5); trk_param_fpga.early_late_space_chips = early_late_space_chips; - int vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L5I_CODE_RATE_HZ) / static_cast(GPS_L5I_CODE_LENGTH_CHIPS))); + int32_t vector_length = std::round(static_cast(fs_in) / (static_cast(GPS_L5I_CODE_RATE_HZ) / static_cast(GPS_L5I_CODE_LENGTH_CHIPS))); trk_param_fpga.vector_length = vector_length; - int extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); + int32_t extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1); float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.15); trk_param_fpga.early_late_space_narrow_chips = early_late_space_narrow_chips; bool track_pilot = configuration->property(role + ".track_pilot", false); @@ -112,32 +109,30 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( trk_param_fpga.system = 'G'; char sig_[3] = "L5"; std::memcpy(trk_param_fpga.signal, sig_, 3); - int cn0_samples = configuration->property(role + ".cn0_samples", 20); + int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20); if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples; trk_param_fpga.cn0_samples = cn0_samples; - int cn0_min = configuration->property(role + ".cn0_min", 25); + int32_t cn0_min = configuration->property(role + ".cn0_min", 25); if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min; trk_param_fpga.cn0_min = cn0_min; - int max_lock_fail = configuration->property(role + ".max_lock_fail", 50); + int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50); if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail; trk_param_fpga.max_lock_fail = max_lock_fail; - double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85); + double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.75); if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th; trk_param_fpga.carrier_lock_th = carrier_lock_th; // FPGA configuration parameters + std::string default_device_name = "/dev/uio"; std::string device_name = configuration->property(role + ".devicename", default_device_name); trk_param_fpga.device_name = device_name; - unsigned int device_base = configuration->property(role + ".device_base", 1); + uint32_t device_base = configuration->property(role + ".device_base", 27); trk_param_fpga.device_base = device_base; - //unsigned int multicorr_type = configuration->property(role + ".multicorr_type", 0); trk_param_fpga.multicorr_type = 0; //multicorr_type : 0 -> 3 correlators, 1 -> 5 correlators - //################# PRE-COMPUTE ALL THE CODES ################# - unsigned int code_samples_per_chip = 1; - auto code_length_chips = static_cast(GPS_L5I_CODE_LENGTH_CHIPS); - //printf("TRK code_length_chips = %d\n", code_length_chips); + uint32_t code_samples_per_chip = 1; + auto code_length_chips = static_cast(GPS_L5I_CODE_LENGTH_CHIPS); float *tracking_code; float *data_code; @@ -149,42 +144,37 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( data_code = static_cast(volk_gnsssdr_malloc(code_length_chips * sizeof(float), volk_gnsssdr_get_alignment())); } - d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips * NUM_PRNs) * sizeof(int), volk_gnsssdr_get_alignment())); + d_ca_codes = static_cast(volk_gnsssdr_malloc(static_cast(code_length_chips * NUM_PRNs) * sizeof(int32_t), volk_gnsssdr_get_alignment())); if (trk_param_fpga.track_pilot) { - d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * NUM_PRNs * sizeof(int), volk_gnsssdr_get_alignment())); + d_data_codes = static_cast(volk_gnsssdr_malloc((static_cast(code_length_chips)) * NUM_PRNs * sizeof(int32_t), volk_gnsssdr_get_alignment())); } - //printf("start \n"); - for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++) + for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++) { - if (track_pilot) + if (trk_param_fpga.track_pilot) { gps_l5q_code_gen_float(tracking_code, PRN); gps_l5i_code_gen_float(data_code, PRN); - for (unsigned int s = 0; s < code_length_chips; s++) + for (uint32_t s = 0; s < code_length_chips; s++) { - d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); - d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); - //printf("%f %d | ", data_codes_f[s], d_data_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); + d_data_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); } } else { gps_l5i_code_gen_float(tracking_code, PRN); - for (unsigned int s = 0; s < code_length_chips; s++) + for (uint32_t s = 0; s < code_length_chips; s++) { - d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(data_code[s]); - //printf("%f %d | ", ca_codes_f[s], d_ca_codes[static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS)* 2 * (PRN - 1) + s]); + d_ca_codes[static_cast(code_length_chips) * (PRN - 1) + s] = static_cast(tracking_code[s]); } } } - //printf("end \n"); - delete[] tracking_code; if (trk_param_fpga.track_pilot) @@ -195,20 +185,7 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga( trk_param_fpga.data_codes = d_data_codes; trk_param_fpga.code_length_chips = code_length_chips; trk_param_fpga.code_samples_per_chip = code_samples_per_chip; // 2 sample per chip - //################# MAKE TRACKING GNURadio object ################### - // if (item_type.compare("gr_complex") == 0) - // { - // item_size_ = sizeof(gr_complex); - // tracking_ = dll_pll_veml_make_tracking(trk_param_fpga); - // } - // else - // { - // item_size_ = sizeof(gr_complex); - // LOG(WARNING) << item_type << " unknown tracking item type."; - // } - //printf("call \n"); tracking_fpga_sc = dll_pll_veml_make_tracking_fpga(trk_param_fpga); - //printf("end2 \n"); channel_ = 0; DLOG(INFO) << "tracking(" << tracking_fpga_sc->unique_id() << ")"; } diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h index 087f3730c..08c085d73 100644 --- a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h @@ -2,6 +2,7 @@ * \file gps_l5_dll_pll_tracking.h * \brief Interface of an adapter of a DLL+PLL tracking loop block * for GPS L5 to a TrackingInterface + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Javier Arribas, 2017. jarribas(at)cttc.es * * Code DLL + carrier PLL according to the algorithms described in: @@ -11,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -95,16 +96,15 @@ public: void stop_tracking() override; private: - //dll_pll_veml_tracking_sptr tracking_; dll_pll_veml_tracking_fpga_sptr tracking_fpga_sc; size_t item_size_; - unsigned int channel_; + uint32_t channel_; std::string role_; - unsigned int in_streams_; - unsigned int out_streams_; + uint32_t in_streams_; + uint32_t out_streams_; bool d_track_pilot; - int* d_ca_codes; - int* d_data_codes; + int32_t* d_ca_codes; + int32_t* d_data_codes; }; #endif // GNSS_SDR_GPS_L5_DLL_PLL_TRACKING_FPGA_H_ diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc index 62479aaae..f470913e7 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.cc @@ -1,9 +1,9 @@ /*! * \file dll_pll_veml_tracking_fpga.cc * \brief Implementation of a code DLL + carrier PLL tracking block using an FPGA - * \author Marc Majoral, 2018. marc.majoral(at)cttc.es - * Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com - * Javier Arribas, 2018. jarribas(at)cttc.es + * \author Marc Majoral, 2019. marc.majoral(at)cttc.es + * \author Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com + * \author Javier Arribas, 2018. jarribas(at)cttc.es * * Code DLL + carrier PLL according to the algorithms described in: * [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, @@ -12,7 +12,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -42,9 +42,13 @@ #include "Galileo_E1.h" #include "Galileo_E5a.h" #include "MATH_CONSTANTS.h" +#include "control_message_factory.h" +#include "galileo_e1_signal_processing.h" +#include "galileo_e5_signal_processing.h" #include "gnss_sdr_create_directory.h" #include "gps_l2c_signal.h" #include "gps_l5_signal.h" +#include "gps_sdr_signal_processing.h" #include "lock_detectors.h" #include "tracking_discriminators.h" #include @@ -56,9 +60,9 @@ #include #include #include +#include #include - using google::LogMessage; dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_) @@ -81,10 +85,10 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & // initialize internal vars d_veml = false; d_cloop = true; - d_synchonizing = false; d_code_chip_rate = 0.0; - d_secondary_code_length = 0; + d_secondary_code_length = 0U; d_secondary_code_string = nullptr; + d_gps_l1ca_preambles_symbols = nullptr; signal_type = std::string(trk_parameters.signal); std::map map_signal_pretty_name; @@ -98,7 +102,8 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & signal_pretty_name = map_signal_pretty_name[signal_type]; - d_prompt_data_shift = nullptr; + d_code_samples_per_chip = trk_parameters.code_samples_per_chip; // number of samples per chip + d_code_length_chips = trk_parameters.code_length_chips; if (trk_parameters.system == 'G') { @@ -110,14 +115,11 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_code_chip_rate = GPS_L1_CA_CODE_RATE_HZ; d_symbols_per_bit = GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; d_correlation_length_ms = 1; - //d_code_samples_per_chip = 1; - //d_code_length_chips = static_cast(GPS_L1_CA_CODE_LENGTH_CHIPS); // GPS L1 C/A does not have pilot component nor secondary code d_secondary = false; trk_parameters.track_pilot = false; interchange_iq = false; - // set the preamble uint16_t preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE; @@ -147,10 +149,8 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_signal_carrier_freq = GPS_L2_FREQ_HZ; d_code_period = GPS_L2_M_PERIOD; d_code_chip_rate = GPS_L2_M_CODE_RATE_HZ; - //d_code_length_chips = static_cast(GPS_L2_M_CODE_LENGTH_CHIPS); d_symbols_per_bit = GPS_L2_SAMPLES_PER_SYMBOL; d_correlation_length_ms = 20; - //d_code_samples_per_chip = 1; // GPS L2 does not have pilot component nor secondary code d_secondary = false; trk_parameters.track_pilot = false; @@ -163,10 +163,7 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_code_chip_rate = GPS_L5I_CODE_RATE_HZ; d_symbols_per_bit = GPS_L5_SAMPLES_PER_SYMBOL; d_correlation_length_ms = 1; - //d_code_samples_per_chip = 1; - //d_code_length_chips = static_cast(GPS_L5i_CODE_LENGTH_CHIPS); d_secondary = true; - // interchange_iq = false; if (trk_parameters.track_pilot) { d_secondary_code_length = static_cast(GPS_L5Q_NH_CODE_LENGTH); @@ -191,8 +188,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & interchange_iq = false; d_signal_carrier_freq = 0.0; d_code_period = 0.0; - //d_code_length_chips = 0; - //d_code_samples_per_chip = 0; d_symbols_per_bit = 0; } } @@ -204,10 +199,8 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_signal_carrier_freq = GALILEO_E1_FREQ_HZ; d_code_period = GALILEO_E1_CODE_PERIOD; d_code_chip_rate = GALILEO_E1_CODE_CHIP_RATE_HZ; - //d_code_length_chips = static_cast(Galileo_E1_B_CODE_LENGTH_CHIPS); d_symbols_per_bit = 1; d_correlation_length_ms = 4; - //d_code_samples_per_chip = 2; // CBOC disabled: 2 samples per chip. CBOC enabled: 12 samples per chip d_veml = true; if (trk_parameters.track_pilot) { @@ -230,20 +223,18 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_code_chip_rate = GALILEO_E5A_CODE_CHIP_RATE_HZ; d_symbols_per_bit = 20; d_correlation_length_ms = 1; - //d_code_samples_per_chip = 1; - //d_code_length_chips = static_cast(Galileo_E5a_CODE_LENGTH_CHIPS); - d_secondary = true; - //interchange_iq = false; + if (trk_parameters.track_pilot) { + d_secondary = true; d_secondary_code_length = static_cast(GALILEO_E5A_Q_SECONDARY_CODE_LENGTH); signal_pretty_name = signal_pretty_name + "Q"; interchange_iq = true; } else { - d_secondary_code_length = static_cast(GALILEO_E5A_I_SECONDARY_CODE_LENGTH); - d_secondary_code_string = const_cast(&GALILEO_E5A_I_SECONDARY_CODE); + //Do not acquire secondary code in data component. It is done in telemetry decoder + d_secondary = false; signal_pretty_name = signal_pretty_name + "I"; interchange_iq = false; } @@ -257,8 +248,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & interchange_iq = false; d_signal_carrier_freq = 0.0; d_code_period = 0.0; - //d_code_length_chips = 0; - //d_code_samples_per_chip = 0; d_symbols_per_bit = 0; } } @@ -271,8 +260,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & interchange_iq = false; d_signal_carrier_freq = 0.0; d_code_period = 0.0; - //d_code_length_chips = 0; - //d_code_samples_per_chip = 0; d_symbols_per_bit = 0; } T_chip_seconds = 0.0; @@ -281,10 +268,10 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & K_blk_samples = 0.0; // Initialize tracking ========================================== + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); d_code_loop_filter = Tracking_2nd_DLL_filter(static_cast(d_code_period)); d_carrier_loop_filter = Tracking_2nd_PLL_filter(static_cast(d_code_period)); - d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); - d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); if (d_veml) { @@ -299,9 +286,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_correlator_outs = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment())); d_local_code_shift_chips = static_cast(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment())); - //std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); - - d_code_samples_per_chip = trk_parameters.code_samples_per_chip; // number of samples per chip // map memory pointers of correlator outputs if (d_veml) @@ -311,11 +295,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_Prompt = &d_correlator_outs[2]; d_Late = &d_correlator_outs[3]; d_Very_Late = &d_correlator_outs[4]; - // printf("aaaa very early %f\n",-trk_parameters.very_early_late_space_chips); - // printf("aaaa early %f\n",-trk_parameters.early_late_space_chips); - // printf("aaaa normal %f\n",0); - // printf("aaaa late %f\n",trk_parameters.early_late_space_chips); - // printf("aaaa very late %f\n",trk_parameters.very_early_late_space_chips); d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast(d_code_samples_per_chip); d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); d_local_code_shift_chips[2] = 0.0; @@ -330,16 +309,13 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_Prompt = &d_correlator_outs[1]; d_Late = &d_correlator_outs[2]; d_Very_Late = nullptr; - // printf("aaaa early %f\n",-trk_parameters.early_late_space_chips); - // printf("aaaa normal %f\n",0); - // printf("aaaa late %f\n",trk_parameters.early_late_space_chips); - d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); d_local_code_shift_chips[1] = 0.0; d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); d_prompt_data_shift = &d_local_code_shift_chips[1]; } + if (trk_parameters.extend_correlation_symbols > 1) { d_enable_extended_integration = true; @@ -350,19 +326,7 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & trk_parameters.extend_correlation_symbols = 1; } - // Enable Data component prompt correlator (slave to Pilot prompt) if tracking uses Pilot signal - if (trk_parameters.track_pilot) - { - // Extra correlator for the data component - //d_Prompt_Data = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); - //d_Prompt_Data[0] = gr_complex(0.0, 0.0); - } - else - { - //d_Prompt_Data = nullptr; - } - - //--- Initializations ---// + // --- Initializations --- // Initial code frequency basis of NCO d_code_freq_chips = d_code_chip_rate; // Residual code phase (in chips) @@ -388,8 +352,6 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_carrier_lock_threshold = trk_parameters.carrier_lock_th; d_Prompt_Data = static_cast(volk_gnsssdr_malloc(sizeof(gr_complex), volk_gnsssdr_get_alignment())); - //clear_tracking_vars(); - d_acquisition_gnss_synchro = nullptr; d_channel = 0; d_acq_code_phase_samples = 0.0; @@ -399,28 +361,24 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & d_extend_correlation_symbols_count = 0; d_code_phase_step_chips = 0.0; + d_code_phase_rate_step_chips = 0.0; d_carrier_phase_step_rad = 0.0; + d_carrier_phase_rate_step_rad = 0.0; d_rem_code_phase_chips = 0.0; - d_K_blk_samples = 0.0; - d_code_phase_samples = 0.0; d_last_prompt = gr_complex(0.0, 0.0); d_state = 0; // initial state: standby clear_tracking_vars(); - //printf("hhhhhhhhhhh d_n_correlator_taps = %d\n", d_n_correlator_taps); - - // create multicorrelator class - std::string device_name = trk_parameters.device_name; - uint32_t device_base = trk_parameters.device_base; - int32_t *ca_codes = trk_parameters.ca_codes; - int32_t *data_codes = trk_parameters.data_codes; - //uint32_t code_length = trk_parameters.code_length_chips; - d_code_length_chips = trk_parameters.code_length_chips; - uint32_t multicorr_type = trk_parameters.multicorr_type; - multicorrelator_fpga = std::make_shared(d_n_correlator_taps, device_name, device_base, ca_codes, data_codes, d_code_length_chips, trk_parameters.track_pilot, multicorr_type, d_code_samples_per_chip); - multicorrelator_fpga->set_output_vectors(d_correlator_outs, d_Prompt_Data); - - d_pull_in = 0; + if (trk_parameters.smoother_length > 0) + { + d_carr_ph_history.resize(trk_parameters.smoother_length * 2); + d_code_ph_history.resize(trk_parameters.smoother_length * 2); + } + else + { + d_carr_ph_history.resize(1); + d_code_ph_history.resize(1); + } d_dump = trk_parameters.dump; d_dump_mat = trk_parameters.dump_mat and d_dump; @@ -428,6 +386,7 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & { d_dump_filename = trk_parameters.dump_filename; std::string dump_path; + // Get path if (d_dump_filename.find_last_of('/') != std::string::npos) { std::string dump_filename_ = d_dump_filename.substr(d_dump_filename.find_last_of('/') + 1); @@ -449,14 +408,21 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga & } d_dump_filename = dump_path + boost::filesystem::path::preferred_separator + d_dump_filename; - // create directory if (!gnss_sdr_create_directory(dump_path)) { std::cerr << "GNSS-SDR cannot create dump files for the tracking block. Wrong permissions?" << std::endl; d_dump = false; - }; + } } + // create multicorrelator class + std::string device_name = trk_parameters.device_name; + uint32_t device_base = trk_parameters.device_base; + int32_t *ca_codes = trk_parameters.ca_codes; + int32_t *data_codes = trk_parameters.data_codes; + uint32_t multicorr_type = trk_parameters.multicorr_type; + multicorrelator_fpga = std::make_shared(d_n_correlator_taps, device_name, device_base, ca_codes, data_codes, d_code_length_chips, trk_parameters.track_pilot, multicorr_type, d_code_samples_per_chip); + multicorrelator_fpga->set_output_vectors(d_correlator_outs, d_Prompt_Data); } @@ -467,70 +433,27 @@ void dll_pll_veml_tracking_fpga::start_tracking() d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz; d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples; - double acq_trk_diff_seconds = 0; // when using the FPGA we don't use the global sample counter - // Doppler effect Fd = (C / (C + Vr)) * F - double radial_velocity = (d_signal_carrier_freq + d_acq_carrier_doppler_hz) / d_signal_carrier_freq; - // new chip and PRN sequence periods based on acq Doppler - d_code_freq_chips = radial_velocity * d_code_chip_rate; - d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; - - double T_chip_mod_seconds = 1.0 / d_code_freq_chips; - double T_prn_mod_seconds = T_chip_mod_seconds * static_cast(d_code_length_chips); - double T_prn_mod_samples = T_prn_mod_seconds * trk_parameters.fs_in; - - //d_current_prn_length_samples = std::round(T_prn_mod_samples); - d_current_prn_length_samples = std::floor(T_prn_mod_samples); - d_next_prn_length_samples = d_current_prn_length_samples; - double T_prn_true_seconds = static_cast(d_code_length_chips) / d_code_chip_rate; - double T_prn_true_samples = T_prn_true_seconds * trk_parameters.fs_in; - double T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds; - double N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds; - double corrected_acq_phase_samples = std::fmod(d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * trk_parameters.fs_in, T_prn_true_samples); - if (corrected_acq_phase_samples < 0.0) - { - corrected_acq_phase_samples += T_prn_mod_samples; - } - double delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples; - - d_acq_code_phase_samples = corrected_acq_phase_samples; - d_carrier_doppler_hz = d_acq_carrier_doppler_hz; d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; - + d_carrier_phase_rate_step_rad = 0.0; + d_carr_ph_history.clear(); + d_code_ph_history.clear(); // DLL/PLL filter initialization d_carrier_loop_filter.initialize(); // initialize the carrier filter d_code_loop_filter.initialize(); // initialize the code filter - if (systemName == "GPS" and signal_type == "1C") - { - // nothing to compute : the local codes are pre-computed in the adapter class - } - else if (systemName == "GPS" and signal_type == "2S") - { - // nothing to compute : the local codes are pre-computed in the adapter class - } - else if (systemName == "GPS" and signal_type == "L5") + if (systemName == "GPS" and signal_type == "L5") { if (trk_parameters.track_pilot) { d_Prompt_Data[0] = gr_complex(0.0, 0.0); } - else - { - // nothing to compute : the local codes are pre-computed in the adapter class - } } else if (systemName == "Galileo" and signal_type == "1B") { if (trk_parameters.track_pilot) { - //char pilot_signal[3] = "1C"; d_Prompt_Data[0] = gr_complex(0.0, 0.0); - // MISSING _: set_local_code_and_taps for the data correlator - } - else - { - // nothing to compute : the local codes are pre-computed in the adapter class } } else if (systemName == "Galileo" and signal_type == "5X") @@ -538,19 +461,8 @@ void dll_pll_veml_tracking_fpga::start_tracking() if (trk_parameters.track_pilot) { d_secondary_code_string = const_cast(&GALILEO_E5A_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1]); - for (uint32_t i = 0; i < d_code_length_chips; i++) - { - // nothing to compute : the local codes are pre-computed in the adapter class - } d_Prompt_Data[0] = gr_complex(0.0, 0.0); } - else - { - for (uint32_t i = 0; i < d_code_length_chips; i++) - { - // nothing to compute : the local codes are pre-computed in the adapter class - } - } } std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); @@ -577,7 +489,6 @@ void dll_pll_veml_tracking_fpga::start_tracking() d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast(d_code_samples_per_chip); } - d_code_phase_samples = d_acq_code_phase_samples; d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz); d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz); d_carrier_loop_filter.set_pdi(static_cast(d_code_period)); @@ -585,20 +496,15 @@ void dll_pll_veml_tracking_fpga::start_tracking() // DEBUG OUTPUT std::cout << "Tracking of " << systemName << " " << signal_pretty_name << " signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; - LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; + DLOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel; - d_synchonizing = false; + + multicorrelator_fpga->set_local_code_and_taps(d_local_code_shift_chips, d_prompt_data_shift, d_acquisition_gnss_synchro->PRN); + // enable tracking pull-in + d_state = 1; d_cloop = true; d_Prompt_buffer_deque.clear(); d_last_prompt = gr_complex(0.0, 0.0); - LOG(INFO) << "PULL-IN Doppler [Hz] = " << d_carrier_doppler_hz - << ". Code Phase correction [samples] = " << delay_correction_samples - << ". PULL-IN Code Phase [samples] = " << d_acq_code_phase_samples; - //multicorrelator_fpga->set_local_code_and_taps(d_code_length_chips, d_local_code_shift_chips, d_acquisition_gnss_synchro->PRN); - multicorrelator_fpga->set_local_code_and_taps(d_local_code_shift_chips, d_prompt_data_shift, d_acquisition_gnss_synchro->PRN); - d_pull_in = 1; - // enable tracking pull-in and d_state at the end to avoid general work from starting pull-in before the start tracking function is finished - d_state = 1; } @@ -636,10 +542,6 @@ dll_pll_veml_tracking_fpga::~dll_pll_veml_tracking_fpga() volk_gnsssdr_free(d_local_code_shift_chips); volk_gnsssdr_free(d_correlator_outs); volk_gnsssdr_free(d_Prompt_Data); - // if (trk_parameters.track_pilot) - // { - // volk_gnsssdr_free(d_Prompt_Data); - // } delete[] d_Prompt_buffer; multicorrelator_fpga->free(); } @@ -680,7 +582,6 @@ bool dll_pll_veml_tracking_fpga::acquire_secondary() } } - // if (abs(corr_value) == d_secondary_code_length) if (abs(corr_value) == static_cast(d_secondary_code_length)) { return true; @@ -694,8 +595,8 @@ bool dll_pll_veml_tracking_fpga::acquire_secondary() bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integration_time_s) { - //printf("kkkkkkkkkkkkk d_cn0_estimation_counter = %d\n", d_cn0_estimation_counter); // ####### CN0 ESTIMATION AND LOCK DETECTORS ###### + if (d_cn0_estimation_counter < trk_parameters.cn0_samples) { // fill buffer with prompt correlator output values @@ -705,7 +606,6 @@ bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integra } else { - //printf("KKKKKKKKKKK checking count fail ...\n"); d_cn0_estimation_counter = 0; // Code lock indicator d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, trk_parameters.cn0_samples, coh_integration_time_s); @@ -737,6 +637,26 @@ bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integra } +// correlation requires: +// - updated remnant carrier phase in radians (rem_carr_phase_rad) +// - updated remnant code phase in samples (d_rem_code_phase_samples) +// - d_code_freq_chips +// - d_carrier_doppler_hz +//void dll_pll_veml_tracking_fpga::do_correlation_step(const gr_complex *input_samples) +void dll_pll_veml_tracking_fpga::do_correlation_step(void) +{ + // // ################# CARRIER WIPEOFF AND CORRELATORS ############################## + + multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( + d_rem_carr_phase_rad, + d_carrier_phase_step_rad, d_carrier_phase_rate_step_rad, + static_cast(d_rem_code_phase_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_step_chips) * static_cast(d_code_samples_per_chip), + static_cast(d_code_phase_rate_step_chips) * static_cast(d_code_samples_per_chip), + d_current_prn_length_samples); +} + + void dll_pll_veml_tracking_fpga::run_dll_pll() { // ################## PLL ########################################################## @@ -756,8 +676,7 @@ void dll_pll_veml_tracking_fpga::run_dll_pll() d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(d_carr_error_hz); // New carrier Doppler frequency estimation d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_carr_error_filt_hz; - // New code Doppler frequency estimation - d_code_freq_chips = (1.0 + (d_carrier_doppler_hz / d_signal_carrier_freq)) * d_code_chip_rate; + // ################## DLL ########################################################## // DLL discriminator @@ -771,13 +690,15 @@ void dll_pll_veml_tracking_fpga::run_dll_pll() } // Code discriminator filter d_code_error_filt_chips = d_code_loop_filter.get_code_nco(d_code_error_chips); // [chips/second] + + // New code Doppler frequency estimation + d_code_freq_chips = (1.0 + (d_carrier_doppler_hz / d_signal_carrier_freq)) * d_code_chip_rate - d_code_error_filt_chips; } void dll_pll_veml_tracking_fpga::clear_tracking_vars() { std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0)); - //if (trk_parameters.track_pilot) *d_Prompt_Data = gr_complex(0.0, 0.0); if (trk_parameters.track_pilot) d_Prompt_Data[0] = gr_complex(0.0, 0.0); d_carr_error_hz = 0.0; d_carr_error_filt_hz = 0.0; @@ -786,6 +707,10 @@ void dll_pll_veml_tracking_fpga::clear_tracking_vars() d_current_symbol = 0; d_Prompt_buffer_deque.clear(); d_last_prompt = gr_complex(0.0, 0.0); + d_carrier_phase_rate_step_rad = 0.0; + d_code_phase_rate_step_chips = 0.0; + d_carr_ph_history.clear(); + d_code_ph_history.clear(); } @@ -793,35 +718,70 @@ void dll_pll_veml_tracking_fpga::update_tracking_vars() { T_chip_seconds = 1.0 / d_code_freq_chips; T_prn_seconds = T_chip_seconds * static_cast(d_code_length_chips); - double code_error_filt_secs = T_prn_seconds * d_code_error_filt_chips * T_chip_seconds; //[seconds] // ################## CARRIER AND CODE NCO BUFFER ALIGNMENT ####################### // keep alignment parameters for the next input buffer // Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation T_prn_samples = T_prn_seconds * trk_parameters.fs_in; - K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * trk_parameters.fs_in; - //d_next_prn_length_samples = round(K_blk_samples); + K_blk_samples = T_prn_samples + d_rem_code_phase_samples; d_next_prn_length_samples = static_cast(std::floor(K_blk_samples)); // round to a discrete number of samples //################### PLL COMMANDS ################################################# // carrier phase step (NCO phase increment per sample) [rads/sample] d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in; + // carrier phase rate step (NCO phase increment rate per sample) [rads/sample^2] + if (trk_parameters.high_dyn) + { + d_carr_ph_history.push_back(std::pair(d_carrier_phase_step_rad, static_cast(d_current_prn_length_samples))); + if (d_carr_ph_history.full()) + { + double tmp_cp1 = 0.0; + double tmp_cp2 = 0.0; + double tmp_samples = 0.0; + for (uint32_t k = 0; k < trk_parameters.smoother_length; k++) + { + tmp_cp1 += d_carr_ph_history.at(k).first; + tmp_cp2 += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first; + tmp_samples += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second; + } + tmp_cp1 /= static_cast(trk_parameters.smoother_length); + tmp_cp2 /= static_cast(trk_parameters.smoother_length); + d_carrier_phase_rate_step_rad = (tmp_cp2 - tmp_cp1) / tmp_samples; + } + } // remnant carrier phase to prevent overflow in the code NCO - d_rem_carr_phase_rad += d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + d_rem_carr_phase_rad += static_cast(d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast(d_current_prn_length_samples) * static_cast(d_current_prn_length_samples)); d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, PI_2); + + // carrier phase accumulator - d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples); + d_acc_carrier_phase_rad -= (d_carrier_phase_step_rad * static_cast(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast(d_current_prn_length_samples) * static_cast(d_current_prn_length_samples)); //################### DLL COMMANDS ################################################# // code phase step (Code resampler phase increment per sample) [chips/sample] d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + if (trk_parameters.high_dyn) + { + d_code_ph_history.push_back(std::pair(d_code_phase_step_chips, static_cast(d_current_prn_length_samples))); + if (d_code_ph_history.full()) + { + double tmp_cp1 = 0.0; + double tmp_cp2 = 0.0; + double tmp_samples = 0.0; + for (uint32_t k = 0; k < trk_parameters.smoother_length; k++) + { + tmp_cp1 += d_code_ph_history.at(k).first; + tmp_cp2 += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first; + tmp_samples += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second; + } + tmp_cp1 /= static_cast(trk_parameters.smoother_length); + tmp_cp2 /= static_cast(trk_parameters.smoother_length); + d_code_phase_rate_step_chips = (tmp_cp2 - tmp_cp1) / tmp_samples; + } + } // remnant code phase [chips] d_rem_code_phase_samples = K_blk_samples - static_cast(d_current_prn_length_samples); // rounding error < 1 sample d_rem_code_phase_chips = d_code_freq_chips * d_rem_code_phase_samples / trk_parameters.fs_in; - //printf("lll d_code_freq_chips = %f\n", d_code_freq_chips); - //printf("lll d_rem_code_phase_samples = %f\n", d_rem_code_phase_samples); - //printf("lll trk_parameters.fs_in = %f\n", trk_parameters.fs_in); - //printf("lll d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); } @@ -961,8 +921,14 @@ void dll_pll_veml_tracking_fpga::log_data(bool integrating) // carrier and code frequency tmp_float = d_carrier_doppler_hz; d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // carrier phase rate [Hz/s] + tmp_float = d_carrier_phase_rate_step_rad * trk_parameters.fs_in * trk_parameters.fs_in / PI_2; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); tmp_float = d_code_freq_chips; d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); + // code phase rate [chips/s^2] + tmp_float = d_code_phase_rate_step_chips * trk_parameters.fs_in * trk_parameters.fs_in; + d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); // PLL commands tmp_float = d_carr_error_hz; d_dump_file.write(reinterpret_cast(&tmp_float), sizeof(float)); @@ -1000,7 +966,7 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() // READ DUMP FILE std::ifstream::pos_type size; int32_t number_of_double_vars = 1; - int32_t number_of_float_vars = 17; + int32_t number_of_float_vars = 19; int32_t epoch_size_bytes = sizeof(uint64_t) + sizeof(double) * number_of_double_vars + sizeof(float) * number_of_float_vars + sizeof(uint32_t); std::ifstream dump_file; @@ -1042,7 +1008,9 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() auto *PRN_start_sample_count = new uint64_t[num_epoch]; auto *acc_carrier_phase_rad = new float[num_epoch]; auto *carrier_doppler_hz = new float[num_epoch]; + auto *carrier_doppler_rate_hz = new float[num_epoch]; auto *code_freq_chips = new float[num_epoch]; + auto *code_freq_rate_chips = new float[num_epoch]; auto *carr_error_hz = new float[num_epoch]; auto *carr_error_filt_hz = new float[num_epoch]; auto *code_error_chips = new float[num_epoch]; @@ -1053,6 +1021,7 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() auto *aux2 = new double[num_epoch]; auto *PRN = new uint32_t[num_epoch]; + try { if (dump_file.is_open()) @@ -1069,7 +1038,9 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() dump_file.read(reinterpret_cast(&PRN_start_sample_count[i]), sizeof(uint64_t)); dump_file.read(reinterpret_cast(&acc_carrier_phase_rad[i]), sizeof(float)); dump_file.read(reinterpret_cast(&carrier_doppler_hz[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&carrier_doppler_rate_hz[i]), sizeof(float)); dump_file.read(reinterpret_cast(&code_freq_chips[i]), sizeof(float)); + dump_file.read(reinterpret_cast(&code_freq_rate_chips[i]), sizeof(float)); dump_file.read(reinterpret_cast(&carr_error_hz[i]), sizeof(float)); dump_file.read(reinterpret_cast(&carr_error_filt_hz[i]), sizeof(float)); dump_file.read(reinterpret_cast(&code_error_chips[i]), sizeof(float)); @@ -1096,7 +1067,9 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() delete[] PRN_start_sample_count; delete[] acc_carrier_phase_rad; delete[] carrier_doppler_hz; + delete[] carrier_doppler_rate_hz; delete[] code_freq_chips; + delete[] code_freq_rate_chips; delete[] carr_error_hz; delete[] carr_error_filt_hz; delete[] code_error_chips; @@ -1159,10 +1132,18 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE Mat_VarFree(matvar); + matvar = Mat_VarCreate("carrier_doppler_rate_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carrier_doppler_rate_hz, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + matvar = Mat_VarCreate("code_freq_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_chips, 0); Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE Mat_VarFree(matvar); + matvar = Mat_VarCreate("code_freq_rate_chips", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, code_freq_rate_chips, 0); + Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE + Mat_VarFree(matvar); + matvar = Mat_VarCreate("carr_error_hz", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, carr_error_hz, 0); Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE Mat_VarFree(matvar); @@ -1210,7 +1191,9 @@ int32_t dll_pll_veml_tracking_fpga::save_matfile() delete[] PRN_start_sample_count; delete[] acc_carrier_phase_rad; delete[] carrier_doppler_hz; + delete[] carrier_doppler_rate_hz; delete[] code_freq_chips; + delete[] code_freq_rate_chips; delete[] carr_error_hz; delete[] carr_error_filt_hz; delete[] code_error_chips; @@ -1260,276 +1243,100 @@ void dll_pll_veml_tracking_fpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro) d_acquisition_gnss_synchro = p_gnss_synchro; } + void dll_pll_veml_tracking_fpga::stop_tracking() { - gr::thread::scoped_lock l(d_setlock); d_state = 0; } -int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), +int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { - gr::thread::scoped_lock l(d_setlock); - // Block input data and block output stream pointers auto **out = reinterpret_cast(&output_items[0]); - - // GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder Gnss_Synchro current_synchro_data = Gnss_Synchro(); d_current_prn_length_samples = d_next_prn_length_samples; - current_synchro_data = *d_acquisition_gnss_synchro; + switch (d_state) { case 0: // Standby - Consume samples at full throttle, do nothing { - for (int32_t n = 0; n < d_n_correlator_taps; n++) - { - d_correlator_outs[n] = gr_complex(0, 0); - } - - current_synchro_data.Tracking_sample_counter = 0ULL; // in order to reduce computational workload do not read the sample counter until we start tracking d_sample_counter + d_current_prn_length_samples; - current_synchro_data.System = {'G'}; - current_synchro_data.correlation_length_ms = 1; + return 0; break; } - case 1: // Standby - Consume samples at full throttle, do nothing + case 1: // Pull-in { - d_pull_in = 0; + int64_t acq_trk_diff_samples; + double acq_trk_diff_seconds; + double delta_trk_to_acq_prn_start_samples; + multicorrelator_fpga->lock_channel(); uint64_t counter_value = multicorrelator_fpga->read_sample_counter(); - //printf("333333 counter_value = %llu\n", counter_value); - //printf("333333 current_synchro_data.Acq_samplestamp_samples = %d\n", current_synchro_data.Acq_samplestamp_samples); - //printf("333333 current_synchro_data.Acq_delay_samples = %f\n", current_synchro_data.Acq_delay_samples); - //printf("333333 d_correlation_length_samples = %d\n", d_correlation_length_samples); - uint32_t num_frames = ceil((counter_value - current_synchro_data.Acq_samplestamp_samples - current_synchro_data.Acq_delay_samples) / d_correlation_length_samples); - //printf("333333 num_frames = %d\n", num_frames); - auto absolute_samples_offset = static_cast(current_synchro_data.Acq_delay_samples + current_synchro_data.Acq_samplestamp_samples + num_frames * d_correlation_length_samples); - //printf("333333 absolute_samples_offset = %llu\n", absolute_samples_offset); + uint64_t absolute_samples_offset; + if (counter_value > (d_acq_sample_stamp + d_acq_code_phase_samples)) + { + // Signal alignment (skip samples until the incoming signal is aligned with local replica) + acq_trk_diff_samples = static_cast(counter_value) - static_cast(d_acq_sample_stamp); + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / trk_parameters.fs_in; + delta_trk_to_acq_prn_start_samples = static_cast(acq_trk_diff_samples) - d_acq_code_phase_samples; + + uint32_t num_frames = ceil((delta_trk_to_acq_prn_start_samples) / d_correlation_length_samples); + absolute_samples_offset = static_cast(d_acq_code_phase_samples + d_acq_sample_stamp + num_frames * d_correlation_length_samples); + } + else + { + // test mode + + acq_trk_diff_samples = -static_cast(counter_value) + static_cast(d_acq_sample_stamp); + acq_trk_diff_seconds = static_cast(acq_trk_diff_samples) / trk_parameters.fs_in; + delta_trk_to_acq_prn_start_samples = static_cast(acq_trk_diff_samples) + d_acq_code_phase_samples; + + absolute_samples_offset = static_cast(delta_trk_to_acq_prn_start_samples); + } multicorrelator_fpga->set_initial_sample(absolute_samples_offset); d_absolute_samples_offset = absolute_samples_offset; d_sample_counter = absolute_samples_offset; current_synchro_data.Tracking_sample_counter = absolute_samples_offset; d_sample_counter_next = d_sample_counter; + + + // Signal alignment (skip samples until the incoming signal is aligned with local replica) + + // Doppler effect Fd = (C / (C + Vr)) * F + double radial_velocity = (d_signal_carrier_freq + d_acq_carrier_doppler_hz) / d_signal_carrier_freq; + // new chip and PRN sequence periods based on acq Doppler + d_code_freq_chips = radial_velocity * d_code_chip_rate; + d_code_phase_step_chips = d_code_freq_chips / trk_parameters.fs_in; + d_code_phase_rate_step_chips = 0.0; + double T_chip_mod_seconds = 1.0 / d_code_freq_chips; + double T_prn_mod_seconds = T_chip_mod_seconds * static_cast(d_code_length_chips); + double T_prn_mod_samples = T_prn_mod_seconds * trk_parameters.fs_in; + + d_acq_code_phase_samples = absolute_samples_offset; + + d_current_prn_length_samples = round(T_prn_mod_samples); + + d_next_prn_length_samples = d_current_prn_length_samples; + int32_t samples_offset = round(d_acq_code_phase_samples); + d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast(samples_offset); d_state = 2; - return 0; + + DLOG(INFO) << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples << " ( " << acq_trk_diff_seconds << " s)"; + DLOG(INFO) << "PULL-IN Doppler [Hz] = " << d_carrier_doppler_hz + << ". PULL-IN Code Phase [samples] = " << d_acq_code_phase_samples; + + // don't leave the HW module blocking the signal path before the first sample arrives + // start the first tracking process + run_state_2(current_synchro_data); break; } - - case 2: + case 2: // Wide tracking and symbol synchronization { - d_sample_counter = d_sample_counter_next; - d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); - - // ################# CARRIER WIPEOFF AND CORRELATORS ############################## - // perform carrier wipe-off and compute Early, Prompt and Late correlation - multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, d_carrier_phase_step_rad, - d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), - d_current_prn_length_samples); - - // Save single correlation step variables - if (d_veml) - { - d_VE_accu = *d_Very_Early; - d_VL_accu = *d_Very_Late; - } - d_E_accu = *d_Early; - d_P_accu = *d_Prompt; - d_L_accu = *d_Late; - - if (!cn0_and_tracking_lock_status(d_code_period)) - { - clear_tracking_vars(); - d_state = 0; // loss-of-lock detected - } - else - { - bool next_state = false; - // Perform DLL/PLL tracking loop computations. Costas Loop enabled - run_dll_pll(); - update_tracking_vars(); - - // enable write dump file this cycle (valid DLL/PLL cycle) - log_data(false); - if (d_secondary) - { - // ####### SECONDARY CODE LOCK ##### - d_Prompt_buffer_deque.push_back(*d_Prompt); - if (d_Prompt_buffer_deque.size() == d_secondary_code_length) - { - next_state = acquire_secondary(); - if (next_state) - { - std::cout << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel - << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; - } - - d_Prompt_buffer_deque.pop_front(); - } - } - else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change - { - // if (d_synchonizing) - // { - // if (d_Prompt->real() * d_last_prompt.real() > 0.0) - // { - // d_current_symbol++; - // } - // else if (d_current_symbol > d_symbols_per_bit) - // { - // d_synchonizing = false; - // d_current_symbol = 1; - // } - // else - // { - // d_current_symbol = 1; - // d_last_prompt = *d_Prompt; - // } - // } - // else if (d_last_prompt.real() != 0.0) - // { - // d_current_symbol++; - // if (d_current_symbol == d_symbols_per_bit) next_state = true; - // } - // else - // { - // d_last_prompt = *d_Prompt; - // d_synchonizing = true; - // d_current_symbol = 1; - // } - // } - //=========================================================================================================== - //float current_tracking_time_s = static_cast(d_sample_counter - d_acq_sample_stamp) / trk_parameters.fs_in; - float current_tracking_time_s = static_cast(d_sample_counter - d_absolute_samples_offset) / trk_parameters.fs_in; - if (current_tracking_time_s > 10) - { - d_symbol_history.push_back(d_Prompt->real()); - //******* preamble correlation ******** - int32_t corr_value = 0; - if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync)) - { - for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) - { - if (d_symbol_history.at(i) < 0) // symbols clipping - { - corr_value -= d_gps_l1ca_preambles_symbols[i]; - } - else - { - corr_value += d_gps_l1ca_preambles_symbols[i]; - } - } - } - if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) - { - //std::cout << "Preamble detected at tracking!" << std::endl; - next_state = true; - } - else - { - next_state = false; - } - } - else - { - next_state = false; - } - } - else - { - next_state = true; - } - - // ########### Output the tracking results to Telemetry block ########## - if (interchange_iq) - { - if (trk_parameters.track_pilot) - { - // Note that data and pilot components are in quadrature. I and Q are interchanged - current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); - current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); - } - else - { - current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); - current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); - } - } - else - { - if (trk_parameters.track_pilot) - { - // Note that data and pilot components are in quadrature. I and Q are interchanged - current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); - current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); - } - else - { - current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); - current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); - } - } - current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; - current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; - current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; - current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; - current_synchro_data.Flag_valid_symbol_output = true; - current_synchro_data.correlation_length_ms = d_correlation_length_ms; - - if (next_state) - { // reset extended correlator - d_VE_accu = gr_complex(0.0, 0.0); - d_E_accu = gr_complex(0.0, 0.0); - d_P_accu = gr_complex(0.0, 0.0); - d_L_accu = gr_complex(0.0, 0.0); - d_VL_accu = gr_complex(0.0, 0.0); - d_last_prompt = gr_complex(0.0, 0.0); - d_Prompt_buffer_deque.clear(); - d_current_symbol = 0; - d_synchonizing = false; - - if (d_enable_extended_integration) - { - // UPDATE INTEGRATION TIME - d_extend_correlation_symbols_count = 0; - float new_correlation_time = static_cast(trk_parameters.extend_correlation_symbols) * static_cast(d_code_period); - d_carrier_loop_filter.set_pdi(new_correlation_time); - d_code_loop_filter.set_pdi(new_correlation_time); - d_state = 3; // next state is the extended correlator integrator - LOG(INFO) << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " - << d_channel - << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN); - std::cout << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " - << d_channel - << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; - // Set narrow taps delay values [chips] - d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_narrow_hz); - d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_narrow_hz); - if (d_veml) - { - d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - d_local_code_shift_chips[1] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - d_local_code_shift_chips[3] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - } - else - { - d_local_code_shift_chips[0] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - d_local_code_shift_chips[2] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); - } - } - else - { - d_state = 4; - } - } - } - + run_state_2(current_synchro_data); break; } - - case 3: + case 3: // coherent integration (correlation time extension) { d_sample_counter = d_sample_counter_next; d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); @@ -1537,10 +1344,7 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un // Fill the acquisition data current_synchro_data = *d_acquisition_gnss_synchro; // perform a correlation step - multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, d_carrier_phase_step_rad, - d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), - d_current_prn_length_samples); + do_correlation_step(); update_tracking_vars(); save_correlation_results(); @@ -1588,19 +1392,15 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un log_data(true); break; } - case 4: // narrow tracking { d_sample_counter = d_sample_counter_next; d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); + // Fill the acquisition data + current_synchro_data = *d_acquisition_gnss_synchro; // perform a correlation step - //do_correlation_step(in); - multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler( - d_rem_carr_phase_rad, d_carrier_phase_step_rad, - d_rem_code_phase_chips * static_cast(d_code_samples_per_chip), d_code_phase_step_chips * static_cast(d_code_samples_per_chip), - d_current_prn_length_samples); - + do_correlation_step(); save_correlation_results(); // check lock status @@ -1643,7 +1443,6 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); } } - current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; @@ -1668,13 +1467,189 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un if (current_synchro_data.Flag_valid_symbol_output) { current_synchro_data.fs = static_cast(trk_parameters.fs_in); - current_synchro_data.Tracking_sample_counter = d_sample_counter + static_cast(d_current_prn_length_samples); + // two choices for the reporting of the sample counter: + // either the sample counter position that should be (d_sample_counter_next) + //or the sample counter corresponding to the number of samples that the FPGA actually consumed. + current_synchro_data.Tracking_sample_counter = d_sample_counter_next; *out[0] = current_synchro_data; return 1; } return 0; } +void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data) +{ + d_sample_counter = d_sample_counter_next; + d_sample_counter_next = d_sample_counter + static_cast(d_current_prn_length_samples); + + do_correlation_step(); + // Save single correlation step variables + if (d_veml) + { + d_VE_accu = *d_Very_Early; + d_VL_accu = *d_Very_Late; + } + d_E_accu = *d_Early; + d_P_accu = *d_Prompt; + d_L_accu = *d_Late; + + // Check lock status + if (!cn0_and_tracking_lock_status(d_code_period)) + { + clear_tracking_vars(); + d_state = 0; // loss-of-lock detected + } + else + { + bool next_state = false; + // Perform DLL/PLL tracking loop computations. Costas Loop enabled + run_dll_pll(); + update_tracking_vars(); + + // enable write dump file this cycle (valid DLL/PLL cycle) + log_data(false); + if (d_secondary) + { + // ####### SECONDARY CODE LOCK ##### + d_Prompt_buffer_deque.push_back(*d_Prompt); + if (d_Prompt_buffer_deque.size() == d_secondary_code_length) + { + next_state = acquire_secondary(); + if (next_state) + { + std::cout << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + } + + d_Prompt_buffer_deque.pop_front(); + } + } + else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change + { + float current_tracking_time_s = static_cast(d_sample_counter - d_absolute_samples_offset) / trk_parameters.fs_in; + if (current_tracking_time_s > 10) + { + d_symbol_history.push_back(d_Prompt->real()); + //******* preamble correlation ******** + int32_t corr_value = 0; + if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync)) + { + for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++) + { + if (d_symbol_history.at(i) < 0) // symbols clipping + { + corr_value -= d_gps_l1ca_preambles_symbols[i]; + } + else + { + corr_value += d_gps_l1ca_preambles_symbols[i]; + } + } + } + if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS) + { + next_state = true; + } + else + { + next_state = false; + } + } + else + { + next_state = false; + } + } + else + { + next_state = true; + } + + // ########### Output the tracking results to Telemetry block ########## + if (interchange_iq) + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).real()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).imag()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).real()); + } + } + else + { + if (trk_parameters.track_pilot) + { + // Note that data and pilot components are in quadrature. I and Q are interchanged + current_synchro_data.Prompt_I = static_cast((*d_Prompt_Data).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt_Data).imag()); + } + else + { + current_synchro_data.Prompt_I = static_cast((*d_Prompt).real()); + current_synchro_data.Prompt_Q = static_cast((*d_Prompt).imag()); + } + } + current_synchro_data.Code_phase_samples = d_rem_code_phase_samples; + current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad; + current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz; + current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz; + current_synchro_data.Flag_valid_symbol_output = true; + current_synchro_data.correlation_length_ms = d_correlation_length_ms; + + if (next_state) + { // reset extended correlator + d_VE_accu = gr_complex(0.0, 0.0); + d_E_accu = gr_complex(0.0, 0.0); + d_P_accu = gr_complex(0.0, 0.0); + d_L_accu = gr_complex(0.0, 0.0); + d_VL_accu = gr_complex(0.0, 0.0); + d_last_prompt = gr_complex(0.0, 0.0); + d_Prompt_buffer_deque.clear(); + d_current_symbol = 0; + + if (d_enable_extended_integration) + { + // UPDATE INTEGRATION TIME + d_extend_correlation_symbols_count = 0; + float new_correlation_time = static_cast(trk_parameters.extend_correlation_symbols) * static_cast(d_code_period); + d_carrier_loop_filter.set_pdi(new_correlation_time); + d_code_loop_filter.set_pdi(new_correlation_time); + d_state = 3; // next state is the extended correlator integrator + LOG(INFO) << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN); + std::cout << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast(d_code_period * 1000.0) << " ms extended correlator in channel " + << d_channel + << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl; + // Set narrow taps delay values [chips] + d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_narrow_hz); + d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_narrow_hz); + if (d_veml) + { + d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[1] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[3] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + else + { + d_local_code_shift_chips[0] = -trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + d_local_code_shift_chips[2] = trk_parameters.early_late_space_narrow_chips * static_cast(d_code_samples_per_chip); + } + } + else + { + d_state = 4; + } + } + } +} + void dll_pll_veml_tracking_fpga::reset(void) { diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h index 4230a018d..64e705aad 100644 --- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h +++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking_fpga.h @@ -1,19 +1,13 @@ /*! - * \file gps_l1_ca_dll_pll_tracking_fpga.h - * \brief Interface of a code DLL + carrier PLL tracking block - * \author Marc Majoral, 2018. marc.majoral(at)cttc.es - * Carlos Aviles, 2010. carlos.avilesr(at)googlemail.com - * Javier Arribas, 2011. jarribas(at)cttc.es - * Cillian O'Driscoll, 2017. cillian.odriscoll(at)gmail.com - * - * Code DLL + carrier PLL according to the algorithms described in: - * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen, - * A Software-Defined GPS and Galileo Receiver. A Single-Frequency Approach, - * Birkhauser, 2007 + * \file dll_pll_veml_tracking_fpga.h + * \brief Implementation of a code DLL + carrier PLL tracking block using an FPGA. + * \author Marc Majoral, 2019. marc.majoral(at)cttc.es + * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \author Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2015 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -31,7 +25,7 @@ * 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 . + * along with GNSS-SDR. If not, see . * * ------------------------------------------------------------------------- */ @@ -49,18 +43,18 @@ #include #include #include -#include +#include +//#include class dll_pll_veml_tracking_fpga; -typedef boost::shared_ptr - dll_pll_veml_tracking_fpga_sptr; +using dll_pll_veml_tracking_fpga_sptr = boost::shared_ptr; dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_); /*! - * \brief This class implements a DLL + PLL tracking loop block + * \brief This class implements a code DLL + carrier PLL tracking block. */ class dll_pll_veml_tracking_fpga : public gr::block { @@ -71,6 +65,7 @@ public: void set_gnss_synchro(Gnss_Synchro *p_gnss_synchro); void start_tracking(); void stop_tracking(); + int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); @@ -84,6 +79,7 @@ private: bool cn0_and_tracking_lock_status(double coh_integration_time_s); bool acquire_secondary(); + void do_correlation_step(void); void run_dll_pll(); void update_tracking_vars(); void clear_tracking_vars(); @@ -91,9 +87,10 @@ private: void log_data(bool integrating); int32_t save_matfile(); + void run_state_2(Gnss_Synchro ¤t_synchro_data); + // tracking configuration vars Dll_Pll_Conf_Fpga trk_parameters; - //dllpllconf_fpga_t trk_parameters; bool d_veml; bool d_cloop; uint32_t d_channel; @@ -119,14 +116,20 @@ private: //tracking state machine int32_t d_state; - bool d_synchonizing; //Integration period in samples int32_t d_correlation_length_ms; int32_t d_n_correlator_taps; + + float *d_tracking_code; + float *d_data_code; float *d_local_code_shift_chips; float *d_prompt_data_shift; - std::shared_ptr multicorrelator_fpga; - + std::shared_ptr multicorrelator_fpga; + /* TODO: currently the multicorrelator does not support adding extra correlator + with different local code, thus we need extra multicorrelator instance. + Implement this functionality inside multicorrelator class + as an enhancement to increase the performance + */ gr_complex *d_correlator_outs; gr_complex *d_Very_Early; gr_complex *d_Early; @@ -148,10 +151,14 @@ private: gr_complex *d_Prompt_Data; double d_code_phase_step_chips; + double d_code_phase_rate_step_chips; + boost::circular_buffer> d_code_ph_history; double d_carrier_phase_step_rad; + double d_carrier_phase_rate_step_rad; + boost::circular_buffer> d_carr_ph_history; // remaining code phase and carrier phase between tracking loops double d_rem_code_phase_samples; - double d_rem_carr_phase_rad; + float d_rem_carr_phase_rad; // PLL and DLL filter library Tracking_2nd_DLL_filter d_code_loop_filter; @@ -166,12 +173,10 @@ private: double d_carr_error_filt_hz; double d_code_error_chips; double d_code_error_filt_chips; - double d_K_blk_samples; double d_code_freq_chips; double d_carrier_doppler_hz; double d_acc_carrier_phase_rad; double d_rem_code_phase_chips; - double d_code_phase_samples; double T_chip_seconds; double T_prn_seconds; double T_prn_samples; @@ -181,11 +186,13 @@ private: // processing samples counters uint64_t d_sample_counter; uint64_t d_acq_sample_stamp; + uint64_t d_absolute_samples_offset; // CN0 estimation and lock detector int32_t d_cn0_estimation_counter; int32_t d_carrier_lock_fail_counter; + std::deque d_carrier_lock_detector_queue; double d_carrier_lock_test; double d_CN0_SNV_dB_Hz; double d_carrier_lock_threshold; @@ -202,7 +209,6 @@ private: int32_t d_correlation_length_samples; int32_t d_next_prn_length_samples; uint64_t d_sample_counter_next; - uint32_t d_pull_in = 0U; }; #endif //GNSS_SDR_DLL_PLL_VEML_TRACKING_FPGA_H diff --git a/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc b/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc index 87b66a911..14ec6ccab 100644 --- a/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc +++ b/src/algorithms/tracking/libs/dll_pll_conf_fpga.cc @@ -1,12 +1,13 @@ /*! - * \file dll_pll_conf.cc + * \file dll_pll_conf_fpga.cc * \brief Class that contains all the configuration parameters for generic - * tracking block based on a DLL and a PLL. + * tracking block based on a DLL and a PLL for the FPGA. + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Javier Arribas, 2018. jarribas(at)cttc.es * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -36,12 +37,14 @@ Dll_Pll_Conf_Fpga::Dll_Pll_Conf_Fpga() { /* DLL/PLL tracking configuration */ + high_dyn = false; + smoother_length = 10; fs_in = 0.0; vector_length = 0U; dump = false; dump_mat = true; dump_filename = std::string("./dll_pll_dump.dat"); - pll_bw_hz = 40.0; + pll_bw_hz = 35.0; dll_bw_hz = 2.0; pll_bw_narrow_hz = 5.0; dll_bw_narrow_hz = 0.75; diff --git a/src/algorithms/tracking/libs/dll_pll_conf_fpga.h b/src/algorithms/tracking/libs/dll_pll_conf_fpga.h index 8fd81fb36..33dd901d7 100644 --- a/src/algorithms/tracking/libs/dll_pll_conf_fpga.h +++ b/src/algorithms/tracking/libs/dll_pll_conf_fpga.h @@ -1,13 +1,15 @@ /*! - * \file dll_pll_conf.h - * \brief Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. + * \file dll_pll_conf_fpga.h + * \brief Class that contains all the configuration parameters for generic + * tracking block based on a DLL and a PLL for the FPGA. + * \author Marc Majoral, 2019. mmajoral(at)cttc.cat * \author Javier Arribas, 2018. jarribas(at)cttc.es * * Class that contains all the configuration parameters for generic tracking block based on a DLL and a PLL. * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -54,9 +56,11 @@ public: float early_late_space_narrow_chips; float very_early_late_space_narrow_chips; int32_t extend_correlation_symbols; + bool high_dyn; int32_t cn0_samples; int32_t cn0_min; int32_t max_lock_fail; + uint32_t smoother_length; double carrier_lock_th; bool track_pilot; char system; diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.cc b/src/algorithms/tracking/libs/fpga_multicorrelator.cc index add36b0a8..c574bab69 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.cc +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.cc @@ -2,7 +2,7 @@ * \file fpga_multicorrelator_8sc.cc * \brief High optimized FPGA vector correlator class * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2015. jarribas(at)cttc.es *
* @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -35,41 +35,23 @@ */ #include "fpga_multicorrelator.h" -#include - -// FPGA stuff -#include - -// libraries used by DMA test code and GIPO test code -#include -#include -#include -#include - -// libraries used by DMA test code +#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include - -// libraries used by GPIO test code -#include -#include -#include - -// logging -#include - -// string manipulation -#include #include -// constants -#include "GPS_L1_CA.h" - -//#include "gps_sdr_signal_processing.h" - -#define NUM_PRNs 32 +// FPGA register access constants #define PAGE_SIZE 0x10000 #define MAX_LENGTH_DEVICEIO_NAME 50 #define CODE_RESAMPLER_NUM_BITS_PRECISION 20 @@ -84,54 +66,50 @@ #define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 #define TEST_REGISTER_TRACK_WRITEVAL 0x55AA -uint64_t fpga_multicorrelator_8sc::read_sample_counter() + +uint64_t Fpga_Multicorrelator_8sc::read_sample_counter() { uint64_t sample_counter_tmp, sample_counter_msw_tmp; - sample_counter_tmp = d_map_base[d_SAMPLE_COUNTER_REG_ADDR_LSW]; - sample_counter_msw_tmp = d_map_base[d_SAMPLE_COUNTER_REG_ADDR_MSW]; + sample_counter_tmp = d_map_base[SAMPLE_COUNTER_REG_ADDR_LSW]; + sample_counter_msw_tmp = d_map_base[SAMPLE_COUNTER_REG_ADDR_MSW]; sample_counter_msw_tmp = sample_counter_msw_tmp << 32; sample_counter_tmp = sample_counter_tmp + sample_counter_msw_tmp; // 2^32 - //return d_map_base[d_SAMPLE_COUNTER_REG_ADDR]; return sample_counter_tmp; } -void fpga_multicorrelator_8sc::set_initial_sample(uint64_t samples_offset) +void Fpga_Multicorrelator_8sc::set_initial_sample(uint64_t samples_offset) { d_initial_sample_counter = samples_offset; - //printf("www writing d map base %d = d_initial_sample_counter = %d\n", d_INITIAL_COUNTER_VALUE_REG_ADDR, d_initial_sample_counter); - d_map_base[d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW] = (d_initial_sample_counter & 0xFFFFFFFF); - d_map_base[d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW] = (d_initial_sample_counter >> 32) & 0xFFFFFFFF; + d_map_base[INITIAL_COUNTER_VALUE_REG_ADDR_LSW] = (d_initial_sample_counter & 0xFFFFFFFF); + d_map_base[INITIAL_COUNTER_VALUE_REG_ADDR_MSW] = (d_initial_sample_counter >> 32) & 0xFFFFFFFF; } -//void fpga_multicorrelator_8sc::set_local_code_and_taps(int32_t code_length_chips, -// float *shifts_chips, int32_t PRN) - -void fpga_multicorrelator_8sc::set_local_code_and_taps(float *shifts_chips, float *prompt_data_shift, int32_t PRN) +void Fpga_Multicorrelator_8sc::set_local_code_and_taps(float *shifts_chips, float *prompt_data_shift, int32_t PRN) { d_shifts_chips = shifts_chips; d_prompt_data_shift = prompt_data_shift; - //d_code_length_chips = code_length_chips; - fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(PRN); + Fpga_Multicorrelator_8sc::fpga_configure_tracking_gps_local_code(PRN); } -void fpga_multicorrelator_8sc::set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data) +void Fpga_Multicorrelator_8sc::set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data) { d_corr_out = corr_out; d_Prompt_Data = Prompt_Data; } -void fpga_multicorrelator_8sc::update_local_code(float rem_code_phase_chips) +void Fpga_Multicorrelator_8sc::update_local_code(float rem_code_phase_chips) { d_rem_code_phase_chips = rem_code_phase_chips; - //printf("uuuuu d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); - fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(); - fpga_multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(); + Fpga_Multicorrelator_8sc::fpga_compute_code_shift_parameters(); + Fpga_Multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(); } -void fpga_multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( +void Fpga_Multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( float rem_carrier_phase_in_rad, float phase_step_rad, + float carrier_phase_rate_step_rad, float rem_code_phase_chips, float code_phase_step_chips, + float code_phase_rate_step_chips, int32_t signal_length_samples) { update_local_code(rem_code_phase_chips); @@ -139,27 +117,24 @@ void fpga_multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler( d_code_phase_step_chips = code_phase_step_chips; d_phase_step_rad = phase_step_rad; d_correlator_length_samples = signal_length_samples; - fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(); - fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(); - fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(); + Fpga_Multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(); + Fpga_Multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(); + Fpga_Multicorrelator_8sc::fpga_launch_multicorrelator_fpga(); int32_t irq_count; ssize_t nb; - //printf("$$$$$ waiting for interrupt ... \n"); nb = read(d_device_descriptor, &irq_count, sizeof(irq_count)); - //printf("$$$$$ interrupt received ... \n"); if (nb != sizeof(irq_count)) { - printf("Tracking_module Read failed to retrieve 4 bytes!\n"); - printf("Tracking_module Interrupt number %d\n", irq_count); + std::cout << "Tracking_module Read failed to retrieve 4 bytes!" << std::endl; + std::cout << "Tracking_module Interrupt number " << irq_count << std::endl; } - fpga_multicorrelator_8sc::read_tracking_gps_results(); + Fpga_Multicorrelator_8sc::read_tracking_gps_results(); } -fpga_multicorrelator_8sc::fpga_multicorrelator_8sc(int32_t n_correlators, +Fpga_Multicorrelator_8sc::Fpga_Multicorrelator_8sc(int32_t n_correlators, std::string device_name, uint32_t device_base, int32_t *ca_codes, int32_t *data_codes, uint32_t code_length_chips, bool track_pilot, uint32_t multicorr_type, uint32_t code_samples_per_chip) { - //printf("tracking fpga class created\n"); d_n_correlators = n_correlators; d_device_name = std::move(device_name); d_device_base = device_base; @@ -195,111 +170,26 @@ fpga_multicorrelator_8sc::fpga_multicorrelator_8sc(int32_t n_correlators, d_initial_sample_counter = 0; d_channel = 0; d_correlator_length_samples = 0, - //d_code_length = code_length; - d_code_length_chips = code_length_chips; + d_code_length_chips = code_length_chips; d_ca_codes = ca_codes; d_data_codes = data_codes; d_multicorr_type = multicorr_type; - d_code_samples_per_chip = code_samples_per_chip; - // set up register mapping - // write-only registers - d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR = 0; - d_INITIAL_INDEX_REG_BASE_ADDR = 1; - // if (d_multicorr_type == 0) - // { - // // multicorrelator with 3 correlators (16 registers only) - // d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR = 4; - // d_NSAMPLES_MINUS_1_REG_ADDR = 7; - // d_CODE_LENGTH_MINUS_1_REG_ADDR = 8; - // d_REM_CARR_PHASE_RAD_REG_ADDR = 9; - // d_PHASE_STEP_RAD_REG_ADDR = 10; - // d_PROG_MEMS_ADDR = 11; - // d_DROP_SAMPLES_REG_ADDR = 12; - // d_INITIAL_COUNTER_VALUE_REG_ADDR = 13; - // d_START_FLAG_ADDR = 14; - // } - // else - // { - // other types of multicorrelators (32 registers) - d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR = 7; - d_NSAMPLES_MINUS_1_REG_ADDR = 13; - d_CODE_LENGTH_MINUS_1_REG_ADDR = 14; - d_REM_CARR_PHASE_RAD_REG_ADDR = 15; - d_PHASE_STEP_RAD_REG_ADDR = 16; - d_PROG_MEMS_ADDR = 17; - d_DROP_SAMPLES_REG_ADDR = 18; - d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW = 19; - d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW = 20; - d_START_FLAG_ADDR = 30; - // } - - //printf("d_n_correlators = %d\n", d_n_correlators); - //printf("d_multicorr_type = %d\n", d_multicorr_type); - // read-write registers - // if (d_multicorr_type == 0) - // { - // // multicorrelator with 3 correlators (16 registers only) - // d_TEST_REG_ADDR = 15; - // } - // else - // { - // other types of multicorrelators (32 registers) - d_TEST_REG_ADDR = 31; - // } - - // result 2's complement saturation value - // if (d_multicorr_type == 0) - // { - // // multicorrelator with 3 correlators (16 registers only) - // d_result_SAT_value = 1048576; // 21 bits 2's complement -> 2^20 - // } - // else - // { - // // other types of multicorrelators (32 registers) - // d_result_SAT_value = 4194304; // 23 bits 2's complement -> 2^22 - // } - - // read only registers - d_RESULT_REG_REAL_BASE_ADDR = 1; - // if (d_multicorr_type == 0) - // { - // // multicorrelator with 3 correlators (16 registers only) - // d_RESULT_REG_IMAG_BASE_ADDR = 4; - // d_RESULT_REG_DATA_REAL_BASE_ADDR = 0; // no pilot tracking - // d_RESULT_REG_DATA_IMAG_BASE_ADDR = 0; - // d_SAMPLE_COUNTER_REG_ADDR = 7; - // - // } - // else - // { - // other types of multicorrelators (32 registers) - d_RESULT_REG_IMAG_BASE_ADDR = 7; - d_RESULT_REG_DATA_REAL_BASE_ADDR = 6; // no pilot tracking - d_RESULT_REG_DATA_IMAG_BASE_ADDR = 12; - d_SAMPLE_COUNTER_REG_ADDR_LSW = 13; - d_SAMPLE_COUNTER_REG_ADDR_MSW = 14; - - // } - - //printf("d_SAMPLE_COUNTER_REG_ADDR = %d\n", d_SAMPLE_COUNTER_REG_ADDR); - //printf("mmmmmmmmmmmmm d_n_correlators = %d\n", d_n_correlators); DLOG(INFO) << "TRACKING FPGA CLASS CREATED"; } -fpga_multicorrelator_8sc::~fpga_multicorrelator_8sc() +Fpga_Multicorrelator_8sc::~Fpga_Multicorrelator_8sc() { - //delete[] d_ca_codes; close_device(); } -bool fpga_multicorrelator_8sc::free() +bool Fpga_Multicorrelator_8sc::free() { // unlock the channel - fpga_multicorrelator_8sc::unlock_channel(); + Fpga_Multicorrelator_8sc::unlock_channel(); // free the FPGA dynamically created variables if (d_initial_index != nullptr) @@ -318,9 +208,8 @@ bool fpga_multicorrelator_8sc::free() } -void fpga_multicorrelator_8sc::set_channel(uint32_t channel) +void Fpga_Multicorrelator_8sc::set_channel(uint32_t channel) { - //printf("www trk set channel\n"); char device_io_name[MAX_LENGTH_DEVICEIO_NAME]; // driver io name d_channel = channel; @@ -332,20 +221,13 @@ void fpga_multicorrelator_8sc::set_channel(uint32_t channel) mergedname = d_device_name + devicebasetemp.str(); strcpy(device_io_name, mergedname.c_str()); - //printf("ppps opening device %s\n", device_io_name); + std::cout << "trk device_io_name = " << device_io_name << std::endl; if ((d_device_descriptor = open(device_io_name, O_RDWR | O_SYNC)) == -1) { LOG(WARNING) << "Cannot open deviceio" << device_io_name; std::cout << "Cannot open deviceio" << device_io_name << std::endl; - - //printf("error opening device\n"); } - // else - // { - // std::cout << "deviceio" << device_io_name << " opened successfully" << std::endl; - // - // } d_map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); @@ -354,79 +236,47 @@ void fpga_multicorrelator_8sc::set_channel(uint32_t channel) LOG(WARNING) << "Cannot map the FPGA tracking module " << d_channel << "into user memory"; std::cout << "Cannot map deviceio" << device_io_name << std::endl; - //printf("error mapping registers\n"); } - // else - // { - // std::cout << "deviceio" << device_io_name << "mapped successfully" << std::endl; - // } - // else - // { - // printf("trk mapping registers succes\n"); // this is for debug -- remove ! - // } // sanity check : check test register uint32_t writeval = TEST_REGISTER_TRACK_WRITEVAL; uint32_t readval; - readval = fpga_multicorrelator_8sc::fpga_acquisition_test_register(writeval); + readval = Fpga_Multicorrelator_8sc::fpga_acquisition_test_register(writeval); if (writeval != readval) { LOG(WARNING) << "Test register sanity check failed"; - printf("tracking test register sanity check failed\n"); - - //printf("lslslls test sanity check reg failure\n"); + std::cout << "tracking test register sanity check failed" << std::endl; } else { LOG(INFO) << "Test register sanity check success !"; - //printf("tracking test register sanity check success\n"); - //printf("lslslls test sanity check reg success\n"); } } -uint32_t fpga_multicorrelator_8sc::fpga_acquisition_test_register( +uint32_t Fpga_Multicorrelator_8sc::fpga_acquisition_test_register( uint32_t writeval) { - //printf("d_TEST_REG_ADDR = %d\n", d_TEST_REG_ADDR); - uint32_t readval = 0; // write value to test register - d_map_base[d_TEST_REG_ADDR] = writeval; + d_map_base[TEST_REG_ADDR] = writeval; // read value from test register - readval = d_map_base[d_TEST_REG_ADDR]; + readval = d_map_base[TEST_REG_ADDR]; // return read value return readval; } -void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PRN) +void Fpga_Multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PRN) { uint32_t k; uint32_t code_chip; uint32_t select_pilot_corelator = LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT; - // select_fpga_correlator = 0; - //printf("kkk d_n_correlators = %x\n", d_n_correlators); - //printf("kkk d_code_length_chips = %d\n", d_code_length_chips); - //printf("programming mems d map base %d\n", d_PROG_MEMS_ADDR); - - //FILE *fp; - //char str[80]; - //sprintf(str, "generated_code_PRN%d", PRN); - //fp = fopen(str,"w"); - // for (s = 0; s < d_n_correlators; s++) - // { - - //printf("kkk select_fpga_correlator = %x\n", select_fpga_correlator); - - d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; + d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++) { - //if (d_local_code_in[k] == 1) - //printf("kkk d_ca_codes %d = %d\n", k, d_ca_codes[((int(d_code_length)) * (PRN - 1)) + k]); - //fprintf(fp, "%d\n", d_ca_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k]); - if (d_ca_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) + if (d_ca_codes[((int32_t(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) { code_chip = 1; } @@ -436,22 +286,14 @@ void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PR } // copy the local code to the FPGA memory one by one - d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip; // | select_fpga_correlator; + d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip; // | select_fpga_correlator; } - // select_fpga_correlator = select_fpga_correlator - // + LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT; - // } - //fclose(fp); - //printf("kkk d_track_pilot = %d\n", d_track_pilot); if (d_track_pilot) { - //printf("kkk select_fpga_correlator = %x\n", select_fpga_correlator); - - d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; + d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER; for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++) { - //if (d_local_code_in[k] == 1) - if (d_data_codes[((int(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) + if (d_data_codes[((int32_t(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1) { code_chip = 1; } @@ -459,53 +301,38 @@ void fpga_multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PR { code_chip = 0; } - //printf("%d %d | ", d_data_codes, code_chip); - // copy the local code to the FPGA memory one by one - d_map_base[d_PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip | select_pilot_corelator; + d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip | select_pilot_corelator; } } - //printf("\n"); } -void fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(void) +void Fpga_Multicorrelator_8sc::fpga_compute_code_shift_parameters(void) { float temp_calculation; int32_t i; - //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); for (i = 0; i < d_n_correlators; i++) { - //printf("ppp d_shifts_chips %d = %f\n", i, d_shifts_chips[i]); - //printf("ppp d_code_samples_per_chip = %d\n", d_code_samples_per_chip); temp_calculation = floor( d_shifts_chips[i] - d_rem_code_phase_chips); - //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); - //printf("ppp temp calculation %d = %f ================================ \n", i, temp_calculation); if (temp_calculation < 0) { temp_calculation = temp_calculation + (d_code_length_chips * d_code_samples_per_chip); // % operator does not work as in Matlab with negative numbers } - //printf("ppp d_rem_code_phase_chips = %f\n", d_rem_code_phase_chips); - //printf("ppp temp calculation %d = %f ================================ \n", i, temp_calculation); d_initial_index[i] = static_cast((static_cast(temp_calculation)) % (d_code_length_chips * d_code_samples_per_chip)); - //printf("ppp d_initial_index %d = %d\n", i, d_initial_index[i]); temp_calculation = fmod(d_shifts_chips[i] - d_rem_code_phase_chips, 1.0); - //printf("ppp fmod %d = fmod(%f, 1) = %f\n", i, d_shifts_chips[i] - d_rem_code_phase_chips, temp_calculation); if (temp_calculation < 0) { temp_calculation = temp_calculation + 1.0; // fmod operator does not work as in Matlab with negative numbers } d_initial_interp_counter[i] = static_cast(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation)); - //printf("ppp d_initial_interp_counter %d = %d\n", i, d_initial_interp_counter[i]); - //printf("MAX_CODE_RESAMPLER_COUNTER = %d\n", MAX_CODE_RESAMPLER_COUNTER); } if (d_track_pilot) { - //printf("tracking pilot !!!!!!!!!!!!!!!!\n"); temp_calculation = floor( d_prompt_data_shift[0] - d_rem_code_phase_chips); @@ -522,47 +349,37 @@ void fpga_multicorrelator_8sc::fpga_compute_code_shift_parameters(void) } d_initial_interp_counter[d_n_correlators] = static_cast(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation)); } - //while(1); } -void fpga_multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(void) +void Fpga_Multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(void) { int32_t i; for (i = 0; i < d_n_correlators; i++) { - //printf("www writing d map base %d = d_initial_index %d = %d\n", d_INITIAL_INDEX_REG_BASE_ADDR + i, i, d_initial_index[i]); - d_map_base[d_INITIAL_INDEX_REG_BASE_ADDR + i] = d_initial_index[i]; - //d_map_base[1 + d_n_correlators + i] = d_initial_interp_counter[i]; - //printf("www writing d map base %d = d_initial_interp_counter %d = %d\n", d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i, i, d_initial_interp_counter[i]); - d_map_base[d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i] = d_initial_interp_counter[i]; + d_map_base[INITIAL_INDEX_REG_BASE_ADDR + i] = d_initial_index[i]; + d_map_base[INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i] = d_initial_interp_counter[i]; } if (d_track_pilot) { - //printf("www writing d map base %d = d_initial_index %d = %d\n", d_INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators, d_n_correlators, d_initial_index[d_n_correlators]); - d_map_base[d_INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators] = d_initial_index[d_n_correlators]; - //d_map_base[1 + d_n_correlators + i] = d_initial_interp_counter[i]; - //printf("www writing d map base %d = d_initial_interp_counter %d = %d\n", d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators, d_n_correlators, d_initial_interp_counter[d_n_correlators]); - d_map_base[d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators] = d_initial_interp_counter[d_n_correlators]; + d_map_base[INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators] = d_initial_index[d_n_correlators]; + d_map_base[INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators] = d_initial_interp_counter[d_n_correlators]; } - //printf("www writing d map base %d = d_code_length_chips*d_code_samples_per_chip - 1 = %d\n", d_CODE_LENGTH_MINUS_1_REG_ADDR, (d_code_length_chips*d_code_samples_per_chip) - 1); - d_map_base[d_CODE_LENGTH_MINUS_1_REG_ADDR] = (d_code_length_chips * d_code_samples_per_chip) - 1; // number of samples - 1 + d_map_base[CODE_LENGTH_MINUS_1_REG_ADDR] = (d_code_length_chips * d_code_samples_per_chip) - 1; // number of samples - 1 } -void fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) +void Fpga_Multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) { float d_rem_carrier_phase_in_rad_temp; d_code_phase_step_chips_num = static_cast(roundf(MAX_CODE_RESAMPLER_COUNTER * d_code_phase_step_chips)); if (d_code_phase_step_chips > 1.0) { - printf("Warning : d_code_phase_step_chips = %f cannot be bigger than one\n", d_code_phase_step_chips); + std::cout << "Warning : d_code_phase_step_chips = " << d_code_phase_step_chips << " cannot be bigger than one" << std::endl; } - //printf("d_rem_carrier_phase_in_rad = %f\n", d_rem_carrier_phase_in_rad); - if (d_rem_carrier_phase_in_rad > M_PI) { d_rem_carrier_phase_in_rad_temp = -2 * M_PI + d_rem_carrier_phase_in_rad; @@ -584,158 +401,77 @@ void fpga_multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void) d_phase_step_rad_int = static_cast(roundf( (fabs(d_phase_step_rad) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC))); // the FPGA accepts a range for the phase step between -pi and +pi - //printf("d_phase_step_rad_int = %d\n", d_phase_step_rad_int); if (d_phase_step_rad < 0) { d_phase_step_rad_int = -d_phase_step_rad_int; } - - //printf("d_phase_step_rad_int = %d\n", d_phase_step_rad_int); } -void fpga_multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(void) +void Fpga_Multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga(void) { - //printf("www d map base %d = d_code_phase_step_chips_num = %d\n", d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR, d_code_phase_step_chips_num); - d_map_base[d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR] = d_code_phase_step_chips_num; + d_map_base[CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR] = d_code_phase_step_chips_num; - //printf("www d map base %d = d_correlator_length_samples - 1 = %d\n", d_NSAMPLES_MINUS_1_REG_ADDR, d_correlator_length_samples - 1); - d_map_base[d_NSAMPLES_MINUS_1_REG_ADDR] = d_correlator_length_samples - 1; + d_map_base[NSAMPLES_MINUS_1_REG_ADDR] = d_correlator_length_samples - 1; - //printf("www d map base %d = d_rem_carr_phase_rad_int = %d\n", d_REM_CARR_PHASE_RAD_REG_ADDR, d_rem_carr_phase_rad_int); - d_map_base[d_REM_CARR_PHASE_RAD_REG_ADDR] = d_rem_carr_phase_rad_int; + d_map_base[REM_CARR_PHASE_RAD_REG_ADDR] = d_rem_carr_phase_rad_int; - //printf("www d map base %d = d_phase_step_rad_int = %d\n", d_PHASE_STEP_RAD_REG_ADDR, d_phase_step_rad_int); - d_map_base[d_PHASE_STEP_RAD_REG_ADDR] = d_phase_step_rad_int; + d_map_base[PHASE_STEP_RAD_REG_ADDR] = d_phase_step_rad_int; } -void fpga_multicorrelator_8sc::fpga_launch_multicorrelator_fpga(void) +void Fpga_Multicorrelator_8sc::fpga_launch_multicorrelator_fpga(void) { // enable interrupts int32_t reenable = 1; write(d_device_descriptor, reinterpret_cast(&reenable), sizeof(int32_t)); // writing 1 to reg 14 launches the tracking - //printf("www writing 1 to d map base %d = start flag\n", d_START_FLAG_ADDR); - d_map_base[d_START_FLAG_ADDR] = 1; - //while(1); + d_map_base[START_FLAG_ADDR] = 1; } -void fpga_multicorrelator_8sc::read_tracking_gps_results(void) +void Fpga_Multicorrelator_8sc::read_tracking_gps_results(void) { int32_t readval_real; int32_t readval_imag; int32_t k; - //printf("www reading trk results\n"); for (k = 0; k < d_n_correlators; k++) { - readval_real = d_map_base[d_RESULT_REG_REAL_BASE_ADDR + k]; - //printf("read real before checking d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_real); - //// if (readval_real > debug_max_readval_real[k]) - //// { - //// debug_max_readval_real[k] = readval_real; - //// } - // if (readval_real >= d_result_SAT_value) // 0x100000 (21 bits two's complement) - // { - // readval_real = -2*d_result_SAT_value + readval_real; - // } - //// if (readval_real > debug_max_readval_real_after_check[k]) - //// { - //// debug_max_readval_real_after_check[k] = readval_real; - //// } - //printf("read real d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_real); - readval_imag = d_map_base[d_RESULT_REG_IMAG_BASE_ADDR + k]; - //printf("read imag before checking d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_imag); - //// if (readval_imag > debug_max_readval_imag[k]) - //// { - //// debug_max_readval_imag[k] = readval_imag; - //// } - // - // if (readval_imag >= d_result_SAT_value) // 0x100000 (21 bits two's complement) - // { - // readval_imag = -2*d_result_SAT_value + readval_imag; - // } - //// if (readval_imag > debug_max_readval_imag_after_check[k]) - //// { - //// debug_max_readval_imag_after_check[k] = readval_real; - //// } - //printf("read imag d map base %d = %d\n", d_RESULT_REG_BASE_ADDR + k, readval_imag); + readval_real = d_map_base[RESULT_REG_REAL_BASE_ADDR + k]; + readval_imag = d_map_base[RESULT_REG_IMAG_BASE_ADDR + k]; d_corr_out[k] = gr_complex(readval_real, readval_imag); - - // if (printcounter > 100) - // { - // printcounter = 0; - // for (int32_t ll=0;ll= d_result_SAT_value) // 0x100000 (21 bits two's complement) - // { - // readval_real = -2*d_result_SAT_value + readval_real; - // } - - readval_imag = d_map_base[d_RESULT_REG_DATA_IMAG_BASE_ADDR]; - // if (readval_imag >= d_result_SAT_value) // 0x100000 (21 bits two's complement) - // { - // readval_imag = -2*d_result_SAT_value + readval_imag; - // } + readval_real = d_map_base[RESULT_REG_REAL_BASE_ADDR + d_n_correlators]; + readval_imag = d_map_base[RESULT_REG_IMAG_BASE_ADDR + d_n_correlators]; d_Prompt_Data[0] = gr_complex(readval_real, readval_imag); } } -void fpga_multicorrelator_8sc::unlock_channel(void) +void Fpga_Multicorrelator_8sc::unlock_channel(void) { // unlock the channel to let the next samples go through - //printf("www writing 1 to d map base %d = drop samples\n", d_DROP_SAMPLES_REG_ADDR); - d_map_base[d_DROP_SAMPLES_REG_ADDR] = 1; // unlock the channel + d_map_base[DROP_SAMPLES_REG_ADDR] = 1; // unlock the channel + d_map_base[STOP_TRACKING_REG_ADDR] = 1; // set the tracking module back to idle } -void fpga_multicorrelator_8sc::close_device() +void Fpga_Multicorrelator_8sc::close_device() { auto *aux = const_cast(d_map_base); if (munmap(static_cast(aux), PAGE_SIZE) == -1) { - printf("Failed to unmap memory uio\n"); + std::cout << "Failed to unmap memory uio" << std::endl; } close(d_device_descriptor); } -void fpga_multicorrelator_8sc::lock_channel(void) +void Fpga_Multicorrelator_8sc::lock_channel(void) { // lock the channel for processing - //printf("www writing 0 to d map base %d = drop samples\n", d_DROP_SAMPLES_REG_ADDR); - d_map_base[d_DROP_SAMPLES_REG_ADDR] = 0; // lock the channel + d_map_base[DROP_SAMPLES_REG_ADDR] = 0; // lock the channel } - -//void fpga_multicorrelator_8sc::read_sample_counters(int32_t *sample_counter, int32_t *secondary_sample_counter, int32_t *counter_corr_0_in, int32_t *counter_corr_0_out) -//{ -// *sample_counter = d_map_base[11]; -// *secondary_sample_counter = d_map_base[8]; -// *counter_corr_0_in = d_map_base[10]; -// *counter_corr_0_out = d_map_base[9]; -// -//} - -//void fpga_multicorrelator_8sc::reset_multicorrelator(void) -//{ -// d_map_base[14] = 2; // writing a 2 to d_map_base[14] resets the multicorrelator -//} diff --git a/src/algorithms/tracking/libs/fpga_multicorrelator.h b/src/algorithms/tracking/libs/fpga_multicorrelator.h index f7fffe1aa..ddf1930c1 100644 --- a/src/algorithms/tracking/libs/fpga_multicorrelator.h +++ b/src/algorithms/tracking/libs/fpga_multicorrelator.h @@ -1,8 +1,8 @@ /*! * \file fpga_multicorrelator_8sc.h - * \brief High optimized FPGA vector correlator class for lv_16sc_t (short int32_t complex) + * \brief High optimized FPGA vector correlator class * \authors
    - *
  • Marc Majoral, 2017. mmajoral(at)cttc.cat + *
  • Marc Majoral, 2019. mmajoral(at)cttc.cat *
  • Javier Arribas, 2016. jarribas(at)cttc.es *
* @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -41,32 +41,49 @@ #include #include -#define MAX_LENGTH_DEVICEIO_NAME 50 +// FPGA register addresses + +// write addresses +#define CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR 0 +#define INITIAL_INDEX_REG_BASE_ADDR 1 +#define INITIAL_INTERP_COUNTER_REG_BASE_ADDR 7 +#define NSAMPLES_MINUS_1_REG_ADDR 13 +#define CODE_LENGTH_MINUS_1_REG_ADDR 14 +#define REM_CARR_PHASE_RAD_REG_ADDR 15 +#define PHASE_STEP_RAD_REG_ADDR 16 +#define PROG_MEMS_ADDR 17 +#define DROP_SAMPLES_REG_ADDR 18 +#define INITIAL_COUNTER_VALUE_REG_ADDR_LSW 19 +#define INITIAL_COUNTER_VALUE_REG_ADDR_MSW 20 +#define STOP_TRACKING_REG_ADDR 23 +#define START_FLAG_ADDR 30 +// read-write addresses +#define TEST_REG_ADDR 31 +// read addresses +#define RESULT_REG_REAL_BASE_ADDR 1 +#define RESULT_REG_IMAG_BASE_ADDR 7 +#define SAMPLE_COUNTER_REG_ADDR_LSW 13 +#define SAMPLE_COUNTER_REG_ADDR_MSW 14 + /*! * \brief Class that implements carrier wipe-off and correlators. */ -class fpga_multicorrelator_8sc +class Fpga_Multicorrelator_8sc { public: - fpga_multicorrelator_8sc(int32_t n_correlators, std::string device_name, + Fpga_Multicorrelator_8sc(int32_t n_correlators, std::string device_name, uint32_t device_base, int32_t *ca_codes, int32_t *data_codes, uint32_t code_length_chips, bool track_pilot, uint32_t multicorr_type, uint32_t code_samples_per_chip); - ~fpga_multicorrelator_8sc(); - //bool set_output_vectors(gr_complex* corr_out); + ~Fpga_Multicorrelator_8sc(); void set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data); - // bool set_local_code_and_taps( - // int32_t code_length_chips, const int* local_code_in, - // float *shifts_chips, int32_t PRN); - //bool set_local_code_and_taps( void set_local_code_and_taps( - // int32_t code_length_chips, float *shifts_chips, float *prompt_data_shift, int32_t PRN); - //bool set_output_vectors(lv_16sc_t* corr_out); void update_local_code(float rem_code_phase_chips); - //bool Carrier_wipeoff_multicorrelator_resampler( void Carrier_wipeoff_multicorrelator_resampler( float rem_carrier_phase_in_rad, float phase_step_rad, + float carrier_phase_rate_step_rad, float rem_code_phase_chips, float code_phase_step_chips, + float code_phase_rate_step_chips, int32_t signal_length_samples); bool free(); void set_channel(uint32_t channel); @@ -74,10 +91,8 @@ public: uint64_t read_sample_counter(); void lock_channel(void); void unlock_channel(void); - //void read_sample_counters(int32_t *sample_counter, int32_t *secondary_sample_counter, int32_t *counter_corr_0_in, int32_t *counter_corr_0_out); // debug private: - //const int32_t *d_local_code_in; gr_complex *d_corr_out; gr_complex *d_Prompt_Data; float *d_shifts_chips; @@ -113,37 +128,11 @@ private: int32_t *d_ca_codes; int32_t *d_data_codes; - //uint32_t d_code_length; // nominal number of chips - uint32_t d_code_samples_per_chip; bool d_track_pilot; uint32_t d_multicorr_type; - // register addresses - // write-only regs - uint32_t d_CODE_PHASE_STEP_CHIPS_NUM_REG_ADDR; - uint32_t d_INITIAL_INDEX_REG_BASE_ADDR; - uint32_t d_INITIAL_INTERP_COUNTER_REG_BASE_ADDR; - uint32_t d_NSAMPLES_MINUS_1_REG_ADDR; - uint32_t d_CODE_LENGTH_MINUS_1_REG_ADDR; - uint32_t d_REM_CARR_PHASE_RAD_REG_ADDR; - uint32_t d_PHASE_STEP_RAD_REG_ADDR; - uint32_t d_PROG_MEMS_ADDR; - uint32_t d_DROP_SAMPLES_REG_ADDR; - uint32_t d_INITIAL_COUNTER_VALUE_REG_ADDR_LSW; - uint32_t d_INITIAL_COUNTER_VALUE_REG_ADDR_MSW; - uint32_t d_START_FLAG_ADDR; - // read-write regs - uint32_t d_TEST_REG_ADDR; - // read-only regs - uint32_t d_RESULT_REG_REAL_BASE_ADDR; - uint32_t d_RESULT_REG_IMAG_BASE_ADDR; - uint32_t d_RESULT_REG_DATA_REAL_BASE_ADDR; - uint32_t d_RESULT_REG_DATA_IMAG_BASE_ADDR; - uint32_t d_SAMPLE_COUNTER_REG_ADDR_LSW; - uint32_t d_SAMPLE_COUNTER_REG_ADDR_MSW; - // private functions uint32_t fpga_acquisition_test_register(uint32_t writeval); void fpga_configure_tracking_gps_local_code(int32_t PRN); @@ -153,17 +142,7 @@ private: void fpga_configure_signal_parameters_in_fpga(void); void fpga_launch_multicorrelator_fpga(void); void read_tracking_gps_results(void); - //void reset_multicorrelator(void); void close_device(void); - - uint32_t d_result_SAT_value; - - int32_t debug_max_readval_real[5] = {0, 0, 0, 0, 0}; - int32_t debug_max_readval_imag[5] = {0, 0, 0, 0, 0}; - - int32_t debug_max_readval_real_after_check[5] = {0, 0, 0, 0, 0}; - int32_t debug_max_readval_imag_after_check[5] = {0, 0, 0, 0, 0}; - int32_t printcounter = 0; }; #endif /* GNSS_SDR_FPGA_MULTICORRELATOR_H_ */ diff --git a/src/core/receiver/control_thread.cc b/src/core/receiver/control_thread.cc index 67dc239c1..37028109b 100644 --- a/src/core/receiver/control_thread.cc +++ b/src/core/receiver/control_thread.cc @@ -273,12 +273,11 @@ int ControlThread::run() cmd_interface_.set_pvt(flowgraph_->get_pvt()); cmd_interface_thread_ = std::thread(&ControlThread::telecommand_listener, this); - bool enable_FPGA = configuration_->property("Channel.enable_FPGA", false); - if (enable_FPGA == true) - { - flowgraph_->start_acquisition_helper(); - } - +#ifdef ENABLE_FPGA + // Create a task for the acquisition such that id doesn't block the flow of the control thread + fpga_helper_thread_ = boost::thread(&GNSSFlowgraph::start_acquisition_helper, + flowgraph_); +#endif // Main loop to read and process the control messages while (flowgraph_->running() && !stop_) { @@ -294,12 +293,23 @@ int ControlThread::run() stop_ = true; flowgraph_->disconnect(); +#ifdef ENABLE_FPGA + // trigger a HW reset + // The HW reset causes any HW accelerator module that is waiting for more samples to complete its calculations + // to trigger an interrupt and finish its signal processing tasks immediately. In this way all SW threads that + // are waiting for interrupts in the HW can exit in a normal way. + flowgraph_->perform_hw_reset(); + fpga_helper_thread_.try_join_until(boost::chrono::steady_clock::now() + boost::chrono::milliseconds(1000)); +#endif + std::this_thread::sleep_for(std::chrono::milliseconds(500)); // Terminate keyboard thread pthread_t id = keyboard_thread_.native_handle(); keyboard_thread_.detach(); pthread_cancel(id); + LOG(INFO) << "Flowgraph stopped"; + if (restart_) { return 42; // signal the gnss-sdr-harness.sh to restart the receiver program diff --git a/src/core/receiver/control_thread.h b/src/core/receiver/control_thread.h index 6507ca645..a1ecc5c1a 100644 --- a/src/core/receiver/control_thread.h +++ b/src/core/receiver/control_thread.h @@ -95,7 +95,6 @@ public: */ void set_control_queue(const gr::msg_queue::sptr control_queue); // NOLINT(performance-unnecessary-value-param) - unsigned int processed_control_messages() { return processed_control_messages_; @@ -168,6 +167,9 @@ private: bool delete_configuration_; unsigned int processed_control_messages_; unsigned int applied_actions_; + + boost::thread fpga_helper_thread_; + std::thread keyboard_thread_; std::thread sysv_queue_thread_; std::thread gps_acq_assist_data_collector_thread_; diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index a87e5bbba..b1e226ca8 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -11,7 +11,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 277cad96c..c4e5934de 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -9,7 +9,7 @@ * * ------------------------------------------------------------------------- * - * Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -50,6 +50,7 @@ #include #include #include +#include #include #ifdef GR_GREATER_38 #include @@ -123,6 +124,7 @@ void GNSSFlowgraph::connect() return; } +#ifndef ENABLE_FPGA for (int i = 0; i < sources_count_; i++) { if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) @@ -141,6 +143,7 @@ void GNSSFlowgraph::connect() } } + // Signal Source > Signal conditioner > for (unsigned int i = 0; i < sig_conditioner_.size(); i++) { @@ -159,7 +162,7 @@ void GNSSFlowgraph::connect() } } } - +#endif for (unsigned int i = 0; i < channels_count_; i++) { try @@ -205,78 +208,78 @@ void GNSSFlowgraph::connect() int RF_Channels = 0; int signal_conditioner_ID = 0; + +#ifndef ENABLE_FPGA + for (int i = 0; i < sources_count_; i++) { - //FPGA Accelerators do not need signal sources or conditioners - //as the samples are feed directly to the FPGA fabric, so, if enabled, do not connect any source - if (configuration_->property(sig_source_.at(i)->role() + ".enable_FPGA", false) == false) + try { - try + //TODO: Remove this array implementation and create generic multistream connector + //(if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") { - //TODO: Remove this array implementation and create generic multistream connector - //(if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) - if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") + //Multichannel Array + std::cout << "ARRAY MODE" << std::endl; + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) { - //Multichannel Array - std::cout << "ARRAY MODE" << std::endl; - for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) - { - std::cout << "connecting ch " << j << std::endl; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); - } + std::cout << "connecting ch " << j << std::endl; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); } - else + } + else + { + //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + //Include GetRFChannels in the interface to avoid read config parameters here + //read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) { - //TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. - //Include GetRFChannels in the interface to avoid read config parameters here - //read the number of RF channels for each front-end - RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + //Connect the multichannel signal source to multiple signal conditioners + // GNURADIO max_streams=-1 means infinite ports! + LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); + LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - for (int j = 0; j < RF_Channels; j++) + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) { - //Connect the multichannel signal source to multiple signal conditioners - // GNURADIO max_streams=-1 means infinite ports! - LOG(INFO) << "sig_source_.at(i)->get_right_block()->output_signature()->max_streams()=" << sig_source_.at(i)->get_right_block()->output_signature()->max_streams(); - LOG(INFO) << "sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()=" << sig_conditioner_.at(signal_conditioner_ID)->get_left_block()->input_signature()->max_streams(); - - if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + if (j == 0) { - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + // RF_channel 0 backward compatibility with single channel sources + LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); } else { - if (j == 0) - { - // RF_channel 0 backward compatibility with single channel sources - LOG(INFO) << "connecting sig_source_ " << i << " stream " << 0 << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } - else - { - // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) - LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; - top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); - } + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + LOG(INFO) << "connecting sig_source_ " << i << " stream " << j << " to conditioner " << j; + top_block_->connect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); } - signal_conditioner_ID++; } + signal_conditioner_ID++; } } - catch (const std::exception& e) - { - LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; - LOG(ERROR) << e.what(); - top_block_->disconnect_all(); - return; - } + } + catch (const std::exception& e) + { + LOG(WARNING) << "Can't connect signal source " << i << " to signal conditioner " << i; + LOG(ERROR) << e.what(); + top_block_->disconnect_all(); + return; } } DLOG(INFO) << "Signal source connected to signal conditioner"; - bool FPGA_enabled = configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false); + +#endif #if ENABLE_FPGA - if (FPGA_enabled == false) + + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) { //connect the signal source to sample counter //connect the sample counter to Observables @@ -352,13 +355,15 @@ void GNSSFlowgraph::connect() return; } #endif + // Signal conditioner (selected_signal_source) >> channels (i) (dependent of their associated SignalSource_ID) int selected_signal_conditioner_ID = 0; bool use_acq_resampler = configuration_->property("GNSS-SDR.use_acquisition_resampler", false); uint32_t fs = configuration_->property("GNSS-SDR.internal_fs_sps", 0); for (unsigned int i = 0; i < channels_count_; i++) { - if (FPGA_enabled == false) +#ifndef ENABLE_FPGA + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) { try { @@ -497,6 +502,7 @@ void GNSSFlowgraph::connect() DLOG(INFO) << "signal conditioner " << selected_signal_conditioner_ID << " connected to channel " << i; } +#endif // Signal Source > Signal conditioner >> Channels >> Observables try { @@ -655,16 +661,15 @@ void GNSSFlowgraph::connect() } } + +#ifndef ENABLE_FPGA // Activate acquisition in enabled channels for (unsigned int i = 0; i < channels_count_; i++) { LOG(INFO) << "Channel " << i << " assigned to " << channels_.at(i)->get_signal(); if (channels_state_[i] == 1) { - if (FPGA_enabled == false) - { - channels_.at(i)->start_acquisition(); - } + channels_.at(i)->start_acquisition(); LOG(INFO) << "Channel " << i << " connected to observables and ready for acquisition"; } else @@ -672,6 +677,7 @@ void GNSSFlowgraph::connect() LOG(INFO) << "Channel " << i << " connected to observables in standby mode"; } } +#endif connected_ = true; LOG(INFO) << "Flowgraph connected"; @@ -693,6 +699,66 @@ void GNSSFlowgraph::disconnect() int RF_Channels = 0; int signal_conditioner_ID = 0; + +#ifdef ENABLE_FPGA + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) + { + for (int i = 0; i < sources_count_; i++) + { + try + { + // TODO: Remove this array implementation and create generic multistream connector + // (if a signal source has more than 1 stream, then connect it to the multistream signal conditioner) + if (sig_source_.at(i)->implementation() == "Raw_Array_Signal_Source") + { + //Multichannel Array + for (int j = 0; j < GNSS_SDR_ARRAY_SIGNAL_CONDITIONER_CHANNELS; j++) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(i)->get_left_block(), j); + } + } + else + { + // TODO: Create a class interface for SignalSources, derived from GNSSBlockInterface. + // Include GetRFChannels in the interface to avoid read config parameters here + // read the number of RF channels for each front-end + RF_Channels = configuration_->property(sig_source_.at(i)->role() + ".RF_channels", 1); + + for (int j = 0; j < RF_Channels; j++) + { + if (sig_source_.at(i)->get_right_block()->output_signature()->max_streams() > 1) + { + top_block_->disconnect(sig_source_.at(i)->get_right_block(), j, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + if (j == 0) + { + // RF_channel 0 backward compatibility with single channel sources + top_block_->disconnect(sig_source_.at(i)->get_right_block(), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + else + { + // Multiple channel sources using multiple output blocks of single channel (requires RF_channel selector in call) + top_block_->disconnect(sig_source_.at(i)->get_right_block(j), 0, sig_conditioner_.at(signal_conditioner_ID)->get_left_block(), 0); + } + } + signal_conditioner_ID++; + } + } + } + catch (const std::exception& e) + { + LOG(INFO) << "Can't disconnect signal source " << i << " to signal conditioner " << i << ": " << e.what(); + top_block_->disconnect_all(); + return; + } + } + } + + +#else + for (int i = 0; i < sources_count_; i++) { try @@ -744,10 +810,10 @@ void GNSSFlowgraph::disconnect() return; } } +#endif -#if ENABLE_FPGA - bool FPGA_enabled = configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false); - if (FPGA_enabled == false) +#ifdef ENABLE_FPGA + if (configuration_->property(sig_source_.at(0)->role() + ".enable_FPGA", false) == false) { // disconnect the signal source to sample counter // disconnect the sample counter to Observables @@ -808,6 +874,7 @@ void GNSSFlowgraph::disconnect() top_block_->disconnect_all(); return; } +#ifndef ENABLE_FPGA try { top_block_->disconnect(sig_conditioner_.at(selected_signal_conditioner_ID)->get_right_block(), 0, @@ -819,7 +886,7 @@ void GNSSFlowgraph::disconnect() top_block_->disconnect_all(); return; } - +#endif // Signal Source > Signal conditioner >> Channels >> Observables try { @@ -1060,7 +1127,14 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); + +#ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[ch_index]); + tmp_thread.detach(); +#endif } DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; } @@ -1131,7 +1205,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << i << " Starting acquisition " << channels_[i]->get_signal().get_satellite() << ", Signal " << channels_[i]->get_signal().get_signal_str(); +#ifndef ENABLE_FPGA channels_[i]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[i]); + tmp_thread.detach(); +#endif } DLOG(INFO) << "Channel " << i << " in state " << channels_state_[i]; } @@ -1146,7 +1226,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) channels_state_[who] = 1; acq_channels_count_++; LOG(INFO) << "Channel " << who << " Starting acquisition " << channels_[who]->get_signal().get_satellite() << ", Signal " << channels_[who]->get_signal().get_signal_str(); +#ifndef ENABLE_FPGA channels_[who]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[who]); + tmp_thread.detach(); +#endif } else { @@ -1275,7 +1361,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); +#ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[ch_index]); + tmp_thread.detach(); +#endif } DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; } @@ -1303,7 +1395,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); +#ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[ch_index]); + tmp_thread.detach(); +#endif } DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; } @@ -1332,7 +1430,13 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what) } acq_channels_count_++; DLOG(INFO) << "Channel " << ch_index << " Starting acquisition " << channels_[ch_index]->get_signal().get_satellite() << ", Signal " << channels_[ch_index]->get_signal().get_signal_str(); +#ifndef ENABLE_FPGA channels_[ch_index]->start_acquisition(); +#else + // create a task for the FPGA such that it doesn't stop the flow + std::thread tmp_thread(&ChannelInterface::start_acquisition, channels_[ch_index]); + tmp_thread.detach(); +#endif } DLOG(INFO) << "Channel " << ch_index << " in state " << channels_state_[ch_index]; } @@ -1412,6 +1516,7 @@ void GNSSFlowgraph::set_configuration(std::shared_ptr co configuration_ = std::move(configuration); } +#ifdef ENABLE_FPGA void GNSSFlowgraph::start_acquisition_helper() { @@ -1425,6 +1530,16 @@ void GNSSFlowgraph::start_acquisition_helper() } +void GNSSFlowgraph::perform_hw_reset() +{ + // a stop acquisition command causes the SW to reset the HW + std::shared_ptr channel_ptr; + channel_ptr = std::dynamic_pointer_cast(channels_.at(0)); + channel_ptr->acquisition()->stop_acquisition(); +} + +#endif + void GNSSFlowgraph::init() { /* diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index e0023b444..0a95eb60b 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -95,9 +95,11 @@ public: void disconnect(); void wait(); - +#ifdef ENABLE_FPGA void start_acquisition_helper(); + void perform_hw_reset(); +#endif /*! * \brief Applies an action to the flow graph * diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 2e200e73b..47da084f0 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -64,17 +64,15 @@ using google::LogMessage; DECLARE_string(log_dir); #if UNIT_TESTING_MINIMAL - #include "unit-tests/arithmetic/matio_test.cc" #if EXTRA_TESTS #include "unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc" #include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc" -#if ENABLE_FPGA +#if FPGA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc" -#endif +#endif // FPGA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc" -#endif - +#endif // EXTRA_TESTS #else @@ -160,12 +158,15 @@ DECLARE_string(log_dir); #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" #include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc" -#if ENABLE_FPGA +#if FPGA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc" -#endif +#endif // FPGA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc" +#if FPGA_BLOCKS_TEST +#include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc" +#endif // FPGA_BLOCKS_TEST #include "unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc" -#endif +#endif // EXTRA_TESTS #endif // UNIT_TESTING_MINIMAL diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc index 3021e15a1..e30e4fe5b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc @@ -94,7 +94,7 @@ DEFINE_bool(acq_test_dump, false, "Dump the results of an acquisition block into // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class AcqPerfTest_msg_rx; -typedef boost::shared_ptr AcqPerfTest_msg_rx_sptr; +using AcqPerfTest_msg_rx_sptr = boost::shared_ptr; AcqPerfTest_msg_rx_sptr AcqPerfTest_msg_rx_make(Concurrent_Queue& queue); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc index 9cd20eefe..86602ec9c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc @@ -57,7 +57,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GlonassL1CaPcpsAcquisitionTest_msg_rx; -typedef boost::shared_ptr GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr; +using GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr = boost::shared_ptr; GlonassL1CaPcpsAcquisitionTest_msg_rx_sptr GlonassL1CaPcpsAcquisitionTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc index fd0da8297..458f53f3f 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc @@ -176,7 +176,7 @@ void thread_acquisition_send_rx_samples(gr::top_block_sptr top_block, // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CaPcpsAcquisitionTestFpga_msg_rx; -typedef boost::shared_ptr GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr; +using GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr = boost::shared_ptr; GpsL1CaPcpsAcquisitionTest_msg_fpga_rx_sptr GpsL1CaPcpsAcquisitionTestFpga_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc index add12d00b..0ade6eb89 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc @@ -63,7 +63,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL2MPcpsAcquisitionTest_msg_rx; -typedef boost::shared_ptr GpsL2MPcpsAcquisitionTest_msg_rx_sptr; +using GpsL2MPcpsAcquisitionTest_msg_rx_sptr = boost::shared_ptr; GpsL2MPcpsAcquisitionTest_msg_rx_sptr GpsL2MPcpsAcquisitionTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc index cee43548b..497805de7 100644 --- a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc @@ -91,7 +91,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER FOR TRACKING MESSAGES ######### class HybridObservablesTest_msg_rx; -typedef boost::shared_ptr HybridObservablesTest_msg_rx_sptr; +using HybridObservablesTest_msg_rx_sptr = boost::shared_ptr; HybridObservablesTest_msg_rx_sptr HybridObservablesTest_msg_rx_make(); @@ -142,7 +142,7 @@ HybridObservablesTest_msg_rx::~HybridObservablesTest_msg_rx() = default; // ######## GNURADIO BLOCK MESSAGE RECEVER FOR TLM MESSAGES ######### class HybridObservablesTest_tlm_msg_rx; -typedef boost::shared_ptr HybridObservablesTest_tlm_msg_rx_sptr; +using HybridObservablesTest_tlm_msg_rx_sptr = boost::shared_ptr; HybridObservablesTest_tlm_msg_rx_sptr HybridObservablesTest_tlm_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc new file mode 100644 index 000000000..5d87e5133 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc @@ -0,0 +1,1974 @@ +/*! + * \file hybrid_observables_test_fpga.cc + * \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking + * implementation based on some input parameters. + * \author Javier Arribas, 2019. jarribas(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2012-2019 (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 "GPS_L1_CA.h" +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "gnss_satellite.h" +#include "gnss_sdr_fpga_sample_counter.h" +#include "gnss_synchro.h" +#include "gnuplot_i.h" +#include "gps_l1_ca_dll_pll_tracking.h" +#include "gps_l1_ca_dll_pll_tracking_fpga.h" +#include "gps_l1_ca_telemetry_decoder.h" +#include "hybrid_observables.h" +#include "in_memory_configuration.h" +#include "observable_tests_flags.h" +#include "observables_dump_reader.h" +#include "signal_generator_flags.h" +#include "telemetry_decoder_interface.h" +#include "test_flags.h" +#include "tlm_dump_reader.h" +#include "tracking_dump_reader.h" +#include "tracking_interface.h" +#include "tracking_tests_flags.h" +#include "tracking_true_obs_reader.h" +#include "true_observables_reader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// threads +#include // for open, O_RDWR, O_SYNC +#include // for cout, endl +#include // for pthread stuff +#include // for mmap +#include + +#define TEST_OBS_MAX_INPUT_COMPLEX_SAMPLES_TOTAL 8192 // maximum DMA sample block size in complex samples +#define TEST_OBS_COMPLEX_SAMPLE_SIZE 2 // sample size in bytes +#define TEST_OBS_NUM_QUEUES 2 // number of queues (1 for GPS L1/Galileo E1, and 1 for GPS L5/Galileo E5) +#define TEST_OBS_DOWNAMPLING_FILTER_INIT_SAMPLES 100 // some samples to initialize the state of the downsampling filter +#define TEST_OBS_DOWNSAMPLING_FILTER_DELAY 48 + + +// HW related options +bool test_observables_show_results_table = false; // 1 => show matrix of (doppler, (max value, power sum)) results (only if test_observables_doppler_control_in_sw = 1), 0=> do not show it +bool test_observables_skip_samples_already_used = true; // if test_observables_doppler_control_in_sw = 1 and test_observables_skip_samples_already_used = 1 => for each PRN loop skip the samples used in the previous PRN loops + // (exactly in the same way as the SW) + +class HybridObservablesTest_msg_rx_Fpga; + +using HybridObservablesTest_msg_rx_Fpga_sptr = boost::shared_ptr; + +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(); + void msg_handler_events(pmt::pmt_t msg); + HybridObservablesTest_msg_rx_Fpga(); + +public: + int rx_message; + ~HybridObservablesTest_msg_rx_Fpga(); //!< Default destructor +}; + +HybridObservablesTest_msg_rx_Fpga_sptr HybridObservablesTest_msg_rx_Fpga_make() +{ + return HybridObservablesTest_msg_rx_Fpga_sptr(new HybridObservablesTest_msg_rx_Fpga()); +} + +void HybridObservablesTest_msg_rx_Fpga::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(std::move(msg)); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +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")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&HybridObservablesTest_msg_rx_Fpga::msg_handler_events, this, _1)); + rx_message = 0; +} + +HybridObservablesTest_msg_rx_Fpga::~HybridObservablesTest_msg_rx_Fpga() = default; + + +class HybridObservablesTest_tlm_msg_rx_Fpga; + +using HybridObservablesTest_tlm_msg_rx_Fpga_sptr = boost::shared_ptr; + +HybridObservablesTest_tlm_msg_rx_Fpga_sptr HybridObservablesTest_tlm_msg_rx_Fpga_make(); + +class HybridObservablesTest_tlm_msg_rx_Fpga : public gr::block +{ +private: + friend HybridObservablesTest_tlm_msg_rx_Fpga_sptr HybridObservablesTest_tlm_msg_rx_Fpga_make(); + void msg_handler_events(pmt::pmt_t msg); + HybridObservablesTest_tlm_msg_rx_Fpga(); + +public: + int rx_message; + ~HybridObservablesTest_tlm_msg_rx_Fpga(); //!< Default destructor +}; + +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()); +} + +void HybridObservablesTest_tlm_msg_rx_Fpga::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(std::move(msg)); + rx_message = message; + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_telemetry Bad any cast!"; + rx_message = 0; + } +} + +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")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&HybridObservablesTest_tlm_msg_rx_Fpga::msg_handler_events, this, _1)); + rx_message = 0; +} + +HybridObservablesTest_tlm_msg_rx_Fpga::~HybridObservablesTest_tlm_msg_rx_Fpga() = default; + +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; + 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; + + int configure_generator(); + int generate_signal(); + bool save_mat_xy(std::vector& x, std::vector& y, std::string filename); + void check_results_carrier_phase( + arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + const std::string& data_title); + 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, + const std::string& data_title); + void check_results_carrier_doppler(arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + const std::string& data_title); + 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, + const std::string& data_title); + 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, + const std::string& data_title); + + HybridObservablesTestFpga() + { + factory = std::make_shared(); + config = std::make_shared(); + item_size = sizeof(gr_complex); + } + + ~HybridObservablesTestFpga() = default; + + bool ReadRinexObs(std::vector* 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, + int extend_correlation_symbols); + + gr::top_block_sptr top_block; + std::shared_ptr factory; + std::shared_ptr config; + Gnss_Synchro gnss_synchro_master; + std::vector gnss_synchro_vec; + size_t item_size; +}; + +int HybridObservablesTestFpga::configure_generator() +{ + // 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 + p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); //Baseband sampling frequency [MSps] + return 0; +} + + +int HybridObservablesTestFpga::generate_signal() +{ + int child_status; + + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], nullptr}; + + int pid; + if ((pid = fork()) == -1) + perror("fork err"); + else if (pid == 0) + { + execv(&generator_binary[0], parmList); + std::cout << "Return not expected. Must be an execv err." << std::endl; + std::terminate(); + } + + waitpid(pid, &child_status, 0); + + std::cout << "Signal and Observables RINEX and RAW files created." << std::endl; + return 0; +} + + +const size_t TEST_OBS_PAGE_SIZE = 0x10000; +const unsigned int TEST_OBS_TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; + +void setup_fpga_switch_obs_test(void) +{ + int switch_device_descriptor; // driver descriptor + volatile unsigned* switch_map_base; // driver memory map + + if ((switch_device_descriptor = open("/dev/uio1", O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" + << "/dev/uio1"; + } + switch_map_base = reinterpret_cast(mmap(nullptr, TEST_OBS_PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, switch_device_descriptor, 0)); + + if (switch_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA switch module into tracking memory"; + std::cout << "Could not map switch memory." << std::endl; + } + + // sanity check : check test register + unsigned writeval = TEST_OBS_TEST_REGISTER_TRACK_WRITEVAL; + unsigned readval; + // write value to test register + switch_map_base[3] = writeval; + // read value from test register + readval = switch_map_base[3]; + + if (writeval != readval) + { + LOG(WARNING) << "Test register sanity check failed"; + } + else + { + LOG(INFO) << "Test register sanity check success !"; + } + + switch_map_base[0] = 0; //0 -> DMA to queue 0, 1 -> DMA to queue 1, 2 -> A/Ds to queues +} + + +static pthread_mutex_t mutex_obs_test = PTHREAD_MUTEX_INITIALIZER; + +volatile unsigned int send_samples_start_obs_test = 0; + +int8_t input_samples_obs_test[TEST_OBS_MAX_INPUT_COMPLEX_SAMPLES_TOTAL * TEST_OBS_COMPLEX_SAMPLE_SIZE]; // re - im +int8_t input_samples_dma_obs_test[TEST_OBS_MAX_INPUT_COMPLEX_SAMPLES_TOTAL * TEST_OBS_COMPLEX_SAMPLE_SIZE * TEST_OBS_NUM_QUEUES]; + +struct DMA_handler_args_obs_test +{ + std::string file; + unsigned int nsamples_tx; + unsigned int skip_used_samples; + unsigned int freq_band; // 0 for GPS L1/ Galileo E1, 1 for GPS L5/Galileo E5 +}; + +void* handler_DMA_obs_test(void* arguments) +{ + // DMA process that configures the DMA to send the samples to the acquisition engine + int tx_fd; // DMA descriptor + FILE* rx_signal_file_id; // Input file descriptor + bool file_completed = false; // flag to indicate if the file is completed + unsigned int nsamples_block; // number of samples to send in the next DMA block of samples + unsigned int nread_elements; // number of elements effectively read from the input file + unsigned int nsamples = 0; // number of complex samples effectively transferred + unsigned int index0, dma_index = 0; // counters used for putting the samples in the order expected by the DMA + + unsigned int nsamples_transmitted; + + auto* args = (struct DMA_handler_args*)arguments; + + unsigned int nsamples_tx = args->nsamples_tx; + std::string file = args->file; // input filename + unsigned int skip_used_samples = args->skip_used_samples; + + // open DMA device + tx_fd = open("/dev/loop_tx", O_WRONLY); + if (tx_fd < 0) + { + std::cout << "DMA can't open loop device" << std::endl; + exit(1); + } + else + + // open input file + rx_signal_file_id = fopen(file.c_str(), "rb"); + if (rx_signal_file_id == nullptr) + { + std::cout << "DMA can't open input file" << std::endl; + exit(1); + } + while (send_samples_start_obs_test == 0) + ; // wait until acquisition starts + // skip initial samples + int skip_samples = (int)FLAGS_skip_samples; + + fseek(rx_signal_file_id, (skip_samples + skip_used_samples) * 2, SEEK_SET); + + usleep(50000); // wait some time to give time to the main thread to start the acquisition module + + while (file_completed == false) + { + if (nsamples_tx - nsamples > TEST_OBS_MAX_INPUT_COMPLEX_SAMPLES_TOTAL) + { + nsamples_block = TEST_OBS_MAX_INPUT_COMPLEX_SAMPLES_TOTAL; + } + else + { + nsamples_block = nsamples_tx - nsamples; // remaining samples to be sent + file_completed = true; + } + + nread_elements = fread(input_samples_obs_test, sizeof(int8_t), nsamples_block * TEST_OBS_COMPLEX_SAMPLE_SIZE, rx_signal_file_id); + + if (nread_elements != nsamples_block * TEST_OBS_COMPLEX_SAMPLE_SIZE) + { + std::cout << "file completed" << std::endl; + file_completed = true; + } + + nsamples += (nread_elements / TEST_OBS_COMPLEX_SAMPLE_SIZE); + + if (nread_elements > 0) + { + // for the 32-BIT DMA + dma_index = 0; + for (index0 = 0; index0 < (nread_elements); index0 += TEST_OBS_COMPLEX_SAMPLE_SIZE) + { + if (args->freq_band == 0) + { + // channel 1 (queue 1) -> E5/L5 + input_samples_dma_obs_test[dma_index] = 0; + input_samples_dma_obs_test[dma_index + 1] = 0; + // channel 0 (queue 0) -> E1/L1 + input_samples_dma_obs_test[dma_index + 2] = input_samples_obs_test[index0]; + input_samples_dma_obs_test[dma_index + 3] = input_samples_obs_test[index0 + 1]; + } + else + { + // channel 1 (queue 1) -> E5/L5 + input_samples_dma_obs_test[dma_index] = input_samples_obs_test[index0]; + input_samples_dma_obs_test[dma_index + 1] = input_samples_obs_test[index0 + 1]; + // channel 0 (queue 0) -> E1/L1 + input_samples_dma_obs_test[dma_index + 2] = 0; + input_samples_dma_obs_test[dma_index + 3] = 0; + } + dma_index += 4; + } + nsamples_transmitted = write(tx_fd, &input_samples_dma_obs_test[0], nread_elements * TEST_OBS_NUM_QUEUES); + if (nsamples_transmitted != nread_elements * TEST_OBS_NUM_QUEUES) + { + std::cout << "Error : DMA could not send all the requested samples" << std::endl; + } + } + } + + + close(tx_fd); + fclose(rx_signal_file_id); + return nullptr; +} + + +bool HybridObservablesTestFpga::acquire_signal() +{ + pthread_t thread_DMA; + + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) + gr::top_block_sptr top_block; + top_block = gr::make_top_block("Acquisition test"); + int SV_ID = 1; //initial sv id + + // Satellite signal definition + Gnss_Synchro tmp_gnss_synchro; + tmp_gnss_synchro.Channel_ID = 0; + config = std::make_shared(); + config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); + + std::shared_ptr acquisition; + + std::string System_and_Signal; + + struct DMA_handler_args_obs_test args; + + //create the correspondign acquisition block according to the desired tracking signal + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + tmp_gnss_synchro.System = 'G'; + std::string signal = "1C"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L1 CA"; + + args.freq_band = 0; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + tmp_gnss_synchro.System = 'E'; + std::string signal = "1B"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E1B"; + + args.freq_band = 0; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + } + + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + tmp_gnss_synchro.System = 'E'; + std::string signal = "5X"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "Galileo E5a"; + + args.freq_band = 1; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + } + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + { + tmp_gnss_synchro.System = 'G'; + std::string signal = "L5"; + signal.copy(tmp_gnss_synchro.Signal, 2, 0); + tmp_gnss_synchro.PRN = SV_ID; + System_and_Signal = "GPS L5I"; + + args.freq_band = 1; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + } + else + { + std::cout << "The test can not run with the selected tracking implementation\n "; + throw(std::exception()); + } + + acquisition->set_channel(0); + acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); + acquisition->connect(top_block); + + std::string file = FLAGS_signal_file; + + 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); + } + + msg_rx->top_block = top_block; + + top_block->msg_connect(acquisition->get_right_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; + + 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; + } + + setup_fpga_switch_obs_test(); + + unsigned int nsamples_to_transfer; + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_HZ / GALILEO_E5A_CODE_LENGTH_CHIPS))); + } + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_HZ / GPS_L5I_CODE_LENGTH_CHIPS))); + } + + int acq_doppler_max = config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz); + int acq_doppler_step = config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz); + + + for (unsigned int PRN = 1; PRN < MAX_PRN_IDX; PRN++) + { + tmp_gnss_synchro.PRN = PRN; + + acquisition->stop_acquisition(); // reset the whole system including the sample counters + acquisition->set_doppler_max(acq_doppler_max); + acquisition->set_doppler_step(acq_doppler_step); + acquisition->set_gnss_synchro(&tmp_gnss_synchro); + acquisition->init(); + acquisition->set_local_code(); + + args.file = file; + + + send_samples_start_obs_test = 0; + + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + { + args.skip_used_samples = -TEST_OBS_DOWNAMPLING_FILTER_INIT_SAMPLES; + + args.nsamples_tx = TEST_OBS_DOWNAMPLING_FILTER_INIT_SAMPLES + TEST_OBS_DOWNSAMPLING_FILTER_DELAY; + + if (pthread_create(&thread_DMA, nullptr, handler_DMA_obs_test, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + pthread_mutex_lock(&mutex); + send_samples_start_obs_test = 1; + pthread_mutex_unlock(&mutex); + pthread_join(thread_DMA, nullptr); + send_samples_start_obs_test = 0; + + args.nsamples_tx = nsamples_to_transfer; + + args.skip_used_samples = TEST_OBS_DOWNSAMPLING_FILTER_DELAY; + } + else + { + args.nsamples_tx = nsamples_to_transfer; + + args.skip_used_samples = 0; + } + + + // create DMA child process + if (pthread_create(&thread_DMA, nullptr, handler_DMA_obs_test, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + + msg_rx->rx_message = 0; + top_block->start(); + + pthread_mutex_lock(&mutex); + send_samples_start_obs_test = 1; + pthread_mutex_unlock(&mutex); + + acquisition->reset(); // set active + + if (start_msg == true) + { + std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; + std::cout << "Searching for " << System_and_Signal << " Satellites..." << std::endl; + std::cout << "["; + start_msg = false; + } + + // wait for the child DMA process to finish + pthread_join(thread_DMA, nullptr); + + pthread_mutex_lock(&mutex); + send_samples_start_obs_test = 0; + pthread_mutex_unlock(&mutex); + + // the DMA sends the exact number of samples needed for the acquisition. + // however because of the LPF in the GPS L1/Gal E1 acquisition, this calculation is approximate + // and some extra samples might be sent. Wait at least once to give time the HW to consume any extra + // sample the DMA might have sent. + do + { + usleep(100000); + } + while (msg_rx->rx_message == 0); + + if (msg_rx->rx_message == 1) + { + std::cout << " " << PRN << " "; + + tmp_gnss_synchro.Acq_doppler_hz = tmp_gnss_synchro.Acq_doppler_hz; + tmp_gnss_synchro.Acq_delay_samples = tmp_gnss_synchro.Acq_delay_samples; + tmp_gnss_synchro.Acq_samplestamp_samples = 0; // do not take into account the filter internal state initialisation + tmp_gnss_synchro.Acq_samplestamp_samples = tmp_gnss_synchro.Acq_samplestamp_samples; // delay due to the downsampling filter in the acquisition + + + gnss_synchro_vec.push_back(tmp_gnss_synchro); + } + else + { + std::cout << " . "; + } + + + top_block->stop(); + + + std::cout.flush(); + } + std::cout << "]" << std::endl; + 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() + << " [seconds]" << std::endl; + if (!gnss_synchro_vec.empty()) + { + return true; + } + else + { + return false; + } + + + return true; +} + + +void HybridObservablesTestFpga::configure_receiver( + double PLL_wide_bw_hz, + double DLL_wide_bw_hz, + double PLL_narrow_bw_hz, + double DLL_narrow_bw_hz, + int extend_correlation_symbols) +{ + config = std::make_shared(); + config->set_property("Tracking.dump", "true"); + config->set_property("Tracking.dump_filename", "./tracking_ch_"); + config->set_property("Tracking.implementation", implementation); + config->set_property("Tracking.item_type", "gr_complex"); + 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)); + 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; + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + 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(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"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); + + config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + 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(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"); + config->set_property("Tracking.very_early_late_space_chips", "0.6"); + config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); + config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); + config->set_property("Tracking.track_pilot", "true"); + + config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + { + 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(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"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + + config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); + } + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + { + 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(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"); + config->set_property("Tracking.track_pilot", "true"); + config->set_property("Tracking.order", "2"); + + 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"; + 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"; + std::cout << "*****************************************\n"; + std::cout << "*****************************************\n"; +} + +void HybridObservablesTestFpga::check_results_carrier_phase( + arma::mat& true_ch0, + arma::vec& true_tow_s, + arma::mat& measured_ch0, + const std::string& data_title) +{ + //1. True value interpolation to match the measurement times + + 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(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector 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); + + //2. RMSE + arma::vec err_ch0_cycles; + + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + 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)); + + //3. Mean err and variance + 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); + + //5. report + 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 + << " [cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + 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]"); + //conversion between arma::vec and std:vector + std::vector 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 + } + + //check results against the test tolerance + 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, + const std::string& data_title) +{ + //1. True value interpolation to match the measurement times + + 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(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector 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 + //compute error without the accumulated carrier phase offsets (which depends on the receiver starting time) + 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)); + + //2. RMSE + 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)); + + //3. Mean err and variance + 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); + + //5. report + 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 + << " [Cycles]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + 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]"); + //conversion between arma::vec and std:vector + std::vector 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 + } + + //check results against the test tolerance + 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, + const std::string& data_title) +{ + //1. True value interpolation to match the measurement times + + 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(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector 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; + + //2. RMSE + 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)); + + //3. Mean err and variance + 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); + + //5. report + 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 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + 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]"); + //conversion between arma::vec and std:vector + std::vector 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 + } + + //check results against the test tolerance + ASSERT_LT(error_mean, 5); + ASSERT_GT(error_mean, -5); + //assuming PLL BW=35 + 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, + const std::string& data_title) +{ + //1. True value interpolation to match the measurement times + + 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(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector 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); + + //2. RMSE + arma::vec err_ch0_hz; + + //compute error + 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)); + + //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 + << " [Hz]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + 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 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 + ASSERT_LT(error_mean_ch0, 5); + ASSERT_GT(error_mean_ch0, -5); + //assuming PLL BW=35 + ASSERT_LT(error_var_ch0, 200); + ASSERT_LT(max_error_ch0, 70); + ASSERT_GT(min_error_ch0, -70); + ASSERT_LT(rmse_ch0, 30); +} + +bool HybridObservablesTestFpga::save_mat_xy(std::vector& x, std::vector& y, std::string filename) +{ + try + { + // WRITE MAT FILE + mat_t* matfp; + matvar_t* matvar; + filename.append(".mat"); + std::cout << "save_mat_xy write " << filename << std::endl; + matfp = Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT5); + if (reinterpret_cast(matfp) != nullptr) + { + 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 + { + std::cout << "save_mat_xy: error creating file" << std::endl; + } + Mat_Close(matfp); + return true; + } + catch (const std::exception& ex) + { + std::cout << "save_mat_xy: " << ex.what() << std::endl; + return false; + } +} + +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, + const std::string& data_title) +{ + //1. True value interpolation to match the measurement times + + 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(t0, t1, floor((t1 - t0) * 1e3)); + //conversion between arma::vec and std:vector + arma::vec t_from_start = arma::linspace(0, t1 - t0, floor((t1 - t0) * 1e3)); + std::vector 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; + + //2. RMSE + arma::vec err; + + err = delta_measured_dist_m - delta_true_dist_m; + arma::vec err2 = arma::square(err); + double rmse = sqrt(arma::mean(err2)); + + //3. Mean err and variance + 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); + + //5. report + 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 + << " [meters]" << std::endl; + std::cout.precision(ss); + + //plots + if (FLAGS_show_plots) + { + 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]"); + //conversion between arma::vec and std:vector + std::vector 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 + } + + //check results against the test tolerance + 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); +} + +bool HybridObservablesTestFpga::ReadRinexObs(std::vector* obs_vec, Gnss_Synchro gnss) +{ + // Open and read reference RINEX observables file + try + { + gpstk::Rinex3ObsStream r_ref(FLAGS_filename_rinex_obs); + r_ref.exceptions(std::ios::failbit); + gpstk::Rinex3ObsData r_ref_data; + gpstk::Rinex3ObsHeader r_ref_header; + + gpstk::RinexDatum dataobj; + + r_ref >> r_ref_header; + + std::vector first_row; + gpstk::SatID prn; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + first_row.push_back(true); + obs_vec->push_back(arma::zeros(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': + prn = gpstk::SatID(myprn, gpstk::SatID::systemGPS); + break; + case 'E': + prn = gpstk::SatID(myprn, gpstk::SatID::systemGalileo); + break; + default: + prn = gpstk::SatID(myprn, gpstk::SatID::systemGPS); + } + + gpstk::CommonTime time = r_ref_data.time; + double sow(static_cast(time).sow); + + auto pointer = r_ref_data.obs.find(prn); + if (pointer == r_ref_data.obs.end()) + { + // PRN not present; do nothing + } + else + { + if (first_row.at(n) == false) + { + //insert next column + 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); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 1) = dataobj.data; //C1C P1 (psudorange L1) + dataobj = r_ref_data.getObs(prn, "D1C", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 2) = dataobj.data; //D1C Carrier Doppler + dataobj = r_ref_data.getObs(prn, "L1C", r_ref_header); + obs_vec->at(n)(obs_vec->at(n).n_rows - 1, 3) = dataobj.data; //L1C Carrier Phase + } + 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; + } + else if (strcmp("2S\0", gnss.Signal) == 0) //L2M + { + 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; + } + else if (strcmp("5X\0", gnss.Signal) == 0) //Simulator gives RINEX with E5a+E5b + { + 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 + { + std::cout << "ReadRinexObs unknown signal requested: " << gnss.Signal << std::endl; + return false; + } + } + } + } // end while + } // End of 'try' block + catch (const gpstk::FFStreamError& e) + { + std::cout << e; + return false; + } + catch (const gpstk::Exception& e) + { + std::cout << e; + return false; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what(); + std::cout << "unknown error. I don't feel so well..." << std::endl; + return false; + } + std::cout << "ReadRinexObs info:" << std::endl; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + std::cout << "SAT PRN " << gnss_synchro_vec.at(n).PRN << " RINEX epoch readed: " << obs_vec->at(n).n_rows << std::endl; + } + return true; +} +TEST_F(HybridObservablesTestFpga, ValidationOfResults) +{ + // pointer to the DMA thread that sends the samples to the acquisition engine + pthread_t thread_DMA; + + struct DMA_handler_args_obs_test args; + + // Configure the signal generator + configure_generator(); + + // Generate signal raw signal samples and observations RINEX file + if (FLAGS_disable_generator == false) + { + generate_signal(); + } + + + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + + // use generator or use an external capture file + if (FLAGS_enable_external_signal_file) + { + //create and configure an acquisition block and perform an acquisition to obtain the synchronization parameters + 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); + + std::istringstream ss(FLAGS_test_satellite_PRN_list); + std::string token; + + while (std::getline(ss, token, ',')) + { + tmp_gnss_synchro.PRN = boost::lexical_cast(token); + gnss_synchro_vec.push_back(tmp_gnss_synchro); + } + } + + configure_receiver(FLAGS_PLL_bw_hz_start, + FLAGS_DLL_bw_hz_start, + FLAGS_PLL_narrow_bw_hz, + FLAGS_DLL_narrow_bw_hz, + FLAGS_extend_correlation_symbols); + + for (auto& n : gnss_synchro_vec) + { + //setup the signal synchronization, simulating an acquisition + if (!FLAGS_enable_external_signal_file) + { + //based on true observables metadata (for custom sdr generator) + //open true observables log file written by the simulator or based on provided RINEX obs + //std::vector> true_reader_vec; + std::vector> true_reader_vec; + //read true data from the generator logs + true_reader_vec.push_back(std::make_shared()); + std::cout << "Loading true observable data for PRN " << n.PRN << std::endl; + std::string true_obs_file = std::string("./gps_l1_ca_obs_prn"); + true_obs_file.append(std::to_string(n.PRN)); + 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"; + + //restart the epoch counter + true_reader_vec.back()->restart(); + + std::cout << "Initial Doppler [Hz]=" << true_reader_vec.back()->doppler_l1_hz << " Initial code delay [Chips]=" + << true_reader_vec.back()->prn_delay_chips << std::endl; + 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; + n.Acq_doppler_hz = true_reader_vec.back()->doppler_l1_hz; + n.Acq_samplestamp_samples = 0; + } + else + { + //based on the signal acquisition process + std::cout << "Estimated Initial Doppler " << n.Acq_doppler_hz + << " [Hz], estimated Initial code delay " << n.Acq_delay_samples << " [Samples]" + << " Acquisition SampleStamp is " << n.Acq_samplestamp_samples << std::endl; + } + } + + + // The HW has been reset after the acquisition phase when the acquisition class was destroyed. + // No more samples remained in the DMA. Therefore any intermediate state in the LPF of the + // GPS L1 / Galileo E1 filter has been cleared. + // During this test all the samples coming from the DMA are consumed so in principle there would be + // no need to reset the HW. However we need to clear the sample counter in each test. Therefore we have + // to reset the HW at the beginning of each test. + + // instantiate the acquisition modules in order to use them to reset the HW. + // (note that the constructor of the acquisition modules resets the HW too) + + + std::shared_ptr acquisition; + + // reset the HW to clear the sample counters: the acquisition constructor generates a reset + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 0; + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 0; + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 1; + } + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(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()); + } + + + std::vector> tracking_ch_vec; + std::vector> tlm_ch_vec; + + std::vector null_sink_vec; + for (unsigned int n = 0; n < gnss_synchro_vec.size(); n++) + { + //set channels ids + gnss_synchro_vec.at(n).Channel_ID = n; + + //create the tracking channels and create the telemetry decoders + + std::shared_ptr trk_ = factory->GetBlock(config, "Tracking", config->property("Tracking.implementation", std::string("undefined")), 1, 1); + tracking_ch_vec.push_back(std::dynamic_pointer_cast(trk_)); + std::shared_ptr tlm_ = factory->GetBlock(config, "TelemetryDecoder", config->property("TelemetryDecoder.implementation", std::string("undefined")), 1, 1); + tlm_ch_vec.push_back(std::dynamic_pointer_cast(tlm_)); + + //create null sinks for observables output + 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."; + } + + top_block = gr::make_top_block("Telemetry_Decoder test"); + boost::shared_ptr dummy_msg_rx_trk = HybridObservablesTest_msg_rx_Fpga_make(); + boost::shared_ptr dummy_tlm_msg_rx = HybridObservablesTest_tlm_msg_rx_Fpga_make(); + //Observables + std::shared_ptr observables(new HybridObservables(config.get(), "Observables", tracking_ch_vec.size() + 1, tracking_ch_vec.size())); + + for (auto& n : tracking_ch_vec) + { + ASSERT_NO_THROW({ + n->connect(top_block); + }) << "Failure connecting tracking to the top_block."; + } + + std::string file; + + ASSERT_NO_THROW({ + if (!FLAGS_enable_external_signal_file) + { + file = "./" + filename_raw_data; + } + else + { + file = FLAGS_signal_file; + } + int observable_interval_ms = 20; + + double fs = static_cast(config->property("GNSS-SDR.internal_fs_sps", 0)); + + 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); + + + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + //top_block->connect(gr_interleaved_char_to_complex, 0, tracking_ch_vec.at(n)->get_left_block(), 0); + 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); + } + //connect sample counter and timmer to the last channel in observables block (extra channel) + //top_block->connect(samp_counter, 0, observables->get_left_block(), tracking_ch_vec.size()); + top_block->connect(ch_out_fpga_sample_counter, 0, observables->get_left_block(), tracking_ch_vec.size()); //extra port for the sample counter pulse + }) << "Failure connecting the blocks."; + + + args.file = file; + args.nsamples_tx = baseband_sampling_freq * FLAGS_duration; + ; + + args.skip_used_samples = 0; + + if (pthread_create(&thread_DMA, nullptr, handler_DMA_obs_test, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + + + for (auto& n : tracking_ch_vec) + { + n->start_tracking(); + } + + pthread_mutex_lock(&mutex_obs_test); + send_samples_start_obs_test = 1; + pthread_mutex_unlock(&mutex_obs_test); + + + top_block->start(); + + + EXPECT_NO_THROW({ + start = std::chrono::system_clock::now(); + //top_block->run(); // Start threads and wait + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + }) << "Failure running the top_block."; + + + // wait for the child DMA process to finish + pthread_join(thread_DMA, nullptr); + + + top_block->stop(); + + + // reset the HW AGAIN + acquisition->stop_acquisition(); + + + // pthread_mutex_lock(&mutex_obs_test); + // send_samples_start_obs_test = 0; + // pthread_mutex_unlock(&mutex_obs_test); + + + //check results + // Matrices for storing columnwise true GPS time, Range, Doppler and Carrier phase + std::vector true_obs_vec; + + if (!FLAGS_enable_external_signal_file) + { + //load the true values + 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"; + + auto nepoch = static_cast(true_observables.num_epochs()); + + std::cout << "True observation epochs = " << nepoch << std::endl; + + 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(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: " + << round(true_observables.prn[n]) << " vs. " << gnss_synchro_vec.at(n).PRN << std::endl; + 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 + { + ASSERT_EQ(ReadRinexObs(&true_obs_vec, gnss_synchro_master), true) + << "Failure reading RINEX file"; + } + + + //read measured values + 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"; + + auto nepoch = static_cast(estimated_observables.num_epochs()); + std::cout << "Measured observations epochs = " << nepoch << std::endl; + + // Matrices for storing columnwise measured RX_time, TOW, Doppler, Carrier phase and Pseudorange + std::vector measured_obs_vec; + std::vector epoch_counters_vec; + for (unsigned int n = 0; n < tracking_ch_vec.size(); n++) + { + measured_obs_vec.push_back(arma::zeros(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(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)++; + } + } + } + + + //Cut measurement tail zeros + arma::uvec index; + for (auto& n : measured_obs_vec) + { + index = arma::find(n.col(0) > 0.0, 1, "last"); + if ((!index.empty()) and index(0) < (nepoch - 1)) + { + n.shed_rows(index(0) + 1, nepoch - 1); + } + } + + //Cut measurement initial transitory of the measurements + + double initial_transitory_s = FLAGS_skip_obs_transitory_s; + + 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"); + if ((!index.empty()) and (index(0) > 0)) + { + measured_obs_vec.at(n).shed_rows(0, index(0)); + } + + 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)); + } + } + + + //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) + + //Find the reference satellite (the nearest) and compute the receiver time offset at observable level + double min_pr = std::numeric_limits::max(); + unsigned int min_pr_ch_id = 0; + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + if (epoch_counters_vec.at(n) > 10) //discard non-valid channels + { + { + if (measured_obs_vec.at(n)(0, 4) < min_pr) + { + min_pr = measured_obs_vec.at(n)(0, 4); + min_pr_ch_id = n; + } + } + } + else + { + std::cout << "PRN " << gnss_synchro_vec.at(n).PRN << " has NO observations!\n"; + } + } + + arma::vec receiver_time_offset_ref_channel_s; + //receiver_time_offset_ref_channel_s = true_obs_vec.at(min_pr_ch_id).col(1) / GPS_C_m_s - GPS_STARTOFFSET_ms / 1000.0; + receiver_time_offset_ref_channel_s = (true_obs_vec.at(min_pr_ch_id).col(1)(0) - measured_obs_vec.at(min_pr_ch_id).col(4)(0)) / GPS_C_M_S; + std::cout << "Ref channel initial Receiver time offset " << receiver_time_offset_ref_channel_s(0) * 1e3 << " [ms]" << std::endl; + + for (unsigned int n = 0; n < measured_obs_vec.size(); n++) + { + //debug save to .mat + std::vector 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 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 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 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 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 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 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 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))); + + if (epoch_counters_vec.at(n) > 10) //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) + " "); + 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 + { + std::cout << "[CH " << std::to_string(n) << "] PRN " << std::to_string(gnss_synchro_vec.at(n).PRN) << " is the reference satellite" << std::endl; + } + if (FLAGS_compute_single_diffs) + { + 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"; + } + } + + + std::cout << "Test completed in " << elapsed_seconds.count() << " [s]" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc index be7963164..9271f669b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc @@ -67,7 +67,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER FOR TRACKING MESSAGES ######### class GpsL1CADllPllTelemetryDecoderTest_msg_rx; -typedef boost::shared_ptr GpsL1CADllPllTelemetryDecoderTest_msg_rx_sptr; +using GpsL1CADllPllTelemetryDecoderTest_msg_rx_sptr = boost::shared_ptr; GpsL1CADllPllTelemetryDecoderTest_msg_rx_sptr GpsL1CADllPllTelemetryDecoderTest_msg_rx_make(); @@ -118,7 +118,7 @@ GpsL1CADllPllTelemetryDecoderTest_msg_rx::~GpsL1CADllPllTelemetryDecoderTest_msg // ######## GNURADIO BLOCK MESSAGE RECEVER FOR TLM MESSAGES ######### class GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx; -typedef boost::shared_ptr GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_sptr; +using GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_sptr = boost::shared_ptr; GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_sptr GpsL1CADllPllTelemetryDecoderTest_tlm_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc index 982eda0ee..d440cb905 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc @@ -63,7 +63,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CADllPllTrackingTest_msg_rx; -typedef boost::shared_ptr GpsL1CADllPllTrackingTest_msg_rx_sptr; +using GpsL1CADllPllTrackingTest_msg_rx_sptr = boost::shared_ptr; GpsL1CADllPllTrackingTest_msg_rx_sptr GpsL1CADllPllTrackingTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc index f1046a12b..7422aa286 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc @@ -65,7 +65,7 @@ DEFINE_bool(plot_gps_l1_kf_tracking_test, false, "Plots results of GpsL1CAKfTrac // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL1CAKfTrackingTest_msg_rx; -typedef boost::shared_ptr GpsL1CAKfTrackingTest_msg_rx_sptr; +using GpsL1CAKfTrackingTest_msg_rx_sptr = boost::shared_ptr; GpsL1CAKfTrackingTest_msg_rx_sptr GpsL1CAKfTrackingTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc index 3b6b325a4..a640db425 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc @@ -57,7 +57,7 @@ // ######## GNURADIO BLOCK MESSAGE RECEVER ######### class GpsL2MDllPllTrackingTest_msg_rx; -typedef boost::shared_ptr GpsL2MDllPllTrackingTest_msg_rx_sptr; +using GpsL2MDllPllTrackingTest_msg_rx_sptr = boost::shared_ptr; GpsL2MDllPllTrackingTest_msg_rx_sptr GpsL2MDllPllTrackingTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc index 306ad74fd..05787d5bd 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc @@ -79,7 +79,7 @@ // ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER ######### class TrackingPullInTest_msg_rx; -typedef boost::shared_ptr TrackingPullInTest_msg_rx_sptr; +using TrackingPullInTest_msg_rx_sptr = boost::shared_ptr; TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make(); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc index 0904d2047..a2546b400 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc @@ -1,13 +1,13 @@ /*! - * \file tracking_test.cc - * \brief This class implements a tracking Pull-In test for GPS_L1_CA_DLL_PLL_Tracking - * implementation based on some input parameters. - * \author Javier Arribas, 2018. jarribas(at)cttc.es + * \file tracking_pull-in_test_fpga.cc + * \brief This class implements a tracking Pull-In test for FPGA HW accelerator + * implementations based on some input parameters. + * \author Marc Majoral, 2019. majoralmarc(at)cttc.es + * Javier Arribas, 2018. jarribas(at)cttc.es * * * ------------------------------------------------------------------------- - * - * Copyright (C) 2012-2018 (see AUTHORS file for a list of contributors) + * Copyright (C) 2012-2019 (see AUTHORS file for a list of contributors) * * GNSS-SDR is a software defined Global Navigation * Satellite Systems receiver @@ -32,14 +32,13 @@ #include "GPS_L1_CA.h" #include "acquisition_msg_rx.h" +#include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" #include "galileo_e5a_noncoherent_iq_acquisition_caf.h" #include "galileo_e5a_pcps_acquisition.h" +#include "galileo_e5a_pcps_acquisition_fpga.h" #include "gnss_block_factory.h" -#include "gnuplot_i.h" -#include "gps_l1_ca_pcps_acquisition.h" -#include "gps_l1_ca_pcps_acquisition_fine_doppler.h" -#include "gps_l2_m_pcps_acquisition.h" -#include "gps_l5i_pcps_acquisition.h" +#include "gps_l1_ca_pcps_acquisition_fpga.h" +#include "gps_l5i_pcps_acquisition_fpga.h" #include "in_memory_configuration.h" #include "signal_generator_flags.h" #include "test_flags.h" @@ -58,13 +57,77 @@ #include #include #include +#include #include +// threads +#include // for open, O_RDWR, O_SYNC +#include // for cout, endl +#include // for pthread stuff +#include // for mmap + +#define MAX_INPUT_COMPLEX_SAMPLES_TOTAL 8192 // maximum DMA sample block size in complex samples +#define COMPLEX_SAMPLE_SIZE 2 // sample size in bytes +#define NUM_QUEUES 2 // number of queues (1 for GPS L1/Galileo E1, and 1 for GPS L5/Galileo E5) +#define DOWNAMPLING_FILTER_INIT_SAMPLES 100 // some samples to initialize the state of the downsampling filter +#define DOWNSAMPLING_FILTER_DELAY 48 // delay of the downsampling filter in samples + + +// HW related options +bool skip_samples_already_used = false; // if skip_samples_already_used = 1 => for each PRN loop skip the samples used in the previous PRN loops + // (exactly in the same way as the SW) + +class Acquisition_msg_rx_Fpga; + +using Acquisition_msg_rx_Fpga_sptr = boost::shared_ptr; + +Acquisition_msg_rx_Fpga_sptr Acquisition_msg_rx_Fpga_make(); + +class Acquisition_msg_rx_Fpga : public gr::block +{ +private: + friend Acquisition_msg_rx_Fpga_sptr Acquisition_msg_rx_Fpga_make(); + void msg_handler_events(pmt::pmt_t msg); + Acquisition_msg_rx_Fpga(); + +public: + int rx_message; + gr::top_block_sptr top_block; + ~Acquisition_msg_rx_Fpga(); //!< Default destructor +}; + +Acquisition_msg_rx_Fpga_sptr Acquisition_msg_rx_Fpga_make() +{ + return Acquisition_msg_rx_Fpga_sptr(new Acquisition_msg_rx_Fpga()); +} + +void Acquisition_msg_rx_Fpga::msg_handler_events(pmt::pmt_t msg) +{ + try + { + int64_t message = pmt::to_long(std::move(msg)); + rx_message = message; + top_block->stop(); //stop the flowgraph + } + catch (boost::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_acquisition Bad cast!\n"; + rx_message = 0; + } +} + +Acquisition_msg_rx_Fpga::Acquisition_msg_rx_Fpga() : gr::block("Acquisition_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")); + this->set_msg_handler(pmt::mp("events"), boost::bind(&Acquisition_msg_rx_Fpga::msg_handler_events, this, _1)); + rx_message = 0; +} + +Acquisition_msg_rx_Fpga::~Acquisition_msg_rx_Fpga() = default; -// ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER ######### class TrackingPullInTestFpga_msg_rx; -typedef boost::shared_ptr TrackingPullInTestFpga_msg_rx_sptr; +using TrackingPullInTestFpga_msg_rx_sptr = boost::shared_ptr; TrackingPullInTestFpga_msg_rx_sptr TrackingPullInTestFpga_msg_rx_make(); @@ -80,20 +143,17 @@ public: ~TrackingPullInTestFpga_msg_rx(); //!< Default destructor }; - TrackingPullInTestFpga_msg_rx_sptr TrackingPullInTestFpga_msg_rx_make() { return TrackingPullInTestFpga_msg_rx_sptr(new TrackingPullInTestFpga_msg_rx()); } - void TrackingPullInTestFpga_msg_rx::msg_handler_events(pmt::pmt_t msg) { try { - int64_t message = pmt::to_long(msg); + int64_t message = pmt::to_long(std::move(msg)); rx_message = message; //3 -> loss of lock - //std::cout << "Received trk message: " << rx_message << std::endl; } catch (boost::bad_any_cast& e) { @@ -102,7 +162,6 @@ void TrackingPullInTestFpga_msg_rx::msg_handler_events(pmt::pmt_t msg) } } - TrackingPullInTestFpga_msg_rx::TrackingPullInTestFpga_msg_rx() : gr::block("TrackingPullInTestFpga_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { this->message_port_register_in(pmt::mp("events")); @@ -111,13 +170,9 @@ TrackingPullInTestFpga_msg_rx::TrackingPullInTestFpga_msg_rx() : gr::block("Trac } -TrackingPullInTestFpga_msg_rx::~TrackingPullInTestFpga_msg_rx() -{ -} +TrackingPullInTestFpga_msg_rx::~TrackingPullInTestFpga_msg_rx() = default; -// ########################################################### - class TrackingPullInTestFpga : public ::testing::Test { public: @@ -131,7 +186,6 @@ public: 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_signal_file; @@ -168,9 +222,7 @@ public: gnss_synchro = Gnss_Synchro(); } - ~TrackingPullInTestFpga() - { - } + ~TrackingPullInTestFpga() = default; void configure_receiver(double PLL_wide_bw_hz, double DLL_wide_bw_hz, @@ -213,7 +265,7 @@ int TrackingPullInTestFpga::generate_signal() { int child_status; - char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], NULL}; + char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], &p6[0], nullptr}; int pid; if ((pid = fork()) == -1) @@ -243,7 +295,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("Tracking.dump", "true"); config->set_property("Tracking.dump_filename", "./tracking_ch_"); config->set_property("Tracking.implementation", implementation); - config->set_property("Tracking.item_type", "gr_complex"); + config->set_property("Tracking.item_type", "cshort"); 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)); @@ -254,16 +306,18 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); std::string System_and_Signal; - if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") { gnss_synchro.System = 'G'; std::string signal = "1C"; System_and_Signal = "GPS L1 CA"; signal.copy(gnss_synchro.Signal, 2, 0); config->set_property("Tracking.early_late_space_chips", "0.5"); - config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); + config->set_property("Tracking.if", "0"); + config->set_property("Tracking.order", "3"); } - else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") { gnss_synchro.System = 'E'; std::string signal = "1B"; @@ -271,34 +325,25 @@ void TrackingPullInTestFpga::configure_receiver( signal.copy(gnss_synchro.Signal, 2, 0); config->set_property("Tracking.early_late_space_chips", "0.15"); config->set_property("Tracking.very_early_late_space_chips", "0.6"); - config->set_property("Tracking.early_late_space_narrow_chips", "0.15"); - config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); config->set_property("Tracking.track_pilot", "true"); + + // added by me + config->set_property("Tracking.if", "0"); + config->set_property("Tracking.devicename", "/dev/uio"); + config->set_property("Tracking.device_base", "15"); } - else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) - { - gnss_synchro.System = 'G'; - std::string signal = "2S"; - System_and_Signal = "GPS L2CM"; - signal.copy(gnss_synchro.Signal, 2, 0); - config->set_property("Tracking.early_late_space_chips", "0.5"); - config->set_property("Tracking.track_pilot", "false"); - } - else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0 or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) { gnss_synchro.System = 'E'; std::string signal = "5X"; System_and_Signal = "Galileo E5a"; signal.copy(gnss_synchro.Signal, 2, 0); - if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) - { - config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking")); - } config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.track_pilot", "false"); config->set_property("Tracking.order", "2"); } - else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") { gnss_synchro.System = 'G'; std::string signal = "L5"; @@ -329,8 +374,178 @@ void TrackingPullInTestFpga::configure_receiver( } +const size_t PAGE_SIZE = 0x10000; +const unsigned int TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; + + +void setup_fpga_switch(void) +{ + int switch_device_descriptor; // driver descriptor + volatile unsigned* switch_map_base; // driver memory map + + if ((switch_device_descriptor = open("/dev/uio1", O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" + << "/dev/uio1"; + } + switch_map_base = reinterpret_cast(mmap(nullptr, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, switch_device_descriptor, 0)); + + if (switch_map_base == reinterpret_cast(-1)) + { + LOG(WARNING) << "Cannot map the FPGA switch module into tracking memory"; + std::cout << "Could not map switch memory." << std::endl; + } + + // sanity check : check test register + unsigned writeval = TEST_REGISTER_TRACK_WRITEVAL; + unsigned readval; + // write value to test register + switch_map_base[3] = writeval; + // read value from test register + readval = switch_map_base[3]; + + if (writeval != readval) + { + LOG(WARNING) << "Test register sanity check failed"; + } + else + { + LOG(INFO) << "Test register sanity check success !"; + } + + switch_map_base[0] = 0; //0 -> DMA to queue 0, 1 -> DMA to queue 1, 2 -> A/Ds to queues +} + + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +volatile unsigned int send_samples_start = 0; + +int8_t input_samples[MAX_INPUT_COMPLEX_SAMPLES_TOTAL * COMPLEX_SAMPLE_SIZE]; // re - im +int8_t input_samples_dma[MAX_INPUT_COMPLEX_SAMPLES_TOTAL * COMPLEX_SAMPLE_SIZE * NUM_QUEUES]; + + +struct DMA_handler_args +{ + std::string file; + unsigned int nsamples_tx; + unsigned int skip_used_samples; + unsigned int freq_band; // 0 for GPS L1/ Galileo E1, 1 for GPS L5/Galileo E5 +}; + + +void* handler_DMA(void* arguments) +{ + // DMA process that configures the DMA to send the samples to the acquisition engine + int tx_fd; // DMA descriptor + FILE* rx_signal_file_id; // Input file descriptor + bool file_completed = false; // flag to indicate if the file is completed + unsigned int nsamples_block; // number of samples to send in the next DMA block of samples + unsigned int nread_elements; // number of elements effectively read from the input file + unsigned int nsamples = 0; // number of complex samples effectively transferred + unsigned int index0, dma_index = 0; // counters used for putting the samples in the order expected by the DMA + + unsigned int nsamples_transmitted; + + auto* args = (struct DMA_handler_args*)arguments; + + unsigned int nsamples_tx = args->nsamples_tx; + std::string file = args->file; // input filename + unsigned int skip_used_samples = args->skip_used_samples; + + // open DMA device + tx_fd = open("/dev/loop_tx", O_WRONLY); + if (tx_fd < 0) + { + std::cout << "DMA can't open loop device" << std::endl; + exit(1); + } + else + + // open input file + rx_signal_file_id = fopen(file.c_str(), "rb"); + if (rx_signal_file_id == nullptr) + { + std::cout << "DMA can't open input file" << std::endl; + exit(1); + } + while (send_samples_start == 0) + ; // wait until main thread tells the DMA to start + + // skip initial samples + int skip_samples = (int)FLAGS_skip_samples; + + fseek(rx_signal_file_id, (skip_samples + skip_used_samples) * 2, SEEK_SET); + + usleep(50000); // wait some time to give time to the main thread to start the acquisition module + + while (file_completed == false) + { + if (nsamples_tx - nsamples > MAX_INPUT_COMPLEX_SAMPLES_TOTAL) + { + nsamples_block = MAX_INPUT_COMPLEX_SAMPLES_TOTAL; + } + else + { + nsamples_block = nsamples_tx - nsamples; // remaining samples to be sent + file_completed = true; + } + + nread_elements = fread(input_samples, sizeof(int8_t), nsamples_block * COMPLEX_SAMPLE_SIZE, rx_signal_file_id); + + if (nread_elements != nsamples_block * COMPLEX_SAMPLE_SIZE) + { + std::cout << "file completed" << std::endl; + file_completed = true; + } + + nsamples += (nread_elements / COMPLEX_SAMPLE_SIZE); + + if (nread_elements > 0) + { + // for the 32-BIT DMA + dma_index = 0; + for (index0 = 0; index0 < (nread_elements); index0 += COMPLEX_SAMPLE_SIZE) + { + if (args->freq_band == 0) + { + // 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] = input_samples[index0]; + input_samples_dma[dma_index + 3] = input_samples[index0 + 1]; + } + else + { + // channel 1 (queue 1) -> E5/L5 + input_samples_dma[dma_index] = input_samples[index0]; + input_samples_dma[dma_index + 1] = input_samples[index0 + 1]; + // channel 0 (queue 0) -> E1/L1 + input_samples_dma[dma_index + 2] = 0; + input_samples_dma[dma_index + 3] = 0; + } + dma_index += 4; + } + nsamples_transmitted = write(tx_fd, &input_samples_dma[0], nread_elements * NUM_QUEUES); + if (nsamples_transmitted != nread_elements * NUM_QUEUES) + { + std::cout << "Error : DMA could not send all the requested samples" << std::endl; + } + } + } + + close(tx_fd); + fclose(rx_signal_file_id); + return nullptr; +} + + bool TrackingPullInTestFpga::acquire_signal(int SV_ID) { + pthread_t thread_DMA; + // 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m) gr::top_block_sptr top_block; top_block = gr::make_top_block("Acquisition test"); @@ -340,17 +555,14 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) tmp_gnss_synchro.Channel_ID = 0; config = std::make_shared(); config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); - config->set_property("Acquisition.blocking_on_standby", "true"); - config->set_property("Acquisition.blocking", "true"); - config->set_property("Acquisition.dump", "false"); - config->set_property("Acquisition.dump_filename", "./data/acquisition.dat"); - config->set_property("Acquisition.use_CFAR_algorithm", "false"); std::shared_ptr acquisition; std::string System_and_Signal; - //create the correspondign acquisition block according to the desired tracking signal - if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0) + + struct DMA_handler_args args; + + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") { tmp_gnss_synchro.System = 'G'; std::string signal = "1C"; @@ -358,11 +570,12 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) std::memcpy(static_cast(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"; - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - //acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + + args.freq_band = 0; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); } - else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") { tmp_gnss_synchro.System = 'E'; std::string signal = "1B"; @@ -370,37 +583,12 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) std::memcpy(static_cast(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"; - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); - } - else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0) - { - tmp_gnss_synchro.System = 'G'; - std::string signal = "2S"; - const char* str = signal.c_str(); // get a C style null terminated string - std::memcpy(static_cast(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 L2CM"; - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); - } - else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) - { - tmp_gnss_synchro.System = 'E'; - std::string signal = "5X"; - const char* str = signal.c_str(); // get a C style null terminated string - std::memcpy(static_cast(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"; - config->set_property("Acquisition_5X.coherent_integration_time_ms", "1"); - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - config->set_property("Acquisition.CAF_window_hz", "0"); // **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz - config->set_property("Acquisition.Zero_padding", "0"); //**Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF. - config->set_property("Acquisition.bit_transition_flag", "false"); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); - } - else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0) + args.freq_band = 0; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") { tmp_gnss_synchro.System = 'E'; std::string signal = "5X"; @@ -408,10 +596,12 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) std::memcpy(static_cast(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"; - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + + args.freq_band = 1; + + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); } - else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0) + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") { tmp_gnss_synchro.System = 'G'; std::string signal = "L5"; @@ -419,41 +609,26 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) std::memcpy(static_cast(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"; - config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells)); - acquisition = std::make_shared(config.get(), "Acquisition", 1, 0); + + args.freq_band = 1; + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); } else { - std::cout << "The test can not run with the selected tracking implementation\n "; + std::cout << "The test can not run with the selected tracking implementation \n "; throw(std::exception()); } - acquisition->set_gnss_synchro(&tmp_gnss_synchro); acquisition->set_channel(0); - 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_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold)); - acquisition->init(); - acquisition->set_local_code(); - acquisition->set_state(1); // Ensure that acquisition starts at the first sample acquisition->connect(top_block); - 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); - file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample - gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make(); - //gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); - 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->connect(head_samples, 0, acquisition->get_left_block(), 0); - - boost::shared_ptr msg_rx; + boost::shared_ptr msg_rx; try { - msg_rx = Acquisition_msg_rx_make(); + msg_rx = Acquisition_msg_rx_Fpga_make(); } catch (const std::exception& e) { @@ -462,6 +637,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) } msg_rx->top_block = top_block; + top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events")); // 5. Run the flowgraph @@ -491,16 +667,86 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) MAX_PRN_IDX = 33; } + setup_fpga_switch(); + + unsigned int nsamples_to_transfer; + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + } + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + { + nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + } + + int acq_doppler_max = config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz); + int acq_doppler_step = config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz); + for (unsigned int PRN = 1; PRN < MAX_PRN_IDX; PRN++) { tmp_gnss_synchro.PRN = PRN; + + acquisition->stop_acquisition(); // reset the whole system including the sample counters + acquisition->set_doppler_max(acq_doppler_max); + acquisition->set_doppler_step(acq_doppler_step); acquisition->set_gnss_synchro(&tmp_gnss_synchro); acquisition->init(); acquisition->set_local_code(); - acquisition->reset(); - acquisition->set_state(1); + + args.file = file; + + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + { + // send the previous samples to set the downsampling filter in a good condition + send_samples_start = 0; + + args.skip_used_samples = -DOWNAMPLING_FILTER_INIT_SAMPLES; + + args.nsamples_tx = DOWNAMPLING_FILTER_INIT_SAMPLES + DOWNSAMPLING_FILTER_DELAY; + + if (pthread_create(&thread_DMA, nullptr, handler_DMA, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + pthread_mutex_lock(&mutex); + send_samples_start = 1; + pthread_mutex_unlock(&mutex); + pthread_join(thread_DMA, nullptr); + send_samples_start = 0; + + args.nsamples_tx = nsamples_to_transfer; + + args.skip_used_samples = DOWNSAMPLING_FILTER_DELAY; + } + else + { + args.nsamples_tx = nsamples_to_transfer; + + args.skip_used_samples = 0; + } + + if (pthread_create(&thread_DMA, nullptr, handler_DMA, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + msg_rx->rx_message = 0; - top_block->run(); + top_block->start(); + + pthread_mutex_lock(&mutex); + send_samples_start = 1; + pthread_mutex_unlock(&mutex); + + acquisition->reset(); // set active + if (start_msg == true) { std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl; @@ -508,25 +754,42 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) std::cout << "["; start_msg = false; } - while (msg_rx->rx_message == 0) + + // wait for the child DMA process to finish + pthread_join(thread_DMA, nullptr); + + pthread_mutex_lock(&mutex); + send_samples_start = 0; + pthread_mutex_unlock(&mutex); + + // the DMA sends the exact number of samples needed for the acquisition. + // however because of the LPF in the GPS L1/Gal E1 acquisition, this calculation is approximate + // and some extra samples might be sent. Wait at least once to give time the HW to consume any extra + // sample the DMA might have sent. + do { usleep(100000); } + while (msg_rx->rx_message == 0); + 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)); + tmp_gnss_synchro.Acq_samplestamp_samples = 0; // do not take into account the filter internal state initialisation acq_samplestamp_map.insert(std::pair(PRN, tmp_gnss_synchro.Acq_samplestamp_samples)); } else { std::cout << " . "; } + top_block->stop(); - file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample + std::cout.flush(); } + std::cout << "]" << std::endl; std::cout << "-------------------------------------------\n"; @@ -544,8 +807,13 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) return true; } + TEST_F(TrackingPullInTestFpga, ValidationOfResults) { + // pointer to the DMA thread that sends the samples to the acquisition engine + pthread_t thread_DMA; + struct DMA_handler_args args; + //************************************************* //***** STEP 1: Prepare the parameters sweep ****** //************************************************* @@ -565,7 +833,6 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) acq_delay_error_chips_values.push_back(tmp_vector); } - //*********************************************************** //***** STEP 2: Generate the input signal (if required) ***** //*********************************************************** @@ -612,7 +879,6 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) } } - configure_receiver(FLAGS_PLL_bw_hz_start, FLAGS_DLL_bw_hz_start, FLAGS_PLL_narrow_bw_hz, @@ -651,21 +917,83 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) { 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; + acq_samplestamp_samples = acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second; 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; + << " Acquisition SampleStamp is " << acq_samplestamp_samples << 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++) + unsigned int code_length; + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + code_length = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + code_length = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_HZ / GALILEO_E1_B_CODE_LENGTH_CHIPS))); + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + code_length = static_cast(std::round(static_cast(baseband_sampling_freq) / GALILEO_E5A_CODE_CHIP_RATE_HZ * static_cast(GALILEO_E5A_CODE_LENGTH_CHIPS))); + } + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + { + code_length = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_HZ / static_cast(GPS_L5I_CODE_LENGTH_CHIPS)))); + } + + float nbits = ceilf(log2f((float)code_length)); + unsigned int fft_size = pow(2, nbits); + + // The HW has been reset after the acquisition phase when the acquisition class was destroyed. + // No more samples remained in the DMA. Therefore any intermediate state in the LPF of the + // GPS L1 / Galileo E1 filter has been cleared. + // During this test all the samples coming from the DMA are consumed so in principle there would be + // no need to reset the HW. However we need to clear the sample counter in each test. Therefore we have + // to reset the HW at the beginning of each test. + + // instantiate the acquisition modules in order to use them to reset the HW. + // (note that the constructor of the acquisition modules resets the HW too) + + std::shared_ptr acquisition; + + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 0; + } + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 0; + } + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); + args.freq_band = 1; + } + else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + { + acquisition = std::make_shared(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()); + } + + for (double generator_CN0_value : generator_CN0_values) { std::vector pull_in_results_v; for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) { 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++) { + // reset the HW to clear the sample counters + acquisition->stop_acquisition(); + gnss_synchro.Acq_samplestamp_samples = acq_samplestamp_samples; //simulate a Doppler error in acquisition gnss_synchro.Acq_doppler_hz = true_acq_doppler_hz + acq_doppler_error_hz_values.at(current_acq_doppler_error_idx); @@ -678,7 +1006,6 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) std::shared_ptr tracking = std::dynamic_pointer_cast(trk_); boost::shared_ptr msg_rx = TrackingPullInTestFpga_msg_rx_make(); - ASSERT_NO_THROW({ tracking->set_channel(gnss_synchro.Channel_ID); }) << "Failure setting channel."; @@ -691,45 +1018,56 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) tracking->connect(top_block); }) << "Failure connecting tracking to the top_block."; - std::string file; ASSERT_NO_THROW({ - 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(); gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro)); - gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration); - top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0); - top_block->connect(gr_interleaved_char_to_complex, 0, head_samples, 0); - top_block->connect(head_samples, 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(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample }) << "Failure connecting the blocks of tracking test."; + std::string file = FLAGS_signal_file; + + args.file = file; + + if (skip_samples_already_used == 1) + { + args.skip_used_samples = (gnss_synchro.PRN - 1) * fft_size; + } + else + { + args.skip_used_samples = 0; + } //******************************************************************** //***** STEP 5: Perform the signal tracking and read the results ***** //******************************************************************** + args.nsamples_tx = baseband_sampling_freq * FLAGS_duration; + + if (pthread_create(&thread_DMA, nullptr, handler_DMA, (void*)&args) < 0) + { + std::cout << "ERROR cannot create DMA Process" << std::endl; + } + std::cout << "--- START TRACKING WITH PULL-IN ERROR: " << acq_doppler_error_hz_values.at(current_acq_doppler_error_idx) << " [Hz] and " << acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) << " [Chips] ---" << std::endl; + tracking->start_tracking(); - std::chrono::time_point start, end; - EXPECT_NO_THROW({ - start = std::chrono::system_clock::now(); - top_block->run(); // Start threads and wait - end = std::chrono::system_clock::now(); - }) << "Failure running the top_block."; - std::chrono::duration elapsed_seconds = end - start; - std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds" << std::endl; + pthread_mutex_lock(&mutex); + send_samples_start = 1; + pthread_mutex_unlock(&mutex); + top_block->start(); + + // wait for the child DMA process to finish + pthread_join(thread_DMA, nullptr); + + top_block->stop(); + + // reset the HW to launch the pending interrupts + acquisition->stop_acquisition(); + + pthread_mutex_lock(&mutex); + send_samples_start = 0; + pthread_mutex_unlock(&mutex); pull_in_results_v.push_back(msg_rx->rx_message != 3); //save last asynchronous tracking message in order to detect a loss of lock @@ -782,7 +1120,6 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) epoch_counter++; } - const std::string gnuplot_executable(FLAGS_gnuplot_executable); if (gnuplot_executable.empty()) { @@ -796,9 +1133,9 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) { boost::filesystem::path p(gnuplot_executable); boost::filesystem::path dir = p.parent_path(); - std::string gnuplot_path = dir.native(); + const std::string& gnuplot_path = dir.native(); Gnuplot::set_GNUPlotPath(gnuplot_path); - unsigned int decimate = static_cast(FLAGS_plot_decimate); + auto decimate = static_cast(FLAGS_plot_decimate); if (FLAGS_plot_detail_level >= 2 and FLAGS_show_plots) { @@ -806,7 +1143,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) 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) + ")"); + g1.set_title(std::to_string(generator_CN0_value) + " 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 { @@ -820,7 +1157,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) g1.plot_xy(trk_timestamp_s, prompt, "Prompt", decimate); g1.plot_xy(trk_timestamp_s, early, "Early", decimate); g1.plot_xy(trk_timestamp_s, late, "Late", decimate); - if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0) + if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking") { g1.plot_xy(trk_timestamp_s, v_early, "Very Early", decimate); g1.plot_xy(trk_timestamp_s, v_late, "Very Late", decimate); @@ -832,7 +1169,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) 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], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); + g2.set_title(std::to_string(generator_CN0_value) + " dB-Hz Constellation " + "PLL/DLL BW: " + std::to_string(FLAGS_PLL_bw_hz_start) + "," + std::to_string(FLAGS_DLL_bw_hz_start) + " [Hz], (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); } else { @@ -849,7 +1186,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) Gnuplot g3("linespoints"); 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) + ")"); + g3.set_title(std::to_string(generator_CN0_value) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); } else { @@ -861,7 +1198,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) g3.cmd("set key box opaque"); g3.plot_xy(trk_timestamp_s, CN0_dBHz, - std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + std::to_string(static_cast(round(generator_CN0_value))) + "[dB-Hz]", decimate); g3.set_legend(); g3.savetops("CN0_output"); @@ -871,7 +1208,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) Gnuplot g4("linespoints"); if (!FLAGS_enable_external_signal_file) { - g4.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) + ")"); + g4.set_title(std::to_string(generator_CN0_value) + " dB-Hz, GPS L1 C/A tracking CN0 output (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")"); } else { @@ -883,7 +1220,7 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) g4.cmd("set key box opaque"); g4.plot_xy(trk_timestamp_s, Doppler, - std::to_string(static_cast(round(generator_CN0_values.at(current_cn0_idx)))) + "[dB-Hz]", decimate); + std::to_string(static_cast(round(generator_CN0_value))) + "[dB-Hz]", decimate); g4.set_legend(); g4.savetops("Doppler"); @@ -899,12 +1236,16 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) } //end plot } //end acquisition Delay errors loop - } //end acquisition Doppler errors loop - pull_in_results_v_v.push_back(pull_in_results_v); + usleep(100000); // give time to the HW to consume all the remaining samples + + } //end acquisition Doppler errors loop + + pull_in_results_v_v.push_back(pull_in_results_v); } //end CN0 LOOP //build the mesh grid + std::vector doppler_error_mesh; std::vector code_delay_error_mesh; for (unsigned int current_acq_doppler_error_idx = 0; current_acq_doppler_error_idx < acq_doppler_error_hz_values.size(); current_acq_doppler_error_idx++) @@ -921,46 +1262,42 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) std::vector pull_in_result_mesh; 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) { + Gnuplot g4("points palette pointsize 2 pointtype 7"); 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; - 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.cmd(R"(set palette defined ( 0 "black", 1 "green" ))"); + g4.cmd("set key off"); + g4.cmd("set view map"); + 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(); - 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); + 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(); + 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); + } } } }