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:
parent
b9fe78cf0a
commit
e9c8a027d0
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user