1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-04-07 19:26:46 +00:00

When using the FPGA, enable automatic selection of the acquisition resampler in the L1/E1 band to apply the lowest possible sample rate during acquisition and automatically manage zero-padding.

This commit is contained in:
Marc Majoral 2025-02-27 13:00:42 +01:00
parent b9fe78cf0a
commit e9c8a027d0
No known key found for this signature in database
GPG Key ID: 936B91D6A360E8BB
18 changed files with 589 additions and 382 deletions

View File

@ -49,7 +49,27 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
out_streams_(out_streams),
acquire_pilot_(configuration->property(role + ".acquire_pilot", false))
{
acq_parameters_.SetFromConfiguration(configuration, role_, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GALILEO_E1_CODE_CHIP_RATE_CPS, GALILEO_E1_B_CODE_LENGTH_CHIPS);
// Set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GALILEO_E1_CODE_CHIP_RATE_CPS, GALILEO_E1_B_CODE_LENGTH_CHIPS);
// Query the capabilities of the instantiated FPGA Acquisition IP Core
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_0, downsampling_filter_specs, max_FFT_size);
// Configure the automatic resampler according to the capabilities of the instantiated FPGA Acquisition IP Core.
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
bool acq_configuration_valid = acq_parameters_.ConfigureAutomaticResampler(downsampling_filter_specs, max_FFT_size, GALILEO_E1_OPT_ACQ_FS_SPS);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the L1/E1 band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_galileo_e1_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
@ -64,10 +84,21 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE1PcpsAmbiguousAcquisitionFpga::generate_galileo_e1_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// 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)
@ -76,7 +107,7 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
volk_gnsssdr::vector<gr_complex> fft_codes_padded(nsamples_total);
d_all_fft_codes_ = volk_gnsssdr::vector<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
float max;
int32_t tmp;
int32_t tmp2;
int32_t local_code;
@ -90,13 +121,13 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
// set local signal generator to Galileo E1 pilot component (1C)
std::array<char, 3> pilot_signal = {{'1', 'C', '\0'}};
galileo_e1_code_gen_complex_sampled(code, pilot_signal,
cboc, PRN, fs_in_, 0, false);
cboc, PRN, acq_parameters_.resampled_fs, 0, false);
}
else
{
std::array<char, 3> data_signal = {{'1', 'B', '\0'}};
galileo_e1_code_gen_complex_sampled(code, data_signal,
cboc, PRN, fs_in_, 0, false);
cboc, PRN, acq_parameters_.resampled_fs, 0, false);
}
if (acq_parameters_.enable_zero_padding)
@ -129,30 +160,17 @@ GalileoE1PcpsAmbiguousAcquisitionFpga::GalileoE1PcpsAmbiguousAcquisitionFpga(
// and package codes in a format that is ready to be written to the FPGA
for (uint32_t i = 0; i < nsamples_total; i++)
{
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_msbits); // put together the real part and the imaginary part
fft_data = local_code & select_all_code_bits;
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_MSBITS); // 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_.data();
DLOG(INFO) << "role " << role_;
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE1PcpsAmbiguousAcquisitionFpga::stop_acquisition()
{
// stop the acquisition and the other FPGA modules.

View File

@ -182,17 +182,15 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t downsampling_factor_default = 4;
static const uint32_t fpga_buff_num = 0; // L1/E1 band
static const uint32_t fpga_blk_exp = 13; // default block exponent
static const uint32_t ACQ_BUFF_0 = 0; // FPGA Acquisition IP buffer containing L1/E1 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 13; // default block exponent
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
// 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.
static const uint32_t quant_bits_local_code = 16;
static const uint32_t select_lsbits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t select_msbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t select_all_code_bits = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t shl_code_bits = 65536; // shift left by 10 bits
void generate_galileo_e1_prn_codes();
pcps_acquisition_fpga_sptr acquisition_fpga_;
volk_gnsssdr::vector<uint32_t> d_all_fft_codes_; // memory that contains all the code ffts
@ -200,7 +198,6 @@ private:
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
int32_t doppler_center_;
uint32_t channel_;
uint32_t doppler_max_;

View File

@ -48,7 +48,27 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(
acq_pilot_(configuration->property(role + ".acquire_pilot", false)),
acq_iq_(configuration->property(role + ".acquire_iq", false))
{
acq_parameters_.SetFromConfiguration(configuration, role_, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GALILEO_E5A_CODE_CHIP_RATE_CPS, GALILEO_E5A_CODE_LENGTH_CHIPS);
// Set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GALILEO_E5A_CODE_CHIP_RATE_CPS, GALILEO_E5A_CODE_LENGTH_CHIPS);
// Query the capabilities of the instantiated FPGA Acquisition IP Core. When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_1, downsampling_filter_specs, max_FFT_size);
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
// Check whether the acquisition configuration is supported by the FPGA.
bool acq_configuration_valid = acq_parameters_.Is_acq_config_valid(max_FFT_size);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the L5/E5a band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_galileo_e5a_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
@ -63,10 +83,21 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE5aPcpsAcquisitionFpga::generate_galileo_e5a_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// 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)
@ -80,7 +111,7 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(
acq_pilot_ = false;
}
float max; // temporary maxima search
float max;
int32_t tmp;
int32_t tmp2;
int32_t local_code;
@ -105,7 +136,7 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(
signal_[1] = 'I';
}
galileo_e5_a_code_gen_complex_sampled(code, PRN, signal_, fs_in_, 0);
galileo_e5_a_code_gen_complex_sampled(code, PRN, signal_, acq_parameters_.fs_in, 0);
if (acq_parameters_.enable_zero_padding)
{
@ -136,30 +167,17 @@ GalileoE5aPcpsAcquisitionFpga::GalileoE5aPcpsAcquisitionFpga(
// and package codes in a format that is ready to be written to the FPGA
for (uint32_t i = 0; i < nsamples_total; i++)
{
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_msbits); // put together the real part and the imaginary part
fft_data = local_code & select_all_code_bits;
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_MSBITS); // 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_.data();
DLOG(INFO) << "role " << role_;
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE5aPcpsAcquisitionFpga::stop_acquisition()
{
// stop the acquisition and the other FPGA modules.

View File

@ -189,17 +189,15 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t downsampling_factor_default = 1;
static const uint32_t fpga_buff_num = 1; // L5/E5a band
static const uint32_t fpga_blk_exp = 13; // default block exponent
static const uint32_t ACQ_BUFF_1 = 1; // FPGA Acquisition IP buffer containing L2 or L5/E5 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 13; // default block exponent
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
// 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.
static const uint32_t quant_bits_local_code = 16;
static const uint32_t select_lsbits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t select_msbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t select_all_code_bits = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t shl_code_bits = 65536; // shift left by 10 bits
void generate_galileo_e5a_prn_codes();
pcps_acquisition_fpga_sptr acquisition_fpga_;
std::weak_ptr<ChannelFsm> channel_fsm_;
@ -207,7 +205,6 @@ private:
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
int32_t doppler_center_;
uint32_t channel_;
uint32_t doppler_max_;

View File

@ -48,7 +48,28 @@ GalileoE5bPcpsAcquisitionFpga::GalileoE5bPcpsAcquisitionFpga(const Configuration
acq_pilot_(configuration->property(role + ".acquire_pilot", false)),
acq_iq_(configuration->property(role + ".acquire_iq", false))
{
acq_parameters_.SetFromConfiguration(configuration, role_, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GALILEO_E5B_CODE_CHIP_RATE_CPS, GALILEO_E5B_CODE_LENGTH_CHIPS);
// Set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GALILEO_E5B_CODE_CHIP_RATE_CPS, GALILEO_E5B_CODE_LENGTH_CHIPS);
// Query the capabilities of the instantiated FPGA Acquisition IP Core. When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_1, downsampling_filter_specs, max_FFT_size);
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
// Check whether the acquisition configuration is supported by the FPGA.
bool acq_configuration_valid = acq_parameters_.Is_acq_config_valid(max_FFT_size);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the E5b band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_galileo_e5b_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
{
@ -62,10 +83,21 @@ GalileoE5bPcpsAcquisitionFpga::GalileoE5bPcpsAcquisitionFpga(const Configuration
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE5bPcpsAcquisitionFpga::generate_galileo_e5b_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// compute all the GALILEO E5b 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)
@ -79,7 +111,7 @@ GalileoE5bPcpsAcquisitionFpga::GalileoE5bPcpsAcquisitionFpga(const Configuration
acq_pilot_ = false;
}
float max; // temporary maxima search
float max;
int32_t tmp;
int32_t tmp2;
int32_t local_code;
@ -104,7 +136,7 @@ GalileoE5bPcpsAcquisitionFpga::GalileoE5bPcpsAcquisitionFpga(const Configuration
signal_[1] = 'I';
}
galileo_e5_b_code_gen_complex_sampled(code, PRN, signal_, fs_in_, 0);
galileo_e5_b_code_gen_complex_sampled(code, PRN, signal_, acq_parameters_.fs_in, 0);
if (acq_parameters_.enable_zero_padding)
{
@ -135,29 +167,17 @@ GalileoE5bPcpsAcquisitionFpga::GalileoE5bPcpsAcquisitionFpga(const Configuration
// and package codes in a format that is ready to be written to the FPGA
for (uint32_t i = 0; i < nsamples_total; i++)
{
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_msbits); // put together the real part and the imaginary part
fft_data = local_code & select_all_code_bits;
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_MSBITS); // 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_.data();
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GalileoE5bPcpsAcquisitionFpga::stop_acquisition()
{
// this command causes the SW to reset the HW.

View File

@ -188,17 +188,15 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t downsampling_factor_default = 1;
static const uint32_t fpga_buff_num = 1; // E5b band
static const uint32_t fpga_blk_exp = 13; // default block exponent
static const uint32_t ACQ_BUFF_1 = 1; // FPGA Acquisition IP buffer containing L2 or L5/E5 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 13; // default block exponent
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
// 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.
static const uint32_t quant_bits_local_code = 16;
static const uint32_t select_lsbits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t select_msbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t select_all_code_bits = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t shl_code_bits = 65536; // shift left by 10 bits
void generate_galileo_e5b_prn_codes();
pcps_acquisition_fpga_sptr acquisition_fpga_;
volk_gnsssdr::vector<uint32_t> d_all_fft_codes_; // memory that contains all the code ffts
@ -207,7 +205,6 @@ private:
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
int32_t doppler_center_;
uint32_t channel_;
uint32_t doppler_max_;

View File

@ -48,10 +48,28 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
in_streams_(in_streams),
out_streams_(out_streams)
{
acq_parameters_.SetFromConfiguration(configuration, role, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GPS_L1_CA_CODE_RATE_CPS, GPS_L1_CA_CODE_LENGTH_CHIPS);
// set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GPS_L1_CA_CODE_RATE_CPS, GPS_L1_CA_CODE_LENGTH_CHIPS);
// Query the capabilities of the instantiated FPGA Acquisition IP Core
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_0, downsampling_filter_specs, max_FFT_size);
// Configure the automatic resampler according to the capabilities of the instantiated FPGA Acquisition IP Core.
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
bool acq_configuration_valid = acq_parameters_.ConfigureAutomaticResampler(downsampling_filter_specs, max_FFT_size, GPS_L1_CA_OPT_ACQ_FS_SPS);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the L1/E1 band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_gps_l1_ca_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
{
@ -65,10 +83,21 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL1CaPcpsAcquisitionFpga::generate_gps_l1_ca_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// 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)
@ -85,7 +114,7 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
// 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
gps_l1_ca_code_gen_complex_sampled(code, PRN, acq_parameters_.resampled_fs, 0); // generate PRN code
if (acq_parameters_.enable_zero_padding)
{
@ -116,30 +145,17 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
// and package codes in a format that is ready to be written to the FPGA
for (uint32_t i = 0; i < nsamples_total; i++)
{
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_msbits); // put together the real part and the imaginary part
fft_data = local_code & select_all_code_bits;
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_MSBITS); // 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
acq_parameters_.all_fft_codes = d_all_fft_codes_.data();
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL1CaPcpsAcquisitionFpga::stop_acquisition()
{
// stop the acquisition and the other FPGA modules.

View File

@ -185,18 +185,16 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t ACQ_BUFF_0 = 0; // FPGA Acquisition IP buffer containing L1/E1 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 10; // default block exponent
static const uint32_t NUM_PRNs = 32;
static const uint32_t downsampling_factor_default = 4;
static const uint32_t fpga_buff_num = 0; // L1/E1 band
static const uint32_t fpga_blk_exp = 10; // default block exponent
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
// 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.
static const uint32_t quant_bits_local_code = 16;
static const uint32_t select_lsbits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t select_msbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t select_all_code_bits = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t shl_code_bits = 65536; // shift left by 10 bits
void generate_gps_l1_ca_prn_codes();
pcps_acquisition_fpga_sptr acquisition_fpga_;
std::weak_ptr<ChannelFsm> channel_fsm_;
@ -204,7 +202,6 @@ private:
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
int32_t doppler_center_;
uint32_t channel_;
uint32_t doppler_max_;

View File

@ -48,9 +48,27 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
in_streams_(in_streams),
out_streams_(out_streams)
{
acq_parameters_.SetFromConfiguration(configuration, role, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GPS_L2_M_CODE_RATE_CPS, GPS_L2_M_CODE_LENGTH_CHIPS);
// Set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GPS_L2_M_CODE_RATE_CPS, GPS_L2_M_CODE_LENGTH_CHIPS);
LOG(INFO) << "role " << role;
// Query the capabilities of the instantiated FPGA Acquisition IP Core. When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_1, downsampling_filter_specs, max_FFT_size);
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
// Check whether the acquisition configuration is supported by the FPGA.
bool acq_configuration_valid = acq_parameters_.Is_acq_config_valid(max_FFT_size);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the L2 band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_gps_l2c_m_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
@ -65,10 +83,21 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL2MPcpsAcquisitionFpga::generate_gps_l2c_m_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// compute all the GPS L2C 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)
@ -78,7 +107,7 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
volk_gnsssdr::vector<std::complex<float>> fft_codes_padded(nsamples_total);
d_all_fft_codes_ = volk_gnsssdr::vector<uint32_t>(nsamples_total * NUM_PRNs); // memory containing all the possible fft codes for PRN 0 to 32
float max; // temporary maxima search
float max;
int32_t tmp;
int32_t tmp2;
int32_t local_code;
@ -86,7 +115,7 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
for (unsigned int PRN = 1; PRN <= NUM_PRNs; PRN++)
{
gps_l2c_m_code_gen_complex_sampled(code, PRN, fs_in_);
gps_l2c_m_code_gen_complex_sampled(code, PRN, acq_parameters_.fs_in);
if (acq_parameters_.enable_zero_padding)
{
@ -118,7 +147,7 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
{
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
local_code = (tmp & SELECT_LSBITS) | ((tmp2 * SHL_CODE_BITS) & SELECT_MSBITS); // 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;
@ -128,20 +157,8 @@ GpsL2MPcpsAcquisitionFpga::GpsL2MPcpsAcquisitionFpga(
}
acq_parameters_.all_fft_codes = d_all_fft_codes_.data();
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL2MPcpsAcquisitionFpga::stop_acquisition()
{
// stop the acquisition and the other FPGA modules.

View File

@ -150,24 +150,23 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t downsampling_factor_default = 1;
static const uint32_t fpga_buff_num = 0; // L2 band
static const uint32_t fpga_blk_exp = 13; // default block exponent
static const uint32_t ACQ_BUFF_1 = 1; // FPGA Acquisition IP buffer containing L2 or L5/E5 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 13; // default block exponent
static const uint32_t NUM_PRNs = 32;
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
void generate_gps_l2c_m_prn_codes();
pcps_acquisition_fpga_sptr acquisition_fpga_;
volk_gnsssdr::vector<uint32_t> d_all_fft_codes_; // memory that contains all the code ffts
std::weak_ptr<ChannelFsm> channel_fsm_;
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
float threshold_;
unsigned int channel_;
unsigned int doppler_max_;

View File

@ -49,9 +49,27 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
in_streams_(in_streams),
out_streams_(out_streams)
{
acq_parameters_.SetFromConfiguration(configuration, role, fpga_buff_num, fpga_blk_exp, downsampling_factor_default, GPS_L5I_CODE_RATE_CPS, GPS_L5I_CODE_LENGTH_CHIPS);
// Set acquisition parameters
acq_parameters_.SetFromConfiguration(configuration, role_, DEFAULT_FPGA_BLK_EXP, GPS_L5I_CODE_RATE_CPS, GPS_L5I_CODE_LENGTH_CHIPS);
LOG(INFO) << "role " << role;
// Query the capabilities of the instantiated FPGA Acquisition IP Core. When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs;
uint32_t max_FFT_size;
acquisition_fpga_ = pcps_make_acquisition_fpga(&acq_parameters_, ACQ_BUFF_1, downsampling_filter_specs, max_FFT_size);
// When the FPGA is in use, the acquisition resampler operates only in the L1/E1 frequency band.
// Check whether the acquisition configuration is supported by the FPGA.
bool acq_configuration_valid = acq_parameters_.Is_acq_config_valid(max_FFT_size);
if (!acq_configuration_valid)
{
std::cout << "The FPGA does not support the required sampling frequency of " << acq_parameters_.fs_in << " SPS for the L5/E5a band. Please update the sampling frequency in the configuration file." << std::endl;
exit(1);
}
DLOG(INFO) << "role " << role;
generate_gps_l5i_prn_codes();
#if USE_GLOG_AND_GFLAGS
if (FLAGS_doppler_max != 0)
@ -66,10 +84,21 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
#endif
doppler_max_ = acq_parameters_.doppler_max;
doppler_step_ = static_cast<unsigned int>(acq_parameters_.doppler_step);
fs_in_ = acq_parameters_.fs_in;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL5iPcpsAcquisitionFpga::generate_gps_l5i_prn_codes()
{
uint32_t code_length = acq_parameters_.code_length;
uint32_t nsamples_total = acq_parameters_.samples_per_code;
uint32_t nsamples_total = acq_parameters_.fft_size;
// 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)
@ -78,7 +107,7 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
volk_gnsssdr::vector<std::complex<float>> fft_codes_padded(nsamples_total);
d_all_fft_codes_ = volk_gnsssdr::vector<uint32_t>(nsamples_total * NUM_PRNs); // memory containing all the possible fft codes for PRN 0 to 32
float max; // temporary maxima search
float max;
int32_t tmp;
int32_t tmp2;
int32_t local_code;
@ -86,7 +115,7 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
for (uint32_t PRN = 1; PRN <= NUM_PRNs; PRN++)
{
gps_l5i_code_gen_complex_sampled(code, PRN, fs_in_);
gps_l5i_code_gen_complex_sampled(code, PRN, acq_parameters_.fs_in);
if (acq_parameters_.enable_zero_padding)
{
@ -117,29 +146,17 @@ GpsL5iPcpsAcquisitionFpga::GpsL5iPcpsAcquisitionFpga(
// and package codes in a format that is ready to be written to the FPGA
for (uint32_t i = 0; i < nsamples_total; i++)
{
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_msbits); // put together the real part and the imaginary part
fft_data = local_code & select_all_code_bits;
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_MSBITS); // 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_.data();
acquisition_fpga_ = pcps_make_acquisition_fpga(acq_parameters_);
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
}
if (out_streams_ > 0)
{
LOG(ERROR) << "This implementation does not provide an output stream";
}
}
void GpsL5iPcpsAcquisitionFpga::stop_acquisition()
{
// stop the acquisition and the other FPGA modules.

View File

@ -185,19 +185,16 @@ public:
void set_resampler_latency(uint32_t latency_samples __attribute__((unused))) override {};
private:
static const uint32_t ACQ_BUFF_1 = 1; // FPGA Acquisition IP buffer containing L2 or L5/E5 frequency band samples by default.
static const uint32_t DEFAULT_FPGA_BLK_EXP = 13; // default block exponent
static const uint32_t NUM_PRNs = 32;
static const uint32_t downsampling_factor_default = 1;
static const uint32_t fpga_buff_num = 1; // L5/E5a band
static const uint32_t fpga_blk_exp = 13; // default block exponent
// 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.
static const uint32_t quant_bits_local_code = 16;
static const uint32_t select_lsbits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t select_msbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t select_all_code_bits = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t shl_code_bits = 65536; // shift left by 10 bits
static const uint32_t QUANT_BITS_LOCAL_CODE = 16;
static const uint32_t SELECT_LSBITS = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBITS = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
void generate_gps_l5i_prn_codes();
float calculate_threshold(float pfa);
pcps_acquisition_fpga_sptr acquisition_fpga_;
@ -206,7 +203,6 @@ private:
Gnss_Synchro* gnss_synchro_;
Acq_Conf_Fpga acq_parameters_;
std::string role_;
int64_t fs_in_;
int32_t doppler_center_;
uint32_t channel_;
uint32_t doppler_max_;

View File

@ -32,13 +32,13 @@
#include <absl/log/log.h>
#endif
pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga& conf_)
pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga *conf, uint32_t acq_buff_num, std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs, uint32_t &max_FFT_size)
{
return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(conf_));
return pcps_acquisition_fpga_sptr(new pcps_acquisition_fpga(conf, acq_buff_num, downsampling_filter_specs, max_FFT_size));
}
pcps_acquisition_fpga::pcps_acquisition_fpga(Acq_Conf_Fpga& conf_)
pcps_acquisition_fpga::pcps_acquisition_fpga(Acq_Conf_Fpga *conf_, uint32_t acq_buff_num, std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs, uint32_t &max_FFT_size)
: d_acq_parameters(conf_),
d_gnss_synchro(nullptr),
d_sample_counter(0ULL),
@ -46,37 +46,34 @@ pcps_acquisition_fpga::pcps_acquisition_fpga(Acq_Conf_Fpga& conf_)
d_mag(0),
d_input_power(0.0),
d_test_statistics(0.0),
d_doppler_step2(d_acq_parameters.doppler_step2),
d_doppler_step2(d_acq_parameters->doppler_step2),
d_doppler_center_step_two(0.0),
d_doppler_center(0U),
d_state(0),
d_doppler_index(0U),
d_channel(0U),
d_doppler_step(0U),
d_doppler_max(d_acq_parameters.doppler_max),
d_fft_size(d_acq_parameters.samples_per_code),
d_doppler_max(d_acq_parameters->doppler_max),
d_num_doppler_bins(0U),
d_downsampling_factor(d_acq_parameters.downsampling_factor),
d_select_queue_Fpga(d_acq_parameters.select_queue_Fpga),
d_total_block_exp(d_acq_parameters.total_block_exp),
d_num_doppler_bins_step2(d_acq_parameters.num_doppler_bins_step2),
d_max_num_acqs(d_acq_parameters.max_num_acqs),
d_total_block_exp(d_acq_parameters->total_block_exp),
d_num_doppler_bins_step2(d_acq_parameters->num_doppler_bins_step2),
d_max_num_acqs(d_acq_parameters->max_num_acqs),
d_active(false),
d_make_2_steps(d_acq_parameters.make_2_steps)
d_make_2_steps(d_acq_parameters->make_2_steps)
{
d_acquisition_fpga = std::make_unique<Fpga_Acquisition>(d_acq_parameters.device_name, d_acq_parameters.code_length, d_acq_parameters.doppler_max, d_fft_size,
d_acq_parameters.fs_in, d_acq_parameters.select_queue_Fpga, d_acq_parameters.all_fft_codes, d_acq_parameters.excludelimit);
d_acquisition_fpga = std::make_unique<Fpga_Acquisition>(d_acq_parameters->device_name, acq_buff_num,
downsampling_filter_specs, max_FFT_size);
}
void pcps_acquisition_fpga::set_local_code()
{
d_acquisition_fpga->set_local_code(d_gnss_synchro->PRN);
}
void pcps_acquisition_fpga::init()
{
d_acquisition_fpga->init(d_acq_parameters->code_length, d_doppler_max, d_acq_parameters->fft_size,
d_acq_parameters->resampled_fs, d_acq_parameters->downsampling_filter_num, d_acq_parameters->excludelimit, d_acq_parameters->all_fft_codes);
d_gnss_synchro->Flag_valid_acquisition = false;
d_gnss_synchro->Flag_valid_symbol_output = false;
d_gnss_synchro->Flag_valid_pseudorange = false;
@ -90,7 +87,6 @@ void pcps_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;
}
void pcps_acquisition_fpga::set_state(int32_t state)
{
d_state = state;
@ -147,7 +143,7 @@ void pcps_acquisition_fpga::send_negative_acquisition()
<< ", magnitude " << d_mag
<< ", input signal power " << d_input_power;
if (d_acq_parameters.repeat_satellite == true)
if (d_acq_parameters->repeat_satellite == true)
{
d_channel_fsm.lock()->Event_failed_acquisition_repeat();
}
@ -164,14 +160,13 @@ void pcps_acquisition_fpga::acquisition_core(uint32_t num_doppler_bins, uint32_t
float firstpeak = 0.0;
float secondpeak = 0.0;
uint32_t total_block_exp;
uint64_t initial_sample;
d_acquisition_fpga->set_doppler_sweep(num_doppler_bins, doppler_step, doppler_min);
d_acquisition_fpga->run_acquisition();
d_acquisition_fpga->read_acquisition_results(&indext,
&firstpeak,
&secondpeak,
&initial_sample,
&d_sample_counter,
&d_input_power,
&d_doppler_index,
&total_block_exp);
@ -197,26 +192,8 @@ void pcps_acquisition_fpga::acquisition_core(uint32_t num_doppler_bins, uint32_t
}
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler);
d_sample_counter = initial_sample;
if (d_select_queue_Fpga == 0)
{
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 * 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
{
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
}
}
else
{
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
}
d_gnss_synchro->Acq_delay_samples = static_cast<double>(indext);
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
}

View File

@ -32,7 +32,8 @@
#include <cstdint> // for uint32_t
#include <memory> // for shared_ptr
#include <string> // for string
#include <utility> // for move
#include <utility> // for for std::move, std::pair
#include <vector> // for std::vector
/** \addtogroup Acquisition
* \{ */
@ -46,7 +47,7 @@ class pcps_acquisition_fpga;
using pcps_acquisition_fpga_sptr = std::shared_ptr<pcps_acquisition_fpga>;
pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga& conf_);
pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga* conf_, uint32_t acq_buff_num, std::vector<std::pair<uint32_t, uint32_t>>& downsampling_filter_specs, uint32_t& max_FFT_size);
/*!
* \brief This class implements a Parallel Code Phase Search Acquisition that uses the FPGA.
@ -168,8 +169,8 @@ public:
void stop_acquisition();
private:
friend pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga& conf_);
explicit pcps_acquisition_fpga(Acq_Conf_Fpga& conf_);
friend pcps_acquisition_fpga_sptr pcps_make_acquisition_fpga(Acq_Conf_Fpga* conf, uint32_t acq_buff_num, std::vector<std::pair<uint32_t, uint32_t>>& downsampling_filter_specs, uint32_t& max_FFT_size);
explicit pcps_acquisition_fpga(Acq_Conf_Fpga* conf, uint32_t acq_buff_num, std::vector<std::pair<uint32_t, uint32_t>>& downsampling_filter_specs, uint32_t& max_FFT_size);
void send_negative_acquisition();
void send_positive_acquisition();
@ -179,7 +180,7 @@ private:
std::shared_ptr<Fpga_Acquisition> d_acquisition_fpga;
std::weak_ptr<ChannelFsm> d_channel_fsm;
Acq_Conf_Fpga d_acq_parameters;
Acq_Conf_Fpga* d_acq_parameters;
Gnss_Synchro* d_gnss_synchro;
@ -199,10 +200,7 @@ private:
uint32_t d_channel;
uint32_t d_doppler_step;
uint32_t d_doppler_max;
uint32_t d_fft_size;
uint32_t d_num_doppler_bins;
uint32_t d_downsampling_factor;
uint32_t d_select_queue_Fpga;
uint32_t d_total_block_exp;
uint32_t d_num_doppler_bins_step2;
uint32_t d_max_num_acqs;

View File

@ -29,37 +29,47 @@
#endif
void Acq_Conf_Fpga::SetFromConfiguration(const ConfigurationInterface *configuration,
const std::string &role, uint32_t sel_queue_fpga, uint32_t blk_exp, uint32_t downsampling_factor_default, double chip_rate, double code_length_chips)
const std::string &role, uint32_t blk_exp, double code_chips_per_sec, double num_chips_per_code)
{
// sampling frequency
const int64_t fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", fs_in);
fs_in = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
// resampling frequency
resampled_fs = fs_in;
// max doppler
doppler_max = configuration->property(role + ".doppler_max", doppler_max);
// downsampling factor
downsampling_factor = configuration->property(role + ".downsampling_factor", downsampling_factor_default);
// code chips per second
code_rate_cps = code_chips_per_sec;
fs_in = fs_in / downsampling_factor;
// code length chips
code_length_chips = num_chips_per_code;
// code length in samples
code_length = static_cast<uint32_t>(std::round(static_cast<double>(fs_in) / (chip_rate / code_length_chips)));
code_length = static_cast<uint32_t>(std::round(static_cast<double>(fs_in) / (code_rate_cps / code_length_chips)));
enable_zero_padding = configuration->property(role + ".enable_zero_padding", true);
// zero padding
if (((code_length & (code_length - 1)) != 0))
{
// If the code length (in samples) is not a power of two, zero padding is required.
enable_zero_padding = true;
}
// The FPGA can only use FFT lengths that are a power of two.
float factor = enable_zero_padding ? 2.0F : 1.0F;
samples_per_code = pow(2, ceilf(log2f(static_cast<float>(code_length) * factor)));
// FFT length
float zero_padding_adjustment = enable_zero_padding ? 2.0F : 1.0F;
fft_size = pow(2, ceilf(log2f(static_cast<float>(code_length) * zero_padding_adjustment)));
// Exclude limit value for the second maxima search
excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / code_rate_cps) * static_cast<float>(resampled_fs)));
// repeat satellite
repeat_satellite = configuration->property(role + ".repeat_satellite", false);
// FPGA buffer number
select_queue_Fpga = configuration->property(role + ".select_queue_Fpga", sel_queue_fpga);
// UIO device file
std::string device_io_name;
// find the uio device file corresponding to the acquisition
if (find_uio_dev_file_name(device_io_name, acquisition_device_name, 0) < 0)
{
@ -68,10 +78,7 @@ void Acq_Conf_Fpga::SetFromConfiguration(const ConfigurationInterface *configura
}
device_name = std::move(device_io_name);
// exclusion limit
excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / chip_rate) * static_cast<float>(fs_in)));
// acquisition step 2 parameters
// parameters for the second acquisition step
num_doppler_bins_step2 = configuration->property(role + ".second_nbins", num_doppler_bins_step2);
doppler_step2 = configuration->property(role + ".second_doppler_step", doppler_step2);
doppler_step = configuration->property(role + ".doppler_step", doppler_step);
@ -81,3 +88,61 @@ void Acq_Conf_Fpga::SetFromConfiguration(const ConfigurationInterface *configura
// reference for the FPGA FFT-IFFT attenuation factor
total_block_exp = configuration->property(role + ".total_block_exp", blk_exp);
}
bool Acq_Conf_Fpga::ConfigureAutomaticResampler(std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs, uint32_t max_FFT_size, double opt_freq)
{
bool acq_configuration_valid = false;
uint32_t optimal_downsampling_factor = fs_in / opt_freq;
if (optimal_downsampling_factor > 1)
{
for (auto it = downsampling_filter_specs.begin(); it != downsampling_filter_specs.end(); ++it)
{
uint32_t dec_factor = it->first;
uint32_t filter_delay = it->second;
// Select the FPGA-supported downsampling factor that is the closest to, but smaller than, the target downsampling factor
if (optimal_downsampling_factor >= dec_factor)
{
// check if the required FFT size is supported in the FPGA
uint32_t fft_size_downsampled = (fft_size / dec_factor);
if (fft_size_downsampled <= max_FFT_size)
{
downsampling_filter_num++;
downsampling_factor = dec_factor;
downsampling_filter_delay = filter_delay;
// update the resampling frequency, the code length, the FFT size, and the exclude limit parameter taking into account the downsampling factor
resampled_fs = fs_in / downsampling_factor;
code_length = static_cast<uint32_t>(std::round(static_cast<double>(resampled_fs) / (code_rate_cps / code_length_chips)));
float zero_padding_adjustment = enable_zero_padding ? 2.0F : 1.0F;
fft_size = pow(2, ceilf(log2f(static_cast<float>(code_length) * zero_padding_adjustment)));
excludelimit = static_cast<unsigned int>(1 + ceil((1.0 / code_rate_cps) * static_cast<float>(resampled_fs)));
acq_configuration_valid = true;
}
break;
}
}
}
else
{
// the buffer containing L2 or L5/E5a frequency band samples by default does not implement a downsampling filter
if (fft_size <= max_FFT_size)
{
acq_configuration_valid = true;
}
}
return acq_configuration_valid;
}
bool Acq_Conf_Fpga::Is_acq_config_valid(uint32_t max_FFT_size)
{
if (fft_size <= max_FFT_size)
{
return true;
}
else
{
return false;
}
}

View File

@ -22,6 +22,8 @@
#include <gnuradio/gr_complex.h>
#include <cstdint>
#include <string>
#include <utility> // for std::move, std::pair
#include <vector> // for std::vector
/** \addtogroup Acquisition
* \{ */
@ -35,29 +37,33 @@ class Acq_Conf_Fpga
public:
Acq_Conf_Fpga() = default;
void SetFromConfiguration(const ConfigurationInterface *configuration, const std::string &role, uint32_t sel_queue_fpga, uint32_t blk_exp, uint32_t downsampling_factor_default, double chip_rate, double code_length_chips);
void SetFromConfiguration(const ConfigurationInterface *configuration, const std::string &role, uint32_t blk_exp, double code_chips_per_sec, double num_chips_per_code);
bool ConfigureAutomaticResampler(std::vector<std::pair<uint32_t, uint32_t>> downsampling_filter_specs, uint32_t max_FFT_size, double opt_freq);
bool Is_acq_config_valid(uint32_t max_FFT_size);
/* PCPS Acquisition configuration */
std::string device_name = "uio0";
uint32_t *all_fft_codes = NULL; // pointer to memory that contains all the code ffts
double code_rate_cps;
double code_length_chips;
int64_t fs_in{4000000LL};
int64_t resampled_fs{4000000LL};
float doppler_step{250.0};
float doppler_step2{125.0};
uint32_t num_doppler_bins_step2{4U};
int32_t doppler_max{5000};
uint32_t select_queue_Fpga{0U};
uint32_t downsampling_factor{4U};
uint32_t downsampling_filter_num{0U};
uint32_t downsampling_factor{1U};
uint32_t downsampling_filter_delay{0U};
uint32_t total_block_exp{13U};
uint32_t excludelimit{5U};
uint32_t max_num_acqs{2U};
uint32_t samples_per_code{1U};
uint32_t fft_size{1U};
uint32_t code_length{16000U};
bool make_2_steps{false};
bool enable_zero_padding{true};
bool enable_zero_padding{false};
bool repeat_satellite{false};
private:

View File

@ -26,7 +26,6 @@
#include <iostream> // for operator<<
#include <sys/mman.h> // libraries used by the GIPO
#include <unistd.h> // for write, close, read, ssize_t
#include <utility> // for move
#if USE_GLOG_AND_GFLAGS
#include <glog/logging.h>
@ -47,36 +46,51 @@
})
#endif
Fpga_Acquisition::Fpga_Acquisition(std::string device_name,
uint32_t nsamples,
uint32_t doppler_max,
uint32_t nsamples_total,
int64_t fs_in,
uint32_t select_queue,
uint32_t *all_fft_codes,
uint32_t excludelimit) : d_device_name(std::move(device_name)),
d_fs_in(fs_in),
d_fd(0), // driver descriptor
d_map_base(nullptr), // driver memory map
d_all_fft_codes(all_fft_codes),
d_vector_length(nsamples_total),
d_excludelimit(excludelimit),
d_nsamples_total(nsamples_total),
d_nsamples(nsamples), // number of samples not including padding
d_select_queue(select_queue),
d_doppler_max(doppler_max),
d_doppler_step(0),
d_PRN(0)
std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs,
uint32_t &max_FFT_size) : d_device_name(device_name),
d_resampled_fs(0),
d_map_base(nullptr), // driver memory map
d_all_fft_codes(nullptr),
d_fd(0), // driver descriptor
d_fft_size(0),
d_excludelimit(0),
d_nsamples(0), // number of samples not including padding
d_filter_num(0),
d_downsampling_factor(1),
d_downsampling_filter_delay(0),
d_select_queue(select_queue),
d_doppler_max(0),
d_doppler_step(0),
d_PRN(0),
d_IP_core_version(0)
{
Fpga_Acquisition::open_device();
Fpga_Acquisition::reset_acquisition();
Fpga_Acquisition::fpga_acquisition_test_register();
Fpga_Acquisition::read_ipcore_info(downsampling_filter_specs, max_FFT_size);
Fpga_Acquisition::close_device();
DLOG(INFO) << "Acquisition FPGA class created";
}
void Fpga_Acquisition::init(uint32_t nsamples, uint32_t doppler_max, uint32_t fft_size,
int64_t resampled_fs, uint32_t downsampling_filter_num, uint32_t excludelimit, uint32_t *all_fft_codes)
{
d_resampled_fs = resampled_fs;
d_all_fft_codes = all_fft_codes;
d_fft_size = fft_size;
d_excludelimit = excludelimit;
d_nsamples = nsamples;
d_filter_num = downsampling_filter_num;
if (d_filter_num > 0)
{
d_downsampling_factor = d_downsampling_filter_specs[d_filter_num - 1].first;
d_downsampling_filter_delay = d_downsampling_filter_specs[d_filter_num - 1].second;
}
d_doppler_max = doppler_max;
}
bool Fpga_Acquisition::set_local_code(uint32_t PRN)
{
@ -88,11 +102,11 @@ bool Fpga_Acquisition::set_local_code(uint32_t PRN)
void Fpga_Acquisition::write_local_code()
{
d_map_base[9] = LOCAL_CODE_CLEAR_MEM;
d_map_base[CLEAR_MEM_REG_ADDR] = LOCAL_CODE_CLEAR_MEM;
// write local code
for (uint32_t k = 0; k < d_vector_length; k++)
for (uint32_t k = 0; k < d_fft_size; k++)
{
d_map_base[6] = d_all_fft_codes[d_nsamples_total * (d_PRN - 1) + k];
d_map_base[PROG_MEM_ADDR] = d_all_fft_codes[d_fft_size * (d_PRN - 1) + k];
}
}
@ -118,15 +132,12 @@ void Fpga_Acquisition::open_device()
void Fpga_Acquisition::fpga_acquisition_test_register()
{
// sanity check : check test register
const uint32_t writeval = TEST_REG_SANITY_CHECK;
// write value to test register
d_map_base[15] = writeval;
d_map_base[TEST_REG_ADDR] = TEST_REG_SANITY_CHECK;
// read value from test register
const uint32_t readval = d_map_base[15];
const uint32_t readval = d_map_base[TEST_REG_ADDR];
if (writeval != readval)
if (readval != TEST_REG_SANITY_CHECK)
{
LOG(WARNING) << "Acquisition test register sanity check failed";
}
@ -136,6 +147,50 @@ void Fpga_Acquisition::fpga_acquisition_test_register()
}
}
void Fpga_Acquisition::read_ipcore_info(std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs, uint32_t &max_FFT_size)
{
d_IP_core_version = d_map_base[FPGA_IP_CORE_VERSION_REG_ADDR];
if (d_IP_core_version == FPGA_ACQ_IP_VERSION_1)
{
// FPGA acquisition IP core version FPGA_ACQ_IP_VERSION_1
max_FFT_size = d_map_base[MAX_FFT_SIZE_REG_ADDR];
if (d_select_queue == ACQ_BUFF_0)
{
// Check if the requested downsampling filter is available on the FPGA and read its implemented latency.
uint32_t downsampling_filter_dec_factors = d_map_base[DOWNSAMPLING_FILTER_DEC_FACTORS_REG_ADDR];
uint32_t downsampling_filter_latencies = d_map_base[DOWNSAMPLING_FILTER_LATENCIES_REG_ADDR];
for (uint32_t filt_num = 1; filt_num <= MAX_FILTERS_AVAILABLE; filt_num++)
{
// The information about the instantiated downsampling filters in the FPGA is ordered such that the largest downsampling factor is stored in the least significant bits (LSBs), while the smallest downsampling factor is stored in the most significant bits (MSBs).
uint32_t dec_factor = downsampling_filter_dec_factors & BIT_MASK_4;
downsampling_filter_dec_factors = downsampling_filter_dec_factors >> RSHIFT_4_BITS;
uint32_t filter_latency = downsampling_filter_latencies & BIT_MASK_8;
downsampling_filter_latencies = downsampling_filter_latencies >> RSHIFT_8_BITS;
if (dec_factor != 0)
{
downsampling_filter_specs.emplace_back(dec_factor, filter_latency);
}
else
{
break;
}
}
}
}
else
{
// FPGA Acquisition IP core versions earlier than FPGA_ACQ_IP_VERSION_1
max_FFT_size = DEFAULT_MAX_FFT_SIZE;
if (d_select_queue == ACQ_BUFF_0)
{
// An acquisition resampler with a downsampling factor of DEFAULT_DOWNSAMPLING_FACTOR is implemented in the L1/E1 frequency band
downsampling_filter_specs.emplace_back(DEFAULT_DOWNSAMPLING_FACTOR, DEFAULT_DOWNSAMPLING_FILTER_DELAY);
}
}
d_downsampling_filter_specs = downsampling_filter_specs;
}
void Fpga_Acquisition::run_acquisition()
{
@ -149,7 +204,7 @@ void Fpga_Acquisition::run_acquisition()
}
// launch the acquisition process
d_map_base[8] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process
d_map_base[ACQ_COMMAND_FLAGS_REG_ADDR] = LAUNCH_ACQUISITION; // writing a 1 to reg 8 launches the acquisition process
int32_t irq_count;
// wait for interrupt
@ -164,7 +219,7 @@ void Fpga_Acquisition::run_acquisition()
void Fpga_Acquisition::set_block_exp(uint32_t total_block_exp)
{
d_map_base[11] = total_block_exp;
d_map_base[MAX_FFT_SCALING_FACTOR_REG_ADDR] = total_block_exp;
}
@ -172,59 +227,47 @@ void Fpga_Acquisition::set_doppler_sweep(uint32_t num_sweeps, uint32_t doppler_s
{
// 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)
float phase_step_rad_real = 2.0F * (doppler_min) / static_cast<float>(d_fs_in);
auto phase_step_rad_int = static_cast<int32_t>(phase_step_rad_real * (POW_2_31));
d_map_base[3] = phase_step_rad_int;
float phase_step_rad_real = 2.0F * (doppler_min) / static_cast<float>(d_resampled_fs);
d_map_base[DOPPLER_MIN_REG_ADDR] = static_cast<int32_t>(phase_step_rad_real * (POW_2_31));
// repeat the calculation with the doppler step
phase_step_rad_real = 2.0F * (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;
phase_step_rad_real = 2.0F * (doppler_step) / static_cast<float>(d_resampled_fs);
d_map_base[DOPPLER_STEP_REG_ADDR] = 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
// write number of doppler sweeps
d_map_base[5] = num_sweeps;
d_map_base[NUM_DOPPLER_SEARCH_STEPS_REG_ADDR] = num_sweeps;
}
void Fpga_Acquisition::configure_acquisition()
{
// Fpga_Acquisition::();
d_map_base[0] = d_select_queue;
d_map_base[1] = d_vector_length;
d_map_base[2] = d_nsamples;
d_map_base[7] = static_cast<int32_t>(std::log2(static_cast<float>(d_vector_length))); // log2 FFTlength
d_map_base[12] = d_excludelimit;
d_map_base[FREQ_BAND_DOWNSAMPLE_REG_ADDR] = d_select_queue | (d_filter_num << 4);
d_map_base[FFT_LENGTH_REG_ADDR] = d_fft_size;
d_map_base[CORR_NSAMPLES_REG_ADDR] = d_nsamples;
d_map_base[LOG2_FFT_LENGTH_REG_ADDR] = static_cast<int32_t>(std::log2(static_cast<float>(d_fft_size))); // log2 FFTlength
d_map_base[EXCL_LIM_REG_ADDR] = d_excludelimit;
}
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)
{
uint32_t readval = d_map_base[1]; // read sample counter (LSW)
auto initial_sample_tmp = static_cast<uint64_t>(readval);
uint64_t readval_long = d_map_base[2]; // read sample counter (MSW)
uint64_t readval_long_shifted = readval_long << 32; // 2^32
initial_sample_tmp += readval_long_shifted; // 2^32
uint64_t initial_sample_tmp = (static_cast<uint64_t>(d_map_base[SAMPLESTAMP_MSW_REG_ADDR]) << 32) + (static_cast<uint64_t>(d_map_base[SAMPLESTAMP_LSW_REG_ADDR]));
uint32_t max_index_tmp = d_map_base[ACQ_DELAY_SAMPLES_REG_ADDR]; // read max index position
if (d_downsampling_factor > 1)
{
initial_sample_tmp *= static_cast<uint64_t>(d_downsampling_factor); // take into account the downsampling factor for the sample stamp
initial_sample_tmp -= static_cast<uint64_t>(d_downsampling_filter_delay); // take into account the downsampling filter delay
max_index_tmp *= d_downsampling_factor; // take into account the downsampling factor for the acq. delay
}
*initial_sample = initial_sample_tmp;
readval = d_map_base[3]; // read first peak value
*firstpeak = static_cast<float>(readval);
readval = d_map_base[4]; // read second peak value
*secondpeak = static_cast<float>(readval);
readval = d_map_base[5]; // read max index position
*max_index = readval;
*power_sum = 0; // power sum is not used
readval = d_map_base[7]; // read doppler index -- this read releases the interrupt line
*doppler_index = readval;
readval = d_map_base[8]; // read FFT block exponent
*total_blk_exp = readval;
*max_index = max_index_tmp;
*firstpeak = d_map_base[MAG_SQ_FIRST_PEAK_REG_ADDR]; // read first peak value
*secondpeak = d_map_base[MAG_SQ_SECOND_PEAK_REG_ADDR]; // read second peak value
*power_sum = 0; // The FPGA does not currently support power sum.
*doppler_index = d_map_base[DOPPLER_INDEX_REG_ADDR]; // read doppler index -- this read releases the interrupt line
*total_blk_exp = d_map_base[FFT_SCALING_FACTOR_REG_ADDR]; // read FFT block exponent
}
@ -241,30 +284,13 @@ void Fpga_Acquisition::close_device()
void Fpga_Acquisition::reset_acquisition()
{
d_map_base[8] = RESET_ACQUISITION; // setting bit 2 of d_map_base[8] resets the acquisition. This causes a reset of all
// the FPGA HW modules including the multicorrelators
d_map_base[ACQ_COMMAND_FLAGS_REG_ADDR] = RESET_ACQUISITION; // setting bit 2 resets the acquisition. This causes a reset of all
// the FPGA HW modules including the multicorrelators
}
void Fpga_Acquisition::stop_acquisition()
{
d_map_base[8] = STOP_ACQUISITION; // setting bit 3 of d_map_base[8] stops the acquisition module. This stops all
// the FPGA HW modules including the multicorrelators
}
// this function is only used for the unit tests
void Fpga_Acquisition::read_fpga_total_scale_factor(uint32_t *total_scale_factor, uint32_t *fw_scale_factor)
{
uint32_t readval = d_map_base[8];
*total_scale_factor = readval;
// only the total scale factor is used for the tests (fw scale factor to be removed)
*fw_scale_factor = 0;
}
void Fpga_Acquisition::read_result_valid(uint32_t *result_valid)
{
uint32_t readval = d_map_base[0];
*result_valid = readval;
d_map_base[ACQ_COMMAND_FLAGS_REG_ADDR] = STOP_ACQUISITION; // setting bit 3 stops the acquisition module. This stops all
// the FPGA HW modules including the multicorrelators
}

View File

@ -24,6 +24,8 @@
#include <cstdint>
#include <string>
#include <utility> // for std::move, std::pair
#include <vector> // for std::vector
/** \addtogroup Acquisition
* \{ */
@ -42,19 +44,22 @@ public:
*/
Fpga_Acquisition(
std::string device_name,
uint32_t nsamples,
uint32_t doppler_max,
uint32_t nsamples_total,
int64_t fs_in,
uint32_t select_queue,
uint32_t *all_fft_codes,
uint32_t excludelimit);
std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs,
uint32_t &max_FFT_size);
/*!
* \brief Destructor
*/
~Fpga_Acquisition() = default;
/*!
* \brief Initialize acquisition parameters
*/
// void init(uint32_t samples_per_code, uint32_t code_length, int64_t resampled_fs, uint32_t *all_fft_codes);
void init(uint32_t nsamples, uint32_t doppler_max, uint32_t d_fft_size,
int64_t resampled_fs, uint32_t downsampling_filter_num, uint32_t excludelimit, uint32_t *all_fft_codes);
/*!
* \brief Select the code with the chosen PRN
*/
@ -110,11 +115,6 @@ public:
*/
void stop_acquisition();
/*!
* \brief Read the scaling factor that has been used by the FFT-IFFT
*/
void read_fpga_total_scale_factor(uint32_t *total_scale_factor, uint32_t *fw_scale_factor);
/*!
* \brief Set the block exponent of the FFT in the FPGA.
*/
@ -141,6 +141,42 @@ public:
void close_device();
private:
// FPGA IP Core version
static const uint32_t FPGA_ACQ_IP_VERSION_1 = 0x0001; // FPGA IP core version
// FPGA register addresses
// write-only registers
static const uint32_t FREQ_BAND_DOWNSAMPLE_REG_ADDR = 0; // Select frequency band and downsampling filter
static const uint32_t FFT_LENGTH_REG_ADDR = 1; // Length of the FFT
static const uint32_t CORR_NSAMPLES_REG_ADDR = 2; // Correlation length
static const uint32_t DOPPLER_MIN_REG_ADDR = 3; // Doppler min
static const uint32_t DOPPLER_STEP_REG_ADDR = 4; // Doppler step
static const uint32_t NUM_DOPPLER_SEARCH_STEPS_REG_ADDR = 5; // Number of Doppler search steps
static const uint32_t PROG_MEM_ADDR = 6; // Access to the memory storing the PRN code of the target satellite.
static const uint32_t LOG2_FFT_LENGTH_REG_ADDR = 7; // Log2(FFT_LENGTH)
static const uint32_t ACQ_COMMAND_FLAGS_REG_ADDR = 8; // Flags that reset, start, and stop the acquisition process.
static const uint32_t CLEAR_MEM_REG_ADDR = 9; // Flag that resets the write address of the PRN code memory.
static const uint32_t MAX_FFT_SCALING_FACTOR_REG_ADDR = 11; // Reference FFT scaling factor
static const uint32_t EXCL_LIM_REG_ADDR = 12; // Exclude Limit value for the second FFT peak search process
// read-write registers
static const uint32_t TEST_REG_ADDR = 15;
// read-only registers
static const uint32_t RESULT_VALID_REG_ADDR = 0; // Flag that indicates a valid result
static const uint32_t SAMPLESTAMP_LSW_REG_ADDR = 1; // Sample stamp LSW
static const uint32_t SAMPLESTAMP_MSW_REG_ADDR = 2; // Sample stamp MSW
static const uint32_t MAG_SQ_FIRST_PEAK_REG_ADDR = 3; // magnitude squared of the first peak
static const uint32_t MAG_SQ_SECOND_PEAK_REG_ADDR = 4; // magnitude squared of the second peak
static const uint32_t ACQ_DELAY_SAMPLES_REG_ADDR = 5; // acquisition delay in samples
static const uint32_t DOPPLER_INDEX_REG_ADDR = 7; // Doppler index
static const uint32_t FFT_SCALING_FACTOR_REG_ADDR = 8; // Scaling factor applied by the FFT
static const uint32_t MAX_FFT_SIZE_REG_ADDR = 9; // Maximum FFT size supported by the FPGA
static const uint32_t DOWNSAMPLING_FILTER_DEC_FACTORS_REG_ADDR = 10; // Available decimation factors
static const uint32_t DOWNSAMPLING_FILTER_LATENCIES_REG_ADDR = 11; // Available downsampling filter latencies
static const uint32_t FPGA_IP_CORE_VERSION_REG_ADDR = 14; // FPGA acquisition IP core version
// FPGA register parameters
static const uint32_t FPGA_PAGE_SIZE = 0x1000; // default page size for the multicorrelator memory map
static const uint32_t LAUNCH_ACQUISITION = 1; // command to launch the acquisition process
@ -152,30 +188,40 @@ private:
static const uint32_t POW_2_2 = 4; // 2^2 (used for the conversion of floating point numbers to integers)
static const uint32_t POW_2_31 = 2147483648; // 2^31 (used for the conversion of floating point numbers to integers)
static const uint32_t SELECT_LSBits = 0x0000FFFF; // Select the 10 LSbits out of a 20-bit word
static const uint32_t SELECT_MSBbits = 0xFFFF0000; // Select the 10 MSbits out of a 20-bit word
static const uint32_t SELECT_ALL_CODE_BITS = 0xFFFFFFFF; // Select a 20 bit word
static const uint32_t SHL_CODE_BITS = 65536; // shift left by 10 bits
static const uint32_t MAX_FILTERS_AVAILABLE = 2; // maximum number of downsampling filters available in the FPGA by default
static const uint32_t DEFAULT_DOWNSAMPLING_FILTER_DELAY = 40; // default downsampling filter delay (for FPGA Acquisition IP core versions earlier than FPGA_ACQ_IP_VERSION_1)
static const uint32_t DEFAULT_DOWNSAMPLING_FACTOR = 4; // default downsampling factor (for FPGA Acquisition IP core versions earlier than FPGA_ACQ_IP_VERSION_1)
static const uint32_t DEFAULT_MAX_FFT_SIZE = 32768; // default maximum FFT size supported by the FPGA
static const uint32_t ACQ_BUFF_0 = 0; // FPGA Acquisition IP buffer containing L1/E1 frequency band samples by default.
static const uint32_t ACQ_BUFF_1 = 0; // FPGA Acquisition IP buffer containing L2 or L5/E5a frequency band samples by default.
// FPGA private functions
// bit manipulation
static const uint32_t RSHIFT_4_BITS = 0x4;
static const uint32_t RSHIFT_8_BITS = 0x8;
static const uint32_t BIT_MASK_4 = 0xF;
static const uint32_t BIT_MASK_8 = 0xFF;
// private methods
void fpga_acquisition_test_register(void);
void read_result_valid(uint32_t *result_valid);
void read_ipcore_info(std::vector<std::pair<uint32_t, uint32_t>> &downsampling_filter_specs, uint32_t &max_FFT_size);
std::string d_device_name; // HW device name
int64_t d_fs_in;
// data related to the hardware module and the driver
int32_t d_fd; // driver descriptor
std::vector<std::pair<uint32_t, uint32_t>> d_downsampling_filter_specs;
std::string d_device_name; // HW device name
int64_t d_resampled_fs; // sampling frequency
volatile uint32_t *d_map_base; // driver memory map
uint32_t *d_all_fft_codes; // memory that contains all the code ffts
uint32_t d_vector_length; // number of samples including padding and number of ms
int32_t d_fd; // driver descriptor
uint32_t d_fft_size; // number of samples including padding
uint32_t d_excludelimit;
uint32_t d_nsamples_total; // number of samples including padding
uint32_t d_nsamples; // number of samples not including padding
uint32_t d_select_queue; // queue selection
uint32_t d_doppler_max; // max doppler
uint32_t d_doppler_step; // doppler step
uint32_t d_PRN; // PRN
uint32_t d_nsamples; // number of samples not including padding
uint32_t d_filter_num; // Selected downsampling filter
uint32_t d_downsampling_factor; // downsampling_factor
uint32_t d_downsampling_filter_delay; // Impulse response delay of the downsampling filter
uint32_t d_select_queue; // queue selection
uint32_t d_doppler_max; // max doppler
uint32_t d_doppler_step; // doppler step
uint32_t d_PRN; // PRN
uint32_t d_IP_core_version; // FPGA acquisition IP core version
};