1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-15 20:50:33 +00:00

Merge branch 'glamountain-kf' into kf

This commit is contained in:
Carles Fernandez 2018-07-20 13:20:04 +02:00
commit ca4614811c
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
69 changed files with 2209 additions and 1122 deletions

View File

@ -40,6 +40,7 @@ Antonio Ramos antonio.ramosdet@gmail.com Developer
Marc Majoral marc.majoral@cttc.cat Developer
Jordi Vilà-Valls jordi.vila@cttc.cat Consultant
Pau Closas pau.closas@northeastern.edu Consultant
Álvaro Cebrián Juan acebrianjuan@gmail.com Contributor
Andres Cecilia Luque a.cecilia.luque@gmail.com Contributor
Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor
Carlos Avilés carlos.avilesr@googlemail.com Contributor

View File

@ -32,12 +32,11 @@
#ifndef GNSS_SDR_GALILEO_E1_PCPS_8MS_AMBIGUOUS_ACQUISITION_H_
#define GNSS_SDR_GALILEO_E1_PCPS_8MS_AMBIGUOUS_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "galileo_pcps_8ms_acquisition_cc.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -123,6 +122,7 @@ public:
* \brief Restart acquisition algorithm
*/
void reset() override;
void set_state(int state __attribute__((unused))) override{};
private:
ConfigurationInterface* configuration_;

View File

@ -58,31 +58,38 @@ GalileoE1PcpsAmbiguousAcquisition::GalileoE1PcpsAmbiguousAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 4000000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
blocking_ = configuration_->property(role + ".blocking", true);
acq_parameters.blocking = blocking_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil((1.0 / Galileo_E1_CODE_CHIP_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
doppler_max_ = configuration_->property(role + ".doppler_max", 5000);
if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max;
acq_parameters.doppler_max = doppler_max_;
sampled_ms_ = 4;
acq_parameters.ms_per_code = 4;
sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", acq_parameters.ms_per_code);
acq_parameters.sampled_ms = sampled_ms_;
if ((acq_parameters.sampled_ms % acq_parameters.ms_per_code) != 0)
{
LOG(WARNING) << "Parameter coherent_integration_time_ms should be a multiple of 4. Setting it to 4";
acq_parameters.sampled_ms = acq_parameters.ms_per_code;
}
bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
acq_parameters.bit_transition_flag = bit_transition_flag_;
use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions
acq_parameters.use_CFAR_algorithm_flag = use_CFAR_algorithm_flag_;
acquire_pilot_ = configuration_->property(role + ".acquire_pilot", false); //will be true in future versions
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
acq_parameters.max_dwells = max_dwells_;
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
blocking_ = configuration_->property(role + ".blocking", true);
acq_parameters.blocking = blocking_;
dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename);
acq_parameters.dump_filename = dump_filename_;
//--- Find number of samples per spreading code (4 ms) -----------------
code_length_ = static_cast<unsigned int>(std::round(static_cast<double>(fs_in_) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)));
acq_parameters.samples_per_code = code_length_;
int samples_per_ms = static_cast<int>(std::round(static_cast<double>(fs_in_) * 0.001));
code_length_ = static_cast<unsigned int>(std::floor(static_cast<double>(fs_in_) / (Galileo_E1_CODE_CHIP_RATE_HZ / Galileo_E1_B_CODE_LENGTH_CHIPS)));
float samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.samples_per_ms = samples_per_ms;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(Galileo_E1_CODE_PERIOD_MS);
vector_length_ = sampled_ms_ * samples_per_ms;
if (bit_transition_flag_)

View File

@ -130,7 +130,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -32,12 +32,11 @@
#ifndef GNSS_SDR_GALILEO_E1_PCPS_CCCWSR_AMBIGUOUS_ACQUISITION_H_
#define GNSS_SDR_GALILEO_E1_PCPS_CCCWSR_AMBIGUOUS_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_cccwsr_acquisition_cc.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -124,7 +123,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -32,11 +32,11 @@
#ifndef GNSS_SDR_GALILEO_E1_PCPS_QUICKSYNC_AMBIGUOUS_ACQUISITION_H_
#define GNSS_SDR_GALILEO_E1_PCPS_QUICKSYNC_AMBIGUOUS_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_quicksync_acquisition_cc.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -127,7 +127,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -32,12 +32,11 @@
#ifndef GNSS_SDR_GALILEO_E1_PCPS_TONG_AMBIGUOUS_ACQUISITION_H_
#define GNSS_SDR_GALILEO_E1_PCPS_TONG_AMBIGUOUS_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_tong_acquisition_cc.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -127,7 +126,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -38,10 +38,10 @@
#ifndef GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_
#define GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_
#include <string>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf_cc.h"
#include <string>
class ConfigurationInterface;
@ -129,7 +129,7 @@ public:
* first available sample.
* \param state - int=1 forces start of acquisition
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -57,6 +57,7 @@ GalileoE5aPcpsAcquisition::GalileoE5aPcpsAcquisition(ConfigurationInterface* con
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil((1.0 / Galileo_E5a_CODE_CHIP_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
acq_pilot_ = configuration_->property(role + ".acquire_pilot", false);
acq_iq_ = configuration_->property(role + ".acquire_iq", false);
if (acq_iq_)
@ -100,9 +101,10 @@ GalileoE5aPcpsAcquisition::GalileoE5aPcpsAcquisition(ConfigurationInterface* con
LOG(WARNING) << item_type_ << " unknown acquisition item type";
}
acq_parameters.it_size = item_size_;
acq_parameters.samples_per_code = code_length_;
acq_parameters.samples_per_ms = code_length_;
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.sampled_ms = sampled_ms_;
acq_parameters.ms_per_code = 1;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GALILEO_E5a_CODE_PERIOD_MS);
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);

View File

@ -121,7 +121,7 @@ public:
* first available sample.
* \param state - int=1 forces start of acquisition
*/
void set_state(int state);
void set_state(int state) override;
private:
float calculate_threshold(float pfa);

View File

@ -59,6 +59,7 @@ GlonassL1CaPcpsAcquisition::GlonassL1CaPcpsAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil(GLONASS_L1_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
@ -99,8 +100,9 @@ GlonassL1CaPcpsAcquisition::GlonassL1CaPcpsAcquisition(
}
acq_parameters.it_size = item_size_;
acq_parameters.sampled_ms = sampled_ms_;
acq_parameters.samples_per_ms = code_length_;
acq_parameters.samples_per_code = code_length_;
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.ms_per_code = 1;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GLONASS_L1_CA_CODE_PERIOD * 1000.0);
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);

View File

@ -130,7 +130,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -58,6 +58,7 @@ GlonassL2CaPcpsAcquisition::GlonassL2CaPcpsAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil(GLONASS_L2_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
@ -98,8 +99,9 @@ GlonassL2CaPcpsAcquisition::GlonassL2CaPcpsAcquisition(
}
acq_parameters.it_size = item_size_;
acq_parameters.sampled_ms = sampled_ms_;
acq_parameters.samples_per_ms = code_length_;
acq_parameters.samples_per_code = code_length_;
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.ms_per_code = 1;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GLONASS_L2_CA_CODE_PERIOD * 1000.0);
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);

View File

@ -129,7 +129,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -60,6 +60,7 @@ GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
@ -70,6 +71,7 @@ GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition(
acq_parameters.doppler_max = doppler_max_;
sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1);
acq_parameters.sampled_ms = sampled_ms_;
acq_parameters.ms_per_code = 1;
bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
acq_parameters.bit_transition_flag = bit_transition_flag_;
use_CFAR_algorithm_flag_ = configuration_->property(role + ".use_CFAR_algorithm", true); //will be false in future versions
@ -82,15 +84,11 @@ GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition(
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
//--- Find number of samples per spreading code -------------------------
code_length_ = static_cast<unsigned int>(std::round(static_cast<double>(fs_in_) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)));
vector_length_ = code_length_ * sampled_ms_;
if (bit_transition_flag_)
{
vector_length_ *= 2;
}
code_length_ = static_cast<unsigned int>(std::floor(static_cast<double>(fs_in_) / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS)));
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GPS_L1_CA_CODE_PERIOD * 1000.0);
vector_length_ = std::floor(acq_parameters.sampled_ms * acq_parameters.samples_per_ms) * (acq_parameters.bit_transition_flag ? 2 : 1);
code_ = new gr_complex[vector_length_];
if (item_type_.compare("cshort") == 0)
@ -101,8 +99,7 @@ GpsL1CaPcpsAcquisition::GpsL1CaPcpsAcquisition(
{
item_size_ = sizeof(gr_complex);
}
acq_parameters.samples_per_ms = code_length_;
acq_parameters.samples_per_code = code_length_;
acq_parameters.it_size = item_size_;
acq_parameters.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false);
acquisition_ = pcps_make_acquisition(acq_parameters);

View File

@ -134,7 +134,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -33,11 +33,12 @@
*/
#include "gps_l1_ca_pcps_acquisition_fine_doppler.h"
#include <glog/logging.h>
#include "gps_sdr_signal_processing.h"
#include "GPS_L1_CA.h"
#include "configuration_interface.h"
#include "gnss_sdr_flags.h"
#include "acq_conf.h"
#include <glog/logging.h>
using google::LogMessage;
@ -49,29 +50,36 @@ GpsL1CaPcpsAcquisitionFineDoppler::GpsL1CaPcpsAcquisitionFineDoppler(
std::string default_dump_filename = "./data/acquisition.dat";
DLOG(INFO) << "role " << role;
Acq_Conf acq_parameters = Acq_Conf();
item_type_ = configuration->property(role + ".item_type", default_item_type);
long fs_in_deprecated = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration->property(role + ".dump", false);
acq_parameters.dump = dump_;
dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename);
acq_parameters.dump_filename = dump_filename_;
doppler_max_ = configuration->property(role + ".doppler_max", 5000);
if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max;
doppler_min_ = configuration->property(role + ".doppler_min", -doppler_max_);
acq_parameters.doppler_max = doppler_max_;
sampled_ms_ = configuration->property(role + ".coherent_integration_time_ms", 1);
acq_parameters.sampled_ms = sampled_ms_;
max_dwells_ = configuration->property(role + ".max_dwells", 1);
acq_parameters.max_dwells = max_dwells_;
acq_parameters.blocking_on_standby = configuration->property(role + ".blocking_on_standby", false);
//--- Find number of samples per spreading code -------------------------
vector_length_ = round(fs_in_ / (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS));
acq_parameters.samples_per_ms = vector_length_;
code_ = new gr_complex[vector_length_];
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(max_dwells_, sampled_ms_,
doppler_max_, doppler_min_, fs_in_, vector_length_,
dump_, dump_filename_);
acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(acq_parameters);
}
else
{
@ -161,6 +169,12 @@ void GpsL1CaPcpsAcquisitionFineDoppler::reset()
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_state(int state)
{
acquisition_cc_->set_state(state);
}
void GpsL1CaPcpsAcquisitionFineDoppler::connect(boost::shared_ptr<gr::top_block> top_block)
{
if (top_block)

View File

@ -34,11 +34,10 @@
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_
#define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_
#include <string>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_acquisition_fine_doppler_cc.h"
#include <string>
class ConfigurationInterface;
@ -122,6 +121,11 @@ public:
*/
void reset() override;
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state) override;
private:
pcps_acquisition_fine_doppler_cc_sptr acquisition_cc_;
size_t item_size_;
@ -131,7 +135,6 @@ private:
float threshold_;
int doppler_max_;
unsigned int doppler_step_;
int doppler_min_;
unsigned int sampled_ms_;
int max_dwells_;
long fs_in_;

View File

@ -60,6 +60,7 @@ GpsL1CaPcpsAcquisitionFpga::GpsL1CaPcpsAcquisitionFpga(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
long fs_in = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(acq_parameters.fs_in)));
doppler_max_ = configuration_->property(role + ".doppler_max", 5000);
if (FLAGS_doppler_max != 0) doppler_max_ = FLAGS_doppler_max;
acq_parameters.doppler_max = doppler_max_;

View File

@ -132,7 +132,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -34,11 +34,10 @@
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_ASSISTED_ACQUISITION_H_
#define GNSS_SDR_GPS_L1_CA_PCPS_ASSISTED_ACQUISITION_H_
#include <string>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_assisted_acquisition_cc.h"
#include <string>
class ConfigurationInterface;
@ -121,6 +120,7 @@ public:
* \brief Restart acquisition algorithm
*/
void reset() override;
void set_state(int state __attribute__((unused))) override{};
private:
pcps_assisted_acquisition_cc_sptr acquisition_cc_;

View File

@ -32,12 +32,11 @@
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_OPENCL_ACQUISITION_H_
#define GNSS_SDR_GPS_L1_CA_PCPS_OPENCL_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_opencl_acquisition_cc.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -123,6 +122,7 @@ public:
* \brief Restart acquisition algorithm
*/
void reset() override;
void set_state(int state __attribute__((unused))) override{};
private:
ConfigurationInterface* configuration_;

View File

@ -33,13 +33,12 @@
#ifndef GNSS_SDR_GPS_L1_CA_PCPS_QUICKSYNC_ACQUISITION_H_
#define GNSS_SDR_GPS_L1_CA_PCPS_QUICKSYNC_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_quicksync_acquisition_cc.h"
#include "configuration_interface.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -129,7 +128,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -32,12 +32,12 @@
#ifndef GNSS_SDR_GPS_L1_CA_TONG_ACQUISITION_H_
#define GNSS_SDR_GPS_L1_CA_TONG_ACQUISITION_H_
#include <string>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_tong_acquisition_cc.h"
#include "configuration_interface.h"
#include <gnuradio/blocks/stream_to_vector.h>
#include <string>
class ConfigurationInterface;
@ -127,7 +127,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;

View File

@ -60,6 +60,7 @@ GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil((1.0 / GPS_L2_M_CODE_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
@ -77,15 +78,19 @@ GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition(
dump_filename_ = configuration_->property(role + ".dump_filename", default_dump_filename);
acq_parameters.dump_filename = dump_filename_;
//--- Find number of samples per spreading code -------------------------
code_length_ = std::round(static_cast<double>(fs_in_) / (GPS_L2_M_CODE_RATE_HZ / static_cast<double>(GPS_L2_M_CODE_LENGTH_CHIPS)));
vector_length_ = code_length_;
if (bit_transition_flag_)
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.ms_per_code = 20;
acq_parameters.sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", acq_parameters.ms_per_code);
if ((acq_parameters.sampled_ms % acq_parameters.ms_per_code) != 0)
{
vector_length_ *= 2;
LOG(WARNING) << "Parameter coherent_integration_time_ms should be a multiple of 20. Setting it to 20";
acq_parameters.sampled_ms = acq_parameters.ms_per_code;
}
code_length_ = acq_parameters.ms_per_code * acq_parameters.samples_per_ms;
vector_length_ = acq_parameters.sampled_ms * acq_parameters.samples_per_ms * (acq_parameters.bit_transition_flag ? 2 : 1);
code_ = new gr_complex[vector_length_];
if (item_type_.compare("cshort") == 0)
@ -96,13 +101,13 @@ GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition(
{
item_size_ = sizeof(gr_complex);
}
acq_parameters.samples_per_ms = static_cast<int>(std::round(static_cast<double>(fs_in_) * 0.001));
acq_parameters.samples_per_code = code_length_;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GPS_L2_M_PERIOD * 1000.0);
acq_parameters.it_size = item_size_;
acq_parameters.sampled_ms = 20;
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", true);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
acq_parameters.blocking_on_standby = configuration_->property(role + ".blocking_on_standby", false);
acquisition_ = pcps_make_acquisition(acq_parameters);
DLOG(INFO) << "acquisition(" << acquisition_->unique_id() << ")";
@ -120,6 +125,7 @@ GpsL2MPcpsAcquisition::GpsL2MPcpsAcquisition(
threshold_ = 0.0;
doppler_step_ = 0;
gnss_synchro_ = 0;
num_codes_ = acq_parameters.sampled_ms / acq_parameters.ms_per_code;
if (in_streams_ > 1)
{
LOG(ERROR) << "This implementation only supports one input stream";
@ -208,9 +214,18 @@ void GpsL2MPcpsAcquisition::init()
void GpsL2MPcpsAcquisition::set_local_code()
{
gps_l2c_m_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_);
std::complex<float>* code = new std::complex<float>[code_length_];
gps_l2c_m_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_);
for (unsigned int i = 0; i < num_codes_; i++)
{
memcpy(&(code_[i * code_length_]), code,
sizeof(gr_complex) * code_length_);
}
acquisition_->set_local_code(code_);
delete[] code;
}

View File

@ -132,7 +132,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;
@ -160,6 +160,7 @@ private:
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
unsigned int num_codes_;
float calculate_threshold(float pfa);
};

View File

@ -1,5 +1,5 @@
/*!
* \file gps_l5i pcps_acquisition.cc
* \file gps_l5i_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an Acquisition Interface for
* GPS L5i signals
* \authors <ul>
@ -59,6 +59,7 @@ GpsL5iPcpsAcquisition::GpsL5iPcpsAcquisition(
long fs_in_deprecated = configuration_->property("GNSS-SDR.internal_fs_hz", 2048000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_sps", fs_in_deprecated);
acq_parameters.fs_in = fs_in_;
acq_parameters.samples_per_chip = static_cast<unsigned int>(ceil((1.0 / GPS_L5i_CODE_RATE_HZ) * static_cast<float>(acq_parameters.fs_in)));
dump_ = configuration_->property(role + ".dump", false);
acq_parameters.dump = dump_;
acq_parameters.dump_channel = configuration_->property(role + ".dump_channel", 0);
@ -95,10 +96,12 @@ GpsL5iPcpsAcquisition::GpsL5iPcpsAcquisition(
{
item_size_ = sizeof(gr_complex);
}
acq_parameters.samples_per_code = code_length_;
acq_parameters.samples_per_ms = code_length_;
acq_parameters.samples_per_ms = static_cast<float>(fs_in_) * 0.001;
acq_parameters.samples_per_code = acq_parameters.samples_per_ms * static_cast<float>(GPS_L5i_PERIOD * 1000.0);
acq_parameters.ms_per_code = 1;
acq_parameters.it_size = item_size_;
acq_parameters.sampled_ms = 1;
acq_parameters.sampled_ms = configuration_->property(role + ".coherent_integration_time_ms", 1);
num_codes_ = acq_parameters.sampled_ms;
acq_parameters.num_doppler_bins_step2 = configuration_->property(role + ".second_nbins", 4);
acq_parameters.doppler_step2 = configuration_->property(role + ".second_doppler_step", 125.0);
acq_parameters.make_2_steps = configuration_->property(role + ".make_two_steps", false);
@ -205,9 +208,18 @@ void GpsL5iPcpsAcquisition::init()
void GpsL5iPcpsAcquisition::set_local_code()
{
gps_l5i_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_);
std::complex<float>* code = new std::complex<float>[code_length_];
gps_l5i_code_gen_complex_sampled(code, gnss_synchro_->PRN, fs_in_);
for (unsigned int i = 0; i < num_codes_; i++)
{
memcpy(&(code_[i * code_length_]), code,
sizeof(gr_complex) * code_length_);
}
acquisition_->set_local_code(code_);
delete[] code;
}

View File

@ -1,5 +1,5 @@
/*!
* \file GPS_L5i_PCPS_Acquisition.h
* \file gps_l5i_pcps_acquisition.h
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* GPS L5i signals
* \authors <ul>
@ -132,7 +132,7 @@ public:
/*!
* \brief If state = 1, it forces the block to start acquiring from the first sample
*/
void set_state(int state);
void set_state(int state) override;
private:
ConfigurationInterface* configuration_;
@ -158,6 +158,7 @@ private:
std::complex<float>* code_;
Gnss_Synchro* gnss_synchro_;
std::string role_;
unsigned int num_codes_;
unsigned int in_streams_;
unsigned int out_streams_;

View File

@ -52,8 +52,8 @@ pcps_acquisition_sptr pcps_make_acquisition(const Acq_Conf& conf_)
pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acquisition",
gr::io_signature::make(1, 1, conf_.it_size * conf_.sampled_ms * conf_.samples_per_ms * (conf_.bit_transition_flag ? 2 : 1)),
gr::io_signature::make(0, 0, conf_.it_size * conf_.sampled_ms * conf_.samples_per_ms * (conf_.bit_transition_flag ? 2 : 1)))
gr::io_signature::make(1, 1, conf_.it_size * std::floor(conf_.sampled_ms * conf_.samples_per_ms) * (conf_.bit_transition_flag ? 2 : 1)),
gr::io_signature::make(0, 0, conf_.it_size))
{
this->message_port_register_out(pmt::mp("events"));
@ -63,8 +63,17 @@ pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acqu
d_positive_acq = 0;
d_state = 0;
d_old_freq = 0;
d_well_count = 0;
d_fft_size = acq_parameters.sampled_ms * acq_parameters.samples_per_ms;
d_num_noncoherent_integrations_counter = 0;
d_consumed_samples = acq_parameters.sampled_ms * acq_parameters.samples_per_ms * (acq_parameters.bit_transition_flag ? 2 : 1);
if (acq_parameters.sampled_ms == acq_parameters.ms_per_code)
{
d_fft_size = d_consumed_samples;
}
else
{
d_fft_size = d_consumed_samples * 2;
}
//d_fft_size = next power of two? ////
d_mag = 0;
d_input_power = 0.0;
d_num_doppler_bins = 0;
@ -94,12 +103,14 @@ pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acqu
// size of the input buffer and padding the code with zeros.
if (acq_parameters.bit_transition_flag)
{
d_fft_size *= 2;
d_fft_size = d_consumed_samples * 2;
acq_parameters.max_dwells = 1; // Activation of acq_parameters.bit_transition_flag invalidates the value of acq_parameters.max_dwells
}
d_tmp_buffer = static_cast<float*>(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment()));
d_fft_codes = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
d_magnitude = static_cast<float*>(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment()));
d_input_signal = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
@ -110,11 +121,12 @@ pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acqu
d_gnss_synchro = 0;
d_grid_doppler_wipeoffs = nullptr;
d_grid_doppler_wipeoffs_step_two = nullptr;
d_magnitude_grid = nullptr;
d_worker_active = false;
d_data_buffer = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
d_data_buffer = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_consumed_samples * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
if (d_cshort)
{
d_data_buffer_sc = static_cast<lv_16sc_t*>(volk_gnsssdr_malloc(d_fft_size * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment()));
d_data_buffer_sc = static_cast<lv_16sc_t*>(volk_gnsssdr_malloc(d_consumed_samples * sizeof(lv_16sc_t), volk_gnsssdr_get_alignment()));
}
else
{
@ -124,6 +136,16 @@ pcps_acquisition::pcps_acquisition(const Acq_Conf& conf_) : gr::block("pcps_acqu
d_step_two = false;
d_dump_number = 0;
d_dump_channel = acq_parameters.dump_channel;
d_samplesPerChip = acq_parameters.samples_per_chip;
// todo: CFAR statistic not available for non-coherent integration
if (acq_parameters.max_dwells == 1)
{
d_use_CFAR_algorithm_flag = acq_parameters.use_CFAR_algorithm_flag;
}
else
{
d_use_CFAR_algorithm_flag = false;
}
}
@ -134,8 +156,10 @@ pcps_acquisition::~pcps_acquisition()
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
volk_gnsssdr_free(d_grid_doppler_wipeoffs[i]);
volk_gnsssdr_free(d_magnitude_grid[i]);
}
delete[] d_grid_doppler_wipeoffs;
delete[] d_magnitude_grid;
}
if (acq_parameters.make_2_steps)
{
@ -147,6 +171,8 @@ pcps_acquisition::~pcps_acquisition()
}
volk_gnsssdr_free(d_fft_codes);
volk_gnsssdr_free(d_magnitude);
volk_gnsssdr_free(d_tmp_buffer);
volk_gnsssdr_free(d_input_signal);
delete d_ifft;
delete d_fft_if;
volk_gnsssdr_free(d_data_buffer);
@ -179,7 +205,15 @@ void pcps_acquisition::set_local_code(std::complex<float>* code)
}
else
{
memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_fft_size);
if (acq_parameters.sampled_ms == acq_parameters.ms_per_code)
{
memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex) * d_consumed_samples);
}
else
{
std::fill_n(d_fft_if->get_inbuf(), d_fft_size - d_consumed_samples, gr_complex(0.0, 0.0));
memcpy(d_fft_if->get_inbuf() + d_consumed_samples, code, sizeof(gr_complex) * d_consumed_samples);
}
}
d_fft_if->execute(); // We need the FFT of local code
@ -244,12 +278,20 @@ void pcps_acquisition::init()
d_grid_doppler_wipeoffs_step_two[doppler_index] = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
}
}
d_magnitude_grid = new float*[d_num_doppler_bins];
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
d_grid_doppler_wipeoffs[doppler_index] = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
d_magnitude_grid[doppler_index] = static_cast<float*>(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment()));
for (unsigned k = 0; k < d_fft_size; k++)
{
d_magnitude_grid[doppler_index][k] = 0.0;
}
int doppler = -static_cast<int>(acq_parameters.doppler_max) + d_doppler_step * doppler_index;
update_local_carrier(d_grid_doppler_wipeoffs[doppler_index], d_fft_size, d_old_freq + doppler);
}
d_worker_active = false;
if (acq_parameters.dump)
@ -269,6 +311,7 @@ void pcps_acquisition::update_grid_doppler_wipeoffs()
}
}
void pcps_acquisition::update_grid_doppler_wipeoffs_step2()
{
for (unsigned int doppler_index = 0; doppler_index < acq_parameters.num_doppler_bins_step2; doppler_index++)
@ -278,6 +321,7 @@ void pcps_acquisition::update_grid_doppler_wipeoffs_step2()
}
}
void pcps_acquisition::set_state(int state)
{
gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler
@ -288,7 +332,6 @@ void pcps_acquisition::set_state(int state)
d_gnss_synchro->Acq_doppler_hz = 0.0;
d_gnss_synchro->Acq_doppler_step = 0;
d_gnss_synchro->Acq_samplestamp_samples = 0;
d_well_count = 0;
d_mag = 0.0;
d_input_power = 0.0;
d_test_statistics = 0.0;
@ -419,117 +462,202 @@ void pcps_acquisition::dump_results(int effective_fft_size)
}
float pcps_acquisition::max_to_input_power_statistic(uint32_t& indext, int& doppler, float input_power, unsigned int num_doppler_bins, int doppler_max, int doppler_step)
{
float grid_maximum = 0.0;
unsigned int index_doppler = 0;
uint32_t tmp_intex_t = 0;
uint32_t index_time = 0;
float fft_normalization_factor = static_cast<float>(d_fft_size) * static_cast<float>(d_fft_size);
// Find the correlation peak and the carrier frequency
for (unsigned int i = 0; i < num_doppler_bins; i++)
{
volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_magnitude_grid[i], d_fft_size);
if (d_magnitude_grid[i][tmp_intex_t] > grid_maximum)
{
grid_maximum = d_magnitude_grid[i][tmp_intex_t];
index_doppler = i;
index_time = tmp_intex_t;
}
}
indext = index_time;
if (!d_step_two)
{
doppler = -static_cast<int>(doppler_max) + doppler_step * static_cast<int>(index_doppler);
}
else
{
doppler = static_cast<int>(d_doppler_center_step_two + (index_doppler - (acq_parameters.num_doppler_bins_step2 / 2.0) * acq_parameters.doppler_step2));
}
float magt = grid_maximum / (fft_normalization_factor * fft_normalization_factor);
return magt / input_power;
}
float pcps_acquisition::first_vs_second_peak_statistic(uint32_t& indext, int& doppler, unsigned int num_doppler_bins, int doppler_max, int doppler_step)
{
// Look for correlation peaks in the results
// Find the highest peak and compare it to the second highest peak
// The second peak is chosen not closer than 1 chip to the highest peak
float firstPeak = 0.0;
unsigned int index_doppler = 0;
uint32_t tmp_intex_t = 0;
uint32_t index_time = 0;
// Find the correlation peak and the carrier frequency
for (unsigned int i = 0; i < num_doppler_bins; i++)
{
volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_magnitude_grid[i], d_fft_size);
if (d_magnitude_grid[i][tmp_intex_t] > firstPeak)
{
firstPeak = d_magnitude_grid[i][tmp_intex_t];
index_doppler = i;
index_time = tmp_intex_t;
}
}
indext = index_time;
if (!d_step_two)
{
doppler = -static_cast<int>(doppler_max) + doppler_step * static_cast<int>(index_doppler);
}
else
{
doppler = static_cast<int>(d_doppler_center_step_two + (index_doppler - (acq_parameters.num_doppler_bins_step2 / 2.0) * acq_parameters.doppler_step2));
}
// Find 1 chip wide code phase exclude range around the peak
int32_t excludeRangeIndex1 = index_time - d_samplesPerChip;
int32_t excludeRangeIndex2 = index_time + d_samplesPerChip;
// Correct code phase exclude range if the range includes array boundaries
if (excludeRangeIndex1 < 0)
{
excludeRangeIndex1 = d_fft_size + excludeRangeIndex1;
}
else if (excludeRangeIndex2 >= static_cast<int>(d_fft_size))
{
excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size;
}
int32_t idx = excludeRangeIndex1;
memcpy(d_tmp_buffer, d_magnitude_grid[index_doppler], d_fft_size);
do
{
d_tmp_buffer[idx] = 0.0;
idx++;
if (idx == static_cast<int>(d_fft_size)) idx = 0;
}
while (idx != excludeRangeIndex2);
// Find the second highest correlation peak in the same freq. bin ---
volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_tmp_buffer, d_fft_size);
float secondPeak = d_tmp_buffer[tmp_intex_t];
// Compute the test statistics and compare to the threshold
return firstPeak / secondPeak;
}
void pcps_acquisition::acquisition_core(unsigned long int samp_count)
{
gr::thread::scoped_lock lk(d_setlock);
// initialize acquisition algorithm
int doppler = 0;
uint32_t indext = 0;
float magt = 0.0;
const gr_complex* in = d_data_buffer; // Get the input samples pointer
int effective_fft_size = (acq_parameters.bit_transition_flag ? d_fft_size / 2 : d_fft_size);
if (d_cshort)
{
volk_gnsssdr_16ic_convert_32fc(d_data_buffer, d_data_buffer_sc, d_fft_size);
volk_gnsssdr_16ic_convert_32fc(d_data_buffer, d_data_buffer_sc, d_consumed_samples);
}
float fft_normalization_factor = static_cast<float>(d_fft_size) * static_cast<float>(d_fft_size);
memcpy(d_input_signal, d_data_buffer, d_consumed_samples * sizeof(gr_complex));
if (d_fft_size > d_consumed_samples)
{
for (unsigned int i = d_consumed_samples; i < d_fft_size; i++)
{
d_input_signal[i] = gr_complex(0.0, 0.0);
}
}
const gr_complex* in = d_input_signal; // Get the input samples pointer
d_input_power = 0.0;
d_mag = 0.0;
d_well_count++;
d_num_noncoherent_integrations_counter++;
DLOG(INFO) << "Channel: " << d_channel
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN
<< " ,sample stamp: " << samp_count << ", threshold: "
<< d_threshold << ", doppler_max: " << acq_parameters.doppler_max
<< ", doppler_step: " << d_doppler_step
<< ", use_CFAR_algorithm_flag: " << (acq_parameters.use_CFAR_algorithm_flag ? "true" : "false");
<< ", use_CFAR_algorithm_flag: " << (d_use_CFAR_algorithm_flag ? "true" : "false");
lk.unlock();
if (acq_parameters.use_CFAR_algorithm_flag)
if (d_use_CFAR_algorithm_flag or acq_parameters.bit_transition_flag)
{
// 1- (optional) Compute the input signal power estimation
volk_32fc_magnitude_squared_32f(d_magnitude, in, d_fft_size);
volk_32f_accumulator_s32f(&d_input_power, d_magnitude, d_fft_size);
// Compute the input signal power estimation
volk_32fc_magnitude_squared_32f(d_tmp_buffer, in, d_fft_size);
volk_32f_accumulator_s32f(&d_input_power, d_tmp_buffer, d_fft_size);
d_input_power /= static_cast<float>(d_fft_size);
}
// 2- Doppler frequency search loop
// Doppler frequency grid loop
if (!d_step_two)
{
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
// doppler search steps
int doppler = -static_cast<int>(acq_parameters.doppler_max) + d_doppler_step * doppler_index;
// Remove Doppler
volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs[doppler_index], d_fft_size);
// 3- Perform the FFT-based convolution (parallel time search)
// Perform the FFT-based convolution (parallel time search)
// Compute the FFT of the carrier wiped--off incoming signal
d_fft_if->execute();
// Multiply carrier wiped--off, Fourier transformed incoming signal
// with the local FFT'd code reference using SIMD operations with VOLK library
// Multiply carrier wiped--off, Fourier transformed incoming signal with the local FFT'd code reference
volk_32fc_x2_multiply_32fc(d_ifft->get_inbuf(), d_fft_if->get_outbuf(), d_fft_codes, d_fft_size);
// compute the inverse FFT
// Compute the inverse FFT
d_ifft->execute();
// Search maximum
// Compute squared magnitude (and accumulate in case of non-coherent integration)
size_t offset = (acq_parameters.bit_transition_flag ? effective_fft_size : 0);
volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf() + offset, effective_fft_size);
volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude, effective_fft_size);
magt = d_magnitude[indext];
if (acq_parameters.use_CFAR_algorithm_flag)
if (d_num_noncoherent_integrations_counter == 1)
{
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt = d_magnitude[indext] / (fft_normalization_factor * fft_normalization_factor);
volk_32fc_magnitude_squared_32f(d_magnitude_grid[doppler_index], d_ifft->get_outbuf() + offset, effective_fft_size);
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
else
{
d_mag = magt;
if (!acq_parameters.use_CFAR_algorithm_flag)
{
// Search grid noise floor approximation for this doppler line
volk_32f_accumulator_s32f(&d_input_power, d_magnitude, effective_fft_size);
d_input_power = (d_input_power - d_mag) / (effective_fft_size - 1);
}
// In case that acq_parameters.bit_transition_flag = true, we compare the potentially
// new maximum test statistics (d_mag/d_input_power) with the value in
// d_test_statistics. When the second dwell is being processed, the value
// of d_mag/d_input_power could be lower than d_test_statistics (i.e,
// the maximum test statistics in the previous dwell is greater than
// current d_mag/d_input_power). Note that d_test_statistics is not
// restarted between consecutive dwells in multidwell operation.
if (d_test_statistics < (d_mag / d_input_power) or !acq_parameters.bit_transition_flag)
{
d_gnss_synchro->Acq_delay_samples = static_cast<double>(indext % acq_parameters.samples_per_code);
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler);
d_gnss_synchro->Acq_samplestamp_samples = samp_count;
// 5- Compute the test statistics and compare to the threshold
//d_test_statistics = 2 * d_fft_size * d_mag / d_input_power;
d_test_statistics = d_mag / d_input_power;
}
volk_32fc_magnitude_squared_32f(d_tmp_buffer, d_ifft->get_outbuf() + offset, effective_fft_size);
volk_32f_x2_add_32f(d_magnitude_grid[doppler_index], d_magnitude_grid[doppler_index], d_tmp_buffer, effective_fft_size);
}
// Record results to file if required
if (acq_parameters.dump and d_channel == d_dump_channel)
{
memcpy(grid_.colptr(doppler_index), d_magnitude, sizeof(float) * effective_fft_size);
memcpy(grid_.colptr(doppler_index), d_magnitude_grid[doppler_index], sizeof(float) * effective_fft_size);
}
}
// Compute the test statistic
if (d_use_CFAR_algorithm_flag)
{
d_test_statistics = max_to_input_power_statistic(indext, doppler, d_input_power, d_num_doppler_bins, acq_parameters.doppler_max, d_doppler_step);
}
else
{
d_test_statistics = first_vs_second_peak_statistic(indext, doppler, d_num_doppler_bins, acq_parameters.doppler_max, d_doppler_step);
}
d_gnss_synchro->Acq_delay_samples = static_cast<double>(std::fmod(static_cast<float>(indext), acq_parameters.samples_per_code));
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler);
d_gnss_synchro->Acq_samplestamp_samples = samp_count;
}
else
{
for (unsigned int doppler_index = 0; doppler_index < acq_parameters.num_doppler_bins_step2; doppler_index++)
{
// doppler search steps
float doppler = d_doppler_center_step_two + (static_cast<float>(doppler_index) - static_cast<float>(acq_parameters.num_doppler_bins_step2) / 2.0) * acq_parameters.doppler_step2;
volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs_step_two[doppler_index], d_fft_size);
// 3- Perform the FFT-based convolution (parallel time search)
@ -543,55 +671,31 @@ void pcps_acquisition::acquisition_core(unsigned long int samp_count)
// compute the inverse FFT
d_ifft->execute();
// Search maximum
size_t offset = (acq_parameters.bit_transition_flag ? effective_fft_size : 0);
volk_32fc_magnitude_squared_32f(d_magnitude, d_ifft->get_outbuf() + offset, effective_fft_size);
volk_gnsssdr_32f_index_max_32u(&indext, d_magnitude, effective_fft_size);
magt = d_magnitude[indext];
if (acq_parameters.use_CFAR_algorithm_flag)
if (d_num_noncoherent_integrations_counter == 1)
{
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt = d_magnitude[indext] / (fft_normalization_factor * fft_normalization_factor);
volk_32fc_magnitude_squared_32f(d_magnitude_grid[doppler_index], d_ifft->get_outbuf() + offset, effective_fft_size);
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
else
{
d_mag = magt;
if (!acq_parameters.use_CFAR_algorithm_flag)
{
// Search grid noise floor approximation for this doppler line
volk_32f_accumulator_s32f(&d_input_power, d_magnitude, effective_fft_size);
d_input_power = (d_input_power - d_mag) / (effective_fft_size - 1);
volk_32fc_magnitude_squared_32f(d_tmp_buffer, d_ifft->get_outbuf() + offset, effective_fft_size);
volk_32f_x2_add_32f(d_magnitude_grid[doppler_index], d_magnitude_grid[doppler_index], d_tmp_buffer, effective_fft_size);
}
// In case that acq_parameters.bit_transition_flag = true, we compare the potentially
// new maximum test statistics (d_mag/d_input_power) with the value in
// d_test_statistics. When the second dwell is being processed, the value
// of d_mag/d_input_power could be lower than d_test_statistics (i.e,
// the maximum test statistics in the previous dwell is greater than
// current d_mag/d_input_power). Note that d_test_statistics is not
// restarted between consecutive dwells in multidwell operation.
if (d_test_statistics < (d_mag / d_input_power) or !acq_parameters.bit_transition_flag)
}
// Compute the test statistic
if (d_use_CFAR_algorithm_flag)
{
d_gnss_synchro->Acq_delay_samples = static_cast<double>(indext % acq_parameters.samples_per_code);
d_test_statistics = max_to_input_power_statistic(indext, doppler, d_input_power, acq_parameters.num_doppler_bins_step2, static_cast<int>(d_doppler_center_step_two - (static_cast<float>(acq_parameters.num_doppler_bins_step2) / 2.0) * acq_parameters.doppler_step2), acq_parameters.doppler_step2);
}
else
{
d_test_statistics = first_vs_second_peak_statistic(indext, doppler, acq_parameters.num_doppler_bins_step2, static_cast<int>(d_doppler_center_step_two - (static_cast<float>(acq_parameters.num_doppler_bins_step2) / 2.0) * acq_parameters.doppler_step2), acq_parameters.doppler_step2);
}
d_gnss_synchro->Acq_delay_samples = static_cast<double>(std::fmod(static_cast<float>(indext), acq_parameters.samples_per_code));
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(doppler);
d_gnss_synchro->Acq_samplestamp_samples = samp_count;
}
// 5- Compute the test statistics and compare to the threshold
//d_test_statistics = 2 * d_fft_size * d_mag / d_input_power;
d_test_statistics = d_mag / d_input_power;
}
}
// Record results to file if required
if (acq_parameters.dump and d_channel == d_dump_channel)
{
memcpy(grid_.colptr(doppler_index), d_magnitude, sizeof(float) * effective_fft_size);
}
}
}
lk.lock();
if (!acq_parameters.bit_transition_flag)
{
@ -618,12 +722,13 @@ void pcps_acquisition::acquisition_core(unsigned long int samp_count)
d_state = 0; // Positive acquisition
}
}
else if (d_well_count == acq_parameters.max_dwells)
if (d_num_noncoherent_integrations_counter == acq_parameters.max_dwells)
{
if (d_state != 0) send_negative_acquisition();
d_state = 0;
d_active = false;
d_step_two = false;
send_negative_acquisition();
}
}
else
@ -659,11 +764,25 @@ void pcps_acquisition::acquisition_core(unsigned long int samp_count)
}
}
d_worker_active = false;
if ((d_num_noncoherent_integrations_counter == acq_parameters.max_dwells) or (d_positive_acq == 1))
{
// Record results to file if required
if (acq_parameters.dump and d_channel == d_dump_channel)
{
pcps_acquisition::dump_results(effective_fft_size);
}
d_num_noncoherent_integrations_counter = 0;
d_positive_acq = 0;
// Reset grid
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
for (unsigned k = 0; k < d_fft_size; k++)
{
d_magnitude_grid[i][k] = 0.0;
}
}
}
}
@ -681,13 +800,12 @@ int pcps_acquisition::general_work(int noutput_items __attribute__((unused)),
* 5. Compute the test statistics and compare to the threshold
* 6. Declare positive or negative acquisition using a message port
*/
gr::thread::scoped_lock lk(d_setlock);
if (!d_active or d_worker_active)
{
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += d_fft_size * ninput_items[0];
d_sample_counter += d_consumed_samples * ninput_items[0];
consume_each(ninput_items[0]);
}
if (d_step_two)
@ -708,14 +826,13 @@ int pcps_acquisition::general_work(int noutput_items __attribute__((unused)),
d_gnss_synchro->Acq_delay_samples = 0.0;
d_gnss_synchro->Acq_doppler_hz = 0.0;
d_gnss_synchro->Acq_samplestamp_samples = 0;
d_well_count = 0;
d_mag = 0.0;
d_input_power = 0.0;
d_test_statistics = 0.0;
d_state = 1;
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
d_sample_counter += d_consumed_samples * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
}
break;
@ -726,11 +843,11 @@ int pcps_acquisition::general_work(int noutput_items __attribute__((unused)),
// Copy the data to the core and let it know that new data is available
if (d_cshort)
{
memcpy(d_data_buffer_sc, input_items[0], d_fft_size * sizeof(lv_16sc_t));
memcpy(d_data_buffer_sc, input_items[0], d_consumed_samples * sizeof(lv_16sc_t));
}
else
{
memcpy(d_data_buffer, input_items[0], d_fft_size * sizeof(gr_complex));
memcpy(d_data_buffer, input_items[0], d_consumed_samples * sizeof(gr_complex));
}
if (acq_parameters.blocking)
{
@ -742,7 +859,7 @@ int pcps_acquisition::general_work(int noutput_items __attribute__((unused)),
gr::thread::thread d_worker(&pcps_acquisition::acquisition_core, this, d_sample_counter);
d_worker_active = true;
}
d_sample_counter += d_fft_size;
d_sample_counter += d_consumed_samples;
consume_each(1);
break;
}

View File

@ -95,24 +95,33 @@ private:
void dump_results(int effective_fft_size);
float first_vs_second_peak_statistic(uint32_t& indext, int& doppler, unsigned int num_doppler_bins, int doppler_max, int doppler_step);
float max_to_input_power_statistic(uint32_t& indext, int& doppler, float input_power, unsigned int num_doppler_bins, int doppler_max, int doppler_step);
Acq_Conf acq_parameters;
bool d_active;
bool d_worker_active;
bool d_cshort;
bool d_step_two;
bool d_use_CFAR_algorithm_flag;
int d_positive_acq;
float d_threshold;
float d_mag;
float d_input_power;
float d_test_statistics;
float* d_magnitude;
float** d_magnitude_grid;
float* d_tmp_buffer;
gr_complex* d_input_signal;
uint32_t d_samplesPerChip;
long d_old_freq;
int d_state;
unsigned int d_channel;
unsigned int d_doppler_step;
float d_doppler_center_step_two;
unsigned int d_well_count;
unsigned int d_num_noncoherent_integrations_counter;
unsigned int d_fft_size;
unsigned int d_consumed_samples;
unsigned int d_num_doppler_bins;
unsigned long int d_sample_counter;
gr_complex** d_grid_doppler_wipeoffs;
@ -150,7 +159,7 @@ public:
}
/*!
* \brief Initializes acquisition algorithm.
* \brief Initializes acquisition algorithm and reserves memory.
*/
void init();

View File

@ -40,46 +40,41 @@
#include <volk_gnsssdr/volk_gnsssdr.h>
#include <algorithm> // std::rotate, std::fill_n
#include <sstream>
#include <matio.h>
using google::LogMessage;
pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc(
int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min,
long fs_in, int samples_per_ms, bool dump,
std::string dump_filename)
pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc(const Acq_Conf &conf_)
{
return pcps_acquisition_fine_doppler_cc_sptr(
new pcps_acquisition_fine_doppler_cc(max_dwells, sampled_ms, doppler_max, doppler_min,
fs_in, samples_per_ms, dump, dump_filename));
new pcps_acquisition_fine_doppler_cc(conf_));
}
pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(
int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min,
long fs_in, int samples_per_ms, bool dump,
std::string dump_filename) : gr::block("pcps_acquisition_fine_doppler_cc",
pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(const Acq_Conf &conf_)
: gr::block("pcps_acquisition_fine_doppler_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(0, 0, sizeof(gr_complex)))
{
this->message_port_register_out(pmt::mp("events"));
acq_parameters = conf_;
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_sampled_ms = sampled_ms;
d_config_doppler_max = doppler_max;
d_config_doppler_min = doppler_min;
d_fft_size = d_sampled_ms * d_samples_per_ms;
d_fs_in = conf_.fs_in;
d_samples_per_ms = conf_.samples_per_ms;
d_config_doppler_max = conf_.doppler_max;
d_fft_size = d_samples_per_ms;
// HS Acquisition
d_max_dwells = max_dwells;
d_max_dwells = conf_.max_dwells;
d_gnuradio_forecast_samples = d_fft_size;
d_input_power = 0.0;
d_state = 0;
d_carrier = static_cast<gr_complex *>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
d_fft_codes = static_cast<gr_complex *>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
d_magnitude = static_cast<float *>(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment()));
d_10_ms_buffer = static_cast<gr_complex *>(volk_gnsssdr_malloc(50 * d_samples_per_ms * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
@ -87,10 +82,10 @@ pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(
d_ifft = new gr::fft::fft_complex(d_fft_size, false);
// For dumping samples into a file
d_dump = dump;
d_dump_filename = dump_filename;
d_dump = conf_.dump;
d_dump_filename = conf_.dump_filename;
d_doppler_resolution = 0;
d_n_samples_in_buffer = 0;
d_threshold = 0;
d_num_doppler_points = 0;
d_doppler_step = 0;
@ -102,21 +97,46 @@ pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(
d_test_statistics = 0;
d_well_count = 0;
d_channel = 0;
d_positive_acq = 0;
d_dump_number = 0;
d_dump_channel = 0; // this implementation can only produce dumps in channel 0
//todo: migrate config parameters to the unified acquisition config class
}
// Finds next power of two
// for n. If n itself is a
// power of two then returns n
unsigned int pcps_acquisition_fine_doppler_cc::nextPowerOf2(unsigned int n)
{
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
void pcps_acquisition_fine_doppler_cc::set_doppler_step(unsigned int doppler_step)
{
d_doppler_step = doppler_step;
// Create the search grid array
d_num_doppler_points = floor(std::abs(d_config_doppler_max - d_config_doppler_min) / d_doppler_step);
d_num_doppler_points = floor(std::abs(2 * d_config_doppler_max) / d_doppler_step);
d_grid_data = new float *[d_num_doppler_points];
for (int i = 0; i < d_num_doppler_points; i++)
{
d_grid_data[i] = static_cast<float *>(volk_gnsssdr_malloc(d_fft_size * sizeof(float), volk_gnsssdr_get_alignment()));
}
if (d_dump)
{
grid_ = arma::fmat(d_fft_size, d_num_doppler_points, arma::fill::zeros);
}
update_carrier_wipeoff();
}
@ -138,12 +158,9 @@ pcps_acquisition_fine_doppler_cc::~pcps_acquisition_fine_doppler_cc()
volk_gnsssdr_free(d_carrier);
volk_gnsssdr_free(d_fft_codes);
volk_gnsssdr_free(d_magnitude);
volk_gnsssdr_free(d_10_ms_buffer);
delete d_ifft;
delete d_fft_if;
if (d_dump)
{
d_dump_file.close();
}
free_grid_memory();
}
@ -167,7 +184,6 @@ void pcps_acquisition_fine_doppler_cc::init()
d_gnss_synchro->Acq_delay_samples = 0.0;
d_gnss_synchro->Acq_doppler_hz = 0.0;
d_gnss_synchro->Acq_samplestamp_samples = 0;
d_input_power = 0.0;
d_state = 0;
}
@ -187,6 +203,7 @@ void pcps_acquisition_fine_doppler_cc::reset_grid()
d_well_count = 0;
for (int i = 0; i < d_num_doppler_points; i++)
{
//todo: use memset here
for (unsigned int j = 0; j < d_fft_size; j++)
{
d_grid_data[i][j] = 0.0;
@ -203,7 +220,7 @@ void pcps_acquisition_fine_doppler_cc::update_carrier_wipeoff()
d_grid_doppler_wipeoffs = new gr_complex *[d_num_doppler_points];
for (int doppler_index = 0; doppler_index < d_num_doppler_points; doppler_index++)
{
doppler_hz = d_config_doppler_min + d_doppler_step * doppler_index;
doppler_hz = d_doppler_step * doppler_index - d_config_doppler_max;
// doppler search steps
// compute the carrier doppler wipe-off signal and store it
phase_step_rad = static_cast<float>(GPS_TWO_PI) * doppler_hz / static_cast<float>(d_fs_in);
@ -215,52 +232,70 @@ void pcps_acquisition_fine_doppler_cc::update_carrier_wipeoff()
}
double pcps_acquisition_fine_doppler_cc::search_maximum()
double pcps_acquisition_fine_doppler_cc::compute_CAF()
{
float magt = 0.0;
float fft_normalization_factor;
float firstPeak = 0.0;
int index_doppler = 0;
uint32_t tmp_intex_t = 0;
uint32_t index_time = 0;
// Look for correlation peaks in the results ==============================
// Find the highest peak and compare it to the second highest peak
// The second peak is chosen not closer than 1 chip to the highest peak
//--- Find the correlation peak and the carrier frequency --------------
for (int i = 0; i < d_num_doppler_points; i++)
{
volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_grid_data[i], d_fft_size);
if (d_grid_data[i][tmp_intex_t] > magt)
if (d_grid_data[i][tmp_intex_t] > firstPeak)
{
magt = d_grid_data[i][tmp_intex_t];
//std::cout<<magt<<std::endl;
firstPeak = d_grid_data[i][tmp_intex_t];
index_doppler = i;
index_time = tmp_intex_t;
}
// Record results to file if required
if (d_dump and d_channel == d_dump_channel)
{
memcpy(grid_.colptr(i), d_grid_data[i], sizeof(float) * d_fft_size);
}
}
// Normalize the maximum value to correct the scale factor introduced by FFTW
fft_normalization_factor = static_cast<float>(d_fft_size) * static_cast<float>(d_fft_size);
magt = magt / (fft_normalization_factor * fft_normalization_factor);
// -- - Find 1 chip wide code phase exclude range around the peak
uint32_t samplesPerChip = ceil(GPS_L1_CA_CHIP_PERIOD * static_cast<float>(this->d_fs_in));
int32_t excludeRangeIndex1 = index_time - samplesPerChip;
int32_t excludeRangeIndex2 = index_time + samplesPerChip;
// -- - Correct code phase exclude range if the range includes array boundaries
if (excludeRangeIndex1 < 0)
{
excludeRangeIndex1 = d_fft_size + excludeRangeIndex1;
}
else if (excludeRangeIndex2 >= static_cast<int>(d_fft_size))
{
excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size;
}
int32_t idx = excludeRangeIndex1;
do
{
d_grid_data[index_doppler][idx] = 0.0;
idx++;
if (idx == static_cast<int>(d_fft_size)) idx = 0;
}
while (idx != excludeRangeIndex2);
//--- Find the second highest correlation peak in the same freq. bin ---
volk_gnsssdr_32f_index_max_32u(&tmp_intex_t, d_grid_data[index_doppler], d_fft_size);
float secondPeak = d_grid_data[index_doppler][tmp_intex_t];
// 5- Compute the test statistics and compare to the threshold
d_test_statistics = magt / (d_input_power * std::sqrt(d_well_count));
d_test_statistics = firstPeak / secondPeak;
// 4- record the maximum peak and the associated synchronization parameters
d_gnss_synchro->Acq_delay_samples = static_cast<double>(index_time);
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(index_doppler * d_doppler_step + d_config_doppler_min);
d_gnss_synchro->Acq_doppler_hz = static_cast<double>(index_doppler * d_doppler_step - d_config_doppler_max);
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// Record results to file if required
if (d_dump)
{
std::stringstream filename;
std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write
filename.str("");
filename << "../data/test_statistics_" << d_gnss_synchro->System
<< "_" << d_gnss_synchro->Signal << "_sat_"
<< d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write(reinterpret_cast<char *>(d_grid_data[index_doppler]), n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
}
return d_test_statistics;
}
@ -296,6 +331,7 @@ int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_cons
// doppler search steps
// Perform the carrier wipe-off
volk_32fc_x2_multiply_32fc(d_fft_if->get_inbuf(), in, d_grid_doppler_wipeoffs[doppler_index], d_fft_size);
// 3- Perform the FFT-based convolution (parallel time search)
// Compute the FFT of the carrier wiped--off incoming signal
d_fft_if->execute();
@ -308,29 +344,38 @@ int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_cons
d_ifft->execute();
// save the grid matrix delay file
volk_32fc_magnitude_squared_32f(p_tmp_vector, d_ifft->get_outbuf(), d_fft_size);
const float *old_vector = d_grid_data[doppler_index];
volk_32f_x2_add_32f(d_grid_data[doppler_index], old_vector, p_tmp_vector, d_fft_size);
//accumulate grid values
volk_32f_x2_add_32f(d_grid_data[doppler_index], d_grid_data[doppler_index], p_tmp_vector, d_fft_size);
}
volk_gnsssdr_free(p_tmp_vector);
return d_fft_size;
//debug
// std::cout << "iff=[";
// for (int n = 0; n < d_fft_size; n++)
// {
// std::cout << std::real(d_ifft->get_outbuf()[n]) << "+" << std::imag(d_ifft->get_outbuf()[n]) << "i,";
// }
// std::cout << "]\n";
// getchar();
}
int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star &input_items)
int pcps_acquisition_fine_doppler_cc::estimate_Doppler()
{
// Direct FFT
int zero_padding_factor = 2;
int fft_size_extended = d_fft_size * zero_padding_factor;
int zero_padding_factor = 8;
int prn_replicas = 10;
int signal_samples = prn_replicas * d_fft_size;
//int fft_size_extended = nextPowerOf2(signal_samples * zero_padding_factor);
int fft_size_extended = signal_samples * zero_padding_factor;
gr::fft::fft_complex *fft_operator = new gr::fft::fft_complex(fft_size_extended, true);
//zero padding the entire vector
std::fill_n(fft_operator->get_inbuf(), fft_size_extended, gr_complex(0.0, 0.0));
//1. generate local code aligned with the acquisition code phase estimation
gr_complex *code_replica = static_cast<gr_complex *>(volk_gnsssdr_malloc(d_fft_size * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
gr_complex *code_replica = static_cast<gr_complex *>(volk_gnsssdr_malloc(signal_samples * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
gps_l1_ca_code_gen_complex_sampled(code_replica, d_gnss_synchro->PRN, d_fs_in, 0);
@ -342,10 +387,12 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star
std::rotate(code_replica, code_replica + (d_fft_size - shift_index), code_replica + d_fft_size - 1);
}
for (int n = 0; n < prn_replicas - 1; n++)
{
memcpy(&code_replica[(n + 1) * d_fft_size], code_replica, d_fft_size * sizeof(gr_complex));
}
//2. Perform code wipe-off
const gr_complex *in = reinterpret_cast<const gr_complex *>(input_items[0]); //Get the input samples pointer
volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), in, code_replica, d_fft_size);
volk_32fc_x2_multiply_32fc(fft_operator->get_inbuf(), d_10_ms_buffer, code_replica, signal_samples);
// 3. Perform the FFT (zero padded!)
fft_operator->execute();
@ -360,8 +407,8 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star
//case even
int counter = 0;
float *fftFreqBins = new float[fft_size_extended];
float fftFreqBins[fft_size_extended];
std::fill_n(fftFreqBins, fft_size_extended, 0.0);
for (int k = 0; k < (fft_size_extended / 2); k++)
@ -372,7 +419,7 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star
for (int k = fft_size_extended / 2; k > 0; k--)
{
fftFreqBins[counter] = ((-static_cast<float>(d_fs_in) / 2) * static_cast<float>(k)) / (static_cast<float>(fft_size_extended) / 2.0);
fftFreqBins[counter] = ((-static_cast<float>(d_fs_in) / 2.0) * static_cast<float>(k)) / (static_cast<float>(fft_size_extended) / 2.0);
counter++;
}
@ -386,44 +433,50 @@ int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star
{
DLOG(INFO) << "Abs(Grid Doppler - FFT Doppler)=" << std::abs(fftFreqBins[tmp_index_freq] - d_gnss_synchro->Acq_doppler_hz);
DLOG(INFO) << "Error estimating fine frequency Doppler";
//debug log
//
// std::cout<<"FFT maximum present at "<<fftFreqBins[tmp_index_freq]<<" [Hz]"<<std::endl;
// std::stringstream filename;
// std::streamsize n = sizeof(gr_complex) * (d_fft_size);
//
// filename.str("");
// filename << "../data/code_prn_" << d_gnss_synchro->PRN << ".dat";
// d_dump_file.open(filename.str().c_str(), std::ios::out
// | std::ios::binary);
// d_dump_file.write(reinterpret_cast<char*>(code_replica), n); //write directly |abs(x)|^2 in this Doppler bin?
// d_dump_file.close();
//
// filename.str("");
// filename << "../data/signal_prn_" << d_gnss_synchro->PRN << ".dat";
// d_dump_file.open(filename.str().c_str(), std::ios::out
// | std::ios::binary);
// d_dump_file.write(reinterpret_cast<char*>(in), n); //write directly |abs(x)|^2 in this Doppler bin?
// d_dump_file.close();
//
//
// n = sizeof(float) * (fft_size_extended);
// filename.str("");
// filename << "../data/fft_prn_" << d_gnss_synchro->PRN << ".dat";
// d_dump_file.open(filename.str().c_str(), std::ios::out
// | std::ios::binary);
// d_dump_file.write(reinterpret_cast<char*>(p_tmp_vector), n); //write directly |abs(x)|^2 in this Doppler bin?
// d_dump_file.close();
}
// free memory!!
delete fft_operator;
volk_gnsssdr_free(code_replica);
volk_gnsssdr_free(p_tmp_vector);
delete[] fftFreqBins;
return d_fft_size;
}
// Called by gnuradio to enable drivers, etc for i/o devices.
bool pcps_acquisition_fine_doppler_cc::start()
{
d_sample_counter = 0;
return true;
}
void pcps_acquisition_fine_doppler_cc::set_state(int state)
{
//gr::thread::scoped_lock lock(d_setlock); // require mutex with work function called by the scheduler
d_state = state;
if (d_state == 1)
{
d_gnss_synchro->Acq_delay_samples = 0.0;
d_gnss_synchro->Acq_doppler_hz = 0.0;
d_gnss_synchro->Acq_samplestamp_samples = 0;
d_well_count = 0;
d_test_statistics = 0.0;
d_active = true;
reset_grid();
}
else if (d_state == 0)
{
}
else
{
LOG(ERROR) << "State can only be set to 0 or 1";
}
}
int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items __attribute__((unused)))
@ -442,29 +495,36 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
* S5. Negative_Acq: Send message and stop acq -> S0
*/
int samples_remaining;
switch (d_state)
{
case 0: // S0. StandBy
//DLOG(INFO) <<"S0"<<std::endl;
if (d_active == true)
{
reset_grid();
d_n_samples_in_buffer = 0;
d_state = 1;
}
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += d_fft_size; // sample counter
consume_each(d_fft_size);
}
break;
case 1: // S1. ComputeGrid
//DLOG(INFO) <<"S1"<<std::endl;
compute_and_accumulate_grid(input_items);
memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast<const gr_complex *>(input_items[0]), d_fft_size * sizeof(gr_complex));
d_n_samples_in_buffer += d_fft_size;
d_well_count++;
if (d_well_count >= d_max_dwells)
{
d_state = 2;
}
d_sample_counter += d_fft_size; // sample counter
consume_each(d_fft_size);
break;
case 2: // Compute test statistics and decide
//DLOG(INFO) <<"S2"<<std::endl;
d_input_power = estimate_input_power(input_items);
d_test_statistics = search_maximum();
d_test_statistics = compute_CAF();
if (d_test_statistics > d_threshold)
{
d_state = 3; //perform fine doppler estimation
@ -472,16 +532,34 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
else
{
d_state = 5; //negative acquisition
d_n_samples_in_buffer = 0;
}
break;
case 3: // Fine doppler estimation
//DLOG(INFO) <<"S3"<<std::endl;
DLOG(INFO) << "Performing fine Doppler estimation";
estimate_Doppler(input_items); //disabled in repo
samples_remaining = 10 * d_samples_per_ms - d_n_samples_in_buffer;
if (samples_remaining > noutput_items)
{
memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast<const gr_complex *>(input_items[0]), noutput_items * sizeof(gr_complex));
d_n_samples_in_buffer += noutput_items;
d_sample_counter += noutput_items; // sample counter
consume_each(noutput_items);
}
else
{
if (samples_remaining > 0)
{
memcpy(&d_10_ms_buffer[d_n_samples_in_buffer], reinterpret_cast<const gr_complex *>(input_items[0]), samples_remaining * sizeof(gr_complex));
d_sample_counter += samples_remaining; // sample counter
consume_each(samples_remaining);
}
estimate_Doppler(); //disabled in repo
d_n_samples_in_buffer = 0;
d_state = 4;
}
break;
case 4: // Positive_Acq
//DLOG(INFO) <<"S4"<<std::endl;
DLOG(INFO) << "positive acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
@ -489,15 +567,23 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "input signal power " << d_input_power;
d_positive_acq = 1;
d_active = false;
// Record results to file if required
if (d_dump and d_channel == d_dump_channel)
{
dump_results(d_fft_size);
}
// Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
this->message_port_pub(pmt::mp("events"), pmt::from_long(1));
d_state = 0;
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += noutput_items; // sample counter
consume_each(noutput_items);
}
break;
case 5: // Negative_Acq
//DLOG(INFO) <<"S5"<<std::endl;
DLOG(INFO) << "negative acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
@ -505,20 +591,108 @@ int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "input signal power " << d_input_power;
d_positive_acq = 0;
d_active = false;
// Record results to file if required
if (d_dump and d_channel == d_dump_channel)
{
dump_results(d_fft_size);
}
// Send message to channel port //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
this->message_port_pub(pmt::mp("events"), pmt::from_long(2));
d_state = 0;
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += noutput_items; // sample counter
consume_each(noutput_items);
}
break;
default:
d_state = 0;
if (!acq_parameters.blocking_on_standby)
{
d_sample_counter += noutput_items; // sample counter
consume_each(noutput_items);
}
break;
}
//DLOG(INFO)<<"d_sample_counter="<<d_sample_counter<<std::endl;
d_sample_counter += d_fft_size; // sample counter
consume_each(d_fft_size);
return noutput_items;
return 0;
}
void pcps_acquisition_fine_doppler_cc::dump_results(int effective_fft_size)
{
d_dump_number++;
std::string filename = d_dump_filename;
filename.append("_");
filename.append(1, d_gnss_synchro->System);
filename.append("_");
filename.append(1, d_gnss_synchro->Signal[0]);
filename.append(1, d_gnss_synchro->Signal[1]);
filename.append("_ch_");
filename.append(std::to_string(d_channel));
filename.append("_");
filename.append(std::to_string(d_dump_number));
filename.append("_sat_");
filename.append(std::to_string(d_gnss_synchro->PRN));
filename.append(".mat");
mat_t *matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT73);
if (matfp == NULL)
{
std::cout << "Unable to create or open Acquisition dump file" << std::endl;
d_dump = false;
}
else
{
size_t dims[2] = {static_cast<size_t>(effective_fft_size), static_cast<size_t>(d_num_doppler_points)};
matvar_t *matvar = Mat_VarCreate("acq_grid", MAT_C_SINGLE, MAT_T_SINGLE, 2, dims, grid_.memptr(), 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
dims[0] = static_cast<size_t>(1);
dims[1] = static_cast<size_t>(1);
matvar = Mat_VarCreate("doppler_max", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_config_doppler_max, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("doppler_step", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_doppler_step, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("d_positive_acq", MAT_C_INT32, MAT_T_INT32, 1, dims, &d_positive_acq, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
float aux = static_cast<float>(d_gnss_synchro->Acq_doppler_hz);
matvar = Mat_VarCreate("acq_doppler_hz", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
aux = static_cast<float>(d_gnss_synchro->Acq_delay_samples);
matvar = Mat_VarCreate("acq_delay_samples", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("test_statistic", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_test_statistics, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("threshold", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &d_threshold, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
aux = 0.0;
matvar = Mat_VarCreate("input_power", MAT_C_SINGLE, MAT_T_SINGLE, 1, dims, &aux, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("sample_counter", MAT_C_UINT64, MAT_T_UINT64, 1, dims, &d_sample_counter, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("PRN", MAT_C_UINT32, MAT_T_UINT32, 1, dims, &d_gnss_synchro->PRN, 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
Mat_Close(matfp);
}
}

View File

@ -1,8 +1,9 @@
/*!
* \file pcps_acquisition_fine_doppler_acquisition_cc.h
* \brief This class implements a Parallel Code Phase Search Acquisition with multi-dwells and fine Doppler estimation
* for GPS L1 C/A signal
*
* Acquisition strategy (Kay Borre book + CFAR threshold).
* Acquisition strategy (Kay Borre book).
* <ol>
* <li> Compute the input signal power estimation
* <li> Doppler serial search loop
@ -49,6 +50,8 @@
#define GNSS_SDR_PCPS_ACQUISITION_FINE_DOPPLER_CC_H_
#include "gnss_synchro.h"
#include "acq_conf.h"
#include <armadillo>
#include <gnuradio/block.h>
#include <gnuradio/gr_complex.h>
#include <gnuradio/fft/fft.h>
@ -61,59 +64,44 @@ typedef boost::shared_ptr<pcps_acquisition_fine_doppler_cc>
pcps_acquisition_fine_doppler_cc_sptr;
pcps_acquisition_fine_doppler_cc_sptr
pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long fs_in, int samples_per_ms,
bool dump, std::string dump_filename);
pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_);
/*!
* \brief This class implements a Parallel Code Phase Search Acquisition.
*
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
* Algorithm 1, for a pseudocode description of this implementation.
*/
class pcps_acquisition_fine_doppler_cc : public gr::block
{
private:
friend pcps_acquisition_fine_doppler_cc_sptr
pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long fs_in,
int samples_per_ms, bool dump,
std::string dump_filename);
pcps_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long fs_in,
int samples_per_ms, bool dump,
std::string dump_filename);
void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift,
int doppler_offset);
pcps_make_acquisition_fine_doppler_cc(const Acq_Conf& conf_);
pcps_acquisition_fine_doppler_cc(const Acq_Conf& conf_);
int compute_and_accumulate_grid(gr_vector_const_void_star& input_items);
int estimate_Doppler(gr_vector_const_void_star& input_items);
int estimate_Doppler();
float estimate_input_power(gr_vector_const_void_star& input_items);
double search_maximum();
double compute_CAF();
void reset_grid();
void update_carrier_wipeoff();
void free_grid_memory();
bool start();
Acq_Conf acq_parameters;
long d_fs_in;
int d_samples_per_ms;
int d_max_dwells;
unsigned int d_doppler_resolution;
int d_gnuradio_forecast_samples;
float d_threshold;
std::string d_satellite_str;
int d_config_doppler_max;
int d_config_doppler_min;
int d_num_doppler_points;
int d_doppler_step;
unsigned int d_sampled_ms;
unsigned int d_fft_size;
unsigned long int d_sample_counter;
gr_complex* d_carrier;
gr_complex* d_fft_codes;
gr_complex* d_10_ms_buffer;
float* d_magnitude;
float** d_grid_data;
@ -124,17 +112,22 @@ private:
Gnss_Synchro* d_gnss_synchro;
unsigned int d_code_phase;
float d_doppler_freq;
float d_input_power;
float d_test_statistics;
std::ofstream d_dump_file;
int d_positive_acq;
int d_state;
bool d_active;
int d_well_count;
int d_n_samples_in_buffer;
bool d_dump;
unsigned int d_channel;
std::string d_dump_filename;
arma::fmat grid_;
long int d_dump_number;
unsigned int d_dump_channel;
public:
/*!
* \brief Default destructor.
@ -187,6 +180,7 @@ public:
inline void set_channel(unsigned int channel)
{
d_channel = channel;
d_dump_channel = d_channel;
}
/*!
@ -214,6 +208,13 @@ public:
*/
void set_doppler_step(unsigned int doppler_step);
/*!
* \brief If set to 1, ensures that acquisition starts at the
* first available sample.
* \param state - int=1 forces start of acquisition
*/
void set_state(int state);
/*!
* \brief Parallel Code Phase Search Acquisition signal processing.
*/
@ -222,6 +223,14 @@ public:
gr_vector_void_star& output_items);
void forecast(int noutput_items, gr_vector_int& ninput_items_required);
/*!
* \brief Obtains the next power of 2 greater or equal to the input parameter
* \param n - Integer value to obtain the next power of 2.
*/
unsigned int nextPowerOf2(unsigned int n);
void dump_results(int effective_fft_size);
};
#endif /* pcps_acquisition_fine_doppler_cc*/

View File

@ -35,13 +35,15 @@ Acq_Conf::Acq_Conf()
{
/* PCPS acquisition configuration */
sampled_ms = 0;
ms_per_code = 0;
max_dwells = 0;
samples_per_chip = 0;
doppler_max = 0;
num_doppler_bins_step2 = 0;
doppler_step2 = 0.0;
fs_in = 0;
samples_per_ms = 0;
samples_per_code = 0;
samples_per_ms = 0.0;
samples_per_code = 0.0;
bit_transition_flag = false;
use_CFAR_algorithm_flag = false;
dump = false;

View File

@ -40,13 +40,15 @@ class Acq_Conf
public:
/* PCPS Acquisition configuration */
unsigned int sampled_ms;
unsigned int ms_per_code;
unsigned int samples_per_chip;
unsigned int max_dwells;
unsigned int doppler_max;
unsigned int num_doppler_bins_step2;
float doppler_step2;
long fs_in;
int samples_per_ms;
int samples_per_code;
float samples_per_ms;
float samples_per_code;
bool bit_transition_flag;
bool use_CFAR_algorithm_flag;
bool dump;

View File

@ -144,6 +144,7 @@ void gps_l1_ca_code_gen_complex(std::complex<float>* _dest, signed int _prn, uns
/*
* Generates complex GPS L1 C/A code for the desired SV ID and sampled to specific sampling frequency
* NOTICE: the number of samples is rounded towards zero (integer truncation)
*/
void gps_l1_ca_code_gen_complex_sampled(std::complex<float>* _dest, unsigned int _prn, signed int _fs, unsigned int _chip_shift)
{

View File

@ -83,26 +83,20 @@ gps_l1_ca_telemetry_decoder_cc::gps_l1_ca_telemetry_decoder_cc(
}
}
d_stat = 0;
d_symbol_accumulator = 0;
d_symbol_accumulator_counter = 0;
d_frame_bit_index = 0;
d_flag_frame_sync = false;
d_GPS_frame_4bytes = 0;
d_prev_GPS_frame_4bytes = 0;
d_flag_parity = false;
d_TOW_at_Preamble_ms = 0;
flag_TOW_set = false;
d_flag_preamble = false;
d_flag_new_tow_available = false;
d_word_number = 0;
d_channel = 0;
flag_PLL_180_deg_phase_locked = false;
d_preamble_time_samples = 0;
d_TOW_at_current_symbol_ms = 0;
d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS + 1); // Change fixed buffer size
d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size
d_symbol_history.clear(); // Clear all the elements in the buffer
d_make_correlation = true;
d_symbol_counter_corr = 0;
d_crc_error_synchronization_counter = 0;
d_current_subframe_symbol = 0;
}
@ -150,9 +144,10 @@ bool gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(unsigned int gpsword)
void gps_l1_ca_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satellite)
{
d_nav.reset();
d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN());
DLOG(INFO) << "Setting decoder Finite State Machine to satellite " << d_satellite;
d_GPS_FSM.i_satellite_PRN = d_satellite.get_PRN();
d_nav.i_satellite_PRN = d_satellite.get_PRN();
DLOG(INFO) << "Navigation Satellite set to " << d_satellite;
}
@ -160,7 +155,7 @@ void gps_l1_ca_telemetry_decoder_cc::set_satellite(const Gnss_Satellite &satelli
void gps_l1_ca_telemetry_decoder_cc::set_channel(int channel)
{
d_channel = channel;
d_GPS_FSM.i_channel_ID = channel;
d_nav.i_channel_ID = channel;
DLOG(INFO) << "Navigation channel set to " << channel;
// ############# ENABLE DATA FILE LOG #################
if (d_dump == true)
@ -186,10 +181,127 @@ void gps_l1_ca_telemetry_decoder_cc::set_channel(int channel)
}
bool gps_l1_ca_telemetry_decoder_cc::decode_subframe()
{
char subframe[GPS_SUBFRAME_LENGTH];
int symbol_accumulator_counter = 0;
int frame_bit_index = 0;
int word_index = 0;
uint32_t GPS_frame_4bytes = 0;
float symbol_accumulator = 0;
bool subframe_synchro_confirmation = false;
bool CRC_ok = true;
for (int n = 0; n < GPS_SUBFRAME_MS; n++)
{
//******* SYMBOL TO BIT *******
// extended correlation to bit period is enabled in tracking!
symbol_accumulator += d_subframe_symbols[n]; // accumulate the input value in d_symbol_accumulator
symbol_accumulator_counter++;
if (symbol_accumulator_counter == 20)
{
//symbol to bit
if (symbol_accumulator > 0) GPS_frame_4bytes += 1; //insert the telemetry bit in LSB
symbol_accumulator = 0;
symbol_accumulator_counter = 0;
//******* bits to words ******
frame_bit_index++;
if (frame_bit_index == 30)
{
frame_bit_index = 0;
// parity check
// Each word in wordbuff is composed of:
// Bits 0 to 29 = the GPS data word
// Bits 30 to 31 = 2 LSBs of the GPS word ahead.
// prepare the extended frame [-2 -1 0 ... 30]
if (d_prev_GPS_frame_4bytes & 0x00000001)
{
GPS_frame_4bytes = GPS_frame_4bytes | 0x40000000;
}
if (d_prev_GPS_frame_4bytes & 0x00000002)
{
GPS_frame_4bytes = GPS_frame_4bytes | 0x80000000;
}
/* Check that the 2 most recently logged words pass parity. Have to first
invert the data bits according to bit 30 of the previous word. */
if (GPS_frame_4bytes & 0x40000000)
{
GPS_frame_4bytes ^= 0x3FFFFFC0; // invert the data bits (using XOR)
}
if (gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(GPS_frame_4bytes))
{
subframe_synchro_confirmation = true;
}
else
{
//std::cout << "word invalid sat " << this->d_satellite << std::endl;
CRC_ok = false;
}
//add word to subframe
// insert the word in the correct position of the subframe
std::memcpy(&subframe[word_index * GPS_WORD_LENGTH], &GPS_frame_4bytes, sizeof(uint32_t));
word_index++;
d_prev_GPS_frame_4bytes = GPS_frame_4bytes; // save the actual frame
GPS_frame_4bytes = 0;
}
else
{
GPS_frame_4bytes <<= 1; //shift 1 bit left the telemetry word
}
}
}
//decode subframe
// NEW GPS SUBFRAME HAS ARRIVED!
if (CRC_ok)
{
int subframe_ID = d_nav.subframe_decoder(subframe); //decode the subframe
std::cout << "New GPS NAV message received in channel " << this->d_channel << ": "
<< "subframe "
<< subframe_ID << " from satellite "
<< Gnss_Satellite(std::string("GPS"), d_nav.i_satellite_PRN) << std::endl;
switch (subframe_ID)
{
case 3: //we have a new set of ephemeris data for the current SV
if (d_nav.satellite_validation() == true)
{
// get ephemeris object for this SV (mandatory)
std::shared_ptr<Gps_Ephemeris> tmp_obj = std::make_shared<Gps_Ephemeris>(d_nav.get_ephemeris());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
break;
case 4: // Possible IONOSPHERE and UTC model update (page 18)
if (d_nav.flag_iono_valid == true)
{
std::shared_ptr<Gps_Iono> tmp_obj = std::make_shared<Gps_Iono>(d_nav.get_iono());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
if (d_nav.flag_utc_model_valid == true)
{
std::shared_ptr<Gps_Utc_Model> tmp_obj = std::make_shared<Gps_Utc_Model>(d_nav.get_utc_model());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
break;
case 5:
// get almanac (if available)
//TODO: implement almanac reader in navigation_message
break;
default:
break;
}
d_flag_new_tow_available = true;
}
return subframe_synchro_confirmation;
}
int gps_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)),
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
{
int corr_value = 0;
int preamble_diff_ms = 0;
Gnss_Synchro **out = reinterpret_cast<Gnss_Synchro **>(&output_items[0]); // Get the output buffer pointer
@ -198,15 +310,25 @@ int gps_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__
Gnss_Synchro current_symbol; //structure to save the synchronization information and send the output object to the next block
//1. Copy the current tracking output
current_symbol = in[0][0];
//record the oldest subframe symbol before inserting a new symbol into the circular buffer
if (d_current_subframe_symbol < GPS_SUBFRAME_MS and d_symbol_history.size() > 0)
{
d_subframe_symbols[d_current_subframe_symbol] = d_symbol_history.at(0).Prompt_I;
d_current_subframe_symbol++;
}
d_symbol_history.push_back(current_symbol); //add new symbol to the symbol queue
consume_each(1);
unsigned int required_symbols = GPS_CA_PREAMBLE_LENGTH_SYMBOLS;
d_flag_preamble = false;
if ((d_symbol_history.size() > required_symbols) and (d_make_correlation or !d_flag_frame_sync))
{
//******* preamble correlation ********
int corr_value = 0;
if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync))
{
// std::cout << "-------\n";
for (unsigned int i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++)
{
if (d_symbol_history.at(i).Flag_valid_symbol_output == true)
@ -221,38 +343,27 @@ int gps_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__
}
}
}
if (std::abs(corr_value) >= GPS_CA_PREAMBLE_LENGTH_SYMBOLS)
{
d_symbol_counter_corr++;
}
}
//******* frame sync ******************
if (std::abs(corr_value) == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)
{
//TODO: Rewrite with state machine
if (d_stat == 0)
{
d_GPS_FSM.Event_gps_word_preamble();
//record the preamble sample stamp
d_preamble_time_samples = d_symbol_history.at(0).Tracking_sample_counter; // record the preamble sample stamp
DLOG(INFO) << "Preamble detection for SAT " << this->d_satellite << "d_symbol_history.at(0).Tracking_sample_counter=" << d_symbol_history.at(0).Tracking_sample_counter;
//sync the symbol to bits integrator
d_symbol_accumulator = 0;
d_symbol_accumulator_counter = 0;
d_frame_bit_index = 0;
d_stat = 1; // enter into frame pre-detection status
}
else if (d_stat == 1) //check 6 seconds of preamble separation
{
preamble_diff_ms = std::round(((static_cast<double>(d_symbol_history.at(0).Tracking_sample_counter) - d_preamble_time_samples) / static_cast<double>(d_symbol_history.at(0).fs)) * 1000.0);
if (std::abs(preamble_diff_ms - GPS_SUBFRAME_MS) < 1)
if (std::abs(preamble_diff_ms - GPS_SUBFRAME_MS) % GPS_SUBFRAME_MS == 0)
{
DLOG(INFO) << "Preamble confirmation for SAT " << this->d_satellite;
d_GPS_FSM.Event_gps_word_preamble();
d_flag_preamble = true;
d_make_correlation = false;
d_symbol_counter_corr = 0;
d_preamble_time_samples = d_symbol_history.at(0).Tracking_sample_counter; // record the PRN start sample index associated to the preamble
if (!d_flag_frame_sync)
{
@ -269,131 +380,46 @@ int gps_l1_ca_telemetry_decoder_cc::general_work(int noutput_items __attribute__
DLOG(INFO) << " Frame sync SAT " << this->d_satellite << " with preamble start at "
<< static_cast<double>(d_preamble_time_samples) / static_cast<double>(d_symbol_history.at(0).fs) << " [s]";
}
}
}
}
else
//try to decode the subframe:
if (decode_subframe() == false)
{
d_symbol_counter_corr++;
if (d_symbol_counter_corr > (GPS_SUBFRAME_MS - GPS_CA_TELEMETRY_SYMBOLS_PER_BIT))
d_crc_error_synchronization_counter++;
if (d_crc_error_synchronization_counter > 3)
{
d_make_correlation = true;
}
if (d_stat == 1)
{
preamble_diff_ms = round(((static_cast<double>(d_symbol_history.at(0).Tracking_sample_counter) - static_cast<double>(d_preamble_time_samples)) / static_cast<double>(d_symbol_history.at(0).fs)) * 1000.0);
if (preamble_diff_ms > GPS_SUBFRAME_MS + 1)
{
DLOG(INFO) << "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff_ms;
DLOG(INFO) << "TOO MANY CRC ERRORS: Lost of frame sync SAT " << this->d_satellite << std::endl;
d_stat = 0; //lost of frame sync
d_flag_frame_sync = false;
flag_TOW_set = false;
d_make_correlation = true;
d_symbol_counter_corr = 0;
d_crc_error_synchronization_counter = 0;
}
}
d_current_subframe_symbol = 0;
}
//******* SYMBOL TO BIT *******
if (d_symbol_history.at(0).Flag_valid_symbol_output == true)
{
// extended correlation to bit period is enabled in tracking!
d_symbol_accumulator += d_symbol_history.at(0).Prompt_I; // accumulate the input value in d_symbol_accumulator
d_symbol_accumulator_counter += d_symbol_history.at(0).correlation_length_ms;
}
if (d_symbol_accumulator_counter >= 20)
{
if (d_symbol_accumulator > 0)
{ //symbol to bit
d_GPS_frame_4bytes += 1; //insert the telemetry bit in LSB
}
d_symbol_accumulator = 0;
d_symbol_accumulator_counter = 0;
//******* bits to words ******
d_frame_bit_index++;
if (d_frame_bit_index == 30)
{
d_frame_bit_index = 0;
// parity check
// Each word in wordbuff is composed of:
// Bits 0 to 29 = the GPS data word
// Bits 30 to 31 = 2 LSBs of the GPS word ahead.
// prepare the extended frame [-2 -1 0 ... 30]
if (d_prev_GPS_frame_4bytes & 0x00000001)
{
d_GPS_frame_4bytes = d_GPS_frame_4bytes | 0x40000000;
}
if (d_prev_GPS_frame_4bytes & 0x00000002)
{
d_GPS_frame_4bytes = d_GPS_frame_4bytes | 0x80000000;
}
/* Check that the 2 most recently logged words pass parity. Have to first
invert the data bits according to bit 30 of the previous word. */
if (d_GPS_frame_4bytes & 0x40000000)
{
d_GPS_frame_4bytes ^= 0x3FFFFFC0; // invert the data bits (using XOR)
}
if (gps_l1_ca_telemetry_decoder_cc::gps_word_parityCheck(d_GPS_frame_4bytes))
{
memcpy(&d_GPS_FSM.d_GPS_frame_4bytes, &d_GPS_frame_4bytes, sizeof(char) * 4);
//d_GPS_FSM.d_preamble_time_ms = d_preamble_time_seconds * 1000.0;
d_GPS_FSM.Event_gps_word_valid();
// send TLM data to PVT using asynchronous message queues
if (d_GPS_FSM.d_flag_new_subframe == true)
{
switch (d_GPS_FSM.d_subframe_ID)
{
case 3: //we have a new set of ephemeris data for the current SV
if (d_GPS_FSM.d_nav.satellite_validation() == true)
{
// get ephemeris object for this SV (mandatory)
std::shared_ptr<Gps_Ephemeris> tmp_obj = std::make_shared<Gps_Ephemeris>(d_GPS_FSM.d_nav.get_ephemeris());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
break;
case 4: // Possible IONOSPHERE and UTC model update (page 18)
if (d_GPS_FSM.d_nav.flag_iono_valid == true)
{
std::shared_ptr<Gps_Iono> tmp_obj = std::make_shared<Gps_Iono>(d_GPS_FSM.d_nav.get_iono());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
if (d_GPS_FSM.d_nav.flag_utc_model_valid == true)
{
std::shared_ptr<Gps_Utc_Model> tmp_obj = std::make_shared<Gps_Utc_Model>(d_GPS_FSM.d_nav.get_utc_model());
this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj));
}
break;
case 5:
// get almanac (if available)
//TODO: implement almanac reader in navigation_message
break;
default:
break;
}
d_GPS_FSM.clear_flag_new_subframe();
d_flag_new_tow_available = true;
}
d_flag_parity = true;
}
else
{
d_GPS_FSM.Event_gps_word_invalid();
d_flag_parity = false;
}
d_prev_GPS_frame_4bytes = d_GPS_frame_4bytes; // save the actual frame
d_GPS_frame_4bytes = d_GPS_frame_4bytes & 0;
}
else
if (d_stat == 1)
{
d_GPS_frame_4bytes <<= 1; //shift 1 bit left the telemetry word
preamble_diff_ms = round(((static_cast<double>(d_symbol_history.at(0).Tracking_sample_counter) - static_cast<double>(d_preamble_time_samples)) / static_cast<double>(d_symbol_history.at(0).fs)) * 1000.0);
if (preamble_diff_ms > GPS_SUBFRAME_MS)
{
DLOG(INFO) << "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff_ms;
// std::cout << "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff_ms << std::endl;
d_stat = 0; //lost of frame sync
d_flag_frame_sync = false;
flag_TOW_set = false;
d_current_subframe_symbol = 0;
d_crc_error_synchronization_counter = 0;
}
}
}
//2. Add the telemetry decoder information
if (this->d_flag_preamble == true and d_flag_new_tow_available == true)
{
d_TOW_at_current_symbol_ms = static_cast<unsigned int>(d_GPS_FSM.d_nav.d_TOW) * 1000 + GPS_L1_CA_CODE_PERIOD_MS + GPS_CA_PREAMBLE_DURATION_MS;
d_TOW_at_current_symbol_ms = static_cast<unsigned int>(d_nav.d_TOW) * 1000 + GPS_L1_CA_CODE_PERIOD_MS + GPS_CA_PREAMBLE_DURATION_MS;
d_TOW_at_Preamble_ms = d_TOW_at_current_symbol_ms;
flag_TOW_set = true;
d_flag_new_tow_available = false;

View File

@ -32,7 +32,7 @@
#define GNSS_SDR_GPS_L1_CA_TELEMETRY_DECODER_CC_H
#include "GPS_L1_CA.h"
#include "gps_l1_ca_subframe_fsm.h"
#include "gps_navigation_message.h"
#include "gnss_satellite.h"
#include "gnss_synchro.h"
#include <gnuradio/block.h>
@ -72,7 +72,9 @@ private:
bool gps_word_parityCheck(unsigned int gpsword);
// class private vars
bool decode_subframe();
bool new_decoder();
int d_crc_error_synchronization_counter;
int *d_preambles_symbols;
unsigned int d_stat;
@ -80,26 +82,16 @@ private:
// symbols
boost::circular_buffer<Gnss_Synchro> d_symbol_history;
double d_symbol_accumulator;
short int d_symbol_accumulator_counter;
// symbol counting
bool d_make_correlation;
unsigned int d_symbol_counter_corr;
float d_subframe_symbols[GPS_SUBFRAME_MS]; //symbols per subframe
int d_current_subframe_symbol;
//bits and frame
unsigned short int d_frame_bit_index;
unsigned int d_GPS_frame_4bytes;
unsigned int d_prev_GPS_frame_4bytes;
bool d_flag_parity;
bool d_flag_preamble;
bool d_flag_new_tow_available;
int d_word_number;
// navigation message vars
Gps_Navigation_Message d_nav;
GpsL1CaSubframeFsm d_GPS_FSM;
bool d_dump;
Gnss_Satellite d_satellite;

View File

@ -19,7 +19,6 @@
add_subdirectory(libswiftcnav)
set(TELEMETRY_DECODER_LIB_SOURCES
gps_l1_ca_subframe_fsm.cc
viterbi_decoder.cc
)

View File

@ -1,289 +0,0 @@
/*!
* \file gps_l1_ca_subframe_fsm.cc
* \brief Implementation of a GPS NAV message word-to-subframe decoder state machine
* \author Javier Arribas, 2011. jarribas(at)cttc.es
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "gps_l1_ca_subframe_fsm.h"
#include "gnss_satellite.h"
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/mpl/list.hpp>
#include <string>
//************ GPS WORD TO SUBFRAME DECODER STATE MACHINE **********
struct Ev_gps_word_valid : sc::event<Ev_gps_word_valid>
{
};
struct Ev_gps_word_invalid : sc::event<Ev_gps_word_invalid>
{
};
struct Ev_gps_word_preamble : sc::event<Ev_gps_word_preamble>
{
};
struct gps_subframe_fsm_S0 : public sc::state<gps_subframe_fsm_S0, GpsL1CaSubframeFsm>
{
public:
// sc::transition(event,next_status)
typedef sc::transition<Ev_gps_word_preamble, gps_subframe_fsm_S1> reactions;
gps_subframe_fsm_S0(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S0 "<<std::endl;
}
};
struct gps_subframe_fsm_S1 : public sc::state<gps_subframe_fsm_S1, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S2> >
reactions;
gps_subframe_fsm_S1(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S1 "<<std::endl;
}
};
struct gps_subframe_fsm_S2 : public sc::state<gps_subframe_fsm_S2, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S3> >
reactions;
gps_subframe_fsm_S2(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S2 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(0);
}
};
struct gps_subframe_fsm_S3 : public sc::state<gps_subframe_fsm_S3, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S4> >
reactions;
gps_subframe_fsm_S3(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S3 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(1);
}
};
struct gps_subframe_fsm_S4 : public sc::state<gps_subframe_fsm_S4, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S5> >
reactions;
gps_subframe_fsm_S4(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S4 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(2);
}
};
struct gps_subframe_fsm_S5 : public sc::state<gps_subframe_fsm_S5, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S6> >
reactions;
gps_subframe_fsm_S5(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S5 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(3);
}
};
struct gps_subframe_fsm_S6 : public sc::state<gps_subframe_fsm_S6, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S7> >
reactions;
gps_subframe_fsm_S6(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S6 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(4);
}
};
struct gps_subframe_fsm_S7 : public sc::state<gps_subframe_fsm_S7, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S8> >
reactions;
gps_subframe_fsm_S7(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S7 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(5);
}
};
struct gps_subframe_fsm_S8 : public sc::state<gps_subframe_fsm_S8, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S9> >
reactions;
gps_subframe_fsm_S8(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S8 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(6);
}
};
struct gps_subframe_fsm_S9 : public sc::state<gps_subframe_fsm_S9, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S10> >
reactions;
gps_subframe_fsm_S9(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S9 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(7);
}
};
struct gps_subframe_fsm_S10 : public sc::state<gps_subframe_fsm_S10, GpsL1CaSubframeFsm>
{
public:
typedef mpl::list<sc::transition<Ev_gps_word_invalid, gps_subframe_fsm_S0>,
sc::transition<Ev_gps_word_valid, gps_subframe_fsm_S11> >
reactions;
gps_subframe_fsm_S10(my_context ctx) : my_base(ctx)
{
//std::cout<<"Enter S10 "<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(8);
}
};
struct gps_subframe_fsm_S11 : public sc::state<gps_subframe_fsm_S11, GpsL1CaSubframeFsm>
{
public:
typedef sc::transition<Ev_gps_word_preamble, gps_subframe_fsm_S1> reactions;
gps_subframe_fsm_S11(my_context ctx) : my_base(ctx)
{
//std::cout<<"Completed GPS Subframe!"<<std::endl;
context<GpsL1CaSubframeFsm>().gps_word_to_subframe(9);
context<GpsL1CaSubframeFsm>().gps_subframe_to_nav_msg(); //decode the subframe
// DECODE SUBFRAME
//std::cout<<"Enter S11"<<std::endl;
}
};
GpsL1CaSubframeFsm::GpsL1CaSubframeFsm()
{
d_nav.reset();
i_channel_ID = 0;
i_satellite_PRN = 0;
d_subframe_ID = 0;
d_flag_new_subframe = false;
initiate(); //start the FSM
}
void GpsL1CaSubframeFsm::gps_word_to_subframe(int position)
{
// insert the word in the correct position of the subframe
std::memcpy(&d_subframe[position * GPS_WORD_LENGTH], &d_GPS_frame_4bytes, sizeof(char) * GPS_WORD_LENGTH);
}
void GpsL1CaSubframeFsm::clear_flag_new_subframe()
{
d_flag_new_subframe = false;
}
void GpsL1CaSubframeFsm::gps_subframe_to_nav_msg()
{
//int subframe_ID;
// NEW GPS SUBFRAME HAS ARRIVED!
d_subframe_ID = d_nav.subframe_decoder(this->d_subframe); //decode the subframe
std::cout << "New GPS NAV message received in channel " << i_channel_ID << ": "
<< "subframe "
<< d_subframe_ID << " from satellite "
<< Gnss_Satellite(std::string("GPS"), i_satellite_PRN) << std::endl;
d_nav.i_satellite_PRN = i_satellite_PRN;
d_nav.i_channel_ID = i_channel_ID;
d_flag_new_subframe = true;
}
void GpsL1CaSubframeFsm::Event_gps_word_valid()
{
this->process_event(Ev_gps_word_valid());
}
void GpsL1CaSubframeFsm::Event_gps_word_invalid()
{
this->process_event(Ev_gps_word_invalid());
}
void GpsL1CaSubframeFsm::Event_gps_word_preamble()
{
this->process_event(Ev_gps_word_preamble());
}

View File

@ -1,100 +0,0 @@
/*!
* \file gps_l1_ca_subframe_fsm.h
* \brief Interface of a GPS NAV message word-to-subframe decoder state machine
* \author Javier Arribas, 2011. jarribas(at)cttc.es
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GPS_L1_CA_SUBFRAME_FSM_H_
#define GNSS_SDR_GPS_L1_CA_SUBFRAME_FSM_H_
#include "GPS_L1_CA.h"
#include "gps_navigation_message.h"
#include "gps_ephemeris.h"
#include "gps_iono.h"
#include "gps_almanac.h"
#include "gps_utc_model.h"
#include <boost/statechart/state_machine.hpp>
namespace sc = boost::statechart;
namespace mpl = boost::mpl;
struct gps_subframe_fsm_S0;
struct gps_subframe_fsm_S1;
struct gps_subframe_fsm_S2;
struct gps_subframe_fsm_S3;
struct gps_subframe_fsm_S4;
struct gps_subframe_fsm_S5;
struct gps_subframe_fsm_S6;
struct gps_subframe_fsm_S7;
struct gps_subframe_fsm_S8;
struct gps_subframe_fsm_S9;
struct gps_subframe_fsm_S10;
struct gps_subframe_fsm_S11;
/*!
* \brief This class implements a Finite State Machine that handles the decoding
* of the GPS L1 C/A NAV message
*/
class GpsL1CaSubframeFsm : public sc::state_machine<GpsL1CaSubframeFsm, gps_subframe_fsm_S0>
{
public:
GpsL1CaSubframeFsm(); //!< The constructor starts the Finite State Machine
void clear_flag_new_subframe();
// channel and satellite info
int i_channel_ID; //!< Channel id
unsigned int i_satellite_PRN; //!< Satellite PRN number
Gps_Navigation_Message d_nav; //!< GPS L1 C/A navigation message object
// GPS SV and System parameters
Gps_Ephemeris ephemeris; //!< Object that handles GPS ephemeris parameters
Gps_Almanac almanac; //!< Object that handles GPS almanac data
Gps_Utc_Model utc_model; //!< Object that handles UTM model parameters
Gps_Iono iono; //!< Object that handles ionospheric parameters
char d_subframe[GPS_SUBFRAME_LENGTH];
int d_subframe_ID;
bool d_flag_new_subframe;
char d_GPS_frame_4bytes[GPS_WORD_LENGTH];
//double d_preamble_time_ms;
void gps_word_to_subframe(int position); //!< inserts the word in the correct position of the subframe
/*!
* \brief This function decodes a NAv message subframe and pushes the information to the right queues
*/
void gps_subframe_to_nav_msg();
//FSM EVENTS
void Event_gps_word_valid(); //!< FSM event: the received word is valid
void Event_gps_word_invalid(); //!< FSM event: the received word is not valid
void Event_gps_word_preamble(); //!< FSM event: word preamble detected
};
#endif

View File

@ -50,6 +50,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/algorithms/tracking/gnuradio_blocks
${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${ARMADILLO_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}
${GNURADIO_RUNTIME_INCLUDE_DIRS}

View File

@ -49,6 +49,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/core/receiver
${CMAKE_SOURCE_DIR}/src/algorithms/tracking/libs
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${ARMADILLO_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}

View File

@ -2,6 +2,7 @@
* \file dll_pll_veml_tracking.cc
* \brief Implementation of a code DLL + carrier PLL tracking block.
* \author Antonio Ramos, 2018 antonio.ramosdet(at)gmail.com
* Javier Arribas, 2018. jarribas(at)cttc.es
*
* Code DLL + carrier PLL according to the algorithms described in:
* [1] K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
@ -84,10 +85,12 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) : gr::bl
this->message_port_register_out(pmt::mp("events"));
this->set_relative_rate(1.0 / static_cast<double>(trk_parameters.vector_length));
// Telemetry bit synchronization message port input (mainly for GPS L1 CA)
this->message_port_register_in(pmt::mp("preamble_samplestamp"));
// initialize internal vars
d_veml = false;
d_cloop = true;
d_synchonizing = false;
d_code_chip_rate = 0.0;
d_secondary_code_length = 0;
d_secondary_code_string = nullptr;
@ -120,6 +123,30 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_) : gr::bl
d_secondary = false;
trk_parameters.track_pilot = false;
interchange_iq = false;
// set the preamble
unsigned short int preambles_bits[GPS_CA_PREAMBLE_LENGTH_BITS] = GPS_PREAMBLE;
// preamble bits to sampled symbols
d_gps_l1ca_preambles_symbols = static_cast<int *>(volk_gnsssdr_malloc(GPS_CA_PREAMBLE_LENGTH_SYMBOLS * sizeof(int), volk_gnsssdr_get_alignment()));
int n = 0;
for (int i = 0; i < GPS_CA_PREAMBLE_LENGTH_BITS; i++)
{
for (unsigned int j = 0; j < GPS_CA_TELEMETRY_SYMBOLS_PER_BIT; j++)
{
if (preambles_bits[i] == 1)
{
d_gps_l1ca_preambles_symbols[n] = 1;
}
else
{
d_gps_l1ca_preambles_symbols[n] = -1;
}
n++;
}
}
d_symbol_history.resize(GPS_CA_PREAMBLE_LENGTH_SYMBOLS); // Change fixed buffer size
d_symbol_history.clear(); // Clear all the elements in the buffer
}
else if (signal_type.compare("2S") == 0)
{
@ -399,7 +426,8 @@ void dll_pll_veml_tracking::start_tracking()
double T_prn_mod_seconds = T_chip_mod_seconds * static_cast<double>(d_code_length_chips);
double T_prn_mod_samples = T_prn_mod_seconds * trk_parameters.fs_in;
d_current_prn_length_samples = std::round(T_prn_mod_samples);
//d_current_prn_length_samples = std::round(T_prn_mod_samples);
d_current_prn_length_samples = std::floor(T_prn_mod_samples);
double T_prn_true_seconds = static_cast<double>(d_code_length_chips) / d_code_chip_rate;
double T_prn_true_samples = T_prn_true_seconds * trk_parameters.fs_in;
@ -520,7 +548,6 @@ void dll_pll_veml_tracking::start_tracking()
// enable tracking pull-in
d_state = 1;
d_synchonizing = false;
d_cloop = true;
d_Prompt_buffer_deque.clear();
d_last_prompt = gr_complex(0.0, 0.0);
@ -532,6 +559,11 @@ void dll_pll_veml_tracking::start_tracking()
dll_pll_veml_tracking::~dll_pll_veml_tracking()
{
if (signal_type.compare("1C") == 0)
{
volk_gnsssdr_free(d_gps_l1ca_preambles_symbols);
}
if (d_dump_file.is_open())
{
try
@ -753,7 +785,8 @@ void dll_pll_veml_tracking::update_tracking_vars()
// Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation
T_prn_samples = T_prn_seconds * trk_parameters.fs_in;
K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs * trk_parameters.fs_in;
d_current_prn_length_samples = static_cast<int>(round(K_blk_samples)); // round to a discrete number of samples
//d_current_prn_length_samples = static_cast<int>(round(K_blk_samples)); // round to a discrete number of samples
d_current_prn_length_samples = static_cast<int>(std::floor(K_blk_samples)); // round to a discrete number of samples
//################### PLL COMMANDS #################################################
// carrier phase step (NCO phase increment per sample) [rads/sample]
@ -834,6 +867,7 @@ void dll_pll_veml_tracking::log_data(bool integrating)
float tmp_VE, tmp_E, tmp_P, tmp_L, tmp_VL;
float tmp_float;
double tmp_double;
unsigned long int tmp_long_int;
if (trk_parameters.track_pilot)
{
if (interchange_iq)
@ -900,7 +934,8 @@ void dll_pll_veml_tracking::log_data(bool integrating)
d_dump_file.write(reinterpret_cast<char *>(&prompt_I), sizeof(float));
d_dump_file.write(reinterpret_cast<char *>(&prompt_Q), sizeof(float));
// PRN start sample stamp
d_dump_file.write(reinterpret_cast<char *>(&d_sample_counter), sizeof(unsigned long int));
tmp_long_int = d_sample_counter + d_current_prn_length_samples;
d_dump_file.write(reinterpret_cast<char *>(&tmp_long_int), sizeof(unsigned long int));
// accumulated carrier phase
tmp_float = d_acc_carrier_phase_rad;
d_dump_file.write(reinterpret_cast<char *>(&tmp_float), sizeof(float));
@ -1277,39 +1312,82 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused)
}
else if (d_symbols_per_bit > 1) //Signal does not have secondary code. Search a bit transition by sign change
{
if (d_synchonizing)
float current_tracking_time_s = static_cast<float>(d_sample_counter - d_acq_sample_stamp) / trk_parameters.fs_in;
if (current_tracking_time_s > 10)
{
if (d_Prompt->real() * d_last_prompt.real() > 0.0)
d_symbol_history.push_back(d_Prompt->real());
//******* preamble correlation ********
int corr_value = 0;
if ((d_symbol_history.size() == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)) // and (d_make_correlation or !d_flag_frame_sync))
{
d_current_symbol++;
}
else if (d_current_symbol > d_symbols_per_bit)
for (unsigned int i = 0; i < GPS_CA_PREAMBLE_LENGTH_SYMBOLS; i++)
{
d_synchonizing = false;
d_current_symbol = 1;
if (d_symbol_history.at(i) < 0) // symbols clipping
{
corr_value -= d_gps_l1ca_preambles_symbols[i];
}
else
{
d_current_symbol = 1;
d_last_prompt = *d_Prompt;
corr_value += d_gps_l1ca_preambles_symbols[i];
}
}
else if (d_last_prompt.real() != 0.0)
}
if (corr_value == GPS_CA_PREAMBLE_LENGTH_SYMBOLS)
{
d_current_symbol++;
if (d_current_symbol == d_symbols_per_bit) next_state = true;
//std::cout << "Preamble detected at tracking!" << std::endl;
next_state = true;
}
else
{
d_last_prompt = *d_Prompt;
d_synchonizing = true;
d_current_symbol = 1;
next_state = false;
}
}
else
{
next_state = false;
}
}
else
{
next_state = true;
}
// ########### Output the tracking results to Telemetry block ##########
if (interchange_iq)
{
if (trk_parameters.track_pilot)
{
// Note that data and pilot components are in quadrature. I and Q are interchanged
current_synchro_data.Prompt_I = static_cast<double>((*d_Prompt_Data).imag());
current_synchro_data.Prompt_Q = static_cast<double>((*d_Prompt_Data).real());
}
else
{
current_synchro_data.Prompt_I = static_cast<double>((*d_Prompt).imag());
current_synchro_data.Prompt_Q = static_cast<double>((*d_Prompt).real());
}
}
else
{
if (trk_parameters.track_pilot)
{
// Note that data and pilot components are in quadrature. I and Q are interchanged
current_synchro_data.Prompt_I = static_cast<double>((*d_Prompt_Data).real());
current_synchro_data.Prompt_Q = static_cast<double>((*d_Prompt_Data).imag());
}
else
{
current_synchro_data.Prompt_I = static_cast<double>((*d_Prompt).real());
current_synchro_data.Prompt_Q = static_cast<double>((*d_Prompt).imag());
}
}
current_synchro_data.Code_phase_samples = d_rem_code_phase_samples;
current_synchro_data.Carrier_phase_rads = d_acc_carrier_phase_rad;
current_synchro_data.Carrier_Doppler_hz = d_carrier_doppler_hz;
current_synchro_data.CN0_dB_hz = d_CN0_SNV_dB_Hz;
current_synchro_data.Flag_valid_symbol_output = true;
current_synchro_data.correlation_length_ms = d_correlation_length_ms;
if (next_state)
{ // reset extended correlator
d_VE_accu = gr_complex(0.0, 0.0);
@ -1320,7 +1398,6 @@ int dll_pll_veml_tracking::general_work(int noutput_items __attribute__((unused)
d_last_prompt = gr_complex(0.0, 0.0);
d_Prompt_buffer_deque.clear();
d_current_symbol = 0;
d_synchonizing = false;
if (d_enable_extended_integration)
{

View File

@ -41,6 +41,7 @@
#include <string>
#include <map>
#include <queue>
#include <boost/circular_buffer.hpp>
class dll_pll_veml_tracking;
@ -69,6 +70,7 @@ private:
friend dll_pll_veml_tracking_sptr dll_pll_veml_make_tracking(const Dll_Pll_Conf &conf_);
dll_pll_veml_tracking(const Dll_Pll_Conf &conf_);
void msg_handler_preamble_index(pmt::pmt_t msg);
bool cn0_and_tracking_lock_status(double coh_integration_time_s);
bool acquire_secondary();
@ -102,9 +104,12 @@ private:
std::string *d_secondary_code_string;
std::string signal_pretty_name;
uint64_t d_preamble_sample_counter;
int *d_gps_l1ca_preambles_symbols;
boost::circular_buffer<float> d_symbol_history;
//tracking state machine
int d_state;
bool d_synchonizing;
//Integration period in samples
int d_correlation_length_ms;
int d_n_correlator_taps;

View File

@ -49,6 +49,7 @@
#include "tracking_2nd_PLL_filter.h"
#include <armadillo>
#include "cpu_multicorrelator_real_codes.h"
#include "bayesian_estimation.h"
class Gps_L1_Ca_Kf_Tracking_cc;
@ -133,6 +134,9 @@ private:
arma::colvec kf_y_pre; //measurement vector
arma::mat kf_K; //Kalman gain matrix
// Bayesian estimator
Bayesian_estimator cov_est;
// PLL and DLL filter library
Tracking_2nd_DLL_filter d_code_loop_filter;

View File

@ -44,6 +44,7 @@ set(TRACKING_LIB_SOURCES
tracking_FLL_PLL_filter.cc
tracking_loop_filter.cc
dll_pll_conf.cc
bayesian_estimation.cc
)
if(ENABLE_FPGA)
@ -56,6 +57,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/core/interfaces
${CMAKE_SOURCE_DIR}/src/core/receiver
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${ARMADILLO_INCLUDE_DIRS}
${VOLK_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}

View File

@ -0,0 +1,167 @@
/*!
* \file bayesian_estimation.cc
* \brief Interface of a library with Bayesian noise statistic estimation
*
* Bayesian_estimator is a Bayesian estimator which attempts to estimate
* the properties of a stochastic process based on a sequence of
* discrete samples of the sequence.
*
* [1] TODO: Refs
*
* \authors <ul>
* <li> Gerald LaMountain, 2018. gerald(at)ece.neu.edu
* <li> Jordi Vila-Valls 2018. jvila(at)cttc.es
* </ul>
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "bayesian_estimation.h"
#include <armadillo>
Bayesian_estimator::Bayesian_estimator()
{
kappa_prior = 0;
nu_prior = 0;
}
Bayesian_estimator::Bayesian_estimator(int ny)
{
mu_prior = arma::zeros(ny,1);
kappa_prior = 0;
nu_prior = 0;
Psi_prior = arma::eye(ny,ny) * (nu_prior + ny + 1);
}
Bayesian_estimator::Bayesian_estimator(arma::vec mu_prior_0, int kappa_prior_0, int nu_prior_0, arma::mat Psi_prior_0)
{
mu_prior = mu_prior_0;
kappa_prior = kappa_prior_0;
nu_prior = nu_prior_0;
Psi_prior = Psi_prior_0;
}
Bayesian_estimator::~Bayesian_estimator()
{
}
/*
* Perform Bayesian noise estimation using the normal-inverse-Wishart priors stored in
* the class structure, and update the priors according to the computed posteriors
*/
void Bayesian_estimator::update_sequential(arma::vec data)
{
int K = data.n_cols;
int ny = data.n_rows;
if (mu_prior.is_empty())
{
mu_prior = arma::zeros(ny,1);
}
if (Psi_prior.is_empty())
{
Psi_prior = arma::zeros(ny,ny);
}
arma::vec y_mean = arma::mean(data, 1);
arma::mat Psi_N = arma::zeros(ny, ny);
for (int kk = 0; kk < K; kk++)
{
Psi_N = Psi_N + (data.col(kk)-y_mean)*((data.col(kk)-y_mean).t());
}
arma::vec mu_posterior = (kappa_prior*mu_prior + K*y_mean) / (kappa_prior + K);
int kappa_posterior = kappa_prior + K;
int nu_posterior = nu_prior + K;
arma::mat Psi_posterior = Psi_prior + Psi_N + (kappa_prior*K)/(kappa_prior + K)*(y_mean - mu_prior)*((y_mean - mu_prior).t());
mu_est = mu_posterior;
if ((nu_posterior - ny - 1) > 0)
{
Psi_est = Psi_posterior / (nu_posterior - ny - 1);
}
else
{
Psi_est = Psi_posterior / (nu_posterior + ny + 1);
}
mu_prior = mu_posterior;
kappa_prior = kappa_posterior;
nu_prior = nu_posterior;
Psi_prior = Psi_posterior;
}
/*
* Perform Bayesian noise estimation using a new set of normal-inverse-Wishart priors
* and update the priors according to the computed posteriors
*/
void Bayesian_estimator::update_sequential(arma::vec data, arma::vec mu_prior_0, int kappa_prior_0, int nu_prior_0, arma::mat Psi_prior_0)
{
int K = data.n_cols;
int ny = data.n_rows;
arma::vec y_mean = arma::mean(data, 1);
arma::mat Psi_N = arma::zeros(ny, ny);
for (int kk = 0; kk < K; kk++)
{
Psi_N = Psi_N + (data.col(kk)-y_mean)*((data.col(kk)-y_mean).t());
}
arma::vec mu_posterior = (kappa_prior_0*mu_prior_0 + K*y_mean) / (kappa_prior_0 + K);
int kappa_posterior = kappa_prior_0 + K;
int nu_posterior = nu_prior_0 + K;
arma::mat Psi_posterior = Psi_prior_0 + Psi_N + (kappa_prior_0*K)/(kappa_prior_0 + K)*(y_mean - mu_prior_0)*((y_mean - mu_prior_0).t());
mu_est = mu_posterior;
if ((nu_posterior - ny - 1) > 0)
{
Psi_est = Psi_posterior / (nu_posterior - ny - 1);
}
else
{
Psi_est = Psi_posterior / (nu_posterior + ny + 1);
}
mu_prior = mu_posterior;
kappa_prior = kappa_posterior;
nu_prior = nu_posterior;
Psi_prior = Psi_posterior;
}
arma::vec Bayesian_estimator::get_mu_est()
{
return mu_est;
}
arma::mat Bayesian_estimator::get_Psi_est()
{
return Psi_est;
}

View File

@ -0,0 +1,86 @@
/*!
* \file bayesian_estimation.h
* \brief Interface of a library with Bayesian noise statistic estimation
*
* Bayesian_estimator is a Bayesian estimator which attempts to estimate
* the properties of a stochastic process based on a sequence of
* discrete samples of the sequence.
*
* [1] TODO: Refs
*
* \authors <ul>
* <li> Gerald LaMountain, 2018. gerald(at)ece.neu.edu
* <li> Jordi Vila-Valls 2018. jvila(at)cttc.es
* </ul>
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2018 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <https://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_BAYESIAN_ESTIMATION_H_
#define GNSS_SDR_BAYESIAN_ESTIMATION_H_
#include <gnuradio/gr_complex.h>
#include <armadillo>
/*! \brief Bayesian_estimator is an estimator of noise characteristics (i.e. mean, covariance)
*
* Bayesian_estimator is an estimator which performs estimation of noise characteristics from
* a sequence of identically and independently distributed (IID) samples of a stationary
* stochastic process by way of Bayesian inference using conjugate priors. The posterior
* distribution is assumed to be Gaussian with mean \mathbf{\mu} and covariance \hat{\mathbf{C}},
* which has a conjugate prior given by a normal-inverse-Wishart distribution with paramemters
* \mathbf{\mu}_{0}, \kappa_{0}, \nu_{0}, and \mathbf{\Psi}.
*
* [1] TODO: Ref1
*
*/
class Bayesian_estimator
{
public:
Bayesian_estimator();
Bayesian_estimator(int ny);
Bayesian_estimator(arma::vec mu_prior_0, int kappa_prior_0, int nu_prior_0, arma::mat Psi_prior_0);
~Bayesian_estimator();
void update_sequential(arma::vec data);
void update_sequential(arma::vec data, arma::vec mu_prior_0, int kappa_prior_0, int nu_prior_0, arma::mat Psi_prior_0);
arma::vec get_mu_est();
arma::mat get_Psi_est();
private:
arma::vec mu_est;
arma::mat Psi_est;
arma::vec mu_prior;
int kappa_prior;
int nu_prior;
arma::mat Psi_prior;
};
#endif

View File

@ -61,6 +61,7 @@ public:
virtual void set_doppler_step(unsigned int doppler_step) = 0;
virtual void init() = 0;
virtual void set_local_code() = 0;
virtual void set_state(int state) = 0;
virtual signed int mag() = 0;
virtual void reset() = 0;
};

View File

@ -27,6 +27,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/core/system_parameters
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}
${GNURADIO_RUNTIME_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
@ -35,3 +36,4 @@ list(SORT CORE_MONITOR_LIBS_HEADERS)
add_library(core_monitor_lib ${CORE_MONITOR_LIBS_SOURCES} ${CORE_MONITOR_LIBS_HEADERS})
source_group(Headers FILES ${CORE_MONITOR_LIBS_HEADERS})
target_link_libraries(core_monitor_lib ${Boost_LIBRARIES})
add_dependencies(core_monitor_lib glog-${glog_RELEASE})

View File

@ -418,7 +418,7 @@ void GNSSFlowgraph::connect()
}
if (sat == 0)
{
channels_.at(i)->set_signal(search_next_signal(gnss_signal, true));
channels_.at(i)->set_signal(search_next_signal(gnss_signal, false));
}
else
{
@ -896,6 +896,43 @@ void GNSSFlowgraph::apply_action(unsigned int who, unsigned int what)
case 1:
LOG(INFO) << "Channel " << who << " ACQ SUCCESS satellite " << channels_[who]->get_signal().get_satellite();
// If the satellite is in the list of available ones, remove it.
switch (mapStringValues_[channels_[who]->get_signal().get_signal_str()])
{
case evGPS_1C:
available_GPS_1C_signals_.remove(channels_[who]->get_signal());
break;
case evGPS_2S:
available_GPS_2S_signals_.remove(channels_[who]->get_signal());
break;
case evGPS_L5:
available_GPS_L5_signals_.remove(channels_[who]->get_signal());
break;
case evGAL_1B:
available_GAL_1B_signals_.remove(channels_[who]->get_signal());
break;
case evGAL_5X:
available_GAL_5X_signals_.remove(channels_[who]->get_signal());
break;
case evGLO_1G:
available_GLO_1G_signals_.remove(channels_[who]->get_signal());
break;
case evGLO_2G:
available_GLO_2G_signals_.remove(channels_[who]->get_signal());
break;
default:
LOG(ERROR) << "This should not happen :-(";
break;
}
channels_state_[who] = 2;
acq_channels_count_--;
for (unsigned int i = 0; i < channels_count_; i++)
@ -1357,9 +1394,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
{
case evGPS_1C:
result = available_GPS_1C_signals_.front();
if (pop)
{
available_GPS_1C_signals_.pop_front();
if (!pop)
{
available_GPS_1C_signals_.push_back(result);
}
if (tracked)
{
@ -1387,9 +1425,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGPS_2S:
result = available_GPS_2S_signals_.front();
if (pop)
{
available_GPS_2S_signals_.pop_front();
if (!pop)
{
available_GPS_2S_signals_.push_back(result);
}
if (tracked)
{
@ -1417,9 +1456,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGPS_L5:
result = available_GPS_L5_signals_.front();
if (pop)
{
available_GPS_L5_signals_.pop_front();
if (!pop)
{
available_GPS_L5_signals_.push_back(result);
}
if (tracked)
{
@ -1447,9 +1487,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGAL_1B:
result = available_GAL_1B_signals_.front();
if (pop)
{
available_GAL_1B_signals_.pop_front();
if (!pop)
{
available_GAL_1B_signals_.push_back(result);
}
if (tracked)
{
@ -1471,9 +1512,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGAL_5X:
result = available_GAL_5X_signals_.front();
if (pop)
{
available_GAL_5X_signals_.pop_front();
if (!pop)
{
available_GAL_5X_signals_.push_back(result);
}
if (tracked)
{
@ -1495,9 +1537,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGLO_1G:
result = available_GLO_1G_signals_.front();
if (pop)
{
available_GLO_1G_signals_.pop_front();
if (!pop)
{
available_GLO_1G_signals_.push_back(result);
}
if (tracked)
{
@ -1519,9 +1562,10 @@ Gnss_Signal GNSSFlowgraph::search_next_signal(std::string searched_signal, bool
case evGLO_2G:
result = available_GLO_2G_signals_.front();
if (pop)
{
available_GLO_2G_signals_.pop_front();
if (!pop)
{
available_GLO_2G_signals_.push_back(result);
}
if (tracked)
{

View File

@ -84,6 +84,9 @@ public:
template <class Archive>
void serialize(Archive& ar, const unsigned int version)
{
if (version)
{
};
// Satellite and signal info
ar& System;
ar& Signal;

View File

@ -34,8 +34,15 @@
#include <gflags/gflags.h>
#include <limits>
DEFINE_string(trk_test_implementation, std::string("GPS_L1_CA_DLL_PLL_Tracking"), "Tracking block implementation under test, defaults to GPS_L1_CA_DLL_PLL_Tracking");
// Input signal configuration
DEFINE_bool(enable_external_signal_file, false, "Use an external signal file capture instead of the software-defined signal generator");
DEFINE_double(external_signal_acquisition_threshold, 2.5, "Threshold for satellite acquisition when external file is used");
DEFINE_int32(external_signal_acquisition_dwells, 5, "Maximum dwells count for satellite acquisition when external file is used");
DEFINE_double(external_signal_acquisition_doppler_max_hz, 5000.0, "Doppler max for satellite acquisition when external file is used");
DEFINE_double(external_signal_acquisition_doppler_step_hz, 125, "Doppler step for satellite acquisition when external file is used");
DEFINE_string(signal_file, std::string("signal_out.bin"), "Path of the external signal capture file");
DEFINE_double(CN0_dBHz_start, std::numeric_limits<double>::infinity(), "Enable noise generator and set the CN0 start sweep value [dB-Hz]");
DEFINE_double(CN0_dBHz_stop, std::numeric_limits<double>::infinity(), "Enable noise generator and set the CN0 stop sweep value [dB-Hz]");
@ -60,9 +67,12 @@ DEFINE_double(acq_Delay_error_chips_start, 2.0, "Acquisition Code Delay error st
DEFINE_double(acq_Delay_error_chips_stop, -2.0, "Acquisition Code Delay error stop sweep value [Chips]");
DEFINE_double(acq_Delay_error_chips_step, -0.1, "Acquisition Code Delay error sweep step value [Chips]");
DEFINE_int64(skip_samples, 0, "Skip an initial transitory in the processed signal file capture [samples]");
DEFINE_int32(plot_detail_level, 0, "Specify the desired plot detail (0,1,2): 0 - Minimum plots (default) 2 - Plot all tracking parameters");
DEFINE_double(skip_trk_transitory_s, 1.0, "Skip the initial tracking output signal to avoid transitory results [s]");
//Emulated acquisition configuration
//Tracking configuration

View File

@ -600,6 +600,14 @@ void ObsSystemTest::compute_pseudorange_error(
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("linespoints");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title(signal_name + " Pseudorange error");
g1.set_grid();
g1.set_xlabel("PRN");
@ -620,7 +628,6 @@ void ObsSystemTest::compute_pseudorange_error(
}
g1.savetops("Pseudorange_error_" + signal_name);
g1.savetopdf("Pseudorange_error_" + signal_name, 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
}
catch (const GnuplotException& ge)
{
@ -691,6 +698,14 @@ void ObsSystemTest::compute_carrierphase_error(
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("linespoints");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title(signal_name + " Carrier phase error");
g1.set_grid();
g1.set_xlabel("PRN");
@ -711,7 +726,6 @@ void ObsSystemTest::compute_carrierphase_error(
}
g1.savetops("Carrier_phase_error_" + signal_name);
g1.savetopdf("Carrier_phase_error_" + signal_name, 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
}
catch (const GnuplotException& ge)
{
@ -782,6 +796,14 @@ void ObsSystemTest::compute_doppler_error(
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("linespoints");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title(signal_name + " Doppler error");
g1.set_grid();
g1.set_xlabel("PRN");
@ -802,7 +824,6 @@ void ObsSystemTest::compute_doppler_error(
}
g1.savetops("Doppler_error_" + signal_name);
g1.savetopdf("Doppler_error_" + signal_name, 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
}
catch (const GnuplotException& ge)
{

View File

@ -619,6 +619,14 @@ void StaticPositionSystemTest::print_results(const std::vector<double>& east,
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("points");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title("2D precision");
g1.set_xlabel("East [m]");
g1.set_ylabel("North [m]");
@ -635,9 +643,16 @@ void StaticPositionSystemTest::print_results(const std::vector<double>& east,
g1.savetops("Position_test_2D");
g1.savetopdf("Position_test_2D", 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
Gnuplot g2("points");
if (FLAGS_show_plots)
{
g2.showonscreen(); // window output
}
else
{
g2.disablescreen();
}
g2.set_title("3D precision");
g2.set_xlabel("East [m]");
g2.set_ylabel("North [m]");
@ -656,7 +671,6 @@ void StaticPositionSystemTest::print_results(const std::vector<double>& east,
g2.savetops("Position_test_3D");
g2.savetopdf("Position_test_3D");
if (FLAGS_show_plots) g2.showonscreen(); // window output
}
catch (const GnuplotException& ge)
{

View File

@ -145,10 +145,11 @@ DECLARE_string(log_dir);
#if EXTRA_TESTS
#include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc"
#include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc"
#include "unit-tests/signal-processing-blocks/acquisition/gps_l1_acq_performance_test.cc"
#include "unit-tests/signal-processing-blocks/acquisition/acq_performance_test.cc"
#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc"
#include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc"
#include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_kf_tracking_test.cc"
#include "unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test.cc"
#include "unit-tests/signal-processing-blocks/telemetry_decoder/gps_l1_ca_telemetry_decoder_test.cc"
#include "unit-tests/signal-processing-blocks/observables/hybrid_observables_test.cc"
#endif

View File

@ -116,6 +116,14 @@ TEST(FFTLengthTest, MeasureExecutionTime)
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("linespoints");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title("FFT execution times for different lengths");
g1.set_grid();
g1.set_xlabel("FFT length");
@ -124,9 +132,16 @@ TEST(FFTLengthTest, MeasureExecutionTime)
g1.set_style("points").plot_xy(powers_of_two, execution_times_powers_of_two, "Power of 2");
g1.savetops("FFT_execution_times_extended");
g1.savetopdf("FFT_execution_times_extended", 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
Gnuplot g2("linespoints");
if (FLAGS_show_plots)
{
g2.showonscreen(); // window output
}
else
{
g2.disablescreen();
}
g2.set_title("FFT execution times for different lengths (up to 2^{14}=16384)");
g2.set_grid();
g2.set_xlabel("FFT length");

View File

@ -1,5 +1,5 @@
/*!
* \file gps_l1_acq_performance_test.cc
* \file acq_performance_test.cc
* \brief This class implements an acquisition performance test
* \author Carles Fernandez-Prades, 2018. cfernandez(at)cttc.cat
*
@ -29,26 +29,38 @@
* -------------------------------------------------------------------------
*/
#include "test_flags.h"
#include "signal_generator_flags.h"
#include "tracking_true_obs_reader.h"
#include "true_observables_reader.h"
#include "gps_l1_ca_pcps_acquisition.h"
#include "gps_l1_ca_pcps_acquisition_fine_doppler.h"
#include "galileo_e1_pcps_ambiguous_acquisition.h"
#include "galileo_e5a_pcps_acquisition.h"
#include "glonass_l1_ca_pcps_acquisition.h"
#include "glonass_l2_ca_pcps_acquisition.h"
#include "gps_l2_m_pcps_acquisition.h"
#include "gps_l5i_pcps_acquisition.h"
#include "display.h"
#include "gnuplot_i.h"
#include "signal_generator_flags.h"
#include "test_flags.h"
#include "tracking_true_obs_reader.h"
#include "true_observables_reader.h"
#include <boost/filesystem.hpp>
#include <gnuradio/top_block.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <gnuradio/blocks/skiphead.h>
DEFINE_string(config_file_ptest, std::string(""), "File containing alternative configuration parameters for the acquisition performance test.");
DEFINE_string(acq_test_input_file, std::string(""), "File containing raw signal data, must be in int8_t format. The signal generator will not be used.");
DEFINE_string(acq_test_implementation, std::string("GPS_L1_CA_PCPS_Acquisition"), "Acquisition block implementation under test. Alternatives: GPS_L1_CA_PCPS_Acquisition, GPS_L1_CA_PCPS_Acquisition_Fine_Doppler, Galileo_E1_PCPS_Ambiguous_Acquisition, GLONASS_L1_CA_PCPS_Acquisition, GLONASS_L2_CA_PCPS_Acquisition, GPS_L2_M_PCPS_Acquisition, Galileo_E5a_Pcps_Acquisition, GPS_L5i_PCPS_Acquisition");
DEFINE_int32(acq_test_doppler_max, 5000, "Maximum Doppler, in Hz");
DEFINE_int32(acq_test_doppler_step, 125, "Doppler step, in Hz.");
DEFINE_int32(acq_test_coherent_time_ms, 1, "Acquisition coherent time, in ms");
DEFINE_int32(acq_test_max_dwells, 1, "Number of non-coherent integrations");
DEFINE_bool(acq_test_use_CFAR_algorithm, true, "Use CFAR algorithm");
DEFINE_bool(acq_test_bit_transition_flag, false, "Bit transition flag");
DEFINE_int32(acq_test_max_dwells, 1, "Number of non-coherent integrations.");
DEFINE_bool(acq_test_use_CFAR_algorithm, true, "Use CFAR algorithm.");
DEFINE_bool(acq_test_bit_transition_flag, false, "Bit transition flag.");
DEFINE_bool(acq_test_make_two_steps, false, "Perform second step in a thinner grid.");
DEFINE_int32(acq_test_second_nbins, 4, "If --acq_test_make_two_steps is set to true, this parameter sets the number of bins done in the acquisition refinement stage.");
DEFINE_int32(acq_test_second_doppler_step, 10, "If --acq_test_make_two_steps is set to true, this parameter sets the Doppler step applied in the acquisition refinement stage, in Hz.");
DEFINE_int32(acq_test_signal_duration_s, 2, "Generated signal duration, in s");
DEFINE_int32(acq_test_num_meas, 0, "Number of measurements per run. 0 means the complete file.");
@ -56,9 +68,9 @@ DEFINE_double(acq_test_cn0_init, 33.0, "Initial CN0, in dBHz.");
DEFINE_double(acq_test_cn0_final, 45.0, "Final CN0, in dBHz.");
DEFINE_double(acq_test_cn0_step, 3.0, "CN0 step, in dB.");
DEFINE_double(acq_test_threshold_init, 11.0, "Initial acquisition threshold");
DEFINE_double(acq_test_threshold_final, 16.0, "Final acquisition threshold");
DEFINE_double(acq_test_threshold_step, 1.0, "Acquisition threshold step");
DEFINE_double(acq_test_threshold_init, 3.0, "Initial acquisition threshold");
DEFINE_double(acq_test_threshold_final, 4.0, "Final acquisition threshold");
DEFINE_double(acq_test_threshold_step, 0.5, "Acquisition threshold step");
DEFINE_double(acq_test_pfa_init, 1e-5, "Set initial threshold via probability of false alarm. Disable with -1.0");
@ -67,6 +79,7 @@ DEFINE_int32(acq_test_fake_PRN, 33, "PRN number of a non-present satellite");
DEFINE_int32(acq_test_iterations, 1, "Number of iterations (same signal, different noise realization)");
DEFINE_bool(plot_acq_test, false, "Plots results with gnuplot, if available");
DEFINE_int32(acq_test_skiphead, 0, "Number of samples to skip in the input file");
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class AcqPerfTest_msg_rx;
@ -151,6 +164,84 @@ protected:
{
cn0_vector = {0.0};
}
if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0)
{
signal_id = "1C";
system_id = 'G';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0)
{
signal_id = "1C";
system_id = 'G';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0)
{
signal_id = "1B";
system_id = 'E';
min_integration_ms = 4;
if (FLAGS_acq_test_coherent_time_ms == 1)
{
coherent_integration_time_ms = 4;
}
else
{
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
}
}
else if (implementation.compare("GLONASS_L1_CA_PCPS_Acquisition") == 0)
{
signal_id = "1G";
system_id = 'R';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
else if (implementation.compare("GLONASS_L2_CA_PCPS_Acquisition") == 0)
{
signal_id = "2G";
system_id = 'R';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
else if (implementation.compare("GPS_L2_M_PCPS_Acquisition") == 0)
{
signal_id = "2S";
system_id = 'G';
if (FLAGS_acq_test_coherent_time_ms == 1)
{
coherent_integration_time_ms = 20;
}
else
{
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
}
min_integration_ms = 20;
}
else if (implementation.compare("Galileo_E5a_Pcps_Acquisition") == 0)
{
signal_id = "5X";
system_id = 'E';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
else if (implementation.compare("GPS_L5i_PCPS_Acquisition") == 0)
{
signal_id = "L5";
system_id = 'G';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
}
else
{
signal_id = "1C";
system_id = 'G';
coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
min_integration_ms = 1;
}
init();
if (FLAGS_acq_test_pfa_init > 0.0)
@ -178,7 +269,7 @@ protected:
num_thresholds = pfa_vector.size();
int aux2 = ((generated_signal_duration_s * 1000 - FLAGS_acq_test_coherent_time_ms) / FLAGS_acq_test_coherent_time_ms);
int aux2 = ((generated_signal_duration_s * 1000 - (FLAGS_acq_test_coherent_time_ms * FLAGS_acq_test_max_dwells)) / (FLAGS_acq_test_coherent_time_ms * FLAGS_acq_test_max_dwells));
if ((FLAGS_acq_test_num_meas > 0) and (FLAGS_acq_test_num_meas < aux2))
{
num_of_measurements = static_cast<unsigned int>(FLAGS_acq_test_num_meas);
@ -200,7 +291,6 @@ protected:
{
}
std::vector<double> cn0_vector;
std::vector<float> pfa_vector;
@ -223,7 +313,7 @@ protected:
gr::msg_queue::sptr queue;
gr::top_block_sptr top_block;
std::shared_ptr<GpsL1CaPcpsAcquisition> acquisition;
std::shared_ptr<AcquisitionInterface> acquisition;
std::shared_ptr<InMemoryConfiguration> config;
std::shared_ptr<FileConfiguration> config_f;
Gnss_Synchro gnss_synchro;
@ -235,10 +325,10 @@ protected:
int message;
boost::thread ch_thread;
std::string implementation = "GPS_L1_CA_PCPS_Acquisition";
std::string implementation = FLAGS_acq_test_implementation;
const double baseband_sampling_freq = static_cast<double>(FLAGS_fs_gen_sps);
const int coherent_integration_time_ms = FLAGS_acq_test_coherent_time_ms;
int coherent_integration_time_ms;
const int in_acquisition = 1;
const int dump_channel = 0;
@ -250,11 +340,14 @@ protected:
std::string path_str = "./acq-perf-test";
int num_thresholds;
unsigned int min_integration_ms;
std::vector<std::vector<float>> Pd;
std::vector<std::vector<float>> Pfa;
std::vector<std::vector<float>> Pd_correct;
std::string signal_id;
private:
std::string generator_binary;
std::string p1;
@ -266,6 +359,7 @@ private:
std::string filename_rinex_obs = FLAGS_filename_rinex_obs;
std::string filename_raw_data = FLAGS_filename_raw_data;
char system_id;
double compute_stdev_precision(const std::vector<double>& vec);
double compute_stdev_accuracy(const std::vector<double>& vec, double ref);
@ -275,8 +369,8 @@ private:
void AcquisitionPerformanceTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'G';
std::string signal = "1C";
gnss_synchro.System = system_id;
std::string signal = signal_id;
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = observed_satellite;
message = 0;
@ -376,50 +470,59 @@ int AcquisitionPerformanceTest::configure_receiver(double cn0, float pfa, unsign
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(sampling_rate_internal));
// Set Acquisition
config->set_property("Acquisition_1C.implementation", implementation);
config->set_property("Acquisition_1C.item_type", "gr_complex");
config->set_property("Acquisition_1C.doppler_max", std::to_string(doppler_max));
config->set_property("Acquisition_1C.doppler_step", std::to_string(doppler_step));
config->set_property("Acquisition.implementation", implementation);
config->set_property("Acquisition.item_type", "gr_complex");
config->set_property("Acquisition.doppler_max", std::to_string(doppler_max));
config->set_property("Acquisition.doppler_min", std::to_string(-doppler_max));
config->set_property("Acquisition.doppler_step", std::to_string(doppler_step));
config->set_property("Acquisition_1C.threshold", std::to_string(pfa));
//if (FLAGS_acq_test_pfa_init > 0.0) config->supersede_property("Acquisition_1C.pfa", std::to_string(pfa));
config->set_property("Acquisition.threshold", std::to_string(pfa));
//if (FLAGS_acq_test_pfa_init > 0.0) config->supersede_property("Acquisition.pfa", std::to_string(pfa));
if (FLAGS_acq_test_pfa_init > 0.0)
{
config->supersede_property("Acquisition_1C.pfa", std::to_string(pfa));
config->supersede_property("Acquisition.pfa", std::to_string(pfa));
}
if (FLAGS_acq_test_use_CFAR_algorithm)
{
config->set_property("Acquisition_1C.use_CFAR_algorithm", "true");
config->set_property("Acquisition.use_CFAR_algorithm", "true");
}
else
{
config->set_property("Acquisition_1C.use_CFAR_algorithm", "false");
config->set_property("Acquisition.use_CFAR_algorithm", "false");
}
config->set_property("Acquisition_1C.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms));
config->set_property("Acquisition.coherent_integration_time_ms", std::to_string(coherent_integration_time_ms));
if (FLAGS_acq_test_bit_transition_flag)
{
config->set_property("Acquisition_1C.bit_transition_flag", "true");
config->set_property("Acquisition.bit_transition_flag", "true");
}
else
{
config->set_property("Acquisition_1C.bit_transition_flag", "false");
config->set_property("Acquisition.bit_transition_flag", "false");
}
config->set_property("Acquisition_1C.max_dwells", std::to_string(FLAGS_acq_test_max_dwells));
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_acq_test_max_dwells));
config->set_property("Acquisition_1C.repeat_satellite", "true");
config->set_property("Acquisition.repeat_satellite", "true");
config->set_property("Acquisition_1C.blocking", "true");
config->set_property("Acquisition_1C.make_two_steps", "false");
config->set_property("Acquisition_1C.second_nbins", std::to_string(4));
config->set_property("Acquisition_1C.second_doppler_step", std::to_string(125));
config->set_property("Acquisition.blocking", "true");
if (FLAGS_acq_test_make_two_steps)
{
config->set_property("Acquisition.make_two_steps", "true");
config->set_property("Acquisition.second_nbins", std::to_string(FLAGS_acq_test_second_nbins));
config->set_property("Acquisition.second_doppler_step", std::to_string(FLAGS_acq_test_second_doppler_step));
}
else
{
config->set_property("Acquisition.make_two_steps", "false");
}
config->set_property("Acquisition_1C.dump", "true");
config->set_property("Acquisition.dump", "true");
std::string dump_file = path_str + std::string("/acquisition_") + std::to_string(cn0) + "_" + std::to_string(iter) + "_" + std::to_string(pfa);
config->set_property("Acquisition_1C.dump_filename", dump_file);
config->set_property("Acquisition_1C.dump_channel", std::to_string(dump_channel));
config->set_property("Acquisition_1C.blocking_on_standby", "true");
config->set_property("Acquisition.dump_filename", dump_file);
config->set_property("Acquisition.dump_channel", std::to_string(dump_channel));
config->set_property("Acquisition.blocking_on_standby", "true");
config_f = 0;
}
@ -450,6 +553,7 @@ int AcquisitionPerformanceTest::run_receiver()
top_block = gr::make_top_block("Acquisition test");
boost::shared_ptr<AcqPerfTest_msg_rx> msg_rx = AcqPerfTest_msg_rx_make(channel_internal_queue);
gr::blocks::skiphead::sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), FLAGS_acq_test_skiphead);
queue = gr::msg_queue::make(0);
gnss_synchro = Gnss_Synchro();
@ -457,23 +561,61 @@ int AcquisitionPerformanceTest::run_receiver()
int nsamples = floor(config->property("GNSS-SDR.internal_fs_sps", 2000000) * generated_signal_duration_s);
boost::shared_ptr<gr::block> valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue);
if (implementation.compare("GPS_L1_CA_PCPS_Acquisition") == 0)
{
acquisition = std::make_shared<GpsL1CaPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GPS_L1_CA_PCPS_Acquisition_Fine_Doppler") == 0)
{
acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFineDoppler>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("Galileo_E1_PCPS_Ambiguous_Acquisition") == 0)
{
acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GLONASS_L1_CA_PCPS_Acquisition") == 0)
{
acquisition = std::make_shared<GlonassL1CaPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GLONASS_L2_CA_PCPS_Acquisition") == 0)
{
acquisition = std::make_shared<GlonassL2CaPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GPS_L2_M_PCPS_Acquisition") == 0)
{
acquisition = std::make_shared<GpsL2MPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("Galileo_E5a_Pcps_Acquisition") == 0)
{
acquisition = std::make_shared<GalileoE5aPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GPS_L5i_PCPS_Acquisition") == 0)
{
acquisition = std::make_shared<GpsL5iPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else
{
bool aux = false;
EXPECT_EQ(true, aux);
}
acquisition = std::make_shared<GpsL1CaPcpsAcquisition>(config.get(), "Acquisition_1C", 1, 0);
acquisition->set_gnss_synchro(&gnss_synchro);
acquisition->set_channel(0);
acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000));
acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 500));
acquisition->set_threshold(config->property("Acquisition.threshold", 0.0));
acquisition->init();
acquisition->set_local_code();
acquisition->set_doppler_max(config->property("Acquisition_1C.doppler_max", 10000));
acquisition->set_doppler_step(config->property("Acquisition_1C.doppler_step", 500));
acquisition->set_threshold(config->property("Acquisition_1C.threshold", 0.0));
acquisition->set_state(1); // Ensure that acquisition starts at the first sample
acquisition->connect(top_block);
top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
acquisition->init();
acquisition->reset();
top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, valve, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, skiphead, 0);
top_block->connect(skiphead, 0, valve, 0);
top_block->connect(valve, 0, acquisition->get_left_block(), 0);
top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
start_queue();
@ -534,9 +676,17 @@ void AcquisitionPerformanceTest::plot_results()
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("linespoints");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.cmd("set font \"Times,18\"");
g1.set_title("Receiver Operating Characteristic for GPS L1 C/A acquisition");
g1.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition_1C.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition_1C.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\"");
g1.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\"");
g1.cmd("set logscale x");
g1.cmd("set yrange [0:1]");
g1.cmd("set xrange[0.0001:1]");
@ -560,12 +710,19 @@ void AcquisitionPerformanceTest::plot_results()
g1.set_legend();
g1.savetops("ROC");
g1.savetopdf("ROC", 18);
if (FLAGS_show_plots) g1.showonscreen(); // window output
Gnuplot g2("linespoints");
if (FLAGS_show_plots)
{
g2.showonscreen(); // window output
}
else
{
g2.disablescreen();
}
g2.cmd("set font \"Times,18\"");
g2.set_title("Receiver Operating Characteristic for GPS L1 C/A valid acquisition");
g2.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition_1C.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition_1C.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\"");
g2.cmd("set label 1 \"" + std::string("Coherent integration time: ") + std::to_string(config->property("Acquisition.coherent_integration_time_ms", 1)) + " ms, Non-coherent integrations: " + std::to_string(config->property("Acquisition.max_dwells", 1)) + " \" at screen 0.12, 0.83 font \"Times,16\"");
g2.cmd("set logscale x");
g2.cmd("set yrange [0:1]");
g2.cmd("set xrange[0.0001:1]");
@ -589,7 +746,6 @@ void AcquisitionPerformanceTest::plot_results()
g2.set_legend();
g2.savetops("ROC-valid-detection");
g2.savetopdf("ROC-valid-detection", 18);
if (FLAGS_show_plots) g2.showonscreen(); // window output
}
catch (const GnuplotException& ge)
{
@ -659,22 +815,40 @@ TEST_F(AcquisitionPerformanceTest, ROC)
run_receiver();
// count executions
std::string basename = path_str + std::string("/acquisition_") + std::to_string(*it) + "_" + std::to_string(iter) + "_" + std::to_string(pfa_vector[pfa_iter]) + "_" + gnss_synchro.System + "_1C";
std::string basename = path_str + std::string("/acquisition_") + std::to_string(*it) + "_" + std::to_string(iter) + "_" + std::to_string(pfa_vector[pfa_iter]) + "_" + gnss_synchro.System + "_" + signal_id;
int num_executions = count_executions(basename, observed_satellite);
// Read measured data
int ch = config->property("Acquisition_1C.dump_channel", 0);
int ch = config->property("Acquisition.dump_channel", 0);
arma::vec meas_timestamp_s = arma::zeros(num_executions, 1);
arma::vec meas_doppler = arma::zeros(num_executions, 1);
arma::vec positive_acq = arma::zeros(num_executions, 1);
arma::vec meas_acq_delay_chips = arma::zeros(num_executions, 1);
double coh_time_ms = config->property("Acquisition_1C.coherent_integration_time_ms", 1);
double coh_time_ms = config->property("Acquisition.coherent_integration_time_ms", 1);
std::cout << "Num executions: " << num_executions << std::endl;
unsigned int fft_size = 0;
unsigned int d_consumed_samples = coh_time_ms * config->property("GNSS-SDR.internal_fs_sps", 0) * 0.001; // * (config->property("Acquisition.bit_transition_flag", false) ? 2 : 1);
if (coh_time_ms == min_integration_ms)
{
fft_size = d_consumed_samples;
}
else
{
fft_size = d_consumed_samples * 2;
}
for (int execution = 1; execution <= num_executions; execution++)
{
acquisition_dump_reader acq_dump(basename, observed_satellite, config->property("Acquisition_1C.doppler_max", 0), config->property("Acquisition_1C.doppler_step", 0), config->property("GNSS-SDR.internal_fs_sps", 0) * GPS_L1_CA_CODE_PERIOD * static_cast<double>(coh_time_ms), ch, execution);
acquisition_dump_reader acq_dump(basename,
observed_satellite,
config->property("Acquisition.doppler_max", 0),
config->property("Acquisition.doppler_step", 0),
fft_size,
ch,
execution);
acq_dump.read_binary_acq();
if (acq_dump.positive_acq)
{
@ -794,7 +968,7 @@ TEST_F(AcquisitionPerformanceTest, ROC)
for (int i = 0; i < num_clean_executions - 1; i++)
{
if (abs(clean_delay_estimation_error(i)) < 0.5 and abs(clean_doppler_estimation_error(i)) < static_cast<float>(config->property("Acquisition_1C.doppler_step", 1)) / 2.0)
if (abs(clean_delay_estimation_error(i)) < 0.5 and abs(clean_doppler_estimation_error(i)) < static_cast<float>(config->property("Acquisition.doppler_step", 1)) / 2.0)
{
correctly_detected = correctly_detected + 1.0;
}

View File

@ -201,6 +201,14 @@ void GalileoE1PcpsAmbiguousAcquisitionTest::plot_grid()
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("lines");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title("Galileo E1b/c signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN));
g1.set_xlabel("Doppler [Hz]");
g1.set_ylabel("Sample");
@ -209,7 +217,6 @@ void GalileoE1PcpsAmbiguousAcquisitionTest::plot_grid()
g1.savetops("Galileo_E1_acq_grid");
g1.savetopdf("Galileo_E1_acq_grid");
if (FLAGS_show_plots) g1.showonscreen();
}
catch (const GnuplotException& ge)
{

View File

@ -341,7 +341,7 @@ void GlonassL1CaPcpsAcquisitionGSoC2017Test::config_2()
std::to_string(integration_time_ms));
config->set_property("Acquisition.max_dwells", "1");
config->set_property("Acquisition.implementation", "GLONASS_L1_CA_PCPS_Acquisition");
config->set_property("Acquisition.pfa", "0.1");
//config->set_property("Acquisition.pfa", "0.1");
config->set_property("Acquisition.doppler_max", "10000");
config->set_property("Acquisition.doppler_step", "250");
config->set_property("Acquisition.bit_transition_flag", "false");
@ -496,7 +496,7 @@ TEST_F(GlonassL1CaPcpsAcquisitionGSoC2017Test, ValidationOfResults)
}) << "Failure setting doppler_step.";
ASSERT_NO_THROW({
acquisition->set_threshold(0.5);
acquisition->set_threshold(0.05);
}) << "Failure setting threshold.";
ASSERT_NO_THROW({

View File

@ -202,6 +202,14 @@ void GpsL1CaPcpsAcquisitionTest::plot_grid()
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("lines");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title("GPS L1 C/A signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN));
g1.set_xlabel("Doppler [Hz]");
g1.set_ylabel("Sample");
@ -210,7 +218,6 @@ void GpsL1CaPcpsAcquisitionTest::plot_grid()
g1.savetops("GPS_L1_acq_grid");
g1.savetopdf("GPS_L1_acq_grid");
if (FLAGS_show_plots) g1.showonscreen();
}
catch (const GnuplotException &ge)
{

View File

@ -205,6 +205,14 @@ void GpsL2MPcpsAcquisitionTest::plot_grid()
Gnuplot::set_GNUPlotPath(gnuplot_path);
Gnuplot g1("impulses");
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title("GPS L2CM signal acquisition for satellite PRN #" + std::to_string(gnss_synchro.PRN));
g1.set_xlabel("Doppler [Hz]");
g1.set_ylabel("Sample");
@ -213,7 +221,6 @@ void GpsL2MPcpsAcquisitionTest::plot_grid()
g1.savetops("GPS_L2CM_acq_grid");
g1.savetopdf("GPS_L2CM_acq_grid");
if (FLAGS_show_plots) g1.showonscreen();
}
catch (const GnuplotException &ge)
{

View File

@ -167,6 +167,20 @@ acquisition_dump_reader::acquisition_dump_reader(const std::string& basename,
{
std::cout << "¡¡¡Unreachable Acquisition dump file!!!" << std::endl;
}
acq_doppler_hz = 0.0;
acq_delay_samples = 0.0;
test_statistic = 0.0;
input_power = 0.0;
threshold = 0.0;
positive_acq = 0;
sample_counter = 0;
PRN = 0;
d_sat = 0;
d_doppler_max = doppler_max_;
d_doppler_step = doppler_step_;
d_samples_per_code = samples_per_code_;
d_num_doppler_bins = 0;
acquisition_dump_reader(basename,
sat_,
doppler_max_,
@ -176,6 +190,7 @@ acquisition_dump_reader::acquisition_dump_reader(const std::string& basename,
execution);
}
acquisition_dump_reader::acquisition_dump_reader(const std::string& basename,
unsigned int sat,
unsigned int doppler_max,
@ -197,6 +212,7 @@ acquisition_dump_reader::acquisition_dump_reader(const std::string& basename,
positive_acq = 0;
sample_counter = 0;
PRN = 0;
if (d_doppler_step == 0) d_doppler_step = 1;
d_num_doppler_bins = static_cast<unsigned int>(ceil(static_cast<double>(static_cast<int>(d_doppler_max) - static_cast<int>(-d_doppler_max)) / static_cast<double>(d_doppler_step)));
std::vector<std::vector<float> > mag_aux(d_num_doppler_bins, std::vector<float>(d_samples_per_code));
mag = mag_aux;

View File

@ -58,6 +58,8 @@
#include "signal_generator_flags.h"
#include "gnss_sdr_sample_counter.h"
#include <matio.h>
#include "test_flags.h"
#include "gnuplot_i.h"
// ######## GNURADIO BLOCK MESSAGE RECEVER FOR TRACKING MESSAGES #########
@ -183,6 +185,7 @@ public:
int configure_generator();
int generate_signal();
bool save_mat_xy(std::vector<double>& x, std::vector<double>& y, std::string filename);
void check_results_carrier_phase(
arma::mat& true_ch0,
arma::mat& true_ch1,
@ -283,10 +286,12 @@ void HybridObservablesTest::configure_receiver()
config->set_property("Tracking_1C.item_type", "gr_complex");
config->set_property("Tracking_1C.dump", "true");
config->set_property("Tracking_1C.dump_filename", "./tracking_ch_");
config->set_property("Tracking_1C.pll_bw_hz", "35.0");
config->set_property("Tracking_1C.dll_bw_hz", "0.5");
config->set_property("Tracking_1C.pll_bw_hz", "5.0");
config->set_property("Tracking_1C.dll_bw_hz", "0.20");
config->set_property("Tracking_1C.pll_bw_narrow_hz", "1.0");
config->set_property("Tracking_1C.dll_bw_narrow_hz", "0.1");
config->set_property("Tracking_1C.extend_correlation_symbols", "20");
config->set_property("Tracking_1C.early_late_space_chips", "0.5");
config->set_property("Tracking_1C.unified", "true");
config->set_property("TelemetryDecoder_1C.dump", "true");
config->set_property("Observables.dump", "true");
@ -384,6 +389,41 @@ void HybridObservablesTest::check_results_carrier_phase(
}
bool HybridObservablesTest::save_mat_xy(std::vector<double>& x, std::vector<double>& y, std::string filename)
{
try
{
// WRITE MAT FILE
mat_t* matfp;
matvar_t* matvar;
filename.append(".mat");
std::cout << "save_mat_xy write " << filename << std::endl;
matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT5);
if (reinterpret_cast<long*>(matfp) != NULL)
{
size_t dims[2] = {1, x.size()};
matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
}
else
{
std::cout << "save_mat_xy: error creating file" << std::endl;
}
Mat_Close(matfp);
return true;
}
catch (const std::exception& ex)
{
std::cout << "save_mat_xy: " << ex.what() << std::endl;
return false;
}
}
void HybridObservablesTest::check_results_code_psudorange(
arma::mat& true_ch0,
arma::mat& true_ch1,
@ -397,7 +437,12 @@ void HybridObservablesTest::check_results_code_psudorange(
int size1 = measured_ch0.col(0).n_rows;
int size2 = measured_ch1.col(0).n_rows;
double t1 = std::min(measured_ch0(size1 - 1, 0), measured_ch1(size2 - 1, 0));
arma::vec t = arma::linspace<arma::vec>(t0, t1, floor((t1 - t0) * 1e3));
//conversion between arma::vec and std:vector
arma::vec t_from_start = arma::linspace<arma::vec>(0, t1 - t0, floor((t1 - t0) * 1e3));
std::vector<double> time_vector(t_from_start.colptr(0), t_from_start.colptr(0) + t_from_start.n_rows);
arma::vec true_ch0_dist_interp;
arma::vec true_ch1_dist_interp;
@ -438,6 +483,31 @@ void HybridObservablesTest::check_results_code_psudorange(
<< " [meters]" << std::endl;
std::cout.precision(ss);
//plots
Gnuplot g3("linespoints");
g3.set_title("Delta Pseudorange error [m]");
g3.set_grid();
g3.set_xlabel("Time [s]");
g3.set_ylabel("Pseudorange error [m]");
//conversion between arma::vec and std:vector
std::vector<double> range_error_m(err.colptr(0), err.colptr(0) + err.n_rows);
g3.cmd("set key box opaque");
g3.plot_xy(time_vector, range_error_m,
"Delta pseudorrange error");
g3.set_legend();
g3.savetops("Delta_pseudorrange_error");
g3.savetopdf("Delta_pseudorrange_error", 18);
if (FLAGS_show_plots)
{
g3.showonscreen(); // window output
}
else
{
g3.disablescreen();
}
//check results against the test tolerance
ASSERT_LT(rmse, 0.5);
ASSERT_LT(error_mean, 0.5);
ASSERT_GT(error_mean, -0.5);
@ -468,7 +538,7 @@ TEST_F(HybridObservablesTest, ValidationOfResults)
tracking_true_obs_reader true_obs_data_ch1;
int test_satellite_PRN = FLAGS_test_satellite_PRN;
int test_satellite_PRN2 = FLAGS_test_satellite_PRN2;
std::cout << "Testing satellite PRNs " << test_satellite_PRN << "," << test_satellite_PRN << std::endl;
std::cout << "Testing satellite PRNs " << test_satellite_PRN << "," << test_satellite_PRN2 << std::endl;
std::string true_obs_file = std::string("./gps_l1_ca_obs_prn");
true_obs_file.append(std::to_string(test_satellite_PRN));
true_obs_file.append(".dat");
@ -700,6 +770,21 @@ TEST_F(HybridObservablesTest, ValidationOfResults)
}
//Cut measurement initial transitory of the measurements
double initial_transitory_s = 30.0;
index = arma::find(measured_ch0.col(0) >= (measured_ch0(0, 0) + initial_transitory_s), 1, "first");
if ((index.size() > 0) and (index(0) > 0))
{
measured_ch0.shed_rows(0, index(0));
}
index = arma::find(measured_ch1.col(0) >= (measured_ch1(0, 0) + initial_transitory_s), 1, "first");
if ((index.size() > 0) and (index(0) > 0))
{
measured_ch1.shed_rows(0, index(0));
}
index = arma::find(measured_ch0.col(0) >= true_ch0(0, 0), 1, "first");
if ((index.size() > 0) and (index(0) > 0))
{

View File

@ -34,6 +34,7 @@
#include <unistd.h>
#include <vector>
#include <armadillo>
#include <matio.h>
#include <boost/filesystem.hpp>
#include <gnuradio/top_block.h>
#include <gnuradio/blocks/file_source.h>
@ -136,20 +137,24 @@ public:
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error);
double& std_dev_error,
double& rmse);
std::vector<double> check_results_acc_carrier_phase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error);
double& std_dev_error,
double& rmse);
std::vector<double> check_results_codephase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error);
double& std_dev_error,
double& rmse);
bool save_mat_xy(std::vector<double>& x, std::vector<double>& y, std::string filename);
GpsL1CADllPllTrackingTest()
{
factory = std::make_shared<GNSSBlockFactory>();
@ -267,7 +272,8 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_doppler(arma::vec&
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error)
double& std_dev_error,
double& rmse)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
@ -289,7 +295,7 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_doppler(arma::vec&
std::vector<double> err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows);
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
@ -317,7 +323,8 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_acc_carrier_phase(a
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error)
double& std_dev_error,
double& rmse)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
@ -332,12 +339,13 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_acc_carrier_phase(a
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
//it is required to remove the initial offset in the accumulated carrier phase error
err = (meas_value - meas_value(0)) - (true_value_interp - true_value_interp(0));
arma::vec err2 = arma::square(err);
//conversion between arma::vec and std:vector
std::vector<double> err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows);
double rmse = sqrt(arma::mean(err2));
rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
@ -364,7 +372,8 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_codephase(arma::vec
arma::vec& meas_time_s,
arma::vec& meas_value,
double& mean_error,
double& std_dev_error)
double& std_dev_error,
double& rmse)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
@ -385,7 +394,7 @@ std::vector<double> GpsL1CADllPllTrackingTest::check_results_codephase(arma::vec
std::vector<double> err_std_vector(err.colptr(0), err.colptr(0) + err.n_rows);
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
@ -420,12 +429,15 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
//data containers for config param sweep
std::vector<std::vector<double>> mean_doppler_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> std_dev_doppler_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> rmse_doppler_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> mean_code_phase_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> std_dev_code_phase_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> rmse_code_phase_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> mean_carrier_phase_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> std_dev_carrier_phase_error_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> rmse_carrier_phase_sweep; //swep config param and cn0 sweep
std::vector<std::vector<double>> trk_valid_timestamp_s_sweep;
std::vector<std::vector<double>> generator_CN0_values_sweep_copy;
@ -528,14 +540,18 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
std::vector<std::vector<double>> doppler_error_sweep;
std::vector<std::vector<double>> code_phase_error_sweep;
std::vector<std::vector<double>> code_phase_error_meters_sweep;
std::vector<std::vector<double>> acc_carrier_phase_error_sweep;
std::vector<double> mean_doppler_error;
std::vector<double> std_dev_doppler_error;
std::vector<double> rmse_doppler;
std::vector<double> mean_code_phase_error;
std::vector<double> std_dev_code_phase_error;
std::vector<double> rmse_code_phase;
std::vector<double> mean_carrier_phase_error;
std::vector<double> std_dev_carrier_phase_error;
std::vector<double> rmse_carrier_phase;
std::vector<double> valid_CN0_values;
configure_receiver(PLL_wide_bw_values.at(config_idx),
@ -682,6 +698,7 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
{
std::vector<double> doppler_error_hz;
std::vector<double> code_phase_error_chips;
std::vector<double> code_phase_error_meters;
std::vector<double> acc_carrier_phase_hz;
try
@ -707,7 +724,7 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
epoch_counter++;
}
// Align initial measurements and cut the tracking pull-in transitory
double pull_in_offset_s = 1.0;
double pull_in_offset_s = FLAGS_skip_trk_transitory_s;
arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first");
if (initial_meas_point.size() > 0 and tracking_last_msg != 3)
@ -720,20 +737,28 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
double mean_error;
double std_dev_error;
double rmse;
valid_CN0_values.push_back(generator_CN0_values.at(current_cn0_idx)); //save the current cn0 value (valid tracking)
doppler_error_hz = check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz, mean_error, std_dev_error);
doppler_error_hz = check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz, mean_error, std_dev_error, rmse);
mean_doppler_error.push_back(mean_error);
std_dev_doppler_error.push_back(std_dev_error);
rmse_doppler.push_back(rmse);
code_phase_error_chips = check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips, mean_error, std_dev_error);
code_phase_error_chips = check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips, mean_error, std_dev_error, rmse);
for (unsigned int ii = 0; ii < code_phase_error_chips.size(); ii++)
{
code_phase_error_meters.push_back(GPS_L1_CA_CHIP_PERIOD * code_phase_error_chips.at(ii) * GPS_C_m_s);
}
mean_code_phase_error.push_back(mean_error);
std_dev_code_phase_error.push_back(std_dev_error);
rmse_code_phase.push_back(rmse);
acc_carrier_phase_hz = check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles, mean_error, std_dev_error);
acc_carrier_phase_hz = check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles, mean_error, std_dev_error, rmse);
mean_carrier_phase_error.push_back(mean_error);
std_dev_carrier_phase_error.push_back(std_dev_error);
rmse_carrier_phase.push_back(rmse);
//save tracking measurement timestamps to std::vector
std::vector<double> vector_trk_timestamp_s(trk_timestamp_s.colptr(0), trk_timestamp_s.colptr(0) + trk_timestamp_s.n_rows);
@ -741,6 +766,7 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
doppler_error_sweep.push_back(doppler_error_hz);
code_phase_error_sweep.push_back(code_phase_error_chips);
code_phase_error_meters_sweep.push_back(code_phase_error_meters);
acc_carrier_phase_error_sweep.push_back(acc_carrier_phase_hz);
}
else
@ -760,10 +786,16 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
{
mean_doppler_error_sweep.push_back(mean_doppler_error);
std_dev_doppler_error_sweep.push_back(std_dev_doppler_error);
rmse_doppler_sweep.push_back(rmse_doppler);
mean_code_phase_error_sweep.push_back(mean_code_phase_error);
std_dev_code_phase_error_sweep.push_back(std_dev_code_phase_error);
rmse_code_phase_sweep.push_back(rmse_code_phase);
mean_carrier_phase_error_sweep.push_back(mean_carrier_phase_error);
std_dev_carrier_phase_error_sweep.push_back(std_dev_carrier_phase_error);
rmse_carrier_phase_sweep.push_back(rmse_carrier_phase);
//make a copy of the CN0 vector for each configuration parameter in order to filter the loss of lock events
generator_CN0_values_sweep_copy.push_back(valid_CN0_values);
}
@ -795,7 +827,14 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++)
{
Gnuplot g1("linespoints");
if (FLAGS_show_plots) g1.showonscreen(); // window output
if (FLAGS_show_plots)
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
g1.set_title(std::to_string(generator_CN0_values.at(current_cn0_idx)) + " dB-Hz, " + "PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz" + "GPS L1 C/A (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g1.set_grid();
g1.set_xlabel("Time [s]");
@ -809,7 +848,14 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
g1.savetopdf("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx)), 18);
}
Gnuplot g2("points");
if (FLAGS_show_plots) g2.showonscreen(); // window output
if (FLAGS_show_plots)
{
g2.showonscreen(); // window output
}
else
{
g2.disablescreen();
}
g2.set_multiplot(ceil(static_cast<float>(generator_CN0_values.size()) / 2.0),
ceil(static_cast<float>(generator_CN0_values.size()) / 2));
for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values.size(); current_cn0_idx++)
@ -840,7 +886,14 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
g3.set_legend();
g3.savetops("CN0_output");
g3.savetopdf("CN0_output", 18);
if (FLAGS_show_plots) g3.showonscreen(); // window output
if (FLAGS_show_plots)
{
g3.showonscreen(); // window output
}
else
{
g3.disablescreen();
}
}
//PLOT ERROR FIGURES (only if it is used the signal generator)
@ -849,7 +902,14 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
if (FLAGS_plot_detail_level >= 1)
{
Gnuplot g5("points");
if (FLAGS_show_plots) g5.showonscreen(); // window output
if (FLAGS_show_plots)
{
g5.showonscreen(); // window output
}
else
{
g5.disablescreen();
}
g5.set_title("Code delay error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g5.set_grid();
g5.set_xlabel("Time [s]");
@ -866,15 +926,61 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
catch (const GnuplotException& ge)
{
}
save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx),
code_phase_error_sweep.at(current_cn0_idx),
"Code_error_chips" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) +
std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx)));
}
g5.set_legend();
g5.set_legend();
g5.savetops("Code_error_output");
g5.savetopdf("Code_error_output", 18);
g5.savetops("Code_error_chips");
g5.savetopdf("Code_error_chips", 18);
Gnuplot g5b("points");
if (FLAGS_show_plots)
{
g5b.showonscreen(); // window output
}
else
{
g5b.disablescreen();
}
g5b.set_title("Code delay error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g5b.set_grid();
g5b.set_xlabel("Time [s]");
g5b.set_ylabel("Code delay error [meters]");
for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++)
{
try
{
g5b.plot_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx), code_phase_error_meters_sweep.at(current_cn0_idx),
std::to_string(static_cast<int>(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz]", decimate);
}
catch (const GnuplotException& ge)
{
}
save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx),
code_phase_error_sweep.at(current_cn0_idx),
"Code_error_meters" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) +
std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx)));
}
g5b.set_legend();
g5b.set_legend();
g5b.savetops("Code_error_meters");
g5b.savetopdf("Code_error_meters", 18);
Gnuplot g6("points");
if (FLAGS_show_plots) g6.showonscreen(); // window output
if (FLAGS_show_plots)
{
g6.showonscreen(); // window output
}
else
{
g6.disablescreen();
}
g6.set_title("Accumulated carrier phase error, PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g6.set_grid();
g6.set_xlabel("Time [s]");
@ -891,20 +997,31 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
catch (const GnuplotException& ge)
{
}
save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx),
acc_carrier_phase_error_sweep.at(current_cn0_idx),
"Carrier_phase_error" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) +
std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx)));
}
g6.set_legend();
g6.set_legend();
g6.savetops("Carrier_phase_error_output");
g6.savetopdf("Carrier_phase_error_output", 18);
g6.savetops("Acc_carrier_phase_error_cycles");
g6.savetopdf("Acc_carrier_phase_error_cycles", 18);
Gnuplot g4("points");
if (FLAGS_show_plots) g4.showonscreen(); // window output
if (FLAGS_show_plots)
{
g4.showonscreen(); // window output
}
else
{
g4.disablescreen();
}
g4.set_multiplot(ceil(static_cast<float>(generator_CN0_values.size()) / 2.0),
ceil(static_cast<float>(generator_CN0_values.size()) / 2));
for (unsigned int current_cn0_idx = 0; current_cn0_idx < generator_CN0_values_sweep_copy.at(config_idx).size(); current_cn0_idx++)
{
g4.reset_plot();
g4.set_title(std::to_string(static_cast<int>(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz], PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g4.set_title("Dopper error" + std::to_string(static_cast<int>(round(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)))) + "[dB-Hz], PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_idx)) + "," + std::to_string(DLL_wide_bw_values.at(config_idx)) + " Hz (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g4.set_grid();
//g4.cmd("set key box opaque");
g4.set_xlabel("Time [s]");
@ -917,10 +1034,15 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
catch (const GnuplotException& ge)
{
}
save_mat_xy(trk_valid_timestamp_s_sweep.at(current_cn0_idx),
doppler_error_sweep.at(current_cn0_idx),
"Doppler_error" + std::to_string(generator_CN0_values_sweep_copy.at(config_idx).at(current_cn0_idx)) +
std::to_string(PLL_wide_bw_values.at(config_idx)) + "_" + std::to_string(DLL_wide_bw_values.at(config_idx)));
}
g4.unset_multiplot();
g4.savetops("Doppler_error_output");
g4.savetopdf("Doppler_error_output", 18);
g4.savetops("Doppler_error_hz");
g4.savetopdf("Doppler_error_hz", 18);
}
}
}
@ -942,7 +1064,14 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
//plot metrics
Gnuplot g7("linespoints");
if (FLAGS_show_plots) g7.showonscreen(); // window output
if (FLAGS_show_plots)
{
g7.showonscreen(); // window output
}
else
{
g7.disablescreen();
}
g7.set_title("Doppler error metrics (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g7.set_grid();
g7.set_xlabel("CN0 [dB-Hz]");
@ -957,10 +1086,17 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
std_dev_doppler_error_sweep.at(config_sweep_idx),
"PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz");
//matlab save
save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx),
rmse_doppler_sweep.at(config_sweep_idx),
"RMSE_Doppler_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)));
}
g7.savetops("Doppler_error_metrics");
g7.savetopdf("Doppler_error_metrics", 18);
Gnuplot g8("linespoints");
g8.set_title("Accumulated carrier phase error metrics (PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
g8.set_grid();
@ -976,6 +1112,11 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
std_dev_carrier_phase_error_sweep.at(config_sweep_idx),
"PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz");
//matlab save
save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx),
rmse_carrier_phase_sweep.at(config_sweep_idx),
"RMSE_Carrier_Phase_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)));
}
g8.savetops("Carrier_error_metrics");
g8.savetopdf("Carrier_error_metrics", 18);
@ -995,6 +1136,11 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
std_dev_code_phase_error_sweep.at(config_sweep_idx),
"PLL/DLL BW: " + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"," + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)) + " Hz");
//matlab save
save_mat_xy(generator_CN0_values_sweep_copy.at(config_sweep_idx),
rmse_code_phase_sweep.at(config_sweep_idx),
"RMSE_Code_Phase_CN0_Sweep_PLL_DLL" + std::to_string(PLL_wide_bw_values.at(config_sweep_idx)) +
+"_" + std::to_string(DLL_wide_bw_values.at(config_sweep_idx)));
}
g9.savetops("Code_error_metrics");
g9.savetopdf("Code_error_metrics", 18);
@ -1006,3 +1152,33 @@ TEST_F(GpsL1CADllPllTrackingTest, ValidationOfResults)
}
}
}
bool GpsL1CADllPllTrackingTest::save_mat_xy(std::vector<double>& x, std::vector<double>& y, std::string filename)
{
try
{
// WRITE MAT FILE
mat_t* matfp;
matvar_t* matvar;
filename.erase(filename.length() - 4, 4);
filename.append(".mat");
matfp = Mat_CreateVer(filename.c_str(), NULL, MAT_FT_MAT73);
if (reinterpret_cast<long*>(matfp) != NULL)
{
size_t dims[2] = {1, x.size()};
matvar = Mat_VarCreate("x", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &x[0], 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
matvar = Mat_VarCreate("y", MAT_C_DOUBLE, MAT_T_DOUBLE, 2, dims, &y[0], 0);
Mat_VarWrite(matfp, matvar, MAT_COMPRESSION_ZLIB); // or MAT_COMPRESSION_NONE
Mat_VarFree(matvar);
}
Mat_Close(matfp);
return true;
}
catch (const std::exception& ex)
{
return false;
}
}

View File

@ -1,5 +1,5 @@
/*!
* \file gps_l1_ca_dll_pll_tracking_test.cc
* \file tracking_test.cc
* \brief This class implements a tracking Pull-In test for GPS_L1_CA_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Javier Arribas, 2018. jarribas(at)cttc.es
@ -40,11 +40,17 @@
#include <gnuradio/blocks/interleaved_char_to_complex.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/blocks/head.h>
#include <gtest/gtest.h>
#include "GPS_L1_CA.h"
#include "gnss_block_factory.h"
#include "tracking_interface.h"
#include "gps_l2_m_pcps_acquisition.h"
#include "gps_l1_ca_pcps_acquisition.h"
#include "gps_l1_ca_pcps_acquisition_fine_doppler.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf.h"
#include "galileo_e5a_pcps_acquisition.h"
#include "gps_l5i_pcps_acquisition.h"
#include "in_memory_configuration.h"
#include "tracking_true_obs_reader.h"
#include "tracking_dump_reader.h"
@ -71,6 +77,7 @@ private:
public:
int rx_message;
gr::top_block_sptr top_block;
~Acquisition_msg_rx(); //!< Default destructor
};
@ -87,6 +94,7 @@ void Acquisition_msg_rx::msg_handler_events(pmt::pmt_t msg)
{
long int message = pmt::to_long(msg);
rx_message = message;
top_block->stop(); //stop the flowgraph
}
catch (boost::bad_any_cast& e)
{
@ -106,32 +114,32 @@ Acquisition_msg_rx::Acquisition_msg_rx() : gr::block("Acquisition_msg_rx", gr::i
Acquisition_msg_rx::~Acquisition_msg_rx() {}
// ######## GNURADIO TRACKING BLOCK MESSAGE RECEVER #########
class GpsL1CADllPllTrackingPullInTest_msg_rx;
class TrackingPullInTest_msg_rx;
typedef boost::shared_ptr<GpsL1CADllPllTrackingPullInTest_msg_rx> GpsL1CADllPllTrackingPullInTest_msg_rx_sptr;
typedef boost::shared_ptr<TrackingPullInTest_msg_rx> TrackingPullInTest_msg_rx_sptr;
GpsL1CADllPllTrackingPullInTest_msg_rx_sptr GpsL1CADllPllTrackingPullInTest_msg_rx_make();
TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make();
class GpsL1CADllPllTrackingPullInTest_msg_rx : public gr::block
class TrackingPullInTest_msg_rx : public gr::block
{
private:
friend GpsL1CADllPllTrackingPullInTest_msg_rx_sptr GpsL1CADllPllTrackingPullInTest_msg_rx_make();
friend TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make();
void msg_handler_events(pmt::pmt_t msg);
GpsL1CADllPllTrackingPullInTest_msg_rx();
TrackingPullInTest_msg_rx();
public:
int rx_message;
~GpsL1CADllPllTrackingPullInTest_msg_rx(); //!< Default destructor
~TrackingPullInTest_msg_rx(); //!< Default destructor
};
GpsL1CADllPllTrackingPullInTest_msg_rx_sptr GpsL1CADllPllTrackingPullInTest_msg_rx_make()
TrackingPullInTest_msg_rx_sptr TrackingPullInTest_msg_rx_make()
{
return GpsL1CADllPllTrackingPullInTest_msg_rx_sptr(new GpsL1CADllPllTrackingPullInTest_msg_rx());
return TrackingPullInTest_msg_rx_sptr(new TrackingPullInTest_msg_rx());
}
void GpsL1CADllPllTrackingPullInTest_msg_rx::msg_handler_events(pmt::pmt_t msg)
void TrackingPullInTest_msg_rx::msg_handler_events(pmt::pmt_t msg)
{
try
{
@ -147,22 +155,22 @@ void GpsL1CADllPllTrackingPullInTest_msg_rx::msg_handler_events(pmt::pmt_t msg)
}
GpsL1CADllPllTrackingPullInTest_msg_rx::GpsL1CADllPllTrackingPullInTest_msg_rx() : gr::block("GpsL1CADllPllTrackingPullInTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
TrackingPullInTest_msg_rx::TrackingPullInTest_msg_rx() : gr::block("TrackingPullInTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"), boost::bind(&GpsL1CADllPllTrackingPullInTest_msg_rx::msg_handler_events, this, _1));
this->set_msg_handler(pmt::mp("events"), boost::bind(&TrackingPullInTest_msg_rx::msg_handler_events, this, _1));
rx_message = 0;
}
GpsL1CADllPllTrackingPullInTest_msg_rx::~GpsL1CADllPllTrackingPullInTest_msg_rx()
TrackingPullInTest_msg_rx::~TrackingPullInTest_msg_rx()
{
}
// ###########################################################
class GpsL1CADllPllTrackingPullInTest : public ::testing::Test
class TrackingPullInTest : public ::testing::Test
{
public:
std::string generator_binary;
@ -172,7 +180,7 @@ public:
std::string p4;
std::string p5;
std::string p6;
std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking"; //"GPS_L1_CA_DLL_PLL_C_Aid_Tracking";
std::string implementation = FLAGS_trk_test_implementation;
const int baseband_sampling_freq = FLAGS_fs_gen_sps;
@ -204,7 +212,7 @@ public:
double& mean_error,
double& std_dev_error);
GpsL1CADllPllTrackingPullInTest()
TrackingPullInTest()
{
factory = std::make_shared<GNSSBlockFactory>();
config = std::make_shared<InMemoryConfiguration>();
@ -212,7 +220,7 @@ public:
gnss_synchro = Gnss_Synchro();
}
~GpsL1CADllPllTrackingPullInTest()
~TrackingPullInTest()
{
}
@ -231,7 +239,7 @@ public:
};
int GpsL1CADllPllTrackingPullInTest::configure_generator(double CN0_dBHz, int file_idx)
int TrackingPullInTest::configure_generator(double CN0_dBHz, int file_idx)
{
// Configure signal generator
generator_binary = FLAGS_generator_binary;
@ -253,7 +261,7 @@ int GpsL1CADllPllTrackingPullInTest::configure_generator(double CN0_dBHz, int fi
}
int GpsL1CADllPllTrackingPullInTest::generate_signal()
int TrackingPullInTest::generate_signal()
{
int child_status;
@ -276,48 +284,104 @@ int GpsL1CADllPllTrackingPullInTest::generate_signal()
}
void GpsL1CADllPllTrackingPullInTest::configure_receiver(
void TrackingPullInTest::configure_receiver(
double PLL_wide_bw_hz,
double DLL_wide_bw_hz,
double PLL_narrow_bw_hz,
double DLL_narrow_bw_hz,
int extend_correlation_symbols)
{
config = std::make_shared<InMemoryConfiguration>();
config->set_property("Tracking.dump", "true");
config->set_property("Tracking.dump_filename", "./tracking_ch_");
config->set_property("Tracking.implementation", implementation);
config->set_property("Tracking.item_type", "gr_complex");
config->set_property("Tracking.pll_bw_hz", std::to_string(PLL_wide_bw_hz));
config->set_property("Tracking.dll_bw_hz", std::to_string(DLL_wide_bw_hz));
config->set_property("Tracking.extend_correlation_symbols", std::to_string(extend_correlation_symbols));
config->set_property("Tracking.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz));
config->set_property("Tracking.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz));
gnss_synchro.PRN = FLAGS_test_satellite_PRN;
gnss_synchro.Channel_ID = 0;
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
std::string System_and_Signal;
if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0)
{
gnss_synchro.System = 'G';
std::string signal = "1C";
System_and_Signal = "GPS L1 CA";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = FLAGS_test_satellite_PRN;
config = std::make_shared<InMemoryConfiguration>();
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
// Set Tracking
config->set_property("Tracking_1C.implementation", implementation);
config->set_property("Tracking_1C.item_type", "gr_complex");
config->set_property("Tracking_1C.pll_bw_hz", std::to_string(PLL_wide_bw_hz));
config->set_property("Tracking_1C.dll_bw_hz", std::to_string(DLL_wide_bw_hz));
config->set_property("Tracking_1C.early_late_space_chips", "0.5");
config->set_property("Tracking_1C.extend_correlation_symbols", std::to_string(extend_correlation_symbols));
config->set_property("Tracking_1C.pll_bw_narrow_hz", std::to_string(PLL_narrow_bw_hz));
config->set_property("Tracking_1C.dll_bw_narrow_hz", std::to_string(DLL_narrow_bw_hz));
config->set_property("Tracking_1C.early_late_space_narrow_chips", "0.5");
config->set_property("Tracking_1C.dump", "true");
config->set_property("Tracking_1C.dump_filename", "./tracking_ch_");
config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.early_late_space_narrow_chips", "0.5");
}
else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0)
{
gnss_synchro.System = 'E';
std::string signal = "1B";
System_and_Signal = "Galileo E1B";
signal.copy(gnss_synchro.Signal, 2, 0);
config->set_property("Tracking.early_late_space_chips", "0.15");
config->set_property("Tracking.very_early_late_space_chips", "0.6");
config->set_property("Tracking.early_late_space_narrow_chips", "0.15");
config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6");
config->set_property("Tracking.track_pilot", "true");
}
else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0)
{
gnss_synchro.System = 'G';
std::string signal = "2S";
System_and_Signal = "GPS L2CM";
signal.copy(gnss_synchro.Signal, 2, 0);
config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.track_pilot", "false");
}
else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0 or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0)
{
gnss_synchro.System = 'E';
std::string signal = "5X";
System_and_Signal = "Galileo E5a";
signal.copy(gnss_synchro.Signal, 2, 0);
if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0)
{
config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking"));
}
config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.track_pilot", "false");
config->set_property("Tracking.order", "2");
}
else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0)
{
gnss_synchro.System = 'G';
std::string signal = "L5";
System_and_Signal = "GPS L5I";
signal.copy(gnss_synchro.Signal, 2, 0);
config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.track_pilot", "false");
config->set_property("Tracking.order", "2");
}
else
{
std::cout << "The test can not run with the selected tracking implementation\n ";
throw(std::exception());
}
std::cout << "*****************************************\n";
std::cout << "*** Tracking configuration parameters ***\n";
std::cout << "*****************************************\n";
std::cout << "pll_bw_hz: " << config->property("Tracking_1C.pll_bw_hz", 0.0) << " Hz\n";
std::cout << "dll_bw_hz: " << config->property("Tracking_1C.dll_bw_hz", 0.0) << " Hz\n";
std::cout << "pll_bw_narrow_hz: " << config->property("Tracking_1C.pll_bw_narrow_hz", 0.0) << " Hz\n";
std::cout << "dll_bw_narrow_hz: " << config->property("Tracking_1C.dll_bw_narrow_hz", 0.0) << " Hz\n";
std::cout << "extend_correlation_symbols: " << config->property("Tracking_1C.extend_correlation_symbols", 0) << " Symbols\n";
std::cout << "Signal: " << System_and_Signal << "\n";
std::cout << "implementation: " << config->property("Tracking.implementation", std::string("undefined")) << " \n";
std::cout << "pll_bw_hz: " << config->property("Tracking.pll_bw_hz", 0.0) << " Hz\n";
std::cout << "dll_bw_hz: " << config->property("Tracking.dll_bw_hz", 0.0) << " Hz\n";
std::cout << "pll_bw_narrow_hz: " << config->property("Tracking.pll_bw_narrow_hz", 0.0) << " Hz\n";
std::cout << "dll_bw_narrow_hz: " << config->property("Tracking.dll_bw_narrow_hz", 0.0) << " Hz\n";
std::cout << "extend_correlation_symbols: " << config->property("Tracking.extend_correlation_symbols", 0) << " Symbols\n";
std::cout << "*****************************************\n";
std::cout << "*****************************************\n";
}
bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
bool TrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
{
// 1. Setup GNU Radio flowgraph (file_source -> Acquisition_10m)
gr::top_block_sptr top_block;
@ -326,23 +390,110 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
// Satellite signal definition
Gnss_Synchro tmp_gnss_synchro;
tmp_gnss_synchro.Channel_ID = 0;
config = std::make_shared<InMemoryConfiguration>();
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
config->set_property("Acquisition.blocking_on_standby", "true");
config->set_property("Acquisition.blocking", "true");
config->set_property("Acquisition.dump", "false");
config->set_property("Acquisition.dump_filename", "./data/acquisition.dat");
config->set_property("Acquisition.use_CFAR_algorithm", "false");
std::shared_ptr<AcquisitionInterface> acquisition;
std::string System_and_Signal;
//create the correspondign acquisition block according to the desired tracking signal
if (implementation.compare("GPS_L1_CA_DLL_PLL_Tracking") == 0)
{
tmp_gnss_synchro.System = 'G';
std::string signal = "1C";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "GPS L1 CA";
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
acquisition = std::make_shared<GpsL1CaPcpsAcquisitionFineDoppler>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0)
{
tmp_gnss_synchro.System = 'E';
std::string signal = "1B";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "Galileo E1B";
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
acquisition = std::make_shared<GalileoE1PcpsAmbiguousAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GPS_L2_M_DLL_PLL_Tracking") == 0)
{
tmp_gnss_synchro.System = 'G';
std::string signal = "2S";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "GPS L2CM";
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
acquisition = std::make_shared<GpsL2MPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0)
{
tmp_gnss_synchro.System = 'E';
std::string signal = "5X";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "Galileo E5a";
config->set_property("Acquisition_5X.coherent_integration_time_ms", "1");
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
config->set_property("Acquisition.CAF_window_hz", "0"); // **Only for E5a** Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated. Recommended value 3000 Hz
config->set_property("Acquisition.Zero_padding", "0"); //**Only for E5a** Avoids power loss and doppler ambiguity in bit transitions by correlating one code with twice the input data length, ensuring that at least one full code is present without transitions. If set to 1 it is ON, if set to 0 it is OFF.
config->set_property("Acquisition.bit_transition_flag", "false");
acquisition = std::make_shared<GalileoE5aNoncoherentIQAcquisitionCaf>(config.get(), "Acquisition", 1, 0);
}
config = std::make_shared<InMemoryConfiguration>();
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0)
{
tmp_gnss_synchro.System = 'E';
std::string signal = "5X";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "Galileo E5a";
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
acquisition = std::make_shared<GalileoE5aPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else if (implementation.compare("GPS_L5_DLL_PLL_Tracking") == 0)
{
tmp_gnss_synchro.System = 'G';
std::string signal = "L5";
signal.copy(tmp_gnss_synchro.Signal, 2, 0);
tmp_gnss_synchro.PRN = SV_ID;
System_and_Signal = "GPS L5I";
config->set_property("Acquisition.max_dwells", std::to_string(FLAGS_external_signal_acquisition_dwells));
acquisition = std::make_shared<GpsL5iPcpsAcquisition>(config.get(), "Acquisition", 1, 0);
}
else
{
std::cout << "The test can not run with the selected tracking implementation\n ";
throw(std::exception());
}
GNSSBlockFactory block_factory;
GpsL1CaPcpsAcquisitionFineDoppler* acquisition;
acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(config.get(), "Acquisition", 1, 1);
acquisition->set_channel(1);
acquisition->set_gnss_synchro(&tmp_gnss_synchro);
acquisition->set_threshold(config->property("Acquisition.threshold", 0.005));
acquisition->set_doppler_max(config->property("Acquisition.doppler_max", 10000));
acquisition->set_doppler_step(config->property("Acquisition.doppler_step", 250));
acquisition->set_channel(0);
acquisition->set_doppler_max(config->property("Acquisition.doppler_max", FLAGS_external_signal_acquisition_doppler_max_hz));
acquisition->set_doppler_step(config->property("Acquisition.doppler_step", FLAGS_external_signal_acquisition_doppler_step_hz));
acquisition->set_threshold(config->property("Acquisition.threshold", FLAGS_external_signal_acquisition_threshold));
acquisition->init();
acquisition->set_local_code();
acquisition->set_state(1); // Ensure that acquisition starts at the first sample
acquisition->connect(top_block);
gr::blocks::file_source::sptr file_source;
std::string file = FLAGS_signal_file;
const char* file_name = file.c_str();
file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false);
file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample
gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make();
//gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration);
top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0);
//top_block->connect(head_samples, 0, acquisition->get_left_block(), 0);
boost::shared_ptr<Acquisition_msg_rx> msg_rx;
try
@ -355,15 +506,8 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
exit(0);
}
gr::blocks::file_source::sptr file_source;
std::string file = FLAGS_signal_file;
const char* file_name = file.c_str();
file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false);
gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make();
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, acquisition->get_left_block(), 0);
top_block->msg_connect(acquisition->get_left_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
msg_rx->top_block = top_block;
top_block->msg_connect(acquisition->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
// 5. Run the flowgraph
// Get visible GPS satellites (positive acquisitions with Doppler measurements)
@ -378,6 +522,7 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
code_delay_measurements_map.clear();
acq_samplestamp_map.clear();
for (unsigned int PRN = 1; PRN < 33; PRN++)
{
tmp_gnss_synchro.PRN = PRN;
@ -385,12 +530,13 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
acquisition->init();
acquisition->set_local_code();
acquisition->reset();
acquisition->set_state(1);
msg_rx->rx_message = 0;
top_block->run();
if (start_msg == true)
{
std::cout << "Reading external signal file: " << FLAGS_signal_file << std::endl;
std::cout << "Searching for GPS Satellites in L1 band..." << std::endl;
std::cout << "Searching for " << System_and_Signal << " Satellites..." << std::endl;
std::cout << "[";
start_msg = false;
}
@ -410,10 +556,16 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
std::cout << " . ";
}
top_block->stop();
file_source->seek(0, 0);
file_source->seek(2 * FLAGS_skip_samples, 0); //skip head. ibyte, two bytes per complex sample
std::cout.flush();
}
std::cout << "]" << std::endl;
std::cout << "-------------------------------------------\n";
for (auto& x : doppler_measurements_map)
{
std::cout << "DETECTED SATELLITE " << System_and_Signal << " PRN: " << x.first << " with Doppler: " << x.second << " [Hz], code phase: " << code_delay_measurements_map.at(x.first) << " [samples] at signal SampleStamp " << acq_samplestamp_map.at(x.first) << "\n";
}
// report the elapsed time
end = std::chrono::system_clock::now();
@ -424,7 +576,7 @@ bool GpsL1CADllPllTrackingPullInTest::acquire_GPS_L1CA_signal(int SV_ID)
return true;
}
TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
TEST_F(TrackingPullInTest, ValidationOfResults)
{
//*************************************************
//***** STEP 1: Prepare the parameters sweep ******
@ -531,8 +683,10 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
{
true_acq_doppler_hz = doppler_measurements_map.find(FLAGS_test_satellite_PRN)->second;
true_acq_delay_samples = code_delay_measurements_map.find(FLAGS_test_satellite_PRN)->second;
acq_samplestamp_samples = 0; //acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second;
std::cout << "Estimated Initial Doppler " << true_acq_doppler_hz << "[Hz], estimated Initial code delay " << true_acq_delay_samples << " [Samples]" << std::endl;
acq_samplestamp_samples = 0;
std::cout << "Estimated Initial Doppler " << true_acq_doppler_hz
<< " [Hz], estimated Initial code delay " << true_acq_delay_samples << " [Samples]"
<< " Acquisition SampleStamp is " << acq_samplestamp_map.find(FLAGS_test_satellite_PRN)->second << std::endl;
}
//CN0 LOOP
std::vector<std::vector<double>> pull_in_results_v_v;
@ -552,9 +706,9 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
//create flowgraph
top_block = gr::make_top_block("Tracking test");
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config, "Tracking_1C", implementation, 1, 1);
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config, "Tracking", config->property("Tracking.implementation", std::string("undefined")), 1, 1);
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_);
boost::shared_ptr<GpsL1CADllPllTrackingPullInTest_msg_rx> msg_rx = GpsL1CADllPllTrackingPullInTest_msg_rx_make();
boost::shared_ptr<TrackingPullInTest_msg_rx> msg_rx = TrackingPullInTest_msg_rx_make();
ASSERT_NO_THROW({
@ -583,19 +737,20 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false);
gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make();
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
gr::blocks::head::sptr head_samples = gr::blocks::head::make(sizeof(gr_complex), baseband_sampling_freq * FLAGS_duration);
top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0);
top_block->connect(gr_interleaved_char_to_complex, 0, head_samples, 0);
top_block->connect(head_samples, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
file_source->seek(acq_samplestamp_samples, 0);
file_source->seek(2 * FLAGS_skip_samples + acq_samplestamp_samples, 0); //skip head. ibyte, two bytes per complex sample
}) << "Failure connecting the blocks of tracking test.";
//********************************************************************
//***** STEP 5: Perform the signal tracking and read the results *****
//********************************************************************
std::cout << "------------ START TRACKING -------------" << std::endl;
std::cout << "--- START TRACKING WITH PULL-IN ERROR: " << acq_doppler_error_hz_values.at(current_acq_doppler_error_idx) << " [Hz] and " << acq_delay_error_chips_values.at(current_acq_doppler_error_idx).at(current_acq_code_error_idx) << " [Chips] ---" << std::endl;
tracking->start_tracking();
std::chrono::time_point<std::chrono::system_clock> start, end;
EXPECT_NO_THROW({
@ -630,6 +785,8 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
std::vector<double> prompt;
std::vector<double> early;
std::vector<double> late;
std::vector<double> v_early;
std::vector<double> v_late;
std::vector<double> promptI;
std::vector<double> promptQ;
std::vector<double> CN0_dBHz;
@ -647,6 +804,8 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
prompt.push_back(trk_dump.abs_P);
early.push_back(trk_dump.abs_E);
late.push_back(trk_dump.abs_L);
v_early.push_back(trk_dump.abs_VE);
v_late.push_back(trk_dump.abs_VL);
promptI.push_back(trk_dump.prompt_I);
promptQ.push_back(trk_dump.prompt_Q);
CN0_dBHz.push_back(trk_dump.CN0_SNV_dB_Hz);
@ -692,6 +851,11 @@ TEST_F(GpsL1CADllPllTrackingPullInTest, ValidationOfResults)
g1.plot_xy(trk_timestamp_s, prompt, "Prompt", decimate);
g1.plot_xy(trk_timestamp_s, early, "Early", decimate);
g1.plot_xy(trk_timestamp_s, late, "Late", decimate);
if (implementation.compare("Galileo_E1_DLL_PLL_VEML_Tracking") == 0)
{
g1.plot_xy(trk_timestamp_s, v_early, "Very Early", decimate);
g1.plot_xy(trk_timestamp_s, v_late, "Very Late", decimate);
}
g1.set_legend();
//g1.savetops("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx)));
//g1.savetopdf("Correlators_outputs" + std::to_string(generator_CN0_values.at(current_cn0_idx)), 18);

View File

@ -33,6 +33,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl
${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters
${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks
${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/libs
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}

View File

@ -144,8 +144,6 @@ FrontEndCal_msg_rx::FrontEndCal_msg_rx() : gr::block("FrontEndCal_msg_rx", gr::i
FrontEndCal_msg_rx::~FrontEndCal_msg_rx() {}
void wait_message()
{
while (!stop)
@ -353,13 +351,14 @@ int main(int argc, char** argv)
gnss_synchro->PRN = 1;
long fs_in_ = configuration->property("GNSS-SDR.internal_fs_sps", 2048000);
configuration->set_property("Acquisition.max_dwells", "10");
GNSSBlockFactory block_factory;
acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(configuration.get(), "Acquisition", 1, 1);
acquisition->set_channel(1);
acquisition->set_gnss_synchro(gnss_synchro);
acquisition->set_threshold(configuration->property("Acquisition.threshold", 0.0));
acquisition->set_threshold(configuration->property("Acquisition.threshold", 2.0));
acquisition->set_doppler_max(configuration->property("Acquisition.doppler_max", 10000));
acquisition->set_doppler_step(configuration->property("Acquisition.doppler_step", 250));

View File

@ -85,7 +85,7 @@ Acquisition_2S.doppler_step=125
Acquisition_2S.use_CFAR_algorithm=false
Acquisition_2S.threshold=19.5
Acquisition_2S.threshold=10
Acquisition_2S.blocking=true