1
0
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:
Carles Fernandez
2018-08-11 12:56:52 +02:00
42 changed files with 6582 additions and 488 deletions

View File

@@ -19,3 +19,4 @@
add_subdirectory(adapters)
add_subdirectory(gnuradio_blocks)
add_subdirectory(libs)

View File

@@ -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)

View File

@@ -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");
}

View File

@@ -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_ */

View File

@@ -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_;
}

View File

@@ -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_ */

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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_;
}

View File

@@ -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_ */

View File

@@ -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_;
}

View File

@@ -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_ */

View File

@@ -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)

View File

@@ -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

View File

@@ -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");
}
/*!

View File

@@ -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();

View File

@@ -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
}

View File

@@ -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();