mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-01-06 07:20:34 +00:00
Created a generic gnuradio block acquisition class for the FPGA.
This commit is contained in:
parent
6a3770c762
commit
512bf3f4cf
@ -1,14 +1,18 @@
|
||||
|
||||
/*!
|
||||
* \file gps_l1_ca_pcps_acquisition_fpga.cc
|
||||
* \brief Adapts a PCPS acquisition block to an FPGA Acquisition Interface for
|
||||
* GPS L1 C/A signals. This file is based on the file gps_l1_ca_pcps_acquisition.cc
|
||||
* \brief Adapts a PCPS acquisition block to an FPGA AcquisitionInterface
|
||||
* for GPS L1 C/A signals
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* <li> Marc Majoral, 2018. mmajoral(at)cttc.es
|
||||
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
|
||||
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
|
||||
* <li> Marc Molina, 2013. marc.molina.pena(at)gmail.com
|
||||
* </ul>
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (C) 2010-2017 (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
|
||||
@ -30,88 +34,109 @@
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "gps_l1_ca_pcps_acquisition_fpga.h"
|
||||
#include <boost/math/distributions/exponential.hpp>
|
||||
#include <new>
|
||||
#include <gnuradio/fft/fft.h>
|
||||
#include <volk/volk.h>
|
||||
#include <glog/logging.h>
|
||||
#include "GPS_L1_CA.h"
|
||||
#include "gps_l1_ca_pcps_acquisition_fpga.h"
|
||||
#include "configuration_interface.h"
|
||||
#include "gps_sdr_signal_processing.h"
|
||||
#include "GPS_L1_CA.h"
|
||||
#include "gnss_sdr_flags.h"
|
||||
|
||||
#define NUM_PRNs 32
|
||||
|
||||
using google::LogMessage;
|
||||
|
||||
GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
ConfigurationInterface* configuration, std::string role,
|
||||
unsigned int in_streams, unsigned int out_streams) :
|
||||
role_(role), in_streams_(in_streams), out_streams_(out_streams)
|
||||
ConfigurationInterface* configuration, std::string role,
|
||||
unsigned int in_streams, unsigned int out_streams) : role_(role), in_streams_(in_streams), out_streams_(out_streams)
|
||||
{
|
||||
unsigned int code_length;
|
||||
bool bit_transition_flag;
|
||||
bool use_CFAR_algorithm_flag;
|
||||
unsigned int sampled_ms;
|
||||
long fs_in;
|
||||
long ifreq;
|
||||
bool dump;
|
||||
std::string dump_filename;
|
||||
unsigned int nsamples_total;
|
||||
unsigned int select_queue_Fpga;
|
||||
std::string device_name;
|
||||
pcpsconf_fpga_t acq_parameters;
|
||||
configuration_ = configuration;
|
||||
std::string default_item_type = "cshort";
|
||||
std::string default_dump_filename = "./data/acquisition.dat";
|
||||
std::string default_item_type = "gr_complex";
|
||||
|
||||
DLOG(INFO) << "role " << role;
|
||||
item_type_ = configuration_->property(role + ".item_type",
|
||||
default_item_type);
|
||||
fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", 2048000);
|
||||
ifreq = configuration_->property(role + ".if", 0);
|
||||
dump = configuration_->property(role + ".dump", false);
|
||||
|
||||
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_;
|
||||
doppler_max_ = configuration_->property(role + ".doppler_max", 5000);
|
||||
sampled_ms = configuration_->property(
|
||||
role + ".coherent_integration_time_ms", 1);
|
||||
// note : the FPGA is implemented according to bit transition flag = 0. Setting bit transition flag to 1 has no effect.
|
||||
bit_transition_flag = configuration_->property(
|
||||
role + ".bit_transition_flag", false);
|
||||
// note : the FPGA is implemented according to use_CFAR_algorithm = 0. Setting use_CFAR_algorithm to 1 has no effect.
|
||||
use_CFAR_algorithm_flag = configuration_->property(
|
||||
role + ".use_CFAR_algorithm", false);
|
||||
// note : the FPGA does not use the max_dwells variable.
|
||||
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
|
||||
dump_filename = configuration_->property(role + ".dump_filename",
|
||||
default_dump_filename);
|
||||
//--- Find number of samples per spreading code -------------------------
|
||||
code_length = round(
|
||||
fs_in / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS));
|
||||
// code length has the same value as d_fft_size
|
||||
float nbits;
|
||||
nbits = ceilf(log2f(code_length));
|
||||
nsamples_total = pow(2, nbits);
|
||||
//vector_length_ = code_length_ * sampled_ms_;
|
||||
vector_length_ = nsamples_total * sampled_ms;
|
||||
// if( bit_transition_flag_ )
|
||||
// {
|
||||
// vector_length_ *= 2;
|
||||
// }
|
||||
select_queue_Fpga = configuration_->property(role + ".select_queue_Fpga",
|
||||
0);
|
||||
std::string default_device_name = "/dev/uio0";
|
||||
device_name = configuration_->property(role + ".devicename",
|
||||
default_device_name);
|
||||
if (item_type_.compare("cshort") == 0)
|
||||
if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max;
|
||||
acq_parameters.doppler_max = doppler_max_;
|
||||
sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1);
|
||||
acq_parameters.sampled_ms = sampled_ms_;
|
||||
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)));
|
||||
|
||||
// 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);
|
||||
vector_length_ = nsamples_total * sampled_ms_;
|
||||
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_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)
|
||||
|
||||
// Direct FFT
|
||||
gr::fft::fft_complex* fft_if = new gr::fft::fft_complex(vector_length_, true);
|
||||
// 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++)
|
||||
{
|
||||
item_size_ = sizeof(lv_16sc_t);
|
||||
gps_acquisition_fpga_sc_ = gps_pcps_make_acquisition_fpga_sc(
|
||||
sampled_ms, max_dwells_, doppler_max_, ifreq, fs_in,
|
||||
code_length, code_length, vector_length_, nsamples_total,
|
||||
bit_transition_flag, use_CFAR_algorithm_flag,
|
||||
select_queue_Fpga, device_name, dump, dump_filename);
|
||||
DLOG(INFO) << "acquisition("
|
||||
<< gps_acquisition_fpga_sc_->unique_id() << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(FATAL) << item_type_ << " FPGA only accepts chsort";
|
||||
}
|
||||
gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in_, 0); // generate PRN code
|
||||
// fill in zero padding
|
||||
for (int s=code_length_;s<nsamples_total;s++)
|
||||
{
|
||||
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
|
||||
{
|
||||
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.all_fft_codes = d_all_fft_codes;
|
||||
//acq_parameters
|
||||
// temporary buffers that we can delete
|
||||
delete[] code;
|
||||
delete fft_if;
|
||||
delete[] fft_codes_padded;
|
||||
|
||||
acquisition_fpga_ = pcps_make_acquisition(acq_parameters);
|
||||
DLOG(INFO) << "acquisition(" << acquisition_fpga_->unique_id() << ")";
|
||||
|
||||
channel_ = 0;
|
||||
threshold_ = 0.0;
|
||||
doppler_step_ = 0;
|
||||
gnss_synchro_ = 0;
|
||||
}
|
||||
@ -119,123 +144,94 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
|
||||
GpsL1CaPcpsAcquisitionFpga::~GpsL1CaPcpsAcquisitionFpga()
|
||||
{
|
||||
//delete[] code_;
|
||||
delete[] d_all_fft_codes;
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_channel(unsigned int channel)
|
||||
{
|
||||
channel_ = channel;
|
||||
gps_acquisition_fpga_sc_->set_channel(channel_);
|
||||
acquisition_fpga_->set_channel(channel_);
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_threshold(float threshold)
|
||||
{
|
||||
float pfa = configuration_->property(role_ + ".pfa", 0.0);
|
||||
|
||||
if (pfa == 0.0)
|
||||
{
|
||||
threshold_ = threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
threshold_ = calculate_threshold(pfa);
|
||||
}
|
||||
|
||||
DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold_;
|
||||
gps_acquisition_fpga_sc_->set_threshold(threshold_);
|
||||
DLOG(INFO) << "Channel " << channel_ << " Threshold = " << threshold;
|
||||
acquisition_fpga_->set_threshold(threshold);
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_doppler_max(unsigned int doppler_max)
|
||||
{
|
||||
doppler_max_ = doppler_max;
|
||||
gps_acquisition_fpga_sc_->set_doppler_max(doppler_max_);
|
||||
acquisition_fpga_->set_doppler_max(doppler_max_);
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_doppler_step(unsigned int doppler_step)
|
||||
{
|
||||
doppler_step_ = doppler_step;
|
||||
gps_acquisition_fpga_sc_->set_doppler_step(doppler_step_);
|
||||
acquisition_fpga_->set_doppler_step(doppler_step_);
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_gnss_synchro(Gnss_Synchro* gnss_synchro)
|
||||
{
|
||||
gnss_synchro_ = gnss_synchro;
|
||||
gps_acquisition_fpga_sc_->set_gnss_synchro(gnss_synchro_);
|
||||
acquisition_fpga_->set_gnss_synchro(gnss_synchro_);
|
||||
}
|
||||
|
||||
|
||||
signed int GpsL1CaPcpsAcquisitionFpga::mag()
|
||||
{
|
||||
return gps_acquisition_fpga_sc_->mag();
|
||||
return acquisition_fpga_->mag();
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::init()
|
||||
{
|
||||
gps_acquisition_fpga_sc_->init();
|
||||
acquisition_fpga_->init();
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_local_code()
|
||||
{
|
||||
gps_acquisition_fpga_sc_->set_local_code();
|
||||
acquisition_fpga_->set_local_code();
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::reset()
|
||||
{
|
||||
gps_acquisition_fpga_sc_->set_active(true);
|
||||
acquisition_fpga_->set_active(true);
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::set_state(int state)
|
||||
{
|
||||
gps_acquisition_fpga_sc_->set_state(state);
|
||||
}
|
||||
|
||||
|
||||
float GpsL1CaPcpsAcquisitionFpga::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 / 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;
|
||||
acquisition_fpga_->set_state(state);
|
||||
}
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::connect(gr::top_block_sptr top_block)
|
||||
{
|
||||
//nothing to connect
|
||||
// nothing to connect
|
||||
}
|
||||
|
||||
|
||||
void GpsL1CaPcpsAcquisitionFpga::disconnect(gr::top_block_sptr top_block)
|
||||
{
|
||||
//nothing to disconnect
|
||||
// nothing to disconnect
|
||||
}
|
||||
|
||||
|
||||
gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_left_block()
|
||||
{
|
||||
return gps_acquisition_fpga_sc_;
|
||||
return acquisition_fpga_;
|
||||
}
|
||||
|
||||
|
||||
gr::basic_block_sptr GpsL1CaPcpsAcquisitionFpga::get_right_block()
|
||||
{
|
||||
return gps_acquisition_fpga_sc_;
|
||||
return acquisition_fpga_;
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
/*!
|
||||
* \file gps_l1_ca_pcps_acquisition_fpga.h
|
||||
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
|
||||
* GPS L1 C/A signals. This file is based on the file gps_l1_ca_pcps_acquisition.h
|
||||
* \brief Adapts a PCPS acquisition block that uses the FPGA to
|
||||
* an AcquisitionInterface for GPS L1 C/A signals
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* <li> Marc Majoral, 2018. mmajoral(at)cttc.es
|
||||
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
|
||||
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
|
||||
* <li> Marc Molina, 2013. marc.molina.pena(at)gmail.com
|
||||
* </ul>
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (C) 2010-2017 (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
|
||||
@ -34,14 +37,11 @@
|
||||
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_
|
||||
#define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_
|
||||
|
||||
#include <string>
|
||||
#include <gnuradio/blocks/stream_to_vector.h>
|
||||
#include <gnuradio/blocks/float_to_complex.h>
|
||||
#include "gnss_synchro.h"
|
||||
#include "acquisition_interface.h"
|
||||
#include "gps_pcps_acquisition_fpga_sc.h"
|
||||
#include "complex_byte_to_float_x2.h"
|
||||
#include <volk_gnsssdr/volk_gnsssdr.h>
|
||||
#include "gnss_synchro.h"
|
||||
#include "pcps_acquisition_fpga.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
class ConfigurationInterface;
|
||||
|
||||
@ -68,12 +68,13 @@ public:
|
||||
*/
|
||||
inline std::string implementation() override
|
||||
{
|
||||
return "GPS_L1_CA_PCPS_Acquisition_Fpga";
|
||||
return "GPS_L1_CA_PCPS_Acquisition";
|
||||
}
|
||||
|
||||
inline size_t item_size() override
|
||||
{
|
||||
return item_size_;
|
||||
size_t item_size = sizeof(lv_16sc_t);
|
||||
return item_size;
|
||||
}
|
||||
|
||||
void connect(gr::top_block_sptr top_block) override;
|
||||
@ -135,21 +136,21 @@ public:
|
||||
|
||||
private:
|
||||
ConfigurationInterface* configuration_;
|
||||
gps_pcps_acquisition_fpga_sc_sptr gps_acquisition_fpga_sc_;
|
||||
size_t item_size_;
|
||||
std::string item_type_;
|
||||
pcps_acquisition_fpga_sptr acquisition_fpga_;
|
||||
unsigned int vector_length_;
|
||||
unsigned int code_length_;
|
||||
unsigned int channel_;
|
||||
float threshold_;
|
||||
unsigned int doppler_max_;
|
||||
unsigned int doppler_step_;
|
||||
unsigned int max_dwells_;
|
||||
unsigned int sampled_ms_;
|
||||
long fs_in_;
|
||||
long if_;
|
||||
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_L1_CA_PCPS_ACQUISITION_H_ */
|
||||
#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ */
|
||||
|
@ -29,7 +29,7 @@ set(ACQ_GR_BLOCKS_SOURCES
|
||||
)
|
||||
|
||||
if(ENABLE_FPGA)
|
||||
set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} gps_pcps_acquisition_fpga_sc.cc)
|
||||
set(ACQ_GR_BLOCKS_SOURCES ${ACQ_GR_BLOCKS_SOURCES} pcps_acquisition_fpga.cc)
|
||||
endif(ENABLE_FPGA)
|
||||
|
||||
if(OPENCL_FOUND)
|
||||
|
@ -1,298 +0,0 @@
|
||||
/*!
|
||||
* \file gps_pcps_acquisition_fpga_sc.cc
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA.
|
||||
* This file is based on the file gps_pcps_acquisition_sc.cc
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* </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_pcps_acquisition_fpga_sc.h"
|
||||
#include <sstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <gnuradio/io_signature.h>
|
||||
#include <glog/logging.h>
|
||||
#include <volk/volk.h>
|
||||
#include <volk_gnsssdr/volk_gnsssdr.h>
|
||||
#include "control_message_factory.h"
|
||||
#include "GPS_L1_CA.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
using google::LogMessage;
|
||||
|
||||
void wait3(int seconds)
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds
|
||||
{ seconds });
|
||||
}
|
||||
|
||||
|
||||
gps_pcps_acquisition_fpga_sc_sptr gps_pcps_make_acquisition_fpga_sc(
|
||||
unsigned int sampled_ms, unsigned int max_dwells,
|
||||
unsigned int doppler_max, long freq, long fs_in, int samples_per_ms,
|
||||
int samples_per_code, int vector_length, unsigned int nsamples_total,
|
||||
bool bit_transition_flag, bool use_CFAR_algorithm_flag,
|
||||
unsigned int select_queue_Fpga, std::string device_name, bool dump,
|
||||
std::string dump_filename)
|
||||
{
|
||||
return gps_pcps_acquisition_fpga_sc_sptr(
|
||||
new gps_pcps_acquisition_fpga_sc(sampled_ms, max_dwells,
|
||||
doppler_max, freq, fs_in, samples_per_ms, samples_per_code,
|
||||
vector_length, nsamples_total, bit_transition_flag,
|
||||
use_CFAR_algorithm_flag, select_queue_Fpga, device_name,
|
||||
dump, dump_filename));
|
||||
}
|
||||
|
||||
|
||||
gps_pcps_acquisition_fpga_sc::gps_pcps_acquisition_fpga_sc(
|
||||
unsigned int sampled_ms, unsigned int max_dwells,
|
||||
unsigned int doppler_max, long freq, long fs_in, int samples_per_ms,
|
||||
int samples_per_code, int vector_length, unsigned int nsamples_total,
|
||||
bool bit_transition_flag, bool use_CFAR_algorithm_flag,
|
||||
unsigned int select_queue_Fpga, std::string device_name, bool dump,
|
||||
std::string dump_filename) :
|
||||
|
||||
//gr::block("pcps_acquisition_fpga_sc",
|
||||
gr::block("gps_pcps_acquisition_fpga_sc",
|
||||
gr::io_signature::make(0, 0, sizeof(lv_16sc_t)),
|
||||
gr::io_signature::make(0, 0, 0))
|
||||
{
|
||||
this->message_port_register_out(pmt::mp("events"));
|
||||
d_sample_counter = 0; // sample counter
|
||||
d_active = false;
|
||||
d_state = 0;
|
||||
d_samples_per_code = samples_per_code;
|
||||
d_max_dwells = max_dwells; // Note : d_max_dwells is not used in the FPGA implementation
|
||||
d_well_count = 0;
|
||||
d_doppler_max = doppler_max;
|
||||
d_fft_size = sampled_ms * samples_per_ms;
|
||||
d_mag = 0;
|
||||
d_num_doppler_bins = 0;
|
||||
d_bit_transition_flag = bit_transition_flag; // Note : bit transition flag is ignored and assumed 0 in the FPGA implementation
|
||||
d_use_CFAR_algorithm_flag = use_CFAR_algorithm_flag; // Note : user CFAR algorithm flag is ignored and assumed 0 in the FPGA implementation
|
||||
d_threshold = 0.0;
|
||||
d_doppler_step = 250;
|
||||
d_channel = 0;
|
||||
// For dumping samples into a file
|
||||
d_dump = dump;
|
||||
d_dump_filename = dump_filename;
|
||||
d_gnss_synchro = 0;
|
||||
// instantiate HW accelerator class
|
||||
acquisition_fpga_8sc = std::make_shared < gps_fpga_acquisition_8sc>
|
||||
(device_name, vector_length, d_fft_size, doppler_max, nsamples_total, fs_in, freq, sampled_ms, select_queue_Fpga);
|
||||
}
|
||||
|
||||
|
||||
gps_pcps_acquisition_fpga_sc::~gps_pcps_acquisition_fpga_sc()
|
||||
{
|
||||
if (d_dump)
|
||||
{
|
||||
d_dump_file.close();
|
||||
}
|
||||
acquisition_fpga_8sc->free();
|
||||
}
|
||||
|
||||
|
||||
void gps_pcps_acquisition_fpga_sc::set_local_code()
|
||||
{
|
||||
acquisition_fpga_8sc->set_local_code(d_gnss_synchro->PRN);
|
||||
}
|
||||
|
||||
|
||||
void gps_pcps_acquisition_fpga_sc::init()
|
||||
{
|
||||
d_gnss_synchro->Flag_valid_acquisition = false;
|
||||
d_gnss_synchro->Flag_valid_symbol_output = false;
|
||||
d_gnss_synchro->Flag_valid_pseudorange = false;
|
||||
d_gnss_synchro->Flag_valid_word = false;
|
||||
d_gnss_synchro->Acq_delay_samples = 0.0;
|
||||
d_gnss_synchro->Acq_doppler_hz = 0.0;
|
||||
d_gnss_synchro->Acq_samplestamp_samples = 0;
|
||||
d_mag = 0.0;
|
||||
d_num_doppler_bins = ceil(
|
||||
static_cast<double>(static_cast<int>(d_doppler_max)
|
||||
- static_cast<int>(-d_doppler_max))
|
||||
/ static_cast<double>(d_doppler_step));
|
||||
//acquisition_fpga_8sc->open_device();
|
||||
acquisition_fpga_8sc->init();
|
||||
}
|
||||
|
||||
|
||||
void gps_pcps_acquisition_fpga_sc::set_state(int state)
|
||||
{
|
||||
d_state = state;
|
||||
if (d_state == 1)
|
||||
{
|
||||
d_gnss_synchro->Acq_delay_samples = 0.0;
|
||||
d_gnss_synchro->Acq_doppler_hz = 0.0;
|
||||
d_gnss_synchro->Acq_samplestamp_samples = 0;
|
||||
d_well_count = 0;
|
||||
d_mag = 0.0;
|
||||
}
|
||||
else if (d_state == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ERROR) << "State can only be set to 0 or 1";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void gps_pcps_acquisition_fpga_sc::set_active(bool active)
|
||||
{
|
||||
float temp_peak_to_noise_level = 0.0;
|
||||
float peak_to_noise_level = 0.0;
|
||||
float input_power;
|
||||
float test_statistics = 0.0;
|
||||
//printf("ACQ : Block samples for PRN %d\n", d_gnss_synchro->PRN);
|
||||
// acquisition_fpga_8sc->block_samples(); // block the samples to run the acquisition this is only necessary for the tests
|
||||
d_active = active;
|
||||
int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
|
||||
d_state = 1;
|
||||
// initialize acquisition algorithm
|
||||
int doppler;
|
||||
uint32_t indext = 0;
|
||||
float magt = 0.0;
|
||||
//int effective_fft_size = ( d_bit_transition_flag ? d_fft_size/2 : d_fft_size );
|
||||
int effective_fft_size = d_fft_size;
|
||||
d_mag = 0.0;
|
||||
unsigned int initial_sample;
|
||||
d_well_count++;
|
||||
DLOG(INFO) << "Channel: " << d_channel
|
||||
<< " , doing acquisition of satellite: " << d_gnss_synchro->System
|
||||
<< " " << d_gnss_synchro->PRN << " ,sample stamp: "
|
||||
<< d_sample_counter << ", threshold: " << ", threshold: "
|
||||
<< d_threshold << ", doppler_max: " << d_doppler_max
|
||||
<< ", doppler_step: " << d_doppler_step;
|
||||
|
||||
// Doppler frequency search loop
|
||||
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins;
|
||||
doppler_index++)
|
||||
{
|
||||
|
||||
doppler = -static_cast<int>(d_doppler_max) + d_doppler_step * doppler_index;
|
||||
|
||||
acquisition_fpga_8sc->set_phase_step(doppler_index);
|
||||
acquisition_fpga_8sc->run_acquisition(); // runs acquisition and waits until it is finished
|
||||
acquisition_fpga_8sc->read_acquisition_results(&indext, &magt,
|
||||
&initial_sample, &input_power);
|
||||
d_sample_counter = initial_sample;
|
||||
temp_peak_to_noise_level = static_cast<float>(magt) / static_cast<float>(input_power);
|
||||
if (peak_to_noise_level < temp_peak_to_noise_level)
|
||||
{
|
||||
peak_to_noise_level = temp_peak_to_noise_level;
|
||||
d_mag = magt;
|
||||
input_power = (input_power - d_mag)
|
||||
/ (effective_fft_size - 1);
|
||||
d_gnss_synchro->Acq_delay_samples =
|
||||
static_cast<double>(indext % d_samples_per_code);
|
||||
d_gnss_synchro->Acq_doppler_hz =
|
||||
static_cast<double>(doppler);
|
||||
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
|
||||
test_statistics = d_mag / input_power;
|
||||
}
|
||||
// Record results to file if required
|
||||
if (d_dump)
|
||||
{
|
||||
std::stringstream filename;
|
||||
//std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write
|
||||
filename.str("");
|
||||
boost::filesystem::path p = d_dump_filename;
|
||||
filename << p.parent_path().string()
|
||||
<< boost::filesystem::path::preferred_separator
|
||||
<< p.stem().string() << "_"
|
||||
<< d_gnss_synchro->System << "_"
|
||||
<< d_gnss_synchro->Signal << "_sat_"
|
||||
<< d_gnss_synchro->PRN << "_doppler_" << doppler
|
||||
<< p.extension().string();
|
||||
DLOG(INFO) << "Writing ACQ out to " << filename.str();
|
||||
d_dump_file.open(filename.str().c_str(),
|
||||
std::ios::out | std::ios::binary);
|
||||
d_dump_file.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//printf("ACQ : unblocking samples for satellite %d\n", d_gnss_synchro->PRN);
|
||||
// acquisition_fpga_8sc->unblock_samples(); // unblock samples before sending positive or negative acquisition message to let the samples flow when the
|
||||
// set local code function is called
|
||||
if (test_statistics > d_threshold)
|
||||
{
|
||||
d_state = 2; // Positive acquisition
|
||||
// 6.1- Declare positive acquisition using a message port
|
||||
DLOG(INFO) << "positive acquisition";
|
||||
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " "
|
||||
<< d_gnss_synchro->PRN;
|
||||
DLOG(INFO) << "sample_stamp " << d_sample_counter;
|
||||
DLOG(INFO) << "test statistics value " << test_statistics;
|
||||
DLOG(INFO) << "test statistics threshold " << d_threshold;
|
||||
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
|
||||
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
|
||||
DLOG(INFO) << "magnitude " << d_mag;
|
||||
DLOG(INFO) << "input signal power " << input_power;
|
||||
d_active = false;
|
||||
d_state = 0;
|
||||
acquisition_message = 1;
|
||||
this->message_port_pub(pmt::mp("events"),
|
||||
pmt::from_long(acquisition_message));
|
||||
}
|
||||
else
|
||||
{
|
||||
d_state = 3; // Negative acquisition
|
||||
// 6.2- Declare negative acquisition using a message port
|
||||
DLOG(INFO) << "negative acquisition";
|
||||
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " "
|
||||
<< d_gnss_synchro->PRN;
|
||||
DLOG(INFO) << "sample_stamp " << d_sample_counter;
|
||||
DLOG(INFO) << "test statistics value " << test_statistics;
|
||||
DLOG(INFO) << "test statistics threshold " << d_threshold;
|
||||
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
|
||||
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
|
||||
DLOG(INFO) << "magnitude " << d_mag;
|
||||
DLOG(INFO) << "input signal power " << input_power;
|
||||
d_active = false;
|
||||
d_state = 0;
|
||||
acquisition_message = 2;
|
||||
this->message_port_pub(pmt::mp("events"),
|
||||
pmt::from_long(acquisition_message));
|
||||
}
|
||||
DLOG(INFO) << "Done. Consumed 1 item.";
|
||||
}
|
||||
|
||||
|
||||
int gps_pcps_acquisition_fpga_sc::general_work(int noutput_items,
|
||||
gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items __attribute__((unused)),
|
||||
gr_vector_void_star &output_items __attribute__((unused)))
|
||||
{
|
||||
// general work not used with the acquisition
|
||||
return noutput_items;
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
/*!
|
||||
* \file gps_pcps_acquisition_fpga_sc.h
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA.
|
||||
* This file is based on the file gps_pcps_acquisition_sc.h
|
||||
*
|
||||
* Acquisition strategy (Kay Borre book + CFAR threshold).
|
||||
* <ol>
|
||||
* <li> Compute the input signal power estimation
|
||||
* <li> Doppler serial search loop
|
||||
* <li> Perform the FFT-based circular convolution (parallel time search)
|
||||
* <li> Record the maximum peak and the associated synchronization parameters
|
||||
* <li> Compute the test statistics and compare to the threshold
|
||||
* <li> Declare positive or negative acquisition using a message port
|
||||
* </ol>
|
||||
*
|
||||
* Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
|
||||
* "A Software-Defined GPS and Galileo Receiver. A Single-Frequency
|
||||
* Approach", Birkhauser, 2007. pp 81-84
|
||||
*
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* </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_PCPS_ACQUISITION_FPGA_SC_H_
|
||||
#define GNSS_SDR_GPS_PCPS_ACQUISITION_FPGA_SC_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <gnuradio/block.h>
|
||||
#include <gnuradio/gr_complex.h>
|
||||
#include <gnuradio/fft/fft.h>
|
||||
#include "gnss_synchro.h"
|
||||
#include "gps_fpga_acquisition_8sc.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
class gps_pcps_acquisition_fpga_sc;
|
||||
|
||||
typedef boost::shared_ptr<gps_pcps_acquisition_fpga_sc> gps_pcps_acquisition_fpga_sc_sptr;
|
||||
|
||||
gps_pcps_acquisition_fpga_sc_sptr
|
||||
gps_pcps_make_acquisition_fpga_sc(unsigned int sampled_ms,
|
||||
unsigned int max_dwells, unsigned int doppler_max, long freq,
|
||||
long fs_in, int samples_per_ms, int samples_per_code,
|
||||
int vector_length_, unsigned int nsamples_total_,
|
||||
bool bit_transition_flag, bool use_CFAR_algorithm_flag,
|
||||
unsigned int select_queue_Fpga, std::string device_name, bool dump,
|
||||
std::string dump_filename);
|
||||
|
||||
/*!
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition.
|
||||
*
|
||||
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
|
||||
* Algorithm 1, for a pseudocode description of this implementation.
|
||||
*/
|
||||
class gps_pcps_acquisition_fpga_sc : public gr::block
|
||||
{
|
||||
private:
|
||||
friend gps_pcps_acquisition_fpga_sc_sptr
|
||||
gps_pcps_make_acquisition_fpga_sc(unsigned int sampled_ms,
|
||||
unsigned int max_dwells, unsigned int doppler_max, long freq,
|
||||
long fs_in, int samples_per_ms, int samples_per_code,
|
||||
int vector_length, unsigned int nsamples_total,
|
||||
bool bit_transition_flag, bool use_CFAR_algorithm_flag,
|
||||
unsigned int select_queue_Fpga, std::string device_name, bool dump,
|
||||
std::string dump_filename);
|
||||
|
||||
gps_pcps_acquisition_fpga_sc(unsigned int sampled_ms,
|
||||
unsigned int max_dwells, unsigned int doppler_max, long freq,
|
||||
long fs_in, int samples_per_ms, int samples_per_code,
|
||||
int vector_length, unsigned int nsamples_total,
|
||||
bool bit_transition_flag, bool use_CFAR_algorithm_flag,
|
||||
unsigned int select_queue_Fpga, std::string device_name, bool dump,
|
||||
std::string dump_filename);
|
||||
int d_samples_per_code;
|
||||
float d_threshold;
|
||||
unsigned int d_doppler_max;
|
||||
unsigned int d_doppler_step;
|
||||
unsigned int d_max_dwells;
|
||||
unsigned int d_well_count;
|
||||
unsigned int d_fft_size;
|
||||
unsigned long int d_sample_counter;
|
||||
unsigned int d_num_doppler_bins;
|
||||
Gnss_Synchro *d_gnss_synchro;
|
||||
float d_mag;bool d_bit_transition_flag;bool d_use_CFAR_algorithm_flag;
|
||||
std::ofstream d_dump_file;
|
||||
bool d_active;
|
||||
int d_state;bool d_dump;
|
||||
unsigned int d_channel;
|
||||
std::string d_dump_filename;
|
||||
std::shared_ptr<gps_fpga_acquisition_8sc> acquisition_fpga_8sc;
|
||||
//void set_active2(bool active);
|
||||
boost::thread d_acq_thread;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Default destructor.
|
||||
*/
|
||||
~gps_pcps_acquisition_fpga_sc();
|
||||
|
||||
/*!
|
||||
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
|
||||
* to exchange synchronization data between acquisition and tracking blocks.
|
||||
* \param p_gnss_synchro Satellite information shared by the processing blocks.
|
||||
*/
|
||||
inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
|
||||
{
|
||||
d_gnss_synchro = p_gnss_synchro;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the maximum peak of grid search.
|
||||
*/
|
||||
inline unsigned int mag() const
|
||||
{
|
||||
return d_mag;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes acquisition algorithm.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*!
|
||||
* \brief Sets local code for PCPS acquisition algorithm.
|
||||
* \param code - Pointer to the PRN code.
|
||||
*/
|
||||
void set_local_code();
|
||||
|
||||
/*!
|
||||
* \brief Starts acquisition algorithm, turning from standby mode to
|
||||
* active mode
|
||||
* \param active - bool that activates/deactivates the block.
|
||||
*/
|
||||
|
||||
|
||||
void set_active(bool active);
|
||||
|
||||
/*!
|
||||
* \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);
|
||||
|
||||
/*!
|
||||
* \brief Set acquisition channel unique ID
|
||||
* \param channel - receiver channel.
|
||||
*/
|
||||
inline void set_channel(unsigned int channel)
|
||||
{
|
||||
d_channel = channel;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set statistics threshold of PCPS algorithm.
|
||||
* \param threshold - Threshold for signal detection (check \ref Navitec2012,
|
||||
* Algorithm 1, for a definition of this threshold).
|
||||
*/
|
||||
inline void set_threshold(float threshold)
|
||||
{
|
||||
d_threshold = threshold;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set maximum Doppler grid search
|
||||
* \param doppler_max - Maximum Doppler shift considered in the grid search [Hz].
|
||||
*/
|
||||
inline void set_doppler_max(unsigned int doppler_max)
|
||||
{
|
||||
d_doppler_max = doppler_max;
|
||||
acquisition_fpga_8sc->set_doppler_max(doppler_max);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set Doppler steps for the grid search
|
||||
* \param doppler_step - Frequency bin of the search grid [Hz].
|
||||
*/
|
||||
inline void set_doppler_step(unsigned int doppler_step)
|
||||
{
|
||||
d_doppler_step = doppler_step;
|
||||
acquisition_fpga_8sc->set_doppler_step(doppler_step);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Parallel Code Phase Search Acquisition signal processing.
|
||||
*/
|
||||
int general_work(int noutput_items, gr_vector_int &ninput_items,
|
||||
gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items);
|
||||
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_GPS_PCPS_ACQUISITION_SC_H_*/
|
@ -0,0 +1,247 @@
|
||||
/*!
|
||||
* \file pcps_acquisition_fpga.cc
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA
|
||||
*
|
||||
* Note: The CFAR algorithm is not implemented in the FPGA.
|
||||
* Note 2: The bit transition flag is not implemented in the FPGA
|
||||
*
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
|
||||
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
|
||||
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
|
||||
* <li> Cillian O'Driscoll, 2017. cillian(at)ieee.org
|
||||
* </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 "pcps_acquisition_fpga.h"
|
||||
#include "GPS_L1_CA.h" // for GPS_TWO_PI
|
||||
#include "GLONASS_L1_L2_CA.h" // for GLONASS_TWO_PI"
|
||||
#include <glog/logging.h>
|
||||
#include <gnuradio/io_signature.h>
|
||||
|
||||
using google::LogMessage;
|
||||
|
||||
pcps_acquisition_fpga_sptr pcps_make_acquisition(pcpsconf_fpga_t conf_)
|
||||
{
|
||||
return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(conf_));
|
||||
}
|
||||
|
||||
|
||||
pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_) : gr::block("pcps_acquisition_fpga",
|
||||
gr::io_signature::make(0, 0, 0),
|
||||
gr::io_signature::make(0, 0, 0))
|
||||
{
|
||||
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_mag = 0;
|
||||
d_input_power = 0.0;
|
||||
d_num_doppler_bins = 0;
|
||||
d_threshold = 0.0;
|
||||
d_doppler_step = 0;
|
||||
d_test_statistics = 0.0;
|
||||
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,
|
||||
acq_parameters.fs_in, acq_parameters.freq, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes);
|
||||
|
||||
}
|
||||
|
||||
|
||||
pcps_acquisition_fpga::~pcps_acquisition_fpga()
|
||||
{
|
||||
acquisition_fpga->free();
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::set_local_code()
|
||||
{
|
||||
acquisition_fpga->set_local_code(d_gnss_synchro->PRN);
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::init()
|
||||
{
|
||||
d_gnss_synchro->Flag_valid_acquisition = false;
|
||||
d_gnss_synchro->Flag_valid_symbol_output = false;
|
||||
d_gnss_synchro->Flag_valid_pseudorange = false;
|
||||
d_gnss_synchro->Flag_valid_word = false;
|
||||
d_gnss_synchro->Acq_delay_samples = 0.0;
|
||||
d_gnss_synchro->Acq_doppler_hz = 0.0;
|
||||
d_gnss_synchro->Acq_samplestamp_samples = 0;
|
||||
d_mag = 0.0;
|
||||
d_input_power = 0.0;
|
||||
d_num_doppler_bins = static_cast<unsigned int>(std::ceil(static_cast<double>(static_cast<int>(acq_parameters.doppler_max) - static_cast<int>(-acq_parameters.doppler_max)) / static_cast<double>(d_doppler_step)));
|
||||
|
||||
acquisition_fpga->init();
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::set_state(int state)
|
||||
{
|
||||
d_state = state;
|
||||
if (d_state == 1)
|
||||
{
|
||||
d_gnss_synchro->Acq_delay_samples = 0.0;
|
||||
d_gnss_synchro->Acq_doppler_hz = 0.0;
|
||||
d_gnss_synchro->Acq_samplestamp_samples = 0;
|
||||
//d_well_count = 0;
|
||||
d_mag = 0.0;
|
||||
d_input_power = 0.0;
|
||||
d_test_statistics = 0.0;
|
||||
d_active = true;
|
||||
}
|
||||
else if (d_state == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(ERROR) << "State can only be set to 0 or 1";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::send_positive_acquisition()
|
||||
{
|
||||
// 6.1- Declare positive acquisition using a message port
|
||||
//0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
|
||||
DLOG(INFO) << "positive acquisition"
|
||||
<< ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN
|
||||
<< ", sample_stamp " << d_sample_counter
|
||||
<< ", test statistics value " << d_test_statistics
|
||||
<< ", test statistics threshold " << d_threshold
|
||||
<< ", code phase " << d_gnss_synchro->Acq_delay_samples
|
||||
<< ", doppler " << d_gnss_synchro->Acq_doppler_hz
|
||||
<< ", magnitude " << d_mag
|
||||
<< ", input signal power " << d_input_power;
|
||||
|
||||
this->message_port_pub(pmt::mp("events"), pmt::from_long(1));
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::send_negative_acquisition()
|
||||
{
|
||||
// 6.2- Declare negative acquisition using a message port
|
||||
//0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
|
||||
DLOG(INFO) << "negative acquisition"
|
||||
<< ", satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN
|
||||
<< ", sample_stamp " << d_sample_counter
|
||||
<< ", test statistics value " << d_test_statistics
|
||||
<< ", test statistics threshold " << d_threshold
|
||||
<< ", code phase " << d_gnss_synchro->Acq_delay_samples
|
||||
<< ", doppler " << d_gnss_synchro->Acq_doppler_hz
|
||||
<< ", magnitude " << d_mag
|
||||
<< ", input signal power " << d_input_power;
|
||||
|
||||
this->message_port_pub(pmt::mp("events"), pmt::from_long(2));
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::set_active(bool active)
|
||||
{
|
||||
d_active = active;
|
||||
|
||||
// initialize acquisition algorithm
|
||||
uint32_t indext = 0;
|
||||
float magt = 0.0;
|
||||
int effective_fft_size = d_fft_size;
|
||||
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;
|
||||
//d_well_count++;
|
||||
|
||||
DLOG(INFO) << "Channel: " << d_channel
|
||||
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN
|
||||
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
|
||||
<< d_threshold << ", doppler_max: " << acq_parameters.doppler_max
|
||||
<< ", doppler_step: " << d_doppler_step
|
||||
// no CFAR algorithm in the FPGA
|
||||
<< ", use_CFAR_algorithm_flag: false";
|
||||
|
||||
unsigned int initial_sample;
|
||||
float input_power_all = 0.0;
|
||||
float input_power_computed = 0.0;
|
||||
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
|
||||
{
|
||||
// doppler search steps
|
||||
int doppler = -static_cast<int>(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->read_acquisition_results(&indext, &magt,
|
||||
&initial_sample, &d_input_power);
|
||||
d_sample_counter = initial_sample;
|
||||
|
||||
if (d_mag < magt)
|
||||
{
|
||||
d_mag = magt;
|
||||
|
||||
input_power_all = d_input_power / (effective_fft_size - 1);
|
||||
input_power_computed = (d_input_power - d_mag) / (effective_fft_size - 1);
|
||||
d_input_power = (d_input_power - d_mag) / (effective_fft_size - 1);
|
||||
|
||||
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_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
|
||||
|
||||
d_test_statistics = (d_mag / d_input_power); //* correction_factor;
|
||||
}
|
||||
|
||||
// In the case of the FPGA the option of dumping the results of the acquisition to a file is not available
|
||||
// because the IFFT vector is not available
|
||||
}
|
||||
|
||||
if (d_test_statistics > d_threshold)
|
||||
{
|
||||
d_active = false;
|
||||
send_positive_acquisition();
|
||||
d_state = 0; // Positive acquisition
|
||||
}
|
||||
else
|
||||
{
|
||||
d_state = 0;
|
||||
d_active = false;
|
||||
send_negative_acquisition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int pcps_acquisition_fpga::general_work(int noutput_items __attribute__((unused)),
|
||||
gr_vector_int& ninput_items, gr_vector_const_void_star& input_items,
|
||||
gr_vector_void_star& output_items __attribute__((unused)))
|
||||
{
|
||||
// the general work is not used with the acquisition that uses the FPGA
|
||||
return noutput_items;
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
/*!
|
||||
* \file pcps_acquisition_fpga.h
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition in the FPGA.
|
||||
*
|
||||
* Note: The CFAR algorithm is not implemented in the FPGA.
|
||||
* Note 2: The bit transition flag is not implemented in the FPGA
|
||||
*
|
||||
* Acquisition strategy (Kay Borre book + CFAR threshold).
|
||||
* <ol>
|
||||
* <li> Compute the input signal power estimation
|
||||
* <li> Doppler serial search loop
|
||||
* <li> Perform the FFT-based circular convolution (parallel time search)
|
||||
* <li> Record the maximum peak and the associated synchronization parameters
|
||||
* <li> Compute the test statistics and compare to the threshold
|
||||
* <li> Declare positive or negative acquisition using a message queue
|
||||
* </ol>
|
||||
*
|
||||
* Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
|
||||
* "A Software-Defined GPS and Galileo Receiver. A Single-Frequency
|
||||
* Approach", Birkhauser, 2007. pp 81-84
|
||||
*
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
|
||||
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
|
||||
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
|
||||
* <li> Cillian O'Driscoll, 2017. cillian(at)ieee.org
|
||||
* <li> Antonio Ramos, 2017. antonio.ramos@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_PCPS_ACQUISITION_FPGA_H_
|
||||
#define GNSS_SDR_PCPS_ACQUISITION_FPGA_H_
|
||||
|
||||
#include "gnss_synchro.h"
|
||||
#include <gnuradio/block.h>
|
||||
#include "fpga_acquisition.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* pcps acquisition configuration */
|
||||
unsigned int sampled_ms;
|
||||
unsigned int doppler_max;
|
||||
long freq;
|
||||
long fs_in;
|
||||
int samples_per_ms;
|
||||
int samples_per_code;
|
||||
std::string dump_filename;
|
||||
unsigned int select_queue_Fpga;
|
||||
std::string device_name;
|
||||
unsigned int code_length;
|
||||
lv_16sc_t *all_fft_codes; // memory that contains all the code ffts
|
||||
|
||||
} pcpsconf_fpga_t;
|
||||
|
||||
class pcps_acquisition_fpga;
|
||||
|
||||
typedef boost::shared_ptr<pcps_acquisition_fpga> pcps_acquisition_fpga_sptr;
|
||||
|
||||
pcps_acquisition_fpga_sptr
|
||||
pcps_make_acquisition(pcpsconf_fpga_t conf_);
|
||||
|
||||
/*!
|
||||
* \brief This class implements a Parallel Code Phase Search Acquisition that uses the FPGA.
|
||||
*
|
||||
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
|
||||
* Algorithm 1, for a pseudocode description of this implementation.
|
||||
*/
|
||||
class pcps_acquisition_fpga : public gr::block
|
||||
{
|
||||
private:
|
||||
friend pcps_acquisition_fpga_sptr
|
||||
|
||||
pcps_make_acquisition(pcpsconf_fpga_t conf_);
|
||||
|
||||
pcps_acquisition_fpga(pcpsconf_fpga_t conf_);
|
||||
|
||||
void send_negative_acquisition();
|
||||
|
||||
void send_positive_acquisition();
|
||||
|
||||
pcpsconf_fpga_t acq_parameters;
|
||||
bool d_active;
|
||||
float d_threshold;
|
||||
float d_mag;
|
||||
float d_input_power;
|
||||
float d_test_statistics;
|
||||
int d_state;
|
||||
unsigned int d_channel;
|
||||
unsigned int d_doppler_step;
|
||||
unsigned int d_fft_size;
|
||||
unsigned int d_num_doppler_bins;
|
||||
unsigned long int d_sample_counter;
|
||||
Gnss_Synchro* d_gnss_synchro;
|
||||
std::shared_ptr<fpga_acquisition> acquisition_fpga;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
~pcps_acquisition_fpga();
|
||||
|
||||
/*!
|
||||
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
|
||||
* to exchange synchronization data between acquisition and tracking blocks.
|
||||
* \param p_gnss_synchro Satellite information shared by the processing blocks.
|
||||
*/
|
||||
inline void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
|
||||
{
|
||||
d_gnss_synchro = p_gnss_synchro;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the maximum peak of grid search.
|
||||
*/
|
||||
inline unsigned int mag() const
|
||||
{
|
||||
return d_mag;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes acquisition algorithm.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*!
|
||||
* \brief Sets local code for PCPS acquisition algorithm.
|
||||
* \param code - Pointer to the PRN code.
|
||||
*/
|
||||
void set_local_code();
|
||||
|
||||
/*!
|
||||
* \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);
|
||||
|
||||
/*!
|
||||
* \brief Starts acquisition algorithm, turning from standby mode to
|
||||
* active mode
|
||||
* \param active - bool that activates/deactivates the block.
|
||||
*/
|
||||
void set_active(bool active);
|
||||
|
||||
/*!
|
||||
* \brief Set acquisition channel unique ID
|
||||
* \param channel - receiver channel.
|
||||
*/
|
||||
inline void set_channel(unsigned int channel)
|
||||
{
|
||||
d_channel = channel;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set statistics threshold of PCPS algorithm.
|
||||
* \param threshold - Threshold for signal detection (check \ref Navitec2012,
|
||||
* Algorithm 1, for a definition of this threshold).
|
||||
*/
|
||||
inline void set_threshold(float threshold)
|
||||
{
|
||||
d_threshold = threshold;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set maximum Doppler grid search
|
||||
* \param doppler_max - Maximum Doppler shift considered in the grid search [Hz].
|
||||
*/
|
||||
inline void set_doppler_max(unsigned int doppler_max)
|
||||
{
|
||||
acq_parameters.doppler_max = doppler_max;
|
||||
acquisition_fpga->set_doppler_max(doppler_max);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set Doppler steps for the grid search
|
||||
* \param doppler_step - Frequency bin of the search grid [Hz].
|
||||
*/
|
||||
inline void set_doppler_step(unsigned int doppler_step)
|
||||
{
|
||||
d_doppler_step = doppler_step;
|
||||
acquisition_fpga->set_doppler_step(doppler_step);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Parallel Code Phase Search Acquisition signal processing.
|
||||
*/
|
||||
int general_work(int noutput_items, gr_vector_int& ninput_items,
|
||||
gr_vector_const_void_star& input_items,
|
||||
gr_vector_void_star& output_items);
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_PCPS_ACQUISITION_FPGA_H_*/
|
@ -18,7 +18,7 @@
|
||||
|
||||
|
||||
set(ACQUISITION_LIB_SOURCES
|
||||
gps_fpga_acquisition_8sc.cc
|
||||
fpga_acquisition.cc
|
||||
)
|
||||
|
||||
include_directories(
|
||||
|
@ -1,12 +1,12 @@
|
||||
/*!
|
||||
* \file gps_fpga_acquisition_8sc.cc
|
||||
* \file fpga_acquisition.cc
|
||||
* \brief High optimized FPGA vector correlator class
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* </ul>
|
||||
* <li> Marc Majoral, 2018. mmajoral(at)cttc.cat
|
||||
* </ul>
|
||||
*
|
||||
* Class that controls and executes a high optimized vector correlator
|
||||
* class in the FPGA
|
||||
* Class that controls and executes a high optimized acquisition HW
|
||||
* accelerator in the FPGA
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
@ -33,65 +33,46 @@
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "gps_fpga_acquisition_8sc.h"
|
||||
#include "fpga_acquisition.h"
|
||||
#include "gps_sdr_signal_processing.h"
|
||||
#include <cmath>
|
||||
|
||||
// allocate memory dynamically
|
||||
#include <new>
|
||||
|
||||
// libraries used by DMA test code and GIPO test code
|
||||
#include <stdio.h>
|
||||
// libraries used by the GIPO
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
// libraries used by DMA test code
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
// libraries used by GPIO test code
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
// logging
|
||||
#include <glog/logging.h>
|
||||
|
||||
// volk
|
||||
#include <volk/volk.h>
|
||||
|
||||
// GPS L1
|
||||
#include "GPS_L1_CA.h"
|
||||
|
||||
#define PAGE_SIZE 0x10000
|
||||
#define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31);
|
||||
#define NUM_PRNs 32
|
||||
#define TEST_REGISTER_ACQ_WRITEVAL 0x55AA
|
||||
#define TEST_REG_SANITY_CHECK 0x55AA
|
||||
|
||||
bool gps_fpga_acquisition_8sc::init()
|
||||
bool fpga_acquisition::init()
|
||||
{
|
||||
// configure the acquisition with the main initialization values
|
||||
gps_fpga_acquisition_8sc::configure_acquisition();
|
||||
fpga_acquisition::configure_acquisition();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gps_fpga_acquisition_8sc::set_local_code(unsigned int PRN)
|
||||
bool fpga_acquisition::set_local_code(unsigned int PRN)
|
||||
{
|
||||
// select the code with the chosen PRN
|
||||
gps_fpga_acquisition_8sc::fpga_configure_acquisition_local_code(
|
||||
fpga_acquisition::fpga_configure_acquisition_local_code(
|
||||
&d_all_fft_codes[d_nsamples_total * (PRN - 1)]);
|
||||
return true;
|
||||
}
|
||||
|
||||
gps_fpga_acquisition_8sc::gps_fpga_acquisition_8sc(std::string device_name,
|
||||
unsigned int vector_length, unsigned int nsamples,
|
||||
fpga_acquisition::fpga_acquisition(std::string device_name,
|
||||
unsigned int nsamples,
|
||||
unsigned int doppler_max,
|
||||
unsigned int nsamples_total, long fs_in, long freq,
|
||||
unsigned int sampled_ms, unsigned select_queue)
|
||||
unsigned int sampled_ms, unsigned select_queue,
|
||||
lv_16sc_t *all_fft_codes)
|
||||
{
|
||||
unsigned int vector_length = nsamples_total*sampled_ms;
|
||||
// initial values
|
||||
d_device_name = device_name;
|
||||
d_freq = freq;
|
||||
@ -104,98 +85,49 @@ gps_fpga_acquisition_8sc::gps_fpga_acquisition_8sc(std::string device_name,
|
||||
d_doppler_step = 0;
|
||||
d_fd = 0; // driver descriptor
|
||||
d_map_base = nullptr; // driver memory map
|
||||
// Direct FFT
|
||||
d_fft_if = new gr::fft::fft_complex(vector_length, true);
|
||||
// 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* d_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 (int s=nsamples;s<nsamples_total;s++)
|
||||
{
|
||||
code[s] = 0;
|
||||
}
|
||||
int offset = 0;
|
||||
memcpy(d_fft_if->get_inbuf() + offset, code, sizeof(gr_complex) * nsamples_total); // copy to FFT buffer
|
||||
d_fft_if->execute(); // Run the FFT of local code
|
||||
volk_32fc_conjugate_32fc(d_fft_codes_padded, d_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(d_fft_codes_padded[i].real()) > max)
|
||||
{
|
||||
max = std::abs(d_fft_codes_padded[i].real());
|
||||
}
|
||||
if (std::abs(d_fft_codes_padded[i].imag()) > max)
|
||||
{
|
||||
max = std::abs(d_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>(d_fft_codes_padded[i].real() * (pow(2, 7) - 1) / max),
|
||||
static_cast<int>(d_fft_codes_padded[i].imag() * (pow(2, 7) - 1) / max));
|
||||
d_all_fft_codes = all_fft_codes;
|
||||
|
||||
}
|
||||
}
|
||||
// open communication with HW accelerator
|
||||
//printf("opening device %s\n", d_device_name.c_str());
|
||||
if ((d_fd = open(d_device_name.c_str(), O_RDWR | O_SYNC)) == -1)
|
||||
{
|
||||
LOG(WARNING) << "Cannot open deviceio" << d_device_name;
|
||||
//std::cout << "acquisition cannot open deviceio";
|
||||
}
|
||||
d_map_base = reinterpret_cast<volatile unsigned *>(mmap(NULL, PAGE_SIZE,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, d_fd, 0));
|
||||
|
||||
if (d_map_base == reinterpret_cast<void*>(-1))
|
||||
{
|
||||
LOG(WARNING) << "Cannot map the FPGA acquisition module into user memory";
|
||||
//std::cout << "acquisition : could not map the fpga registers to the driver" << std::endl;
|
||||
}
|
||||
|
||||
// sanity check : check test register
|
||||
// we only nee to do this when the class is created
|
||||
// but the device is not opened yet when the class is create
|
||||
// because we need to open and close the device every time we run an acquisition
|
||||
// since the same device may be used by more than one class (gps acquisition, galileo
|
||||
// acquisition, etc ..)
|
||||
unsigned writeval = TEST_REGISTER_ACQ_WRITEVAL;
|
||||
unsigned writeval = TEST_REG_SANITY_CHECK;
|
||||
unsigned readval;
|
||||
readval = gps_fpga_acquisition_8sc::fpga_acquisition_test_register(writeval);
|
||||
readval = fpga_acquisition::fpga_acquisition_test_register(writeval);
|
||||
if (writeval != readval)
|
||||
{
|
||||
LOG(WARNING) << "Acquisition test register sanity check failed";
|
||||
//std:: cout << "Acquisition test register sanity check failed" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "Acquisition test register sanity check success !" << std::endl;
|
||||
LOG(INFO) << "Acquisition test register sanity check success !";
|
||||
}
|
||||
gps_fpga_acquisition_8sc::reset_acquisition();
|
||||
fpga_acquisition::reset_acquisition();
|
||||
DLOG(INFO) << "Acquisition FPGA class created";
|
||||
// temporary buffers that we can delete
|
||||
delete[] code;
|
||||
delete d_fft_if;
|
||||
delete[] d_fft_codes_padded;
|
||||
|
||||
}
|
||||
|
||||
gps_fpga_acquisition_8sc::~gps_fpga_acquisition_8sc()
|
||||
fpga_acquisition::~fpga_acquisition()
|
||||
{
|
||||
close_device();
|
||||
delete[] d_all_fft_codes;
|
||||
}
|
||||
|
||||
bool gps_fpga_acquisition_8sc::free()
|
||||
bool fpga_acquisition::free()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned gps_fpga_acquisition_8sc::fpga_acquisition_test_register(unsigned writeval)
|
||||
unsigned fpga_acquisition::fpga_acquisition_test_register(unsigned writeval)
|
||||
{
|
||||
unsigned readval;
|
||||
// write value to test register
|
||||
@ -206,7 +138,7 @@ unsigned gps_fpga_acquisition_8sc::fpga_acquisition_test_register(unsigned write
|
||||
return readval;
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[])
|
||||
void fpga_acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[])
|
||||
{
|
||||
unsigned short local_code;
|
||||
unsigned int k, tmp, tmp2;
|
||||
@ -224,7 +156,7 @@ void gps_fpga_acquisition_8sc::fpga_configure_acquisition_local_code(lv_16sc_t f
|
||||
}
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::run_acquisition(void)
|
||||
void fpga_acquisition::run_acquisition(void)
|
||||
{
|
||||
// enable interrupts
|
||||
int reenable = 1;
|
||||
@ -243,7 +175,7 @@ void gps_fpga_acquisition_8sc::run_acquisition(void)
|
||||
}
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::configure_acquisition()
|
||||
void fpga_acquisition::configure_acquisition()
|
||||
{
|
||||
d_map_base[0] = d_select_queue;
|
||||
d_map_base[1] = d_vector_length;
|
||||
@ -251,7 +183,7 @@ void gps_fpga_acquisition_8sc::configure_acquisition()
|
||||
d_map_base[5] = (int) log2((float) d_vector_length); // log2 FFTlength
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::set_phase_step(unsigned int doppler_index)
|
||||
void fpga_acquisition::set_phase_step(unsigned int doppler_index)
|
||||
{
|
||||
float phase_step_rad_real;
|
||||
float phase_step_rad_int_temp;
|
||||
@ -274,7 +206,7 @@ void gps_fpga_acquisition_8sc::set_phase_step(unsigned int doppler_index)
|
||||
d_map_base[3] = phase_step_rad_int;
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::read_acquisition_results(uint32_t* max_index,
|
||||
void fpga_acquisition::read_acquisition_results(uint32_t* max_index,
|
||||
float* max_magnitude, unsigned *initial_sample, float *power_sum)
|
||||
{
|
||||
unsigned readval = 0;
|
||||
@ -288,18 +220,18 @@ void gps_fpga_acquisition_8sc::read_acquisition_results(uint32_t* max_index,
|
||||
*max_index = readval;
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::block_samples()
|
||||
void fpga_acquisition::block_samples()
|
||||
{
|
||||
d_map_base[14] = 1; // block the samples
|
||||
}
|
||||
|
||||
|
||||
void gps_fpga_acquisition_8sc::unblock_samples()
|
||||
void fpga_acquisition::unblock_samples()
|
||||
{
|
||||
d_map_base[14] = 0; // unblock the samples
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::close_device()
|
||||
void fpga_acquisition::close_device()
|
||||
{
|
||||
unsigned * aux = const_cast<unsigned*>(d_map_base);
|
||||
if (munmap(static_cast<void*>(aux), PAGE_SIZE) == -1)
|
||||
@ -309,7 +241,7 @@ void gps_fpga_acquisition_8sc::close_device()
|
||||
close(d_fd);
|
||||
}
|
||||
|
||||
void gps_fpga_acquisition_8sc::reset_acquisition(void)
|
||||
void fpga_acquisition::reset_acquisition(void)
|
||||
{
|
||||
d_map_base[6] = 2; // writing a 2 to d_map_base[6] resets the multicorrelator
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
/*!
|
||||
* \file fpga_acquisition_8sc.h
|
||||
* \brief High optimized FPGA vector correlator class for lv_16sc_t (short int complex).
|
||||
* \file fpga_acquisition.h
|
||||
* \brief High optimized FPGA vector correlator class
|
||||
* \authors <ul>
|
||||
* <li> Marc Majoral, 2017. mmajoral(at)cttc.cat
|
||||
* <li> Marc Majoral, 2018. mmajoral(at)cttc.cat
|
||||
* </ul>
|
||||
*
|
||||
* Class that controls and executes a high optimized vector correlator
|
||||
* class in the FPGA
|
||||
* Class that controls and executes a high optimized acquisition HW
|
||||
* accelerator in the FPGA
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
@ -33,26 +33,26 @@
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GNSS_GPS_SDR_FPGA_ACQUISITION_8SC_H_
|
||||
#define GNSS_GPS_SDR_FPGA_ACQUISITION_8SC_H_
|
||||
#ifndef GNSS_SDR_FPGA_ACQUISITION_H_
|
||||
#define GNSS_SDR_FPGA_ACQUISITION_H_
|
||||
|
||||
#include <volk_gnsssdr/volk_gnsssdr.h>
|
||||
#include <gnuradio/block.h>
|
||||
#include <gnuradio/fft/fft.h>
|
||||
|
||||
/*!
|
||||
* \brief Class that implements carrier wipe-off and correlators.
|
||||
*/
|
||||
class gps_fpga_acquisition_8sc
|
||||
class fpga_acquisition
|
||||
{
|
||||
public:
|
||||
gps_fpga_acquisition_8sc(std::string device_name,
|
||||
unsigned int vector_length, unsigned int nsamples,
|
||||
fpga_acquisition(std::string device_name,
|
||||
unsigned int nsamples,
|
||||
unsigned int doppler_max,
|
||||
unsigned int nsamples_total, long fs_in, long freq,
|
||||
unsigned int sampled_ms, unsigned select_queue);
|
||||
~gps_fpga_acquisition_8sc();bool init();bool set_local_code(
|
||||
unsigned int PRN); //int code_length_chips, const lv_16sc_t* local_code_in, float *shifts_chips);
|
||||
unsigned int sampled_ms, unsigned select_queue,
|
||||
lv_16sc_t *all_fft_codes);
|
||||
~fpga_acquisition();bool init();bool set_local_code(
|
||||
unsigned int PRN);
|
||||
bool free();
|
||||
void run_acquisition(void);
|
||||
void set_phase_step(unsigned int doppler_index);
|
||||
@ -60,7 +60,7 @@ public:
|
||||
unsigned *initial_sample, float *power_sum);
|
||||
void block_samples();
|
||||
void unblock_samples();
|
||||
//void open_device();
|
||||
|
||||
/*!
|
||||
* \brief Set maximum Doppler grid search
|
||||
* \param doppler_max - Maximum Doppler shift considered in the grid search [Hz].
|
||||
@ -69,6 +69,7 @@ public:
|
||||
{
|
||||
d_doppler_max = doppler_max;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set Doppler steps for the grid search
|
||||
* \param doppler_step - Frequency bin of the search grid [Hz].
|
||||
@ -102,4 +103,4 @@ private:
|
||||
void close_device();
|
||||
};
|
||||
|
||||
#endif /* GNSS_GPS_SDR_FPGA_MULTICORRELATOR_H_ */
|
||||
#endif /* GNSS_SDR_FPGA_ACQUISITION_H_ */
|
Loading…
Reference in New Issue
Block a user