mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-01-12 02:10:34 +00:00
Unified acquisition
This commit is contained in:
parent
7d6ec42f24
commit
3b3c809dab
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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_;
|
||||
}
|
@ -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_ */
|
@ -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_;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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_;
|
||||
}
|
||||
|
@ -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_ */
|
@ -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_;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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++)
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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_;
|
||||
}
|
@ -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_ */
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
88
src/utils/matlab/galileo_e5a_dll_pll_plot_sample_64bits.m
Normal file
88
src/utils/matlab/galileo_e5a_dll_pll_plot_sample_64bits.m
Normal 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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user