mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-15 12:40:35 +00:00
Merge branch 'next' of https://github.com/gnss-sdr/gnss-sdr into next
This commit is contained in:
commit
31f96ea6c8
@ -578,7 +578,7 @@ $ sudo port install doxygen +docs
|
||||
You also might need to activate a Python installation. The list of installed versions can be retrieved with:
|
||||
|
||||
~~~~~~
|
||||
$ port select list python
|
||||
$ port select --list python
|
||||
~~~~~~
|
||||
|
||||
and you can activate a certain version by typing:
|
||||
|
@ -100,6 +100,13 @@ else()
|
||||
gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND)
|
||||
gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND)
|
||||
endif()
|
||||
if(NOT MAKO_FOUND OR NOT SIX_FOUND)
|
||||
unset(PYTHON_EXECUTABLE)
|
||||
find_package(PythonInterp ${GNSSSDR_PYTHON_MIN_VERSION})
|
||||
gnsssdr_python_check_module("python >= ${GNSSSDR_PYTHON_MIN_VERSION}" sys "sys.version.split()[0] >= '${GNSSSDR_PYTHON_MIN_VERSION}'" PYTHON_MIN_VER_FOUND)
|
||||
gnsssdr_python_check_module("mako >= ${GNSSSDR_MAKO_MIN_VERSION}" mako "mako.__version__ >= '${GNSSSDR_MAKO_MIN_VERSION}'" MAKO_FOUND)
|
||||
gnsssdr_python_check_module("six - python 2 and 3 compatibility library" six "True" SIX_FOUND)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -44,6 +44,13 @@
|
||||
#include <complex> // for complex
|
||||
#include <cstring> // for memcpy
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the fft of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define QUANT_BITS_LOCAL_CODE 16
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
|
||||
ConfigurationInterface* configuration,
|
||||
@ -67,7 +74,7 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
|
||||
acq_parameters.repeat_satellite = configuration_->property(role + ".repeat_satellite", false);
|
||||
DLOG(INFO) << role << " satellite repeat = " << acq_parameters.repeat_satellite;
|
||||
|
||||
float downsampling_factor = configuration_->property(role + ".downsampling_factor", 4.0);
|
||||
uint32_t downsampling_factor = configuration_->property(role + ".downsampling_factor", 4);
|
||||
acq_parameters.downsampling_factor = downsampling_factor;
|
||||
|
||||
fs_in = fs_in / downsampling_factor;
|
||||
@ -97,15 +104,16 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
|
||||
acq_parameters.device_name = device_name;
|
||||
acq_parameters.samples_per_ms = nsamples_total / sampled_ms;
|
||||
acq_parameters.samples_per_code = nsamples_total;
|
||||
acq_parameters.excludelimit = static_cast<uint32_t>(std::round(static_cast<double>(fs_in) / GALILEO_E1_CODE_CHIP_RATE_HZ));
|
||||
acq_parameters.excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / GALILEO_E1_CODE_CHIP_RATE_HZ) * static_cast<float>(fs_in)));
|
||||
|
||||
// compute all the GALILEO E1 PRN Codes (this is done only once in the class constructor in order to avoid re-computing the PRN codes every time
|
||||
// a channel is assigned)
|
||||
auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT
|
||||
auto* code = new std::complex<float>[nsamples_total]; // buffer for the local code
|
||||
auto* fft_codes_padded = static_cast<gr_complex*>(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
|
||||
d_all_fft_codes_ = new lv_16sc_t[nsamples_total * GALILEO_E1_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
d_all_fft_codes_ = new uint32_t[(nsamples_total * GALILEO_E1_NUMBER_OF_CODES)]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
float max; // temporary maxima search
|
||||
int32_t tmp, tmp2, local_code, fft_data;
|
||||
|
||||
for (uint32_t PRN = 1; PRN <= GALILEO_E1_NUMBER_OF_CODES; PRN++)
|
||||
{
|
||||
@ -153,17 +161,26 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
|
||||
max = std::abs(fft_codes_padded[i].imag());
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// and package codes in a format that is ready to be written to the FPGA
|
||||
for (uint32_t i = 0; i < nsamples_total; i++)
|
||||
{
|
||||
d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)),
|
||||
static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max)));
|
||||
tmp = static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
tmp2 = static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_all_fft_codes_[i + (nsamples_total * (PRN - 1))] = fft_data;
|
||||
}
|
||||
}
|
||||
|
||||
acq_parameters.all_fft_codes = d_all_fft_codes_;
|
||||
|
||||
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
|
||||
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
|
||||
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
|
||||
acq_parameters.max_num_acqs = configuration_->property(role + ".max_num_acqs", 2);
|
||||
// reference for the FPGA FFT-IFFT attenuation factor
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14);
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 12);
|
||||
|
||||
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters);
|
||||
|
||||
|
@ -166,7 +166,7 @@ private:
|
||||
unsigned int in_streams_;
|
||||
unsigned int out_streams_;
|
||||
|
||||
lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
uint32_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_GALILEO_E1_PCPS_AMBIGUOUS_ACQUISITION_FPGA_H_ */
|
||||
|
@ -44,6 +44,13 @@
|
||||
#include <complex> // for complex
|
||||
#include <cstring> // for strcpy, memcpy
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the fft of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define QUANT_BITS_LOCAL_CODE 16
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterface* configuration,
|
||||
const std::string& role,
|
||||
@ -64,7 +71,7 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf
|
||||
acq_parameters.repeat_satellite = configuration_->property(role + ".repeat_satellite", false);
|
||||
DLOG(INFO) << role << " satellite repeat = " << acq_parameters.repeat_satellite;
|
||||
|
||||
float downsampling_factor = configuration_->property(role + ".downsampling_factor", 1.0);
|
||||
uint32_t downsampling_factor = configuration_->property(role + ".downsampling_factor", 1);
|
||||
acq_parameters.downsampling_factor = downsampling_factor;
|
||||
fs_in = fs_in / downsampling_factor;
|
||||
|
||||
@ -98,15 +105,17 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf
|
||||
acq_parameters.samples_per_ms = nsamples_total / sampled_ms;
|
||||
acq_parameters.samples_per_code = nsamples_total;
|
||||
|
||||
acq_parameters.excludelimit = static_cast<uint32_t>(ceil((1.0 / GALILEO_E5A_CODE_CHIP_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
|
||||
acq_parameters.excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / GALILEO_E5A_CODE_CHIP_RATE_HZ) * static_cast<float>(fs_in)));
|
||||
|
||||
// compute all the GALILEO E5 PRN Codes (this is done only once in the class constructor in order to avoid re-computing the PRN codes every time
|
||||
// a channel is assigned)
|
||||
auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT
|
||||
auto* code = new std::complex<float>[nsamples_total]; // buffer for the local code
|
||||
auto* fft_codes_padded = static_cast<gr_complex*>(volk_gnsssdr_malloc(nsamples_total * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
|
||||
d_all_fft_codes_ = new lv_16sc_t[nsamples_total * GALILEO_E5A_NUMBER_OF_CODES]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
d_all_fft_codes_ = new uint32_t[(nsamples_total * GALILEO_E5A_NUMBER_OF_CODES)]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
|
||||
float max; // temporary maxima search
|
||||
int32_t tmp, tmp2, local_code, fft_data;
|
||||
|
||||
for (uint32_t PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++)
|
||||
{
|
||||
@ -154,18 +163,27 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(ConfigurationInterf
|
||||
max = std::abs(fft_codes_padded[i].imag());
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// and package codes in a format that is ready to be written to the FPGA
|
||||
for (uint32_t i = 0; i < nsamples_total; i++)
|
||||
{
|
||||
d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)),
|
||||
static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max)));
|
||||
tmp = static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
tmp2 = static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_all_fft_codes_[i + (nsamples_total * (PRN - 1))] = fft_data;
|
||||
}
|
||||
}
|
||||
|
||||
acq_parameters.all_fft_codes = d_all_fft_codes_;
|
||||
|
||||
// reference for the FPGA FFT-IFFT attenuation factor
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14);
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 13);
|
||||
|
||||
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
|
||||
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
|
||||
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
|
||||
acq_parameters.max_num_acqs = configuration_->property(role + ".max_num_acqs", 2);
|
||||
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters);
|
||||
|
||||
channel_ = 0;
|
||||
|
@ -184,7 +184,7 @@ private:
|
||||
|
||||
Gnss_Synchro* gnss_synchro_;
|
||||
|
||||
lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
uint32_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_FPGA_H_ */
|
||||
|
@ -47,9 +47,15 @@
|
||||
#include <complex> // for complex
|
||||
#include <cstring> // for memcpy
|
||||
|
||||
|
||||
#define NUM_PRNs 32
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the fft of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define QUANT_BITS_LOCAL_CODE 16
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
ConfigurationInterface* configuration,
|
||||
@ -71,9 +77,8 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
acq_parameters.repeat_satellite = configuration_->property(role + ".repeat_satellite", false);
|
||||
DLOG(INFO) << role << " satellite repeat = " << acq_parameters.repeat_satellite;
|
||||
|
||||
float downsampling_factor = configuration_->property(role + ".downsampling_factor", 4.0);
|
||||
uint32_t downsampling_factor = configuration_->property(role + ".downsampling_factor", 4);
|
||||
acq_parameters.downsampling_factor = downsampling_factor;
|
||||
|
||||
fs_in = fs_in / downsampling_factor;
|
||||
|
||||
acq_parameters.fs_in = fs_in;
|
||||
@ -94,7 +99,7 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
acq_parameters.device_name = device_name;
|
||||
acq_parameters.samples_per_ms = nsamples_total / sampled_ms;
|
||||
acq_parameters.samples_per_code = nsamples_total;
|
||||
acq_parameters.excludelimit = static_cast<uint32_t>(std::round(static_cast<double>(fs_in) / GPS_L1_CA_CODE_RATE_HZ));
|
||||
acq_parameters.excludelimit = static_cast<unsigned int>(1 + ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(fs_in)));
|
||||
|
||||
// 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)
|
||||
@ -102,8 +107,10 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
// allocate memory to compute all the PRNs and compute all the possible codes
|
||||
auto* code = new std::complex<float>[nsamples_total]; // buffer for the local code
|
||||
auto* 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
|
||||
d_all_fft_codes_ = new uint32_t[(nsamples_total * NUM_PRNs)]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
float max;
|
||||
int32_t tmp, tmp2, local_code, fft_data;
|
||||
// temporary maxima search
|
||||
for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++)
|
||||
{
|
||||
gps_l1_ca_code_gen_complex_sampled(code, PRN, fs_in, 0); // generate PRN code
|
||||
@ -135,10 +142,15 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
max = std::abs(fft_codes_padded[i].imag());
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// and package codes in a format that is ready to be written to the FPGA
|
||||
for (uint32_t i = 0; i < nsamples_total; i++)
|
||||
{
|
||||
d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)),
|
||||
static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max)));
|
||||
tmp = static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
tmp2 = static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_all_fft_codes_[i + (nsamples_total * (PRN - 1))] = fft_data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +158,12 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
|
||||
acq_parameters.all_fft_codes = d_all_fft_codes_;
|
||||
|
||||
// reference for the FPGA FFT-IFFT attenuation factor
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14);
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 11);
|
||||
|
||||
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
|
||||
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
|
||||
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
|
||||
acq_parameters.max_num_acqs = configuration_->property(role + ".max_num_acqs", 2);
|
||||
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters);
|
||||
|
||||
channel_ = 0;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_
|
||||
#define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_
|
||||
|
||||
|
||||
#include "channel_fsm.h"
|
||||
#include "pcps_acquisition_fpga.h"
|
||||
#include <gnuradio/runtime_types.h> // for basic_block_sptr, top_block_sptr
|
||||
@ -166,7 +167,7 @@ private:
|
||||
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
|
||||
uint32_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FPGA_H_ */
|
||||
|
@ -47,7 +47,11 @@
|
||||
#include <cstring> // for memcpy
|
||||
|
||||
#define NUM_PRNs 32
|
||||
|
||||
#define QUANT_BITS_LOCAL_CODE 16
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
|
||||
ConfigurationInterface* configuration,
|
||||
@ -102,8 +106,11 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
|
||||
// allocate memory to compute all the PRNs and compute all the possible codes
|
||||
auto* code = new std::complex<float>[nsamples_total]; // buffer for the local code
|
||||
auto* 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
|
||||
//d_all_fft_codes_ = new lv_16sc_t[nsamples_total * NUM_PRNs]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
d_all_fft_codes_ = new uint32_t[(nsamples_total * NUM_PRNs)]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
float max; // temporary maxima search
|
||||
int32_t tmp, tmp2, local_code, fft_data;
|
||||
|
||||
for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++)
|
||||
{
|
||||
gps_l2c_m_code_gen_complex_sampled(code, PRN, fs_in_);
|
||||
@ -127,10 +134,18 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
|
||||
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
|
||||
// map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// and package codes in a format that is ready to be written to the FPGA
|
||||
for (uint32_t i = 0; i < nsamples_total; i++)
|
||||
{
|
||||
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)));
|
||||
tmp = static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
tmp2 = static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_all_fft_codes_[i + (nsamples_total * (PRN - 1))] = fft_data;
|
||||
|
||||
// d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max)),
|
||||
// static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ private:
|
||||
unsigned int in_streams_;
|
||||
unsigned int out_streams_;
|
||||
|
||||
lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
uint32_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
|
||||
//float calculate_threshold(float pfa);
|
||||
};
|
||||
|
@ -49,6 +49,14 @@
|
||||
|
||||
#define NUM_PRNs 32
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the fft of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define QUANT_BITS_LOCAL_CODE 16
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
|
||||
GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
|
||||
ConfigurationInterface* configuration,
|
||||
@ -70,7 +78,7 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
|
||||
acq_parameters.repeat_satellite = configuration_->property(role + ".repeat_satellite", false);
|
||||
DLOG(INFO) << role << " satellite repeat = " << acq_parameters.repeat_satellite;
|
||||
|
||||
float downsampling_factor = configuration_->property(role + ".downsampling_factor", 1.0);
|
||||
uint32_t downsampling_factor = configuration_->property(role + ".downsampling_factor", 1);
|
||||
acq_parameters.downsampling_factor = downsampling_factor;
|
||||
|
||||
fs_in = fs_in / downsampling_factor;
|
||||
@ -96,16 +104,18 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
|
||||
acq_parameters.samples_per_ms = nsamples_total / sampled_ms;
|
||||
acq_parameters.samples_per_code = nsamples_total;
|
||||
|
||||
acq_parameters.excludelimit = static_cast<uint32_t>(ceil((1.0 / GPS_L5I_CODE_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
|
||||
acq_parameters.excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / GPS_L5I_CODE_RATE_HZ) * static_cast<float>(fs_in)));
|
||||
|
||||
// compute all the GPS L5 PRN Codes (this is done only once upon the class constructor in order to avoid re-computing the PRN codes every time
|
||||
// a channel is assigned)
|
||||
auto* fft_if = new gr::fft::fft_complex(nsamples_total, true); // Direct FFT
|
||||
auto* code = new gr_complex[nsamples_total];
|
||||
auto* 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
|
||||
d_all_fft_codes_ = new uint32_t[(nsamples_total * NUM_PRNs)]; // memory containing all the possible fft codes for PRN 0 to 32
|
||||
|
||||
float max; // temporary maxima search
|
||||
int32_t tmp, tmp2, local_code, fft_data;
|
||||
|
||||
for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++)
|
||||
{
|
||||
gps_l5i_code_gen_complex_sampled(code, PRN, fs_in);
|
||||
@ -136,18 +146,27 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
|
||||
max = std::abs(fft_codes_padded[i].imag());
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < nsamples_total; i++) // map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// map the FFT to the dynamic range of the fixed point values an copy to buffer containing all FFTs
|
||||
// and package codes in a format that is ready to be written to the FPGA
|
||||
for (uint32_t i = 0; i < nsamples_total; i++)
|
||||
{
|
||||
d_all_fft_codes_[i + nsamples_total * (PRN - 1)] = lv_16sc_t(static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, 9) - 1) / max)),
|
||||
static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, 9) - 1) / max)));
|
||||
tmp = static_cast<int32_t>(floor(fft_codes_padded[i].real() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
tmp2 = static_cast<int32_t>(floor(fft_codes_padded[i].imag() * (pow(2, QUANT_BITS_LOCAL_CODE - 1) - 1) / max));
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_all_fft_codes_[i + (nsamples_total * (PRN - 1))] = fft_data;
|
||||
}
|
||||
}
|
||||
|
||||
acq_parameters.all_fft_codes = d_all_fft_codes_;
|
||||
|
||||
// reference for the FPGA FFT-IFFT attenuation factor
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 14);
|
||||
acq_parameters.total_block_exp = configuration_->property(role + ".total_block_exp", 11);
|
||||
|
||||
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
|
||||
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
|
||||
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
|
||||
acq_parameters.max_num_acqs = configuration_->property(role + ".max_num_acqs", 2);
|
||||
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters);
|
||||
|
||||
channel_ = 0;
|
||||
|
@ -106,6 +106,7 @@ public:
|
||||
channel_fsm_ = channel_fsm;
|
||||
acquisition_fpga_->set_channel_fsm(channel_fsm);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Set statistics threshold of PCPS algorithm
|
||||
*/
|
||||
@ -167,7 +168,7 @@ private:
|
||||
unsigned int in_streams_;
|
||||
unsigned int out_streams_;
|
||||
|
||||
lv_16sc_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
uint32_t* d_all_fft_codes_; // memory that contains all the code ffts
|
||||
|
||||
float calculate_threshold(float pfa);
|
||||
};
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "pcps_acquisition_fpga.h"
|
||||
#include "gnss_synchro.h"
|
||||
//#include <boost/chrono.hpp>
|
||||
#include <glog/logging.h>
|
||||
#include <cmath> // for ceil
|
||||
#include <iostream> // for operator<<
|
||||
@ -42,7 +43,6 @@
|
||||
|
||||
#define AQ_DOWNSAMPLING_DELAY 40 // delay due to the downsampling filter in the acquisition
|
||||
|
||||
|
||||
pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_)
|
||||
{
|
||||
return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(std::move(conf_)));
|
||||
@ -52,7 +52,7 @@ pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(pcpsconf_fpga_t conf_)
|
||||
pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_)
|
||||
{
|
||||
acq_parameters = std::move(conf_);
|
||||
d_sample_counter = 0ULL; // SAMPLE COUNTER
|
||||
d_sample_counter = 0ULL; // Sample Counter
|
||||
d_active = false;
|
||||
d_state = 0;
|
||||
d_fft_size = acq_parameters.samples_per_code;
|
||||
@ -71,6 +71,15 @@ pcps_acquisition_fpga::pcps_acquisition_fpga(pcpsconf_fpga_t conf_)
|
||||
|
||||
d_total_block_exp = acq_parameters.total_block_exp;
|
||||
|
||||
d_make_2_steps = acq_parameters.make_2_steps;
|
||||
d_num_doppler_bins_step2 = acq_parameters.num_doppler_bins_step2;
|
||||
d_doppler_step2 = acq_parameters.doppler_step2;
|
||||
d_doppler_center_step_two = 0.0;
|
||||
|
||||
d_doppler_max = acq_parameters.doppler_max;
|
||||
|
||||
d_max_num_acqs = acq_parameters.max_num_acqs;
|
||||
|
||||
acquisition_fpga = std::make_shared<Fpga_Acquisition>(acq_parameters.device_name, acq_parameters.code_length, acq_parameters.doppler_max, d_fft_size,
|
||||
acq_parameters.fs_in, acq_parameters.sampled_ms, acq_parameters.select_queue_Fpga, acq_parameters.all_fft_codes, acq_parameters.excludelimit);
|
||||
}
|
||||
@ -100,9 +109,7 @@ void pcps_acquisition_fpga::init()
|
||||
d_mag = 0.0;
|
||||
d_input_power = 0.0;
|
||||
|
||||
d_num_doppler_bins = static_cast<uint32_t>(std::ceil(static_cast<double>(static_cast<int32_t>(acq_parameters.doppler_max) - static_cast<int32_t>(-acq_parameters.doppler_max)) / static_cast<double>(d_doppler_step))) + 1;
|
||||
|
||||
acquisition_fpga->init();
|
||||
d_num_doppler_bins = static_cast<uint32_t>(std::ceil(static_cast<double>(static_cast<int32_t>(d_doppler_max) - static_cast<int32_t>(-d_doppler_max)) / static_cast<double>(d_doppler_step))) + 1;
|
||||
}
|
||||
|
||||
|
||||
@ -171,48 +178,35 @@ void pcps_acquisition_fpga::send_negative_acquisition()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::set_active(bool active)
|
||||
void pcps_acquisition_fpga::acquisition_core(uint32_t num_doppler_bins, uint32_t doppler_step, int32_t doppler_min)
|
||||
{
|
||||
d_active = active;
|
||||
|
||||
// initialize acquisition algorithm
|
||||
uint32_t indext = 0U;
|
||||
float firstpeak = 0.0;
|
||||
float secondpeak = 0.0;
|
||||
uint32_t total_block_exp;
|
||||
|
||||
d_input_power = 0.0;
|
||||
d_mag = 0.0;
|
||||
|
||||
int32_t doppler;
|
||||
|
||||
DLOG(INFO) << "Channel: " << d_channel
|
||||
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN
|
||||
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
|
||||
<< d_threshold << ", doppler_max: " << acq_parameters.doppler_max
|
||||
<< ", doppler_step: " << d_doppler_step
|
||||
// no CFAR algorithm in the FPGA
|
||||
<< ", use_CFAR_algorithm_flag: false";
|
||||
|
||||
uint64_t initial_sample;
|
||||
|
||||
acquisition_fpga->configure_acquisition();
|
||||
acquisition_fpga->set_doppler_sweep(d_num_doppler_bins);
|
||||
acquisition_fpga->write_local_code();
|
||||
acquisition_fpga->set_block_exp(d_total_block_exp);
|
||||
int32_t doppler;
|
||||
acquisition_fpga->set_doppler_sweep(num_doppler_bins, doppler_step, doppler_min);
|
||||
acquisition_fpga->run_acquisition();
|
||||
acquisition_fpga->read_acquisition_results(&indext, &firstpeak, &secondpeak, &initial_sample, &d_input_power, &d_doppler_index, &total_block_exp);
|
||||
acquisition_fpga->read_acquisition_results(&indext,
|
||||
&firstpeak,
|
||||
&secondpeak,
|
||||
&initial_sample,
|
||||
&d_input_power,
|
||||
&d_doppler_index,
|
||||
&total_block_exp);
|
||||
|
||||
doppler = static_cast<int32_t>(doppler_min) + doppler_step * (d_doppler_index - 1);
|
||||
|
||||
if (total_block_exp > d_total_block_exp)
|
||||
{
|
||||
// if the attenuation factor of the FPGA FFT-IFFT is smaller than the reference attenuation factor then we need to update the reference attenuation factor
|
||||
std::cout << "changing blk exp..... d_total_block_exp = " << d_total_block_exp << " total_block_exp = " << total_block_exp << " chan = " << d_channel << std::endl;
|
||||
d_total_block_exp = total_block_exp;
|
||||
d_test_statistics = 0;
|
||||
}
|
||||
|
||||
doppler = -static_cast<int32_t>(acq_parameters.doppler_max) + d_doppler_step * (d_doppler_index - 1);
|
||||
|
||||
else
|
||||
{
|
||||
if (secondpeak > 0)
|
||||
{
|
||||
d_test_statistics = firstpeak / secondpeak;
|
||||
@ -221,6 +215,14 @@ void pcps_acquisition_fpga::set_active(bool active)
|
||||
{
|
||||
d_test_statistics = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// debug
|
||||
// if (d_test_statistics > d_threshold)
|
||||
// {
|
||||
// printf("firstpeak = %f, secondpeak = %f, test_statistics = %f reported block exp = %d PRN = %d inext = %d, initial_sample = %ld doppler = %d\n", firstpeak, secondpeak, d_test_statistics, (int)total_block_exp, (int)d_gnss_synchro->PRN, (int)indext, (long int)initial_sample, (int)doppler);
|
||||
// printf("doppler_min = %d doppler_step = %d num_doppler_bins = %d\n", (int)doppler_min, (int)doppler_step, (int)num_doppler_bins);
|
||||
// }
|
||||
|
||||
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler);
|
||||
d_sample_counter = initial_sample;
|
||||
@ -230,7 +232,7 @@ void pcps_acquisition_fpga::set_active(bool active)
|
||||
if (d_downsampling_factor > 1)
|
||||
{
|
||||
d_gnss_synchro->Acq_delay_samples = static_cast<double>(d_downsampling_factor * (indext));
|
||||
d_gnss_synchro->Acq_samplestamp_samples = d_downsampling_factor * d_sample_counter - 44; //33; //41; //+ 81*0.5; // delay due to the downsampling filter in the acquisition
|
||||
d_gnss_synchro->Acq_samplestamp_samples = d_downsampling_factor * static_cast<uint64_t>(d_sample_counter) - static_cast<uint64_t>(44); //33; //41; //+ 81*0.5; // delay due to the downsampling filter in the acquisition
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -243,7 +245,34 @@ void pcps_acquisition_fpga::set_active(bool active)
|
||||
d_gnss_synchro->Acq_delay_samples = static_cast<double>(indext);
|
||||
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter; // delay due to the downsampling filter in the acquisition
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::set_active(bool active)
|
||||
{
|
||||
d_active = active;
|
||||
|
||||
d_input_power = 0.0;
|
||||
|
||||
d_mag = 0.0;
|
||||
|
||||
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: " << d_doppler_max
|
||||
<< ", doppler_step: " << d_doppler_step
|
||||
// no CFAR algorithm in the FPGA
|
||||
<< ", use_CFAR_algorithm_flag: false";
|
||||
|
||||
acquisition_fpga->open_device();
|
||||
acquisition_fpga->configure_acquisition();
|
||||
acquisition_fpga->write_local_code();
|
||||
acquisition_fpga->set_block_exp(d_total_block_exp);
|
||||
|
||||
acquisition_core(d_num_doppler_bins, d_doppler_step, -d_doppler_max);
|
||||
if (!d_make_2_steps)
|
||||
{
|
||||
acquisition_fpga->close_device();
|
||||
if (d_test_statistics > d_threshold)
|
||||
{
|
||||
d_active = false;
|
||||
@ -256,17 +285,49 @@ void pcps_acquisition_fpga::set_active(bool active)
|
||||
d_active = false;
|
||||
send_negative_acquisition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d_test_statistics > d_threshold)
|
||||
{
|
||||
d_doppler_center_step_two = static_cast<float>(d_gnss_synchro->Acq_doppler_hz);
|
||||
|
||||
uint32_t num_second_acq = 1;
|
||||
|
||||
while (num_second_acq < d_max_num_acqs)
|
||||
{
|
||||
acquisition_core(d_num_doppler_bins_step2, d_doppler_step2, d_doppler_center_step_two - static_cast<float>(floor(d_num_doppler_bins_step2 / 2.0)) * d_doppler_step2);
|
||||
if (d_test_statistics > d_threshold)
|
||||
{
|
||||
d_active = false;
|
||||
send_positive_acquisition();
|
||||
d_state = 0; // Positive acquisition
|
||||
break;
|
||||
}
|
||||
num_second_acq = num_second_acq + 1;
|
||||
}
|
||||
if (d_test_statistics <= d_threshold)
|
||||
{
|
||||
d_state = 0;
|
||||
d_active = false;
|
||||
send_negative_acquisition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
acquisition_fpga->close_device();
|
||||
d_state = 0;
|
||||
d_active = false;
|
||||
send_negative_acquisition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::reset_acquisition(void)
|
||||
{
|
||||
// this function triggers a HW reset of the FPGA PL.
|
||||
acquisition_fpga->open_device();
|
||||
acquisition_fpga->reset_acquisition();
|
||||
}
|
||||
|
||||
|
||||
void pcps_acquisition_fpga::read_fpga_total_scale_factor(uint32_t* total_scale_factor, uint32_t* fw_scale_factor)
|
||||
{
|
||||
acquisition_fpga->read_fpga_total_scale_factor(total_scale_factor, fw_scale_factor);
|
||||
acquisition_fpga->close_device();
|
||||
}
|
||||
|
@ -62,11 +62,16 @@ typedef struct
|
||||
int32_t code_length;
|
||||
uint32_t select_queue_Fpga;
|
||||
std::string device_name;
|
||||
lv_16sc_t* all_fft_codes; // memory that contains all the code ffts
|
||||
float downsampling_factor;
|
||||
uint32_t* all_fft_codes; // pointer to memory that contains all the code ffts
|
||||
//float downsampling_factor;
|
||||
uint32_t downsampling_factor;
|
||||
uint32_t total_block_exp;
|
||||
uint32_t excludelimit;
|
||||
bool make_2_steps;
|
||||
uint32_t num_doppler_bins_step2;
|
||||
float doppler_step2;
|
||||
bool repeat_satellite;
|
||||
uint32_t max_num_acqs;
|
||||
} pcpsconf_fpga_t;
|
||||
|
||||
class pcps_acquisition_fpga;
|
||||
@ -95,6 +100,8 @@ private:
|
||||
|
||||
float first_vs_second_peak_statistic(uint32_t& indext, int32_t& doppler, uint32_t num_doppler_bins, int32_t doppler_max, int32_t doppler_step);
|
||||
|
||||
void acquisition_core(uint32_t num_doppler_bins, uint32_t doppler_step, int32_t doppler_max);
|
||||
|
||||
pcpsconf_fpga_t acq_parameters;
|
||||
bool d_active;
|
||||
float d_threshold;
|
||||
@ -106,17 +113,25 @@ private:
|
||||
uint32_t d_channel;
|
||||
std::shared_ptr<ChannelFsm> d_channel_fsm;
|
||||
uint32_t d_doppler_step;
|
||||
uint32_t d_doppler_max;
|
||||
uint32_t d_fft_size;
|
||||
uint32_t d_num_doppler_bins;
|
||||
uint64_t d_sample_counter;
|
||||
Gnss_Synchro* d_gnss_synchro;
|
||||
std::shared_ptr<Fpga_Acquisition> acquisition_fpga;
|
||||
|
||||
float d_downsampling_factor;
|
||||
//float d_downsampling_factor;
|
||||
uint32_t d_downsampling_factor;
|
||||
uint32_t d_select_queue_Fpga;
|
||||
|
||||
uint32_t d_total_block_exp;
|
||||
|
||||
bool d_make_2_steps;
|
||||
uint32_t d_num_doppler_bins_step2;
|
||||
float d_doppler_step2;
|
||||
float d_doppler_center_step_two;
|
||||
uint32_t d_max_num_acqs;
|
||||
|
||||
public:
|
||||
~pcps_acquisition_fpga();
|
||||
|
||||
@ -172,7 +187,6 @@ public:
|
||||
d_channel = channel;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Set channel fsm associated to this acquisition instance
|
||||
*/
|
||||
@ -197,7 +211,7 @@ public:
|
||||
*/
|
||||
inline void set_doppler_max(uint32_t doppler_max)
|
||||
{
|
||||
acq_parameters.doppler_max = doppler_max;
|
||||
d_doppler_max = doppler_max;
|
||||
acquisition_fpga->set_doppler_max(doppler_max);
|
||||
}
|
||||
|
||||
@ -215,11 +229,6 @@ public:
|
||||
* \brief This funciton triggers a HW reset of the FPGA PL.
|
||||
*/
|
||||
void reset_acquisition(void);
|
||||
|
||||
/*!
|
||||
* \brief This funciton is only used for the unit tests
|
||||
*/
|
||||
void read_fpga_total_scale_factor(uint32_t* total_scale_factor, uint32_t* fw_scale_factor);
|
||||
};
|
||||
|
||||
#endif /* GNSS_SDR_PCPS_ACQUISITION_FPGA_H_*/
|
||||
|
@ -46,22 +46,19 @@
|
||||
|
||||
// FPGA register parameters
|
||||
#define PAGE_SIZE 0x10000 // default page size for the multicorrelator memory map
|
||||
#define MAX_PHASE_STEP_RAD 0.999999999534339 // 1 - pow(2,-31);
|
||||
#define RESET_ACQUISITION 2 // command to reset the multicorrelator
|
||||
#define LAUNCH_ACQUISITION 1 // command to launch the multicorrelator
|
||||
#define TEST_REG_SANITY_CHECK 0x55AA // value to check the presence of the test register (to detect the hw)
|
||||
#define LOCAL_CODE_CLEAR_MEM 0x10000000 // command to clear the internal memory of the multicorrelator
|
||||
#define MEM_LOCAL_CODE_WR_ENABLE 0x0C000000 // command to enable the ENA and WR pins of the internal memory of the multicorrelator
|
||||
#define POW_2_2 4 // 2^2 (used for the conversion of floating point numbers to integers)
|
||||
#define POW_2_29 536870912 // 2^29 (used for the conversion of floating point numbers to integers)
|
||||
#define SELECT_LSB 0x00FF // value to select the least significant byte
|
||||
#define SELECT_MSB 0XFF00 // value to select the most significant byte
|
||||
#define SELECT_16_BITS 0xFFFF // value to select 16 bits
|
||||
#define SHL_8_BITS 256 // value used to shift a value 8 bits to the left
|
||||
#define SELECT_LSBits 0x000003FF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0x000FFC00 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0x000FFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 1024 // shift left by 10 bits
|
||||
#define POW_2_31 2147483648 // 2^31 (used for the conversion of floating point numbers to integers)
|
||||
|
||||
#define SELECT_LSBits 0x0000FFFF // Select the 10 LSbits out of a 20-bit word
|
||||
#define SELECT_MSBbits 0xFFFF0000 // Select the 10 MSbits out of a 20-bit word
|
||||
#define SELECT_ALL_CODE_BITS 0xFFFFFFFF // Select a 20 bit word
|
||||
#define SHL_CODE_BITS 65536 // shift left by 10 bits
|
||||
|
||||
|
||||
#ifndef TEMP_FAILURE_RETRY
|
||||
#define TEMP_FAILURE_RETRY(exp) \
|
||||
@ -84,7 +81,8 @@ Fpga_Acquisition::Fpga_Acquisition(std::string device_name,
|
||||
int64_t fs_in,
|
||||
uint32_t sampled_ms __attribute__((unused)),
|
||||
uint32_t select_queue,
|
||||
lv_16sc_t *all_fft_codes,
|
||||
//lv_16sc_t *all_fft_codes,
|
||||
uint32_t *all_fft_codes,
|
||||
uint32_t excludelimit)
|
||||
{
|
||||
uint32_t vector_length = nsamples_total;
|
||||
@ -102,12 +100,10 @@ Fpga_Acquisition::Fpga_Acquisition(std::string device_name,
|
||||
d_fd = 0; // driver descriptor
|
||||
d_map_base = nullptr; // driver memory map
|
||||
d_all_fft_codes = all_fft_codes;
|
||||
|
||||
Fpga_Acquisition::reset_acquisition();
|
||||
Fpga_Acquisition::open_device();
|
||||
Fpga_Acquisition::reset_acquisition();
|
||||
Fpga_Acquisition::fpga_acquisition_test_register();
|
||||
Fpga_Acquisition::close_device();
|
||||
|
||||
d_PRN = 0;
|
||||
DLOG(INFO) << "Acquisition FPGA class created";
|
||||
}
|
||||
@ -116,12 +112,6 @@ Fpga_Acquisition::Fpga_Acquisition(std::string device_name,
|
||||
Fpga_Acquisition::~Fpga_Acquisition() = default;
|
||||
|
||||
|
||||
bool Fpga_Acquisition::init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Fpga_Acquisition::set_local_code(uint32_t PRN)
|
||||
{
|
||||
// select the code with the chosen PRN
|
||||
@ -132,8 +122,12 @@ bool Fpga_Acquisition::set_local_code(uint32_t PRN)
|
||||
|
||||
void Fpga_Acquisition::write_local_code()
|
||||
{
|
||||
Fpga_Acquisition::fpga_configure_acquisition_local_code(
|
||||
&d_all_fft_codes[d_nsamples_total * (d_PRN - 1)]);
|
||||
d_map_base[9] = LOCAL_CODE_CLEAR_MEM;
|
||||
// write local code
|
||||
for (uint32_t k = 0; k < d_vector_length; k++)
|
||||
{
|
||||
d_map_base[6] = d_all_fft_codes[d_nsamples_total * (d_PRN - 1) + k];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -184,26 +178,6 @@ void Fpga_Acquisition::fpga_acquisition_test_register()
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[])
|
||||
{
|
||||
uint32_t local_code;
|
||||
uint32_t k, tmp, tmp2;
|
||||
uint32_t fft_data;
|
||||
|
||||
d_map_base[9] = LOCAL_CODE_CLEAR_MEM;
|
||||
// write local code
|
||||
for (k = 0; k < d_vector_length; k++)
|
||||
{
|
||||
tmp = fft_local_code[k].real();
|
||||
tmp2 = fft_local_code[k].imag();
|
||||
|
||||
local_code = (tmp & SELECT_LSBits) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBbits); // put together the real part and the imaginary part
|
||||
fft_data = local_code & SELECT_ALL_CODE_BITS;
|
||||
d_map_base[6] = fft_data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::run_acquisition(void)
|
||||
{
|
||||
// enable interrupts
|
||||
@ -241,47 +215,30 @@ void Fpga_Acquisition::set_block_exp(uint32_t total_block_exp)
|
||||
d_map_base[11] = total_block_exp;
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::set_doppler_sweep(uint32_t num_sweeps)
|
||||
void Fpga_Acquisition::set_doppler_sweep(uint32_t num_sweeps, uint32_t doppler_step, int32_t doppler_min)
|
||||
{
|
||||
float phase_step_rad_real;
|
||||
float phase_step_rad_int_temp;
|
||||
int32_t phase_step_rad_int;
|
||||
auto doppler = static_cast<int32_t>(-d_doppler_max);
|
||||
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
||||
|
||||
// The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing
|
||||
// The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi)
|
||||
// The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x)
|
||||
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
||||
|
||||
// avoid saturation of the fixed point representation in the fpga
|
||||
// (only the positive value can saturate due to the 2's complement representation)
|
||||
if (phase_step_rad_real >= 1.0)
|
||||
{
|
||||
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
||||
}
|
||||
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
||||
phase_step_rad_int = static_cast<int32_t>(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings
|
||||
phase_step_rad_real = 2.0 * (doppler_min) / static_cast<float>(d_fs_in);
|
||||
phase_step_rad_int = static_cast<int32_t>(phase_step_rad_real * (POW_2_31));
|
||||
d_map_base[3] = phase_step_rad_int;
|
||||
|
||||
// repeat the calculation with the doppler step
|
||||
doppler = static_cast<int32_t>(d_doppler_step);
|
||||
phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
||||
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
||||
if (phase_step_rad_real >= 1.0)
|
||||
{
|
||||
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
||||
}
|
||||
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
||||
phase_step_rad_int = static_cast<int32_t>(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings
|
||||
phase_step_rad_real = 2.0 * (doppler_step) / static_cast<float>(d_fs_in);
|
||||
phase_step_rad_int = static_cast<int32_t>(phase_step_rad_real * (POW_2_31)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings
|
||||
d_map_base[4] = phase_step_rad_int;
|
||||
|
||||
// write number of doppler sweeps
|
||||
d_map_base[5] = num_sweeps;
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::configure_acquisition()
|
||||
{
|
||||
Fpga_Acquisition::open_device();
|
||||
//Fpga_Acquisition::open_device();
|
||||
|
||||
d_map_base[0] = d_select_queue;
|
||||
d_map_base[1] = d_vector_length;
|
||||
@ -291,30 +248,6 @@ void Fpga_Acquisition::configure_acquisition()
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::set_phase_step(uint32_t doppler_index)
|
||||
{
|
||||
float phase_step_rad_real;
|
||||
float phase_step_rad_int_temp;
|
||||
int32_t phase_step_rad_int;
|
||||
int32_t doppler = -static_cast<int32_t>(d_doppler_max) + d_doppler_step * doppler_index;
|
||||
float phase_step_rad = GPS_TWO_PI * (doppler) / static_cast<float>(d_fs_in);
|
||||
// The doppler step can never be outside the range -pi to +pi, otherwise there would be aliasing
|
||||
// The FPGA expects phase_step_rad between -1 (-pi) to +1 (+pi)
|
||||
// The FPGA also expects the phase to be negative since it produces cos(x) -j*sin(x)
|
||||
// while the gnss-sdr software (volk_gnsssdr_s32f_sincos_32fc) generates cos(x) + j*sin(x)
|
||||
phase_step_rad_real = phase_step_rad / (GPS_TWO_PI / 2);
|
||||
// avoid saturation of the fixed point representation in the fpga
|
||||
// (only the positive value can saturate due to the 2's complement representation)
|
||||
if (phase_step_rad_real >= 1.0)
|
||||
{
|
||||
phase_step_rad_real = MAX_PHASE_STEP_RAD;
|
||||
}
|
||||
phase_step_rad_int_temp = phase_step_rad_real * POW_2_2; // * 2^2
|
||||
phase_step_rad_int = static_cast<int32_t>(phase_step_rad_int_temp * (POW_2_29)); // * 2^29 (in total it makes x2^31 in two steps to avoid the warnings
|
||||
d_map_base[3] = phase_step_rad_int;
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Acquisition::read_acquisition_results(uint32_t *max_index,
|
||||
float *firstpeak, float *secondpeak, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index, uint32_t *total_blk_exp)
|
||||
{
|
||||
@ -349,9 +282,7 @@ void Fpga_Acquisition::read_acquisition_results(uint32_t *max_index,
|
||||
readval = d_map_base[7]; // read doppler index -- this read releases the interrupt line
|
||||
*doppler_index = readval;
|
||||
|
||||
readval = d_map_base[15]; // read dummy
|
||||
|
||||
Fpga_Acquisition::close_device();
|
||||
readval = d_map_base[15]; // read dummy (to be removed)
|
||||
}
|
||||
|
||||
|
||||
@ -380,9 +311,7 @@ void Fpga_Acquisition::close_device()
|
||||
|
||||
void Fpga_Acquisition::reset_acquisition(void)
|
||||
{
|
||||
Fpga_Acquisition::open_device();
|
||||
d_map_base[8] = RESET_ACQUISITION; // writing a 2 to d_map_base[8] resets the multicorrelator
|
||||
Fpga_Acquisition::close_device();
|
||||
}
|
||||
|
||||
|
||||
@ -392,8 +321,7 @@ void Fpga_Acquisition::read_fpga_total_scale_factor(uint32_t *total_scale_factor
|
||||
uint32_t readval = 0;
|
||||
readval = d_map_base[8];
|
||||
*total_scale_factor = readval;
|
||||
|
||||
//readval = d_map_base[8];
|
||||
// only the total scale factor is used for the tests (fw scale factor to be removed)
|
||||
*fw_scale_factor = 0;
|
||||
}
|
||||
|
||||
|
@ -53,16 +53,15 @@ public:
|
||||
int64_t fs_in,
|
||||
uint32_t sampled_ms,
|
||||
uint32_t select_queue,
|
||||
lv_16sc_t *all_fft_codes,
|
||||
uint32_t *all_fft_codes,
|
||||
uint32_t excludelimit);
|
||||
|
||||
~Fpga_Acquisition();
|
||||
bool init();
|
||||
bool set_local_code(uint32_t PRN);
|
||||
bool free();
|
||||
void set_doppler_sweep(uint32_t num_sweeps);
|
||||
void set_doppler_sweep(uint32_t num_sweeps, uint32_t doppler_step, int32_t doppler_min);
|
||||
void run_acquisition(void);
|
||||
void set_phase_step(uint32_t doppler_index);
|
||||
|
||||
void read_acquisition_results(uint32_t *max_index, float *firstpeak, float *secondpeak, uint64_t *initial_sample, float *power_sum, uint32_t *doppler_index, uint32_t *total_blk_exp);
|
||||
|
||||
void block_samples();
|
||||
@ -110,7 +109,7 @@ private:
|
||||
// data related to the hardware module and the driver
|
||||
int32_t d_fd; // driver descriptor
|
||||
volatile uint32_t *d_map_base; // driver memory map
|
||||
lv_16sc_t *d_all_fft_codes; // memory that contains all the code ffts
|
||||
uint32_t *d_all_fft_codes; // memory that contains all the code ffts
|
||||
uint32_t d_vector_length; // number of samples incluing padding and number of ms
|
||||
uint32_t d_excludelimit;
|
||||
uint32_t d_nsamples_total; // number of samples including padding
|
||||
@ -122,7 +121,6 @@ private:
|
||||
uint32_t d_PRN; // PRN
|
||||
// FPGA private functions
|
||||
void fpga_acquisition_test_register(void);
|
||||
void fpga_configure_acquisition_local_code(lv_16sc_t fft_local_code[]);
|
||||
void read_result_valid(uint32_t *result_valid);
|
||||
};
|
||||
|
||||
|
@ -218,7 +218,6 @@ void Channel::set_signal(const Gnss_Signal& gnss_signal)
|
||||
acq_->set_local_code();
|
||||
if (flag_enable_fpga)
|
||||
{
|
||||
//set again the gnss_synchro pointer to trigger the preloading of the current PRN code to the FPGA fabric
|
||||
trk_->set_gnss_synchro(&gnss_synchro_);
|
||||
}
|
||||
nav_->set_satellite(gnss_signal_.get_satellite());
|
||||
|
@ -53,10 +53,10 @@ Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(ConfigurationInterface* configura
|
||||
std::string default_item_type = "gr_complex";
|
||||
std::string default_dump_file = "./data/signal_source.dat";
|
||||
freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ);
|
||||
sample_rate_ = configuration->property(role + ".sampling_frequency", 2600000);
|
||||
bandwidth_ = configuration->property(role + ".bandwidth", 2000000);
|
||||
sample_rate_ = configuration->property(role + ".sampling_frequency", 12500000);
|
||||
bandwidth_ = configuration->property(role + ".bandwidth", 12500000);
|
||||
rx1_en_ = configuration->property(role + ".rx1_enable", true);
|
||||
rx2_en_ = configuration->property(role + ".rx2_enable", false);
|
||||
rx2_en_ = configuration->property(role + ".rx2_enable", true);
|
||||
buffer_size_ = configuration->property(role + ".buffer_size", 0xA0000);
|
||||
quadrature_ = configuration->property(role + ".quadrature", true);
|
||||
rf_dc_ = configuration->property(role + ".rf_dc", true);
|
||||
|
@ -48,6 +48,11 @@
|
||||
#include <cstring> // for memcpy
|
||||
#include <iostream> // for operator<<,
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 // flag that enables WE (Write Enable) of the local code FPGA
|
||||
#define LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT 0x20000000 // flag that selects the writing of the pilot code in the FPGA (as opposed to the data code)
|
||||
|
||||
|
||||
GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga(
|
||||
ConfigurationInterface* configuration, const std::string& role,
|
||||
@ -56,8 +61,6 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga(
|
||||
Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga();
|
||||
DLOG(INFO) << "role " << role;
|
||||
//################# CONFIGURATION PARAMETERS ########################
|
||||
std::string default_item_type = "gr_complex";
|
||||
std::string item_type = configuration->property(role + ".item_type", default_item_type);
|
||||
int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
|
||||
int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
|
||||
trk_param_fpga.fs_in = fs_in;
|
||||
@ -68,16 +71,76 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga(
|
||||
trk_param_fpga.dump_filename = dump_filename;
|
||||
bool dump_mat = configuration->property(role + ".dump_mat", true);
|
||||
trk_param_fpga.dump_mat = dump_mat;
|
||||
trk_param_fpga.high_dyn = configuration->property(role + ".high_dyn", false);
|
||||
if (configuration->property(role + ".smoother_length", 10) < 1)
|
||||
{
|
||||
trk_param_fpga.smoother_length = 1;
|
||||
std::cout << TEXT_RED << "WARNING: Gal. E1. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
trk_param_fpga.smoother_length = configuration->property(role + ".smoother_length", 10);
|
||||
}
|
||||
|
||||
float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 5.0);
|
||||
if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
if (FLAGS_pll_bw_hz != 0.0)
|
||||
{
|
||||
pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.pll_bw_hz = pll_bw_hz;
|
||||
float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 0.5);
|
||||
if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
if (FLAGS_dll_bw_hz != 0.0)
|
||||
{
|
||||
dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.dll_bw_hz = dll_bw_hz;
|
||||
float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0);
|
||||
trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz;
|
||||
float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 0.25);
|
||||
trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz;
|
||||
|
||||
int dll_filter_order = configuration->property(role + ".dll_filter_order", 2);
|
||||
if (dll_filter_order < 1)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 1.";
|
||||
dll_filter_order = 1;
|
||||
}
|
||||
if (dll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 3.";
|
||||
dll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.dll_filter_order = dll_filter_order;
|
||||
|
||||
int pll_filter_order = configuration->property(role + ".pll_filter_order", 3);
|
||||
if (pll_filter_order < 2)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 2.";
|
||||
pll_filter_order = 2;
|
||||
}
|
||||
if (pll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 3.";
|
||||
pll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.pll_filter_order = pll_filter_order;
|
||||
|
||||
if (pll_filter_order == 2)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 1;
|
||||
}
|
||||
if (pll_filter_order == 3)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 2;
|
||||
}
|
||||
|
||||
bool enable_fll_pull_in = configuration->property(role + ".enable_fll_pull_in", false);
|
||||
trk_param_fpga.enable_fll_pull_in = enable_fll_pull_in;
|
||||
float fll_bw_hz = configuration->property(role + ".fll_bw_hz", 35.0);
|
||||
trk_param_fpga.fll_bw_hz = fll_bw_hz;
|
||||
float pull_in_time_s = configuration->property(role + ".pull_in_time_s", 2.0);
|
||||
trk_param_fpga.pull_in_time_s = pull_in_time_s;
|
||||
|
||||
int32_t extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1);
|
||||
float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.15);
|
||||
trk_param_fpga.early_late_space_chips = early_late_space_chips;
|
||||
@ -111,16 +174,29 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga(
|
||||
char sig_[3] = "1B";
|
||||
std::memcpy(trk_param_fpga.signal, sig_, 3);
|
||||
int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20);
|
||||
if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples;
|
||||
if (FLAGS_cn0_samples != 20)
|
||||
{
|
||||
cn0_samples = FLAGS_cn0_samples;
|
||||
}
|
||||
|
||||
trk_param_fpga.cn0_samples = cn0_samples;
|
||||
int32_t cn0_min = configuration->property(role + ".cn0_min", 25);
|
||||
if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min;
|
||||
if (FLAGS_cn0_min != 25)
|
||||
{
|
||||
cn0_min = FLAGS_cn0_min;
|
||||
}
|
||||
trk_param_fpga.cn0_min = cn0_min;
|
||||
int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50);
|
||||
if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail;
|
||||
if (FLAGS_max_lock_fail != 50)
|
||||
{
|
||||
max_lock_fail = FLAGS_max_lock_fail;
|
||||
}
|
||||
trk_param_fpga.max_lock_fail = max_lock_fail;
|
||||
double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85);
|
||||
if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
if (FLAGS_carrier_lock_th != 0.85)
|
||||
{
|
||||
carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
}
|
||||
trk_param_fpga.carrier_lock_th = carrier_lock_th;
|
||||
|
||||
// FPGA configuration parameters
|
||||
@ -158,19 +234,39 @@ GalileoE1DllPllVemlTrackingFpga::GalileoE1DllPllVemlTrackingFpga(
|
||||
galileo_e1_code_gen_sinboc11_float(ca_codes_f, pilot_signal, PRN);
|
||||
galileo_e1_code_gen_sinboc11_float(data_codes_f, data_signal, PRN);
|
||||
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast<int32_t>(ca_codes_f[s]);
|
||||
d_data_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast<int32_t>(data_codes_f[s]);
|
||||
int32_t tmp_value = static_cast<int32_t>(ca_codes_f[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = tmp_value;
|
||||
tmp_value = static_cast<int32_t>(data_codes_f[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT;
|
||||
d_data_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
galileo_e1_code_gen_sinboc11_float(ca_codes_f, data_signal, PRN);
|
||||
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < 2 * GALILEO_E1_B_CODE_LENGTH_CHIPS; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = static_cast<int32_t>(ca_codes_f[s]);
|
||||
int32_t tmp_value = static_cast<int32_t>(ca_codes_f[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(GALILEO_E1_B_CODE_LENGTH_CHIPS) * 2 * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,11 @@
|
||||
#include <cstring> // for memcpy
|
||||
#include <iostream>
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 // flag that enables WE (Write Enable) of the local code FPGA
|
||||
#define LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT 0x20000000 // flag that selects the writing of the pilot code in the FPGA (as opposed to the data code)
|
||||
|
||||
|
||||
GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga(
|
||||
ConfigurationInterface *configuration, const std::string &role,
|
||||
@ -53,8 +58,6 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga(
|
||||
Dll_Pll_Conf_Fpga trk_param_fpga = Dll_Pll_Conf_Fpga();
|
||||
DLOG(INFO) << "role " << role;
|
||||
//################# CONFIGURATION PARAMETERS ########################
|
||||
std::string default_item_type = "gr_complex";
|
||||
std::string item_type = configuration->property(role + ".item_type", default_item_type);
|
||||
int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 12000000);
|
||||
int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
|
||||
trk_param_fpga.fs_in = fs_in;
|
||||
@ -65,12 +68,71 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga(
|
||||
trk_param_fpga.dump_filename = dump_filename;
|
||||
bool dump_mat = configuration->property(role + ".dump_mat", true);
|
||||
trk_param_fpga.dump_mat = dump_mat;
|
||||
trk_param_fpga.high_dyn = configuration->property(role + ".high_dyn", false);
|
||||
if (configuration->property(role + ".smoother_length", 10) < 1)
|
||||
{
|
||||
trk_param_fpga.smoother_length = 1;
|
||||
std::cout << TEXT_RED << "WARNING: Gal. E5a. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
trk_param_fpga.smoother_length = configuration->property(role + ".smoother_length", 10);
|
||||
}
|
||||
float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 20.0);
|
||||
if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
if (FLAGS_pll_bw_hz != 0.0)
|
||||
{
|
||||
pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.pll_bw_hz = pll_bw_hz;
|
||||
float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 20.0);
|
||||
if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
if (FLAGS_dll_bw_hz != 0.0)
|
||||
{
|
||||
dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.dll_bw_hz = dll_bw_hz;
|
||||
|
||||
int dll_filter_order = configuration->property(role + ".dll_filter_order", 2);
|
||||
if (dll_filter_order < 1)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 1.";
|
||||
dll_filter_order = 1;
|
||||
}
|
||||
if (dll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 3.";
|
||||
dll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.dll_filter_order = dll_filter_order;
|
||||
|
||||
int pll_filter_order = configuration->property(role + ".pll_filter_order", 3);
|
||||
if (pll_filter_order < 2)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 2.";
|
||||
pll_filter_order = 2;
|
||||
}
|
||||
if (pll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 3.";
|
||||
pll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.pll_filter_order = pll_filter_order;
|
||||
|
||||
if (pll_filter_order == 2)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 1;
|
||||
}
|
||||
if (pll_filter_order == 3)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 2;
|
||||
}
|
||||
|
||||
bool enable_fll_pull_in = configuration->property(role + ".enable_fll_pull_in", false);
|
||||
trk_param_fpga.enable_fll_pull_in = enable_fll_pull_in;
|
||||
float fll_bw_hz = configuration->property(role + ".fll_bw_hz", 35.0);
|
||||
trk_param_fpga.fll_bw_hz = fll_bw_hz;
|
||||
float pull_in_time_s = configuration->property(role + ".pull_in_time_s", 2.0);
|
||||
trk_param_fpga.pull_in_time_s = pull_in_time_s;
|
||||
|
||||
float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 5.0);
|
||||
trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz;
|
||||
float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0);
|
||||
@ -106,17 +168,30 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga(
|
||||
char sig_[3] = "5X";
|
||||
std::memcpy(trk_param_fpga.signal, sig_, 3);
|
||||
int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20);
|
||||
if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples;
|
||||
if (FLAGS_cn0_samples != 20)
|
||||
{
|
||||
cn0_samples = FLAGS_cn0_samples;
|
||||
}
|
||||
trk_param_fpga.cn0_samples = cn0_samples;
|
||||
int32_t cn0_min = configuration->property(role + ".cn0_min", 25);
|
||||
if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min;
|
||||
if (FLAGS_cn0_min != 25)
|
||||
{
|
||||
cn0_min = FLAGS_cn0_min;
|
||||
}
|
||||
trk_param_fpga.cn0_min = cn0_min;
|
||||
int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50);
|
||||
if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail;
|
||||
if (FLAGS_max_lock_fail != 50)
|
||||
{
|
||||
max_lock_fail = FLAGS_max_lock_fail;
|
||||
}
|
||||
trk_param_fpga.max_lock_fail = max_lock_fail;
|
||||
double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85);
|
||||
if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
if (FLAGS_carrier_lock_th != 0.85)
|
||||
{
|
||||
carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
}
|
||||
trk_param_fpga.carrier_lock_th = carrier_lock_th;
|
||||
|
||||
d_data_codes = nullptr;
|
||||
|
||||
// FPGA configuration parameters
|
||||
@ -143,19 +218,41 @@ GalileoE5aDllPllTrackingFpga::GalileoE5aDllPllTrackingFpga(
|
||||
for (uint32_t PRN = 1; PRN <= GALILEO_E5A_NUMBER_OF_CODES; PRN++)
|
||||
{
|
||||
galileo_e5_a_code_gen_complex_primary(aux_code, PRN, const_cast<char *>(sig_));
|
||||
|
||||
if (trk_param_fpga.track_pilot)
|
||||
{
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < code_length_chips; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(aux_code[s].imag());
|
||||
d_data_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(aux_code[s].real());
|
||||
int32_t tmp_value = static_cast<int32_t>(aux_code[s].imag());
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
|
||||
tmp_value = static_cast<int32_t>(aux_code[s].real());
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT;
|
||||
d_data_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < code_length_chips; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(aux_code[s].real());
|
||||
int32_t tmp_value = static_cast<int32_t>(aux_code[s].real());
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,6 @@ private:
|
||||
std::string role_;
|
||||
uint32_t in_streams_;
|
||||
uint32_t out_streams_;
|
||||
|
||||
int32_t* d_ca_codes;
|
||||
int32_t* d_data_codes;
|
||||
bool d_track_pilot;
|
||||
|
@ -48,8 +48,11 @@
|
||||
#include <cstring> // for memcpy
|
||||
#include <iostream>
|
||||
|
||||
#define NUM_PRNs 32
|
||||
#define NUM_PRNs 32 // total number of PRNs
|
||||
|
||||
// the following flag is FPGA-specific and they are using arrange the values of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 // flag that enables WE (Write Enable) of the local code FPGA
|
||||
|
||||
GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga(
|
||||
ConfigurationInterface* configuration, const std::string& role,
|
||||
@ -62,6 +65,17 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga(
|
||||
int32_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
|
||||
int32_t fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
|
||||
trk_param_fpga.fs_in = fs_in;
|
||||
trk_param_fpga.high_dyn = configuration->property(role + ".high_dyn", false);
|
||||
if (configuration->property(role + ".smoother_length", 10) < 1)
|
||||
{
|
||||
trk_param_fpga.smoother_length = 1;
|
||||
std::cout << TEXT_RED << "WARNING: GPS L1 C/A. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
trk_param_fpga.smoother_length = configuration->property(role + ".smoother_length", 10);
|
||||
}
|
||||
|
||||
bool dump = configuration->property(role + ".dump", false);
|
||||
trk_param_fpga.dump = dump;
|
||||
std::string default_dump_filename = "./track_ch";
|
||||
@ -70,15 +84,64 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga(
|
||||
bool dump_mat = configuration->property(role + ".dump_mat", true);
|
||||
trk_param_fpga.dump_mat = dump_mat;
|
||||
float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0);
|
||||
if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
if (FLAGS_pll_bw_hz != 0.0)
|
||||
{
|
||||
pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.pll_bw_hz = pll_bw_hz;
|
||||
float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 20.0);
|
||||
trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz;
|
||||
float dll_bw_narrow_hz = configuration->property(role + ".dll_bw_narrow_hz", 2.0);
|
||||
trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz;
|
||||
float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0);
|
||||
if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
if (FLAGS_dll_bw_hz != 0.0)
|
||||
{
|
||||
dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.dll_bw_hz = dll_bw_hz;
|
||||
|
||||
int dll_filter_order = configuration->property(role + ".dll_filter_order", 2);
|
||||
if (dll_filter_order < 1)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 1.";
|
||||
dll_filter_order = 1;
|
||||
}
|
||||
if (dll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 3.";
|
||||
dll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.dll_filter_order = dll_filter_order;
|
||||
|
||||
int pll_filter_order = configuration->property(role + ".pll_filter_order", 3);
|
||||
if (pll_filter_order < 2)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 2.";
|
||||
pll_filter_order = 2;
|
||||
}
|
||||
if (pll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 3.";
|
||||
pll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.pll_filter_order = pll_filter_order;
|
||||
|
||||
if (pll_filter_order == 2)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 1;
|
||||
}
|
||||
if (pll_filter_order == 3)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 2;
|
||||
}
|
||||
|
||||
bool enable_fll_pull_in = configuration->property(role + ".enable_fll_pull_in", false);
|
||||
trk_param_fpga.enable_fll_pull_in = enable_fll_pull_in;
|
||||
float fll_bw_hz = configuration->property(role + ".fll_bw_hz", 35.0);
|
||||
trk_param_fpga.fll_bw_hz = fll_bw_hz;
|
||||
float pull_in_time_s = configuration->property(role + ".pull_in_time_s", 2.0);
|
||||
trk_param_fpga.pull_in_time_s = pull_in_time_s;
|
||||
|
||||
float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5);
|
||||
trk_param_fpga.early_late_space_chips = early_late_space_chips;
|
||||
float early_late_space_narrow_chips = configuration->property(role + ".early_late_space_narrow_chips", 0.5);
|
||||
@ -113,16 +176,28 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga(
|
||||
char sig_[3] = "1C";
|
||||
std::memcpy(trk_param_fpga.signal, sig_, 3);
|
||||
int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20);
|
||||
if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples;
|
||||
if (FLAGS_cn0_samples != 20)
|
||||
{
|
||||
cn0_samples = FLAGS_cn0_samples;
|
||||
}
|
||||
trk_param_fpga.cn0_samples = cn0_samples;
|
||||
int32_t cn0_min = configuration->property(role + ".cn0_min", 25);
|
||||
if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min;
|
||||
int32_t cn0_min = configuration->property(role + ".cn0_min", 30);
|
||||
if (FLAGS_cn0_min != 25)
|
||||
{
|
||||
cn0_min = FLAGS_cn0_min;
|
||||
}
|
||||
trk_param_fpga.cn0_min = cn0_min;
|
||||
int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50);
|
||||
if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail;
|
||||
if (FLAGS_max_lock_fail != 50)
|
||||
{
|
||||
max_lock_fail = FLAGS_max_lock_fail;
|
||||
}
|
||||
trk_param_fpga.max_lock_fail = max_lock_fail;
|
||||
double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.85);
|
||||
if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.80);
|
||||
if (FLAGS_carrier_lock_th != 0.85)
|
||||
{
|
||||
carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
}
|
||||
trk_param_fpga.carrier_lock_th = carrier_lock_th;
|
||||
|
||||
// FPGA configuration parameters
|
||||
@ -138,6 +213,18 @@ GpsL1CaDllPllTrackingFpga::GpsL1CaDllPllTrackingFpga(
|
||||
for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++)
|
||||
{
|
||||
gps_l1_ca_code_gen_int(&d_ca_codes[(int32_t(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1)], PRN, 0);
|
||||
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t k = 0; k < GPS_L1_CA_CODE_LENGTH_CHIPS; k++)
|
||||
{
|
||||
int32_t tmp_value = d_ca_codes[(int32_t(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1) + k];
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[(int32_t(GPS_L1_CA_CODE_LENGTH_CHIPS)) * (PRN - 1) + k] = tmp_value;
|
||||
}
|
||||
}
|
||||
trk_param_fpga.ca_codes = d_ca_codes;
|
||||
trk_param_fpga.code_length_chips = GPS_L1_CA_CODE_LENGTH_CHIPS;
|
||||
|
@ -50,7 +50,12 @@
|
||||
#include <cstring> // for memcpy
|
||||
#include <iostream>
|
||||
|
||||
#define NUM_PRNs 32
|
||||
#define NUM_PRNs 32 // number of PRNS
|
||||
|
||||
// the following flags are FPGA-specific and they are using arrange the values of the local code in the way the FPGA
|
||||
// expects. This arrangement is done in the initialisation to avoid consuming unnecessary clock cycles during tracking.
|
||||
#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000 // flag that enables WE (Write Enable) of the local code FPGA
|
||||
#define LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT 0x20000000 // flag that selects the writing of the pilot code in the FPGA (as opposed to the data code)
|
||||
|
||||
|
||||
GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga(
|
||||
@ -70,11 +75,27 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga(
|
||||
trk_param_fpga.dump_filename = dump_filename;
|
||||
bool dump_mat = configuration->property(role + ".dump_mat", true);
|
||||
trk_param_fpga.dump_mat = dump_mat;
|
||||
trk_param_fpga.high_dyn = configuration->property(role + ".high_dyn", false);
|
||||
if (configuration->property(role + ".smoother_length", 10) < 1)
|
||||
{
|
||||
trk_param_fpga.smoother_length = 1;
|
||||
std::cout << TEXT_RED << "WARNING: GPS L5. smoother_length must be bigger than 0. It has been set to 1" << TEXT_RESET << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
trk_param_fpga.smoother_length = configuration->property(role + ".smoother_length", 10);
|
||||
}
|
||||
float pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0);
|
||||
if (FLAGS_pll_bw_hz != 0.0) pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
if (FLAGS_pll_bw_hz != 0.0)
|
||||
{
|
||||
pll_bw_hz = static_cast<float>(FLAGS_pll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.pll_bw_hz = pll_bw_hz;
|
||||
float dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0);
|
||||
if (FLAGS_dll_bw_hz != 0.0) dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
if (FLAGS_dll_bw_hz != 0.0)
|
||||
{
|
||||
dll_bw_hz = static_cast<float>(FLAGS_dll_bw_hz);
|
||||
}
|
||||
trk_param_fpga.dll_bw_hz = dll_bw_hz;
|
||||
float pll_bw_narrow_hz = configuration->property(role + ".pll_bw_narrow_hz", 2.0);
|
||||
trk_param_fpga.pll_bw_narrow_hz = pll_bw_narrow_hz;
|
||||
@ -82,6 +103,49 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga(
|
||||
trk_param_fpga.dll_bw_narrow_hz = dll_bw_narrow_hz;
|
||||
float early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5);
|
||||
trk_param_fpga.early_late_space_chips = early_late_space_chips;
|
||||
|
||||
int dll_filter_order = configuration->property(role + ".dll_filter_order", 2);
|
||||
if (dll_filter_order < 1)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 1.";
|
||||
dll_filter_order = 1;
|
||||
}
|
||||
if (dll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "dll_filter_order parameter must be 1, 2 or 3. Set to 3.";
|
||||
dll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.dll_filter_order = dll_filter_order;
|
||||
|
||||
int pll_filter_order = configuration->property(role + ".pll_filter_order", 3);
|
||||
if (pll_filter_order < 2)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 2.";
|
||||
pll_filter_order = 2;
|
||||
}
|
||||
if (pll_filter_order > 3)
|
||||
{
|
||||
LOG(WARNING) << "pll_filter_order parameter must be 2 or 3. Set to 3.";
|
||||
pll_filter_order = 3;
|
||||
}
|
||||
trk_param_fpga.pll_filter_order = pll_filter_order;
|
||||
|
||||
if (pll_filter_order == 2)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 1;
|
||||
}
|
||||
if (pll_filter_order == 3)
|
||||
{
|
||||
trk_param_fpga.fll_filter_order = 2;
|
||||
}
|
||||
|
||||
bool enable_fll_pull_in = configuration->property(role + ".enable_fll_pull_in", false);
|
||||
trk_param_fpga.enable_fll_pull_in = enable_fll_pull_in;
|
||||
float fll_bw_hz = configuration->property(role + ".fll_bw_hz", 35.0);
|
||||
trk_param_fpga.fll_bw_hz = fll_bw_hz;
|
||||
float pull_in_time_s = configuration->property(role + ".pull_in_time_s", 2.0);
|
||||
trk_param_fpga.pull_in_time_s = pull_in_time_s;
|
||||
|
||||
int32_t vector_length = std::round(static_cast<double>(fs_in) / (static_cast<double>(GPS_L5I_CODE_RATE_HZ) / static_cast<double>(GPS_L5I_CODE_LENGTH_CHIPS)));
|
||||
trk_param_fpga.vector_length = vector_length;
|
||||
int32_t extend_correlation_symbols = configuration->property(role + ".extend_correlation_symbols", 1);
|
||||
@ -111,16 +175,28 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga(
|
||||
char sig_[3] = "L5";
|
||||
std::memcpy(trk_param_fpga.signal, sig_, 3);
|
||||
int32_t cn0_samples = configuration->property(role + ".cn0_samples", 20);
|
||||
if (FLAGS_cn0_samples != 20) cn0_samples = FLAGS_cn0_samples;
|
||||
if (FLAGS_cn0_samples != 20)
|
||||
{
|
||||
cn0_samples = FLAGS_cn0_samples;
|
||||
}
|
||||
trk_param_fpga.cn0_samples = cn0_samples;
|
||||
int32_t cn0_min = configuration->property(role + ".cn0_min", 25);
|
||||
if (FLAGS_cn0_min != 25) cn0_min = FLAGS_cn0_min;
|
||||
if (FLAGS_cn0_min != 25)
|
||||
{
|
||||
cn0_min = FLAGS_cn0_min;
|
||||
}
|
||||
trk_param_fpga.cn0_min = cn0_min;
|
||||
int32_t max_lock_fail = configuration->property(role + ".max_lock_fail", 50);
|
||||
if (FLAGS_max_lock_fail != 50) max_lock_fail = FLAGS_max_lock_fail;
|
||||
if (FLAGS_max_lock_fail != 50)
|
||||
{
|
||||
max_lock_fail = FLAGS_max_lock_fail;
|
||||
}
|
||||
trk_param_fpga.max_lock_fail = max_lock_fail;
|
||||
double carrier_lock_th = configuration->property(role + ".carrier_lock_th", 0.75);
|
||||
if (FLAGS_carrier_lock_th != 0.85) carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
if (FLAGS_carrier_lock_th != 0.85)
|
||||
{
|
||||
carrier_lock_th = FLAGS_carrier_lock_th;
|
||||
}
|
||||
trk_param_fpga.carrier_lock_th = carrier_lock_th;
|
||||
|
||||
// FPGA configuration parameters
|
||||
@ -163,18 +239,40 @@ GpsL5DllPllTrackingFpga::GpsL5DllPllTrackingFpga(
|
||||
gps_l5q_code_gen_float(tracking_code, PRN);
|
||||
gps_l5i_code_gen_float(data_code, PRN);
|
||||
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < code_length_chips; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(tracking_code[s]);
|
||||
d_data_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(data_code[s]);
|
||||
int32_t tmp_value = static_cast<int32_t>(tracking_code[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
|
||||
tmp_value = static_cast<int32_t>(data_code[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT;
|
||||
d_data_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gps_l5i_code_gen_float(tracking_code, PRN);
|
||||
|
||||
// The code is generated as a series of 1s and -1s. In order to store the values using only one bit, a -1 is stored as a 0 in the FPGA
|
||||
for (uint32_t s = 0; s < code_length_chips; s++)
|
||||
{
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = static_cast<int32_t>(tracking_code[s]);
|
||||
int32_t tmp_value = static_cast<int32_t>(tracking_code[s]);
|
||||
if (tmp_value < 0)
|
||||
{
|
||||
tmp_value = 0;
|
||||
}
|
||||
tmp_value = tmp_value | LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY;
|
||||
d_ca_codes[static_cast<int32_t>(code_length_chips) * (PRN - 1) + s] = tmp_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,15 +80,17 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
this->message_port_register_in(pmt::mp("preamble_samplestamp"));
|
||||
// Telemetry message port input
|
||||
this->message_port_register_in(pmt::mp("telemetry_to_trk"));
|
||||
//todo: Implement the telemetry_to_trk handler in the same way the software version of tracking
|
||||
this->set_msg_handler(pmt::mp("telemetry_to_trk"), boost::bind(&dll_pll_veml_tracking_fpga::msg_handler_telemetry_to_trk, this, _1));
|
||||
|
||||
// initialize internal vars
|
||||
d_veml = false;
|
||||
d_cloop = true;
|
||||
d_pull_in_transitory = true;
|
||||
d_code_chip_rate = 0.0;
|
||||
d_secondary_code_length = 0U;
|
||||
d_secondary_code_string = nullptr;
|
||||
d_gps_l1ca_preambles_symbols = nullptr;
|
||||
d_preambles_symbols = nullptr;
|
||||
d_preamble_length_symbols = 0;
|
||||
signal_type = std::string(trk_parameters.signal);
|
||||
|
||||
std::map<std::string, std::string> map_signal_pretty_name;
|
||||
@ -124,7 +126,8 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
uint16_t preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE;
|
||||
|
||||
// preamble bits to sampled symbols
|
||||
d_gps_l1ca_preambles_symbols = static_cast<int32_t *>(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int32_t), volk_gnsssdr_get_alignment()));
|
||||
d_preamble_length_symbols = GPS_CA_PREAMBLE_LENGTH_SYMBOLS;
|
||||
d_preambles_symbols = static_cast<int32_t *>(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int32_t), volk_gnsssdr_get_alignment()));
|
||||
int32_t n = 0;
|
||||
for (uint16_t preambles_bit : preambles_bits)
|
||||
{
|
||||
@ -132,16 +135,16 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
{
|
||||
if (preambles_bit == 1)
|
||||
{
|
||||
d_gps_l1ca_preambles_symbols[n] = 1;
|
||||
d_preambles_symbols[n] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_gps_l1ca_preambles_symbols[n] = -1;
|
||||
d_preambles_symbols[n] = -1;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size
|
||||
d_symbol_history.set_capacity(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size
|
||||
d_symbol_history.clear(); // Clear all the elements in the buffer
|
||||
}
|
||||
else if (signal_type == "2S")
|
||||
@ -268,10 +271,9 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
K_blk_samples = 0.0;
|
||||
|
||||
// Initialize tracking ==========================================
|
||||
d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz);
|
||||
d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz);
|
||||
d_code_loop_filter = Tracking_2nd_DLL_filter(static_cast<float>(d_code_period));
|
||||
d_carrier_loop_filter = Tracking_2nd_PLL_filter(static_cast<float>(d_code_period));
|
||||
d_code_loop_filter = Tracking_loop_filter(d_code_period, trk_parameters.dll_bw_hz, trk_parameters.dll_filter_order, false);
|
||||
printf("trk_parameters.fll_bw_hz = %f trk_parameters.pll_bw_hz = %f trk_parameters.pll_filter_order = %d\n", trk_parameters.fll_bw_hz, trk_parameters.pll_bw_hz, trk_parameters.pll_filter_order);
|
||||
d_carrier_loop_filter.set_params(trk_parameters.fll_bw_hz, trk_parameters.pll_bw_hz, trk_parameters.pll_filter_order);
|
||||
|
||||
if (d_veml)
|
||||
{
|
||||
@ -326,6 +328,7 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
}
|
||||
|
||||
// --- Initializations ---
|
||||
d_Prompt_circular_buffer.set_capacity(d_secondary_code_length);
|
||||
// Initial code frequency basis of NCO
|
||||
d_code_freq_chips = d_code_chip_rate;
|
||||
// Residual code phase (in chips)
|
||||
@ -340,6 +343,8 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
|
||||
d_current_prn_length_samples = static_cast<int32_t>(trk_parameters.vector_length);
|
||||
d_next_prn_length_samples = d_current_prn_length_samples;
|
||||
d_current_correlation_time_s = 0.0;
|
||||
|
||||
d_correlation_length_samples = static_cast<int32_t>(trk_parameters.vector_length); // this one is only for initialisation and does not change its value (MM)
|
||||
|
||||
// CN0 estimation and lock detector buffers
|
||||
@ -370,13 +375,13 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
|
||||
if (trk_parameters.smoother_length > 0)
|
||||
{
|
||||
d_carr_ph_history.resize(trk_parameters.smoother_length * 2);
|
||||
d_code_ph_history.resize(trk_parameters.smoother_length * 2);
|
||||
d_carr_ph_history.set_capacity(trk_parameters.smoother_length * 2);
|
||||
d_code_ph_history.set_capacity(trk_parameters.smoother_length * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_carr_ph_history.resize(1);
|
||||
d_code_ph_history.resize(1);
|
||||
d_carr_ph_history.set_capacity(1);
|
||||
d_code_ph_history.set_capacity(1);
|
||||
}
|
||||
|
||||
d_dump = trk_parameters.dump;
|
||||
@ -425,9 +430,45 @@ dll_pll_veml_tracking_fpga::dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &
|
||||
d_sample_counter_next = 0ULL;
|
||||
}
|
||||
|
||||
void dll_pll_veml_tracking_fpga::msg_handler_telemetry_to_trk(const pmt::pmt_t &msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pmt::any_ref(msg).type() == typeid(int))
|
||||
{
|
||||
int tlm_event;
|
||||
tlm_event = boost::any_cast<int>(pmt::any_ref(msg));
|
||||
|
||||
switch (tlm_event)
|
||||
{
|
||||
case 1: //tlm fault in current channel
|
||||
{
|
||||
DLOG(INFO) << "Telemetry fault received in ch " << this->d_channel;
|
||||
gr::thread::scoped_lock lock(d_setlock);
|
||||
d_carrier_lock_fail_counter = 10000; //force loss-of-lock condition
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (boost::bad_any_cast &e)
|
||||
{
|
||||
LOG(WARNING) << "msg_handler_telemetry_to_trk Bad any cast!";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dll_pll_veml_tracking_fpga::start_tracking()
|
||||
{
|
||||
// all the calculations that do not require the data from the acquisition module are moved to the
|
||||
// set_gnss_synchro command, which is received with a valid PRN before the acquisition module starts the
|
||||
// acquisition process. This is done to minimize the time between the end of the acquisition process and
|
||||
// the beginning of the tracking process.
|
||||
|
||||
// correct the code phase according to the delay between acq and trk
|
||||
d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples;
|
||||
d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz;
|
||||
@ -435,75 +476,13 @@ void dll_pll_veml_tracking_fpga::start_tracking()
|
||||
|
||||
d_carrier_doppler_hz = d_acq_carrier_doppler_hz;
|
||||
d_carrier_phase_step_rad = PI_2 * d_carrier_doppler_hz / trk_parameters.fs_in;
|
||||
d_carrier_phase_rate_step_rad = 0.0;
|
||||
d_carr_ph_history.clear();
|
||||
d_code_ph_history.clear();
|
||||
// DLL/PLL filter initialization
|
||||
d_carrier_loop_filter.initialize(); // initialize the carrier filter
|
||||
d_code_loop_filter.initialize(); // initialize the code filter
|
||||
|
||||
if (systemName == "GPS" and signal_type == "L5")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else if (systemName == "Galileo" and signal_type == "1B")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else if (systemName == "Galileo" and signal_type == "5X")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_secondary_code_string = const_cast<std::string *>(&GALILEO_E5A_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1]);
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0));
|
||||
// filter initialization
|
||||
d_carrier_loop_filter.initialize(static_cast<float>(d_acq_carrier_doppler_hz)); // initialize the carrier filter
|
||||
|
||||
d_carrier_lock_fail_counter = 0;
|
||||
d_rem_code_phase_samples = 0.0;
|
||||
d_rem_carr_phase_rad = 0.0;
|
||||
d_rem_code_phase_chips = 0.0;
|
||||
d_acc_carrier_phase_rad = 0.0;
|
||||
d_cn0_estimation_counter = 0;
|
||||
d_carrier_lock_test = 1.0;
|
||||
d_CN0_SNV_dB_Hz = 0.0;
|
||||
|
||||
if (d_veml)
|
||||
{
|
||||
d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
}
|
||||
|
||||
d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_hz);
|
||||
d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_hz);
|
||||
d_carrier_loop_filter.set_pdi(static_cast<float>(d_code_period));
|
||||
d_code_loop_filter.set_pdi(static_cast<float>(d_code_period));
|
||||
|
||||
// DEBUG OUTPUT
|
||||
std::cout << "Tracking of " << systemName << " " << signal_pretty_name << " signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
DLOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel;
|
||||
|
||||
multicorrelator_fpga->set_local_code_and_taps(d_local_code_shift_chips, d_prompt_data_shift, d_acquisition_gnss_synchro->PRN);
|
||||
// enable tracking pull-in
|
||||
d_state = 1;
|
||||
d_cloop = true;
|
||||
d_Prompt_buffer_deque.clear();
|
||||
d_last_prompt = gr_complex(0.0, 0.0);
|
||||
}
|
||||
|
||||
|
||||
@ -511,7 +490,7 @@ dll_pll_veml_tracking_fpga::~dll_pll_veml_tracking_fpga()
|
||||
{
|
||||
if (signal_type == "1C")
|
||||
{
|
||||
volk_gnsssdr_free(d_gps_l1ca_preambles_symbols);
|
||||
volk_gnsssdr_free(d_preambles_symbols);
|
||||
}
|
||||
|
||||
if (d_dump_file.is_open())
|
||||
@ -557,7 +536,8 @@ bool dll_pll_veml_tracking_fpga::acquire_secondary()
|
||||
int32_t corr_value = 0;
|
||||
for (uint32_t i = 0; i < d_secondary_code_length; i++)
|
||||
{
|
||||
if (d_Prompt_buffer_deque.at(i).real() < 0.0) // symbols clipping
|
||||
if (d_Prompt_circular_buffer[i].real() < 0.0) // symbols clipping
|
||||
//if (d_Prompt_buffer_deque.at(i).real() < 0.0) // symbols clipping
|
||||
{
|
||||
if (d_secondary_code_string->at(i) == '0')
|
||||
{
|
||||
@ -585,17 +565,14 @@ bool dll_pll_veml_tracking_fpga::acquire_secondary()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integration_time_s)
|
||||
{
|
||||
// ####### CN0 ESTIMATION AND LOCK DETECTORS ######
|
||||
|
||||
if (d_cn0_estimation_counter < trk_parameters.cn0_samples)
|
||||
{
|
||||
// fill buffer with prompt correlator output values
|
||||
@ -611,13 +588,19 @@ bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integra
|
||||
// Carrier lock indicator
|
||||
d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, trk_parameters.cn0_samples);
|
||||
// Loss of lock detection
|
||||
if (!d_pull_in_transitory)
|
||||
{
|
||||
if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < trk_parameters.cn0_min)
|
||||
{
|
||||
d_carrier_lock_fail_counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--;
|
||||
if (d_carrier_lock_fail_counter > 0)
|
||||
{
|
||||
d_carrier_lock_fail_counter--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d_carrier_lock_fail_counter > trk_parameters.max_lock_fail)
|
||||
{
|
||||
@ -641,10 +624,10 @@ bool dll_pll_veml_tracking_fpga::cn0_and_tracking_lock_status(double coh_integra
|
||||
// - updated remnant code phase in samples (d_rem_code_phase_samples)
|
||||
// - d_code_freq_chips
|
||||
// - d_carrier_doppler_hz
|
||||
//void dll_pll_veml_tracking_fpga::do_correlation_step(const gr_complex *input_samples)
|
||||
void dll_pll_veml_tracking_fpga::do_correlation_step(void)
|
||||
{
|
||||
// // ################# CARRIER WIPEOFF AND CORRELATORS ##############################
|
||||
// ################# CARRIER WIPEOFF AND CORRELATORS ##############################
|
||||
// perform carrier wipe-off and compute Early, Prompt and Late correlation
|
||||
|
||||
multicorrelator_fpga->Carrier_wipeoff_multicorrelator_resampler(
|
||||
d_rem_carr_phase_rad,
|
||||
@ -660,22 +643,48 @@ void dll_pll_veml_tracking_fpga::run_dll_pll()
|
||||
{
|
||||
// ################## PLL ##########################################################
|
||||
// PLL discriminator
|
||||
//printf("d_cloop = %d\n", d_cloop);
|
||||
if (d_cloop)
|
||||
{
|
||||
// Costas loop discriminator, insensitive to 180 deg phase transitions
|
||||
d_carr_phase_error_hz = pll_cloop_two_quadrant_atan(d_P_accu) / PI_2;
|
||||
d_carr_error_hz = pll_cloop_two_quadrant_atan(d_P_accu) / PI_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Secondary code acquired. No symbols transition should be present in the signal
|
||||
d_carr_phase_error_hz = pll_four_quadrant_atan(d_P_accu) / PI_2;
|
||||
d_carr_error_hz = pll_four_quadrant_atan(d_P_accu) / PI_2;
|
||||
}
|
||||
|
||||
if ((d_pull_in_transitory == true and trk_parameters.enable_fll_pull_in == true) or trk_parameters.enable_fll_steady_state)
|
||||
{
|
||||
// FLL discriminator
|
||||
d_carr_freq_error_hz = fll_four_quadrant_atan(d_P_accu_old, d_P_accu, 0, d_current_correlation_time_s) / GPS_TWO_PI;
|
||||
d_P_accu_old = d_P_accu;
|
||||
// Carrier discriminator filter
|
||||
d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(d_carr_error_hz);
|
||||
// New carrier Doppler frequency estimation
|
||||
d_carrier_doppler_hz = d_acq_carrier_doppler_hz + d_carr_error_filt_hz;
|
||||
if ((d_pull_in_transitory == true and trk_parameters.enable_fll_pull_in == true))
|
||||
{
|
||||
//pure FLL, disable PLL
|
||||
d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_error(d_carr_freq_error_hz, 0, d_current_correlation_time_s);
|
||||
}
|
||||
else
|
||||
{
|
||||
//FLL-aided PLL
|
||||
d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_error(d_carr_freq_error_hz, d_carr_phase_error_hz, d_current_correlation_time_s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Carrier discriminator filter
|
||||
d_carr_error_filt_hz = d_carrier_loop_filter.get_carrier_error(0, d_carr_phase_error_hz, d_current_correlation_time_s);
|
||||
}
|
||||
|
||||
// New carrier Doppler frequency estimation
|
||||
d_carrier_doppler_hz = d_carr_error_filt_hz;
|
||||
|
||||
// std::cout << "d_carrier_doppler_hz: " << d_carrier_doppler_hz << std::endl;
|
||||
// std::cout << "d_CN0_SNV_dB_Hz: " << this->d_CN0_SNV_dB_Hz << std::endl;
|
||||
// ################## DLL ##########################################################
|
||||
// DLL discriminator
|
||||
if (d_veml)
|
||||
@ -687,7 +696,7 @@ void dll_pll_veml_tracking_fpga::run_dll_pll()
|
||||
d_code_error_chips = dll_nc_e_minus_l_normalized(d_E_accu, d_L_accu); // [chips/Ti]
|
||||
}
|
||||
// Code discriminator filter
|
||||
d_code_error_filt_chips = d_code_loop_filter.get_code_nco(d_code_error_chips); // [chips/second]
|
||||
d_code_error_filt_chips = d_code_loop_filter.apply(d_code_error_chips); // [chips/second]
|
||||
|
||||
// New code Doppler frequency estimation
|
||||
d_code_freq_chips = (1.0 + (d_carrier_doppler_hz / d_signal_carrier_freq)) * d_code_chip_rate - d_code_error_filt_chips;
|
||||
@ -697,13 +706,20 @@ void dll_pll_veml_tracking_fpga::run_dll_pll()
|
||||
void dll_pll_veml_tracking_fpga::clear_tracking_vars()
|
||||
{
|
||||
std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0));
|
||||
if (trk_parameters.track_pilot) d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
d_P_accu_old = gr_complex(0.0, 0.0);
|
||||
d_carr_phase_error_hz = 0.0;
|
||||
d_carr_freq_error_hz = 0.0;
|
||||
d_carr_error_hz = 0.0;
|
||||
d_carr_error_filt_hz = 0.0;
|
||||
d_code_error_chips = 0.0;
|
||||
d_code_error_filt_chips = 0.0;
|
||||
d_current_symbol = 0;
|
||||
d_Prompt_buffer_deque.clear();
|
||||
d_Prompt_circular_buffer.clear();
|
||||
//d_Prompt_buffer_deque.clear();
|
||||
d_last_prompt = gr_complex(0.0, 0.0);
|
||||
d_carrier_phase_rate_step_rad = 0.0;
|
||||
d_code_phase_rate_step_chips = 0.0;
|
||||
@ -722,6 +738,7 @@ void dll_pll_veml_tracking_fpga::update_tracking_vars()
|
||||
// Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation
|
||||
T_prn_samples = T_prn_seconds * trk_parameters.fs_in;
|
||||
K_blk_samples = T_prn_samples + d_rem_code_phase_samples;
|
||||
//d_next_prn_length_samples = static_cast<int32_t>(std::floor(K_blk_samples)); // round to a discrete number of samples
|
||||
d_next_prn_length_samples = static_cast<int32_t>(std::floor(K_blk_samples)); // round to a discrete number of samples
|
||||
|
||||
//################### PLL COMMANDS #################################################
|
||||
@ -736,22 +753,26 @@ void dll_pll_veml_tracking_fpga::update_tracking_vars()
|
||||
double tmp_cp1 = 0.0;
|
||||
double tmp_cp2 = 0.0;
|
||||
double tmp_samples = 0.0;
|
||||
for (uint32_t k = 0; k < trk_parameters.smoother_length; k++)
|
||||
for (unsigned int k = 0; k < trk_parameters.smoother_length; k++)
|
||||
{
|
||||
tmp_cp1 += d_carr_ph_history.at(k).first;
|
||||
tmp_cp2 += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first;
|
||||
tmp_samples += d_carr_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second;
|
||||
tmp_cp1 += d_carr_ph_history[k].first;
|
||||
tmp_cp2 += d_carr_ph_history[trk_parameters.smoother_length * 2 - k - 1].first;
|
||||
tmp_samples += d_carr_ph_history[trk_parameters.smoother_length * 2 - k - 1].second;
|
||||
}
|
||||
tmp_cp1 /= static_cast<double>(trk_parameters.smoother_length);
|
||||
tmp_cp2 /= static_cast<double>(trk_parameters.smoother_length);
|
||||
d_carrier_phase_rate_step_rad = (tmp_cp2 - tmp_cp1) / tmp_samples;
|
||||
}
|
||||
}
|
||||
//std::cout << d_carrier_phase_rate_step_rad * trk_parameters.fs_in * trk_parameters.fs_in / PI_2 << std::endl;
|
||||
// remnant carrier phase to prevent overflow in the code NCO
|
||||
d_rem_carr_phase_rad += static_cast<float>(d_carrier_phase_step_rad * static_cast<double>(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples));
|
||||
d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, PI_2);
|
||||
|
||||
// carrier phase accumulator
|
||||
//double a = d_carrier_phase_step_rad * static_cast<double>(d_current_prn_length_samples);
|
||||
//double b = 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples);
|
||||
//std::cout << fmod(b, PI_2) / fmod(a, PI_2) << std::endl;
|
||||
d_acc_carrier_phase_rad -= (d_carrier_phase_step_rad * static_cast<double>(d_current_prn_length_samples) + 0.5 * d_carrier_phase_rate_step_rad * static_cast<double>(d_current_prn_length_samples) * static_cast<double>(d_current_prn_length_samples));
|
||||
|
||||
//################### DLL COMMANDS #################################################
|
||||
@ -765,11 +786,11 @@ void dll_pll_veml_tracking_fpga::update_tracking_vars()
|
||||
double tmp_cp1 = 0.0;
|
||||
double tmp_cp2 = 0.0;
|
||||
double tmp_samples = 0.0;
|
||||
for (uint32_t k = 0; k < trk_parameters.smoother_length; k++)
|
||||
for (unsigned int k = 0; k < trk_parameters.smoother_length; k++)
|
||||
{
|
||||
tmp_cp1 += d_code_ph_history.at(k).first;
|
||||
tmp_cp2 += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).first;
|
||||
tmp_samples += d_code_ph_history.at(trk_parameters.smoother_length * 2 - k - 1).second;
|
||||
tmp_cp1 += d_code_ph_history[k].first;
|
||||
tmp_cp2 += d_code_ph_history[trk_parameters.smoother_length * 2 - k - 1].first;
|
||||
tmp_samples += d_code_ph_history[trk_parameters.smoother_length * 2 - k - 1].second;
|
||||
}
|
||||
tmp_cp1 /= static_cast<double>(trk_parameters.smoother_length);
|
||||
tmp_cp2 /= static_cast<double>(trk_parameters.smoother_length);
|
||||
@ -827,9 +848,13 @@ void dll_pll_veml_tracking_fpga::save_correlation_results()
|
||||
}
|
||||
// If tracking pilot, disable Costas loop
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_cloop = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_cloop = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -927,7 +952,8 @@ void dll_pll_veml_tracking_fpga::log_data(bool integrating)
|
||||
tmp_float = d_code_phase_rate_step_chips * trk_parameters.fs_in * trk_parameters.fs_in;
|
||||
d_dump_file.write(reinterpret_cast<char *>(&tmp_float), sizeof(float));
|
||||
// PLL commands
|
||||
tmp_float = d_carr_error_hz;
|
||||
tmp_float = d_carr_phase_error_hz;
|
||||
//tmp_float = d_carr_error_hz;
|
||||
d_dump_file.write(reinterpret_cast<char *>(&tmp_float), sizeof(float));
|
||||
tmp_float = d_carr_error_filt_hz;
|
||||
d_dump_file.write(reinterpret_cast<char *>(&tmp_float), sizeof(float));
|
||||
@ -1221,6 +1247,8 @@ void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
//trk_parameters.dump_filename.append(boost::lexical_cast<std::string>(d_channel));
|
||||
//trk_parameters.dump_filename.append(".dat");
|
||||
d_dump_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
d_dump_file.open(dump_filename_.c_str(), std::ios::out | std::ios::binary);
|
||||
LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << dump_filename_.c_str();
|
||||
@ -1237,6 +1265,86 @@ void dll_pll_veml_tracking_fpga::set_channel(uint32_t channel)
|
||||
void dll_pll_veml_tracking_fpga::set_gnss_synchro(Gnss_Synchro *p_gnss_synchro)
|
||||
{
|
||||
d_acquisition_gnss_synchro = p_gnss_synchro;
|
||||
if (p_gnss_synchro->PRN > 0)
|
||||
{
|
||||
//std::cout << "Acquisition is about to start " << std::endl;
|
||||
|
||||
// When using the FPGA the SW only reads the sample counter during active tracking in order to spare CPU clock cycles.
|
||||
d_sample_counter = 0;
|
||||
d_sample_counter_next = 0;
|
||||
|
||||
d_carrier_phase_rate_step_rad = 0.0;
|
||||
|
||||
d_code_ph_history.clear();
|
||||
|
||||
// DLL/PLL filter initialization
|
||||
d_code_loop_filter.initialize(); // initialize the code filter
|
||||
|
||||
d_carr_ph_history.clear();
|
||||
|
||||
if (systemName == "GPS" and signal_type == "L5")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else if (systemName == "Galileo" and signal_type == "1B")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
else if (systemName == "Galileo" and signal_type == "5X")
|
||||
{
|
||||
if (trk_parameters.track_pilot)
|
||||
{
|
||||
d_secondary_code_string = const_cast<std::string *>(&GALILEO_E5A_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN - 1]);
|
||||
d_Prompt_Data[0] = gr_complex(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
std::fill_n(d_correlator_outs, d_n_correlator_taps, gr_complex(0.0, 0.0));
|
||||
|
||||
d_carrier_lock_fail_counter = 0;
|
||||
d_rem_code_phase_samples = 0.0;
|
||||
d_rem_carr_phase_rad = 0.0;
|
||||
d_rem_code_phase_chips = 0.0;
|
||||
d_acc_carrier_phase_rad = 0.0;
|
||||
d_cn0_estimation_counter = 0;
|
||||
d_carrier_lock_test = 1.0;
|
||||
d_CN0_SNV_dB_Hz = 0.0;
|
||||
|
||||
if (d_veml)
|
||||
{
|
||||
d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[1] = -trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[3] = trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[4] = trk_parameters.very_early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_local_code_shift_chips[0] = -trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
d_local_code_shift_chips[2] = trk_parameters.early_late_space_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
}
|
||||
|
||||
d_current_correlation_time_s = d_code_period;
|
||||
|
||||
d_code_loop_filter.set_noise_bandwidth(trk_parameters.dll_bw_hz);
|
||||
d_code_loop_filter.set_update_interval(d_code_period);
|
||||
|
||||
multicorrelator_fpga->set_local_code_and_taps(d_local_code_shift_chips, d_prompt_data_shift, d_acquisition_gnss_synchro->PRN);
|
||||
|
||||
d_pull_in_transitory = true;
|
||||
|
||||
//d_Prompt_buffer_deque.clear();
|
||||
d_last_prompt = gr_complex(0.0, 0.0);
|
||||
|
||||
d_cloop = true;
|
||||
|
||||
d_Prompt_circular_buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1262,15 +1370,30 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un
|
||||
|
||||
d_current_prn_length_samples = d_next_prn_length_samples;
|
||||
|
||||
|
||||
if (d_pull_in_transitory == true)
|
||||
{
|
||||
if (d_sample_counter > 0) // do not execute this condition until the sample counter has ben read for the first time after start_tracking
|
||||
{
|
||||
if (trk_parameters.pull_in_time_s < (d_sample_counter - d_acq_sample_stamp) / static_cast<int>(trk_parameters.fs_in))
|
||||
{
|
||||
d_pull_in_transitory = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (d_state)
|
||||
{
|
||||
case 0: // Standby - Consume samples at full throttle, do nothing
|
||||
{
|
||||
return 0;
|
||||
*out[0] = *d_acquisition_gnss_synchro;
|
||||
usleep(1000);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
case 1: // Pull-in
|
||||
{
|
||||
// Signal alignment (skip samples until the incoming signal is aligned with local replica)
|
||||
|
||||
int64_t acq_trk_diff_samples;
|
||||
double acq_trk_diff_seconds;
|
||||
double delta_trk_to_acq_prn_start_samples;
|
||||
@ -1304,7 +1427,6 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un
|
||||
current_synchro_data.Tracking_sample_counter = absolute_samples_offset;
|
||||
d_sample_counter_next = d_sample_counter;
|
||||
|
||||
// Signal alignment (skip samples until the incoming signal is aligned with local replica)
|
||||
|
||||
// Doppler effect Fd = (C / (C + Vr)) * F
|
||||
double radial_velocity = (d_signal_carrier_freq + d_acq_carrier_doppler_hz) / d_signal_carrier_freq;
|
||||
@ -1325,7 +1447,12 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un
|
||||
d_acc_carrier_phase_rad -= d_carrier_phase_step_rad * static_cast<double>(samples_offset);
|
||||
d_state = 2;
|
||||
|
||||
// DEBUG OUTPUT
|
||||
std::cout << "Tracking of " << systemName << " " << signal_pretty_name << " signal started on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
DLOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel;
|
||||
|
||||
DLOG(INFO) << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples << " ( " << acq_trk_diff_seconds << " s)";
|
||||
std::cout << "Number of samples between Acquisition and Tracking = " << acq_trk_diff_samples << " ( " << acq_trk_diff_seconds << " s)" << std::endl;
|
||||
DLOG(INFO) << "PULL-IN Doppler [Hz] = " << d_carrier_doppler_hz
|
||||
<< ". PULL-IN Code Phase [samples] = " << d_acq_code_phase_samples;
|
||||
|
||||
@ -1470,9 +1597,6 @@ int dll_pll_veml_tracking_fpga::general_work(int noutput_items __attribute__((un
|
||||
if (current_synchro_data.Flag_valid_symbol_output)
|
||||
{
|
||||
current_synchro_data.fs = static_cast<int64_t>(trk_parameters.fs_in);
|
||||
// two choices for the reporting of the sample counter:
|
||||
// either the sample counter position that should be (d_sample_counter_next)
|
||||
//or the sample counter corresponding to the number of samples that the FPGA actually consumed.
|
||||
current_synchro_data.Tracking_sample_counter = d_sample_counter_next;
|
||||
*out[0] = current_synchro_data;
|
||||
return 1;
|
||||
@ -1515,17 +1639,20 @@ void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data)
|
||||
if (d_secondary)
|
||||
{
|
||||
// ####### SECONDARY CODE LOCK #####
|
||||
d_Prompt_buffer_deque.push_back(*d_Prompt);
|
||||
if (d_Prompt_buffer_deque.size() == d_secondary_code_length)
|
||||
d_Prompt_circular_buffer.push_back(*d_Prompt);
|
||||
//d_Prompt_buffer_deque.push_back(*d_Prompt);
|
||||
//if (d_Prompt_buffer_deque.size() == d_secondary_code_length)
|
||||
if (d_Prompt_circular_buffer.size() == d_secondary_code_length)
|
||||
{
|
||||
next_state = acquire_secondary();
|
||||
if (next_state)
|
||||
{
|
||||
LOG(INFO) << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel
|
||||
<< " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
std::cout << systemName << " " << signal_pretty_name << " secondary code locked in channel " << d_channel
|
||||
<< " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
}
|
||||
|
||||
d_Prompt_buffer_deque.pop_front();
|
||||
//d_Prompt_buffer_deque.pop_front();
|
||||
}
|
||||
}
|
||||
else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change
|
||||
@ -1538,20 +1665,24 @@ void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data)
|
||||
int32_t corr_value = 0;
|
||||
if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync))
|
||||
{
|
||||
for (uint32_t i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++)
|
||||
int i = 0;
|
||||
for (const auto &iter : d_symbol_history)
|
||||
{
|
||||
if (d_symbol_history.at(i) < 0) // symbols clipping
|
||||
if (iter < 0.0) // symbols clipping
|
||||
{
|
||||
corr_value -= d_gps_l1ca_preambles_symbols[i];
|
||||
corr_value -= d_preambles_symbols[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
corr_value += d_gps_l1ca_preambles_symbols[i];
|
||||
corr_value += d_preambles_symbols[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)
|
||||
{
|
||||
LOG(INFO) << systemName << " " << signal_pretty_name << " tracking preamble detected in channel " << d_channel
|
||||
<< " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
next_state = true;
|
||||
}
|
||||
else
|
||||
@ -1598,6 +1729,7 @@ void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data)
|
||||
current_synchro_data.Prompt_Q = static_cast<double>((*d_Prompt).imag());
|
||||
}
|
||||
}
|
||||
|
||||
current_synchro_data.Code_phase_samples = d_rem_code_phase_samples;
|
||||
current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad;
|
||||
current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz;
|
||||
@ -1612,17 +1744,17 @@ void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data)
|
||||
d_P_accu = gr_complex(0.0, 0.0);
|
||||
d_L_accu = gr_complex(0.0, 0.0);
|
||||
d_VL_accu = gr_complex(0.0, 0.0);
|
||||
d_last_prompt = gr_complex(0.0, 0.0);
|
||||
d_Prompt_buffer_deque.clear();
|
||||
d_Prompt_circular_buffer.clear();
|
||||
d_current_symbol = 0;
|
||||
d_last_prompt = gr_complex(0.0, 0.0);
|
||||
//d_Prompt_buffer_deque.clear();
|
||||
|
||||
if (d_enable_extended_integration)
|
||||
{
|
||||
// UPDATE INTEGRATION TIME
|
||||
d_extend_correlation_symbols_count = 0;
|
||||
float new_correlation_time = static_cast<float>(trk_parameters.extend_correlation_symbols) * static_cast<float>(d_code_period);
|
||||
d_carrier_loop_filter.set_pdi(new_correlation_time);
|
||||
d_code_loop_filter.set_pdi(new_correlation_time);
|
||||
d_current_correlation_time_s = static_cast<float>(trk_parameters.extend_correlation_symbols) * static_cast<float>(d_code_period);
|
||||
|
||||
d_state = 3; // next state is the extended correlator integrator
|
||||
LOG(INFO) << "Enabled " << trk_parameters.extend_correlation_symbols * static_cast<int32_t>(d_code_period * 1000.0) << " ms extended correlator in channel "
|
||||
<< d_channel
|
||||
@ -1631,8 +1763,9 @@ void dll_pll_veml_tracking_fpga::run_state_2(Gnss_Synchro ¤t_synchro_data)
|
||||
<< d_channel
|
||||
<< " for satellite " << Gnss_Satellite(systemName, d_acquisition_gnss_synchro->PRN) << std::endl;
|
||||
// Set narrow taps delay values [chips]
|
||||
d_code_loop_filter.set_DLL_BW(trk_parameters.dll_bw_narrow_hz);
|
||||
d_carrier_loop_filter.set_PLL_BW(trk_parameters.pll_bw_narrow_hz);
|
||||
d_code_loop_filter.set_update_interval(d_current_correlation_time_s);
|
||||
d_code_loop_filter.set_noise_bandwidth(trk_parameters.dll_bw_narrow_hz);
|
||||
d_carrier_loop_filter.set_params(trk_parameters.fll_bw_hz, trk_parameters.pll_bw_narrow_hz, trk_parameters.pll_filter_order);
|
||||
if (d_veml)
|
||||
{
|
||||
d_local_code_shift_chips[0] = -trk_parameters.very_early_late_space_narrow_chips * static_cast<float>(d_code_samples_per_chip);
|
||||
|
@ -33,20 +33,20 @@
|
||||
#define GNSS_SDR_DLL_PLL_VEML_TRACKING_FPGA_H
|
||||
|
||||
#include "dll_pll_conf_fpga.h"
|
||||
#include "tracking_2nd_DLL_filter.h"
|
||||
#include "tracking_2nd_PLL_filter.h"
|
||||
#include "tracking_FLL_PLL_filter.h" // for PLL/FLL filter
|
||||
#include "tracking_loop_filter.h" // for DLL filter
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <gnuradio/block.h>
|
||||
#include <boost/shared_ptr.hpp> // for boost::shared_ptr
|
||||
#include <gnuradio/block.h> // for block
|
||||
#include <gnuradio/gr_complex.h> // for gr_complex
|
||||
#include <gnuradio/types.h> // for gr_vector_const_void_star
|
||||
#include <gnuradio/types.h> // for gr_vector_int, gr_vector...
|
||||
#include <pmt/pmt.h> // for pmt_t
|
||||
#include <cstdint>
|
||||
#include <cstdint> // for int32_t
|
||||
#include <deque> // for deque
|
||||
#include <fstream> // for ofstream
|
||||
#include <fstream> // for string, ofstream
|
||||
#include <memory> // for shared_ptr
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <utility> // for pair
|
||||
|
||||
class Fpga_Multicorrelator_8sc;
|
||||
class Gnss_Synchro;
|
||||
@ -77,7 +77,7 @@ public:
|
||||
|
||||
private:
|
||||
friend dll_pll_veml_tracking_fpga_sptr dll_pll_veml_make_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_);
|
||||
|
||||
void msg_handler_telemetry_to_trk(const pmt::pmt_t &msg);
|
||||
dll_pll_veml_tracking_fpga(const Dll_Pll_Conf_Fpga &conf_);
|
||||
void msg_handler_preamble_index(pmt::pmt_t msg);
|
||||
|
||||
@ -115,23 +115,20 @@ private:
|
||||
std::string *d_secondary_code_string;
|
||||
std::string signal_pretty_name;
|
||||
|
||||
int32_t *d_gps_l1ca_preambles_symbols;
|
||||
int32_t *d_preambles_symbols;
|
||||
int32_t d_preamble_length_symbols;
|
||||
boost::circular_buffer<float> d_symbol_history;
|
||||
|
||||
//tracking state machine
|
||||
// tracking state machine
|
||||
int32_t d_state;
|
||||
//Integration period in samples
|
||||
|
||||
// Integration period in samples
|
||||
int32_t d_correlation_length_ms;
|
||||
int32_t d_n_correlator_taps;
|
||||
|
||||
float *d_local_code_shift_chips;
|
||||
float *d_prompt_data_shift;
|
||||
std::shared_ptr<Fpga_Multicorrelator_8sc> multicorrelator_fpga;
|
||||
/* TODO: currently the multicorrelator does not support adding extra correlator
|
||||
with different local code, thus we need extra multicorrelator instance.
|
||||
Implement this functionality inside multicorrelator class
|
||||
as an enhancement to increase the performance
|
||||
*/
|
||||
gr_complex *d_correlator_outs;
|
||||
gr_complex *d_Very_Early;
|
||||
gr_complex *d_Early;
|
||||
@ -146,6 +143,7 @@ private:
|
||||
gr_complex d_VE_accu;
|
||||
gr_complex d_E_accu;
|
||||
gr_complex d_P_accu;
|
||||
gr_complex d_P_accu_old;
|
||||
gr_complex d_L_accu;
|
||||
gr_complex d_VL_accu;
|
||||
gr_complex d_last_prompt;
|
||||
@ -163,14 +161,18 @@ private:
|
||||
float d_rem_carr_phase_rad;
|
||||
|
||||
// PLL and DLL filter library
|
||||
Tracking_2nd_DLL_filter d_code_loop_filter;
|
||||
Tracking_2nd_PLL_filter d_carrier_loop_filter;
|
||||
Tracking_loop_filter d_code_loop_filter;
|
||||
Tracking_FLL_PLL_filter d_carrier_loop_filter;
|
||||
|
||||
// acquisition
|
||||
double d_acq_code_phase_samples;
|
||||
double d_acq_carrier_doppler_hz;
|
||||
|
||||
// tracking vars
|
||||
bool d_pull_in_transitory;
|
||||
double d_current_correlation_time_s;
|
||||
double d_carr_phase_error_hz;
|
||||
double d_carr_freq_error_hz;
|
||||
double d_carr_error_hz;
|
||||
double d_carr_error_filt_hz;
|
||||
double d_code_error_chips;
|
||||
@ -194,11 +196,12 @@ private:
|
||||
// CN0 estimation and lock detector
|
||||
int32_t d_cn0_estimation_counter;
|
||||
int32_t d_carrier_lock_fail_counter;
|
||||
std::deque<float> d_carrier_lock_detector_queue;
|
||||
//std::deque<float> d_carrier_lock_detector_queue;
|
||||
double d_carrier_lock_test;
|
||||
double d_CN0_SNV_dB_Hz;
|
||||
double d_carrier_lock_threshold;
|
||||
std::deque<gr_complex> d_Prompt_buffer_deque;
|
||||
boost::circular_buffer<gr_complex> d_Prompt_circular_buffer;
|
||||
//std::deque<gr_complex> d_Prompt_buffer_deque;
|
||||
gr_complex *d_Prompt_buffer;
|
||||
|
||||
// file dump
|
||||
|
@ -44,6 +44,15 @@ Dll_Pll_Conf_Fpga::Dll_Pll_Conf_Fpga()
|
||||
dump = false;
|
||||
dump_mat = true;
|
||||
dump_filename = std::string("./dll_pll_dump.dat");
|
||||
enable_fll_pull_in = false;
|
||||
enable_fll_steady_state = false;
|
||||
pull_in_time_s = 2;
|
||||
fll_filter_order = 1;
|
||||
pll_filter_order = 3;
|
||||
dll_filter_order = 2;
|
||||
fll_bw_hz = 35.0;
|
||||
pll_pull_in_bw_hz = 50.0;
|
||||
dll_pull_in_bw_hz = 3.0;
|
||||
pll_bw_hz = 35.0;
|
||||
dll_bw_hz = 2.0;
|
||||
pll_bw_narrow_hz = 5.0;
|
||||
|
@ -42,11 +42,22 @@ class Dll_Pll_Conf_Fpga
|
||||
{
|
||||
public:
|
||||
/* DLL/PLL tracking configuration */
|
||||
int fll_filter_order;
|
||||
bool enable_fll_pull_in;
|
||||
bool enable_fll_steady_state;
|
||||
unsigned int pull_in_time_s; // signed integer, when pull in time is not yet reached it has to be compared against a negative number
|
||||
int pll_filter_order;
|
||||
int dll_filter_order;
|
||||
|
||||
|
||||
double fs_in;
|
||||
uint32_t vector_length;
|
||||
bool dump;
|
||||
bool dump_mat;
|
||||
std::string dump_filename;
|
||||
float pll_pull_in_bw_hz;
|
||||
float dll_pull_in_bw_hz;
|
||||
float fll_bw_hz;
|
||||
float pll_bw_hz;
|
||||
float dll_bw_hz;
|
||||
float pll_bw_narrow_hz;
|
||||
|
@ -51,9 +51,9 @@
|
||||
#define CODE_PHASE_STEP_CHIPS_NUM_NBITS CODE_RESAMPLER_NUM_BITS_PRECISION
|
||||
#define pwrtwo(x) (1 << (x))
|
||||
#define MAX_CODE_RESAMPLER_COUNTER pwrtwo(CODE_PHASE_STEP_CHIPS_NUM_NBITS) // 2^CODE_PHASE_STEP_CHIPS_NUM_NBITS
|
||||
#define PHASE_CARR_NBITS 32
|
||||
#define PHASE_CARR_NBITS_INT 1
|
||||
#define PHASE_CARR_NBITS_FRAC PHASE_CARR_NBITS - PHASE_CARR_NBITS_INT
|
||||
#define PHASE_CARR_MAX 2147483648 // 2^(31) The phase is represented as a 32-bit vector in 1.31 format
|
||||
#define PHASE_CARR_MAX_div_PI 683565275.5764316 // 2^(31)/pi
|
||||
#define TWO_PI 6.283185307179586
|
||||
#define LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT 0x20000000
|
||||
#define LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER 0x10000000
|
||||
#define LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY 0x0C000000
|
||||
@ -118,6 +118,7 @@ Fpga_Multicorrelator_8sc::Fpga_Multicorrelator_8sc(int32_t n_correlators,
|
||||
d_data_codes = data_codes;
|
||||
d_multicorr_type = multicorr_type;
|
||||
d_code_samples_per_chip = code_samples_per_chip;
|
||||
d_code_length_samples = d_code_length_chips * d_code_samples_per_chip;
|
||||
|
||||
DLOG(INFO) << "TRACKING FPGA CLASS CREATED";
|
||||
}
|
||||
@ -171,9 +172,9 @@ void Fpga_Multicorrelator_8sc::set_output_vectors(gr_complex *corr_out, gr_compl
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Multicorrelator_8sc::update_local_code(float rem_code_phase_chips)
|
||||
void Fpga_Multicorrelator_8sc::update_local_code()
|
||||
{
|
||||
d_rem_code_phase_chips = rem_code_phase_chips;
|
||||
//d_rem_code_phase_chips = rem_code_phase_chips;
|
||||
Fpga_Multicorrelator_8sc::fpga_compute_code_shift_parameters();
|
||||
Fpga_Multicorrelator_8sc::fpga_configure_code_parameters_in_fpga();
|
||||
}
|
||||
@ -188,11 +189,12 @@ void Fpga_Multicorrelator_8sc::Carrier_wipeoff_multicorrelator_resampler(
|
||||
float code_phase_rate_step_chips __attribute__((unused)),
|
||||
int32_t signal_length_samples)
|
||||
{
|
||||
update_local_code(rem_code_phase_chips);
|
||||
d_rem_code_phase_chips = rem_code_phase_chips;
|
||||
d_rem_carrier_phase_in_rad = rem_carrier_phase_in_rad;
|
||||
d_code_phase_step_chips = code_phase_step_chips;
|
||||
d_phase_step_rad = phase_step_rad;
|
||||
d_correlator_length_samples = signal_length_samples;
|
||||
Fpga_Multicorrelator_8sc::update_local_code();
|
||||
Fpga_Multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga();
|
||||
Fpga_Multicorrelator_8sc::fpga_configure_signal_parameters_in_fpga();
|
||||
Fpga_Multicorrelator_8sc::fpga_launch_multicorrelator_fpga();
|
||||
@ -298,88 +300,72 @@ uint32_t Fpga_Multicorrelator_8sc::fpga_acquisition_test_register(
|
||||
void Fpga_Multicorrelator_8sc::fpga_configure_tracking_gps_local_code(int32_t PRN)
|
||||
{
|
||||
uint32_t k;
|
||||
uint32_t code_chip;
|
||||
uint32_t select_pilot_corelator = LOCAL_CODE_FPGA_CORRELATOR_SELECT_COUNT;
|
||||
|
||||
d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER;
|
||||
for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++)
|
||||
for (k = 0; k < d_code_length_samples; k++)
|
||||
{
|
||||
if (d_ca_codes[((int32_t(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1)
|
||||
{
|
||||
code_chip = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
code_chip = 0;
|
||||
}
|
||||
|
||||
// copy the local code to the FPGA memory one by one
|
||||
d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip; // | select_fpga_correlator;
|
||||
d_map_base[PROG_MEMS_ADDR] = d_ca_codes[(d_code_length_samples * (PRN - 1)) + k];
|
||||
}
|
||||
if (d_track_pilot)
|
||||
{
|
||||
d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_CLEAR_ADDRESS_COUNTER;
|
||||
for (k = 0; k < d_code_length_chips * d_code_samples_per_chip; k++)
|
||||
for (k = 0; k < d_code_length_samples; k++)
|
||||
{
|
||||
if (d_data_codes[((int32_t(d_code_length_chips)) * d_code_samples_per_chip * (PRN - 1)) + k] == 1)
|
||||
{
|
||||
code_chip = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
code_chip = 0;
|
||||
}
|
||||
d_map_base[PROG_MEMS_ADDR] = LOCAL_CODE_FPGA_ENABLE_WRITE_MEMORY | code_chip | select_pilot_corelator;
|
||||
d_map_base[PROG_MEMS_ADDR] = d_data_codes[(d_code_length_samples * (PRN - 1)) + k];
|
||||
}
|
||||
}
|
||||
|
||||
d_map_base[CODE_LENGTH_MINUS_1_REG_ADDR] = (d_code_length_samples)-1; // number of samples - 1
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Multicorrelator_8sc::fpga_compute_code_shift_parameters(void)
|
||||
{
|
||||
float temp_calculation;
|
||||
int32_t i;
|
||||
float frac_part; // decimal part
|
||||
int32_t dec_part; // fractional part
|
||||
|
||||
for (i = 0; i < d_n_correlators; i++)
|
||||
for (uint32_t i = 0; i < d_n_correlators; i++)
|
||||
{
|
||||
temp_calculation = floor(d_shifts_chips[i] - d_rem_code_phase_chips);
|
||||
dec_part = floor(d_shifts_chips[i] - d_rem_code_phase_chips);
|
||||
|
||||
if (temp_calculation < 0)
|
||||
if (dec_part < 0)
|
||||
{
|
||||
temp_calculation = temp_calculation + (d_code_length_chips * d_code_samples_per_chip); // % operator does not work as in Matlab with negative numbers
|
||||
dec_part = dec_part + d_code_length_samples; // % operator does not work as in Matlab with negative numbers
|
||||
}
|
||||
d_initial_index[i] = static_cast<uint32_t>((static_cast<int32_t>(temp_calculation)) % (d_code_length_chips * d_code_samples_per_chip));
|
||||
temp_calculation = fmod(d_shifts_chips[i] - d_rem_code_phase_chips, 1.0);
|
||||
if (temp_calculation < 0)
|
||||
d_initial_index[i] = dec_part;
|
||||
|
||||
|
||||
frac_part = fmod(d_shifts_chips[i] - d_rem_code_phase_chips, 1.0);
|
||||
if (frac_part < 0)
|
||||
{
|
||||
temp_calculation = temp_calculation + 1.0; // fmod operator does not work as in Matlab with negative numbers
|
||||
frac_part = frac_part + 1.0; // fmod operator does not work as in Matlab with negative numbers
|
||||
}
|
||||
|
||||
d_initial_interp_counter[i] = static_cast<uint32_t>(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation));
|
||||
d_initial_interp_counter[i] = static_cast<uint32_t>(floor(MAX_CODE_RESAMPLER_COUNTER * frac_part));
|
||||
}
|
||||
if (d_track_pilot)
|
||||
{
|
||||
temp_calculation = floor(d_prompt_data_shift[0] - d_rem_code_phase_chips);
|
||||
dec_part = floor(d_prompt_data_shift[0] - d_rem_code_phase_chips);
|
||||
|
||||
if (temp_calculation < 0)
|
||||
if (dec_part < 0)
|
||||
{
|
||||
temp_calculation = temp_calculation + (d_code_length_chips * d_code_samples_per_chip); // % operator does not work as in Matlab with negative numbers
|
||||
dec_part = dec_part + d_code_length_samples; // % operator does not work as in Matlab with negative numbers
|
||||
}
|
||||
d_initial_index[d_n_correlators] = static_cast<uint32_t>((static_cast<int32_t>(temp_calculation)) % (d_code_length_chips * d_code_samples_per_chip));
|
||||
temp_calculation = fmod(d_prompt_data_shift[0] - d_rem_code_phase_chips, 1.0);
|
||||
if (temp_calculation < 0)
|
||||
d_initial_index[d_n_correlators] = dec_part;
|
||||
|
||||
frac_part = fmod(d_prompt_data_shift[0] - d_rem_code_phase_chips, 1.0);
|
||||
if (frac_part < 0)
|
||||
{
|
||||
temp_calculation = temp_calculation + 1.0; // fmod operator does not work as in Matlab with negative numbers
|
||||
frac_part = frac_part + 1.0; // fmod operator does not work as in Matlab with negative numbers
|
||||
}
|
||||
d_initial_interp_counter[d_n_correlators] = static_cast<uint32_t>(floor(MAX_CODE_RESAMPLER_COUNTER * temp_calculation));
|
||||
d_initial_interp_counter[d_n_correlators] = static_cast<uint32_t>(floor(MAX_CODE_RESAMPLER_COUNTER * frac_part));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Fpga_Multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(void)
|
||||
{
|
||||
int32_t i;
|
||||
for (i = 0; i < d_n_correlators; i++)
|
||||
for (uint32_t i = 0; i < d_n_correlators; i++)
|
||||
{
|
||||
d_map_base[INITIAL_INDEX_REG_BASE_ADDR + i] = d_initial_index[i];
|
||||
d_map_base[INITIAL_INTERP_COUNTER_REG_BASE_ADDR + i] = d_initial_interp_counter[i];
|
||||
@ -389,8 +375,6 @@ void Fpga_Multicorrelator_8sc::fpga_configure_code_parameters_in_fpga(void)
|
||||
d_map_base[INITIAL_INDEX_REG_BASE_ADDR + d_n_correlators] = d_initial_index[d_n_correlators];
|
||||
d_map_base[INITIAL_INTERP_COUNTER_REG_BASE_ADDR + d_n_correlators] = d_initial_interp_counter[d_n_correlators];
|
||||
}
|
||||
|
||||
d_map_base[CODE_LENGTH_MINUS_1_REG_ADDR] = (d_code_length_chips * d_code_samples_per_chip) - 1; // number of samples - 1
|
||||
}
|
||||
|
||||
|
||||
@ -399,34 +383,22 @@ void Fpga_Multicorrelator_8sc::fpga_compute_signal_parameters_in_fpga(void)
|
||||
float d_rem_carrier_phase_in_rad_temp;
|
||||
|
||||
d_code_phase_step_chips_num = static_cast<uint32_t>(roundf(MAX_CODE_RESAMPLER_COUNTER * d_code_phase_step_chips));
|
||||
if (d_code_phase_step_chips > 1.0)
|
||||
{
|
||||
std::cout << "Warning : d_code_phase_step_chips = " << d_code_phase_step_chips << " cannot be bigger than one" << std::endl;
|
||||
}
|
||||
|
||||
if (d_rem_carrier_phase_in_rad > M_PI)
|
||||
{
|
||||
d_rem_carrier_phase_in_rad_temp = -2 * M_PI + d_rem_carrier_phase_in_rad;
|
||||
d_rem_carrier_phase_in_rad_temp = -TWO_PI + d_rem_carrier_phase_in_rad;
|
||||
}
|
||||
else if (d_rem_carrier_phase_in_rad < -M_PI)
|
||||
{
|
||||
d_rem_carrier_phase_in_rad_temp = 2 * M_PI + d_rem_carrier_phase_in_rad;
|
||||
d_rem_carrier_phase_in_rad_temp = TWO_PI + d_rem_carrier_phase_in_rad;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_rem_carrier_phase_in_rad_temp = d_rem_carrier_phase_in_rad;
|
||||
}
|
||||
d_rem_carr_phase_rad_int = static_cast<int32_t>(roundf((fabs(d_rem_carrier_phase_in_rad_temp) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC)));
|
||||
if (d_rem_carrier_phase_in_rad_temp < 0)
|
||||
{
|
||||
d_rem_carr_phase_rad_int = -d_rem_carr_phase_rad_int;
|
||||
}
|
||||
d_phase_step_rad_int = static_cast<int32_t>(roundf((fabs(d_phase_step_rad) / M_PI) * pow(2, PHASE_CARR_NBITS_FRAC))); // the FPGA accepts a range for the phase step between -pi and +pi
|
||||
|
||||
if (d_phase_step_rad < 0)
|
||||
{
|
||||
d_phase_step_rad_int = -d_phase_step_rad_int;
|
||||
}
|
||||
d_rem_carr_phase_rad_int = static_cast<int32_t>(roundf((d_rem_carrier_phase_in_rad_temp)*PHASE_CARR_MAX_div_PI));
|
||||
d_phase_step_rad_int = static_cast<int32_t>(roundf((d_phase_step_rad)*PHASE_CARR_MAX_div_PI)); // the FPGA accepts a range for the phase step between -pi and +pi
|
||||
}
|
||||
|
||||
|
||||
@ -460,9 +432,8 @@ void Fpga_Multicorrelator_8sc::read_tracking_gps_results(void)
|
||||
{
|
||||
int32_t readval_real;
|
||||
int32_t readval_imag;
|
||||
int32_t k;
|
||||
|
||||
for (k = 0; k < d_n_correlators; k++)
|
||||
for (uint32_t k = 0; k < d_n_correlators; k++)
|
||||
{
|
||||
readval_real = d_map_base[RESULT_REG_REAL_BASE_ADDR + k];
|
||||
readval_imag = d_map_base[RESULT_REG_IMAG_BASE_ADDR + k];
|
||||
|
@ -77,7 +77,7 @@ public:
|
||||
void set_output_vectors(gr_complex *corr_out, gr_complex *Prompt_Data);
|
||||
void set_local_code_and_taps(
|
||||
float *shifts_chips, float *prompt_data_shift, int32_t PRN);
|
||||
void update_local_code(float rem_code_phase_chips);
|
||||
void update_local_code();
|
||||
void Carrier_wipeoff_multicorrelator_resampler(
|
||||
float rem_carrier_phase_in_rad, float phase_step_rad,
|
||||
float carrier_phase_rate_step_rad,
|
||||
@ -96,8 +96,9 @@ private:
|
||||
gr_complex *d_Prompt_Data;
|
||||
float *d_shifts_chips;
|
||||
float *d_prompt_data_shift;
|
||||
int32_t d_code_length_chips;
|
||||
int32_t d_n_correlators; // number of correlators
|
||||
uint32_t d_code_length_chips;
|
||||
uint32_t d_code_length_samples;
|
||||
uint32_t d_n_correlators; // number of correlators
|
||||
|
||||
// data related to the hardware module and the driver
|
||||
int32_t d_device_descriptor; // driver descriptor
|
||||
|
@ -2,11 +2,12 @@
|
||||
* \file gnss_sdr_fpga_sample_counter.cc
|
||||
* \brief Simple block to report the current receiver time based on the output
|
||||
* of the tracking or telemetry blocks
|
||||
* \author Marc Majoral 2019. mmajoral(at)cttc.es
|
||||
* \author Javier Arribas 2018. jarribas(at)cttc.es
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
|
||||
* Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors)
|
||||
*
|
||||
* GNSS-SDR is a software defined Global Navigation
|
||||
* Satellite Systems receiver
|
||||
@ -69,19 +70,17 @@ gnss_sdr_fpga_sample_counter::gnss_sdr_fpga_sample_counter(
|
||||
interval_ms = _interval_ms;
|
||||
fs = _fs;
|
||||
samples_per_output = std::round(fs * static_cast<double>(interval_ms) / 1e3);
|
||||
//todo: Load here the hardware counter register with this amount of samples. It should produce an
|
||||
//interrupt every samples_per_output count.
|
||||
//The hardware timer must keep always interrupting the PS. It must not wait for the interrupt to
|
||||
//be served.
|
||||
open_device();
|
||||
is_open = true;
|
||||
sample_counter = 0ULL;
|
||||
last_sample_counter = 0ULL;
|
||||
current_T_rx_ms = 0;
|
||||
current_s = 0;
|
||||
current_m = 0;
|
||||
current_h = 0;
|
||||
current_days = 0;
|
||||
report_interval_ms = 1000; // default reporting 1 second
|
||||
samples_per_report = std::round(fs * static_cast<double>(report_interval_ms) / 1e3);
|
||||
flag_enable_send_msg = false; // enable it for reporting time with asynchronous message
|
||||
flag_m = false;
|
||||
flag_h = false;
|
||||
@ -105,11 +104,9 @@ gnss_sdr_fpga_sample_counter::~gnss_sdr_fpga_sample_counter()
|
||||
}
|
||||
|
||||
|
||||
// Called by gnuradio to enable drivers, etc for i/o devices.
|
||||
// Called by GNU Radio to enable drivers, etc for i/o devices.
|
||||
bool gnss_sdr_fpga_sample_counter::start()
|
||||
{
|
||||
//todo: place here the RE-INITIALIZATION routines. This function will be called by GNURadio at every start of the flowgraph.
|
||||
|
||||
// configure the number of samples per output in the FPGA and enable the interrupts
|
||||
configure_samples_per_output(samples_per_output);
|
||||
|
||||
@ -118,11 +115,9 @@ bool gnss_sdr_fpga_sample_counter::start()
|
||||
}
|
||||
|
||||
|
||||
// Called by GNURadio to disable drivers, etc for i/o devices.
|
||||
// Called by GNU Radio to disable drivers, etc for i/o devices.
|
||||
bool gnss_sdr_fpga_sample_counter::stop()
|
||||
{
|
||||
//todo: place here the routines to stop the associated hardware (if needed).This function will be called by GNURadio at every stop of the flowgraph.
|
||||
// return true if everything is ok.
|
||||
close_device();
|
||||
is_open = false;
|
||||
return true;
|
||||
@ -194,65 +189,31 @@ void gnss_sdr_fpga_sample_counter::close_device()
|
||||
}
|
||||
|
||||
|
||||
uint32_t gnss_sdr_fpga_sample_counter::wait_for_interrupt_and_read_counter()
|
||||
{
|
||||
int32_t irq_count;
|
||||
ssize_t nb;
|
||||
int32_t counter;
|
||||
|
||||
// enable interrupts
|
||||
int32_t reenable = 1;
|
||||
ssize_t nbytes = TEMP_FAILURE_RETRY(write(fd, reinterpret_cast<void *>(&reenable), sizeof(int32_t)));
|
||||
if (nbytes != sizeof(int32_t))
|
||||
{
|
||||
std::cerr << "Error enabling interruptions in the FPGA." << std::endl;
|
||||
}
|
||||
|
||||
// wait for interrupt
|
||||
nb = read(fd, &irq_count, sizeof(irq_count));
|
||||
if (nb != sizeof(irq_count))
|
||||
{
|
||||
std::cout << "FPGA sample counter module read failed to retrieve 4 bytes!" << std::endl;
|
||||
std::cout << "FPGA sample counter module interrupt number " << irq_count << std::endl;
|
||||
}
|
||||
|
||||
// it is a rising edge interrupt, the interrupt does not need to be acknowledged
|
||||
//map_base[1] = 0; // writing anything to reg 1 acknowledges the interrupt
|
||||
|
||||
// add number of passed samples or read the current counter value for more accuracy
|
||||
counter = samples_per_output; //map_base[0];
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__((unused)),
|
||||
__attribute__((unused)) gr_vector_int &ninput_items,
|
||||
__attribute__((unused)) gr_vector_const_void_star &input_items,
|
||||
gr_vector_void_star &output_items)
|
||||
{
|
||||
//todo: Call here a function that waits for an interrupt. Do not open a thread,
|
||||
//it must be a simple call to a BLOCKING function.
|
||||
// The function will return the actual absolute sample count of the internal counter of the timmer.
|
||||
// store the sample count in class member sample_counter
|
||||
// Possible problem: what happen if the PS is overloaded and gnuradio does not call this function
|
||||
// with the sufficient rate to catch all the interrupts in the counter. To be evaluated later.
|
||||
wait_for_interrupt();
|
||||
|
||||
uint32_t counter = wait_for_interrupt_and_read_counter();
|
||||
uint64_t samples_passed = 2 * static_cast<uint64_t>(samples_per_output) - static_cast<uint64_t>(counter); // ellapsed samples
|
||||
// Note: at this moment the sample counter is implemented as a sample counter that decreases to zero and then it is automatically
|
||||
// reloaded again and keeps counter. It is done in this way to minimize the logic in the FPGA and maximize the FPGA clock performance
|
||||
// (it takes less resources and latency in the FPGA to compare a number against a fixed value like zero than to compare it to a programmable
|
||||
// variable number).
|
||||
uint64_t sample_counter_tmp, sample_counter_msw_tmp;
|
||||
sample_counter_tmp = map_base[0];
|
||||
sample_counter_msw_tmp = map_base[1];
|
||||
sample_counter_msw_tmp = sample_counter_msw_tmp << 32;
|
||||
sample_counter_tmp = sample_counter_tmp + sample_counter_msw_tmp; // 2^32
|
||||
sample_counter = sample_counter_tmp;
|
||||
|
||||
sample_counter = sample_counter + samples_passed; //samples_per_output;
|
||||
auto *out = reinterpret_cast<Gnss_Synchro *>(output_items[0]);
|
||||
out[0] = Gnss_Synchro();
|
||||
out[0].Flag_valid_symbol_output = false;
|
||||
out[0].Flag_valid_word = false;
|
||||
out[0].Channel_ID = -1;
|
||||
out[0].fs = fs;
|
||||
if ((current_T_rx_ms % report_interval_ms) == 0)
|
||||
|
||||
if ((sample_counter - last_sample_counter) > samples_per_report)
|
||||
{
|
||||
last_sample_counter = sample_counter;
|
||||
|
||||
current_s++;
|
||||
if ((current_s % 60) == 0)
|
||||
{
|
||||
@ -310,7 +271,25 @@ int gnss_sdr_fpga_sample_counter::general_work(int noutput_items __attribute__((
|
||||
}
|
||||
}
|
||||
out[0].Tracking_sample_counter = sample_counter;
|
||||
//current_T_rx_ms = (sample_counter * 1000) / samples_per_output;
|
||||
current_T_rx_ms = interval_ms * (sample_counter) / samples_per_output;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void gnss_sdr_fpga_sample_counter::wait_for_interrupt()
|
||||
{
|
||||
int32_t irq_count;
|
||||
ssize_t nb;
|
||||
|
||||
// enable interrupts
|
||||
int32_t reenable = 1;
|
||||
write(fd, reinterpret_cast<void *>(&reenable), sizeof(int32_t));
|
||||
|
||||
// wait for interrupt
|
||||
nb = read(fd, &irq_count, sizeof(irq_count));
|
||||
if (nb != sizeof(irq_count))
|
||||
{
|
||||
std::cout << "fpga sample counter module read failed to retrieve 4 bytes!" << std::endl;
|
||||
std::cout << "fpga sample counter module interrupt number " << irq_count << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -55,11 +55,15 @@ private:
|
||||
void close_device(void);
|
||||
void open_device(void);
|
||||
bool start();
|
||||
|
||||
bool stop();
|
||||
uint32_t wait_for_interrupt_and_read_counter(void);
|
||||
void wait_for_interrupt(void);
|
||||
uint32_t samples_per_output;
|
||||
uint32_t samples_per_report;
|
||||
double fs;
|
||||
uint64_t sample_counter;
|
||||
uint64_t last_sample_counter;
|
||||
|
||||
uint32_t interval_ms;
|
||||
uint64_t current_T_rx_ms; // Receiver time in ms since the beginning of the run
|
||||
uint32_t current_s; // Receiver time in seconds, modulo 60
|
||||
@ -70,6 +74,7 @@ private:
|
||||
bool flag_days; // True if the receiver has been running for at least 1 day
|
||||
uint32_t current_days; // Receiver time in days since the beginning of the run
|
||||
int32_t report_interval_ms;
|
||||
|
||||
bool flag_enable_send_msg;
|
||||
int32_t fd; // driver descriptor
|
||||
volatile uint32_t *map_base; // driver memory map
|
||||
|
@ -63,7 +63,13 @@ for channelNr = channelList
|
||||
|
||||
%% Plot all figures =======================================================
|
||||
|
||||
timeAxisInSeconds = (1:4:settings.msToProcess)/1000;
|
||||
if isfield(trackResults(channelNr), 'prn_start_time_s')
|
||||
timeAxis=trackResults(channelNr).prn_start_time_s;
|
||||
time_label='RX Time (s)';
|
||||
else
|
||||
timeAxis = (1:length(trackResults(channelNr).PRN));
|
||||
time_label='Epoch';
|
||||
end
|
||||
|
||||
%----- Discrete-Time Scatter Plot ---------------------------------
|
||||
plot(handles(1, 1), trackResults(channelNr).data_I,...
|
||||
@ -77,29 +83,26 @@ for channelNr = channelList
|
||||
ylabel(handles(1, 1), 'Q prompt');
|
||||
|
||||
%----- Nav bits ---------------------------------------------------
|
||||
t = (1:length(trackResults(channelNr).data_I));
|
||||
plot (handles(1, 2), t, ...
|
||||
plot (handles(1, 2), timeAxis, ...
|
||||
trackResults(channelNr).data_I);
|
||||
|
||||
grid (handles(1, 2));
|
||||
title (handles(1, 2), 'Bits of the navigation message');
|
||||
xlabel(handles(1, 2), 'Time (s)');
|
||||
xlabel(handles(1, 2), time_label);
|
||||
axis (handles(1, 2), 'tight');
|
||||
|
||||
%----- PLL discriminator unfiltered--------------------------------
|
||||
t = (1:length(trackResults(channelNr).pllDiscr));
|
||||
plot (handles(2, 1), t, ...
|
||||
plot (handles(2, 1), timeAxis, ...
|
||||
trackResults(channelNr).pllDiscr, 'r');
|
||||
|
||||
grid (handles(2, 1));
|
||||
axis (handles(2, 1), 'tight');
|
||||
xlabel(handles(2, 1), 'Time (s)');
|
||||
xlabel(handles(2, 1), time_label);
|
||||
ylabel(handles(2, 1), 'Amplitude');
|
||||
title (handles(2, 1), 'Raw PLL discriminator');
|
||||
|
||||
%----- Correlation ------------------------------------------------
|
||||
t = (1:length(trackResults(channelNr).I_VE));
|
||||
plot(handles(2, 2), t, ...
|
||||
plot(handles(2, 2), timeAxis, ...
|
||||
[sqrt(trackResults(channelNr).I_VE.^2 + ...
|
||||
trackResults(channelNr).Q_VE.^2)', ...
|
||||
sqrt(trackResults(channelNr).I_E.^2 + ...
|
||||
@ -114,7 +117,7 @@ for channelNr = channelList
|
||||
|
||||
grid (handles(2, 2));
|
||||
title (handles(2, 2), 'Correlation results');
|
||||
xlabel(handles(2, 2), 'Time (s)');
|
||||
xlabel(handles(2, 2), time_label);
|
||||
axis (handles(2, 2), 'tight');
|
||||
|
||||
hLegend = legend(handles(2, 2), '$\sqrt{I_{VE}^2 + Q_{VE}^2}$', ...
|
||||
@ -127,35 +130,32 @@ for channelNr = channelList
|
||||
set(hLegend, 'Interpreter', 'Latex');
|
||||
|
||||
%----- PLL discriminator filtered----------------------------------
|
||||
t = (1:length(trackResults(channelNr).pllDiscrFilt));
|
||||
plot (handles(3, 1), t, ...
|
||||
plot (handles(3, 1), timeAxis, ...
|
||||
trackResults(channelNr).pllDiscrFilt, 'b');
|
||||
|
||||
grid (handles(3, 1));
|
||||
axis (handles(3, 1), 'tight');
|
||||
xlabel(handles(3, 1), 'Time (s)');
|
||||
xlabel(handles(3, 1), time_label);
|
||||
ylabel(handles(3, 1), 'Amplitude');
|
||||
title (handles(3, 1), 'Filtered PLL discriminator');
|
||||
|
||||
%----- DLL discriminator unfiltered--------------------------------
|
||||
t = (1:length(trackResults(channelNr).dllDiscr));
|
||||
plot (handles(3, 2), t, ...
|
||||
plot (handles(3, 2), timeAxis, ...
|
||||
trackResults(channelNr).dllDiscr, 'r');
|
||||
|
||||
grid (handles(3, 2));
|
||||
axis (handles(3, 2), 'tight');
|
||||
xlabel(handles(3, 2), 'Time (s)');
|
||||
xlabel(handles(3, 2), time_label);
|
||||
ylabel(handles(3, 2), 'Amplitude');
|
||||
title (handles(3, 2), 'Raw DLL discriminator');
|
||||
|
||||
%----- DLL discriminator filtered----------------------------------
|
||||
t = (1:length(trackResults(channelNr).dllDiscrFilt));
|
||||
plot (handles(3, 3), t, ...
|
||||
plot (handles(3, 3), timeAxis, ...
|
||||
trackResults(channelNr).dllDiscrFilt, 'b');
|
||||
|
||||
grid (handles(3, 3));
|
||||
axis (handles(3, 3), 'tight');
|
||||
xlabel(handles(3, 3), 'Time (s)');
|
||||
xlabel(handles(3, 3), time_label);
|
||||
ylabel(handles(3, 3), 'Amplitude');
|
||||
title (handles(3, 3), 'Filtered DLL discriminator');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user