Unified acquisition

This commit is contained in:
marc-sales 2014-08-05 02:01:37 +02:00
parent 7d6ec42f24
commit 3b3c809dab
45 changed files with 2081 additions and 5289 deletions

View File

@ -7,7 +7,7 @@
;######### GLOBAL OPTIONS ##################
;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz].
GNSS-SDR.internal_fs_hz=12000000
GNSS-SDR.internal_fs_hz=32000000
;######### CONTROL_THREAD CONFIG ############
ControlThread.wait_for_flowgraph=false
@ -32,15 +32,15 @@ SignalSource.implementation=File_Signal_Source
;SignalSource.filename=/home/marc/E5a_acquisitions/signal_source_5X_primary.dat
;SignalSource.filename=/home/marc/E5a_acquisitions/galileo_E5_8M_r2_upsampled_12.dat
;SignalSource.filename=/home/marc/E5a_acquisitions/Tiered_sim_4sat_stup4_2s_up.dat
SignalSource.filename=/home/marc/E5a_acquisitions/signal_source_sec21M_long.dat
;SignalSource.filename=/home/marc/E5a_acquisitions/signal_source_sec21M_long.dat
SignalSource.filename=/home/marc/E5a_acquisitions/32MS_complex.dat;
;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version.
SignalSource.item_type=gr_complex
;#sampling_frequency: Original Signal sampling frequency in [Hz]
SignalSource.sampling_frequency=12000000
SignalSource.sampling_frequency=32000000
;#freq: RF front-end center frequency in [Hz]
SignalSource.freq=1176450000
@ -151,7 +151,7 @@ InputFilter.grid_density=16
;#The following options are used only in Freq_Xlating_Fir_Filter implementation.
;#InputFilter.IF is the intermediate frequency (in Hz) shifted down to zero Hz
InputFilter.sampling_frequency=12000000
InputFilter.sampling_frequency=32000000
InputFilter.IF=0
@ -246,7 +246,7 @@ Channel.system=Galileo
;# "6Q" COMPASS E6 Q
;# "6X" COMPASS E6 IQ
;#if the option is disabled by default is assigned "1C" GPS L1 C/A
Channel.signal=5Q
Channel.signal=5X
;######### SPECIFIC CHANNELS CONFIG ######
;#The following options are specific to each channel and overwrite the generic options
@ -254,29 +254,29 @@ Channel.signal=5Q
;######### CHANNEL 0 CONFIG ############
Channel0.system=Galileo
Channel0.signal=5Q
Channel0.signal=5X
;#satellite: Satellite PRN ID for this channel. Disable this option to random search
Channel0.satellite=11
Channel0.satellite=19
;Channel0.repeat_satellite=true
;######### CHANNEL 1 CONFIG ############
Channel1.system=Galileo
Channel1.signal=5Q
Channel1.satellite=12
;Channel1.system=Galileo
;Channel1.signal=5Q
;Channel1.satellite=12
;######### CHANNEL 2 CONFIG ############
Channel2.system=Galileo
Channel2.signal=5Q
Channel2.satellite=19
;Channel2.system=Galileo
;Channel2.signal=5Q
;Channel2.satellite=11
;######### CHANNEL 3 CONFIG ############
Channel3.system=Galileo
Channel3.signal=5Q
Channel3.satellite=20
;Channel3.system=Galileo
;Channel3.signal=5Q
;Channel3.satellite=20
;######### ACQUISITION GLOBAL CONFIG ############
@ -289,13 +289,13 @@ Acquisition.item_type=gr_complex
;#if: Signal intermediate frequency in [Hz]
Acquisition.if=0
;#sampled_ms: Signal block duration for the acquisition signal detection [ms]
Acquisition.coherent_integration_time_ms=2
Acquisition.coherent_integration_time_ms=1
;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition]
Acquisition.implementation=Galileo_E5a_3ms_Noncoherent_IQ_Acquisition
Acquisition.implementation=Galileo_E5a_Noncoherent_IQ_Acquisition_CAF
;#threshold: Acquisition threshold. It will be ignored if pfa is defined.
Acquisition.threshold=0.0005
Acquisition.threshold=0.001
;#pfa: Acquisition false alarm probability. This option overrides the threshold option. Only use with implementations: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition]
;Acquisition.pfa=0.0001
Acquisition.pfa=0.0003
;#doppler_max: Maximum expected Doppler shift [Hz]
Acquisition.doppler_max=10000
;#doppler_max: Doppler step in the grid search [Hz]
@ -304,7 +304,13 @@ Acquisition.doppler_step=250
;maximum test statistics. Only use with implementation: [GPS_L1_CA_PCPS_Acquisition] (should not be used for Galileo_E1_PCPS_Ambiguous_Acquisition])
Acquisition.bit_transition_flag=false
;#max_dwells: Maximum number of consecutive dwells to be processed. It will be ignored if bit_transition_flag=true
Acquisition.max_dwells=2
Acquisition.max_dwells=1
;#CAF filter: Resolves doppler ambiguity averaging the specified BW in the winner code delay. If set to 0 CAF filter is desactivated.
Acquisition.CAF_window_hz=2000
;#Zero_padding: 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.
Acquisition.Zero_padding=0
;######### ACQUISITION CHANNELS CONFIG ######
;#The following options are specific to each channel and overwrite the generic options
@ -343,8 +349,15 @@ Tracking.dump=true
;#dump_filename: Log path and filename. Notice that the tracking channel will add "x.dat" where x is the channel number.
Tracking.dump_filename=./tracking_ch_
;#pll_bw_hz_init: PLL loop filter bandwidth during initialization [Hz]
Tracking.pll_bw_hz_init=20.0;
;#dll_bw_hz_init: DLL loop filter bandwidth during initialization [Hz]
Tracking.dll_bw_hz_init=20.0;
;#dll_ti_ms: loop filter integration time after initialization (secondary code delay search)[ms]
Tracking.ti_ms=3;
;#pll_bw_hz: PLL loop filter bandwidth [Hz]
Tracking.pll_bw_hz=50.0;
Tracking.pll_bw_hz=5.0;
;#dll_bw_hz: DLL loop filter bandwidth [Hz]
Tracking.dll_bw_hz=2.0;

View File

@ -28,10 +28,7 @@ if(OPENCL_FOUND)
galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc
galileo_e1_pcps_tong_ambiguous_acquisition.cc
galileo_e1_pcps_8ms_ambiguous_acquisition.cc
galileo_e5a_pcps_acquisition.cc
galileo_e5a_pilot_3ms_acquisition.cc
galileo_e5ax_2ms_pcps_acquisition.cc
galileo_e5a_3ms_noncoherent_iq_acquisition.cc
galileo_e5a_noncoherent_iq_acquisition_caf.cc
)
else(OPENCL_FOUND)
set(ACQ_ADAPTER_SOURCES
@ -44,10 +41,7 @@ else(OPENCL_FOUND)
galileo_e1_pcps_cccwsr_ambiguous_acquisition.cc
galileo_e1_pcps_tong_ambiguous_acquisition.cc
galileo_e1_pcps_8ms_ambiguous_acquisition.cc
galileo_e5a_pcps_acquisition.cc
galileo_e5a_pilot_3ms_acquisition.cc
galileo_e5ax_2ms_pcps_acquisition.cc
galileo_e5a_3ms_noncoherent_iq_acquisition.cc
galileo_e5a_noncoherent_iq_acquisition_caf.cc
)
endif(OPENCL_FOUND)

View File

@ -1,8 +1,14 @@
/*!
* \file galileo_e5a_3ms_noncoherent_iq_acquisition.cc
* \file galileo_e5a_noncoherent_iq_acquisition_caf.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
* \based on work from:
* <ul>
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
* </ul>
*
* -------------------------------------------------------------------------
*
@ -29,7 +35,7 @@
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_3ms_noncoherent_iq_acquisition.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
@ -39,11 +45,10 @@
#include "galileo_e5_signal_processing.h"
#include "Galileo_E5a.h"
#include "configuration_interface.h"
//#include <tgmath.h>
using google::LogMessage;
GalileoE5a3msNoncoherentIQAcquisition::GalileoE5a3msNoncoherentIQAcquisition(
GalileoE5aNoncoherentIQAcquisitionCaf::GalileoE5aNoncoherentIQAcquisitionCaf(
ConfigurationInterface* configuration, std::string role,
unsigned int in_streams, unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
@ -58,24 +63,26 @@ GalileoE5a3msNoncoherentIQAcquisition::GalileoE5a3msNoncoherentIQAcquisition(
item_type_ = configuration_->property(role + ".item_type",
default_item_type);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 21000000);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 32000000);
if_ = configuration_->property(role + ".ifreq", 0);
dump_ = configuration_->property(role + ".dump", false);
shift_resolution_ = configuration_->property(role + ".doppler_max", 15);
sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 3);
if (sampled_ms_ < 2)
{
sampled_ms_=2;
DLOG(INFO) << "Coherent integration time should be 2 or 3 ms. Changing to 2ms ";
std::cout<<"Too low coherent integration time. Changing to 2ms" << std::endl;
}
else if (sampled_ms_ > 3)
CAF_window_hz_ = configuration_->property(role + ".CAF_window_hz",0);
Zero_padding = configuration_->property(role + ".Zero_padding",0);
sampled_ms_ = configuration_->property(role + ".coherent_integration_time_ms", 1);
if (sampled_ms_ > 3)
{
sampled_ms_=3;
DLOG(INFO) << "Coherent integration time should be 2 or 3 ms. Changing to 3ms ";
std::cout<<"Too low coherent integration time. Changing to 3ms" << std::endl;
DLOG(INFO) << "Coherent integration time should be 3 ms or less. Changing to 3ms ";
std::cout<<"Too high coherent integration time. Changing to 3ms" << std::endl;
}
//bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
if (Zero_padding > 0)
{
sampled_ms_ = 2;
DLOG(INFO) << "Zero padding activated. Changing to 1ms code + 1ms zero padding ";
std::cout<<"Zero padding activated. Changing to 1ms code + 1ms zero padding" << std::endl;
}
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
dump_filename_ = configuration_->property(role + ".dump_filename",
@ -84,31 +91,23 @@ GalileoE5a3msNoncoherentIQAcquisition::GalileoE5a3msNoncoherentIQAcquisition(
//--- Find number of samples per spreading code (1ms)-------------------------
code_length_ = round(fs_in_/ Galileo_E5a_CODE_CHIP_RATE_HZ*Galileo_E5a_CODE_LENGTH_CHIPS);
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
vector_length_=code_length_ * sampled_ms_;
// vector_length_=15*code_length_;
//std::cout << sampled_ms_ << " sampledms" << code_length_ << " cdelength" << std::endl;
//if (posix_memalign((void**)&(code_), 16,vector_length_ * sizeof(gr_complex)) == 0){};
codeI_= new gr_complex[vector_length_];
codeQ_= new gr_complex[vector_length_];
both_signal_components = false;
std::string sig_ = configuration_->property("Channel.signal", std::string("5X"));
if (sig_.at(0) == '5' && sig_.at(1) == 'X')
{
both_signal_components = true;
}
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = galileo_e5a_3ms_noncoherentIQ_make_acquisition_cc(sampled_ms_, max_dwells_,
acquisition_cc_ = galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(sampled_ms_, max_dwells_,
shift_resolution_, if_, fs_in_, code_length_, code_length_,
bit_transition_flag_, queue_, dump_, dump_filename_);
// stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_);
//
// DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id()
// << ")";
// DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id()
// << ")";
bit_transition_flag_, queue_, dump_, dump_filename_, both_signal_components, CAF_window_hz_);
}
else
{
@ -118,13 +117,13 @@ GalileoE5a3msNoncoherentIQAcquisition::GalileoE5a3msNoncoherentIQAcquisition(
}
GalileoE5a3msNoncoherentIQAcquisition::~GalileoE5a3msNoncoherentIQAcquisition()
GalileoE5aNoncoherentIQAcquisitionCaf::~GalileoE5aNoncoherentIQAcquisitionCaf()
{
delete[] codeI_;
delete[] codeQ_;
}
void GalileoE5a3msNoncoherentIQAcquisition::set_channel(unsigned int channel)
void GalileoE5aNoncoherentIQAcquisitionCaf::set_channel(unsigned int channel)
{
channel_ = channel;
if (item_type_.compare("gr_complex") == 0)
@ -133,7 +132,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_channel(unsigned int channel)
}
}
void GalileoE5a3msNoncoherentIQAcquisition::set_threshold(float threshold)
void GalileoE5aNoncoherentIQAcquisitionCaf::set_threshold(float threshold)
{
float pfa = configuration_->property(role_+ boost::lexical_cast<std::string>(channel_) + ".pfa", 0.0);
@ -158,7 +157,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_threshold(float threshold)
}
void GalileoE5a3msNoncoherentIQAcquisition::set_doppler_max(unsigned int doppler_max)
void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_max(unsigned int doppler_max)
{
doppler_max_ = doppler_max;
@ -168,7 +167,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_doppler_max(unsigned int doppler
}
}
void GalileoE5a3msNoncoherentIQAcquisition::set_doppler_step(unsigned int doppler_step)
void GalileoE5aNoncoherentIQAcquisitionCaf::set_doppler_step(unsigned int doppler_step)
{
doppler_step_ = doppler_step;
if (item_type_.compare("gr_complex") == 0)
@ -177,7 +176,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_doppler_step(unsigned int dopple
}
}
void GalileoE5a3msNoncoherentIQAcquisition::set_channel_queue(
void GalileoE5aNoncoherentIQAcquisitionCaf::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
@ -188,7 +187,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_channel_queue(
}
void GalileoE5a3msNoncoherentIQAcquisition::set_gnss_synchro(
void GalileoE5aNoncoherentIQAcquisitionCaf::set_gnss_synchro(
Gnss_Synchro* gnss_synchro)
{
gnss_synchro_ = gnss_synchro;
@ -199,7 +198,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_gnss_synchro(
}
signed int GalileoE5a3msNoncoherentIQAcquisition::mag()
signed int GalileoE5aNoncoherentIQAcquisitionCaf::mag()
{
if (item_type_.compare("gr_complex") == 0)
{
@ -212,13 +211,13 @@ signed int GalileoE5a3msNoncoherentIQAcquisition::mag()
}
void GalileoE5a3msNoncoherentIQAcquisition::init()
void GalileoE5aNoncoherentIQAcquisitionCaf::init()
{
acquisition_cc_->init();
set_local_code();
}
void GalileoE5a3msNoncoherentIQAcquisition::set_local_code()
void GalileoE5aNoncoherentIQAcquisitionCaf::set_local_code()
{
if (item_type_.compare("gr_complex")==0)
{
@ -226,28 +225,48 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_local_code()
std::complex<float>* codeI = new std::complex<float>[code_length_];
std::complex<float>* codeQ = new std::complex<float>[code_length_];
std::cout << "ADAPTER E5a 3ms noncoherentIQ. SIGNAL = " << gnss_synchro_->Signal << " PRN = " << gnss_synchro_->PRN << std::endl;
char a[3];
strcpy(a,"5I");
galileo_e5_a_code_gen_complex_sampled(codeI, a,
gnss_synchro_->PRN, fs_in_, 0, false);
strcpy(a,"5Q");
galileo_e5_a_code_gen_complex_sampled(codeQ, a,
gnss_synchro_->PRN, fs_in_, 0, false);
if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X')
{
char a[3];
strcpy(a,"5I");
galileo_e5_a_code_gen_complex_sampled(codeI, a,
gnss_synchro_->PRN, fs_in_, 0);
strcpy(a,"5Q");
galileo_e5_a_code_gen_complex_sampled(codeQ, a,
gnss_synchro_->PRN, fs_in_, 0);
}
else
{
galileo_e5_a_code_gen_complex_sampled(codeI, gnss_synchro_->Signal,
gnss_synchro_->PRN, fs_in_, 0);
}
// WARNING: 3ms are coherently integrated. Secondary sequence (1,1,1)
// is generated, and modulated in the 'block'.
for (unsigned int i = 0; i < sampled_ms_; i++)
if (Zero_padding == 0) // if no zero_padding
{
memcpy(&(codeI_[i*code_length_]), codeI,
sizeof(gr_complex)*code_length_);
memcpy(&(codeQ_[i*code_length_]), codeQ,
sizeof(gr_complex)*code_length_);
for (unsigned int i = 0; i < sampled_ms_; i++)
{
memcpy(&(codeI_[i*code_length_]), codeI,
sizeof(gr_complex)*code_length_);
if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X')
{
memcpy(&(codeQ_[i*code_length_]), codeQ,
sizeof(gr_complex)*code_length_);
}
}
}
else
{
// 1ms code + 1ms zero padding
memcpy(&(codeI_[0]), codeI,
sizeof(gr_complex)*code_length_);
if (gnss_synchro_->Signal[0] == '5' && gnss_synchro_->Signal[1] == 'X')
{
memcpy(&(codeQ_[0]), codeQ,
sizeof(gr_complex)*code_length_);
}
}
acquisition_cc_->set_local_code(codeI_,codeQ_);
delete[] codeI;
@ -257,7 +276,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::set_local_code()
}
void GalileoE5a3msNoncoherentIQAcquisition::reset()
void GalileoE5aNoncoherentIQAcquisitionCaf::reset()
{
if (item_type_.compare("gr_complex") == 0)
{
@ -266,7 +285,7 @@ void GalileoE5a3msNoncoherentIQAcquisition::reset()
}
float GalileoE5a3msNoncoherentIQAcquisition::calculate_threshold(float pfa)
float GalileoE5aNoncoherentIQAcquisitionCaf::calculate_threshold(float pfa)
{
//Calculate the threshold
unsigned int frequency_bins = 0;
@ -286,31 +305,24 @@ float GalileoE5a3msNoncoherentIQAcquisition::calculate_threshold(float pfa)
}
void GalileoE5a3msNoncoherentIQAcquisition::connect(gr::top_block_sptr top_block)
void GalileoE5aNoncoherentIQAcquisitionCaf::connect(gr::top_block_sptr top_block)
{
// if (item_type_.compare("gr_complex") == 0)
// {
// top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0);
// }
// Nothing to connect internally
}
void GalileoE5a3msNoncoherentIQAcquisition::disconnect(gr::top_block_sptr top_block)
void GalileoE5aNoncoherentIQAcquisitionCaf::disconnect(gr::top_block_sptr top_block)
{
// if (item_type_.compare("gr_complex") == 0)
// {
// top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0);
// }
// Nothing to disconnect internally
}
gr::basic_block_sptr GalileoE5a3msNoncoherentIQAcquisition::get_left_block()
{
return acquisition_cc_;
//return stream_to_vector_;
}
gr::basic_block_sptr GalileoE5a3msNoncoherentIQAcquisition::get_right_block()
gr::basic_block_sptr GalileoE5aNoncoherentIQAcquisitionCaf::get_left_block()
{
return acquisition_cc_;
}
gr::basic_block_sptr GalileoE5aNoncoherentIQAcquisitionCaf::get_right_block()
{
return acquisition_cc_;
}

View File

@ -1,8 +1,14 @@
/*!
* \file galileo_e5a_3ms_noncoherent_iq_acquisition.h
* \file galileo_e5a_noncoherent_iq_acquisition_caf.h
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
* \author Marc Sales, 2014. marcsales92(at)gmail.com
* \based on work from:
* <ul>
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
* </ul>
*
* -------------------------------------------------------------------------
*
@ -29,37 +35,37 @@
* -------------------------------------------------------------------------
*/
#ifndef GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_H_
#define GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_H_
#ifndef GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_
#define GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_
#include <string>
#include <gnuradio/msg_queue.h>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "galileo_e5a_3ms_noncoherent_iq_acquisition_cc.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf_cc.h"
class ConfigurationInterface;
class GalileoE5a3msNoncoherentIQAcquisition: public AcquisitionInterface
class GalileoE5aNoncoherentIQAcquisitionCaf: public AcquisitionInterface
{
public:
GalileoE5a3msNoncoherentIQAcquisition(ConfigurationInterface* configuration,
GalileoE5aNoncoherentIQAcquisitionCaf(ConfigurationInterface* configuration,
std::string role, unsigned int in_streams,
unsigned int out_streams, boost::shared_ptr<gr::msg_queue> queue);
virtual ~GalileoE5a3msNoncoherentIQAcquisition();
virtual ~GalileoE5aNoncoherentIQAcquisitionCaf();
std::string role()
{
return role_;
}
/*!
* \brief Returns "Galileo_E5a_3ms_Noncoherent_IQ_Acquisition"
* \brief Returns "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF"
*/
std::string implementation()
{
return "Galileo_E5a_3ms_Noncoherent_IQ_Acquisition";
return "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF";
}
size_t item_size()
{
@ -71,7 +77,6 @@ public:
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to efficiently exchange synchronization data between acquisition and
@ -126,7 +131,7 @@ public:
private:
ConfigurationInterface* configuration_;
galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr acquisition_cc_;
galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr acquisition_cc_;
gr::blocks::stream_to_vector::sptr stream_to_vector_;
size_t item_size_;
std::string item_type_;
@ -144,8 +149,11 @@ private:
long if_;
bool dump_;
std::string dump_filename_;
int Zero_padding;
int CAF_window_hz_;
std::complex<float> * codeI_;
std::complex<float> * codeQ_;
bool both_signal_components;
Gnss_Synchro * gnss_synchro_;
std::string role_;
unsigned int in_streams_;
@ -154,4 +162,4 @@ private:
concurrent_queue<int> *channel_internal_queue_;
float calculate_threshold(float pfa);
};
#endif /* GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_H_ */
#endif /* GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_H_ */

View File

@ -1,300 +0,0 @@
/*!
* \file galileo_e5a_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_pcps_acquisition.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <boost/math/distributions/exponential.hpp>
#include <glog/logging.h>
#include <gnuradio/msg_queue.h>
#include "galileo_e5_signal_processing.h"
#include "Galileo_E5a.h"
#include "configuration_interface.h"
//#include <tgmath.h>
using google::LogMessage;
GalileoE5aPcpsAcquisition::GalileoE5aPcpsAcquisition(
ConfigurationInterface* configuration, std::string role,
unsigned int in_streams, unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue)
{
configuration_ = configuration;
std::string default_item_type = "gr_complex";
std::string default_dump_filename = "../data/acquisition.dat";
DLOG(INFO) << "role " << role;
item_type_ = configuration_->property(role + ".item_type",
default_item_type);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 12000000);
if_ = configuration_->property(role + ".ifreq", 0);
dump_ = configuration_->property(role + ".dump", false);
shift_resolution_ = configuration_->property(role + ".doppler_max", 15);
sampled_ms_ = 1; // try luck without zero padding to achieve better gain when bit transition coincides.
bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
if (!bit_transition_flag_)
{
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
}
else
{
max_dwells_ = 2;
}
dump_filename_ = configuration_->property(role + ".dump_filename",
default_dump_filename);
//--- Find number of samples per spreading code (1ms)-------------------------
code_length_ = round(fs_in_/ Galileo_E5a_CODE_CHIP_RATE_HZ*Galileo_E5a_CODE_LENGTH_CHIPS);
// Several dwells will be needed without zero-padding. Only 1ms in this implementation.
vector_length_=code_length_;// * sampled_ms_;
//std::cout << sampled_ms_ << " sampledms" << code_length_ << " cdelength" << std::endl;
//if (posix_memalign((void**)&(code_), 16,vector_length_ * sizeof(gr_complex)) == 0){};
code_= new gr_complex[vector_length_];
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = pcps_make_acquisition_cc(sampled_ms_, max_dwells_,
shift_resolution_, if_, fs_in_, code_length_, code_length_,
bit_transition_flag_, queue_, dump_, dump_filename_);
stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_);
DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id()
<< ")";
DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id()
<< ")";
}
else
{
LOG(WARNING) << item_type_
<< " unknown acquisition item type";
}
}
GalileoE5aPcpsAcquisition::~GalileoE5aPcpsAcquisition()
{
delete[] code_;
}
void GalileoE5aPcpsAcquisition::set_channel(unsigned int channel)
{
channel_ = channel;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel(channel_);
}
}
void GalileoE5aPcpsAcquisition::set_threshold(float threshold)
{
float pfa = configuration_->property(role_+ boost::lexical_cast<std::string>(channel_) + ".pfa", 0.0);
if(pfa==0.0) pfa = configuration_->property(role_+".pfa", 0.0);
if(pfa==0.0)
{
threshold_ = threshold;
}
else
{
threshold_ = calculate_threshold(pfa);
}
DLOG(INFO) <<"Channel "<<channel_<<" Threshold = " << threshold_;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_threshold(threshold_);
}
}
void GalileoE5aPcpsAcquisition::set_doppler_max(unsigned int doppler_max)
{
doppler_max_ = doppler_max;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_max(doppler_max_);
}
}
void GalileoE5aPcpsAcquisition::set_doppler_step(unsigned int doppler_step)
{
doppler_step_ = doppler_step;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_step(doppler_step_);
}
}
void GalileoE5aPcpsAcquisition::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel_queue(channel_internal_queue_);
}
}
void GalileoE5aPcpsAcquisition::set_gnss_synchro(
Gnss_Synchro* gnss_synchro)
{
gnss_synchro_ = gnss_synchro;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_gnss_synchro(gnss_synchro_);
}
}
signed int GalileoE5aPcpsAcquisition::mag()
{
if (item_type_.compare("gr_complex") == 0)
{
return acquisition_cc_->mag();
}
else
{
return 0;
}
}
void GalileoE5aPcpsAcquisition::init()
{
acquisition_cc_->init();
set_local_code();
}
void GalileoE5aPcpsAcquisition::set_local_code()
{
if (item_type_.compare("gr_complex")==0)
{
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
//std::complex<float>* code = new std::complex<float>[2*code_length_];
std::cout << "ADAPTER E5a. SIGNAL = " << gnss_synchro_->Signal << " PRN = " << gnss_synchro_->PRN << std::endl;
galileo_e5_a_code_gen_complex_sampled(code_, gnss_synchro_->Signal,
gnss_synchro_->PRN, fs_in_, 0, false);
// WARNING: In presence of secondary codes, 2ms of input signal are required
// which are correlated with 1ms of primary code and 1ms of zero padding
// for (unsigned int i = 0; i < sampled_ms_; i++)
// {
// memcpy(&(code_[i*code_length_]), code,
// sizeof(gr_complex)*code_length_);
//
// }
acquisition_cc_->set_local_code(code_);
//delete[] code;
}
}
void GalileoE5aPcpsAcquisition::reset()
{
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_active(true);
}
}
float GalileoE5aPcpsAcquisition::calculate_threshold(float pfa)
{
//Calculate the threshold
unsigned int frequency_bins = 0;
for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_)
{
frequency_bins++;
}
DLOG(INFO) << "Channel " << channel_<< " Pfa = " << pfa;
unsigned int ncells = vector_length_*frequency_bins;
double exponent = 1/(double)ncells;
double val = pow(1.0 - pfa, exponent);
double lambda = double(vector_length_);
boost::math::exponential_distribution<double> mydist (lambda);
float threshold = (float)quantile(mydist,val);
return threshold;
}
void GalileoE5aPcpsAcquisition::connect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
void GalileoE5aPcpsAcquisition::disconnect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
gr::basic_block_sptr GalileoE5aPcpsAcquisition::get_left_block()
{
return stream_to_vector_;
}
gr::basic_block_sptr GalileoE5aPcpsAcquisition::get_right_block()
{
return acquisition_cc_;
}

View File

@ -1,157 +0,0 @@
/*!
* \file galileo_e5a_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_H_
#define GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_H_
#include <string>
#include <gnuradio/msg_queue.h>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_acquisition_cc.h"
class ConfigurationInterface;
class GalileoE5aPcpsAcquisition: public AcquisitionInterface
{
public:
GalileoE5aPcpsAcquisition(ConfigurationInterface* configuration,
std::string role, unsigned int in_streams,
unsigned int out_streams, boost::shared_ptr<gr::msg_queue> queue);
virtual ~GalileoE5aPcpsAcquisition();
std::string role()
{
return role_;
}
/*!
* \brief Returns "Galileo_E5a_PCPS_Acquisition"
*/
std::string implementation()
{
return "Galileo_E5a_PCPS_Acquisition";
}
size_t item_size()
{
return item_size_;
}
void connect(gr::top_block_sptr top_block);
void disconnect(gr::top_block_sptr top_block);
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to efficiently exchange synchronization data between acquisition and
* tracking blocks
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro);
/*!
* \brief Set acquisition channel unique ID
*/
void set_channel(unsigned int channel);
/*!
* \brief Set statistics threshold of PCPS algorithm
*/
void set_threshold(float threshold);
/*!
* \brief Set maximum Doppler off grid search
*/
void set_doppler_max(unsigned int doppler_max);
/*!
* \brief Set Doppler steps for the grid search
*/
void set_doppler_step(unsigned int doppler_step);
/*!
* \brief Set tracking channel internal queue
*/
void set_channel_queue(concurrent_queue<int> *channel_internal_queue);
/*!
* \brief Initializes acquisition algorithm.
*/
void init();
/*!
* \brief Sets local Galileo E5a (data or pilot) code for PCPS acquisition algorithm.
*/
void set_local_code();
/*!
* \brief Returns the maximum peak of grid search
*/
signed int mag();
/*!
* \brief Restart acquisition algorithm
*/
void reset();
private:
ConfigurationInterface* configuration_;
pcps_acquisition_cc_sptr acquisition_cc_;
gr::blocks::stream_to_vector::sptr stream_to_vector_;
size_t item_size_;
std::string item_type_;
unsigned int vector_length_;
unsigned int code_length_;
bool bit_transition_flag_;
unsigned int channel_;
float threshold_;
unsigned int doppler_max_;
unsigned int doppler_step_;
unsigned int shift_resolution_;
unsigned int sampled_ms_;
unsigned int max_dwells_;
long fs_in_;
long if_;
bool dump_;
std::string dump_filename_;
std::complex<float> * code_;
Gnss_Synchro * gnss_synchro_;
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
boost::shared_ptr<gr::msg_queue> queue_;
concurrent_queue<int> *channel_internal_queue_;
float calculate_threshold(float pfa);
};
#endif /* GNSS_SDR_GALILEO_E5A_PCPS_ACQUISITION_H_ */

View File

@ -1,296 +0,0 @@
/*!
* \file galileo_e5a_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_pilot_3ms_acquisition.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <boost/math/distributions/exponential.hpp>
#include <glog/logging.h>
#include <gnuradio/msg_queue.h>
#include "galileo_e5_signal_processing.h"
#include "Galileo_E5a.h"
#include "configuration_interface.h"
//#include <tgmath.h>
using google::LogMessage;
GalileoE5aPilot_3msAcquisition::GalileoE5aPilot_3msAcquisition(
ConfigurationInterface* configuration, std::string role,
unsigned int in_streams, unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue)
{
configuration_ = configuration;
std::string default_item_type = "gr_complex";
std::string default_dump_filename = "../data/acquisition.dat";
DLOG(INFO) << "role " << role;
item_type_ = configuration_->property(role + ".item_type",
default_item_type);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 12000000);
if_ = configuration_->property(role + ".ifreq", 0);
dump_ = configuration_->property(role + ".dump", false);
shift_resolution_ = configuration_->property(role + ".doppler_max", 15);
sampled_ms_ = 3; // needed 3 ms of input in presence of secondary code.
// sampled_ms_ = 15;
//bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
dump_filename_ = configuration_->property(role + ".dump_filename",
default_dump_filename);
//--- Find number of samples per spreading code (1ms)-------------------------
code_length_ = round(fs_in_/ Galileo_E5a_CODE_CHIP_RATE_HZ*Galileo_E5a_CODE_LENGTH_CHIPS);
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
vector_length_=3*code_length_;// * sampled_ms_;
// vector_length_=15*code_length_;
//std::cout << sampled_ms_ << " sampledms" << code_length_ << " cdelength" << std::endl;
//if (posix_memalign((void**)&(code_), 16,vector_length_ * sizeof(gr_complex)) == 0){};
code_= new gr_complex[vector_length_];
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = galileo_e5a_pilot_3ms_make_acquisition_cc(max_dwells_,
shift_resolution_, if_, fs_in_, code_length_, code_length_,
bit_transition_flag_, queue_, dump_, dump_filename_);
stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_);
DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id()
<< ")";
DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id()
<< ")";
}
else
{
LOG(WARNING) << item_type_
<< " unknown acquisition item type";
}
}
GalileoE5aPilot_3msAcquisition::~GalileoE5aPilot_3msAcquisition()
{
delete[] code_;
}
void GalileoE5aPilot_3msAcquisition::set_channel(unsigned int channel)
{
channel_ = channel;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel(channel_);
}
}
void GalileoE5aPilot_3msAcquisition::set_threshold(float threshold)
{
float pfa = configuration_->property(role_+ boost::lexical_cast<std::string>(channel_) + ".pfa", 0.0);
if(pfa==0.0) pfa = configuration_->property(role_+".pfa", 0.0);
if(pfa==0.0)
{
threshold_ = threshold;
}
else
{
threshold_ = calculate_threshold(pfa);
}
DLOG(INFO) <<"Channel "<<channel_<<" Threshold = " << threshold_;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_threshold(threshold_);
}
}
void GalileoE5aPilot_3msAcquisition::set_doppler_max(unsigned int doppler_max)
{
doppler_max_ = doppler_max;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_max(doppler_max_);
}
}
void GalileoE5aPilot_3msAcquisition::set_doppler_step(unsigned int doppler_step)
{
doppler_step_ = doppler_step;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_step(doppler_step_);
}
}
void GalileoE5aPilot_3msAcquisition::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel_queue(channel_internal_queue_);
}
}
void GalileoE5aPilot_3msAcquisition::set_gnss_synchro(
Gnss_Synchro* gnss_synchro)
{
gnss_synchro_ = gnss_synchro;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_gnss_synchro(gnss_synchro_);
}
}
signed int GalileoE5aPilot_3msAcquisition::mag()
{
if (item_type_.compare("gr_complex") == 0)
{
return acquisition_cc_->mag();
}
else
{
return 0;
}
}
void GalileoE5aPilot_3msAcquisition::init()
{
acquisition_cc_->init();
set_local_code();
}
void GalileoE5aPilot_3msAcquisition::set_local_code()
{
if (item_type_.compare("gr_complex")==0)
{
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
std::complex<float>* code = new std::complex<float>[code_length_];
std::cout << "ADAPTER E5a 3ms. SIGNAL = " << gnss_synchro_->Signal << " PRN = " << gnss_synchro_->PRN << std::endl;
char a[3];
strcpy(a,"5X");
galileo_e5_a_code_gen_complex_sampled(code, a,
gnss_synchro_->PRN, fs_in_, 0, false);
// WARNING: 3ms are coherently integrated. Secondary sequence (1,1,1)
// is generated, and modulated in the 'block'.
for (unsigned int i = 0; i < 3; i++)
{
memcpy(&(code_[i*code_length_]), code,
sizeof(gr_complex)*code_length_);
}
acquisition_cc_->set_local_code(code_);
delete[] code;
}
}
void GalileoE5aPilot_3msAcquisition::reset()
{
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_active(true);
}
}
float GalileoE5aPilot_3msAcquisition::calculate_threshold(float pfa)
{
//Calculate the threshold
unsigned int frequency_bins = 0;
for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_)
{
frequency_bins++;
}
DLOG(INFO) << "Channel " << channel_<< " Pfa = " << pfa;
unsigned int ncells = vector_length_*frequency_bins;
double exponent = 1/(double)ncells;
double val = pow(1.0 - pfa, exponent);
double lambda = double(vector_length_);
boost::math::exponential_distribution<double> mydist (lambda);
float threshold = (float)quantile(mydist,val);
return threshold;
}
void GalileoE5aPilot_3msAcquisition::connect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
void GalileoE5aPilot_3msAcquisition::disconnect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
gr::basic_block_sptr GalileoE5aPilot_3msAcquisition::get_left_block()
{
return stream_to_vector_;
}
gr::basic_block_sptr GalileoE5aPilot_3msAcquisition::get_right_block()
{
return acquisition_cc_;
}

View File

@ -1,157 +0,0 @@
/*!
* \file galileo_e5a_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GALILEO_E5A_PILOT_3MS_ACQUISITION_H_
#define GALILEO_E5A_PILOT_3MS_ACQUISITION_H_
#include <string>
#include <gnuradio/msg_queue.h>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "galileo_e5a_pilot_3ms_acquisition_cc.h"
class ConfigurationInterface;
class GalileoE5aPilot_3msAcquisition: public AcquisitionInterface
{
public:
GalileoE5aPilot_3msAcquisition(ConfigurationInterface* configuration,
std::string role, unsigned int in_streams,
unsigned int out_streams, boost::shared_ptr<gr::msg_queue> queue);
virtual ~GalileoE5aPilot_3msAcquisition();
std::string role()
{
return role_;
}
/*!
* \brief Returns "Galileo_E5a_Pilot_3ms_Acquisition"
*/
std::string implementation()
{
return "Galileo_E5a_Pilot_3ms_Acquisition";
}
size_t item_size()
{
return item_size_;
}
void connect(gr::top_block_sptr top_block);
void disconnect(gr::top_block_sptr top_block);
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to efficiently exchange synchronization data between acquisition and
* tracking blocks
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro);
/*!
* \brief Set acquisition channel unique ID
*/
void set_channel(unsigned int channel);
/*!
* \brief Set statistics threshold of PCPS algorithm
*/
void set_threshold(float threshold);
/*!
* \brief Set maximum Doppler off grid search
*/
void set_doppler_max(unsigned int doppler_max);
/*!
* \brief Set Doppler steps for the grid search
*/
void set_doppler_step(unsigned int doppler_step);
/*!
* \brief Set tracking channel internal queue
*/
void set_channel_queue(concurrent_queue<int> *channel_internal_queue);
/*!
* \brief Initializes acquisition algorithm.
*/
void init();
/*!
* \brief Sets local Galileo E5a (pilot) code for PCPS acquisition algorithm.
*/
void set_local_code();
/*!
* \brief Returns the maximum peak of grid search
*/
signed int mag();
/*!
* \brief Restart acquisition algorithm
*/
void reset();
private:
ConfigurationInterface* configuration_;
galileo_e5a_pilot_3ms_acquisition_cc_sptr acquisition_cc_;
gr::blocks::stream_to_vector::sptr stream_to_vector_;
size_t item_size_;
std::string item_type_;
unsigned int vector_length_;
unsigned int code_length_;
bool bit_transition_flag_;
unsigned int channel_;
float threshold_;
unsigned int doppler_max_;
unsigned int doppler_step_;
unsigned int shift_resolution_;
unsigned int sampled_ms_;
unsigned int max_dwells_;
long fs_in_;
long if_;
bool dump_;
std::string dump_filename_;
std::complex<float> * code_;
Gnss_Synchro * gnss_synchro_;
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
boost::shared_ptr<gr::msg_queue> queue_;
concurrent_queue<int> *channel_internal_queue_;
float calculate_threshold(float pfa);
};
#endif /* GALILEO_E5A_PILOT_3MS_ACQUISITION_H_ */

View File

@ -1,297 +0,0 @@
/*\file galileo_e5a_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5ax_2ms_pcps_acquisition.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <stdexcept>
#include <boost/math/distributions/exponential.hpp>
#include <glog/logging.h>
#include <gnuradio/msg_queue.h>
#include "galileo_e5_signal_processing.h"
#include "Galileo_E5a.h"
#include "configuration_interface.h"
//#include <tgmath.h>
using google::LogMessage;
GalileoE5ax2msPcpsAcquisition::GalileoE5ax2msPcpsAcquisition(
ConfigurationInterface* configuration, std::string role,
unsigned int in_streams, unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
role_(role), in_streams_(in_streams), out_streams_(out_streams), queue_(queue)
{
configuration_ = configuration;
std::string default_item_type = "gr_complex";
std::string default_dump_filename = "../data/acquisition.dat";
DLOG(INFO) << "role " << role;
item_type_ = configuration_->property(role + ".item_type",
default_item_type);
fs_in_ = configuration_->property("GNSS-SDR.internal_fs_hz", 12000000);
if_ = configuration_->property(role + ".ifreq", 0);
dump_ = configuration_->property(role + ".dump", false);
shift_resolution_ = configuration_->property(role + ".doppler_max", 15);
sampled_ms_ = 2; // needed 2 ms of input in presence of secondary code.
//there is always bit transition in e5
//bit_transition_flag_ = configuration_->property(role + ".bit_transition_flag", false);
max_dwells_ = configuration_->property(role + ".max_dwells", 1);
dump_filename_ = configuration_->property(role + ".dump_filename",
default_dump_filename);
//--- Find number of samples per spreading code (1ms)-------------------------
code_length_ = round(fs_in_/ Galileo_E5a_CODE_CHIP_RATE_HZ*Galileo_E5a_CODE_LENGTH_CHIPS);
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
vector_length_=2*code_length_;// * sampled_ms_;
//std::cout << sampled_ms_ << " sampledms" << code_length_ << " cdelength" << std::endl;
//if (posix_memalign((void**)&(code_), 16,vector_length_ * sizeof(gr_complex)) == 0){};
code_= new gr_complex[vector_length_];
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = galileo_e5ax_2ms_pcps_make_acquisition_cc(max_dwells_,
shift_resolution_, if_, fs_in_, code_length_, code_length_,
bit_transition_flag_, queue_, dump_, dump_filename_);
stream_to_vector_ = gr::blocks::stream_to_vector::make(item_size_, vector_length_);
DLOG(INFO) << "stream_to_vector(" << stream_to_vector_->unique_id()
<< ")";
DLOG(INFO) << "acquisition(" << acquisition_cc_->unique_id()
<< ")";
}
else
{
LOG(WARNING) << item_type_
<< " unknown acquisition item type";
}
}
GalileoE5ax2msPcpsAcquisition::~GalileoE5ax2msPcpsAcquisition()
{
delete[] code_;
}
void GalileoE5ax2msPcpsAcquisition::set_channel(unsigned int channel)
{
channel_ = channel;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel(channel_);
}
}
void GalileoE5ax2msPcpsAcquisition::set_threshold(float threshold)
{
float pfa = configuration_->property(role_+ boost::lexical_cast<std::string>(channel_) + ".pfa", 0.0);
if(pfa==0.0) pfa = configuration_->property(role_+".pfa", 0.0);
if(pfa==0.0)
{
threshold_ = threshold;
}
else
{
threshold_ = calculate_threshold(pfa);
}
DLOG(INFO) <<"Channel "<<channel_<<" Threshold = " << threshold_;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_threshold(threshold_);
}
}
void GalileoE5ax2msPcpsAcquisition::set_doppler_max(unsigned int doppler_max)
{
doppler_max_ = doppler_max;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_max(doppler_max_);
}
}
void GalileoE5ax2msPcpsAcquisition::set_doppler_step(unsigned int doppler_step)
{
doppler_step_ = doppler_step;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_doppler_step(doppler_step_);
}
}
void GalileoE5ax2msPcpsAcquisition::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_channel_queue(channel_internal_queue_);
}
}
void GalileoE5ax2msPcpsAcquisition::set_gnss_synchro(
Gnss_Synchro* gnss_synchro)
{
gnss_synchro_ = gnss_synchro;
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_gnss_synchro(gnss_synchro_);
}
}
signed int GalileoE5ax2msPcpsAcquisition::mag()
{
if (item_type_.compare("gr_complex") == 0)
{
return acquisition_cc_->mag();
}
else
{
return 0;
}
}
void GalileoE5ax2msPcpsAcquisition::init()
{
acquisition_cc_->init();
set_local_code();
}
void GalileoE5ax2msPcpsAcquisition::set_local_code()
{
if (item_type_.compare("gr_complex")==0)
{
// WARNING: In presence of secondary codes, 2ms must be correlated with 1ms
// of primary code and 1ms of padded zeros.
//std::complex<float>* code = new std::complex<float>[2*code_length_];
std::cout << "ADAPTER E5a. SIGNAL = " << gnss_synchro_->Signal << " PRN = " << gnss_synchro_->PRN << std::endl;
char a[3];
strcpy(a,"5X");
galileo_e5_a_code_gen_complex_sampled(code_, a,
gnss_synchro_->PRN, fs_in_, 0, false);
// WARNING: In presence of secondary codes, 2ms of input signal are required
// which are correlated with 1ms of primary code and 1ms of zero padding
// for (unsigned int i = 0; i < sampled_ms_; i++)
// {
// memcpy(&(code_[i*code_length_]), code,
// sizeof(gr_complex)*code_length_);
//
// }
acquisition_cc_->set_local_code(code_);
//delete[] code;
}
}
void GalileoE5ax2msPcpsAcquisition::reset()
{
if (item_type_.compare("gr_complex") == 0)
{
acquisition_cc_->set_active(true);
}
}
float GalileoE5ax2msPcpsAcquisition::calculate_threshold(float pfa)
{
//Calculate the threshold
unsigned int frequency_bins = 0;
for (int doppler = (int)(-doppler_max_); doppler <= (int)doppler_max_; doppler += doppler_step_)
{
frequency_bins++;
}
DLOG(INFO) << "Channel " << channel_<< " Pfa = " << pfa;
unsigned int ncells = vector_length_*frequency_bins;
double exponent = 1/(double)ncells;
double val = pow(1.0 - pfa, exponent);
double lambda = double(vector_length_);
boost::math::exponential_distribution<double> mydist (lambda);
float threshold = (float)quantile(mydist,val);
return threshold;
}
void GalileoE5ax2msPcpsAcquisition::connect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->connect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
void GalileoE5ax2msPcpsAcquisition::disconnect(gr::top_block_sptr top_block)
{
if (item_type_.compare("gr_complex") == 0)
{
top_block->disconnect(stream_to_vector_, 0, acquisition_cc_, 0);
}
}
gr::basic_block_sptr GalileoE5ax2msPcpsAcquisition::get_left_block()
{
return stream_to_vector_;
}
gr::basic_block_sptr GalileoE5ax2msPcpsAcquisition::get_right_block()
{
return acquisition_cc_;
}

View File

@ -1,133 +0,0 @@
/*
* galileo_e5ax_1ms_pcps_acquisition.h
*
* Created on: Jun 23, 2014
* Author: marc
*/
#ifndef GALILEO_E5AX_2MS_PCPS_ACQUISITION_H_
#define GALILEO_E5AX_2MS_PCPS_ACQUISITION_H_
#include <string>
#include <gnuradio/msg_queue.h>
#include <gnuradio/blocks/stream_to_vector.h>
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "galileo_e5ax_2ms_pcps_acquisition_cc.h"
class ConfigurationInterface;
class GalileoE5ax2msPcpsAcquisition: public AcquisitionInterface
{
public:
GalileoE5ax2msPcpsAcquisition(ConfigurationInterface* configuration,
std::string role, unsigned int in_streams,
unsigned int out_streams, boost::shared_ptr<gr::msg_queue> queue);
virtual ~GalileoE5ax2msPcpsAcquisition();
std::string role()
{
return role_;
}
/*!
* \brief Returns "Galileo_E5ax_2ms_Pcps_Acquisition"
*/
std::string implementation()
{
return "Galileo_E5ax_2ms_Pcps_Acquisition";
}
size_t item_size()
{
return item_size_;
}
void connect(gr::top_block_sptr top_block);
void disconnect(gr::top_block_sptr top_block);
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to efficiently exchange synchronization data between acquisition and
* tracking blocks
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro);
/*!
* \brief Set acquisition channel unique ID
*/
void set_channel(unsigned int channel);
/*!
* \brief Set statistics threshold of PCPS algorithm
*/
void set_threshold(float threshold);
/*!
* \brief Set maximum Doppler off grid search
*/
void set_doppler_max(unsigned int doppler_max);
/*!
* \brief Set Doppler steps for the grid search
*/
void set_doppler_step(unsigned int doppler_step);
/*!
* \brief Set tracking channel internal queue
*/
void set_channel_queue(concurrent_queue<int> *channel_internal_queue);
/*!
* \brief Initializes acquisition algorithm.
*/
void init();
/*!
* \brief Sets local Galileo E5a (pilot) code for PCPS acquisition algorithm.
*/
void set_local_code();
/*!
* \brief Returns the maximum peak of grid search
*/
signed int mag();
/*!
* \brief Restart acquisition algorithm
*/
void reset();
private:
ConfigurationInterface* configuration_;
galileo_e5ax_2ms_pcps_acquisition_cc_sptr acquisition_cc_;
gr::blocks::stream_to_vector::sptr stream_to_vector_;
size_t item_size_;
std::string item_type_;
unsigned int vector_length_;
unsigned int code_length_;
bool bit_transition_flag_;
unsigned int channel_;
float threshold_;
unsigned int doppler_max_;
unsigned int doppler_step_;
unsigned int shift_resolution_;
unsigned int sampled_ms_;
unsigned int max_dwells_;
long fs_in_;
long if_;
bool dump_;
std::string dump_filename_;
std::complex<float> * code_;
Gnss_Synchro * gnss_synchro_;
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
boost::shared_ptr<gr::msg_queue> queue_;
concurrent_queue<int> *channel_internal_queue_;
float calculate_threshold(float pfa);
};
#endif /* GALILEO_E5AX_2MS_PCPS_ACQUISITION_H_ */

View File

@ -25,9 +25,7 @@ if(OPENCL_FOUND)
pcps_tong_acquisition_cc.cc
pcps_cccwsr_acquisition_cc.cc
galileo_pcps_8ms_acquisition_cc.cc
galileo_e5a_pilot_3ms_acquisition_cc.cc
galileo_e5ax_2ms_pcps_acquisition_cc.cc
galileo_e5a_3ms_noncoherent_iq_acquisition_cc.cc
galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc
pcps_opencl_acquisition_cc.cc # Needs OpenCL
)
else(OPENCL_FOUND)
@ -39,9 +37,7 @@ else(OPENCL_FOUND)
pcps_tong_acquisition_cc.cc
pcps_cccwsr_acquisition_cc.cc
galileo_pcps_8ms_acquisition_cc.cc
galileo_e5a_pilot_3ms_acquisition_cc.cc
galileo_e5ax_2ms_pcps_acquisition_cc.cc
galileo_e5a_3ms_noncoherent_iq_acquisition_cc.cc
galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc
)
endif(OPENCL_FOUND)

View File

@ -1,592 +0,0 @@
/*!
* \file galileo_e5a_3ms_noncoherent_iq_acquisition_cc.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_3ms_noncoherent_iq_acquisition_cc.h"
#include <sys/time.h>
#include <sstream>
#include <gnuradio/io_signature.h>
#include <glog/logging.h>
#include <volk/volk.h>
#include "gnss_signal_processing.h"
#include "control_message_factory.h"
using google::LogMessage;
galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr galileo_e5a_3ms_noncoherentIQ_make_acquisition_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename)
{
return galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr(
new galileo_e5a_3ms_noncoherentIQ_acquisition_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms,
samples_per_code, bit_transition_flag, queue, dump, dump_filename));
}
galileo_e5a_3ms_noncoherentIQ_acquisition_cc::galileo_e5a_3ms_noncoherentIQ_acquisition_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename) :
gr::block("galileo_e5a_3ms_noncoherentIQ_acquisition_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(0, 0, sizeof(gr_complex)))
//gr::io_signature::make(1, 1, sizeof(gr_complex) * 3 * samples_per_ms),
//gr::io_signature::make(0, 0, sizeof(gr_complex) * 3 * samples_per_ms))
{
//this->set_relative_rate(1.0/1*samples_per_ms);
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_state = 0;
d_queue = queue;
d_freq = freq;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_samples_per_code = samples_per_code;
d_max_dwells = max_dwells;
d_well_count = 0;
d_doppler_max = doppler_max;
d_fft_size = sampled_ms * d_samples_per_ms;
d_mag = 0;
d_input_power = 0.0;
d_num_doppler_bins = 0;
d_bit_transition_flag = bit_transition_flag;
d_buffer_count=0;
d_gr_stream_buffer = 7000; // number of samples entering each general work, arbitrary number. Works with all numbers below gnu radio maximum buffer
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&d_inbuffer, 16, ceil((double)d_fft_size/(double)d_gr_stream_buffer)*d_gr_stream_buffer * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_I_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_I_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_Q_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_Q_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitudeIA, 16, d_fft_size * sizeof(float)) == 0){};
if (posix_memalign((void**)&d_magnitudeIB, 16, d_fft_size * sizeof(float)) == 0){};
if (posix_memalign((void**)&d_magnitudeQA, 16, d_fft_size * sizeof(float)) == 0){};
if (posix_memalign((void**)&d_magnitudeQB, 16, d_fft_size * sizeof(float)) == 0){};
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
// Inverse FFT
d_ifft = new gr::fft::fft_complex(d_fft_size, false);
// d_ifft = new gr::fft::fft_complex(d_fft_size, true);
// For dumping samples into a file
d_dump = dump;
d_dump_filename = dump_filename;
}
galileo_e5a_3ms_noncoherentIQ_acquisition_cc::~galileo_e5a_3ms_noncoherentIQ_acquisition_cc()
{
if (d_num_doppler_bins > 0)
{
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
free(d_grid_doppler_wipeoffs[i]);
}
delete[] d_grid_doppler_wipeoffs;
}
free(d_fft_code_I_A);
free(d_fft_code_I_B);
free(d_fft_code_Q_A);
free(d_fft_code_Q_B);
free(d_magnitudeIA);
free(d_magnitudeIB);
free(d_magnitudeQA);
free(d_magnitudeQB);
delete d_fft_if;
delete d_ifft;
if (d_dump)
{
d_dump_file.close();
}
}
void galileo_e5a_3ms_noncoherentIQ_acquisition_cc::forecast (int noutput_items,
gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = d_gr_stream_buffer ; //set the required available samples in each call
}
void galileo_e5a_3ms_noncoherentIQ_acquisition_cc::set_local_code(std::complex<float> * codeI, std::complex<float> * codeQ )
{
// DATA SIGNAL
// Three replicas of data primary code. CODE A: (1,1,1)
memcpy(d_fft_if->get_inbuf(), codeI, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_I_A,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_I_A,d_fft_if->get_outbuf(),d_fft_size);
}
// CODE B: First replica is inverted (0,1,1)
volk_32fc_s32fc_multiply_32fc_a(&(d_fft_if->get_inbuf())[0],
&codeI[0], gr_complex(-1,0),
d_samples_per_code);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_I_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_I_B,d_fft_if->get_outbuf(),d_fft_size);
}
// SAME FOR PILOT SIGNAL
// Three replicas of pilot primary code. CODE A: (1,1,1)
memcpy(d_fft_if->get_inbuf(), codeQ, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_Q_A,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_Q_A,d_fft_if->get_outbuf(),d_fft_size);
}
// CODE B: First replica is inverted (0,1,1)
volk_32fc_s32fc_multiply_32fc_a(&(d_fft_if->get_inbuf())[0],
&codeQ[0], gr_complex(-1,0),
d_samples_per_code);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_Q_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_Q_B,d_fft_if->get_outbuf(),d_fft_size);
}
}
void galileo_e5a_3ms_noncoherentIQ_acquisition_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_mag = 0.0;
d_input_power = 0.0;
// Count the number of bins
d_num_doppler_bins = 0;
for (int doppler = (int)(-d_doppler_max);
doppler <= (int)d_doppler_max;
doppler += d_doppler_step)
{
d_num_doppler_bins++;
}
// Create the carrier Doppler wipeoff signals
d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins];
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
if (posix_memalign((void**)&(d_grid_doppler_wipeoffs[doppler_index]), 16,
d_fft_size * sizeof(gr_complex)) == 0){};
int doppler = -(int)d_doppler_max + d_doppler_step*doppler_index;
complex_exp_gen_conj(d_grid_doppler_wipeoffs[doppler_index],
d_freq + doppler, d_fs_in, d_fft_size);
}
}
int galileo_e5a_3ms_noncoherentIQ_acquisition_cc::general_work(int noutput_items,
gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
/*
* By J.Arribas, L.Esteve, M.Molina and M.Sales
* Acquisition strategy (Kay Borre book + CFAR threshold):
* 1. Compute the input signal power estimation
* 2. Doppler serial search loop
* 3. Perform the FFT-based circular convolution (parallel time search)
* 4. Record the maximum peak and the associated synchronization parameters
* 5. Compute the test statistics and compare to the threshold
* 6. Declare positive or negative acquisition using a message queue
*/
int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
/* States: 0 Reset and load first stream
* 1 Load the buffer until it reaches fft_size
* 2 Acquisition algorithm
* 3 Positive acquisition
* 4 Negative acquisition
*/
d_sample_counter += d_gr_stream_buffer;
std::cout << d_state <<" "<< d_sample_counter << std::endl;
switch (d_state)
{
case 0:
{
if (d_active)
{
//restart acquisition variables
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;
}
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
memcpy(&d_inbuffer[d_buffer_count*d_gr_stream_buffer], in, sizeof(gr_complex)*d_gr_stream_buffer);
d_buffer_count++;
//d_sample_counter += ninput_items[0]; // sample counter
//consume_each(ninput_items[0]);
break;
}
case 1:
{
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
memcpy(&d_inbuffer[d_buffer_count*d_gr_stream_buffer], in, sizeof(gr_complex)*d_gr_stream_buffer);
d_buffer_count++;
if (d_buffer_count*d_gr_stream_buffer >= d_fft_size-d_gr_stream_buffer)
{
d_state=2;
}
// volk_32fc_x2_multiply_32fc_a(d_fft_if->get_inbuf(), in,
// d_grid_doppler_wipeoffs[0], d_fft_size);
//consume_each(7000);
break;
}
case 2:
{
// Fill last part of the buffer and reset counter
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
memcpy(&d_inbuffer[d_buffer_count*d_gr_stream_buffer], in, sizeof(gr_complex)*d_gr_stream_buffer);
d_buffer_count = 0;
// initialize acquisition algorithm
int doppler;
unsigned int indext = 0;
unsigned int indext_IA = 0;
unsigned int indext_IB = 0;
unsigned int indext_QA = 0;
unsigned int indext_QB = 0;
float magt = 0.0;
float magt_IA = 0.0;
float magt_IB = 0.0;
float magt_QA = 0.0;
float magt_QB = 0.0;
//const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
float fft_normalization_factor = (float)d_fft_size * (float)d_fft_size;
d_input_power = 0.0;
d_mag = 0.0;
int comb = 0;
//d_sample_counter += d_fft_size; // sample counter
d_well_count++;
DLOG(INFO) << "Channel: " << d_channel
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
<< d_threshold << ", doppler_max: " << d_doppler_max
<< ", doppler_step: " << d_doppler_step;
// 1- Compute the input signal power estimation
volk_32fc_magnitude_squared_32f_a(d_magnitudeIA, d_inbuffer, d_fft_size);
volk_32f_accumulator_s32f_a(&d_input_power, d_magnitudeIA, d_fft_size);
d_input_power /= (float)d_fft_size;
// 2- Doppler frequency search loop
for (unsigned int doppler_index=0;doppler_index<d_num_doppler_bins;doppler_index++)
{
// doppler search steps
doppler=-(int)d_doppler_max+d_doppler_step*doppler_index;
volk_32fc_x2_multiply_32fc_a(d_fft_if->get_inbuf(), d_inbuffer,
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();
// CODE IA
// Multiply carrier wiped--off, Fourier transformed incoming signal
// with the local FFT'd code reference using SIMD operations with VOLK library
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_I_A, d_fft_size);
// compute the inverse FFT
d_ifft->execute();
// Search maximum
volk_32fc_magnitude_squared_32f_a(d_magnitudeIA, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_IA, d_magnitudeIA, d_fft_size);
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt_IA = d_magnitudeIA[indext_IA] / (fft_normalization_factor * fft_normalization_factor);
// only 1 ms
//magt=magt_A;
//indext=indext_A;
// REPEAT FOR ALL CODES. CODE_IB
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_I_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeIB, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_IB, d_magnitudeIB, d_fft_size);
magt_IB = d_magnitudeIB[indext_IB] / (fft_normalization_factor * fft_normalization_factor);
// REPEAT FOR ALL CODES. CODE_QA
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_Q_A, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeQA, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_QA, d_magnitudeQA, d_fft_size);
magt_QA = d_magnitudeQA[indext_QA] / (fft_normalization_factor * fft_normalization_factor);
// REPEAT FOR ALL CODES. CODE_QB
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_Q_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeQB, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_QB, d_magnitudeQB, d_fft_size);
magt_QB = d_magnitudeIB[indext_QB] / (fft_normalization_factor * fft_normalization_factor);
// Integrate noncoherently the two best combinations (I² + Q²)
// and store the result in the I channel.
if (magt_IA >= magt_IB)
{
if (magt_QA >= magt_QB)
{
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIA[i] += d_magnitudeQA[i];
}
}
else
{
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIA[i] += d_magnitudeQB[i];
}
}
volk_32f_index_max_16u_a(&indext, d_magnitudeIA, d_fft_size);
magt = d_magnitudeIA[indext] / (fft_normalization_factor * fft_normalization_factor);
}
else
{
if (magt_QA >= magt_QB)
{
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIB[i] += d_magnitudeQA[i];
}
}
else
{
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIB[i] += d_magnitudeQB[i];
}
}
volk_32f_index_max_16u_a(&indext, d_magnitudeIB, d_fft_size);
magt = d_magnitudeIB[indext] / (fft_normalization_factor * fft_normalization_factor);
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
{
d_mag = magt;
//std::cout << "ACQ_block_e5a_3ms secondary combination " << sec_comb << std::endl;
// In case that d_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) || !d_bit_transition_flag)
{
d_gnss_synchro->Acq_delay_samples = (double)(indext % d_samples_per_code);
d_gnss_synchro->Acq_doppler_hz = (double)doppler;
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// 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 (d_dump)
{
std::stringstream filename;
std::streamsize n = sizeof(float) * (d_fft_size); // noncomplex file write
filename.str("");
filename << "../data/test_statistics_" << d_gnss_synchro->System
<<"_" << d_gnss_synchro->Signal << "_sat_"
<< d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
if (magt_IA >= magt_IB)
{
d_dump_file.write((char*)d_magnitudeIA, n);
}
else
{
d_dump_file.write((char*)d_magnitudeIB, n);
}
//d_dump_file.write((char*)d_magnitudeIA, n);
d_dump_file.close();
}
}
if (!d_bit_transition_flag)
{
if (d_test_statistics > d_threshold)
{
d_state = 3; // Positive acquisition
}
else if (d_well_count == d_max_dwells)
{
d_state = 4; // Negative acquisition
}
else
{
d_state = 2;
}
}
else
{
if (d_well_count == d_max_dwells) // d_max_dwells = 2
{
if (d_test_statistics > d_threshold)
{
d_state = 3; // Positive acquisition
}
else
{
d_state = 4; // Negative acquisition
}
}
else
{
d_state = 2;
}
}
//consume_each(1);
//consume_each(d_fft_size);
break;
}
case 3:
{
// 6.1- Declare positive acquisition using a message queue
DLOG(INFO) << "positive acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
//d_sample_counter += 7000;
//d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
//consume_each(ninput_items[0]);
//consume_each(d_fft_size);
acquisition_message = 1;
d_channel_internal_queue->push(acquisition_message);
break;
}
case 4:
{
// 6.2- Declare negative acquisition using a message queue
DLOG(INFO) << "negative acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
//d_sample_counter += 7000;
//d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
//consume_each(ninput_items[0]);
//consume_each(d_fft_size);
acquisition_message = 2;
d_channel_internal_queue->push(acquisition_message);
break;
}
}
consume_each(d_gr_stream_buffer);
return 0;
}

View File

@ -0,0 +1,771 @@
/*!
* \file galileo_e5a_noncoherent_iq_acquisition_caf_cc.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
* \based on work from:
* <ul>
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
* </ul>
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_noncoherent_iq_acquisition_caf_cc.h"
#include <sys/time.h>
#include <sstream>
#include <gnuradio/io_signature.h>
#include <glog/logging.h>
#include <volk/volk.h>
#include "gnss_signal_processing.h"
#include "control_message_factory.h"
using google::LogMessage;
galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename,
bool both_signal_components_,
int CAF_window_hz_)
{
return galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr(
new galileo_e5a_noncoherentIQ_acquisition_caf_cc(sampled_ms, max_dwells, doppler_max, freq, fs_in, samples_per_ms,
samples_per_code, bit_transition_flag, queue, dump, dump_filename, both_signal_components_, CAF_window_hz_));
}
galileo_e5a_noncoherentIQ_acquisition_caf_cc::galileo_e5a_noncoherentIQ_acquisition_caf_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename,
bool both_signal_components_,
int CAF_window_hz_) :
gr::block("galileo_e5a_noncoherentIQ_acquisition_caf_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(0, 0, sizeof(gr_complex)))
{
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_state = 0;
d_queue = queue;
d_freq = freq;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_samples_per_code = samples_per_code;
d_max_dwells = max_dwells;
d_well_count = 0;
d_doppler_max = doppler_max;
d_fft_size = sampled_ms * d_samples_per_ms;
d_mag = 0;
d_input_power = 0.0;
d_num_doppler_bins = 0;
d_bit_transition_flag = bit_transition_flag;
d_buffer_count=0;
d_both_signal_components = both_signal_components_;
// d_CAF_filter = true;
// d_CAF_window_hz = 6000;
d_CAF_window_hz = CAF_window_hz_;
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&d_inbuffer, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_I_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitudeIA, 16, d_fft_size * sizeof(float)) == 0){};
if (d_both_signal_components == true)
{
if (posix_memalign((void**)&d_fft_code_Q_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitudeQA, 16, d_fft_size * sizeof(float)) == 0){};
}
// IF INTEGRATION TIME > 1
if (d_samples_per_ms != d_fft_size)
{
if (posix_memalign((void**)&d_fft_code_I_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitudeIB, 16, d_fft_size * sizeof(float)) == 0){};
if (d_both_signal_components == true)
{
if (posix_memalign((void**)&d_fft_code_Q_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitudeQB, 16, d_fft_size * sizeof(float)) == 0){};
}
}
// if (posix_memalign((void**)&d_fft_code_Q_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
// if (posix_memalign((void**)&d_magnitudeQA, 16, d_fft_size * sizeof(float)) == 0){};
// if (posix_memalign((void**)&d_fft_code_I_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
// if (posix_memalign((void**)&d_magnitudeIB, 16, d_fft_size * sizeof(float)) == 0){};
// if (posix_memalign((void**)&d_fft_code_Q_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
// if (posix_memalign((void**)&d_magnitudeQB, 16, d_fft_size * sizeof(float)) == 0){};
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
// Inverse FFT
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;
}
galileo_e5a_noncoherentIQ_acquisition_caf_cc::~galileo_e5a_noncoherentIQ_acquisition_caf_cc()
{
if (d_num_doppler_bins > 0)
{
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
free(d_grid_doppler_wipeoffs[i]);
}
delete[] d_grid_doppler_wipeoffs;
}
free(d_fft_code_I_A);
free(d_magnitudeIA);
if (d_both_signal_components == true)
{
free(d_fft_code_Q_A);
free(d_magnitudeQA);
}
// IF INTEGRATION TIME > 1
if (d_samples_per_ms != d_fft_size)
{
free(d_fft_code_I_B);
free(d_magnitudeIB);
if (d_both_signal_components == true)
{
free(d_fft_code_Q_B);
free(d_magnitudeQB);
}
}
delete d_fft_if;
delete d_ifft;
if (d_dump)
{
d_dump_file.close();
}
}
void galileo_e5a_noncoherentIQ_acquisition_caf_cc::set_local_code(std::complex<float> * codeI, std::complex<float> * codeQ )
{
// DATA SIGNAL
// Three replicas of data primary code. CODE A: (1,1,1)
memcpy(d_fft_if->get_inbuf(), codeI, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_I_A,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_I_A,d_fft_if->get_outbuf(),d_fft_size);
}
// SAME FOR PILOT SIGNAL
if (d_both_signal_components == true)
{
// Three replicas of pilot primary code. CODE A: (1,1,1)
memcpy(d_fft_if->get_inbuf(), codeQ, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_Q_A,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_Q_A,d_fft_if->get_outbuf(),d_fft_size);
}
}
// IF INTEGRATION TIME > 1 code, we need to evaluate the other possible combination
// Note: max integration time allowed = 3ms (dealt in adapter)
if (d_samples_per_ms != d_fft_size)
{
// DATA CODE B: First replica is inverted (0,1,1)
volk_32fc_s32fc_multiply_32fc_a(&(d_fft_if->get_inbuf())[0],
&codeI[0], gr_complex(-1,0),
d_samples_per_code);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_I_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_I_B,d_fft_if->get_outbuf(),d_fft_size);
}
if (d_both_signal_components == true)
{
// PILOT CODE B: First replica is inverted (0,1,1)
volk_32fc_s32fc_multiply_32fc_a(&(d_fft_if->get_inbuf())[0],
&codeQ[0], gr_complex(-1,0),
d_samples_per_code);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_Q_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_Q_B,d_fft_if->get_outbuf(),d_fft_size);
}
}
}
}
void galileo_e5a_noncoherentIQ_acquisition_caf_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_mag = 0.0;
d_input_power = 0.0;
// Count the number of bins
d_num_doppler_bins = 0;
for (int doppler = (int)(-d_doppler_max);
doppler <= (int)d_doppler_max;
doppler += d_doppler_step)
{
d_num_doppler_bins++;
}
// Create the carrier Doppler wipeoff signals
d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins];
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
if (posix_memalign((void**)&(d_grid_doppler_wipeoffs[doppler_index]), 16,
d_fft_size * sizeof(gr_complex)) == 0){};
int doppler = -(int)d_doppler_max + d_doppler_step*doppler_index;
complex_exp_gen_conj(d_grid_doppler_wipeoffs[doppler_index],
d_freq + doppler, d_fs_in, d_fft_size);
}
/* CAF Filtering to resolve doppler ambiguity. Phase and quadrature must be processed
* separately before non-coherent integration */
// if (d_CAF_filter)
if (d_CAF_window_hz > 0)
{
if (posix_memalign((void**)&d_CAF_vector, 16, d_num_doppler_bins * sizeof(float)) == 0){};
if (posix_memalign((void**)&d_CAF_vector_I, 16, d_num_doppler_bins * sizeof(float)) == 0){};
if (d_both_signal_components == true)
{
if (posix_memalign((void**)&d_CAF_vector_Q, 16, d_num_doppler_bins * sizeof(float)) == 0){};
}
}
}
int galileo_e5a_noncoherentIQ_acquisition_caf_cc::general_work(int noutput_items,
gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
/*
* By J.Arribas, L.Esteve, M.Molina and M.Sales
* Acquisition strategy (Kay Borre book + CFAR threshold):
* 1. Compute the input signal power estimation
* 2. Doppler serial search loop
* 3. Perform the FFT-based circular convolution (parallel time search)
* 4. OPTIONAL: CAF filter to avoid doppler ambiguity
* 5. Record the maximum peak and the associated synchronization parameters
* 6. Compute the test statistics and compare to the threshold
* 7. Declare positive or negative acquisition using a message queue
*/
int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
/* States: 0 Stop Channel
* 1 Load the buffer until it reaches fft_size
* 2 Acquisition algorithm
* 3 Positive acquisition
* 4 Negative acquisition
*/
switch (d_state)
{
case 0:
{
if (d_active)
{
//restart acquisition variables
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;
}
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
}
case 1:
{
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
unsigned int buff_increment;
if (ninput_items[0]+d_buffer_count <= d_fft_size)
{
buff_increment = ninput_items[0];
}
else
{
buff_increment = (d_fft_size-d_buffer_count);
}
memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex)*buff_increment);
// If buffer will be full in next iteration
if (d_buffer_count >= d_fft_size-d_gr_stream_buffer)
{
d_state=2;
}
d_buffer_count += buff_increment;
d_sample_counter += buff_increment; // sample counter
consume_each(buff_increment);
break;
}
case 2:
{
// Fill last part of the buffer and reset counter
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
if (d_buffer_count < d_fft_size)
{
memcpy(&d_inbuffer[d_buffer_count], in, sizeof(gr_complex)*(d_fft_size-d_buffer_count));
}
d_sample_counter += d_fft_size-d_buffer_count; // sample counter
// initialize acquisition algorithm
int doppler;
unsigned int indext = 0;
unsigned int indext_IA = 0;
unsigned int indext_IB = 0;
unsigned int indext_QA = 0;
unsigned int indext_QB = 0;
float magt = 0.0;
float magt_IA = 0.0;
float magt_IB = 0.0;
float magt_QA = 0.0;
float magt_QB = 0.0;
float fft_normalization_factor = (float)d_fft_size * (float)d_fft_size;
d_input_power = 0.0;
d_mag = 0.0;
d_well_count++;
DLOG(INFO) << "Channel: " << d_channel
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
<< d_threshold << ", doppler_max: " << d_doppler_max
<< ", doppler_step: " << d_doppler_step;
// 1- Compute the input signal power estimation
volk_32fc_magnitude_squared_32f_a(d_magnitudeIA, d_inbuffer, d_fft_size);
volk_32f_accumulator_s32f_a(&d_input_power, d_magnitudeIA, d_fft_size);
d_input_power /= (float)d_fft_size;
// 2- Doppler frequency search loop
for (unsigned int doppler_index=0;doppler_index<d_num_doppler_bins;doppler_index++)
{
// doppler search steps
doppler=-(int)d_doppler_max+d_doppler_step*doppler_index;
volk_32fc_x2_multiply_32fc_a(d_fft_if->get_inbuf(), d_inbuffer,
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();
// CODE IA
// Multiply carrier wiped--off, Fourier transformed incoming signal
// with the local FFT'd code reference using SIMD operations with VOLK library
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_I_A, d_fft_size);
// compute the inverse FFT
d_ifft->execute();
// Search maximum
volk_32fc_magnitude_squared_32f_a(d_magnitudeIA, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_IA, d_magnitudeIA, d_fft_size);
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt_IA = d_magnitudeIA[indext_IA] / (fft_normalization_factor * fft_normalization_factor);
if (d_both_signal_components == true)
{
// REPEAT FOR ALL CODES. CODE_QA
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_Q_A, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeQA, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_QA, d_magnitudeQA, d_fft_size);
magt_QA = d_magnitudeQA[indext_QA] / (fft_normalization_factor * fft_normalization_factor);
}
if (d_samples_per_ms != d_fft_size) // If Integration time > 1 code
{
// REPEAT FOR ALL CODES. CODE_IB
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_I_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeIB, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_IB, d_magnitudeIB, d_fft_size);
magt_IB = d_magnitudeIB[indext_IB] / (fft_normalization_factor * fft_normalization_factor);
if (d_both_signal_components == true)
{
// REPEAT FOR ALL CODES. CODE_QB
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_Q_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitudeQB, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_QB, d_magnitudeQB, d_fft_size);
magt_QB = d_magnitudeIB[indext_QB] / (fft_normalization_factor * fft_normalization_factor);
}
}
// Integrate noncoherently the two best combinations (I² + Q²)
// and store the result in the I channel.
// If CAF filter to resolve doppler ambiguity is needed,
// peak is stored before non-coherent integration.
if (d_samples_per_ms != d_fft_size) // T_integration > 1 code
{
if (magt_IA >= magt_IB)
{
// if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IA;}
if (d_CAF_window_hz > 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA];}
if (d_both_signal_components)
{
// Integrate non-coherently I+Q
if (magt_QA >= magt_QB)
{
// if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;}
if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];}
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIA[i] += d_magnitudeQA[i];
}
}
else
{
// if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QB;}
if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB];}
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIA[i] += d_magnitudeQB[i];
}
}
}
volk_32f_index_max_16u_a(&indext, d_magnitudeIA, d_fft_size);
magt = d_magnitudeIA[indext] / (fft_normalization_factor * fft_normalization_factor);
}
else
{
// if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IB;}
if (d_CAF_window_hz > 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIB[indext_IB];}
if (d_both_signal_components)
{
// Integrate non-coherently I+Q
if (magt_QA >= magt_QB)
{
//if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;}
if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];}
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIB[i] += d_magnitudeQA[i];
}
}
else
{
// if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QB;}
if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQB[indext_QB];}
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIB[i] += d_magnitudeQB[i];
}
}
}
volk_32f_index_max_16u_a(&indext, d_magnitudeIB, d_fft_size);
magt = d_magnitudeIB[indext] / (fft_normalization_factor * fft_normalization_factor);
}
}
else
{
// if (d_CAF_filter) {d_CAF_vector_I[doppler_index] = magt_IA;}
if (d_CAF_window_hz > 0) {d_CAF_vector_I[doppler_index] = d_magnitudeIA[indext_IA];}
if (d_both_signal_components)
{
// if (d_CAF_filter) {d_CAF_vector_Q[doppler_index] = magt_QA;}
if (d_CAF_window_hz > 0) {d_CAF_vector_Q[doppler_index] = d_magnitudeQA[indext_QA];}
// NON-Coherent integration of only 1 code
for (unsigned int i=0; i<d_fft_size; i++)
{
d_magnitudeIA[i] += d_magnitudeQA[i];
}
}
volk_32f_index_max_16u_a(&indext, d_magnitudeIA, d_fft_size);
magt = d_magnitudeIA[indext] / (fft_normalization_factor * fft_normalization_factor);
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
{
d_mag = magt;
// In case that d_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) || !d_bit_transition_flag)
{
d_gnss_synchro->Acq_delay_samples = (double)(indext % d_samples_per_code);
d_gnss_synchro->Acq_doppler_hz = (double)doppler;
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// 5- Compute the test statistics and compare to the threshold
d_test_statistics = d_mag / d_input_power;
}
}
// Record results to file if required
if (d_dump)
{
std::stringstream filename;
std::streamsize n = sizeof(float) * (d_fft_size); // noncomplex file write
filename.str("");
filename << "../data/test_statistics_E5a_sat_"
<< d_gnss_synchro->PRN << "_doppler_" << doppler << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
if (d_samples_per_ms != d_fft_size) // If integration time > 1 code
{
if (magt_IA >= magt_IB)
{
d_dump_file.write((char*)d_magnitudeIA, n);
}
else
{
d_dump_file.write((char*)d_magnitudeIB, n);
}
}
else
{
d_dump_file.write((char*)d_magnitudeIA, n);
}
d_dump_file.close();
}
}
std::cout << "d_mag " << d_mag << ".d_sample_counter " << d_sample_counter << std::endl;
// 6 OPTIONAL: CAF filter to avoid Doppler ambiguity in bit transition.
if (d_CAF_window_hz > 0)
{
int CAF_bins_half;
float* accum;
// double* accum;
if (posix_memalign((void**)&accum, 16, sizeof(float)) == 0){};
CAF_bins_half = d_CAF_window_hz/(2*d_doppler_step);
std::cout << "CAF_bins_half " << CAF_bins_half << std::endl;
// Initialize first iterations
for (int doppler_index=0;doppler_index<CAF_bins_half;doppler_index++)
{
d_CAF_vector[doppler_index] = 0;
// volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], d_CAF_vector_I, CAF_bins_half+doppler_index+1);
for (int i = 0; i < CAF_bins_half+doppler_index+1; i++)
{
d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1-0.1*(abs(doppler_index - i)));
}
// d_CAF_vector[doppler_index] /= CAF_bins_half+doppler_index+1;
d_CAF_vector[doppler_index] /= 1+CAF_bins_half+doppler_index - 0.1*CAF_bins_half*(CAF_bins_half+1)/2 - 0.1*doppler_index*(doppler_index+1)/2; // triangles = [n*(n+1)/2]
if (d_both_signal_components)
{
accum[0] = 0;
// volk_32f_accumulator_s32f_a(&accum[0], d_CAF_vector_Q, CAF_bins_half+doppler_index+1);
for (int i = 0; i < CAF_bins_half+doppler_index+1; i++)
{
accum[0] += d_CAF_vector_Q[i] * (1-0.1*(abs(doppler_index - i)));
}
// accum[0] /= CAF_bins_half+doppler_index+1;
accum[0] /= 1+CAF_bins_half+doppler_index - 0.1*CAF_bins_half*(CAF_bins_half+1)/2 - 0.1*doppler_index*(doppler_index+1)/2; // triangles = [n*(n+1)/2]
d_CAF_vector[doppler_index] += accum[0];
}
}
// Body loop
for (unsigned int doppler_index=CAF_bins_half;doppler_index<d_num_doppler_bins-CAF_bins_half;doppler_index++)
{
d_CAF_vector[doppler_index] = 0;
// volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], 2*CAF_bins_half+1);
for (int i = doppler_index-CAF_bins_half; i < doppler_index+CAF_bins_half+1; i++)
{
d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1-0.1*(abs(doppler_index - i)));
}
// d_CAF_vector[doppler_index] /= 2*CAF_bins_half+1;
d_CAF_vector[doppler_index] /= 1+2*CAF_bins_half - 2*0.1*CAF_bins_half*(CAF_bins_half+1)/2;
if (d_both_signal_components)
{
accum[0] = 0;
// volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], 2*CAF_bins_half);
for (int i = doppler_index-CAF_bins_half; i < doppler_index+CAF_bins_half+1; i++)
{
accum[0] += d_CAF_vector_Q[i] * (1-0.1*(abs(doppler_index - i)));
}
// accum[0] /= 2*CAF_bins_half+1;
accum[0] /= 1+2*CAF_bins_half - 2*0.1*CAF_bins_half*(CAF_bins_half+1)/2;
d_CAF_vector[doppler_index] += accum[0];
}
}
// Final iterations
for (unsigned int doppler_index=d_num_doppler_bins-CAF_bins_half;doppler_index<d_num_doppler_bins;doppler_index++)
{
d_CAF_vector[doppler_index] = 0;
// volk_32f_accumulator_s32f_a(&d_CAF_vector[doppler_index], &d_CAF_vector_I[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index));
for (int i = doppler_index-CAF_bins_half; i < d_num_doppler_bins; i++)
{
d_CAF_vector[doppler_index] += d_CAF_vector_I[i] * (1-0.1*(abs(doppler_index - i)));
}
// d_CAF_vector[doppler_index] /= CAF_bins_half+(d_num_doppler_bins-doppler_index);
d_CAF_vector[doppler_index] /= 1+CAF_bins_half+(d_num_doppler_bins-doppler_index-1) -0.1*CAF_bins_half*(CAF_bins_half+1)/2 -0.1*(d_num_doppler_bins-doppler_index-1)*(d_num_doppler_bins-doppler_index)/2;
if (d_both_signal_components)
{
accum[0] = 0;
// volk_32f_accumulator_s32f_a(&accum[0], &d_CAF_vector_Q[doppler_index-CAF_bins_half], CAF_bins_half + (d_num_doppler_bins-doppler_index));
for (int i = doppler_index-CAF_bins_half; i < d_num_doppler_bins; i++)
{
accum[0] += d_CAF_vector_Q[i] * (1-0.1*(abs(doppler_index - i)));
}
// accum[0] /= CAF_bins_half+(d_num_doppler_bins-doppler_index);
accum[0] /= 1+CAF_bins_half+(d_num_doppler_bins-doppler_index-1) -0.1*CAF_bins_half*(CAF_bins_half+1)/2 -0.1*(d_num_doppler_bins-doppler_index-1)*(d_num_doppler_bins-doppler_index)/2;
d_CAF_vector[doppler_index] += accum[0];
}
}
// Recompute the maximum doppler peak
volk_32f_index_max_16u_a(&indext, d_CAF_vector, d_num_doppler_bins);
doppler=-(int)d_doppler_max+d_doppler_step*indext;
d_gnss_synchro->Acq_doppler_hz = (double)doppler;
// Dump if required, appended at the end of the file
if (d_dump)
{
std::stringstream filename;
std::streamsize n = sizeof(float) * (d_num_doppler_bins); // noncomplex file write
filename.str("");
filename << "../data/test_statistics_E5a_sat_"
<< d_gnss_synchro->PRN << "_CAF.dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write((char*)d_CAF_vector, n);
d_dump_file.close();
}
}
if (d_well_count == d_max_dwells)
{
if (d_test_statistics > d_threshold)
{
d_state = 3; // Positive acquisition
}
else
{
d_state = 4; // Negative acquisition
}
}
else
{
d_state = 1;
}
consume_each(d_fft_size-d_buffer_count);
d_buffer_count = 0;
break;
}
case 3:
{
// 7.1- Declare positive acquisition using a message queue
DLOG(INFO) << "positive acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
acquisition_message = 1;
d_channel_internal_queue->push(acquisition_message);
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
}
case 4:
{
// 7.2- Declare negative acquisition using a message queue
DLOG(INFO) << "negative acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
acquisition_message = 2;
d_channel_internal_queue->push(acquisition_message);
break;
}
}
return 0;
}

View File

@ -1,8 +1,14 @@
/*!
* \file galileo_e5a_3ms_noncoherent_iq_acquisition_cc.h
* \file galileo_e5a_noncoherent_iq_acquisition_caf_cc.h
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* Galileo E5a data and pilot Signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
* \based on work from:
* <ul>
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
* <li> Marc Molina, 2013. marc.molina.pena@gmail.com
* </ul>
*
* -------------------------------------------------------------------------
*
@ -29,8 +35,8 @@
* -------------------------------------------------------------------------
*/
#ifndef GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_CC_H_
#define GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_CC_H_
#ifndef GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_
#define GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_
#include <fstream>
#include <queue>
@ -44,18 +50,20 @@
#include "concurrent_queue.h"
#include "gnss_synchro.h"
class galileo_e5a_3ms_noncoherentIQ_acquisition_cc;
class galileo_e5a_noncoherentIQ_acquisition_caf_cc;
typedef boost::shared_ptr<galileo_e5a_3ms_noncoherentIQ_acquisition_cc> galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr;
typedef boost::shared_ptr<galileo_e5a_noncoherentIQ_acquisition_caf_cc> galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr;
galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr
galileo_e5a_3ms_noncoherentIQ_make_acquisition_cc(unsigned int sampled_ms,
galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr
galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
std::string dump_filename,
bool both_signal_components_,
int CAF_window_hz_);
/*!
* \brief This class implements a Parallel Code Phase Search Acquisition.
@ -63,27 +71,31 @@ galileo_e5a_3ms_noncoherentIQ_make_acquisition_cc(unsigned int sampled_ms,
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
* Algorithm 1, for a pseudocode description of this implementation.
*/
class galileo_e5a_3ms_noncoherentIQ_acquisition_cc: public gr::block
class galileo_e5a_noncoherentIQ_acquisition_caf_cc: public gr::block
{
private:
friend galileo_e5a_3ms_noncoherentIQ_acquisition_cc_sptr
galileo_e5a_3ms_noncoherentIQ_make_acquisition_cc(
friend galileo_e5a_noncoherentIQ_acquisition_caf_cc_sptr
galileo_e5a_noncoherentIQ_make_acquisition_caf_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
std::string dump_filename,
bool both_signal_components_,
int CAF_window_hz_);
galileo_e5a_3ms_noncoherentIQ_acquisition_cc(
galileo_e5a_noncoherentIQ_acquisition_caf_cc(
unsigned int sampled_ms,
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
std::string dump_filename,
bool both_signal_components_,
int CAF_window_hz_);
void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift,
int doppler_offset);
@ -128,6 +140,15 @@ private:
bool d_active;
int d_state;
bool d_dump;
bool d_both_signal_components;
// bool d_CAF_filter;
int d_CAF_window_hz;
float* d_CAF_vector;
float* d_CAF_vector_I;
float* d_CAF_vector_Q;
// double* d_CAF_vector;
// double* d_CAF_vector_I;
// double* d_CAF_vector_Q;
unsigned int d_channel;
std::string d_dump_filename;
unsigned int d_buffer_count;
@ -137,7 +158,7 @@ public:
/*!
* \brief Default destructor.
*/
~galileo_e5a_3ms_noncoherentIQ_acquisition_cc();
~galileo_e5a_noncoherentIQ_acquisition_caf_cc();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
@ -232,6 +253,5 @@ public:
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
};
#endif /* GALILEO_E5A_3MS_NONCOHERENT_IQ_ACQUISITION_CC_H_ */
#endif /* GALILEO_E5A_NONCOHERENT_IQ_ACQUISITION_CAF_CC_H_ */

View File

@ -1,415 +0,0 @@
/*
* galileo_e5a_pilot_3ms_acquisition_cc.cc
*
* Created on: Jun 22, 2014
* Author: marc
*/
#include "galileo_e5a_pilot_3ms_acquisition_cc.h"
#include <sys/time.h>
#include <sstream>
#include <gnuradio/io_signature.h>
#include <glog/logging.h>
#include <volk/volk.h>
#include "gnss_signal_processing.h"
#include "control_message_factory.h"
using google::LogMessage;
galileo_e5a_pilot_3ms_acquisition_cc_sptr galileo_e5a_pilot_3ms_make_acquisition_cc(
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename)
{
return galileo_e5a_pilot_3ms_acquisition_cc_sptr(
new galileo_e5a_pilot_3ms_acquisition_cc(max_dwells, doppler_max, freq, fs_in, samples_per_ms,
samples_per_code, bit_transition_flag, queue, dump, dump_filename));
}
galileo_e5a_pilot_3ms_acquisition_cc::galileo_e5a_pilot_3ms_acquisition_cc(
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename) :
gr::block("galileo_e5a_pilot_3ms_acquisition_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex) * 3 * samples_per_ms),
gr::io_signature::make(0, 0, sizeof(gr_complex) * 3 * samples_per_ms))
{
//this->set_relative_rate(1.0/3*samples_per_ms);
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_state = 0;
d_queue = queue;
d_freq = freq;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_samples_per_code = samples_per_code;
d_max_dwells = max_dwells;
d_well_count = 0;
d_doppler_max = doppler_max;
d_fft_size = 3 * d_samples_per_ms;
d_mag = 0;
d_input_power = 0.0;
d_num_doppler_bins = 0;
d_bit_transition_flag = bit_transition_flag;
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&d_fft_code_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_C, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_D, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitude, 16, d_fft_size * sizeof(float)) == 0){};
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
// Inverse FFT
d_ifft = new gr::fft::fft_complex(d_fft_size, false);
// d_ifft = new gr::fft::fft_complex(d_fft_size, true);
// For dumping samples into a file
d_dump = dump;
d_dump_filename = dump_filename;
}
galileo_e5a_pilot_3ms_acquisition_cc::~galileo_e5a_pilot_3ms_acquisition_cc()
{
if (d_num_doppler_bins > 0)
{
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
free(d_grid_doppler_wipeoffs[i]);
}
delete[] d_grid_doppler_wipeoffs;
}
free(d_fft_code_A);
free(d_fft_code_B);
free(d_fft_code_C);
free(d_fft_code_D);
free(d_magnitude);
delete d_ifft;
delete d_fft_if;
if (d_dump)
{
d_dump_file.close();
}
}
void galileo_e5a_pilot_3ms_acquisition_cc::set_local_code(std::complex<float> * code)
{
// Three replicas of pilot primary code. CODE A: (1,1,1)
memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_A,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_A,d_fft_if->get_outbuf(),d_fft_size);
}
// CODE B: First replica is inverted (0,1,1)
volk_32fc_s32fc_multiply_32fc_a(&(d_fft_if->get_inbuf())[0],
&code[0], gr_complex(-1,0),
d_samples_per_code);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_B,d_fft_if->get_outbuf(),d_fft_size);
}
}
void galileo_e5a_pilot_3ms_acquisition_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_mag = 0.0;
d_input_power = 0.0;
// Count the number of bins
d_num_doppler_bins = 0;
for (int doppler = (int)(-d_doppler_max);
doppler <= (int)d_doppler_max;
doppler += d_doppler_step)
{
d_num_doppler_bins++;
}
// Create the carrier Doppler wipeoff signals
d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins];
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
if (posix_memalign((void**)&(d_grid_doppler_wipeoffs[doppler_index]), 16,
d_fft_size * sizeof(gr_complex)) == 0){};
int doppler = -(int)d_doppler_max + d_doppler_step*doppler_index;
complex_exp_gen_conj(d_grid_doppler_wipeoffs[doppler_index],
d_freq + doppler, d_fs_in, d_fft_size);
}
}
int galileo_e5a_pilot_3ms_acquisition_cc::general_work(int noutput_items,
gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
/*
* By J.Arribas, L.Esteve and M.Molina
* Acquisition strategy (Kay Borre book + CFAR threshold):
* 1. Compute the input signal power estimation
* 2. Doppler serial search loop
* 3. Perform the FFT-based circular convolution (parallel time search)
* 4. Record the maximum peak and the associated synchronization parameters
* 5. Compute the test statistics and compare to the threshold
* 6. Declare positive or negative acquisition using a message queue
*/
int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
switch (d_state)
{
case 0:
{
if (d_active)
{
//restart acquisition variables
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;
}
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
}
case 1:
{
// initialize acquisition algorithm
int doppler;
unsigned int indext = 0;
unsigned int indext_A = 0;
unsigned int indext_B = 0;
float magt = 0.0;
float magt_A = 0.0;
float magt_B = 0.0;
unsigned int sec_comb = 0; // secondary combination 0=(111), 1=(011)
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
float fft_normalization_factor = (float)d_fft_size * (float)d_fft_size;
d_input_power = 0.0;
d_mag = 0.0;
d_sample_counter += d_fft_size; // sample counter
d_well_count++;
DLOG(INFO) << "Channel: " << d_channel
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
<< d_threshold << ", doppler_max: " << d_doppler_max
<< ", doppler_step: " << d_doppler_step;
// 1- Compute the input signal power estimation
volk_32fc_magnitude_squared_32f_a(d_magnitude, in, d_fft_size);
volk_32f_accumulator_s32f_a(&d_input_power, d_magnitude, d_fft_size);
d_input_power /= (float)d_fft_size;
// 2- Doppler frequency search loop
for (unsigned int doppler_index=0;doppler_index<d_num_doppler_bins;doppler_index++)
{
// doppler search steps
doppler=-(int)d_doppler_max+d_doppler_step*doppler_index;
volk_32fc_x2_multiply_32fc_a(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();
// Multiply carrier wiped--off, Fourier transformed incoming signal
// with the local FFT'd code reference using SIMD operations with VOLK library
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_A, d_fft_size);
// compute the inverse FFT
d_ifft->execute();
// Search maximum
volk_32fc_magnitude_squared_32f_a(d_magnitude, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_A, d_magnitude, d_fft_size);
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt_A = d_magnitude[indext_A] / (fft_normalization_factor * fft_normalization_factor);
// REPEAT FOR ALL CODES. CODE_B
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitude, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_B, d_magnitude, d_fft_size);
magt_B = d_magnitude[indext_B] / (fft_normalization_factor * fft_normalization_factor);
//Choose the best correlation
if (magt_A >= magt_B)
{
magt = magt_A;
indext = indext_A;
sec_comb = 0;
}
else
{
magt = magt_B;
indext = indext_B;
sec_comb = 1;
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
{
d_mag = magt;
std::cout << "ACQ_block_e5a_3ms secondary combination " << sec_comb << std::endl;
// In case that d_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) || !d_bit_transition_flag)
{
d_gnss_synchro->Acq_delay_samples = (double)(indext % d_samples_per_code);
d_gnss_synchro->Acq_doppler_hz = (double)doppler;
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// 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 (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_" << doppler << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
}
}
if (!d_bit_transition_flag)
{
if (d_test_statistics > d_threshold)
{
d_state = 2; // Positive acquisition
}
else if (d_well_count == d_max_dwells)
{
d_state = 3; // Negative acquisition
}
}
else
{
if (d_well_count == d_max_dwells) // d_max_dwells = 2
{
if (d_test_statistics > d_threshold)
{
d_state = 2; // Positive acquisition
}
else
{
d_state = 3; // Negative acquisition
}
}
}
consume_each(1);
break;
}
case 2:
{
// 6.1- Declare positive acquisition using a message queue
DLOG(INFO) << "positive acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
acquisition_message = 1;
d_channel_internal_queue->push(acquisition_message);
break;
}
case 3:
{
// 6.2- Declare negative acquisition using a message queue
DLOG(INFO) << "negative acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
acquisition_message = 2;
d_channel_internal_queue->push(acquisition_message);
break;
}
}
return 0;
}

View File

@ -1,200 +0,0 @@
/*
* galileo_e5a_pilot_3ms_acquisition_cc.h
*
* Created on: Jun 22, 2014
* Author: marc
*/
#ifndef GALILEO_E5A_PILOT_3MS_ACQUISITION_CC_H_
#define GALILEO_E5A_PILOT_3MS_ACQUISITION_CC_H_
#include <fstream>
#include <queue>
#include <string>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
#include <gnuradio/gr_complex.h>
#include <gnuradio/fft/fft.h>
#include "concurrent_queue.h"
#include "gnss_synchro.h"
class galileo_e5a_pilot_3ms_acquisition_cc;
typedef boost::shared_ptr<galileo_e5a_pilot_3ms_acquisition_cc> galileo_e5a_pilot_3ms_acquisition_cc_sptr;
galileo_e5a_pilot_3ms_acquisition_cc_sptr
galileo_e5a_pilot_3ms_make_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
/*!
* \brief This class implements a Parallel Code Phase Search Acquisition.
*
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
* Algorithm 1, for a pseudocode description of this implementation.
*/
class galileo_e5a_pilot_3ms_acquisition_cc: public gr::block
{
private:
friend galileo_e5a_pilot_3ms_acquisition_cc_sptr
galileo_e5a_pilot_3ms_make_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
galileo_e5a_pilot_3ms_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift,
int doppler_offset);
long d_fs_in;
long d_freq;
int d_samples_per_ms;
int d_samples_per_code;
unsigned int d_doppler_resolution;
float d_threshold;
std::string d_satellite_str;
unsigned int d_doppler_max;
unsigned int d_doppler_step;
unsigned int d_max_dwells;
unsigned int d_well_count;
unsigned int d_fft_size;
unsigned long int d_sample_counter;
gr_complex** d_grid_doppler_wipeoffs;
unsigned int d_num_doppler_bins;
gr_complex* d_fft_code_A;
gr_complex* d_fft_code_B;
gr_complex* d_fft_code_C;
gr_complex* d_fft_code_D;
gr::fft::fft_complex* d_fft_if;
gr::fft::fft_complex* d_ifft;
Gnss_Synchro *d_gnss_synchro;
unsigned int d_code_phase;
float d_doppler_freq;
float d_mag;
float* d_magnitude;
float d_input_power;
float d_test_statistics;
bool d_bit_transition_flag;
gr::msg_queue::sptr d_queue;
concurrent_queue<int> *d_channel_internal_queue;
std::ofstream d_dump_file;
bool d_active;
int d_state;
bool d_dump;
unsigned int d_channel;
std::string d_dump_filename;
public:
/*!
* \brief Default destructor.
*/
~galileo_e5a_pilot_3ms_acquisition_cc();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to exchange synchronization data between acquisition and tracking blocks.
* \param p_gnss_synchro Satellite information shared by the processing blocks.
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
{
d_gnss_synchro = p_gnss_synchro;
}
/*!
* \brief Returns the maximum peak of grid search.
*/
unsigned int mag()
{
return d_mag;
}
/*!
* \brief Initializes acquisition algorithm.
*/
void init();
/*!
* \brief Sets local code for PCPS acquisition algorithm.
* \param code - Pointer to the PRN code.
*/
void set_local_code(std::complex<float> * code);
/*!
* \brief Starts acquisition algorithm, turning from standby mode to
* active mode
* \param active - bool that activates/deactivates the block.
*/
void set_active(bool active)
{
d_active = active;
}
/*!
* \brief Set acquisition channel unique ID
* \param channel - receiver channel.
*/
void set_channel(unsigned int channel)
{
d_channel = channel;
}
/*!
* \brief Set statistics threshold of PCPS algorithm.
* \param threshold - Threshold for signal detection (check \ref Navitec2012,
* Algorithm 1, for a definition of this threshold).
*/
void set_threshold(float threshold)
{
d_threshold = threshold;
}
/*!
* \brief Set maximum Doppler grid search
* \param doppler_max - Maximum Doppler shift considered in the grid search [Hz].
*/
void set_doppler_max(unsigned int doppler_max)
{
d_doppler_max = doppler_max;
}
/*!
* \brief Set Doppler steps for the grid search
* \param doppler_step - Frequency bin of the search grid [Hz].
*/
void set_doppler_step(unsigned int doppler_step)
{
d_doppler_step = doppler_step;
}
/*!
* \brief Set tracking channel internal queue.
* \param channel_internal_queue - Channel's internal blocks information queue.
*/
void set_channel_queue(concurrent_queue<int> *channel_internal_queue)
{
d_channel_internal_queue = channel_internal_queue;
}
/*!
* \brief Parallel Code Phase Search Acquisition signal processing.
*/
int general_work(int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
#endif /* GALILEO_E5A_PILOT_3MS_ACQUISITION_CC_H_ */

View File

@ -1,402 +0,0 @@
/*
* galileo_e5ax_1ms_pcps_acquisition_cc.cc
*
* Created on: Jun 23, 2014
* Author: marc
*/
#include "galileo_e5ax_2ms_pcps_acquisition_cc.h"
#include <sys/time.h>
#include <sstream>
#include <gnuradio/io_signature.h>
#include <glog/logging.h>
#include <volk/volk.h>
#include "gnss_signal_processing.h"
#include "control_message_factory.h"
using google::LogMessage;
galileo_e5ax_2ms_pcps_acquisition_cc_sptr galileo_e5ax_2ms_pcps_make_acquisition_cc(
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename)
{
return galileo_e5ax_2ms_pcps_acquisition_cc_sptr(
new galileo_e5ax_2ms_pcps_acquisition_cc(max_dwells, doppler_max, freq, fs_in, samples_per_ms,
samples_per_code, bit_transition_flag, queue, dump, dump_filename));
}
galileo_e5ax_2ms_pcps_acquisition_cc::galileo_e5ax_2ms_pcps_acquisition_cc(
unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename) :
gr::block("galileo_e5ax_2ms_pcps_acquisition_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex) * 2 * samples_per_ms),
gr::io_signature::make(0, 0, sizeof(gr_complex) * 2 * samples_per_ms))
{
//this->set_relative_rate(1.0/3*samples_per_ms);
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_state = 0;
d_queue = queue;
d_freq = freq;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_samples_per_code = samples_per_code;
d_max_dwells = max_dwells;
d_well_count = 0;
d_doppler_max = doppler_max;
d_fft_size = 2 * d_samples_per_ms;
d_mag = 0;
d_input_power = 0.0;
d_num_doppler_bins = 0;
//always bit transition in e5
//d_bit_transition_flag = bit_transition_flag;
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&d_fft_code_A, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_code_B, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_magnitude, 16, d_fft_size * sizeof(float)) == 0){};
// Direct FFT
d_fft_if = new gr::fft::fft_complex(d_fft_size, true);
// Inverse FFT
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;
}
galileo_e5ax_2ms_pcps_acquisition_cc::~galileo_e5ax_2ms_pcps_acquisition_cc()
{
if (d_num_doppler_bins > 0)
{
for (unsigned int i = 0; i < d_num_doppler_bins; i++)
{
free(d_grid_doppler_wipeoffs[i]);
}
delete[] d_grid_doppler_wipeoffs;
}
free(d_fft_code_A);
free(d_fft_code_B);
free(d_magnitude);
delete d_ifft;
delete d_fft_if;
if (d_dump)
{
d_dump_file.close();
}
}
void galileo_e5ax_2ms_pcps_acquisition_cc::set_local_code(std::complex<float> * code)
{
// Three replicas of pilot primary code. CODE A: (1,1)
memcpy(d_fft_if->get_inbuf(), code, sizeof(gr_complex)*d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
if (is_unaligned())
{
volk_32fc_conjugate_32fc_u(d_fft_code_A,d_fft_if->get_outbuf(),d_fft_size);
// CODE B: First replica is inverted (0,1) by conjugating the code (I - Qi)
volk_32fc_conjugate_32fc_u(d_fft_if->get_inbuf(),code,d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
volk_32fc_conjugate_32fc_u(d_fft_code_B,d_fft_if->get_outbuf(),d_fft_size);
}
else
{
volk_32fc_conjugate_32fc_a(d_fft_code_A,d_fft_if->get_outbuf(),d_fft_size);
// CODE B: First replica is inverted (0,1) by conjugating the code (I - Qi)
volk_32fc_conjugate_32fc_a(d_fft_if->get_inbuf(),code,d_fft_size);
d_fft_if->execute(); // We need the FFT of local code
volk_32fc_conjugate_32fc_a(d_fft_code_B,d_fft_if->get_outbuf(),d_fft_size);
}
}
void galileo_e5ax_2ms_pcps_acquisition_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_mag = 0.0;
d_input_power = 0.0;
// Count the number of bins
d_num_doppler_bins = 0;
for (int doppler = (int)(-d_doppler_max);
doppler <= (int)d_doppler_max;
doppler += d_doppler_step)
{
d_num_doppler_bins++;
}
// Create the carrier Doppler wipeoff signals
d_grid_doppler_wipeoffs = new gr_complex*[d_num_doppler_bins];
for (unsigned int doppler_index = 0; doppler_index < d_num_doppler_bins; doppler_index++)
{
if (posix_memalign((void**)&(d_grid_doppler_wipeoffs[doppler_index]), 16,
d_fft_size * sizeof(gr_complex)) == 0){};
int doppler = -(int)d_doppler_max + d_doppler_step*doppler_index;
complex_exp_gen_conj(d_grid_doppler_wipeoffs[doppler_index],
d_freq + doppler, d_fs_in, d_fft_size);
}
}
int galileo_e5ax_2ms_pcps_acquisition_cc::general_work(int noutput_items,
gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
/*
* By J.Arribas, L.Esteve and M.Molina
* Acquisition strategy (Kay Borre book + CFAR threshold):
* 1. Compute the input signal power estimation
* 2. Doppler serial search loop
* 3. Perform the FFT-based circular convolution (parallel time search)
* 4. Record the maximum peak and the associated synchronization parameters
* 5. Compute the test statistics and compare to the threshold
* 6. Declare positive or negative acquisition using a message queue
*/
int acquisition_message = -1; //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
switch (d_state)
{
case 0:
{
if (d_active)
{
//restart acquisition variables
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;
}
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
}
case 1:
{
// initialize acquisition algorithm
int doppler;
unsigned int indext = 0;
unsigned int indext_A = 0;
unsigned int indext_B = 0;
float magt = 0.0;
float magt_A = 0.0;
float magt_B = 0.0;
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
float fft_normalization_factor = (float)d_fft_size * (float)d_fft_size;
d_input_power = 0.0;
d_mag = 0.0;
d_sample_counter += d_fft_size; // sample counter
d_well_count++;
DLOG(INFO) << "Channel: " << d_channel
<< " , doing acquisition of satellite: " << d_gnss_synchro->System << " "<< d_gnss_synchro->PRN
<< " ,sample stamp: " << d_sample_counter << ", threshold: "
<< d_threshold << ", doppler_max: " << d_doppler_max
<< ", doppler_step: " << d_doppler_step;
// 1- Compute the input signal power estimation
volk_32fc_magnitude_squared_32f_a(d_magnitude, in, d_fft_size);
volk_32f_accumulator_s32f_a(&d_input_power, d_magnitude, d_fft_size);
d_input_power /= (float)d_fft_size;
// 2- Doppler frequency search loop
for (unsigned int doppler_index=0;doppler_index<d_num_doppler_bins;doppler_index++)
{
// doppler search steps
doppler=-(int)d_doppler_max+d_doppler_step*doppler_index;
volk_32fc_x2_multiply_32fc_a(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();
// Multiply carrier wiped--off, Fourier transformed incoming signal
// with the local FFT'd code reference using SIMD operations with VOLK library
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_A, d_fft_size);
// compute the inverse FFT
d_ifft->execute();
// Search maximum
volk_32fc_magnitude_squared_32f_a(d_magnitude, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_A, d_magnitude, d_fft_size);
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt_A = d_magnitude[indext_A] / (fft_normalization_factor * fft_normalization_factor);
// REPEAT FOR CODE_B
volk_32fc_x2_multiply_32fc_a(d_ifft->get_inbuf(),
d_fft_if->get_outbuf(), d_fft_code_B, d_fft_size);
d_ifft->execute();
volk_32fc_magnitude_squared_32f_a(d_magnitude, d_ifft->get_outbuf(), d_fft_size);
volk_32f_index_max_16u_a(&indext_B, d_magnitude, d_fft_size);
magt_B = d_magnitude[indext_B] / (fft_normalization_factor * fft_normalization_factor);
//Choose the best correlation
if (magt_A >= magt_B)
{
magt = magt_A;
indext = indext_A;
}
else
{
magt = magt_B;
indext = indext_B;
}
// 4- record the maximum peak and the associated synchronization parameters
if (d_mag < magt)
{
d_mag = magt;
// In case that d_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) || !d_bit_transition_flag)
{
d_gnss_synchro->Acq_delay_samples = (double)(indext % d_samples_per_code);
d_gnss_synchro->Acq_doppler_hz = (double)doppler;
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// 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 (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_" << doppler << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write((char*)d_ifft->get_outbuf(), n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
}
}
if (!d_bit_transition_flag)
{
if (d_test_statistics > d_threshold)
{
d_state = 2; // Positive acquisition
}
else if (d_well_count == d_max_dwells)
{
d_state = 3; // Negative acquisition
}
}
else
{
if (d_well_count == d_max_dwells) // d_max_dwells = 2
{
if (d_test_statistics > d_threshold)
{
d_state = 2; // Positive acquisition
}
else
{
d_state = 3; // Negative acquisition
}
}
}
consume_each(1);
break;
}
case 2:
{
// 6.1- Declare positive acquisition using a message queue
DLOG(INFO) << "positive acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
acquisition_message = 1;
d_channel_internal_queue->push(acquisition_message);
break;
}
case 3:
{
// 6.2- Declare negative acquisition using a message queue
DLOG(INFO) << "negative acquisition";
DLOG(INFO) << "satellite " << d_gnss_synchro->System << " " << d_gnss_synchro->PRN;
DLOG(INFO) << "sample_stamp " << d_sample_counter;
DLOG(INFO) << "test statistics value " << d_test_statistics;
DLOG(INFO) << "test statistics threshold " << d_threshold;
DLOG(INFO) << "code phase " << d_gnss_synchro->Acq_delay_samples;
DLOG(INFO) << "doppler " << d_gnss_synchro->Acq_doppler_hz;
DLOG(INFO) << "magnitude " << d_mag;
DLOG(INFO) << "input signal power " << d_input_power;
d_active = false;
d_state = 0;
d_sample_counter += d_fft_size * ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
acquisition_message = 2;
d_channel_internal_queue->push(acquisition_message);
break;
}
}
return 0;
}

View File

@ -1,197 +0,0 @@
/*
* galileo_e5ax_1ms_pcps_acquisition_cc.h
*
* Created on: Jun 23, 2014
* Author: marc
*/
#ifndef GALILEO_E5AX_2MS_PCPS_ACQUISITION_CC_H_
#define GALILEO_E5AX_2MS_PCPS_ACQUISITION_CC_H_
#include <fstream>
#include <queue>
#include <string>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
#include <gnuradio/gr_complex.h>
#include <gnuradio/fft/fft.h>
#include "concurrent_queue.h"
#include "gnss_synchro.h"
class galileo_e5ax_2ms_pcps_acquisition_cc;
typedef boost::shared_ptr<galileo_e5ax_2ms_pcps_acquisition_cc> galileo_e5ax_2ms_pcps_acquisition_cc_sptr;
galileo_e5ax_2ms_pcps_acquisition_cc_sptr
galileo_e5ax_2ms_pcps_make_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
/*!
* \brief This class implements a Parallel Code Phase Search Acquisition.
*
* Check \ref Navitec2012 "An Open Source Galileo E1 Software Receiver",
* Algorithm 1, for a pseudocode description of this implementation.
*/
class galileo_e5ax_2ms_pcps_acquisition_cc: public gr::block
{
private:
friend galileo_e5ax_2ms_pcps_acquisition_cc_sptr
galileo_e5ax_2ms_pcps_make_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
galileo_e5ax_2ms_pcps_acquisition_cc(unsigned int max_dwells,
unsigned int doppler_max, long freq, long fs_in,
int samples_per_ms, int samples_per_code,
bool bit_transition_flag,
gr::msg_queue::sptr queue, bool dump,
std::string dump_filename);
void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift,
int doppler_offset);
long d_fs_in;
long d_freq;
int d_samples_per_ms;
int d_samples_per_code;
unsigned int d_doppler_resolution;
float d_threshold;
std::string d_satellite_str;
unsigned int d_doppler_max;
unsigned int d_doppler_step;
unsigned int d_max_dwells;
unsigned int d_well_count;
unsigned int d_fft_size;
unsigned long int d_sample_counter;
gr_complex** d_grid_doppler_wipeoffs;
unsigned int d_num_doppler_bins;
gr_complex* d_fft_code_A;
gr_complex* d_fft_code_B;
gr::fft::fft_complex* d_fft_if;
gr::fft::fft_complex* d_ifft;
Gnss_Synchro *d_gnss_synchro;
unsigned int d_code_phase;
float d_doppler_freq;
float d_mag;
float* d_magnitude;
float d_input_power;
float d_test_statistics;
bool d_bit_transition_flag;
gr::msg_queue::sptr d_queue;
concurrent_queue<int> *d_channel_internal_queue;
std::ofstream d_dump_file;
bool d_active;
int d_state;
bool d_dump;
unsigned int d_channel;
std::string d_dump_filename;
public:
/*!
* \brief Default destructor.
*/
~galileo_e5ax_2ms_pcps_acquisition_cc();
/*!
* \brief Set acquisition/tracking common Gnss_Synchro object pointer
* to exchange synchronization data between acquisition and tracking blocks.
* \param p_gnss_synchro Satellite information shared by the processing blocks.
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
{
d_gnss_synchro = p_gnss_synchro;
}
/*!
* \brief Returns the maximum peak of grid search.
*/
unsigned int mag()
{
return d_mag;
}
/*!
* \brief Initializes acquisition algorithm.
*/
void init();
/*!
* \brief Sets local code for PCPS acquisition algorithm.
* \param code - Pointer to the PRN code.
*/
void set_local_code(std::complex<float> * code);
/*!
* \brief Starts acquisition algorithm, turning from standby mode to
* active mode
* \param active - bool that activates/deactivates the block.
*/
void set_active(bool active)
{
d_active = active;
}
/*!
* \brief Set acquisition channel unique ID
* \param channel - receiver channel.
*/
void set_channel(unsigned int channel)
{
d_channel = channel;
}
/*!
* \brief Set statistics threshold of PCPS algorithm.
* \param threshold - Threshold for signal detection (check \ref Navitec2012,
* Algorithm 1, for a definition of this threshold).
*/
void set_threshold(float threshold)
{
d_threshold = threshold;
}
/*!
* \brief Set maximum Doppler grid search
* \param doppler_max - Maximum Doppler shift considered in the grid search [Hz].
*/
void set_doppler_max(unsigned int doppler_max)
{
d_doppler_max = doppler_max;
}
/*!
* \brief Set Doppler steps for the grid search
* \param doppler_step - Frequency bin of the search grid [Hz].
*/
void set_doppler_step(unsigned int doppler_step)
{
d_doppler_step = doppler_step;
}
/*!
* \brief Set tracking channel internal queue.
* \param channel_internal_queue - Channel's internal blocks information queue.
*/
void set_channel_queue(concurrent_queue<int> *channel_internal_queue)
{
d_channel_internal_queue = channel_internal_queue;
}
/*!
* \brief Parallel Code Phase Search Acquisition signal processing.
*/
int general_work(int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
};
#endif /* GALILEO_E5AX_2MS_PCPS_ACQUISITION_CC_H_ */

View File

@ -35,7 +35,6 @@
void galileo_e5_a_code_gen_complex_primary(std::complex<float>* _dest, signed int _prn, char _Signal[3])
{
std::string _galileo_signal = _Signal;
unsigned int prn=_prn-1;
unsigned int index=0;
int a[4];
@ -43,7 +42,7 @@ void galileo_e5_a_code_gen_complex_primary(std::complex<float>* _dest, signed in
{
return;
}
if (_galileo_signal.rfind("5Q") != std::string::npos && _galileo_signal.length() >= 2)
if (_Signal[0]=='5' && _Signal[1]=='Q')
{
for (size_t i = 0; i < Galileo_E5a_Q_PRIMARY_CODE[prn].length()-1; i++)
{
@ -61,7 +60,7 @@ void galileo_e5_a_code_gen_complex_primary(std::complex<float>* _dest, signed in
_dest[index]=std::complex<float>(float(0.0),a[0]);
_dest[index+1]=std::complex<float>(float(0.0),a[1]);
}
else if (_galileo_signal.rfind("5I") != std::string::npos && _galileo_signal.length() >= 2)
else if (_Signal[0]=='5' && _Signal[1]=='I')
{
for (size_t i = 0; i < Galileo_E5a_I_PRIMARY_CODE[prn].length()-1; i++)
{
@ -79,7 +78,7 @@ void galileo_e5_a_code_gen_complex_primary(std::complex<float>* _dest, signed in
_dest[index]=std::complex<float>(float(a[0]),0.0);
_dest[index+1]=std::complex<float>(float(a[1]),0.0);
}
else if (_galileo_signal.rfind("5X") != std::string::npos && _galileo_signal.length() >= 2)
else if (_Signal[0]=='5' && _Signal[1]=='X')
{
int b[4];
for (size_t i = 0; i < Galileo_E5a_I_PRIMARY_CODE[prn].length()-1; i++)
@ -104,74 +103,11 @@ void galileo_e5_a_code_gen_complex_primary(std::complex<float>* _dest, signed in
}
}
void galileo_e5_a_code_gen_tiered(std::complex<float>* _dest,std::complex<float>* _primary ,unsigned int _prn, char _Signal[3])
{
std::string _galileo_signal = _Signal;
unsigned int prn=_prn-1;
// Note: always generates 100 ms of tiered code
if (_galileo_signal.rfind("5Q") != std::string::npos && _galileo_signal.length() >= 2)
{
for (size_t i = 0; i < Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++)
{
for (size_t k=0; k< Galileo_E5a_CODE_LENGTH_CHIPS; k++)
{
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = _primary[k];
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = new std::complex<float>(0,0);
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].imag( _primary[k].imag() *
(Galileo_E5a_Q_SECONDARY_CODE[prn].at(i)=='0' ? (float)1 : (float)-1));
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].real((float)0);
}
}
}
else if (_galileo_signal.rfind("5I") != std::string::npos && _galileo_signal.length() >= 2)
{
for (size_t i = 0; i < Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++)
{
for (size_t k=0; k< Galileo_E5a_CODE_LENGTH_CHIPS; k++)
{
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = _primary[k];
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = new std::complex<float>(0,0);
// Modulo operator i%20 since i[0,99] and sec code[0,19]
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].real( _primary[k].real() *
(Galileo_E5a_I_SECONDARY_CODE.at(i%20)=='0' ? (float)1 : (float)-1));
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].imag((float)0);
}
}
}
else if (_galileo_signal.rfind("5X") != std::string::npos && _galileo_signal.length() >= 2)
{
for (size_t i = 0; i < Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++)
{
for (size_t k=0; k< Galileo_E5a_CODE_LENGTH_CHIPS; k++)
{
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = _primary[k];
//_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k] = new std::complex<float>(0,0);
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].imag( _primary[k].imag() *
(Galileo_E5a_Q_SECONDARY_CODE[prn].at(i)=='0' ? (float)1 : (float)-1));
_dest[i*Galileo_E5a_CODE_LENGTH_CHIPS + k].real( _primary[k].real() *
(Galileo_E5a_I_SECONDARY_CODE.at(i%20)=='0' ? (float)1 : (float)-1));
}
}
}
else
{
std::cout << "Signal doesn't correspond to E5a signal" << std::endl;
}
}
void galileo_e5_a_code_gen_complex_sampled(std::complex<float>* _dest, char _Signal[3],
unsigned int _prn, signed int _fs, unsigned int _chip_shift,
bool _secondary_flag)
unsigned int _prn, signed int _fs, unsigned int _chip_shift)
{
// This function is based on the GNU software GPS for MATLAB in the Kay Borre book
//std::string _galileo_signal = _Signal;
unsigned int _samplesPerCode;
unsigned int delay;
unsigned int _codeLength = Galileo_E5a_CODE_LENGTH_CHIPS;
@ -179,74 +115,31 @@ void galileo_e5_a_code_gen_complex_sampled(std::complex<float>* _dest, char _Sig
std::complex<float>* _code;
// if (posix_memalign((void**)&_code, 16, _codeLength * sizeof(gr_complex)) == 0){};
_code=new std::complex<float>[_codeLength];
//std::complex<float> primary_code_E5a_chips[(int)Galileo_E5a_CODE_LENGTH_CHIPS];
galileo_e5_a_code_gen_complex_primary(_code , _prn , _Signal);
if (_secondary_flag)
{
std::complex<float>* _tiered_code = new std::complex<float>
[Galileo_E5a_Q_SECONDARY_CODE_LENGTH * Galileo_E5a_CODE_LENGTH_CHIPS];
_codeLength *= Galileo_E5a_Q_SECONDARY_CODE_LENGTH;
// std::complex<float>* _tiered_code;
// if (posix_memalign((void**)&_tiered_code, 16, _codeLength * sizeof(gr_complex)) == 0){};
// std::complex<float> _tiered_code[Galileo_E5a_Q_SECONDARY_CODE_LENGTH * Galileo_E5a_CODE_LENGTH_CHIPS];
//malloc(_tiered_code, )
//std::cout << sizeof (&_tiered_code) << std::endl;
galileo_e5_a_code_gen_tiered(_tiered_code, _code,_prn, _Signal);
delete[] _code;
//free(_code);
//if (posix_memalign((void**)&_code, 16, _codeLength * sizeof(gr_complex)) == 0){};
_code = _tiered_code;
// delete[] _tiered_code;
free(_tiered_code);
}
_samplesPerCode = round(_fs / (_codeFreqBasis / _codeLength));
// NOTE: if secondary, delay accounts for tiered code delay and samples/codesecondary
delay = ((_codeLength - _chip_shift)
% _codeLength) * _samplesPerCode / _codeLength;
//std::cout << "check tiered code delay" << delay << std::endl;
//std::cout << "check codelength" << _codeLength << std::endl;
if (_fs != _codeFreqBasis)
{
std::complex<float>* _resampled_signal;// = new std::complex<float>[_codeLength];
std::complex<float>* _resampled_signal;
if (posix_memalign((void**)&_resampled_signal, 16, _samplesPerCode * sizeof(gr_complex)) == 0){};
resampler(_code, _resampled_signal, _codeFreqBasis, _fs,
_codeLength, _samplesPerCode); //resamples code to fs
// free(_code);
// if (posix_memalign((void**)&_code, 16, _samplesPerCode * sizeof(gr_complex)) == 0){};
delete[] _code;
_code = _resampled_signal;
// delete[] _resampled_signal;
//free(_resampled_signal);
}
//std::cout << _fs << "fs" << std::endl;
for (unsigned int i = 0; i < _samplesPerCode; i++)
{
_dest[(i+delay)%_samplesPerCode] = _code[i];
}
// if (_code[0]==gr_complex(0,0))
// {
// std::cout <<"ERROR: first chip is 0. prn:"<< _prn << std::endl;
// std::cout << _Signal << "signal" << std::endl;
// }
//std::cout << "no problem gen sampled code" <<_prn << " " << _code[0] <<std::endl;
free(_code);
}

View File

@ -54,8 +54,7 @@ void galileo_e5_a_code_gen_tiered(std::complex<float>* _dest,std::complex<float>
* bool _pilot generates E5aQ code if true and E5aI (data signal) if false.
*/
void galileo_e5_a_code_gen_complex_sampled(std::complex<float>* _dest,
char _Signal[3], unsigned int _prn, signed int _fs, unsigned int _chip_shift,
bool _secondary_flag);
char _Signal[3], unsigned int _prn, signed int _fs, unsigned int _chip_shift);
#endif /* GNSS_SDR_GALILEO_E5_SIGNAL_PROCESSING_H_ */

View File

@ -199,59 +199,22 @@ void signal_generator_c::generate_codes()
if(signal_[sat].at(0)=='5')
{
char signal[3];
// strcpy(signal,"5I");
strcpy(signal,"5X");
if (posix_memalign((void**)&(sampled_code_data_[sat]), 16,
vector_length_ * sizeof(gr_complex)) == 0){};
// galileo_e5_a_code_gen_complex_sampled(sampled_code_data_[sat] , signal, PRN_[sat], fs_in_,
// (int)Galileo_E5a_Q_SECONDARY_CODE_LENGTH - delay_chips_[sat], true);
galileo_e5_a_code_gen_complex_sampled(sampled_code_data_[sat] , signal, PRN_[sat], fs_in_,
(int)Galileo_E5a_CODE_LENGTH_CHIPS-delay_chips_[sat],false);
(int)Galileo_E5a_CODE_LENGTH_CHIPS-delay_chips_[sat]);
std::cout << "PRN "<< PRN_[sat] << " first two bytes "<< sampled_code_data_[sat][0] << sampled_code_data_[sat][1] << sampled_code_data_[sat][2] << sampled_code_data_[sat][3] << sampled_code_data_[sat][4] << sampled_code_data_[sat][5] << sampled_code_data_[sat][6] << sampled_code_data_[sat][7] << std::endl;
///////////
/*
std::ofstream d_dump_file;
std::stringstream filename;
std::streamsize n = 2 * sizeof(float) * (Galileo_E5a_CODE_LENGTH_CHIPS); // complex file write
filename.str("");
filename << "../data/PRN11_Xcode_noiseless" << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write((char*)&sampled_code_data_[sat][0], n);
d_dump_file.close();
*/
/////////////////////
//// std::ofstream myfile;
// //myfile.open ("example_sink_gencode.dat");
// std::ofstream myfile("example_sink_gencode.bin",std::ios_base::binary);
//// for (int k=0; k< vector_length_; k++)
//// {
// myfile.write((char*)&sampled_code_data_[sat],sizeof(gr_complex)*vector_length_);
// //myfile << sampled_code_data_[sat][k];
//// }
//
// myfile.close();
//std::cout << "checking tiered code" << sampled_code_data_[sat][0] << sampled_code_data_[sat][1] << sampled_code_data_[sat][2] << sampled_code_data_[sat][3] << sampled_code_data_[sat][4] << sampled_code_data_[sat][1200000] << sampled_code_data_[sat][1200000-1] << std::endl;
// PILOT
// if (posix_memalign((void**)&(sampled_code_pilot_[sat]), 16,
// vector_length_ * sizeof(gr_complex)) == 0){};
//
// strcpy(signal, "5Q");
//
// galileo_e5_a_code_gen_complex_sampled(sampled_code_pilot_[sat] , signal, PRN_[sat], fs_in_,
// (int)Galileo_E5a_CODE_LENGTH_CHIPS - delay_chips_[sat], false);
//noise
if (noise_flag_)
{
for (unsigned int i = 0; i < vector_length_; i++)
{
sampled_code_data_[sat][i] *= sqrt(pow(10, CN0_dB_[sat] / 10) / BW_BB_ / 2);
//sampled_code_pilot_[sat][i] *= sqrt(pow(10, CN0_dB_[sat] / 10) / BW_BB_ / 2);
}
}
@ -389,7 +352,6 @@ gr_vector_void_star &output_items)
if(signal_[sat].at(0)=='5')
{
// EACH WORK outputs 1 modulated primary code
//int codelen = (int)(Galileo_E5a_CODE_LENGTH_CHIPS * Galileo_E5a_Q_SECONDARY_CODE_LENGTH);
int codelen = (int)Galileo_E5a_CODE_LENGTH_CHIPS;
unsigned int delay_samples = (delay_chips_[sat] % codelen)
* samples_per_code_[sat] / codelen;
@ -409,12 +371,6 @@ gr_vector_void_star &output_items)
data_modulation_[sat] = current_data_bit_int_[sat] * (Galileo_E5a_I_SECONDARY_CODE.at((ms_counter_[sat]+delay_sec_[sat])%20)=='0' ? 1 : -1);
pilot_modulation_[sat] = (Galileo_E5a_Q_SECONDARY_CODE[PRN_[sat]-1].at((ms_counter_[sat]+delay_sec_[sat])%100)=='0' ? 1 : -1);
// if (work_counter_==1)
// {
//std::cout << "ms " << ms_counter_[sat] << " sat " << sat << " PRN" << PRN_[sat];
//std::cout << " delay_secI " << (ms_counter_[sat]+delay_sec_[sat])%20 << " delay_secQ " << (ms_counter_[sat]+delay_sec_[sat])%100 << std::endl;//" pilot mod " << pilot_modulation_[sat] << " data bit " << current_data_bit_int_[sat] << " data mod " << data_modulation_[sat] << std::endl;
//std::cout << "code 1st 2 byte " << out[0] << out[1] << out[2] << out[3] << out[4] << out[5] << out[6] << out[7] << std::endl;
// }
ms_counter_[sat] = ms_counter_[sat] + (int)round(1e3*GALILEO_E5a_CODE_PERIOD);
for (k = delay_samples; k < samples_per_code_[sat]; k++)
@ -425,8 +381,6 @@ gr_vector_void_star &output_items)
out_idx++;
}
}
else
{
@ -473,19 +427,7 @@ gr_vector_void_star &output_items)
out[out_idx] += gr_complex(random_->gasdev(),random_->gasdev());
}
}
/*
if (work_counter_==1)
{
std::ofstream d_dump_file;
std::stringstream filename;
std::streamsize n = 2 * sizeof(float) * (samples_per_code_[0]); // complex file write
filename.str("");
filename << "../data/PRN11_Xcode_genwork" << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out | std::ios::binary);
d_dump_file.write((char*)out, n);
d_dump_file.close();
}
*/
// Tell runtime system how many output items we produced.
return 1;
}

View File

@ -41,6 +41,7 @@
#include "galileo_fnav_message.h"
#include "gnss_synchro.h"
#include "convolutional.h"
//#include <volk/volk.h>
//#include "galileo_e1b_telemetry_decoder_cc.h"
#define CRC_ERROR_LIMIT 6
@ -58,12 +59,14 @@ galileo_e5a_make_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, lo
void galileo_e5a_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = GALILEO_FNAV_SYMBOLS_PER_PAGE; // set the required sample history
//ninput_items_required[0] = GALILEO_FNAV_SAMPLES_PER_PAGE; // set the required sample history
ninput_items_required[0] = GALILEO_FNAV_CODES_PER_PREAMBLE;
}
void galileo_e5a_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols, int *page_part_bits)
{
int CodeLength = 240;
// int CodeLength = 240;
int CodeLength = 488;
int DataLength;
int nn, KK, mm, max_states;
int g_encoder[2];
@ -72,6 +75,8 @@ void galileo_e5a_telemetry_decoder_cc::viterbi_decoder(double *page_part_symbols
KK = 7; // Constraint Length
g_encoder[0] = 121; // Polynomial G1
g_encoder[1] = 91; // Polynomial G2
// g_encoder[0] = 171; // Polynomial G1
// g_encoder[1] = 133; // Polynomial G2
mm = KK - 1;
max_states = 1 << mm; // 2^mm
@ -127,15 +132,14 @@ void galileo_e5a_telemetry_decoder_cc::decode_word(double *page_symbols,int fram
page_symbols_deint[i] = -page_symbols_deint[i];
}
}
int page_part_bits[frame_length];
viterbi_decoder(page_symbols_deint, page_part_bits);
int page_bits[frame_length/2];
galileo_e5a_telemetry_decoder_cc::viterbi_decoder(page_symbols_deint, page_bits);
// 3. Call the Galileo page decoder
std::string page_String;
for(int i = 0; i < frame_length; i++)
{
if (page_part_bits[i] > 0)
if (page_bits[i] > 0)
{
page_String.push_back('1');
}
@ -202,36 +206,49 @@ galileo_e5a_telemetry_decoder_cc::galileo_e5a_telemetry_decoder_cc(
d_fs_in = fs_in;
// set the preamble
unsigned short int preambles_bits[GALILEO_INAV_PREAMBLE_LENGTH_BITS] = GALILEO_INAV_PREAMBLE;
//unsigned short int preambles_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS] = GALILEO_FNAV_PREAMBLE;
for (int i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
{
if (GALILEO_FNAV_PREAMBLE.at(i) == '0')
{
d_preamble_bits[i] = 1;
}
else
{
d_preamble_bits[i] = -1;
}
}
//d_symbols_per_preamble = GALILEO_INAV_PREAMBLE_LENGTH_BITS * d_samples_per_symbol;
// memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GALILEO_FNAV_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int));
memcpy((unsigned short int*)this->d_preambles_bits, (unsigned short int*)preambles_bits, GALILEO_INAV_PREAMBLE_LENGTH_BITS*sizeof(unsigned short int));
// preamble bits to sampled symbols
d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * GALILEO_FNAV_SAMPLES_PER_PREAMBLE);
int n = 0;
for (int i = 0; i < GALILEO_INAV_PREAMBLE_LENGTH_BITS; i++)
{
for (unsigned int j = 0; j < GALILEO_FNAV_SAMPLES_PER_SYMBOL; j++)
{
if (d_preambles_bits[i] == 1)
{
d_preambles_symbols[n] = 1;
}
else
{
d_preambles_symbols[n] = -1;
}
n++;
}
}
// // preamble bits to sampled symbols
// d_preambles_symbols = (signed int*)malloc(sizeof(signed int) * GALILEO_FNAV_SAMPLES_PER_PREAMBLE);
// int n = 0;
// for (int i = 0; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
// {
// for (unsigned int j = 0; j < GALILEO_FNAV_SAMPLES_PER_SYMBOL; j++)
// {
// if (d_preambles_bits[i] == 1)
// {
// d_preambles_symbols[n] = 1;
// }
// else
// {
// d_preambles_symbols[n] = -1;
// }
// n++;
// }
// }
//
d_sample_counter = 0;
//d_stat = 0;
d_state = 0;
d_preamble_lock=false;
d_preamble_index = 0;
d_preamble_time_seconds = 0;
d_flag_frame_sync = false;
d_current_symbol_float = 0;
d_prompt_counter = 0;
d_symbol_counter = 0;
d_TOW_at_Preamble = 0;
d_TOW_at_current_symbol = 0;
@ -241,222 +258,300 @@ galileo_e5a_telemetry_decoder_cc::galileo_e5a_telemetry_decoder_cc(
galileo_e5a_telemetry_decoder_cc::~galileo_e5a_telemetry_decoder_cc()
{
delete d_preambles_symbols;
d_dump_file.close();
delete d_preamble_bits;
d_dump_file.close();
}
int galileo_e5a_telemetry_decoder_cc::general_work (int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
{
int preamble_diff = 0;
int corr_sign=0;
bool corr_flag=true;
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0];
d_sample_counter++; //count for the processed samples
// ########### Output the tracking data to navigation and PVT ##########
//
const Gnss_Synchro **in = (const Gnss_Synchro **) &input_items[0]; //Get the input samples pointer
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0];
d_flag_preamble = false;
//******* frame sync ******************
if (d_preamble_lock == false)
{
// d_preamble_lock tells if we have received a valid preamble and we are waiting
// for the next one. Doesn't ensure frame sync yet.
//******* preamble correlation ********
// check if the preamble starts positive correlated or negative correlated
if (in[0][0].Prompt_I < 0) // symbols clipping
{
corr_sign=d_preambles_symbols[0];
}
else
{
corr_sign=-d_preambles_symbols[0];
}
// the preamble is fully correlated only if maintains corr_sign along the whole sequence
for (int i = 1; i < GALILEO_FNAV_SAMPLES_PER_PREAMBLE; i++)
{
if (in[0][i].Prompt_I < 0 && d_preambles_symbols[i]+corr_sign != 0)
{
//exit for
corr_flag=false;
break;
}
if (in[0][i].Prompt_I > 0 && d_preambles_symbols[i]+corr_sign == 0)
{
//exit for
corr_flag=false;
break;
}
}
if (corr_flag==true)
{
d_preamble_index = d_sample_counter;//record the preamble sample stamp
LOG(INFO) << "Preamble detection for Galileo SAT " << this->d_satellite << std::endl;
d_preamble_lock=true;
}
}
// else, preamble_lock == true , we are waiting for the next preamble at a specific time
else if (d_sample_counter == d_preamble_index + GALILEO_FNAV_SAMPLES_PER_PAGE)
{
// only correlate preamble at the right time
//******* preamble correlation ********
// check if the preamble starts positive correlated or negative correlated
if (in[0][0].Prompt_I < 0) // symbols clipping
{
corr_sign = d_preambles_symbols[0];
}
else
{
corr_sign = -d_preambles_symbols[0];
}
// the preamble is fully correlated only if maintains corr_sign along the whole sequence
for (int i = 1; i < GALILEO_FNAV_SAMPLES_PER_PREAMBLE; i++)
{
if (in[0][i].Prompt_I < 0 && d_preambles_symbols[i] + corr_sign != 0)
{
//exit for
corr_flag = false;
break;
}
if (in[0][i].Prompt_I > 0
&& d_preambles_symbols[i] + corr_sign == 0)
{
//exit for
corr_flag = false;
break;
}
}
if (corr_flag == false) // lost preamble sync
{
d_preamble_lock = false;
LOG(INFO)<< "Lost of frame sync SAT " << this->d_satellite << " preamble_diff= " << preamble_diff;
d_flag_frame_sync = false;
flag_TOW_set = false;
}
else // NEW PAGE RECEIVED
{
// 1 - Obtain message symbols averaging samples (20 samples / symbol)
int frame_length_symbols = GALILEO_FNAV_SYMBOLS_PER_PAGE
- GALILEO_FNAV_PREAMBLE_LENGTH_BITS;
//int page_symbols[frame_length_symbols];
double samples_to_bit_accumulator[frame_length_symbols];
//int samples_to_bit_accumulator = 0;
for (int i = 0; i < frame_length_symbols; i++)
{
samples_to_bit_accumulator[i]=0.0;
for (int k = 0; k < GALILEO_FNAV_SAMPLES_PER_SYMBOL; k++)
{
samples_to_bit_accumulator[i] += in[0][k + i*GALILEO_FNAV_SAMPLES_PER_SYMBOL + GALILEO_FNAV_SAMPLES_PER_PREAMBLE].Prompt_I;
// Reminder: corr_sign is negative if phase lock is at 180º
// if (in[0][k + i*GALILEO_FNAV_SAMPLES_PER_SYMBOL + GALILEO_FNAV_SAMPLES_PER_PREAMBLE].Prompt_I
// > 0)
// {
// samples_to_bit_accumulator += corr_sign;
// }
// else
// {
// samples_to_bit_accumulator -= corr_sign;
// }
/* Terminology: Prompt: output from tracking Prompt correlator (Prompt samples)
* Symbol: encoded navigation bits. 1 symbol = 20 samples in E5a
* Bit: decoded navigation bits forming words as described in Galileo ICD
* States: 0 Receiving dummy samples.
* 1 Preamble not locked
* 3 Preamble lock
*/
switch (d_state)
{
case 0:
{
if (in[0][0].Prompt_I != 0)
{
d_current_symbol_float += (float)in[0][0].Prompt_I;
if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1)
{
if (d_current_symbol_float > 0)
{
d_page_symbols[d_symbol_counter] = 1;
}
else
{
d_page_symbols[d_symbol_counter] = -1;
}
d_current_symbol_float = 0;
d_symbol_counter++;
d_prompt_counter = 0;
if (d_symbol_counter == GALILEO_FNAV_PREAMBLE_LENGTH_BITS-1)
{
d_state = 1;
}
}
else
{
d_prompt_counter++;
}
}
break;
}
case 1:
{
d_current_symbol_float += (float)in[0][0].Prompt_I;
if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1)
{
if (d_current_symbol_float > 0)
{
d_page_symbols[d_symbol_counter] = 1;
}
else
{
d_page_symbols[d_symbol_counter] = -1;
}
// d_page_symbols[d_symbol_counter] = d_current_symbol_float/(float)GALILEO_FNAV_CODES_PER_SYMBOL;
d_current_symbol_float = 0;
d_symbol_counter++;
d_prompt_counter = 0;
// **** Attempt Preamble correlation ****
bool corr_flag=true;
int corr_sign = 0; // sequence can be found inverted
// corr_sign = d_preamble_bits[0] * d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
// for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
// {
// if ((d_preamble_bits[i] * d_page_symbols[i + d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS]) != corr_sign)
// {
// //exit for if one bit doesn't correlate
// corr_flag=false;
// break;
// }
// }
// check if the preamble starts positive correlated or negative correlated
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS] < 0) // symbols clipping
{
corr_sign=-d_preamble_bits[0];
}
else
{
corr_sign=d_preamble_bits[0];
}
// the preamble is fully correlated only if maintains corr_sign along the whole sequence
for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
{
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] < 0 && d_preamble_bits[i]+corr_sign != 0)
{
//exit for
corr_flag=false;
break;
}
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] > 0 && d_preamble_bits[i]+corr_sign == 0)
{
//exit for
corr_flag=false;
break;
}
}
//
if (corr_flag==true) // preamble fully correlates
{
d_preamble_index = d_sample_counter - GALILEO_FNAV_CODES_PER_PREAMBLE;//record the preamble sample stamp. Remember correlation appears at the end of the preamble in this design
LOG(INFO) << "Preamble detection for Galileo SAT " << this->d_satellite << std::endl;
d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble.
d_state = 2; // preamble lock
}
if (d_symbol_counter >= GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS)
{
d_symbol_counter = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; // prevents overflow
}
}
else
{
d_prompt_counter++;
}
break;
}
case 2:
{
d_current_symbol_float += (float)in[0][0].Prompt_I;
if (d_prompt_counter == GALILEO_FNAV_CODES_PER_SYMBOL - 1)
{
if (d_current_symbol_float > 0)
{
d_page_symbols[d_symbol_counter] = 1;
}
else
{
d_page_symbols[d_symbol_counter] = -1;
}
// d_page_symbols[d_symbol_counter] = d_current_symbol_float/(float)GALILEO_FNAV_CODES_PER_SYMBOL;
d_current_symbol_float = 0;
d_symbol_counter++;
d_prompt_counter = 0;
// At the right sample stamp, check preamble synchro
if (d_sample_counter == d_preamble_index + GALILEO_FNAV_CODES_PER_PAGE + GALILEO_FNAV_CODES_PER_PREAMBLE)
{
// **** Attempt Preamble correlation ****
bool corr_flag = true;
int corr_sign = 0; // sequence can be found inverted
// corr_sign = d_preamble_bits[0] * d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
// for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
// {
// if ((d_preamble_bits[i] * d_page_symbols[i + d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS]) != corr_sign)
// {
// //exit for if one bit doesn't correlate
// corr_flag=false;
// break;
// }
// }
// check if the preamble starts positive correlated or negative correlated
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS] < 0) // symbols clipping
{
corr_sign=-d_preamble_bits[0];
}
else
{
corr_sign=d_preamble_bits[0];
}
// the preamble is fully correlated only if maintains corr_sign along the whole sequence
for (int i = 1; i < GALILEO_FNAV_PREAMBLE_LENGTH_BITS; i++)
{
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] < 0 && d_preamble_bits[i]+corr_sign != 0)
{
//exit for
corr_flag=false;
break;
}
if (d_page_symbols[d_symbol_counter - GALILEO_FNAV_PREAMBLE_LENGTH_BITS + i] > 0 && d_preamble_bits[i]+corr_sign == 0)
{
//exit for
corr_flag=false;
break;
}
}
//
if (corr_flag==true) // NEW PREAMBLE RECEIVED. DECODE PAGE
{
d_preamble_index = d_sample_counter - GALILEO_FNAV_CODES_PER_PREAMBLE;//record the preamble sample stamp
// Change sign if necessary
// if (corr_sign < 0)
// {
// // NOTE: exists volk library for integers ???
// for (int i = 0; i < d_symbol_counter; i++)
// {
// d_page_symbols[i] = -d_page_symbols[i];
// }
// }
// DECODE WORD
decode_word(d_page_symbols, GALILEO_FNAV_SYMBOLS_PER_PAGE - GALILEO_FNAV_PREAMBLE_LENGTH_BITS);
// CHECK CRC
if (d_nav.flag_CRC_test == true)
{
d_CRC_error_counter = 0;
d_flag_preamble = true; //valid preamble indicator (initialized to false every work())
d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs - ((double)(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD); //record the PRN start sample index associated to the preamble start.
if (!d_flag_frame_sync)
{
d_flag_frame_sync = true;
LOG(INFO) <<" Frame sync SAT " << this->d_satellite << " with preamble start at " << d_preamble_time_seconds << " [s]";
}
d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble.
}
else
{
d_CRC_error_counter++;
if (d_CRC_error_counter > CRC_ERROR_LIMIT)
{
LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite;
d_state = 1;
d_symbol_counter = GALILEO_FNAV_PREAMBLE_LENGTH_BITS; // prevents overflow
d_flag_frame_sync = false;
}
else
{
d_symbol_counter = 0; // d_page_symbols start right after preamble and finish at the end of next preamble.
}
}
}
}
}
else
{
d_prompt_counter++;
}
break;
}
}
consume_each(1);
}
samples_to_bit_accumulator[i] /= corr_sign*GALILEO_FNAV_SAMPLES_PER_SYMBOL;
// if (samples_to_bit_accumulator > 0)
// {
// page_symbols[i] = 1; // because last symbol of the preamble is just received now!
//
// }
// else
// {
// page_symbols[i] = -1; // because last symbol of the preamble is just received now!
// }
}
// DECODE WORD
decode_word(samples_to_bit_accumulator, frame_length_symbols);
// CHECK CRC
if (d_nav.flag_CRC_test == true)
{
d_CRC_error_counter = 0;
d_flag_preamble = true; //valid preamble indicator (initialized to false every work())
d_preamble_index = d_sample_counter; //record the preamble sample stamp (t_P)
d_preamble_time_seconds = in[0][0].Tracking_timestamp_secs; // - d_preamble_duration_seconds; //record the PRN start sample index associated to the preamble
if (!d_flag_frame_sync)
{
d_flag_frame_sync = true;
LOG(INFO) <<" Frame sync SAT " << this->d_satellite << " with preamble start at " << d_preamble_time_seconds << " [s]";
}
}
else
{
d_CRC_error_counter++;
d_preamble_index = d_sample_counter; //record the preamble sample stamp
if (d_CRC_error_counter > CRC_ERROR_LIMIT)
{
LOG(INFO) << "Lost of frame sync SAT " << this->d_satellite;
d_flag_frame_sync = false;
d_preamble_lock = false;
}
}
}
}
consume_each(1); //one by one
// UPDATE GNSS SYNCHRO DATA
Gnss_Synchro current_synchro_data; //structure to save the synchronization information and send the output object to the next block
//1. Copy the current tracking output
current_synchro_data = in[0][0];
//2. Add the telemetry decoder information
if (this->d_flag_preamble == true and d_nav.flag_TOW_set == true)
//update TOW at the preamble instant
//We expect a preamble each 10 seconds (FNAV page period)
{
Prn_timestamp_at_preamble_ms = in[0][0].Tracking_timestamp_secs * 1000.0;
if (d_nav.flag_TOW_1 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_1;
d_TOW_at_current_symbol = d_TOW_at_Preamble;
d_nav.flag_TOW_1 = false;
}
if (d_nav.flag_TOW_2 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_2;
d_TOW_at_current_symbol = d_TOW_at_Preamble;
d_nav.flag_TOW_2 = false;
}
if (d_nav.flag_TOW_3 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_3;
d_TOW_at_current_symbol = d_TOW_at_Preamble;
d_nav.flag_TOW_3 = false;
}
if (d_nav.flag_TOW_4 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_4;
d_TOW_at_current_symbol = d_TOW_at_Preamble;
d_nav.flag_TOW_4 = false;
}
else
{
//this page has no timming information
d_TOW_at_Preamble = d_TOW_at_Preamble + GALILEO_FNAV_SECONDS_PER_PAGE;
d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD;
}
//update TOW at the preamble instant
//We expect a preamble each 10 seconds (FNAV page period)
{
Prn_timestamp_at_preamble_ms = d_preamble_time_seconds * 1000;
//Prn_timestamp_at_preamble_ms = in[0][0].Tracking_timestamp_secs * 1000.0;
if (d_nav.flag_TOW_1 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_1;
d_TOW_at_current_symbol = d_TOW_at_Preamble + ((double)(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD);
d_nav.flag_TOW_1 = false;
}
if (d_nav.flag_TOW_2 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_2;
d_TOW_at_current_symbol = d_TOW_at_Preamble + ((double)(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD);
d_nav.flag_TOW_2 = false;
}
if (d_nav.flag_TOW_3 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_3;
d_TOW_at_current_symbol = d_TOW_at_Preamble + ((double)(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD);
d_nav.flag_TOW_3 = false;
}
if (d_nav.flag_TOW_4 == true)
{
d_TOW_at_Preamble = d_nav.FNAV_TOW_4;
d_TOW_at_current_symbol = d_TOW_at_Preamble + ((double)(GALILEO_FNAV_CODES_PER_PAGE+GALILEO_FNAV_CODES_PER_PREAMBLE) * GALILEO_E5a_CODE_PERIOD);
d_nav.flag_TOW_4 = false;
}
else
{
//this page has no timming information
d_TOW_at_Preamble = d_TOW_at_Preamble + GALILEO_FNAV_SECONDS_PER_PAGE;
d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD;
}
}
}
else //if there is not a new preamble, we define the TOW of the current symbol
{
d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD;
}
{
d_TOW_at_current_symbol = d_TOW_at_current_symbol + GALILEO_E5a_CODE_PERIOD;
}
//if (d_flag_frame_sync == true and d_nav.flag_TOW_set==true and d_nav.flag_CRC_test == true)
if (d_flag_frame_sync == true and d_nav.flag_TOW_set == true)
{
current_synchro_data.Flag_valid_word = true;
}
{
current_synchro_data.Flag_valid_word = true;
}
else
{
current_synchro_data.Flag_valid_word = false;
}
{
current_synchro_data.Flag_valid_word = false;
}
current_synchro_data.d_TOW = d_TOW_at_Preamble;
current_synchro_data.d_TOW_at_current_symbol = d_TOW_at_current_symbol;
@ -465,23 +560,24 @@ int galileo_e5a_telemetry_decoder_cc::general_work (int noutput_items, gr_vector
current_synchro_data.Prn_timestamp_at_preamble_ms = Prn_timestamp_at_preamble_ms;
if(d_dump == true)
{
// MULTIPLEXED FILE RECORDING - Record results to file
try
{
double tmp_double;
tmp_double = d_TOW_at_current_symbol;
d_dump_file.write((char*)&tmp_double, sizeof(double));
tmp_double = current_synchro_data.Prn_timestamp_ms;
d_dump_file.write((char*)&tmp_double, sizeof(double));
tmp_double = d_TOW_at_Preamble;
d_dump_file.write((char*)&tmp_double, sizeof(double));
}
catch (const std::ifstream::failure& e)
{
LOG(WARNING) << "Exception writing observables dump file " << e.what();
}
}
{
// MULTIPLEXED FILE RECORDING - Record results to file
try
{
double tmp_double;
tmp_double = d_TOW_at_current_symbol;
d_dump_file.write((char*)&tmp_double, sizeof(double));
tmp_double = current_synchro_data.Prn_timestamp_ms;
d_dump_file.write((char*)&tmp_double, sizeof(double));
tmp_double = d_TOW_at_Preamble;
d_dump_file.write((char*)&tmp_double, sizeof(double));
}
catch (const std::ifstream::failure& e)
{
LOG(WARNING) << "Exception writing observables dump file " << e.what();
}
}
d_sample_counter++; //count for the processed samples
//3. Make the output (copy the object contents to the GNURadio reserved memory)
*out[0] = current_synchro_data;
return 1;

View File

@ -96,15 +96,20 @@ private:
void decode_word(double *page_symbols,int frame_length);
unsigned short int d_preambles_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
signed int *d_preambles_symbols;
signed int d_preamble_bits[GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
// signed int d_page_symbols[GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
double d_page_symbols[GALILEO_FNAV_SYMBOLS_PER_PAGE + GALILEO_FNAV_PREAMBLE_LENGTH_BITS];
signed int *d_preamble_symbols;
float d_current_symbol_float;
long unsigned int d_symbol_counter;
int d_prompt_counter;
long unsigned int d_sample_counter;
long unsigned int d_preamble_index;
bool d_preamble_lock;
bool d_flag_frame_sync;
int d_state;
bool d_flag_preamble;
int d_CRC_error_counter;

View File

@ -441,7 +441,7 @@ static void Viterbi(int output_u_int[],
for (t = 0; t < LL + mm; t++)
{
for (i = 0; i < nn; i++)
rec_array[i] = (float)input_c[nn*t + i];
rec_array[i] = (float)input_c[nn*t + i];
/* precompute all possible branch metrics */
for (i = 0; i < number_symbols; i++)

View File

@ -24,7 +24,6 @@ set(TRACKING_ADAPTER_SOURCES
gps_l1_ca_dll_pll_optim_tracking.cc
gps_l1_ca_dll_pll_tracking.cc
gps_l1_ca_tcp_connector_tracking.cc
galileo_e5a_dll_fll_pll_tracking.cc
galileo_e5a_dll_pll_tracking.cc
)

View File

@ -1,149 +0,0 @@
/*!
* \file galileo_e5a_dll_fll_pll_tracking_cc.h
* \brief Adapts code DLL + carrier PLL aided with FLL
* tracking block to TrackingInterface for Galileo E5a signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_dll_fll_pll_tracking.h"
#include <glog/logging.h>
#include "Galileo_E5a.h"
#include "configuration_interface.h"
using google::LogMessage;
GalileoE5aDllFllPllTracking::GalileoE5aDllFllPllTracking(
ConfigurationInterface* configuration,
std::string role,
unsigned int in_streams, unsigned int
out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
role_(role),
in_streams_(in_streams),
out_streams_(out_streams),
queue_(queue)
{
DLOG(INFO) << "role " << role;
//################# CONFIGURATION PARAMETERS ########################
int fs_in;
int vector_length;
int f_if;
bool dump;
std::string dump_filename;
std::string item_type;
std::string default_item_type = "gr_complex";
float pll_bw_hz;
float fll_bw_hz;
float dll_bw_hz;
float early_late_space_chips;
int order;
item_type = configuration->property(role + ".item_type",default_item_type);
//vector_length = configuration->property(role + ".vector_length", 2048);
fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
f_if = configuration->property(role + ".if", 0);
dump = configuration->property(role + ".dump", false);
order = configuration->property(role + ".order", 2);
pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0);
fll_bw_hz = configuration->property(role + ".fll_bw_hz", 100.0);
dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0);
early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5);
std::string default_dump_filename = "./track_ch";
dump_filename = configuration->property(role + ".dump_filename",
default_dump_filename); //unused!
vector_length = round(fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS));
//################# MAKE TRACKING GNURadio object ###################
if (item_type.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
tracking_ = galileo_e5a_dll_fll_pll_make_tracking_cc(
f_if,
fs_in,
vector_length,
queue_,
dump,
dump_filename,
order,
fll_bw_hz,
pll_bw_hz,
dll_bw_hz,
early_late_space_chips);
}
else
{
LOG(WARNING) << item_type << " unknown tracking item type.";
}
DLOG(INFO) << "tracking(" << tracking_->unique_id() << ")";
}
GalileoE5aDllFllPllTracking::~GalileoE5aDllFllPllTracking()
{}
void GalileoE5aDllFllPllTracking::start_tracking()
{
tracking_->start_tracking();
}
void GalileoE5aDllFllPllTracking::set_channel(unsigned int channel)
{
channel_ = channel;
tracking_->set_channel(channel);
}
void GalileoE5aDllFllPllTracking::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
tracking_->set_channel_queue(channel_internal_queue_);
}
void GalileoE5aDllFllPllTracking::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
{
return tracking_->set_gnss_synchro(p_gnss_synchro);
}
void GalileoE5aDllFllPllTracking::connect(gr::top_block_sptr top_block)
{
//nothing to connect, now the tracking uses gr_sync_decimator
}
void GalileoE5aDllFllPllTracking::disconnect(gr::top_block_sptr top_block)
{
//nothing to disconnect, now the tracking uses gr_sync_decimator
}
gr::basic_block_sptr GalileoE5aDllFllPllTracking::get_left_block()
{
return tracking_;
}
gr::basic_block_sptr GalileoE5aDllFllPllTracking::get_right_block()
{
return tracking_;
}

View File

@ -1,90 +0,0 @@
/*!
* \file galileo_e5a_dll_fll_pll_tracking_cc.h
* \brief Adapts code DLL + carrier PLL aided with FLL
* tracking block to TrackingInterface for Galileo E5a signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_H_
#define GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_H_
#include <string>
#include <gnuradio/msg_queue.h>
#include "tracking_interface.h"
#include "galileo_e5a_dll_fll_pll_tracking_cc.h"
class ConfigurationInterface;
class GalileoE5aDllFllPllTracking: public TrackingInterface
{
public:
GalileoE5aDllFllPllTracking(ConfigurationInterface* configuration,
std::string role,
unsigned int in_streams,
unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue);
virtual ~GalileoE5aDllFllPllTracking();
std::string role()
{
return role_;
}
//! Returns "Galileo_E5a_DLL_FLL_PLL_Tracking"
std::string implementation()
{
return "Galileo_E5a_DLL_FLL_PLL_Tracking";
}
size_t item_size()
{
return item_size_;
}
void connect(gr::top_block_sptr top_block);
void disconnect(gr::top_block_sptr top_block);
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
void set_channel(unsigned int channel);
void set_channel_queue(concurrent_queue<int> *channel_internal_queue);
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro);
void start_tracking();
private:
galileo_e5a_dll_fll_pll_tracking_cc_sptr tracking_;
size_t item_size_;
unsigned int channel_;
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
boost::shared_ptr<gr::msg_queue> queue_;
concurrent_queue<int> *channel_internal_queue_;
};
#endif /* GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_H_ */

View File

@ -31,14 +31,21 @@ GalileoE5aDllPllTracking::GalileoE5aDllPllTracking(
std::string default_item_type = "gr_complex";
float pll_bw_hz;
float dll_bw_hz;
float pll_bw_init_hz;
float dll_bw_init_hz;
int ti_ms;
float early_late_space_chips;
item_type = configuration->property(role + ".item_type", default_item_type);
//vector_length = configuration->property(role + ".vector_length", 2048);
fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 12000000);
f_if = configuration->property(role + ".if", 0);
dump = configuration->property(role + ".dump", false);
pll_bw_hz = configuration->property(role + ".pll_bw_hz", 50.0);
pll_bw_hz = configuration->property(role + ".pll_bw_hz", 5.0);
dll_bw_hz = configuration->property(role + ".dll_bw_hz", 2.0);
pll_bw_init_hz = configuration->property(role + ".pll_bw_init_hz", 20.0);
dll_bw_init_hz = configuration->property(role + ".dll_bw_init_hz", 20.0);
ti_ms = configuration->property(role + ".ti_ms", 3);
early_late_space_chips = configuration->property(role + ".early_late_space_chips", 0.5);
std::string default_dump_filename = "./track_ch";
dump_filename = configuration->property(role + ".dump_filename",
@ -58,6 +65,9 @@ GalileoE5aDllPllTracking::GalileoE5aDllPllTracking(
dump_filename,
pll_bw_hz,
dll_bw_hz,
pll_bw_init_hz,
dll_bw_init_hz,
ti_ms,
early_late_space_chips);
}
else

View File

@ -23,7 +23,6 @@ set(TRACKING_GR_BLOCKS_SOURCES
gps_l1_ca_dll_pll_optim_tracking_cc.cc
gps_l1_ca_dll_pll_tracking_cc.cc
gps_l1_ca_tcp_connector_tracking_cc.cc
galileo_e5a_dll_fll_pll_tracking_cc.cc
galileo_e5a_dll_pll_tracking_cc.cc
)

View File

@ -1,670 +0,0 @@
/*!
* \file galileo_e5a_dll_fll_pll_tracking_cc.h
* \brief Implementation of a code DLL + carrier PLL aided with FLL
* tracking block for Galileo E5a signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "galileo_e5a_dll_fll_pll_tracking_cc.h"
#include <cmath>
#include <iostream>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <glog/logging.h>
#include <gnuradio/io_signature.h>
#include "gnss_synchro.h"
#include "galileo_e5_signal_processing.h"
#include "Galileo_E5a.h"
#include "Galileo_E1.h"
#include "tracking_discriminators.h"
#include "lock_detectors.h"
#include "tracking_FLL_PLL_filter.h"
#include "control_message_factory.h"
#include "gnss_flowgraph.h"
/*!
* \todo Include in definition header file
*/
#define CN0_ESTIMATION_SAMPLES 20
#define MINIMUM_VALID_CN0 25
#define MAXIMUM_LOCK_FAIL_COUNTER 50
#define CARRIER_LOCK_THRESHOLD 0.85
using google::LogMessage;
galileo_e5a_dll_fll_pll_tracking_cc_sptr galileo_e5a_dll_fll_pll_make_tracking_cc(
long if_freq,
long fs_in,
unsigned
int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump, std::string dump_filename,
int order,
float fll_bw_hz,
float pll_bw_hz,
float dll_bw_hz,
float early_late_space_chips)
{
return galileo_e5a_dll_fll_pll_tracking_cc_sptr(new galileo_e5a_dll_fll_pll_tracking_cc(if_freq,
fs_in, vector_length, queue, dump, dump_filename, order, fll_bw_hz, pll_bw_hz,dll_bw_hz,
early_late_space_chips));
}
void galileo_e5a_dll_fll_pll_tracking_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = d_vector_length*2; //set the required available samples in each call
}
galileo_e5a_dll_fll_pll_tracking_cc::galileo_e5a_dll_fll_pll_tracking_cc(
long if_freq,
long fs_in,
unsigned int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump,
std::string dump_filename,
int order,
float fll_bw_hz,
float pll_bw_hz,
float dll_bw_hz,
float early_late_space_chips) :
gr::block("galileo_e5a_dll_fll_pll_tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)))
{
this->set_relative_rate(1.0/vector_length);
// initialize internal vars
d_queue = queue;
d_dump = dump;
d_acquisition_gnss_synchro = NULL;
d_if_freq = (double)if_freq;
d_fs_in = (double)fs_in;
d_vector_length = vector_length;
d_early_late_spc_chips = (double)early_late_space_chips; // Define early-late offset (in chips)
d_dump_filename = dump_filename;
//d_sampled_codeLength = round(d_fs_in / (Galileo_E5a_CODE_CHIP_RATE_HZ / Galileo_E5a_CODE_LENGTH_CHIPS));
// Initialize tracking variables ==========================================
d_carrier_loop_filter.set_params(fll_bw_hz, pll_bw_hz,order);
d_code_loop_filter = Tracking_2nd_DLL_filter(GALILEO_E5a_CODE_PERIOD);
d_code_loop_filter.set_DLL_BW(dll_bw_hz);
// Get space for a vector with the C/A code replica sampled 1x/chip
d_ca_code = new gr_complex[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 2];
/* If an array is partitioned for more than one thread to operate on,
* having the sub-array boundaries unaligned to cache lines could lead
* to performance degradation. Here we allocate memory
* (gr_complex array of size 2*d_vector_length) aligned to cache of 16 bytes
*/
// todo: do something if posix_memalign fails
// Get space for the resampled early / prompt / late local replicas
if (posix_memalign((void**)&d_early_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_late_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_prompt_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
// space for carrier wipeoff and signal baseband vectors
if (posix_memalign((void**)&d_carr_sign, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_Early, 16, sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_Prompt, 16, sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_Late, 16, sizeof(gr_complex)) == 0){};
// sample synchronization
d_sample_counter = 0;
d_acq_sample_stamp = 0;
d_last_seg = 0;// this is for debug output only
d_code_phase_samples = 0;
d_enable_tracking = false;
d_current_prn_length_samples = (int)d_vector_length;
// CN0 estimation and lock detector buffers
d_cn0_estimation_counter = 0;
d_Prompt_buffer = new gr_complex[CN0_ESTIMATION_SAMPLES];
d_carrier_lock_test = 1;
d_CN0_SNV_dB_Hz = 0;
d_carrier_lock_fail_counter = 0;
d_carrier_lock_threshold = CARRIER_LOCK_THRESHOLD;
systemName["G"] = std::string("GPS");
systemName["R"] = std::string("GLONASS");
systemName["S"] = std::string("SBAS");
systemName["E"] = std::string("Galileo");
systemName["C"] = std::string("Compass");
}
void galileo_e5a_dll_fll_pll_tracking_cc::start_tracking()
{
/*
* correct the code phase according to the delay between acq and trk
*/
d_acq_code_phase_samples = d_acquisition_gnss_synchro->Acq_delay_samples;
d_acq_carrier_doppler_hz = d_acquisition_gnss_synchro->Acq_doppler_hz;
d_acq_sample_stamp = d_acquisition_gnss_synchro->Acq_samplestamp_samples;
long int acq_trk_diff_samples;
float acq_trk_diff_seconds;
acq_trk_diff_samples = (long int)d_sample_counter - (long int)d_acq_sample_stamp;
acq_trk_diff_seconds = (double)acq_trk_diff_samples / d_fs_in;
//doppler effect
// Fd=(C/(C+Vr))*F
double radial_velocity;
radial_velocity = (Galileo_E5a_FREQ_HZ + d_acq_carrier_doppler_hz) / Galileo_E5a_FREQ_HZ;
// new chip and prn sequence periods based on acq Doppler
double T_chip_mod_seconds;
double T_prn_mod_seconds;
double T_prn_mod_samples;
d_code_freq_hz = radial_velocity * Galileo_E5a_CODE_CHIP_RATE_HZ;
T_chip_mod_seconds = 1 / d_code_freq_hz;
T_prn_mod_seconds = T_chip_mod_seconds * Galileo_E5a_CODE_LENGTH_CHIPS;
T_prn_mod_samples = T_prn_mod_seconds * d_fs_in;
d_current_prn_length_samples = round(T_prn_mod_samples);
double T_prn_true_seconds = Galileo_E5a_CODE_LENGTH_CHIPS / Galileo_E5a_CODE_CHIP_RATE_HZ;
double T_prn_true_samples = T_prn_true_seconds * d_fs_in;
double T_prn_diff_seconds;
T_prn_diff_seconds = T_prn_true_seconds - T_prn_mod_seconds;
double N_prn_diff;
N_prn_diff = acq_trk_diff_seconds / T_prn_true_seconds;
double corrected_acq_phase_samples, delay_correction_samples;
corrected_acq_phase_samples = fmod((d_acq_code_phase_samples + T_prn_diff_seconds * N_prn_diff * d_fs_in), T_prn_true_samples);
if (corrected_acq_phase_samples < 0)
{
corrected_acq_phase_samples = T_prn_mod_samples + corrected_acq_phase_samples;
}
delay_correction_samples = d_acq_code_phase_samples - corrected_acq_phase_samples;
d_acq_code_phase_samples = corrected_acq_phase_samples;
d_carrier_doppler_hz = d_acq_carrier_doppler_hz;
// DLL/PLL filter initialization
d_carrier_loop_filter.initialize(d_acq_carrier_doppler_hz);
d_FLL_wait = 1;
// generate local reference ALWAYS starting at chip 1 (1 sample per chip)
galileo_e5_a_code_gen_complex_sampled(&d_ca_code[1], d_acquisition_gnss_synchro->Signal, d_acquisition_gnss_synchro->PRN, d_fs_in,0,false);
d_ca_code[0] = d_ca_code[(int)Galileo_E5a_CODE_LENGTH_CHIPS];
d_ca_code[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 1] = d_ca_code[1];
d_carrier_lock_fail_counter = 0;
d_Prompt_prev = 0;
d_rem_code_phase_samples = 0;
d_rem_carr_phase = 0;
d_FLL_discriminator_hz = 0;
d_rem_code_phase_samples = 0;
d_acc_carrier_phase_rad = 0;
std::string sys_ = &d_acquisition_gnss_synchro->System;
sys = sys_.substr(0,1);
// DEBUG OUTPUT
std::cout << "Tracking start on channel " << d_channel << " for satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << std::endl;
LOG(INFO) << "Starting tracking of satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << " on channel " << d_channel;
// enable tracking Gnss_Satellite(systemName[&d_acquisition_gnss_synchro->System], d_acquisition_gnss_synchro->PRN)
d_pull_in = true;
d_enable_tracking = true;
LOG(INFO) << "PULL-IN Doppler [Hz]= " << d_carrier_doppler_hz
<< " Code Phase correction [samples]=" << delay_correction_samples
<< " PULL-IN Code Phase [samples]= " << d_acq_code_phase_samples << std::endl;
}
void galileo_e5a_dll_fll_pll_tracking_cc::update_local_code()
{
double tcode_chips;
double rem_code_phase_chips;
double code_phase_step_chips;
int early_late_spc_samples;
int epl_loop_length_samples;
int associated_chip_index;
int code_length_chips = (int)Galileo_E5a_CODE_LENGTH_CHIPS;
code_phase_step_chips = d_code_freq_hz / d_fs_in;
rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_hz / d_fs_in);
// unified loop for E, P, L code vectors
tcode_chips = -rem_code_phase_chips;
// Alternative EPL code generation (40% of speed improvement!)
early_late_spc_samples = round(d_early_late_spc_chips/code_phase_step_chips);
epl_loop_length_samples = d_current_prn_length_samples + early_late_spc_samples*2;
for (int i = 0; i < epl_loop_length_samples; i++)
{
associated_chip_index = 1 + round(fmod(tcode_chips - d_early_late_spc_chips, code_length_chips));
d_early_code[i] = d_ca_code[associated_chip_index];
tcode_chips = tcode_chips + code_phase_step_chips;
}
memcpy(d_prompt_code,&d_early_code[early_late_spc_samples],d_current_prn_length_samples* sizeof(gr_complex));
memcpy(d_late_code,&d_early_code[early_late_spc_samples*2],d_current_prn_length_samples* sizeof(gr_complex));
// for (int i=0; i<d_current_prn_length_samples; i++)
// {
// associated_chip_index = 1 + round(fmod(tcode_chips - d_early_late_spc_chips, code_length_chips));
// d_early_code[i] = d_ca_code[associated_chip_index];
// associated_chip_index = 1 + round(fmod(tcode_chips, code_length_chips));
// d_prompt_code[i] = d_ca_code[associated_chip_index];
// associated_chip_index = 1 + round(fmod(tcode_chips + d_early_late_spc_chips, code_length_chips));
// d_late_code[i] = d_ca_code[associated_chip_index];
// tcode_chips = tcode_chips + code_phase_step_chips;
// }
}
void galileo_e5a_dll_fll_pll_tracking_cc::update_local_carrier()
{
double phase, phase_step;
phase_step = 2*GALILEO_PI * d_carrier_doppler_hz / d_fs_in;
phase = d_rem_carr_phase;
for(int i = 0; i < d_current_prn_length_samples; i++)
{
d_carr_sign[i] = gr_complex(cos(phase), -sin(phase));
phase += phase_step;
}
d_rem_carr_phase = fmod(phase, 2*GALILEO_PI);
d_acc_carrier_phase_rad = d_acc_carrier_phase_rad + phase;
}
galileo_e5a_dll_fll_pll_tracking_cc::~galileo_e5a_dll_fll_pll_tracking_cc()
{
d_dump_file.close();
delete[] d_ca_code;
free(d_prompt_code);
free(d_late_code);
free(d_early_code);
free(d_carr_sign);
free(d_Early);
free(d_Prompt);
free(d_Late);
delete[] d_Prompt_buffer;
}
int galileo_e5a_dll_fll_pll_tracking_cc::general_work (int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
{
double code_error_chips = 0;
double code_error_filt_chips = 0;
double correlation_time_s = 0;
double PLL_discriminator_hz = 0;
double carr_nco_hz = 0;
// get the sample in and out pointers
const gr_complex* in = (gr_complex*) input_items[0]; // block input samples pointer
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; // block output streams pointer
d_Prompt_prev = *d_Prompt; // for the FLL discriminator
if (d_enable_tracking == true)
{
// GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder
Gnss_Synchro current_synchro_data;
// Fill the acquisition data
current_synchro_data = *d_acquisition_gnss_synchro;
/*
* Receiver signal alignment
*/
if (d_pull_in == true)
{
int samples_offset;
double acq_trk_shif_correction_samples;
int acq_to_trk_delay_samples;
acq_to_trk_delay_samples = d_sample_counter-d_acq_sample_stamp;
acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod((double)acq_to_trk_delay_samples, (double)d_current_prn_length_samples);
samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples);
// /todo: Check if the sample counter sent to the next block as a time reference should be incremented AFTER sended or BEFORE
d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples
d_pull_in = false;
consume_each(samples_offset); //shift input to perform alignment with local replica
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
*out[0] = current_synchro_data;
return 1;
}
update_local_code();
update_local_carrier();
// perform Early, Prompt and Late correlation
d_correlator.Carrier_wipeoff_and_EPL_volk(d_current_prn_length_samples,
in,
d_carr_sign,
d_early_code,
d_prompt_code,
d_late_code,
d_Early,
d_Prompt,
d_Late,
is_unaligned());
// check for samples consistency (this should be done before in the receiver / here only if the source is a file)
if (isnan((*d_Prompt).real()) == true or isnan((*d_Prompt).imag()) == true )// or std::isinf(in[i].real())==true or std::isinf(in[i].imag())==true)
{
const int samples_available = ninput_items[0];
d_sample_counter = d_sample_counter + samples_available;
LOG(WARNING) << "Detected NaN samples at sample number " << d_sample_counter;
consume_each(samples_available);
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
*out[0] =current_synchro_data;
return 1;
}
/*
* DLL, FLL, and PLL discriminators
*/
// Compute DLL error
code_error_chips = dll_nc_e_minus_l_normalized(*d_Early, *d_Late);
// Compute DLL filtered error
code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips);
//compute FLL error
correlation_time_s = ((double)d_current_prn_length_samples) / d_fs_in;
if (d_FLL_wait == 1)
{
d_Prompt_prev = *d_Prompt;
d_FLL_wait = 0;
}
else
{
d_FLL_discriminator_hz = fll_four_quadrant_atan(d_Prompt_prev, *d_Prompt, 0, correlation_time_s) / GPS_TWO_PI;
d_Prompt_prev = *d_Prompt;
d_FLL_wait = 1;
}
// Compute PLL error
PLL_discriminator_hz = pll_cloop_two_quadrant_atan(*d_Prompt) / GPS_TWO_PI;
/*
* DLL and FLL+PLL filter and get current carrier Doppler and code frequency
*/
carr_nco_hz = d_carrier_loop_filter.get_carrier_error(d_FLL_discriminator_hz, PLL_discriminator_hz, correlation_time_s);
d_carrier_doppler_hz = d_if_freq + carr_nco_hz;
d_code_freq_hz = Galileo_E5a_CODE_CHIP_RATE_HZ + (((d_carrier_doppler_hz + d_if_freq) * Galileo_E5a_CODE_CHIP_RATE_HZ) / Galileo_E5a_FREQ_HZ);
/*!
* \todo Improve the lock detection algorithm!
*/
// ####### CN0 ESTIMATION AND LOCK DETECTORS ######
if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES)
{
// fill buffer with prompt correlator output values
d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt;
d_cn0_estimation_counter++;
}
else
{
d_cn0_estimation_counter = 0;
//d_CN0_SNV_dB_Hz = gps_l1_ca_CN0_SNV(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in);
d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, Galileo_E5a_CODE_LENGTH_CHIPS);
d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES);
// ###### TRACKING UNLOCK NOTIFICATION #####
if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0)
{
d_carrier_lock_fail_counter++;
}
else
{
if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--;
}
if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER)
{
std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl;
LOG(INFO) << "Loss of lock in channel " << d_channel << "!";
ControlMessageFactory* cmf = new ControlMessageFactory();
if (d_queue != gr::msg_queue::sptr())
{
d_queue->handle(cmf->GetQueueMessage(d_channel, 2));
}
delete cmf;
d_carrier_lock_fail_counter = 0;
d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine
}
}
// ########## DEBUG OUTPUT
/*!
* \todo The stop timer has to be moved to the signal source!
*/
// debug: Second counter in channel 0
if (d_channel == 0)
{
if (floor(d_sample_counter/d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter/d_fs_in);
std::cout << "Current input signal time = " << d_last_seg << " [s]" << std::endl;
LOG(INFO) << "Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]";
}
}
else
{
if (floor(d_sample_counter/d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter/d_fs_in);
LOG(INFO) << "Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN) << ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]";
}
}
//predict the next loop PRN period length prediction
double T_chip_seconds;
double T_prn_seconds;
double T_prn_samples;
double K_blk_samples;
T_chip_seconds = 1/d_code_freq_hz;
T_prn_seconds = T_chip_seconds * Galileo_E5a_CODE_LENGTH_CHIPS;
T_prn_samples = T_prn_seconds * d_fs_in;
float code_error_filt_samples;
code_error_filt_samples = T_prn_seconds*code_error_filt_chips*T_chip_seconds*(float)d_fs_in; //[seconds]
d_acc_code_phase_samples = d_acc_code_phase_samples + code_error_filt_samples;
K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_samples;
d_current_prn_length_samples = round(K_blk_samples); //round to a discrete sample
d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error
// ########### Output the tracking data to navigation and PVT ##########
current_synchro_data.Prompt_I = (double)(*d_Prompt).real();
current_synchro_data.Prompt_Q = (double)(*d_Prompt).imag();
// Tracking_timestamp_secs is aligned with the PRN start sample
current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_current_prn_length_samples + d_rem_code_phase_samples)/d_fs_in;
// This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, Code_phase_secs=0
current_synchro_data.Code_phase_secs = 0;
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_tracking = true;
*out[0] = current_synchro_data;
}
else
{
// ########## DEBUG OUTPUT (TIME ONLY for channel 0 when tracking is disabled)
/*!
* \todo The stop timer has to be moved to the signal source!
*/
// stream to collect cout calls to improve thread safety
std::stringstream tmp_str_stream;
if (floor(d_sample_counter / d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter / d_fs_in);
if (d_channel == 0)
{
// debug: Second counter in channel 0
tmp_str_stream << "Current input signal time = " << d_last_seg << " [s]" << std::endl << std::flush;
std::cout << tmp_str_stream.rdbuf() << std::flush;
}
}
*d_Early = gr_complex(0,0);
*d_Prompt = gr_complex(0,0);
*d_Late = gr_complex(0,0);
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; //block output streams pointer
*out[0] = *d_acquisition_gnss_synchro;
}
if(d_dump)
{
// MULTIPLEXED FILE RECORDING - Record results to file
float prompt_I;
float prompt_Q;
float tmp_E, tmp_P, tmp_L;
float tmp_float;
double tmp_double;
prompt_I = (*d_Prompt).real();
prompt_Q = (*d_Prompt).imag();
tmp_E = std::abs<float>(*d_Early);
tmp_P = std::abs<float>(*d_Prompt);
tmp_L = std::abs<float>(*d_Late);
try
{
// EPR
d_dump_file.write((char*)&tmp_E, sizeof(float));
d_dump_file.write((char*)&tmp_P, sizeof(float));
d_dump_file.write((char*)&tmp_L, sizeof(float));
// PROMPT I and Q (to analyze navigation symbols)
d_dump_file.write((char*)&prompt_I, sizeof(float));
d_dump_file.write((char*)&prompt_Q, sizeof(float));
// PRN start sample stamp
d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int));
// accumulated carrier phase
tmp_float = (float)d_acc_carrier_phase_rad;
d_dump_file.write((char*)&tmp_float, sizeof(float));
// carrier and code frequency
tmp_float = (float)d_carrier_doppler_hz;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_float = (float)d_code_freq_hz;
d_dump_file.write((char*)&tmp_float, sizeof(float));
//PLL commands
tmp_float = (float)PLL_discriminator_hz;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_float = (float)carr_nco_hz;
d_dump_file.write((char*)&tmp_float, sizeof(float));
//DLL commands
tmp_float = (float)code_error_chips;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_float = (float)code_error_filt_chips;
d_dump_file.write((char*)&tmp_float, sizeof(float));
// CN0 and carrier lock test
tmp_float = (float)d_CN0_SNV_dB_Hz;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_float = (float)d_carrier_lock_test;
d_dump_file.write((char*)&tmp_float, sizeof(float));
// AUX vars (for debug purposes)
tmp_float = (float)d_rem_code_phase_samples;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_double = (double)(d_sample_counter + d_current_prn_length_samples);
d_dump_file.write((char*)&tmp_double, sizeof(double));
}
catch (std::ifstream::failure e)
{
LOG(INFO) << "Exception writing trk dump file "<< e.what() << std::endl;
}
}
consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates
d_sample_counter += d_current_prn_length_samples; //count for the processed samples
return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false
}
void galileo_e5a_dll_fll_pll_tracking_cc::set_channel(unsigned int channel)
{
d_channel = channel;
LOG(INFO) << "Tracking Channel set to " << d_channel;
// ############# ENABLE DATA FILE LOG #################
if (d_dump == true)
{
if (d_dump_file.is_open() == false)
{
try
{
d_dump_filename.append(boost::lexical_cast<std::string>(d_channel));
d_dump_filename.append(".dat");
d_dump_file.exceptions ( std::ifstream::failbit | std::ifstream::badbit );
d_dump_file.open(d_dump_filename.c_str(), std::ios::out | std::ios::binary);
LOG(INFO) << "Tracking dump enabled on channel " << d_channel << " Log file: " << d_dump_filename.c_str();
}
catch (std::ifstream::failure e)
{
LOG(WARNING) << "channel " << d_channel << " Exception opening trk dump file " << e.what();
}
}
}
}
void galileo_e5a_dll_fll_pll_tracking_cc::set_channel_queue(concurrent_queue<int> *channel_internal_queue)
{
d_channel_internal_queue = channel_internal_queue;
}
void galileo_e5a_dll_fll_pll_tracking_cc::set_gnss_synchro(Gnss_Synchro* p_gnss_synchro)
{
d_acquisition_gnss_synchro=p_gnss_synchro;
}

View File

@ -1,206 +0,0 @@
/*!
* \file galileo_e5a_dll_fll_pll_tracking_cc.h
* \brief Implementation of a code DLL + carrier PLL aided with FLL
* tracking block for Galileo E5a signals
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_CC_H_
#define GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_CC_H_
#include <fstream>
#include <queue>
#include <map>
#include <string>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
#include "concurrent_queue.h"
#include "galileo_e5_signal_processing.h"
#include "tracking_FLL_PLL_filter.h"
#include "tracking_2nd_DLL_filter.h"
#include "gnss_synchro.h"
#include "correlator.h"
class galileo_e5a_dll_fll_pll_tracking_cc;
typedef boost::shared_ptr<galileo_e5a_dll_fll_pll_tracking_cc>
galileo_e5a_dll_fll_pll_tracking_cc_sptr;
galileo_e5a_dll_fll_pll_tracking_cc_sptr
galileo_e5a_dll_fll_pll_make_tracking_cc(
long if_freq,
long fs_in,
unsigned int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump,
std::string dump_filename,
int order,
float fll_bw_hz,
float pll_bw_hz,
float dll_bw_hz,
float early_late_space_chips);
/*!
* \brief This class implements a DLL and a FLL assisted PLL tracking loop block
*/
class galileo_e5a_dll_fll_pll_tracking_cc: public gr::block
{
public:
~galileo_e5a_dll_fll_pll_tracking_cc();
void set_channel(unsigned int channel);
void start_tracking();
void update_local_code();
void update_local_carrier();
void set_FLL_and_PLL_BW(float fll_bw_hz,float pll_bw_hz);
/*
* \brief Satellite signal synchronization parameters uses shared memory between acquisition and tracking
*/
void set_gnss_synchro(Gnss_Synchro* p_gnss_synchro);
void set_channel_queue(concurrent_queue<int> *channel_internal_queue);
/*
* \brief just like gr_block::general_work, only this arranges to call consume_each for you
*
* The user must override work to define the signal processing code
*/
int general_work (int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items);
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
private:
friend galileo_e5a_dll_fll_pll_tracking_cc_sptr
galileo_e5a_dll_fll_pll_make_tracking_cc(
long if_freq,
long fs_in, unsigned
int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump,
std::string dump_filename,
int order,
float fll_bw_hz,
float pll_bw_hz,
float dll_bw_hz,
float early_late_space_chips);
galileo_e5a_dll_fll_pll_tracking_cc(
long if_freq,
long fs_in, unsigned
int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump,
std::string dump_filename,
int order,
float fll_bw_hz,
float pll_bw_hz,
float dll_bw_hz,
float early_late_space_chips);
void CN0_estimation_and_lock_detectors();
// class private vars
Gnss_Synchro *d_acquisition_gnss_synchro;
boost::shared_ptr<gr::msg_queue> d_queue;
concurrent_queue<int> *d_channel_internal_queue;
unsigned int d_vector_length;
bool d_dump;
unsigned int d_channel;
int d_last_seg;
double d_if_freq;
double d_fs_in;
//int d_sampled_codeLength;
gr_complex* d_ca_code;
gr_complex* d_early_code;
gr_complex* d_late_code;
gr_complex* d_prompt_code;
gr_complex* d_carr_sign;
gr_complex* d_Early;
gr_complex* d_Prompt;
gr_complex* d_Late;
gr_complex d_Prompt_prev;
double d_early_late_spc_chips;
double d_carrier_doppler_hz;
double d_code_freq_hz;
double d_code_phase_samples;
int d_current_prn_length_samples;
//int d_next_prn_length_samples;
int d_FLL_wait;
double d_rem_carr_phase;
double d_rem_code_phase_samples;
//double d_next_rem_code_phase_samples;
bool d_pull_in;
// acquisition
double d_acq_code_phase_samples;
double d_acq_carrier_doppler_hz;
// correlator
Correlator d_correlator;
// FLL + PLL filter
double d_FLL_discriminator_hz; // This is a class variable because FLL needs to have memory
Tracking_FLL_PLL_filter d_carrier_loop_filter;
double d_acc_carrier_phase_rad;
double d_acc_code_phase_samples;
Tracking_2nd_DLL_filter d_code_loop_filter;
unsigned long int d_sample_counter;
unsigned long int d_acq_sample_stamp;
// CN0 estimation and lock detector
int d_cn0_estimation_counter;
gr_complex* d_Prompt_buffer;
double d_carrier_lock_test;
double d_CN0_SNV_dB_Hz;
double d_carrier_lock_threshold;
int d_carrier_lock_fail_counter;
bool d_enable_tracking;
std::string d_dump_filename;
std::ofstream d_dump_file;
std::map<std::string, std::string> systemName;
std::string sys;
};
#endif /* GNSS_SDR_GALILEO_E5A_DLL_FLL_PLL_TRACKING_CC_H_ */

View File

@ -48,8 +48,7 @@
/*!
* \todo Include in definition header file
*/
//#define CN0_ESTIMATION_SAMPLES 20
#define CN0_ESTIMATION_SAMPLES 80
#define CN0_ESTIMATION_SAMPLES 20
#define MINIMUM_VALID_CN0 25
#define MAXIMUM_LOCK_FAIL_COUNTER 50
#define CARRIER_LOCK_THRESHOLD 0.85
@ -67,10 +66,13 @@ galileo_e5a_dll_pll_make_tracking_cc(
std::string dump_filename,
float pll_bw_hz,
float dll_bw_hz,
float pll_bw_init_hz,
float dll_bw_init_hz,
int ti_ms,
float early_late_space_chips)
{
return galileo_e5a_dll_pll_tracking_cc_sptr(new Galileo_E5a_Dll_Pll_Tracking_cc(if_freq,
fs_in, vector_length, queue, dump, dump_filename, pll_bw_hz, dll_bw_hz, early_late_space_chips));
fs_in, vector_length, queue, dump, dump_filename, pll_bw_hz, dll_bw_hz,pll_bw_init_hz, dll_bw_init_hz, ti_ms, early_late_space_chips));
}
@ -90,6 +92,9 @@ Galileo_E5a_Dll_Pll_Tracking_cc::Galileo_E5a_Dll_Pll_Tracking_cc(
std::string dump_filename,
float pll_bw_hz,
float dll_bw_hz,
float pll_bw_init_hz,
float dll_bw_init_hz,
int ti_ms,
float early_late_space_chips) :
gr::block("Galileo_E5a_Dll_Pll_Tracking_cc", gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)))
@ -104,17 +109,24 @@ Galileo_E5a_Dll_Pll_Tracking_cc::Galileo_E5a_Dll_Pll_Tracking_cc(
d_dump_filename = dump_filename;
d_code_loop_filter = Tracking_2nd_DLL_filter(GALILEO_E5a_CODE_PERIOD);
d_carrier_loop_filter = Tracking_2nd_PLL_filter(GALILEO_E5a_CODE_PERIOD);
d_current_ti_ms = 1; // initializes with 1ms of integration time until secondary code lock
d_ti_ms = ti_ms;
d_dll_bw_hz = dll_bw_hz;
d_pll_bw_hz = pll_bw_hz;
d_dll_bw_init_hz = dll_bw_init_hz;
d_pll_bw_init_hz = pll_bw_init_hz;
// Initialize tracking ==========================================
d_code_loop_filter.set_DLL_BW(dll_bw_hz);
d_carrier_loop_filter.set_PLL_BW(pll_bw_hz);
d_code_loop_filter.set_DLL_BW(d_dll_bw_init_hz);
d_carrier_loop_filter.set_PLL_BW(d_pll_bw_init_hz);
//--- DLL variables --------------------------------------------------------
d_early_late_spc_chips = early_late_space_chips; // Define early-late offset (in chips)
// Initialization of local code replica
// Get space for a vector with the E5a primary complex code replica sampled 1x/chip
d_code = new gr_complex[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 2];
// Get space for a vector with the E5a primary code replicas sampled 1x/chip
d_codeQ = new gr_complex[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 2];
d_codeI = new gr_complex[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 2];
/* If an array is partitioned for more than one thread to operate on,
* having the sub-array boundaries unaligned to cache lines could lead
@ -126,11 +138,16 @@ Galileo_E5a_Dll_Pll_Tracking_cc::Galileo_E5a_Dll_Pll_Tracking_cc(
if (posix_memalign((void**)&d_early_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_late_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_prompt_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_prompt_data_code, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
// space for carrier wipeoff and signal baseband vectors
if (posix_memalign((void**)&d_carr_sign, 16, d_vector_length * sizeof(gr_complex) * 2) == 0){};
if (posix_memalign((void**)&d_Early, 16, sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_Prompt, 16, sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_Late, 16, sizeof(gr_complex)) == 0){};
// if (posix_memalign((void**)&d_Prompt_data, 16, sizeof(gr_complex)*MAX_INTEGRATION_TIME_MS) == 0){};
if (posix_memalign((void**)&d_Prompt_data, 16, sizeof(gr_complex)) == 0){};
// space for buffer, notice max Ti+1 to ensure enough space since code samples is doppler dependant.
// if (posix_memalign((void**)&d_inbuffer, 16, (MAX_INTEGRATION_TIME_MS+1)*d_vector_length*sizeof(gr_complex)) == 0){};
//--- Perform initializations ------------------------------
// define initial code frequency basis of NCO
@ -140,17 +157,23 @@ Galileo_E5a_Dll_Pll_Tracking_cc::Galileo_E5a_Dll_Pll_Tracking_cc(
// define residual carrier phase
d_rem_carr_phase_rad = 0.0;
//Filter error vars
d_code_error_filt_secs = 0.0;
// sample synchronization
d_sample_counter = 0;
//d_sample_counter_seconds = 0;
d_acq_sample_stamp = 0;
d_enable_tracking = false;
d_pull_in = false;
//d_enable_tracking = false;
//d_pull_in = false;
d_last_seg = 0;
d_first_transition = false;
d_secondary_lock=false;
d_secondary_delay=0;
d_integration_counter = 0;
// d_buffer_counter = 0;
d_current_prn_length_samples = (int)d_vector_length;
@ -178,11 +201,9 @@ Galileo_E5a_Dll_Pll_Tracking_cc::~Galileo_E5a_Dll_Pll_Tracking_cc ()
free(d_late_code);
free(d_early_code);
free(d_carr_sign);
free(d_Early);
free(d_Prompt);
free(d_Late);
delete[] d_code;
delete[] d_codeQ;
delete[] d_codeI;
delete[] d_Prompt_buffer;
}
@ -238,12 +259,16 @@ void Galileo_E5a_Dll_Pll_Tracking_cc::start_tracking()
d_code_loop_filter.initialize(); // initialize the code filter
// generate local reference ALWAYS starting at chip 1 (1 sample per chip)
char sig_pilot[3];
strcpy(sig_pilot,"5Q");
galileo_e5_a_code_gen_complex_primary(&d_code[1], d_acquisition_gnss_synchro->PRN, sig_pilot);
char sig[3];
strcpy(sig,"5Q");
galileo_e5_a_code_gen_complex_primary(&d_codeQ[1], d_acquisition_gnss_synchro->PRN, sig);
d_codeQ[0] = d_codeQ[(int)Galileo_E5a_CODE_LENGTH_CHIPS];
d_codeQ[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 1] = d_codeQ[1];
d_code[0] = d_code[(int)Galileo_E5a_CODE_LENGTH_CHIPS];
d_code[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 1] = d_code[1];
strcpy(sig,"5I");
galileo_e5_a_code_gen_complex_primary(&d_codeI[1], d_acquisition_gnss_synchro->PRN, sig);
d_codeI[0] = d_codeI[(int)Galileo_E5a_CODE_LENGTH_CHIPS];
d_codeI[(int)Galileo_E5a_CODE_LENGTH_CHIPS + 1] = d_codeI[1];
d_carrier_lock_fail_counter = 0;
d_rem_code_phase_samples = 0;
@ -262,19 +287,15 @@ void Galileo_E5a_Dll_Pll_Tracking_cc::start_tracking()
// enable tracking
d_pull_in = true;
d_enable_tracking = true;
d_state = 1;
LOG(INFO) << "PULL-IN Doppler [Hz]=" << d_carrier_doppler_hz
<< " Code Phase correction [samples]=" << delay_correction_samples
<< " PULL-IN Code Phase [samples]=" << d_acq_code_phase_samples;
}
void Galileo_E5a_Dll_Pll_Tracking_cc::acquire_secondary()
{
//d_Prompt_buffer
//CN0_ESTIMATION_SAMPLES
//d_secondary_lock
//d_secondary_delay
// 1. Transform replica to 1 and -1
int sec_code_signed[Galileo_E5a_Q_SECONDARY_CODE_LENGTH];
for (unsigned int i=0; i<Galileo_E5a_Q_SECONDARY_CODE_LENGTH; i++)
@ -292,7 +313,6 @@ void Galileo_E5a_Dll_Pll_Tracking_cc::acquire_secondary()
int in_corr[CN0_ESTIMATION_SAMPLES];
for (unsigned int i=0; i<CN0_ESTIMATION_SAMPLES; i++)
{
std::cout << d_Prompt_buffer[i] << std::endl;
if (d_Prompt_buffer[i].real() >0)
{
in_corr[i]=1;
@ -313,32 +333,25 @@ void Galileo_E5a_Dll_Pll_Tracking_cc::acquire_secondary()
//reverse replica sign since i*i=-1 (conjugated complex)
out_corr += in_corr[j] * -sec_code_signed[(j+i)%Galileo_E5a_Q_SECONDARY_CODE_LENGTH];
}
// VOLK function uses floats, possibly slower
// if (is_unaligned())
// {
// volk_32f_x2_dot_prod_32f_u();
// }
// else
// {
// volk_32f_x2_dot_prod_32f_a();
// }
if (abs(out_corr) > current_best_)
{
current_best_ = abs(out_corr);
d_secondary_delay=i;
}
}
//if (current_best_ > SECONDARY_THRESHOLD)
if (current_best_ >= 0.8*CN0_ESTIMATION_SAMPLES)
if (current_best_ == CN0_ESTIMATION_SAMPLES) // all bits correlate
{
d_secondary_lock = true;
d_secondary_delay = (d_secondary_delay+CN0_ESTIMATION_SAMPLES-1)%Galileo_E5a_Q_SECONDARY_CODE_LENGTH;
}
}
void Galileo_E5a_Dll_Pll_Tracking_cc::update_local_code()
{
double tcode_chips;
double rem_code_phase_chips;
int associated_chip_index;
int associated_chip_index_data;
int code_length_chips = (int)Galileo_E5a_CODE_LENGTH_CHIPS;
double code_phase_step_chips;
int early_late_spc_samples;
@ -348,32 +361,24 @@ void Galileo_E5a_Dll_Pll_Tracking_cc::update_local_code()
code_phase_step_chips = ((double)d_code_freq_chips) / ((double)d_fs_in);
rem_code_phase_chips = d_rem_code_phase_samples * (d_code_freq_chips / d_fs_in);
tcode_chips = -rem_code_phase_chips;
// SPACING USING QUADRATURE COMPONENT as 0.5 CHIP
double corr_spc_samples = d_early_late_spc_chips / code_phase_step_chips;
// CONVENTIONAL
// Alternative EPL code generation (40% of speed improvement!)
early_late_spc_samples = round(d_early_late_spc_chips / code_phase_step_chips);
epl_loop_length_samples = d_current_prn_length_samples + early_late_spc_samples*2;
for (int i = 0; i < epl_loop_length_samples; i++)
{
associated_chip_index = 1 + round(fmod(tcode_chips - d_early_late_spc_chips, code_length_chips));
d_early_code[i] = d_code[associated_chip_index];
associated_chip_index_data = 1 + round(fmod(tcode_chips, code_length_chips));
d_early_code[i] = d_codeQ[associated_chip_index];
d_prompt_data_code[i] = d_codeI[associated_chip_index_data];
tcode_chips = tcode_chips + code_phase_step_chips;
}
memcpy(d_prompt_code,&d_early_code[early_late_spc_samples],d_current_prn_length_samples* sizeof(gr_complex));
memcpy(d_late_code,&d_early_code[early_late_spc_samples*2],d_current_prn_length_samples* sizeof(gr_complex));
//EXPERIMENTAL
}
void Galileo_E5a_Dll_Pll_Tracking_cc::update_local_carrier()
{
float phase_rad, phase_step_rad;
@ -395,243 +400,347 @@ int Galileo_E5a_Dll_Pll_Tracking_cc::general_work (int noutput_items, gr_vector_
float carr_error_filt_hz;
float code_error_chips;
float code_error_filt_chips;
// GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; //block output streams pointer
if (d_enable_tracking == true)
{
if (d_secondary_lock==false)
{
// Receiver signal alignment
if (d_pull_in == true)
{
int samples_offset;
float acq_trk_shif_correction_samples;
int acq_to_trk_delay_samples;
acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp;
acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod((float)acq_to_trk_delay_samples, (float)d_current_prn_length_samples);
samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples);
// /todo: Check if the sample counter sent to the next block as a time reference should be incremented AFTER sended or BEFORE
//d_sample_counter_seconds = d_sample_counter_seconds + (((double)samples_offset) / (double)d_fs_in);
d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples
d_pull_in = false;
std::cout<<" samples_offset="<<samples_offset<<"\r\n";
consume_each(samples_offset); //shift input to perform alignment with local replica
return 1;
}
// GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder
Gnss_Synchro current_synchro_data;
// Fill the acquisition data
current_synchro_data = *d_acquisition_gnss_synchro;
// GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder
Gnss_Synchro current_synchro_data;
// Fill the acquisition data
current_synchro_data = *d_acquisition_gnss_synchro;
/* States: 0 Tracking not enabled
* 1 Pull-in of primary code (alignment).
* 3 Tracking algorithm. Correlates EPL each loop and accumulates the result
* until it reaches integration time.
*/
switch (d_state)
{
case 0:
{
// ########## DEBUG OUTPUT (TIME ONLY for channel 0 when tracking is disabled)
/*!
* \todo The stop timer has to be moved to the signal source!
*/
// stream to collect cout calls to improve thread safety
std::stringstream tmp_str_stream;
if (floor(d_sample_counter / d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter / d_fs_in);
// Block input data and block output stream pointers
const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0];
if (d_channel == 0)
{
// debug: Second counter in channel 0
tmp_str_stream << "Current input signal time = " << d_last_seg << " [s]" << std::endl << std::flush;
std::cout << tmp_str_stream.rdbuf() << std::flush;
}
}
d_Early = gr_complex(0,0);
d_Prompt = gr_complex(0,0);
d_Late = gr_complex(0,0);
d_Prompt_data = gr_complex(0,0);
// Generate local code and carrier replicas (using \hat{f}_d(k-1))
update_local_code();
update_local_carrier();
*out[0] = *d_acquisition_gnss_synchro;
// perform carrier wipe-off and compute Early, Prompt and Late correlation
d_correlator.Carrier_wipeoff_and_EPL_volk(d_current_prn_length_samples,
in,
d_carr_sign,
d_early_code,
d_prompt_code,
d_late_code,
d_Early,
d_Prompt,
d_Late,
is_unaligned());
break;
}
case 1:
{
int samples_offset;
float acq_trk_shif_correction_samples;
int acq_to_trk_delay_samples;
acq_to_trk_delay_samples = d_sample_counter - d_acq_sample_stamp;
acq_trk_shif_correction_samples = d_current_prn_length_samples - fmod((float)acq_to_trk_delay_samples, (float)d_current_prn_length_samples);
samples_offset = round(d_acq_code_phase_samples + acq_trk_shif_correction_samples);
// /todo: Check if the sample counter sent to the next block as a time reference should be incremented AFTER sended or BEFORE
d_sample_counter = d_sample_counter + samples_offset; //count for the processed samples
std::cout<<" samples_offset="<<samples_offset<<"\r\n";
d_state = 2; // start in Ti = 1 code, until secondary code lock.
// check for samples consistency (this should be done before in the receiver / here only if the source is a file)
if (std::isnan((*d_Prompt).real()) == true or std::isnan((*d_Prompt).imag()) == true ) // or std::isinf(in[i].real())==true or std::isinf(in[i].imag())==true)
{
const int samples_available = ninput_items[0];
d_sample_counter = d_sample_counter + samples_available;
LOG(WARNING) << "Detected NaN samples at sample number " << d_sample_counter;
consume_each(samples_available);
std::cout << "acq_code_phase" << d_acq_code_phase_samples << " d_sample_counter" << d_sample_counter << " d_acq_sample_stamp " << d_acq_sample_stamp << std::endl;
std::cout << "acq doppler " << d_acq_carrier_doppler_hz << std::endl;
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/(double)d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
*out[0] = current_synchro_data;
consume_each(samples_offset); //shift input to perform alignment with local replica
return 1;
}
case 2:
{
// Block input data and block output stream pointers
const gr_complex* in = (gr_complex*) input_items[0]; //PRN start block alignment
gr_complex sec_sign_Q;
gr_complex sec_sign_I;
// Secondary code Chip
if (d_secondary_lock)
{
sec_sign_Q = gr_complex((Galileo_E5a_Q_SECONDARY_CODE[d_acquisition_gnss_synchro->PRN-1].at(d_secondary_delay)=='0' ? 1 : -1),0);
sec_sign_I = gr_complex((Galileo_E5a_I_SECONDARY_CODE.at(d_secondary_delay%Galileo_E5a_I_SECONDARY_CODE_LENGTH))=='0' ? 1 : -1,0);
}
else
{
sec_sign_Q = gr_complex(1.0,0.0);
sec_sign_I = gr_complex(1.0,0.0);
}
// Reset integration counter
if (d_integration_counter == d_current_ti_ms)
{
d_integration_counter = 0;
}
//Generate local code and carrier replicas (using \hat{f}_d(k-1))
if (d_integration_counter == 0)
{
update_local_code();
update_local_carrier();
// Reset accumulated values
d_Early = gr_complex(0,0);
d_Prompt = gr_complex(0,0);
d_Late = gr_complex(0,0);
}
gr_complex single_early;
gr_complex single_prompt;
gr_complex single_late;
*out[0] = current_synchro_data;
// perform carrier wipe-off and compute Early, Prompt and Late
// correlation of 1 primary code
d_correlator.Carrier_wipeoff_and_EPL_volk_IQ(d_current_prn_length_samples,
in,
d_carr_sign,
d_early_code,
d_prompt_code,
d_late_code,
d_prompt_data_code,
&single_early,
&single_prompt,
&single_late,
&d_Prompt_data,
is_unaligned());
return 1;
}
// Accumulate results (coherent integration)
d_Early += single_early * sec_sign_Q;
d_Prompt += single_prompt * sec_sign_Q;
d_Late += single_late * sec_sign_Q;
d_Prompt_data *= sec_sign_I;
d_integration_counter++;
// ################## PLL ##########################################################
// PLL discriminator
carr_error_hz = pll_cloop_two_quadrant_atan(*d_Prompt) / (float)GALILEO_PI*2;
// Carrier discriminator filter
carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz);
// New carrier Doppler frequency estimation
d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz;
// New code Doppler frequency estimation
d_code_freq_chips = Galileo_E5a_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E5a_CODE_CHIP_RATE_HZ) / Galileo_E5a_FREQ_HZ);
//carrier phase accumulator for (K) doppler estimation
d_acc_carrier_phase_rad = d_acc_carrier_phase_rad + 2*GALILEO_PI*d_carrier_doppler_hz*GALILEO_E5a_CODE_PERIOD;
//remanent carrier phase to prevent overflow in the code NCO
d_rem_carr_phase_rad = d_rem_carr_phase_rad+2*GALILEO_PI*d_carrier_doppler_hz*GALILEO_E5a_CODE_PERIOD;
d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, 2*GALILEO_PI);
// check for samples consistency (this should be done before in the receiver / here only if the source is a file)
if (std::isnan((d_Prompt).real()) == true or std::isnan((d_Prompt).imag()) == true ) // or std::isinf(in[i].real())==true or std::isinf(in[i].imag())==true)
{
const int samples_available = ninput_items[0];
d_sample_counter = d_sample_counter + samples_available;
LOG(WARNING) << "Detected NaN samples at sample number " << d_sample_counter;
consume_each(samples_available);
// ################## DLL ##########################################################
// DLL discriminator
code_error_chips = dll_nc_e_minus_l_normalized(*d_Early, *d_Late); //[chips/Ti]
// Code discriminator filter
code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); //[chips/second]
//Code phase accumulator
float code_error_filt_secs;
code_error_filt_secs = (GALILEO_E5a_CODE_PERIOD*code_error_filt_chips)/Galileo_E5a_CODE_CHIP_RATE_HZ; //[seconds]
d_acc_code_phase_secs = d_acc_code_phase_secs + code_error_filt_secs;
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/(double)d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
std::cout<< "Early " << *d_Early << std::endl;
std::cout<< "Prompt " << *d_Prompt << std::endl;
std::cout<< "Late " << *d_Late << std::endl;
// ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT #######################
// keep alignment parameters for the next input buffer
float T_chip_seconds;
float T_prn_seconds;
float T_prn_samples;
float K_blk_samples;
// Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation
T_chip_seconds = 1 / d_code_freq_chips;
T_prn_seconds = T_chip_seconds * Galileo_E5a_CODE_LENGTH_CHIPS;
T_prn_samples = T_prn_seconds * (float)d_fs_in;
K_blk_samples = T_prn_samples + d_rem_code_phase_samples + code_error_filt_secs*(float)d_fs_in;
d_current_prn_length_samples = round(K_blk_samples); //round to a discrete samples
d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample
*out[0] = current_synchro_data;
// ####### CN0 ESTIMATION AND LOCK DETECTORS ######
if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES)
{
// fill buffer with prompt correlator output values
d_Prompt_buffer[d_cn0_estimation_counter] = *d_Prompt;
d_cn0_estimation_counter++;
}
else
{
// ATTEMPT SECONDARY CODE ACQUISITION
acquire_secondary(); // changes d_secondary_lock and d_secondary_delay
//
d_cn0_estimation_counter = 0;
// Code lock indicator
d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, Galileo_E5a_CODE_LENGTH_CHIPS);
// Carrier lock indicator
d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES);
// Loss of lock detection
if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0)
{
d_carrier_lock_fail_counter++;
}
else
{
if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--;
}
if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER)
{
std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl;
LOG(INFO) << "Loss of lock in channel " << d_channel << "!";
ControlMessageFactory* cmf = new ControlMessageFactory();
if (d_queue != gr::msg_queue::sptr())
{
d_queue->handle(cmf->GetQueueMessage(d_channel, 2));
}
delete cmf;
d_carrier_lock_fail_counter = 0;
d_enable_tracking = false; // TODO: check if disabling tracking is consistent with the channel state machine
}
}
return 1;
}
// ################## PLL ##########################################################
// PLL discriminator
if (d_integration_counter == d_current_ti_ms)
{
if (d_secondary_lock == true)
{
carr_error_hz = pll_four_quadrant_atan(d_Prompt) / (float)GALILEO_PI*2;
}
else
{
carr_error_hz = pll_cloop_two_quadrant_atan(d_Prompt) / (float)GALILEO_PI*2;
}
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/(double)d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
// Carrier discriminator filter
carr_error_filt_hz = d_carrier_loop_filter.get_carrier_nco(carr_error_hz);
// TEST
// carr_error_filt_hz = 0;
//
// New carrier Doppler frequency estimation
d_carrier_doppler_hz = d_acq_carrier_doppler_hz + carr_error_filt_hz;
// New code Doppler frequency estimation
d_code_freq_chips = Galileo_E5a_CODE_CHIP_RATE_HZ + ((d_carrier_doppler_hz * Galileo_E5a_CODE_CHIP_RATE_HZ) / Galileo_E5a_FREQ_HZ);
}
//carrier phase accumulator for (K) doppler estimation
d_acc_carrier_phase_rad = d_acc_carrier_phase_rad + 2*GALILEO_PI*d_carrier_doppler_hz*GALILEO_E5a_CODE_PERIOD;
//remanent carrier phase to prevent overflow in the code NCO
d_rem_carr_phase_rad = d_rem_carr_phase_rad+2*GALILEO_PI*d_carrier_doppler_hz*GALILEO_E5a_CODE_PERIOD;
d_rem_carr_phase_rad = fmod(d_rem_carr_phase_rad, 2*GALILEO_PI);
*out[0] = current_synchro_data;
// ################## DLL ##########################################################
if (d_integration_counter == d_current_ti_ms)
{
// DLL discriminator
code_error_chips = dll_nc_e_minus_l_normalized(d_Early, d_Late); //[chips/Ti]
// Code discriminator filter
code_error_filt_chips = d_code_loop_filter.get_code_nco(code_error_chips); //[chips/second]
// TEST
// code_error_filt_chips = 0;
//
//Code phase accumulator
d_code_error_filt_secs = (GALILEO_E5a_CODE_PERIOD*code_error_filt_chips)/Galileo_E5a_CODE_CHIP_RATE_HZ; //[seconds]
}
d_acc_code_phase_secs = d_acc_code_phase_secs + d_code_error_filt_secs;
// std::cout<< "Early " << d_Early << std::endl;
// std::cout<< "Prompt " << d_Prompt << std::endl;
// std::cout<< "Late " << d_Late << std::endl;
// std::cout<< "Prompt data " << d_Prompt_data << std::endl;
}
else
{
// code with known secondary chip delay
// ########### Output the tracking data to navigation and PVT ##########
/*
current_synchro_data.Prompt_I = (double)(*d_Prompt).real();
current_synchro_data.Prompt_Q = (double)(*d_Prompt).imag();
// Tracking_timestamp_secs is aligned with the PRN start sample
current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_current_prn_length_samples + (double)d_rem_code_phase_samples)/(double)d_fs_in;
// This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0
current_synchro_data.Code_phase_secs = 0;
current_synchro_data.Carrier_phase_rads = (double)d_acc_carrier_phase_rad;
current_synchro_data.Carrier_Doppler_hz = (double)d_carrier_doppler_hz;
current_synchro_data.CN0_dB_hz = (double)d_CN0_SNV_dB_Hz;
*out[0] = current_synchro_data;
*/
}
// ########## DEBUG OUTPUT
/*!
* \todo The stop timer has to be moved to the signal source!
*/
// debug: Second counter in channel 0
if (d_channel == 0)
{
if (floor(d_sample_counter / d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter / d_fs_in);
std::cout << "Current input signal time = " << d_last_seg << " [s]" << std::endl;
LOG(INFO) << "Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN)
<< ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]";
//if (d_last_seg==5) d_carrier_lock_fail_counter=500; //DEBUG: force unlock!
}
}
else
{
if (floor(d_sample_counter / d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter / d_fs_in);
LOG(INFO) << "Tracking CH " << d_channel << ": Satellite " << Gnss_Satellite(systemName[sys], d_acquisition_gnss_synchro->PRN)
<< ", CN0 = " << d_CN0_SNV_dB_Hz << " [dB-Hz]";
//std::cout<<"TRK CH "<<d_channel<<" Carrier_lock_test="<<d_carrier_lock_test<< std::endl;
}
}
}
else
{
// ########## DEBUG OUTPUT (TIME ONLY for channel 0 when tracking is disabled)
/*!
* \todo The stop timer has to be moved to the signal source!
*/
// stream to collect cout calls to improve thread safety
std::stringstream tmp_str_stream;
if (floor(d_sample_counter / d_fs_in) != d_last_seg)
{
d_last_seg = floor(d_sample_counter / d_fs_in);
// ################## CARRIER AND CODE NCO BUFFER ALIGNEMENT #######################
// keep alignment parameters for the next input buffer
double T_chip_seconds;
double T_prn_seconds;
float T_prn_samples;
float K_blk_samples;
//double T_chip_seconds;
// double T_prn_seconds;
// double T_prn_samples;
// double K_blk_samples;
// Compute the next buffer length based in the new period of the PRN sequence and the code phase error estimation
T_chip_seconds = 1 / (double)d_code_freq_chips;
T_prn_seconds = T_chip_seconds * Galileo_E5a_CODE_LENGTH_CHIPS;
T_prn_samples = T_prn_seconds * (float)d_fs_in;
K_blk_samples = T_prn_samples + d_rem_code_phase_samples + d_code_error_filt_secs*(float)d_fs_in;
d_current_prn_length_samples = round(K_blk_samples); //round to a discrete samples
d_rem_code_phase_samples = K_blk_samples - d_current_prn_length_samples; //rounding error < 1 sample
if (d_channel == 0)
{
// debug: Second counter in channel 0
tmp_str_stream << "Current input signal time = " << d_last_seg << " [s]" << std::endl << std::flush;
std::cout << tmp_str_stream.rdbuf() << std::flush;
}
}
*d_Early = gr_complex(0,0);
*d_Prompt = gr_complex(0,0);
*d_Late = gr_complex(0,0);
Gnss_Synchro **out = (Gnss_Synchro **) &output_items[0]; //block output streams pointer
// GNSS_SYNCHRO OBJECT to interchange data between tracking->telemetry_decoder
*out[0] = *d_acquisition_gnss_synchro;
}
// ####### CN0 ESTIMATION AND LOCK DETECTORS ######
if (d_cn0_estimation_counter < CN0_ESTIMATION_SAMPLES-1)
{
// fill buffer with prompt correlator output values
d_Prompt_buffer[d_cn0_estimation_counter] = d_Prompt;
d_cn0_estimation_counter++;
// d_cn0_estimation_counter += d_integration_t_ms;
}
else
{
d_Prompt_buffer[d_cn0_estimation_counter] = d_Prompt;
// ATTEMPT SECONDARY CODE ACQUISITION
if (d_secondary_lock == false)
{
acquire_secondary(); // changes d_secondary_lock and d_secondary_delay
if (d_secondary_lock == true)
{
// std::cout << "first prompt=" << d_Prompt_buffer[0] << std::endl;
std::cout << "Secondary code locked." << std::endl;
d_current_ti_ms = d_ti_ms;
d_integration_counter = 0;
// Change loop parameters ==========================================
d_code_loop_filter.set_pdi(d_current_ti_ms * GALILEO_E5a_CODE_PERIOD);
d_carrier_loop_filter.set_pdi(d_current_ti_ms * GALILEO_E5a_CODE_PERIOD);
d_code_loop_filter.initialize();
d_carrier_loop_filter.initialize();
d_code_loop_filter.set_DLL_BW(d_dll_bw_hz);
d_carrier_loop_filter.set_PLL_BW(d_pll_bw_hz);
consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates
d_secondary_delay = (d_secondary_delay + 1)%Galileo_E5a_Q_SECONDARY_CODE_LENGTH;
d_sample_counter += d_current_prn_length_samples; //count for the processed samples
return 1;
}
else
{
// std::cout << "first prompt=" << d_Prompt_buffer[0] << std::endl;
std::cout << "Secondary code delay couldn't be resolved." << std::endl;
d_carrier_lock_fail_counter++;
if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER)
{
std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl;
LOG(INFO) << "Loss of lock in channel " << d_channel << "!";
ControlMessageFactory* cmf = new ControlMessageFactory();
if (d_queue != gr::msg_queue::sptr())
{
d_queue->handle(cmf->GetQueueMessage(d_channel, 2));
}
delete cmf;
d_carrier_lock_fail_counter = 0;
d_state = 0; // TODO: check if disabling tracking is consistent with the channel state machine
}
}
}
else // Secondary lock achieved, monitor carrier lock.
{
// Code lock indicator
d_CN0_SNV_dB_Hz = cn0_svn_estimator(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES, d_fs_in, Galileo_E5a_CODE_LENGTH_CHIPS);
// Carrier lock indicator
d_carrier_lock_test = carrier_lock_detector(d_Prompt_buffer, CN0_ESTIMATION_SAMPLES);
// TODO: tune Time integration period and filter parameters according to CN0 levels
// Loss of lock detection
if (d_carrier_lock_test < d_carrier_lock_threshold or d_CN0_SNV_dB_Hz < MINIMUM_VALID_CN0)
{
d_carrier_lock_fail_counter++;
}
else
{
if (d_carrier_lock_fail_counter > 0) d_carrier_lock_fail_counter--;
if (d_carrier_lock_fail_counter > MAXIMUM_LOCK_FAIL_COUNTER)
{
std::cout << "Loss of lock in channel " << d_channel << "!" << std::endl;
LOG(INFO) << "Loss of lock in channel " << d_channel << "!";
ControlMessageFactory* cmf = new ControlMessageFactory();
if (d_queue != gr::msg_queue::sptr())
{
d_queue->handle(cmf->GetQueueMessage(d_channel, 2));
}
delete cmf;
d_carrier_lock_fail_counter = 0;
d_state = 0;
}
}
}
d_cn0_estimation_counter = 0;
}
if (d_secondary_lock && (d_secondary_delay%Galileo_E5a_I_SECONDARY_CODE_LENGTH)==0)
{
d_first_transition = true;
}
// ########### Output the tracking data to navigation and PVT ##########
// The first Prompt output not equal to 0 is synchronized with the transition of a navigation data bit.
if (d_secondary_lock && d_first_transition)
{
current_synchro_data.Prompt_I = (double)(d_Prompt_data.real());
current_synchro_data.Prompt_Q = (double)(d_Prompt_data.imag());
// Tracking_timestamp_secs is aligned with the PRN start sample
current_synchro_data.Tracking_timestamp_secs = ((double)d_sample_counter + (double)d_current_prn_length_samples + (double)d_rem_code_phase_samples)/(double)d_fs_in;
// This tracking block aligns the Tracking_timestamp_secs with the start sample of the PRN, thus, Code_phase_secs=0
current_synchro_data.Code_phase_secs = 0;
current_synchro_data.Carrier_phase_rads = (double)d_acc_carrier_phase_rad;
current_synchro_data.Carrier_Doppler_hz = (double)d_carrier_doppler_hz;
current_synchro_data.CN0_dB_hz = (double)d_CN0_SNV_dB_Hz;
}
else
{
// make an output to not stop the rest of the processing blocks
current_synchro_data.Prompt_I = 0.0;
current_synchro_data.Prompt_Q = 0.0;
current_synchro_data.Tracking_timestamp_secs = (double)d_sample_counter/d_fs_in;
current_synchro_data.Carrier_phase_rads = 0.0;
current_synchro_data.Code_phase_secs = 0.0;
current_synchro_data.CN0_dB_hz = 0.0;
current_synchro_data.Flag_valid_tracking = false;
}
*out[0] = current_synchro_data;
}
}
if(d_dump)
{
@ -641,55 +750,59 @@ int Galileo_E5a_Dll_Pll_Tracking_cc::general_work (int noutput_items, gr_vector_
float tmp_E, tmp_P, tmp_L;
float tmp_float;
double tmp_double;
prompt_I = (*d_Prompt).real();
prompt_Q = (*d_Prompt).imag();
tmp_E = std::abs<float>(*d_Early);
tmp_P = std::abs<float>(*d_Prompt);
tmp_L = std::abs<float>(*d_Late);
prompt_I = d_Prompt_data.real();
prompt_Q = d_Prompt_data.imag();
if (d_integration_counter == d_current_ti_ms)
{
tmp_E = std::abs<float>(d_Early);
tmp_P = std::abs<float>(d_Prompt);
tmp_L = std::abs<float>(d_Late);
}
try
{
// EPR
d_dump_file.write((char*)&tmp_E, sizeof(float));
d_dump_file.write((char*)&tmp_P, sizeof(float));
d_dump_file.write((char*)&tmp_L, sizeof(float));
// PROMPT I and Q (to analyze navigation symbols)
d_dump_file.write((char*)&prompt_I, sizeof(float));
d_dump_file.write((char*)&prompt_Q, sizeof(float));
// PRN start sample stamp
//tmp_float=(float)d_sample_counter;
d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int));
// accumulated carrier phase
d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float));
// EPR
d_dump_file.write((char*)&tmp_E, sizeof(float));
d_dump_file.write((char*)&tmp_P, sizeof(float));
d_dump_file.write((char*)&tmp_L, sizeof(float));
// PROMPT I and Q (to analyze navigation symbols)
//TODO: save all nav symbols, not only the first of the integration time.
d_dump_file.write((char*)&prompt_I, sizeof(float));
d_dump_file.write((char*)&prompt_Q, sizeof(float));
// PRN start sample stamp
d_dump_file.write((char*)&d_sample_counter, sizeof(unsigned long int));
// accumulated carrier phase
d_dump_file.write((char*)&d_acc_carrier_phase_rad, sizeof(float));
// carrier and code frequency
d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float));
d_dump_file.write((char*)&d_code_freq_chips, sizeof(float));
// carrier and code frequency
d_dump_file.write((char*)&d_carrier_doppler_hz, sizeof(float));
d_dump_file.write((char*)&d_code_freq_chips, sizeof(float));
//PLL commands
d_dump_file.write((char*)&carr_error_hz, sizeof(float));
d_dump_file.write((char*)&carr_error_filt_hz, sizeof(float));
//PLL commands
d_dump_file.write((char*)&carr_error_hz, sizeof(float));
d_dump_file.write((char*)&carr_error_filt_hz, sizeof(float));
//DLL commands
d_dump_file.write((char*)&code_error_chips, sizeof(float));
d_dump_file.write((char*)&code_error_filt_chips, sizeof(float));
//DLL commands
d_dump_file.write((char*)&code_error_chips, sizeof(float));
d_dump_file.write((char*)&code_error_filt_chips, sizeof(float));
// CN0 and carrier lock test
d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float));
d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float));
// CN0 and carrier lock test
d_dump_file.write((char*)&d_CN0_SNV_dB_Hz, sizeof(float));
d_dump_file.write((char*)&d_carrier_lock_test, sizeof(float));
// AUX vars (for debug purposes)
tmp_float = d_rem_code_phase_samples;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_double=(double)(d_sample_counter+d_current_prn_length_samples);
d_dump_file.write((char*)&tmp_double, sizeof(double));
// AUX vars (for debug purposes)
tmp_float = d_rem_code_phase_samples;
d_dump_file.write((char*)&tmp_float, sizeof(float));
tmp_double=(double)(d_sample_counter+d_current_prn_length_samples);
d_dump_file.write((char*)&tmp_double, sizeof(double));
}
catch (std::ifstream::failure e)
{
LOG(WARNING) << "Exception writing trk dump file " << e.what();
LOG(WARNING) << "Exception writing trk dump file " << e.what();
}
}
consume_each(d_current_prn_length_samples); // this is necessary in gr::block derivates
d_secondary_delay = (d_secondary_delay + 1)%Galileo_E5a_Q_SECONDARY_CODE_LENGTH;
d_sample_counter += d_current_prn_length_samples; //count for the processed samples
return 1; //output tracking result ALWAYS even in the case of d_enable_tracking==false
}

View File

@ -61,6 +61,9 @@ galileo_e5a_dll_pll_make_tracking_cc(long if_freq,
std::string dump_filename,
float pll_bw_hz,
float dll_bw_hz,
float pll_bw_init_hz,
float dll_bw_init_hz,
int ti_ms,
float early_late_space_chips);
@ -93,6 +96,9 @@ private:
std::string dump_filename,
float pll_bw_hz,
float dll_bw_hz,
float pll_bw_init_hz,
float dll_bw_init_hz,
int ti_ms,
float early_late_space_chips);
Galileo_E5a_Dll_Pll_Tracking_cc(long if_freq,
@ -103,6 +109,9 @@ private:
std::string dump_filename,
float pll_bw_hz,
float dll_bw_hz,
float pll_bw_init_hz,
float dll_bw_init_hz,
int ti_ms,
float early_late_space_chips);
void update_local_code();
void update_local_carrier();
@ -111,8 +120,11 @@ private:
boost::shared_ptr<gr::msg_queue> d_queue;
concurrent_queue<int> *d_channel_internal_queue;
unsigned int d_vector_length;
int d_current_ti_ms;
int d_ti_ms;
bool d_dump;
Gnss_Synchro* d_acquisition_gnss_synchro;
unsigned int d_channel;
int d_last_seg;
@ -120,17 +132,25 @@ private:
long d_fs_in;
double d_early_late_spc_chips;
float d_dll_bw_hz;
float d_pll_bw_hz;
float d_dll_bw_init_hz;
float d_pll_bw_init_hz;
gr_complex* d_code;
gr_complex* d_codeQ;
gr_complex* d_codeI;
gr_complex* d_early_code;
gr_complex* d_late_code;
gr_complex* d_prompt_code;
gr_complex* d_prompt_data_code;
gr_complex* d_carr_sign;
gr_complex *d_Early;
gr_complex *d_Prompt;
gr_complex *d_Late;
gr_complex d_Early;
gr_complex d_Prompt;
gr_complex d_Late;
gr_complex d_Prompt_data;
// remaining code phase and carrier phase between tracking loops
float d_rem_code_phase_samples;
@ -152,6 +172,7 @@ private:
float d_acc_carrier_phase_rad;
float d_code_phase_samples;
float d_acc_code_phase_secs;
float d_code_error_filt_secs;
//PRN period in samples
int d_current_prn_length_samples;
@ -169,12 +190,13 @@ private:
int d_carrier_lock_fail_counter;
// control vars
bool d_enable_tracking;
bool d_pull_in;
int d_state;
bool d_first_transition;
// Secondary code acquisition
bool d_secondary_lock;
int d_secondary_delay;
unsigned int d_integration_counter;
// file dump
std::string d_dump_filename;

View File

@ -113,6 +113,80 @@ void Correlator::Carrier_wipeoff_and_EPL_volk(int signal_length_samples, const g
//}
}
//void Correlator::Carrier_wipeoff_and_EPL_volk_IQ(int prn_length_samples,int integration_time ,const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* P_data_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, gr_complex* P_data_out, bool input_vector_unaligned)
//{
// gr_complex* bb_signal;
// //gr_complex* input_aligned;
//
// //todo: do something if posix_memalign fails
// if (posix_memalign((void**)&bb_signal, 16, integration_time * prn_length_samples * sizeof(gr_complex)) == 0) {};
//
// if (input_vector_unaligned == true)
// {
// //todo: do something if posix_memalign fails
// //if (posix_memalign((void**)&input_aligned, 16, signal_length_samples * sizeof(gr_complex)) == 0){};
// //memcpy(input_aligned,input,signal_length_samples * sizeof(gr_complex));
//
// volk_32fc_x2_multiply_32fc_u(bb_signal, input, carrier, integration_time * prn_length_samples);
// }
// else
// {
// /*
// * todo: There is a problem with the aligned version of volk_32fc_x2_multiply_32fc_a.
// * It crashes even if the is_aligned() work function returns true. Im keeping the unaligned version in both cases..
// */
// //use directly the input vector
// volk_32fc_x2_multiply_32fc_u(bb_signal, input, carrier, integration_time * prn_length_samples);
// }
//
// volk_32fc_x2_dot_prod_32fc_a(E_out, bb_signal, E_code, integration_time * prn_length_samples);
// volk_32fc_x2_dot_prod_32fc_a(P_out, bb_signal, P_code, integration_time * prn_length_samples);
// volk_32fc_x2_dot_prod_32fc_a(L_out, bb_signal, L_code, integration_time * prn_length_samples);
// // Vector of Prompts of I code
// for (int i = 0; i < integration_time; i++)
// {
// volk_32fc_x2_dot_prod_32fc_a(&P_data_out[i], &bb_signal[i*prn_length_samples], P_data_code, prn_length_samples);
// }
//
// free(bb_signal);
//
//}
void Correlator::Carrier_wipeoff_and_EPL_volk_IQ(int signal_length_samples ,const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* P_data_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, gr_complex* P_data_out, bool input_vector_unaligned)
{
gr_complex* bb_signal;
//gr_complex* input_aligned;
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&bb_signal, 16, signal_length_samples * sizeof(gr_complex)) == 0) {};
if (input_vector_unaligned == true)
{
//todo: do something if posix_memalign fails
//if (posix_memalign((void**)&input_aligned, 16, signal_length_samples * sizeof(gr_complex)) == 0){};
//memcpy(input_aligned,input,signal_length_samples * sizeof(gr_complex));
volk_32fc_x2_multiply_32fc_u(bb_signal, input, carrier, signal_length_samples);
}
else
{
/*
* todo: There is a problem with the aligned version of volk_32fc_x2_multiply_32fc_a.
* It crashes even if the is_aligned() work function returns true. Im keeping the unaligned version in both cases..
*/
//use directly the input vector
volk_32fc_x2_multiply_32fc_u(bb_signal, input, carrier, signal_length_samples);
}
volk_32fc_x2_dot_prod_32fc_a(E_out, bb_signal, E_code, signal_length_samples);
volk_32fc_x2_dot_prod_32fc_a(P_out, bb_signal, P_code, signal_length_samples);
volk_32fc_x2_dot_prod_32fc_a(L_out, bb_signal, L_code, signal_length_samples);
volk_32fc_x2_dot_prod_32fc_a(P_data_out, bb_signal, P_data_code, signal_length_samples);
free(bb_signal);
}
void Correlator::Carrier_wipeoff_and_EPL_volk_custom(int signal_length_samples, const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, bool input_vector_unaligned)
{
volk_cw_epl_corr_u(input, carrier, E_code, P_code, L_code, E_out, P_out, L_out, signal_length_samples);

View File

@ -57,6 +57,8 @@ public:
void Carrier_wipeoff_and_EPL_volk(int signal_length_samples, const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, bool input_vector_unaligned);
void Carrier_wipeoff_and_EPL_volk_custom(int signal_length_samples, const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, bool input_vector_unaligned);
void Carrier_wipeoff_and_VEPL_volk(int signal_length_samples, const gr_complex* input, gr_complex* carrier, gr_complex* VE_code, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* VL_code, gr_complex* VE_out, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, gr_complex* VL_out, bool input_vector_unaligned);
// void Carrier_wipeoff_and_EPL_volk_IQ(int prn_length_samples,int integration_time ,const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* P_data_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, gr_complex* P_data_out, bool input_vector_unaligned);
void Carrier_wipeoff_and_EPL_volk_IQ(int signal_length_samples, const gr_complex* input, gr_complex* carrier, gr_complex* E_code, gr_complex* P_code, gr_complex* L_code, gr_complex* P_data_code, gr_complex* E_out, gr_complex* P_out, gr_complex* L_out, gr_complex* P_data_out, bool input_vector_unaligned);
Correlator();
~Correlator();
private:

View File

@ -71,7 +71,8 @@ void Tracking_2nd_DLL_filter::initialize()
float Tracking_2nd_DLL_filter::get_code_nco(float DLL_discriminator)
{
float code_nco;
code_nco = d_old_code_nco + (d_tau2_code/d_tau1_code)*(DLL_discriminator - d_old_code_error) + DLL_discriminator * (d_pdi_code/d_tau1_code);
code_nco = d_old_code_nco + (d_tau2_code/d_tau1_code)*(DLL_discriminator - d_old_code_error) + (DLL_discriminator+d_old_code_error) * (d_pdi_code/(2*d_tau1_code));
//code_nco = d_old_code_nco + (d_tau2_code/d_tau1_code)*(DLL_discriminator - d_old_code_error) + DLL_discriminator * (d_pdi_code/d_tau1_code);
d_old_code_nco = code_nco;
d_old_code_error = DLL_discriminator; //[chips]
return code_nco;
@ -92,3 +93,7 @@ Tracking_2nd_DLL_filter::Tracking_2nd_DLL_filter ()
Tracking_2nd_DLL_filter::~Tracking_2nd_DLL_filter ()
{}
void Tracking_2nd_DLL_filter::set_pdi(float pdi_code)
{
d_pdi_code = pdi_code; // Summation interval for code
}

View File

@ -60,6 +60,7 @@ private:
public:
void set_DLL_BW(float dll_bw_hz); //! Set DLL filter bandwidth [Hz]
void set_pdi(float pdi_code); //! Set Summation interval for code [s]
void initialize(); //! Start tracking with acquisition information
float get_code_nco(float DLL_discriminator); //! Numerically controlled oscillator
Tracking_2nd_DLL_filter(float pdi_code);

View File

@ -74,7 +74,8 @@ void Tracking_2nd_PLL_filter::initialize()
float Tracking_2nd_PLL_filter::get_carrier_nco(float PLL_discriminator)
{
float carr_nco;
carr_nco = d_old_carr_nco + (d_tau2_carr/d_tau1_carr)*(PLL_discriminator - d_old_carr_error) + PLL_discriminator * (d_pdi_carr/d_tau1_carr);
carr_nco = d_old_carr_nco + (d_tau2_carr/d_tau1_carr)*(PLL_discriminator - d_old_carr_error) + (PLL_discriminator + d_old_carr_error) * (d_pdi_carr/(2*d_tau1_carr));
//carr_nco = d_old_carr_nco + (d_tau2_carr/d_tau1_carr)*(PLL_discriminator - d_old_carr_error) + PLL_discriminator * (d_pdi_carr/d_tau1_carr);
d_old_carr_nco = carr_nco;
d_old_carr_error = PLL_discriminator;
return carr_nco;
@ -84,7 +85,8 @@ Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter (float pdi_carr)
{
//--- PLL variables --------------------------------------------------------
d_pdi_carr = pdi_carr;// Summation interval for carrier
d_plldampingratio = 0.65;
//d_plldampingratio = 0.65;
d_plldampingratio = 0.7;
}
@ -100,3 +102,8 @@ Tracking_2nd_PLL_filter::Tracking_2nd_PLL_filter ()
Tracking_2nd_PLL_filter::~Tracking_2nd_PLL_filter ()
{}
void Tracking_2nd_PLL_filter::set_pdi(float pdi_carr)
{
d_pdi_carr = pdi_carr; // Summation interval for code
}

View File

@ -62,6 +62,7 @@ private:
public:
void set_PLL_BW(float pll_bw_hz); //! Set PLL loop bandwidth [Hz]
void set_pdi(float pdi_carr); //! Set Summation interval for code [s]
void initialize();
float get_carrier_nco(float PLL_discriminator);
Tracking_2nd_PLL_filter(float pdi_carr);

View File

@ -65,21 +65,17 @@
#include "galileo_e1_pcps_8ms_ambiguous_acquisition.h"
#include "galileo_e1_pcps_tong_ambiguous_acquisition.h"
#include "galileo_e1_pcps_cccwsr_ambiguous_acquisition.h"
#include "galileo_e5a_pcps_acquisition.h" //
#include "galileo_e5a_pilot_3ms_acquisition.h"
#include "galileo_e5ax_2ms_pcps_acquisition.h"
#include "galileo_e5a_3ms_noncoherent_iq_acquisition.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf.h"
#include "gps_l1_ca_dll_pll_tracking.h"
#include "gps_l1_ca_dll_pll_optim_tracking.h"
#include "gps_l1_ca_dll_fll_pll_tracking.h"
#include "gps_l1_ca_tcp_connector_tracking.h"
#include "galileo_e1_dll_pll_veml_tracking.h"
#include "galileo_e1_tcp_connector_tracking.h"
#include "galileo_e5a_dll_fll_pll_tracking.h" //
#include "galileo_e5a_dll_pll_tracking.h"
#include "gps_l1_ca_telemetry_decoder.h"
#include "galileo_e1b_telemetry_decoder.h"
#include "galileo_e5a_telemetry_decoder.h" // problematic
#include "galileo_e5a_telemetry_decoder.h"
#include "sbas_l1_telemetry_decoder.h"
#include "gps_l1_ca_observables.h"
#include "galileo_e1_observables.h"
@ -460,27 +456,9 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_PCPS_Acquisition") == 0)
else if (implementation.compare("Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5aPcpsAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_Pilot_3ms_Acquisition") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5aPilot_3msAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5ax_2ms_Pcps_Acquisition") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5ax2msPcpsAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_3ms_Noncoherent_IQ_Acquisition") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5a3msNoncoherentIQAcquisition(configuration.get(), role, in_streams,
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5aNoncoherentIQAcquisitionCaf(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
@ -523,12 +501,6 @@ std::unique_ptr<GNSSBlockInterface> GNSSBlockFactory::GetBlock(
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_DLL_FLL_PLL_Tracking") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5aDllFllPllTracking(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0)
{
std::unique_ptr<GNSSBlockInterface> block_(new GalileoE5aDllPllTracking(configuration.get(), role, in_streams,
@ -692,27 +664,9 @@ std::unique_ptr<AcquisitionInterface> GNSSBlockFactory::GetAcqBlock(
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_PCPS_Acquisition") == 0)
else if (implementation.compare("Galileo_E5a_Noncoherent_IQ_Acquisition_CAF") == 0)
{
std::unique_ptr<AcquisitionInterface> block_(new GalileoE5aPcpsAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_Pilot_3ms_Acquisition") == 0)
{
std::unique_ptr<AcquisitionInterface> block_(new GalileoE5aPilot_3msAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5ax_2ms_Pcps_Acquisition") == 0)
{
std::unique_ptr<AcquisitionInterface> block_(new GalileoE5ax2msPcpsAcquisition(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_3ms_Noncoherent_IQ_Acquisition") == 0)
{
std::unique_ptr<AcquisitionInterface> block_(new GalileoE5a3msNoncoherentIQAcquisition(configuration.get(), role, in_streams,
std::unique_ptr<AcquisitionInterface> block_(new GalileoE5aNoncoherentIQAcquisitionCaf(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
@ -770,12 +724,6 @@ std::unique_ptr<TrackingInterface> GNSSBlockFactory::GetTrkBlock(
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_DLL_FLL_PLL_Tracking") == 0)
{
std::unique_ptr<TrackingInterface> block_(new GalileoE5aDllFllPllTracking(configuration.get(), role, in_streams,
out_streams, queue));
block = std::move(block_);
}
else if (implementation.compare("Galileo_E5a_DLL_PLL_Tracking") == 0)
{
std::unique_ptr<TrackingInterface> block_(new GalileoE5aDllPllTracking(configuration.get(), role, in_streams,

View File

@ -54,15 +54,13 @@ const int Galileo_E5a_NUMBER_OF_CODES = 50;
// F/NAV message structure
#define GALILEO_FNAV_PREAMBLE {1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0}
const int GALILEO_FNAV_PREAMBLE_LENGTH_BITS = 12;
const int GALILEO_FNAV_SAMPLES_PER_SYMBOL = 20; // (chip rate/ code length)/telemetry bps
//const int GALILEO_FNAV_SYMBOLS_PER_PREAMBLE=240;
const int GALILEO_FNAV_SAMPLES_PER_PREAMBLE = 240; // bits preamble * samples/symbol
const std::string GALILEO_FNAV_PREAMBLE = {"101101110000"};
const int GALILEO_FNAV_CODES_PER_SYMBOL = 20; // (chip rate/ code length)/telemetry bps
const int GALILEO_FNAV_CODES_PER_PREAMBLE = 240; // bits preamble * codes/symbol
const int GALILEO_FNAV_SYMBOLS_PER_PAGE = 500; //Total symbols per page including preamble. See Galileo ICD 4.2.2
const int GALILEO_FNAV_SECONDS_PER_PAGE = 10;
const int GALILEO_FNAV_SAMPLES_PER_PAGE = 10000; // symbols * samples/symbol, where each 'sample' is a primary code
const int GALILEO_FNAV_CODES_PER_PAGE = 10000; // symbols * codes/symbol, where code stands for primary code
const int GALILEO_FNAV_INTERLEAVER_ROWS = 8;
const int GALILEO_FNAV_INTERLEAVER_COLS = 61;

View File

@ -42,10 +42,7 @@
#include "in_memory_configuration.h"
#include "configuration_interface.h"
#include "gnss_synchro.h"
#include "galileo_e5a_pcps_acquisition.h"
#include "galileo_e5a_pilot_3ms_acquisition.h"
#include "galileo_e5ax_2ms_pcps_acquisition.h"
#include "galileo_e5a_3ms_noncoherent_iq_acquisition.h"
#include "galileo_e5a_noncoherent_iq_acquisition_caf.h"
#include "signal_generator.h"
#include "signal_generator_c.h"
#include "fir_filter.h"
@ -86,10 +83,8 @@ protected:
gr::msg_queue::sptr queue;
gr::top_block_sptr top_block;
//std::shared_ptr<GNSSBlockFactory> factory = std::make_shared<GNSSBlockFactory>();
// GalileoE5aPcpsAcquisition *acquisition;
//GalileoE5aPilot_3msAcquisition *acquisition;
//GalileoE5ax2msPcpsAcquisition *acquisition;
GalileoE5a3msNoncoherentIQAcquisition *acquisition;
GalileoE5aNoncoherentIQAcquisitionCaf *acquisition;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
@ -115,6 +110,8 @@ protected:
double expected_doppler_hz3;
float max_doppler_error_hz;
float max_delay_error_chips;
int CAF_window_hz;
int Zero_padding;
unsigned int num_of_realizations;
unsigned int realization_counter;
@ -152,22 +149,28 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_1()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'E';
std::string signal = "5I";
//std::string signal = "5Q";
//std::string signal = "5X";
// std::string signal = "5I";
// std::string signal = "5Q";
std::string signal = "5X";
signal.copy(gnss_synchro.Signal,2,0);
integration_time_ms = 3;
//fs_in = 10.24e6;
integration_time_ms = 1;
//fs_in = 11e6;
//fs_in = 18e6;
fs_in = 32e6;
//fs_in = 30.69e6;
//fs_in = 20.47e6;
// unsigned int delay_samples = (delay_chips_[sat] % codelen)
// * samples_per_code_[sat] / codelen;
expected_delay_chips = round(14000*((double)10230000/(double)fs_in));
expected_doppler_hz = 2800;
//expected_doppler_hz = 0;
expected_delay_sec = 94;
CAF_window_hz = 2000;
// CAF_window_hz = 0;
Zero_padding = 0;
//expected_delay_chips = 1000;
//expected_doppler_hz = 250;
@ -181,7 +184,12 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_1()
config = std::make_shared<InMemoryConfiguration>();
config->set_property("Channel.signal",signal);
config->set_property("GNSS-SDR.internal_fs_hz", std::to_string(fs_in));
int a = config->property("GNSS-SDR.internal_fs_hz",10);
std::cout << "fs "<< a <<std::endl;
config->set_property("SignalSource.fs_hz", std::to_string(fs_in));
@ -228,11 +236,12 @@ void GalileoE5aPcpsAcquisitionGSoC2014GensourceTest::config_1()
config->set_property("Acquisition.coherent_integration_time_ms",
std::to_string(integration_time_ms));
config->set_property("Acquisition.max_dwells", "1");
// config->set_property("Acquisition.implementation", "Galileo_E5a_PCPS_Acquisition");
//config->set_property("Acquisition.implementation", "Galileo_E5a_Pilot_3ms_Acquisition");
config->set_property("Acquisition.CAF_window_hz",std::to_string(CAF_window_hz));
config->set_property("Acquisition.Zero_padding",std::to_string(Zero_padding));
config->set_property("Acquisition.implementation", "Galileo_E5a_3ms_Noncoherent_IQ_Acquisition");
config->set_property("Acquisition.threshold", "0.1");
config->set_property("Acquisition.implementation", "Galileo_E5a_Noncoherent_IQ_Acquisition_CAF");
config->set_property("Acquisition.pfa","0.003");
// config->set_property("Acquisition.threshold", "0.01");
config->set_property("Acquisition.doppler_max", "10000");
config->set_property("Acquisition.doppler_step", "250");
config->set_property("Acquisition.bit_transition_flag", "false");
@ -602,9 +611,10 @@ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ValidationOfSIM)
config_1();
//int nsamples = floor(fs_in*integration_time_ms*1e-3);
// acquisition = new GalileoE5aPcpsAcquisition(config.get(), "Acquisition", 1, 1, queue);
acquisition = new GalileoE5a3msNoncoherentIQAcquisition(config.get(), "Acquisition", 1, 1, queue);
unsigned int skiphead_sps = 0; // 32 Msps
acquisition = new GalileoE5aNoncoherentIQAcquisitionCaf(config.get(), "Acquisition", 1, 1, queue);
unsigned int skiphead_sps = 28000; // 32 Msps
// unsigned int skiphead_sps = 0;
//unsigned int skiphead_sps = 84000;
ASSERT_NO_THROW( {
acquisition->set_channel(1);
@ -662,23 +672,19 @@ TEST_F(GalileoE5aPcpsAcquisitionGSoC2014GensourceTest, ValidationOfSIM)
*/
ASSERT_NO_THROW( {
//std::string path = std::string(TEST_PATH);
//std::string file = "/home/marc/E5a_acquisitions/signal_source_21MPrimary.dat";
//noiseless
std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11.dat";
//std::string file = "/home/marc/E5a_acquisitions/signal_source_21MSecondary.dat";
//noiseless sim
std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11_long.dat";
// real
//std::string file = "/home/marc/E5a_acquisitions/32MS_complex.dat";
//std::string file = "/home/marc/E5a_acquisitions/galileo_E5_8M_r2_upsampled_12.dat";
//CN040
const char * file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false);
// gr::blocks::skiphead::sptr skip_head = gr::blocks::skiphead::make(sizeof(gr_complex), skiphead_sps);
// top_block->connect(file_source, 0, skip_head, 0);
// top_block->connect(skip_head, 0, acquisition->get_left_block(), 0);
gr::blocks::skiphead::sptr skip_head = gr::blocks::skiphead::make(sizeof(gr_complex), skiphead_sps);
top_block->connect(file_source, 0, skip_head, 0);
top_block->connect(skip_head, 0, acquisition->get_left_block(), 0);
top_block->connect(file_source, 0, acquisition->get_left_block(), 0);
// top_block->connect(file_source, 0, acquisition->get_left_block(), 0);
}) << "Failure connecting the blocks of acquisition test." << std::endl;
// i = 0 --> satellite in acquisition is visible

View File

@ -84,10 +84,9 @@ void GalileoE5aTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'E';
std::string signal = "5X";
std::string signal = "5Q";
signal.copy(gnss_synchro.Signal, 2, 0);
//gnss_synchro.PRN = 19;//real
gnss_synchro.PRN = 11;//sim
config->set_property("GNSS-SDR.internal_fs_hz", "32000000");
config->set_property("Tracking.item_type", "gr_complex");
@ -97,10 +96,11 @@ void GalileoE5aTrackingTest::init()
config->set_property("Tracking.early_late_space_chips", "0.5");
config->set_property("Tracking.pll_bw_hz", "5.0");
config->set_property("Tracking.dll_bw_hz", "2.0");
//config->set_property("Tracking.fll_bw_hz", "10.0");
// config->set_property("Tracking.pll_bw_hz", "20.0");
// config->set_property("Tracking.dll_bw_hz", "1.0");
config->set_property("Tracking.pll_bw_hz_init","20.0");
config->set_property("Tracking.dll_bw_hz_init","20.0");
config->set_property("Tracking.ti_ms","3");
//config->set_property("Tracking.fll_bw_hz", "10.0");
}
/*
TEST_F(GalileoE5aTrackingTest, InstantiateTrack)
@ -169,9 +169,10 @@ TEST_F(GalileoE5aTrackingTest, ValidationOfResults)
struct timeval tv;
long long int begin = 0;
long long int end = 0;
int num_samples = 3200000000; // 32 Msps
int num_samples = 32000000000; // 32 Msps
//unsigned int skiphead_sps = 98000; // 1 Msample
unsigned int skiphead_sps = 0; // 1 Msample
unsigned int skiphead_sps = 0; // 1 Msampl
// unsigned int skiphead_sps = 104191; // 1 Msampl
init();
// Example using smart pointers and the block factory
@ -179,16 +180,22 @@ TEST_F(GalileoE5aTrackingTest, ValidationOfResults)
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_);
//REAL
// gnss_synchro.Acq_delay_samples = 15579; // 32 Msps
// gnss_synchro.Acq_doppler_hz = 3500; // 32 Msps
//// gnss_synchro.Acq_samplestamp_samples = 98000;
// gnss_synchro.Acq_samplestamp_samples = 0;
//SIM
gnss_synchro.Acq_delay_samples = 14001; // 32 Msps
gnss_synchro.Acq_doppler_hz = 2750; // 32 Msps (real 2800)
gnss_synchro.Acq_delay_samples = 15579+1; // 32 Msps
gnss_synchro.Acq_doppler_hz = 3500; // 32 Msps
// gnss_synchro.Acq_samplestamp_samples = 98000;
gnss_synchro.Acq_samplestamp_samples = 0;
//SIM
// gnss_synchro.Acq_delay_samples = 14001+1; // 32 Msps
// //gnss_synchro.Acq_doppler_hz = 2750; // 32 Msps (real 2800)
// gnss_synchro.Acq_doppler_hz = 2800; // 32 Msps (real 2800)
// //gnss_synchro.Acq_doppler_hz = 0; // 32 Msps (real 2800)
//// gnss_synchro.Acq_samplestamp_samples = 98000;
// gnss_synchro.Acq_samplestamp_samples = 0;
//SIM2
// gnss_synchro.Acq_delay_samples = 5810; // 32 Msps
// gnss_synchro.Acq_doppler_hz = 2750;
// gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW( {
tracking->set_channel(gnss_synchro.Channel_ID);
@ -207,9 +214,11 @@ TEST_F(GalileoE5aTrackingTest, ValidationOfResults)
}) << "Failure connecting tracking to the top_block." << std::endl;
ASSERT_NO_THROW( {
//std::string file = "/home/marc/E5a_acquisitions/Tiered_sink_4sat.dat";
//std::string file = "/home/marc/E5a_acquisitions/32MS_complex.dat";
std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11.dat";
std::string file = "/home/marc/E5a_acquisitions/32MS_complex.dat";
//std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11_long.dat";
//std::string file = "/home/marc/E5a_acquisitions/sim_32M_sec94_PRN11_long_0dopp.dat";
gnss_synchro.PRN = 19;//real
//gnss_synchro.PRN = 11;//sim
const char * file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex),file_name,false);

View File

@ -0,0 +1,88 @@
% /*!
% * \file galileo_e5a_dll_pll_plot_sample_64bits.m
% * \brief Read GNSS-SDR Tracking dump binary file using the provided
% function and plot some internal variables
% * \author Javier Arribas, Marc Sales 2014. jarribas(at)cttc.es
% marcsales92@gmail.com
% * -------------------------------------------------------------------------
% *
% * Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
% *
% * GNSS-SDR is a software defined Global Navigation
% * Satellite Systems receiver
% *
% * This file is part of GNSS-SDR.
% *
% * GNSS-SDR is free software: you can redistribute it and/or modify
% * it under the terms of the GNU General Public License as published by
% * the Free Software Foundation, either version 3 of the License, or
% * at your option) any later version.
% *
% * GNSS-SDR is distributed in the hope that it will be useful,
% * but WITHOUT ANY WARRANTY; without even the implied warranty of
% * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% * GNU General Public License for more details.
% *
% * You should have received a copy of the GNU General Public License
% * along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
% *
% * -------------------------------------------------------------------------
% */
close all;
clear all;
samplingFreq = 64e6/32; %[Hz]
channels=1;
%path='/home/javier/workspace/gnss-sdr/trunk/install/';
path='/home/marc/git/gnss-sdr/data/';
clear PRN_absolute_sample_start;
for N=1:1:channels
tracking_log_path=[path 'e5a_tracking_ch_' num2str(N-1) '.dat'];
GNSS_tracking(N)= gps_l1_ca_dll_pll_read_tracking_dump_64bits(tracking_log_path);
end
% GNSS-SDR format conversion to MATLAB GPS receiver
for N=1:1:channels
trackResults(N).status='T'; %fake track
trackResults(N).codeFreq=GNSS_tracking(N).code_freq_hz.';
trackResults(N).carrFreq=GNSS_tracking(N).carrier_doppler_hz.';
trackResults(N).dllDiscr = GNSS_tracking(N).code_error.';
trackResults(N).dllDiscrFilt = GNSS_tracking(N).code_nco.';
trackResults(N).pllDiscr = GNSS_tracking(N).carr_error.';
trackResults(N).pllDiscrFilt = GNSS_tracking(N).carr_nco.';
trackResults(N).I_P=GNSS_tracking(N).prompt_I.';
trackResults(N).Q_P=GNSS_tracking(N).prompt_Q.';
trackResults(N).I_E= GNSS_tracking(N).E.';
trackResults(N).I_L = GNSS_tracking(N).L.';
trackResults(N).Q_E = zeros(1,length(GNSS_tracking(N).E));
trackResults(N).Q_L =zeros(1,length(GNSS_tracking(N).E));
trackResults(N).PRN=N; %fake PRN
% Use original MATLAB tracking plot function
settings.numberOfChannels=channels;
settings.msToProcess=length(GNSS_tracking(N).E);
plotTracking(N,trackResults,settings)
end
for N=1:1:channels
% figure;
% plot([GNSS_tracking(N).E,GNSS_tracking(N).P,GNSS_tracking(N).L],'-*');
% title(['Early, Prompt, and Late correlator absolute value output for channel ' num2str(N)']);
% figure;
% plot(GNSS_tracking(N).prompt_I,GNSS_tracking(N).prompt_Q,'+');
% title(['Navigation constellation plot for channel ' num2str(N)]);
% figure;
%
% plot(GNSS_tracking(N).prompt_Q,'r');
% hold on;
% plot(GNSS_tracking(N).prompt_I);
% title(['Navigation symbols I(red) Q(blue) for channel ' num2str(N)]);
%
figure;
t=0:length(GNSS_tracking(N).carrier_doppler_hz)-1;
t=t/1000;
plot(t,GNSS_tracking(N).carrier_doppler_hz/1000);
xlabel('Time(s)');ylabel('Doppler(KHz)');title(['Doppler frequency channel ' num2str(N)]);
end

View File

@ -1,16 +1,18 @@
% /*!
% * \file plot_acq_grid_gsoc.m
% * \file plot_acq_grid_gsoc_e5.m
% * \brief Read GNSS-SDR Acquisition dump binary file using the provided
% function and plot acquisition grid of acquisition statistic of PRN sat
% function and plot acquisition grid of acquisition statistic of PRN sat.
% CAF input must be 0 or 1 depending if the user desires to read the file
% that resolves doppler ambiguity or not.
%
% This function analyzes a experiment performed by Luis Esteve in the framework
% of the Google Summer of Code (GSoC) 2012, with the collaboration of Javier Arribas
% This function analyzes a experiment performed by Marc Sales in the framework
% of the Google Summer of Code (GSoC) 2014, with the collaboration of Luis Esteve, Javier Arribas
% and Carles Fernández, related to the extension of GNSS-SDR to Galileo.
%
% * \author Luis Esteve, 2012. luis(at)epsilon-formacion.com
% * \author Marc Sales marcsales92(at)gmail.com, Luis Esteve, 2014. luis(at)epsilon-formacion.com
% * -------------------------------------------------------------------------
% *
% * Copyright (C) 2010-2011 (see AUTHORS file for a list of contributors)
% * Copyright (C) 2010-2014 (see AUTHORS file for a list of contributors)
% *
% * GNSS-SDR is a software defined Global Navigation
% * Satellite Systems receiver
@ -33,22 +35,30 @@
% * -------------------------------------------------------------------------
% */
function plot_acq_grid_gsoc_e5(sat)
function plot_acq_grid_gsoc_e5(sat,CAF)
file=['test_statistics_E_5I_sat_' num2str(sat) '_doppler_0.dat'];
path='/home/marc/git/gnss-sdr/data/';
file=[path 'test_statistics_E5a_sat_' num2str(sat) '_doppler_0.dat'];
sampling_freq_Hz=12E6
Doppler_max_Hz = 9875
sampling_freq_Hz=32E6
%Doppler_max_Hz = 14875
%Doppler_min_Hz = -15000
%Doppler_step_Hz = 125
Doppler_max_Hz = 10000
Doppler_min_Hz = -10000
Doppler_step_Hz = 125
Doppler_step_Hz = 250
% read files
%x=read_complex_binary (file);
x=load_complex_data(file);
%x=load_complex_data(file); % complex
%l_y=length(x);
myFile = java.io.File(file);
flen = length(myFile);
l_y=flen/4;% float
l_y=length(x);
Doppler_axes=Doppler_min_Hz:Doppler_step_Hz:Doppler_max_Hz;
@ -60,20 +70,33 @@ index=0;
for k=Doppler_min_Hz:Doppler_step_Hz:Doppler_max_Hz
index=index+1;
filename=['test_statistics_E_5I_sat_' num2str(sat) '_doppler_' num2str(k) '.dat'];
acq_grid(index,:)=abs(read_complex_binary (filename));
end
maximum_correlation_peak = max(max(acq_grid))
filename=[path 'test_statistics_E5a_sat_' num2str(sat) '_doppler_' num2str(k) '.dat'];
fid=fopen(filename,'r');
xx=fread(fid,'float');%floats from squared correlation
%xx=load_complex_data (filename); %complex
acq_grid(index,:)=abs(xx);
end
[fila,col]=find(acq_grid==max(max(acq_grid)));
if (CAF > 0)
filename=[path 'test_statistics_E5a_sat_' num2str(sat) '_CAF.dat'];
fid=fopen(filename,'r');
xx=fread(fid,'float');%floats from squared correlation
acq_grid(:,col)=abs(xx);
Doppler_error_Hz = Doppler_axes(xx==max(xx))
maximum_correlation_peak = max(xx)
else
Doppler_error_Hz = Doppler_axes(fila)
maximum_correlation_peak = max(max(acq_grid))
end
delay_error_sps = col -1
Doppler_error_Hz = Doppler_axes(fila)
noise_grid=acq_grid;
delay_span=floor(3*sampling_freq_Hz/(1.023e6));
delay_span=floor(3*sampling_freq_Hz/(1.023e7));
Doppler_span=floor(500/Doppler_step_Hz);
noise_grid(fila-Doppler_span:fila+Doppler_span,col-delay_span:col+delay_span)=0;
@ -91,25 +114,24 @@ Gain_dbs = 10*log10(maximum_correlation_peak/noise_floor)
figure;
surf(X,Y,acq_grid');
xlabel('Doppler(Hz)');ylabel('Code Delay(samples)');title(['GLRT statistic of Galileo Parallel Code Phase Search Acquisition. Local replica: E5a-I PRN ' num2str(sat)]);
xlabel('Doppler(Hz)');ylabel('Code Delay(samples)');title(['GLRT statistic of Galileo Parallel Code Phase Search Acquisition. PRN ' num2str(sat)]);
end
function x=load_complex_data(file)
%fid = fopen(file,'r');
fid = fopen('signal_source.dat','r');
k=1;
tline=fgetl(fid);
%while (~feof(fid))
while (ischar(tline))
%x(k,1:2) = fread(fid, 2, 'float');
a=strplit(tline);
disp(a);
tline=fgetl(fid);
fid = fopen(file,'r');
%fid = fopen('signal_source.dat','r');
myFile = java.io.File(file);
flen = length(myFile);
num_samples=flen/8; % 8 bytes (2 single floats) per complex sample
for k=1:num_samples
a(1:2) = fread(fid, 2, 'float');
x(k) = a(1) + a(2)*1i;
k=k+1;
if k==12000
end
end
end
end