1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-06-24 22:13:15 +00:00

Created a generic gnuradio block acquisition class for the FPGA.

This commit is contained in:
mmajoral 2018-04-27 20:00:50 +02:00
parent 6a3770c762
commit 512bf3f4cf
10 changed files with 655 additions and 779 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@
set(ACQUISITION_LIB_SOURCES
gps_fpga_acquisition_8sc.cc
fpga_acquisition.cc
)
include_directories(

View File

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

View File

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