mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-31 07:13:03 +00:00 
			
		
		
		
	Merge branch 'fpga' of https://github.com/mmajoral/gnss-sdr into merge-marc
This commit is contained in:
		| @@ -19,3 +19,4 @@ | ||||
| add_subdirectory(adapters) | ||||
| add_subdirectory(gnuradio_blocks) | ||||
| add_subdirectory(libs) | ||||
|  | ||||
|   | ||||
| @@ -37,9 +37,9 @@ set(ACQ_ADAPTER_SOURCES | ||||
| ) | ||||
|  | ||||
| if(ENABLE_FPGA) | ||||
|     set(ACQ_ADAPTER_SOURCES ${ACQ_ADAPTER_SOURCES} gps_l1_ca_pcps_acquisition_fpga.cc) | ||||
|     set(ACQ_ADAPTER_SOURCES ${ACQ_ADAPTER_SOURCES} gps_l1_ca_pcps_acquisition_fpga.cc gps_l2_m_pcps_acquisition_fpga.cc galileo_e1_pcps_ambiguous_acquisition_fpga.cc galileo_e5a_pcps_acquisition_fpga.cc gps_l5i_pcps_acquisition_fpga.cc) | ||||
| endif(ENABLE_FPGA) | ||||
|  | ||||
|      | ||||
| if(OPENCL_FOUND) | ||||
|     set(ACQ_ADAPTER_SOURCES ${ACQ_ADAPTER_SOURCES} gps_l1_ca_pcps_opencl_acquisition.cc) | ||||
| endif(OPENCL_FOUND) | ||||
|   | ||||
| @@ -0,0 +1,552 @@ | ||||
| /*! | ||||
|  * \file galileo_e1_pcps_ambiguous_acquisition.cc | ||||
|  * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for | ||||
|  *  Galileo E1 Signals | ||||
|  * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2015  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "galileo_e1_pcps_ambiguous_acquisition_fpga.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "galileo_e1_signal_processing.h" | ||||
| #include "Galileo_E1.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/math/distributions/exponential.hpp> | ||||
| #include <glog/logging.h> | ||||
|  | ||||
|  | ||||
|  | ||||
| using google::LogMessage; | ||||
|  | ||||
| GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga( | ||||
|     ConfigurationInterface* configuration, std::string role, | ||||
|     unsigned int in_streams, unsigned int out_streams) : role_(role), 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 = "./data/acquisition.dat"; | ||||
|  | ||||
|     DLOG(INFO) << "role " << role; | ||||
|  | ||||
| //    item_type_ = configuration_->property(role + ".item_type", default_item_type); | ||||
|  | ||||
|     long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000); | ||||
|     long 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_; | ||||
|     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); | ||||
|     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)  ----------------- | ||||
|     unsigned int code_length = static_cast<unsigned int>(std::round(static_cast<double>(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<int>(std::round(static_cast<double>(fs_in_) * 0.001)); | ||||
|     //acq_parameters.samples_per_ms = samples_per_ms; | ||||
|     //unsigned int vector_length = sampled_ms * samples_per_ms; | ||||
|  | ||||
| //    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); | ||||
|     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; | ||||
|  | ||||
|     // 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 | ||||
|     // a channel is assigned) | ||||
|     gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(nsamples_total, true);  // Direct FFT | ||||
|     std::complex<float>* code = new std::complex<float>[nsamples_total];  // buffer for the local code | ||||
|     gr_complex* fft_codes_padded = static_cast<gr_complex*>(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); | ||||
|     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++) | ||||
|         { | ||||
|  | ||||
|         //code_ = new gr_complex[vector_length_]; | ||||
|  | ||||
|         bool cboc = false; // cboc is set to 0 when using the FPGA | ||||
|  | ||||
|         //std::complex<float>* code = new std::complex<float>[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, | ||||
|                     cboc, PRN, fs_in, 0, false); | ||||
|             } | ||||
|         else | ||||
|             { | ||||
|                 char data_signal[3] = "1B"; | ||||
|                 galileo_e1_code_gen_complex_sampled(code, data_signal, | ||||
|                     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_); | ||||
| //            } | ||||
|  | ||||
|  | ||||
| //                // 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++) | ||||
|             { | ||||
|                 code[s] = std::complex<float>(static_cast<float>(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 | ||||
|             { | ||||
|                 if (std::abs(fft_codes_padded[i].real()) > max) | ||||
|                     { | ||||
|                         max = std::abs(fft_codes_padded[i].real()); | ||||
|                     } | ||||
|                 if (std::abs(fft_codes_padded[i].imag()) > max) | ||||
|                     { | ||||
|                         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 | ||||
|             { | ||||
|                 //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(4096*fft_codes_padded[i].real() * (pow(2, 3) - 1) / max)), | ||||
|                 //    static_cast<int>(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<int>(floor(1024*fft_codes_padded[i].real() * (pow(2, 5) - 1) / max)), | ||||
| //                    static_cast<int>(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<int>(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), | ||||
|  //                   static_cast<int>(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<int>(floor(16*fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), | ||||
| //                    static_cast<int>(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<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                     static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); | ||||
|  | ||||
| //                tmp_re = static_cast<int>(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)); | ||||
| //                tmp_im = static_cast<int>(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<int>(tmp_re), static_cast<int>(tmp_im)); | ||||
| // | ||||
|             } | ||||
|  | ||||
| //        // 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_; | ||||
|  | ||||
|     // 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_ = 0; | ||||
|     //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::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<std::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_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<std::string>(channel_) + ".cboc", false); | ||||
| // | ||||
| //    std::complex<float>* code = new std::complex<float>[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"); | ||||
|     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<int>(-doppler_max_); doppler <= static_cast<int>(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<double>(ncells); | ||||
| //    double val = pow(1.0 - pfa, exponent); | ||||
| //    double lambda = double(vector_length_); | ||||
| //    boost::math::exponential_distribution<double> mydist(lambda); | ||||
| //    float threshold = static_cast<float>(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 | ||||
| } | ||||
|  | ||||
|  | ||||
| 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"); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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"); | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,175 @@ | ||||
| /*! | ||||
|  * \file galileo_e1_pcps_ambiguous_acquisition.h | ||||
|  * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for | ||||
|  *  Galileo E1 Signals | ||||
|  * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2015  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #ifndef GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ | ||||
| #define GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ | ||||
|  | ||||
| #include "acquisition_interface.h" | ||||
| #include "gnss_synchro.h" | ||||
| #include "pcps_acquisition_fpga.h" | ||||
| #include "complex_byte_to_float_x2.h" | ||||
| #include <gnuradio/blocks/stream_to_vector.h> | ||||
| #include <gnuradio/blocks/float_to_complex.h> | ||||
| #include <volk_gnsssdr/volk_gnsssdr.h> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| /*! | ||||
|  * \brief This class adapts a PCPS acquisition block to an | ||||
|  *  AcquisitionInterface for Galileo E1 Signals | ||||
|  */ | ||||
| class GalileoE1PcpsAmbiguousAcquisitionFpga : public AcquisitionInterface | ||||
| { | ||||
| public: | ||||
|     GalileoE1PcpsAmbiguousAcquisitionFpga(ConfigurationInterface* configuration, | ||||
|         std::string role, unsigned int in_streams, | ||||
|         unsigned int out_streams); | ||||
|  | ||||
|     virtual ~GalileoE1PcpsAmbiguousAcquisitionFpga(); | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         //   printf("top acq role\n"); | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition" | ||||
|      */ | ||||
|     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; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition/tracking common Gnss_Synchro object pointer | ||||
|      * to efficiently exchange synchronization data between acquisition and | ||||
|      *  tracking blocks | ||||
|      */ | ||||
|     void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition channel unique ID | ||||
|      */ | ||||
|     void set_channel(unsigned int channel) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set statistics threshold of PCPS algorithm | ||||
|      */ | ||||
|     void set_threshold(float threshold) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set maximum Doppler off grid search | ||||
|      */ | ||||
|     void set_doppler_max(unsigned int doppler_max) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set Doppler steps for the grid search | ||||
|      */ | ||||
|     void set_doppler_step(unsigned int doppler_step) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Initializes acquisition algorithm. | ||||
|      */ | ||||
|     void init() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Sets local code for Galileo E1 PCPS acquisition algorithm. | ||||
|      */ | ||||
|     void set_local_code() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns the maximum peak of grid search | ||||
|      */ | ||||
|     signed int mag() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Restart acquisition algorithm | ||||
|      */ | ||||
|     void reset() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief If state = 1, it forces the block to start acquiring from the first sample | ||||
|      */ | ||||
|     void set_state(int state) 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_; | ||||
|     bool dump_; | ||||
|     bool blocking_; | ||||
|     std::string dump_filename_; | ||||
|     //std::complex<float>* 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 | ||||
| }; | ||||
|  | ||||
| #endif /* GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ */ | ||||
| @@ -0,0 +1,405 @@ | ||||
| /*! | ||||
|  * \file galileo_e5a_pcps_acquisition.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 | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2018  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
|  * | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * GNSS-SDR is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * GNSS-SDR is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "galileo_e5a_pcps_acquisition_fpga.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "galileo_e5_signal_processing.h" | ||||
| #include "Galileo_E5a.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/math/distributions/exponential.hpp> | ||||
| #include <glog/logging.h> | ||||
| #include <volk_gnsssdr/volk_gnsssdr_complex.h> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| using google::LogMessage; | ||||
|  | ||||
| GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterface* configuration, | ||||
|     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 acquisition"); | ||||
|     pcpsconf_fpga_t acq_parameters; | ||||
|     configuration_ = configuration; | ||||
|     std::string default_item_type = "gr_complex"; | ||||
|     std::string default_dump_filename = "../data/acquisition.dat"; | ||||
|  | ||||
|     DLOG(INFO) << "Role " << role; | ||||
|  | ||||
|     //item_type_ = configuration_->property(role + ".item_type", default_item_type); | ||||
|  | ||||
|     long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000); | ||||
|     long fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); | ||||
|     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)------------------------- | ||||
|  | ||||
|     acq_pilot_ = configuration_->property(role + ".acquire_pilot", false); | ||||
|     acq_iq_ = configuration_->property(role + ".acquire_iq", false); | ||||
|     if (acq_iq_) | ||||
|         { | ||||
|             acq_pilot_ = false; | ||||
|         } | ||||
|  | ||||
|     unsigned int code_length = static_cast<unsigned int>(std::round(static_cast<double>(fs_in) / Galileo_E5a_CODE_CHIP_RATE_HZ * static_cast<double>(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); | ||||
|     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; | ||||
|  | ||||
|     //vector_length_ = code_length_ * sampled_ms_; | ||||
|  | ||||
|     // 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 | ||||
|     // a channel is assigned) | ||||
|     gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(nsamples_total, true);  // Direct FFT | ||||
|     std::complex<float>* code = new std::complex<float>[nsamples_total];  // buffer for the local code | ||||
|     gr_complex* fft_codes_padded = static_cast<gr_complex*>(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment())); | ||||
|     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++) | ||||
|         { | ||||
|             //    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_, PRN, fs_in, 0); | ||||
|  | ||||
|             // fill in zero padding | ||||
|             for (int s = code_length; s < nsamples_total; s++) | ||||
|                 { | ||||
|                     code[s] = std::complex<float>(static_cast<float>(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 | ||||
|                 { | ||||
|                     if (std::abs(fft_codes_padded[i].real()) > max) | ||||
|                         { | ||||
|                             max = std::abs(fft_codes_padded[i].real()); | ||||
|                         } | ||||
|                     if (std::abs(fft_codes_padded[i].imag()) > max) | ||||
|                         { | ||||
|                             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 | ||||
|                 { | ||||
|                     d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                         static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); | ||||
|                 } | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|     acq_parameters.all_fft_codes = d_all_fft_codes_; | ||||
|  | ||||
|     // 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_ = 0; | ||||
|     //printf("creating the E5A acquisition end"); | ||||
| } | ||||
|  | ||||
|  | ||||
| GalileoE5aPcpsAcquisitionFpga::~GalileoE5aPcpsAcquisitionFpga() | ||||
| { | ||||
|     //delete[] code_; | ||||
|     delete[] d_all_fft_codes_; | ||||
| } | ||||
|  | ||||
|  | ||||
| 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_ + boost::lexical_cast<std::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); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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_); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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_); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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<int>(-doppler_max_); doppler <= static_cast<int>(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<double>(ncells); | ||||
| //    double val = pow(1.0 - pfa, exponent); | ||||
| //    double lambda = double(vector_length_); | ||||
| //    boost::math::exponential_distribution<double> mydist(lambda); | ||||
| //    float threshold = static_cast<float>(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"; | ||||
| //        } | ||||
| } | ||||
|  | ||||
|  | ||||
| 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"; | ||||
| //        } | ||||
| } | ||||
|  | ||||
|  | ||||
| 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_; | ||||
| } | ||||
| @@ -0,0 +1,175 @@ | ||||
| /*! | ||||
|  * \file galileo_e5a_pcps_acquisition.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 | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2018  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
|  * | ||||
|  * This file is part of GNSS-SDR. | ||||
|  * | ||||
|  * GNSS-SDR is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * GNSS-SDR is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #ifndef GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ | ||||
| #define GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ | ||||
|  | ||||
|  | ||||
| #include "acquisition_interface.h" | ||||
| #include "gnss_synchro.h" | ||||
| #include "pcps_acquisition_fpga.h" | ||||
| #include <gnuradio/blocks/stream_to_vector.h> | ||||
| #include <volk_gnsssdr/volk_gnsssdr.h> | ||||
| #include <string> | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| class GalileoE5aPcpsAcquisitionFpga : public AcquisitionInterface | ||||
| { | ||||
| public: | ||||
|     GalileoE5aPcpsAcquisitionFpga(ConfigurationInterface* configuration, | ||||
|         std::string role, unsigned int in_streams, | ||||
|         unsigned int out_streams); | ||||
|  | ||||
|     virtual ~GalileoE5aPcpsAcquisitionFpga(); | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "Galileo_E5a_Pcps_Acquisition_Fpga"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition/tracking common Gnss_Synchro object pointer | ||||
|      * to efficiently exchange synchronization data between acquisition and | ||||
|      *  tracking blocks | ||||
|      */ | ||||
|     void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition channel unique ID | ||||
|      */ | ||||
|     void set_channel(unsigned int channel) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set statistics threshold of PCPS algorithm | ||||
|      */ | ||||
|     void set_threshold(float threshold) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set maximum Doppler off grid search | ||||
|      */ | ||||
|     void set_doppler_max(unsigned int doppler_max) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set Doppler steps for the grid search | ||||
|      */ | ||||
|     void set_doppler_step(unsigned int doppler_step) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Initializes acquisition algorithm. | ||||
|      */ | ||||
|     void init() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Sets local Galileo E5a code for PCPS acquisition algorithm. | ||||
|      */ | ||||
|     void set_local_code() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns the maximum peak of grid search | ||||
|      */ | ||||
|     signed int mag() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Restart acquisition algorithm | ||||
|      */ | ||||
|     void reset() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief If set to 1, ensures that acquisition starts at the | ||||
|      * first available sample. | ||||
|      * \param state - int=1 forces start of acquisition | ||||
|      */ | ||||
|     void set_state(int state) override; | ||||
|  | ||||
| private: | ||||
|     //float calculate_threshold(float pfa); | ||||
|  | ||||
|     ConfigurationInterface* configuration_; | ||||
|  | ||||
|     pcps_acquisition_fpga_sptr acquisition_fpga_; | ||||
|     gr::blocks::stream_to_vector::sptr stream_to_vector_; | ||||
|  | ||||
|     size_t item_size_; | ||||
|  | ||||
|     std::string item_type_; | ||||
|     std::string dump_filename_; | ||||
|     std::string role_; | ||||
|  | ||||
|     bool bit_transition_flag_; | ||||
|     bool dump_; | ||||
|     bool acq_pilot_; | ||||
|     bool use_CFAR_; | ||||
|     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_; | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|  | ||||
|     long fs_in_; | ||||
|  | ||||
|  | ||||
|     float threshold_; | ||||
|  | ||||
|     /* | ||||
|     std::complex<float>* codeI_; | ||||
|     std::complex<float>* 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_ */ | ||||
| @@ -11,7 +11,7 @@ | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2018  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2015  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
| @@ -29,20 +29,21 @@ | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  * along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "gps_l1_ca_pcps_acquisition_fpga.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "gps_l1_ca_pcps_acquisition_fpga.h" | ||||
| #include "gps_sdr_signal_processing.h" | ||||
| #include "GPS_L1_CA.h" | ||||
| #include <gnuradio/fft/fft.h> | ||||
| #include <glog/logging.h> | ||||
| #include <new> | ||||
|  | ||||
|  | ||||
| #define NUM_PRNs 32 | ||||
|  | ||||
| using google::LogMessage; | ||||
| @@ -59,6 +60,8 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( | ||||
|  | ||||
|     long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); | ||||
|     long 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); | ||||
|     acq_parameters.fs_in = fs_in; | ||||
|     acq_parameters.samples_per_code = static_cast<unsigned int>(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in))); | ||||
|     doppler_max_ = configuration_->property(role + ".doppler_max", 5000); | ||||
| @@ -67,43 +70,56 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( | ||||
|     unsigned int sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1); | ||||
|     acq_parameters.sampled_ms = sampled_ms; | ||||
|     unsigned int code_length = static_cast<unsigned int>(std::round(static_cast<double>(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 * sampled_ms; | ||||
|     unsigned int vector_length = nsamples_total; | ||||
|     unsigned int 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; | ||||
|     acq_parameters.samples_per_ms = nsamples_total / sampled_ms; | ||||
|     acq_parameters.samples_per_code = nsamples_total; | ||||
|  | ||||
|     // 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) | ||||
|  | ||||
|     gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(vector_length, true);  // Direct FFT | ||||
|     // allocate memory to compute all the PRNs and compute all the possible codes | ||||
|     std::complex<float>* code = new std::complex<float>[nsamples_total];  // buffer for the local code | ||||
|     gr_complex* fft_codes_padded = static_cast<gr_complex*>(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++) | ||||
|         { | ||||
|             gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0);  // generate PRN code | ||||
|             // fill in zero padding | ||||
|             for (unsigned int s = code_length; s < nsamples_total; s++) | ||||
|             for (int s = code_length; s < nsamples_total; s++) | ||||
|                 { | ||||
|                     code[s] = 0; | ||||
|                     code[s] = std::complex<float>(static_cast<float>(0, 0)); | ||||
|                     //code[s] = 0; | ||||
|                 } | ||||
|             int offset = 0; | ||||
|             memcpy(fft_if->get_inbuf() + offset, 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 | ||||
|  | ||||
|  | ||||
|             //            // 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 | ||||
|                 { | ||||
|                     if (std::abs(fft_codes_padded[i].real()) > max) | ||||
|                         { | ||||
| @@ -116,12 +132,31 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( | ||||
|                 } | ||||
|             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 | ||||
|                 { | ||||
|                     d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), | ||||
|                         static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); | ||||
|                     //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), | ||||
|                     //    static_cast<int>(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<int>(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), | ||||
|                     //    static_cast<int>(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<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                     //    static_cast<int>(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<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                         static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 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 | ||||
|     acq_parameters.all_fft_codes = d_all_fft_codes_; | ||||
|  | ||||
|     // temporary buffers that we can delete | ||||
| @@ -135,14 +170,6 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga( | ||||
|     channel_ = 0; | ||||
|     doppler_step_ = 0; | ||||
|     gnss_synchro_ = 0; | ||||
|     if (in_streams_ > 1) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation only supports one input stream"; | ||||
|         } | ||||
|     if (out_streams_ > 0) | ||||
|         { | ||||
|             LOG(ERROR) << "This implementation does not provide an output stream"; | ||||
|         } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -161,6 +188,8 @@ 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); | ||||
| } | ||||
| @@ -216,26 +245,21 @@ void GpsL1CaPcpsAcquisitionFpga::set_state(int state) | ||||
|     acquisition_fpga_->set_state(state); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL1CaPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (top_block) | ||||
|         {  // nothing to disconnect | ||||
|         } | ||||
|     // nothing to connect | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL1CaPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block) | ||||
| { | ||||
|     if (top_block) | ||||
|         {  // nothing to disconnect | ||||
|         } | ||||
|     // nothing to disconnect | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_left_block() | ||||
| { | ||||
|     return acquisition_fpga_; | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -68,7 +68,7 @@ public: | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "GPS_L1_CA_PCPS_Acquisition"; | ||||
|         return "GPS_L1_CA_PCPS_Acquisition_Fpga"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|   | ||||
| @@ -0,0 +1,398 @@ | ||||
| /*! | ||||
|  * \file gps_l2_m_pcps_acquisition.cc | ||||
|  * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for | ||||
|  *  GPS L2 M signals | ||||
|  * \authors <ul> | ||||
|  *          <li> Javier Arribas, 2015. jarribas(at)cttc.es | ||||
|  *          </ul> | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2015  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "gps_l2_m_pcps_acquisition_fpga.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gps_l2c_signal.h" | ||||
| #include "GPS_L2C.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include <boost/math/distributions/exponential.hpp> | ||||
| #include <glog/logging.h> | ||||
|  | ||||
| #define NUM_PRNs 32 | ||||
|  | ||||
| using google::LogMessage; | ||||
|  | ||||
| GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga( | ||||
|     ConfigurationInterface* configuration, std::string role, | ||||
|     unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams) | ||||
| { | ||||
|     //pcpsconf_t acq_parameters; | ||||
|     pcpsconf_fpga_t acq_parameters; | ||||
|     configuration_ = configuration; | ||||
|     std::string default_item_type = "gr_complex"; | ||||
|     std::string default_dump_filename = "./data/acquisition.dat"; | ||||
|  | ||||
|     LOG(INFO) << "role " << role; | ||||
|  | ||||
|     item_type_ = configuration_->property(role + ".item_type", default_item_type); | ||||
|     //float pfa =  configuration_->property(role + ".pfa", 0.0); | ||||
|  | ||||
|     long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); | ||||
|     fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated); | ||||
|     acq_parameters.fs_in = fs_in_; | ||||
|     //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_; | ||||
|     //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 ------------------------- | ||||
|     //code_length_ = std::round(static_cast<double>(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / static_cast<double>(GPS_L2_M_CODE_LENGTH_CHIPS))); | ||||
|  | ||||
|     acq_parameters.sampled_ms = 20; | ||||
|     unsigned code_length = std::round(static_cast<double>(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / static_cast<double>(GPS_L2_M_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); | ||||
|     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.sampled_ms; | ||||
|     //acq_parameters.samples_per_ms = static_cast<int>(std::round(static_cast<double>(fs_in_) * 0.001)); | ||||
|     acq_parameters.samples_per_code = nsamples_total; | ||||
|  | ||||
|     // 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) | ||||
|     gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(vector_length, true);  // Direct FFT | ||||
|     // allocate memory to compute all the PRNs and compute all the possible codes | ||||
|     std::complex<float>* code = new std::complex<float>[nsamples_total];  // buffer for the local code | ||||
|     gr_complex* fft_codes_padded = static_cast<gr_complex*>(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++) | ||||
|         { | ||||
|             gps_l2c_m_code_gen_complex_sampled(code, PRN, fs_in_); | ||||
|             // fill in zero padding | ||||
|             for (int s = code_length; s < nsamples_total; s++) | ||||
|                 { | ||||
|                     code[s] = std::complex<float>(static_cast<float>(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 | ||||
|                 { | ||||
|                     if (std::abs(fft_codes_padded[i].real()) > max) | ||||
|                         { | ||||
|                             max = std::abs(fft_codes_padded[i].real()); | ||||
|                         } | ||||
|                     if (std::abs(fft_codes_padded[i].imag()) > max) | ||||
|                         { | ||||
|                             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 | ||||
|                 { | ||||
|                     d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), | ||||
|                         static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max))); | ||||
|                 } | ||||
|  | ||||
|         } | ||||
|  | ||||
|     //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; | ||||
|  | ||||
|     acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters); | ||||
|     DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")"; | ||||
|  | ||||
|     channel_ = 0; | ||||
|     doppler_step_ = 0; | ||||
|     gnss_synchro_ = 0; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| //    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_ms = static_cast<int>(std::round(static_cast<double>(fs_in_) * 0.001)); | ||||
|     //acq_parameters.samples_per_code = code_length_; | ||||
|     //acq_parameters.it_size = item_size_; | ||||
|     //acq_parameters.sampled_ms = 20; | ||||
|     //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", true); | ||||
|     //acquisition_ = pcps_make_acquisition(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_ = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| GpsL2MPcpsAcquisitionFpga::~GpsL2MPcpsAcquisitionFpga() | ||||
| { | ||||
|     //delete[] code_; | ||||
|     delete[] d_all_fft_codes_; | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_channel(unsigned int channel) | ||||
| { | ||||
|     channel_ = channel; | ||||
|     acquisition_fpga_->set_channel(channel_); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_threshold(float threshold) | ||||
| { | ||||
| //    float pfa = configuration_->property(role_ + boost::lexical_cast<std::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_fpga_->set_threshold(threshold_); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) | ||||
| { | ||||
|     doppler_max_ = doppler_max; | ||||
|  | ||||
|     acquisition_fpga_->set_doppler_max(doppler_max_); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Be aware that Doppler step should be set to 2/(3T) Hz, where T is the coherent integration time (GPS L2 period is 0.02s) | ||||
| // Doppler bin minimum size= 33 Hz | ||||
| void GpsL2MPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) | ||||
| { | ||||
|     doppler_step_ = doppler_step; | ||||
|  | ||||
|     acquisition_fpga_->set_doppler_step(doppler_step_); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) | ||||
| { | ||||
|     gnss_synchro_ = gnss_synchro; | ||||
|  | ||||
|     acquisition_fpga_->set_gnss_synchro(gnss_synchro_); | ||||
| } | ||||
|  | ||||
|  | ||||
| signed int GpsL2MPcpsAcquisitionFpga::mag() | ||||
| { | ||||
|     return acquisition_fpga_->mag(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::init() | ||||
| { | ||||
|     acquisition_fpga_->init(); | ||||
|     //set_local_code(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_local_code() | ||||
| { | ||||
|     //gps_l2c_m_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_); | ||||
|  | ||||
|     //acquisition_fpga_->set_local_code(code_); | ||||
|     acquisition_fpga_->set_local_code(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::reset() | ||||
| { | ||||
|     acquisition_fpga_->set_active(true); | ||||
| } | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::set_state(int state) | ||||
| { | ||||
|     acquisition_fpga_->set_state(state); | ||||
| } | ||||
|  | ||||
|  | ||||
| //float GpsL2MPcpsAcquisitionFpga::calculate_threshold(float pfa) | ||||
| //{ | ||||
| //    //Calculate the threshold | ||||
| //    unsigned int frequency_bins = 0; | ||||
| //    for (int doppler = static_cast<int>(-doppler_max_); doppler <= static_cast<int>(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<double>(ncells); | ||||
| //    double val = pow(1.0 - pfa, exponent); | ||||
| //    double lambda = double(vector_length_); | ||||
| //    boost::math::exponential_distribution<double> mydist(lambda); | ||||
| //    float threshold = static_cast<float>(quantile(mydist, val)); | ||||
| // | ||||
| //    return threshold; | ||||
| //} | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::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 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_, 0); | ||||
| //        } | ||||
| //    else | ||||
| //        { | ||||
| //            LOG(WARNING) << item_type_ << " unknown acquisition item type"; | ||||
| //        } | ||||
|  | ||||
|     // nothing to connect | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL2MPcpsAcquisitionFpga::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 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_, 0); | ||||
| //        } | ||||
| //    else | ||||
| //        { | ||||
| //            LOG(WARNING) << item_type_ << " unknown acquisition item type"; | ||||
| //        } | ||||
|  | ||||
|     // nothing to disconnect | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr GpsL2MPcpsAcquisitionFpga::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; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr GpsL2MPcpsAcquisitionFpga::get_right_block() | ||||
| { | ||||
|     return acquisition_fpga_; | ||||
| } | ||||
| @@ -0,0 +1,171 @@ | ||||
| /*! | ||||
|  * \file gps_l2_m_pcps_acquisition.h | ||||
|  * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for | ||||
|  *  GPS L2 M signals | ||||
|  * \authors <ul> | ||||
|  *          <li> Javier Arribas, 2015. jarribas(at)cttc.es | ||||
|  *          </ul> | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2015  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #ifndef GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ | ||||
| #define GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ | ||||
|  | ||||
| #include "acquisition_interface.h" | ||||
| #include "gnss_synchro.h" | ||||
| #include "pcps_acquisition_fpga.h" | ||||
| #include "complex_byte_to_float_x2.h" | ||||
| #include <gnuradio/blocks/stream_to_vector.h> | ||||
| #include <gnuradio/blocks/float_to_complex.h> | ||||
| #include <volk_gnsssdr/volk_gnsssdr.h> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| /*! | ||||
|  * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface | ||||
|  *  for GPS L2 M signals | ||||
|  */ | ||||
| class GpsL2MPcpsAcquisitionFpga : public AcquisitionInterface | ||||
| { | ||||
| public: | ||||
|     GpsL2MPcpsAcquisitionFpga(ConfigurationInterface* configuration, | ||||
|         std::string role, unsigned int in_streams, | ||||
|         unsigned int out_streams); | ||||
|  | ||||
|     virtual ~GpsL2MPcpsAcquisitionFpga(); | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "GPS_L2_M_PCPS_Acquisition" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "GPS_L2_M_PCPS_Acquisition"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition/tracking common Gnss_Synchro object pointer | ||||
|      * to efficiently exchange synchronization data between acquisition and | ||||
|      *  tracking blocks | ||||
|      */ | ||||
|     void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition channel unique ID | ||||
|      */ | ||||
|     void set_channel(unsigned int channel) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set statistics threshold of PCPS algorithm | ||||
|      */ | ||||
|     void set_threshold(float threshold) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set maximum Doppler off grid search | ||||
|      */ | ||||
|     void set_doppler_max(unsigned int doppler_max) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set Doppler steps for the grid search | ||||
|      */ | ||||
|     void set_doppler_step(unsigned int doppler_step) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Initializes acquisition algorithm. | ||||
|      */ | ||||
|     void init() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. | ||||
|      */ | ||||
|     void set_local_code() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns the maximum peak of grid search | ||||
|      */ | ||||
|     signed int mag() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Restart acquisition algorithm | ||||
|      */ | ||||
|     void reset() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief If state = 1, it forces the block to start acquiring from the first sample | ||||
|      */ | ||||
|     void set_state(int state) 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_; | ||||
|     unsigned int channel_; | ||||
|     float threshold_; | ||||
|     unsigned int doppler_max_; | ||||
|     unsigned int doppler_step_; | ||||
|     unsigned int max_dwells_; | ||||
|     long fs_in_; | ||||
|     //long if_; | ||||
|     bool dump_; | ||||
|     bool blocking_; | ||||
|     std::string dump_filename_; | ||||
|     std::complex<float>* code_; | ||||
|     Gnss_Synchro* gnss_synchro_; | ||||
|     std::string role_; | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|  | ||||
|     lv_16sc_t* d_all_fft_codes_;  // memory that contains all the code ffts | ||||
|  | ||||
|     //float calculate_threshold(float pfa); | ||||
| }; | ||||
|  | ||||
| #endif /* GNSS_SDR_GPS_L2_M_PCPS_ACQUISITION_FPGA_H_ */ | ||||
| @@ -0,0 +1,404 @@ | ||||
| /*! | ||||
|  * \file gps_l5i pcps_acquisition.cc | ||||
|  * \brief Adapts a PCPS acquisition block to an Acquisition Interface for | ||||
|  *  GPS L5i signals | ||||
|  * \authors <ul> | ||||
|  *          <li> Javier Arribas, 2017. jarribas(at)cttc.es | ||||
|  *          </ul> | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2017  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "gps_l5i_pcps_acquisition_fpga.h" | ||||
| #include "configuration_interface.h" | ||||
| #include "gps_l5_signal.h" | ||||
| #include "GPS_L5.h" | ||||
| #include "gnss_sdr_flags.h" | ||||
| #include <boost/math/distributions/exponential.hpp> | ||||
| #include <glog/logging.h> | ||||
|  | ||||
| #define NUM_PRNs 32 | ||||
|  | ||||
| using google::LogMessage; | ||||
|  | ||||
| GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga( | ||||
|     ConfigurationInterface* configuration, std::string role, | ||||
|     unsigned int in_streams, unsigned int out_streams) : role_(role), 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 = "./data/acquisition.dat"; | ||||
|  | ||||
|     LOG(INFO) << "role " << role; | ||||
|  | ||||
|     //item_type_ = configuration_->property(role + ".item_type", default_item_type); | ||||
|  | ||||
|     long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000); | ||||
|     long 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_; | ||||
|     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); | ||||
|     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 ------------------------- | ||||
|     unsigned int code_length = static_cast<unsigned int>(std::round(static_cast<double>(fs_in) / (GPS_L5i_CODE_RATE_HZ / static_cast<double>(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); | ||||
|     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_code = nsamples_total; | ||||
|     //printf("L5 ACQ CLASS MID 01\n"); | ||||
|     // 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) | ||||
|     gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(vector_length, true);  // Direct FFT | ||||
|     //printf("L5 ACQ CLASS MID 02\n"); | ||||
|     std::complex<float>* code = new gr_complex[vector_length]; | ||||
|     //printf("L5 ACQ CLASS MID 03\n"); | ||||
|     gr_complex* fft_codes_padded = static_cast<gr_complex*>(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++) | ||||
|     { | ||||
|     	//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++) | ||||
|             { | ||||
|                 code[s] = std::complex<float>(static_cast<float>(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 | ||||
|             { | ||||
|                 if (std::abs(fft_codes_padded[i].real()) > max) | ||||
|                     { | ||||
|                         max = std::abs(fft_codes_padded[i].real()); | ||||
|                     } | ||||
|                 if (std::abs(fft_codes_padded[i].imag()) > max) | ||||
|                     { | ||||
|                         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 | ||||
|             { | ||||
|                 //d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int>(floor(256*fft_codes_padded[i].real() * (pow(2, 7) - 1) / max)), | ||||
|                 //    static_cast<int>(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<int>(16*floor(fft_codes_padded[i].real() * (pow(2, 11) - 1) / max)), | ||||
|                 //    static_cast<int>(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<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                 //    static_cast<int>(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<int>(floor(fft_codes_padded[i].real() * (pow(2, 15) - 1) / max)), | ||||
|                     static_cast<int>(floor(fft_codes_padded[i].imag() * (pow(2, 15) - 1) / max))); | ||||
|             } | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     //printf("L5 ACQ CLASS MID 2\n"); | ||||
|  | ||||
|     //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; | ||||
| //    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_ = 0; | ||||
|     //printf("L5 ACQ CLASS FINISHED\n"); | ||||
| } | ||||
|  | ||||
|  | ||||
| GpsL5iPcpsAcquisitionFpga::~GpsL5iPcpsAcquisitionFpga() | ||||
| { | ||||
|     //delete[] code_; | ||||
|     delete[] d_all_fft_codes_; | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::set_channel(unsigned int channel) | ||||
| { | ||||
|     channel_ = channel; | ||||
|     acquisition_fpga_->set_channel(channel_); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::set_threshold(float threshold) | ||||
| { | ||||
| //    float pfa = configuration_->property(role_ + boost::lexical_cast<std::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); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max) | ||||
| { | ||||
|     doppler_max_ = doppler_max; | ||||
|     acquisition_fpga_->set_doppler_max(doppler_max_); | ||||
| } | ||||
|  | ||||
|  | ||||
| // Be aware that Doppler step should be set to 2/(3T) Hz, where T is the coherent integration time (GPS L2 period is 0.02s) | ||||
| // Doppler bin minimum size= 33 Hz | ||||
| void GpsL5iPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step) | ||||
| { | ||||
|     doppler_step_ = doppler_step; | ||||
|     acquisition_fpga_->set_doppler_step(doppler_step_); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro) | ||||
| { | ||||
|     gnss_synchro_ = gnss_synchro; | ||||
|     acquisition_fpga_->set_gnss_synchro(gnss_synchro_); | ||||
| } | ||||
|  | ||||
|  | ||||
| signed int GpsL5iPcpsAcquisitionFpga::mag() | ||||
| { | ||||
| 	return acquisition_fpga_->mag(); | ||||
| } | ||||
|  | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::init() | ||||
| { | ||||
| 	acquisition_fpga_->init(); | ||||
| } | ||||
|  | ||||
| void GpsL5iPcpsAcquisitionFpga::set_local_code() | ||||
| { | ||||
| 	acquisition_fpga_->set_local_code(); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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<int>(-doppler_max_); doppler <= static_cast<int>(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<double>(ncells); | ||||
| //    double val = pow(1.0 - pfa, exponent); | ||||
| //    double lambda = double(vector_length_); | ||||
| //    boost::math::exponential_distribution<double> mydist(lambda); | ||||
| //    float threshold = static_cast<float>(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 | ||||
| } | ||||
|  | ||||
|  | ||||
| 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 | ||||
| } | ||||
|  | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
|  | ||||
| gr::basic_block_sptr GpsL5iPcpsAcquisitionFpga::get_right_block() | ||||
| { | ||||
|     return acquisition_fpga_; | ||||
| } | ||||
| @@ -0,0 +1,171 @@ | ||||
| /*! | ||||
|  * \file GPS_L5i_PCPS_Acquisition.h | ||||
|  * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for | ||||
|  *  GPS L5i signals | ||||
|  * \authors <ul> | ||||
|  *          <li> Javier Arribas, 2017. jarribas(at)cttc.es | ||||
|  *          </ul> | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2017  (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 <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #ifndef GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ | ||||
| #define GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ | ||||
|  | ||||
| #include "acquisition_interface.h" | ||||
| #include "gnss_synchro.h" | ||||
| #include "pcps_acquisition_fpga.h" | ||||
| #include "complex_byte_to_float_x2.h" | ||||
| #include <gnuradio/blocks/stream_to_vector.h> | ||||
| #include <gnuradio/blocks/float_to_complex.h> | ||||
| #include <volk_gnsssdr/volk_gnsssdr.h> | ||||
| #include <string> | ||||
|  | ||||
|  | ||||
| class ConfigurationInterface; | ||||
|  | ||||
| /*! | ||||
|  * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface | ||||
|  *  for GPS L5i signals | ||||
|  */ | ||||
| class GpsL5iPcpsAcquisitionFpga : public AcquisitionInterface | ||||
| { | ||||
| public: | ||||
|     GpsL5iPcpsAcquisitionFpga(ConfigurationInterface* configuration, | ||||
|         std::string role, unsigned int in_streams, | ||||
|         unsigned int out_streams); | ||||
|  | ||||
|     virtual ~GpsL5iPcpsAcquisitionFpga(); | ||||
|  | ||||
|     inline std::string role() override | ||||
|     { | ||||
|         return role_; | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns "GPS_L5i_PCPS_Acquisition" | ||||
|      */ | ||||
|     inline std::string implementation() override | ||||
|     { | ||||
|         return "GPS_L5i_PCPS_Acquisition"; | ||||
|     } | ||||
|  | ||||
|     inline size_t item_size() override | ||||
|     { | ||||
|         return item_size_; | ||||
|     } | ||||
|  | ||||
|     void connect(gr::top_block_sptr top_block) override; | ||||
|     void disconnect(gr::top_block_sptr top_block) override; | ||||
|     gr::basic_block_sptr get_left_block() override; | ||||
|     gr::basic_block_sptr get_right_block() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition/tracking common Gnss_Synchro object pointer | ||||
|      * to efficiently exchange synchronization data between acquisition and | ||||
|      *  tracking blocks | ||||
|      */ | ||||
|     void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set acquisition channel unique ID | ||||
|      */ | ||||
|     void set_channel(unsigned int channel) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set statistics threshold of PCPS algorithm | ||||
|      */ | ||||
|     void set_threshold(float threshold) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set maximum Doppler off grid search | ||||
|      */ | ||||
|     void set_doppler_max(unsigned int doppler_max) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Set Doppler steps for the grid search | ||||
|      */ | ||||
|     void set_doppler_step(unsigned int doppler_step) override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Initializes acquisition algorithm. | ||||
|      */ | ||||
|     void init() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Sets local code for GPS L2/M PCPS acquisition algorithm. | ||||
|      */ | ||||
|     void set_local_code() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Returns the maximum peak of grid search | ||||
|      */ | ||||
|     signed int mag() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief Restart acquisition algorithm | ||||
|      */ | ||||
|     void reset() override; | ||||
|  | ||||
|     /*! | ||||
|      * \brief If state = 1, it forces the block to start acquiring from the first sample | ||||
|      */ | ||||
|     void set_state(int state) 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_; | ||||
|     unsigned int channel_; | ||||
|     float threshold_; | ||||
|     unsigned int doppler_max_; | ||||
|     unsigned int doppler_step_; | ||||
|     unsigned int max_dwells_; | ||||
|     long fs_in_; | ||||
|     //long if_; | ||||
|     bool dump_; | ||||
|     bool blocking_; | ||||
|     std::string dump_filename_; | ||||
|     std::complex<float>* code_; | ||||
|     Gnss_Synchro* gnss_synchro_; | ||||
|     std::string role_; | ||||
|     unsigned int in_streams_; | ||||
|     unsigned int out_streams_; | ||||
|  | ||||
|     lv_16sc_t* d_all_fft_codes_;  // memory that contains all the code ffts | ||||
|  | ||||
|     float calculate_threshold(float pfa); | ||||
| }; | ||||
|  | ||||
| #endif /* GNSS_SDR_GPS_L5i_PCPS_ACQUISITION_FPGA_H_ */ | ||||
| @@ -26,12 +26,12 @@ set(ACQ_GR_BLOCKS_SOURCES | ||||
|     pcps_quicksync_acquisition_cc.cc | ||||
|     galileo_pcps_8ms_acquisition_cc.cc | ||||
|     galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc | ||||
| ) | ||||
| )  | ||||
|  | ||||
| if(ENABLE_FPGA) | ||||
|     set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_acquisition_fpga.cc) | ||||
| endif(ENABLE_FPGA) | ||||
|  | ||||
|      | ||||
| if(OPENCL_FOUND) | ||||
|     set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_opencl_acquisition_cc.cc) | ||||
| endif(OPENCL_FOUND) | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  * | ||||
|  * Copyright (C) 2010-2018  (see AUTHORS file for a list of contributors) | ||||
|  * Copyright (C) 2010-2017  (see AUTHORS file for a list of contributors) | ||||
|  * | ||||
|  * GNSS-SDR is a software defined Global Navigation | ||||
|  *          Satellite Systems receiver | ||||
| @@ -33,16 +33,19 @@ | ||||
|  * 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 <https://www.gnu.org/licenses/>. | ||||
|  * along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * ------------------------------------------------------------------------- | ||||
|  */ | ||||
|  | ||||
| #include "pcps_acquisition_fpga.h" | ||||
|  | ||||
| #include <glog/logging.h> | ||||
| #include <gnuradio/io_signature.h> | ||||
| #include "pcps_acquisition_fpga.h" | ||||
|  | ||||
|  | ||||
| #define AQ_DOWNSAMPLING_DELAY 40  // delay due to the downsampling filter in the acquisition | ||||
|  | ||||
| using google::LogMessage; | ||||
|  | ||||
| pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_) | ||||
| @@ -55,13 +58,15 @@ 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 = conf_; | ||||
|     d_sample_counter = 0;  // 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.sampled_ms * acq_parameters.samples_per_ms; | ||||
|     d_fft_size = acq_parameters.samples_per_code; | ||||
|     d_mag = 0; | ||||
|     d_input_power = 0.0; | ||||
|     d_num_doppler_bins = 0; | ||||
| @@ -71,25 +76,49 @@ pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block( | ||||
|     d_channel = 0; | ||||
|     d_gnss_synchro = 0; | ||||
|  | ||||
|     acquisition_fpga = std::make_shared<fpga_acquisition>(acq_parameters.device_name, d_fft_size, acq_parameters.doppler_max, acq_parameters.samples_per_ms, | ||||
|     //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); | ||||
|  | ||||
|     // this one works we don't know why | ||||
|     //    acquisition_fpga = std::make_shared <fpga_acquisition> | ||||
|     //          (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); | ||||
|  | ||||
|     // this one is the one it should be but it doesn't work | ||||
|     acquisition_fpga = std::make_shared<fpga_acquisition>(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 <fpga_acquisition> | ||||
|     //          (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"); | ||||
| } | ||||
|  | ||||
|  | ||||
| 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; | ||||
| @@ -102,11 +131,13 @@ void pcps_acquisition_fpga::init() | ||||
|     d_num_doppler_bins = static_cast<uint32_t>(std::ceil(static_cast<double>(static_cast<int32_t>(acq_parameters.doppler_max) - static_cast<int32_t>(-acq_parameters.doppler_max)) / static_cast<double>(d_doppler_step))); | ||||
|  | ||||
|     acquisition_fpga->init(); | ||||
|     //  printf("acq init end\n"); | ||||
| } | ||||
|  | ||||
|  | ||||
| void pcps_acquisition_fpga::set_state(int32_tstate) | ||||
| void pcps_acquisition_fpga::set_state(int32_t state) | ||||
| { | ||||
|     //   printf("acq set state start\n"); | ||||
|     d_state = state; | ||||
|     if (d_state == 1) | ||||
|         { | ||||
| @@ -126,11 +157,13 @@ void pcps_acquisition_fpga::set_state(int32_tstate) | ||||
|         { | ||||
|             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 | ||||
|     //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL | ||||
|     DLOG(INFO) << "positive acquisition" | ||||
| @@ -144,11 +177,13 @@ 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 | ||||
|     DLOG(INFO) << "negative acquisition" | ||||
| @@ -162,16 +197,19 @@ 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 = 0; | ||||
|     float magt = 0.0; | ||||
|     float fft_normalization_factor = static_cast<float>(d_fft_size) * static_cast<float>(d_fft_size); | ||||
|  | ||||
|     d_input_power = 0.0; | ||||
|     d_mag = 0.0; | ||||
| @@ -184,24 +222,32 @@ void pcps_acquisition_fpga::set_active(bool active) | ||||
|                // no CFAR algorithm in the FPGA | ||||
|                << ", use_CFAR_algorithm_flag: false"; | ||||
|  | ||||
|     uint32_t initial_sample; | ||||
|     uint64_t initial_sample; | ||||
|     float input_power_all = 0.0; | ||||
|     float input_power_computed = 0.0; | ||||
|     for (uint32_t doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++) | ||||
|  | ||||
|     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_tdoppler = -static_cast<int32_t>(acq_parameters.doppler_max) + d_doppler_step * doppler_index; | ||||
|             int32_t doppler = -static_cast<int32_t>(acq_parameters.doppler_max) + d_doppler_step * doppler_index; | ||||
|  | ||||
|             acquisition_fpga->set_phase_step(doppler_index); | ||||
|             acquisition_fpga->run_acquisition();  // runs acquisition and waits until it is finished | ||||
|             //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_sample_counter = static_cast<uint64_t>(initial_sample); | ||||
|                     &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); | ||||
| @@ -210,16 +256,79 @@ void pcps_acquisition_fpga::set_active(bool active) | ||||
|                     d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler); | ||||
|                     d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; | ||||
|  | ||||
|                     d_test_statistics = (d_mag / d_input_power);  //* correction_factor; | ||||
|                     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->set_doppler_sweep(d_num_doppler_bins); | ||||
|     acquisition_fpga->run_acquisition(); | ||||
|     acquisition_fpga->read_acquisition_results(&indext, &magt, | ||||
|         &initial_sample, &d_input_power, &d_doppler_index); | ||||
|     //printf("READ ACQ RESULTS\n"); | ||||
|  | ||||
|     // debug | ||||
|     //acquisition_fpga->unblock_samples(); | ||||
|  | ||||
|     d_mag = magt; | ||||
|  | ||||
|  | ||||
|     // 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<int32_t>(acq_parameters.doppler_max) + d_doppler_step * d_doppler_index; | ||||
|     //d_gnss_synchro->Acq_delay_samples = static_cast<double>(2*(indext % (2*acq_parameters.samples_per_code))); | ||||
|     d_gnss_synchro->Acq_delay_samples = static_cast<double>(indext % acq_parameters.samples_per_code); | ||||
|     d_gnss_synchro->Acq_doppler_hz = static_cast<double>(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_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 | ||||
|         } | ||||
| @@ -229,12 +338,13 @@ void pcps_acquisition_fpga::set_active(bool active) | ||||
|             d_active = false; | ||||
|             send_negative_acquisition(); | ||||
|         } | ||||
|  | ||||
|     //   printf("acq set active end\n"); | ||||
| } | ||||
|  | ||||
|  | ||||
| int pcps_acquisition_fpga::general_work(int noutput_items __attribute__((unused)), | ||||
|     gr_vector_int& ninput_items __attribute__((unused)), | ||||
|     gr_vector_const_void_star& input_items __attribute__((unused)), | ||||
|     gr_vector_int& ninput_items, gr_vector_const_void_star& input_items, | ||||
|     gr_vector_void_star& output_items __attribute__((unused))) | ||||
| { | ||||
|     // the general work is not used with the acquisition that uses the FPGA | ||||
|   | ||||
| @@ -66,10 +66,10 @@ typedef struct | ||||
|     /* pcps acquisition configuration */ | ||||
|     uint32_t sampled_ms; | ||||
|     uint32_t doppler_max; | ||||
|     int64_t freq; | ||||
|     int64_t fs_in; | ||||
|     int32_tsamples_per_ms; | ||||
|     int32_tsamples_per_code; | ||||
|     int32_t samples_per_ms; | ||||
|     int32_t samples_per_code; | ||||
|     int32_t code_length; | ||||
|     uint32_t select_queue_Fpga; | ||||
|     std::string device_name; | ||||
|     lv_16sc_t* all_fft_codes;  // memory that contains all the code ffts | ||||
| @@ -107,8 +107,9 @@ private: | ||||
|     float d_threshold; | ||||
|     float d_mag; | ||||
|     float d_input_power; | ||||
|     uint32_t d_doppler_index; | ||||
|     float d_test_statistics; | ||||
|     int32_td_state; | ||||
|     int32_t d_state; | ||||
|     uint32_t d_channel; | ||||
|     uint32_t d_doppler_step; | ||||
|     uint32_t d_fft_size; | ||||
| @@ -117,6 +118,12 @@ private: | ||||
|     Gnss_Synchro* d_gnss_synchro; | ||||
|     std::shared_ptr<fpga_acquisition> acquisition_fpga; | ||||
|  | ||||
|     // debug | ||||
|     float debug_d_max_absolute; | ||||
|     float debug_d_input_power_absolute; | ||||
|     int32_t debug_indext; | ||||
|     int32_t debug_doppler_index; | ||||
|  | ||||
| public: | ||||
|     ~pcps_acquisition_fpga(); | ||||
|  | ||||
| @@ -127,7 +134,9 @@ 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"); | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
| @@ -135,7 +144,9 @@ public: | ||||
|      */ | ||||
|     inline uint32_t mag() const | ||||
|     { | ||||
|         //   printf("acq dmag start\n"); | ||||
|         return d_mag; | ||||
|         //   printf("acq dmag end\n"); | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
| @@ -154,7 +165,7 @@ public: | ||||
|       * first available sample. | ||||
|       * \param state - int=1 forces start of acquisition | ||||
|       */ | ||||
|     void set_state(int32_tstate); | ||||
|     void set_state(int32_t state); | ||||
|  | ||||
|     /*! | ||||
|       * \brief Starts acquisition algorithm, turning from standby mode to | ||||
| @@ -179,7 +190,9 @@ public: | ||||
|       */ | ||||
|     inline void set_threshold(float threshold) | ||||
|     { | ||||
|         //    printf("acq set threshold start\n"); | ||||
|         d_threshold = threshold; | ||||
|         //   printf("acq set threshold end\n"); | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
| @@ -188,8 +201,10 @@ 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"); | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
| @@ -198,8 +213,10 @@ 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"); | ||||
|     } | ||||
|  | ||||
|     /*! | ||||
|   | ||||
| @@ -33,20 +33,21 @@ | ||||
| #define GNSS_SDR_ACQ_CONF_H_ | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| class Acq_Conf | ||||
| { | ||||
| public: | ||||
|     /* PCPS Acquisition configuration */ | ||||
|     unsigned int sampled_ms; | ||||
|     unsigned int ms_per_code; | ||||
|     unsigned int samples_per_chip; | ||||
|     unsigned int max_dwells; | ||||
|     unsigned int doppler_max; | ||||
|     unsigned int num_doppler_bins_step2; | ||||
|     uint32_t sampled_ms; | ||||
|     uint32_t ms_per_code; | ||||
|     uint32_t samples_per_chip; | ||||
|     uint32_t max_dwells; | ||||
|     uint32_t doppler_max; | ||||
|     uint32_t num_doppler_bins_step2; | ||||
|     float doppler_step2; | ||||
|     long fs_in; | ||||
|     int64_t fs_in; | ||||
|     float samples_per_ms; | ||||
|     float samples_per_code; | ||||
|     bool bit_transition_flag; | ||||
| @@ -56,7 +57,7 @@ public: | ||||
|     bool blocking_on_standby;  // enable it only for unit testing to avoid sample consume on idle status | ||||
|     bool make_2_steps; | ||||
|     std::string dump_filename; | ||||
|     unsigned int dump_channel; | ||||
|     uint32_t dump_channel; | ||||
|     size_t it_size; | ||||
|  | ||||
|     Acq_Conf(); | ||||
|   | ||||
| @@ -37,6 +37,7 @@ | ||||
| #include "GPS_L1_CA.h" | ||||
| #include "gps_sdr_signal_processing.h" | ||||
| #include <glog/logging.h> | ||||
| #include <iostream> | ||||
| #include <fcntl.h>     // libraries used by the GIPO | ||||
| #include <sys/mman.h>  // libraries used by the GIPO | ||||
|  | ||||
| @@ -55,6 +56,17 @@ | ||||
| #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 | ||||
|  | ||||
|  | ||||
| bool fpga_acquisition::init() | ||||
| { | ||||
| @@ -69,6 +81,10 @@ 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]); | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -80,9 +96,14 @@ fpga_acquisition::fpga_acquisition(std::string device_name, | ||||
|     uint32_t sampled_ms, uint32_t select_queue, | ||||
|     lv_16sc_t *all_fft_codes) | ||||
| { | ||||
|     uint32_t vector_length = nsamples_total * sampled_ms; | ||||
|     //printf("AAA- sampled_ms = %d\n ", sampled_ms); | ||||
|  | ||||
|     uint32_t vector_length = nsamples_total;  // * sampled_ms; | ||||
|  | ||||
|     //printf("AAA- vector_length = %d\n ", vector_length); | ||||
|     // initial values | ||||
|     d_device_name = device_name; | ||||
|     //d_freq = freq; | ||||
|     d_fs_in = fs_in; | ||||
|     d_vector_length = vector_length; | ||||
|     d_nsamples = nsamples;  // number of samples not including padding | ||||
| @@ -98,6 +119,7 @@ fpga_acquisition::fpga_acquisition(std::string device_name, | ||||
|     if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1) | ||||
|         { | ||||
|             LOG(WARNING) << "Cannot open deviceio" << d_device_name; | ||||
|             std::cout << "Acq: cannot open deviceio" << d_device_name << std::endl; | ||||
|         } | ||||
|     d_map_base = reinterpret_cast<volatile uint32_t *>(mmap(NULL, PAGE_SIZE, | ||||
|         PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0)); | ||||
| @@ -105,6 +127,7 @@ fpga_acquisition::fpga_acquisition(std::string device_name, | ||||
|     if (d_map_base == reinterpret_cast<void *>(-1)) | ||||
|         { | ||||
|             LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory"; | ||||
|             std::cout << "Acq: cannot map deviceio" << d_device_name << std::endl; | ||||
|         } | ||||
|  | ||||
|     // sanity check : check test register | ||||
| @@ -118,6 +141,7 @@ 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"; | ||||
| @@ -150,20 +174,35 @@ uint32_t fpga_acquisition::fpga_acquisition_test_register(uint32_t writeval) | ||||
|  | ||||
| void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]) | ||||
| { | ||||
|     uint16_t local_code; | ||||
|     uint32_t local_code; | ||||
|     uint32_t k, tmp, tmp2; | ||||
|     uint32_t fft_data; | ||||
|  | ||||
|     // clear memory address counter | ||||
|     d_map_base[4] = LOCAL_CODE_CLEAR_MEM; | ||||
|     //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(); | ||||
|             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); | ||||
|             d_map_base[4] = fft_data; | ||||
|             //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; | ||||
|             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); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -173,12 +212,14 @@ void fpga_acquisition::run_acquisition(void) | ||||
|     int32_t reenable = 1; | ||||
|     write(d_fd, reinterpret_cast<void *>(&reenable), sizeof(int32_t)); | ||||
|     // launch the acquisition process | ||||
|     d_map_base[6] = LAUNCH_ACQUISITION;  // writing anything to reg 6 launches the acquisition process | ||||
|     //printf("launchin acquisition ...\n"); | ||||
|     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"); | ||||
| @@ -187,12 +228,111 @@ void fpga_acquisition::run_acquisition(void) | ||||
| } | ||||
|  | ||||
|  | ||||
| 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<int32_t>(-d_doppler_max) + d_doppler_step * doppler_index; | ||||
|     int32_t doppler = static_cast<int32_t>(-d_doppler_max); | ||||
|     //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in); | ||||
|     float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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<int32_t>(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<int32_t>(d_doppler_step); | ||||
|     phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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<int32_t>(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<int32_t>(d_doppler_max) + d_doppler_step * doppler_index; | ||||
|     //int32_t doppler = static_cast<int32_t>(-d_doppler_max); | ||||
|     //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in); | ||||
|     float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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<int32_t>(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<int32_t>(d_doppler_step); | ||||
|     phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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<int32_t>(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() | ||||
| { | ||||
|     //printf("AAA d_select_queue = %d\n", d_select_queue); | ||||
|     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; | ||||
|     d_map_base[5] = static_cast<int32_t>(log2(static_cast<float>(d_vector_length)));  // log2 FFTlength | ||||
|     //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<int32_t>(log2(static_cast<float>(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)); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -201,8 +341,9 @@ 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<int>(-d_doppler_max) + d_doppler_step * doppler_index; | ||||
|     float phase_step_rad = GPS_TWO_PI * doppler / static_cast<float>(d_fs_in); | ||||
|     int32_t doppler = -static_cast<int32_t>(d_doppler_max) + d_doppler_step * doppler_index; | ||||
|     //float phase_step_rad = GPS_TWO_PI * (d_freq + doppler) / static_cast<float>(d_fs_in); | ||||
|     float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(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) | ||||
| @@ -210,28 +351,46 @@ 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; | ||||
|         } | ||||
|     phase_step_rad_int_temp = phase_step_rad_real * POW_2_2;               // * 2^2 | ||||
|     phase_step_rad_int = (int32_t)(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+ 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<int32_t>(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, uint32_t *initial_sample, float *power_sum) | ||||
|     float *max_magnitude, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index) | ||||
| { | ||||
|     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 = readval; | ||||
|     readval = d_map_base[2]; | ||||
|     initial_sample_tmp = readval; | ||||
|     readval_long = d_map_base[2]; | ||||
|     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<float>(readval); | ||||
|     //printf("read max_magnitude dmap 2 = %d\n", readval); | ||||
|     readval = d_map_base[4]; | ||||
|     *power_sum = static_cast<float>(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]; | ||||
|     *max_index = readval; | ||||
|     //printf("read max index dmap 3 = %d\n", readval); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -260,5 +419,5 @@ void fpga_acquisition::close_device() | ||||
|  | ||||
| void fpga_acquisition::reset_acquisition(void) | ||||
| { | ||||
|     d_map_base[6] = RESET_ACQUISITION;  // writing a 2 to d_map_base[6] resets the multicorrelator | ||||
|     d_map_base[8] = RESET_ACQUISITION;  // writing a 2 to d_map_base[8] resets the multicorrelator | ||||
| } | ||||
|   | ||||
| @@ -59,10 +59,12 @@ public: | ||||
|     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, | ||||
|         uint32_t *initial_sample, float *power_sum); | ||||
|         uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index); | ||||
|     void block_samples(); | ||||
|     void unblock_samples(); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez