Towards a front-end frequency and sample rate calibration tool. VERY experimental yet.

Bug fixes in acquisition assistance and in linker include files.


git-svn-id: https://svn.code.sf.net/p/gnss-sdr/code/trunk@371 64b25241-fba3-4117-9849-534c7e92360d
This commit is contained in:
Javier Arribas 2013-07-05 17:00:48 +00:00
parent 4739a05a4e
commit 6f8ef58802
17 changed files with 2263 additions and 7 deletions

193
conf/front-end-cal.conf Normal file
View File

@ -0,0 +1,193 @@
; Default configuration file
; You can define your own receiver and invoke it by doing
; gnss-sdr --config_file=my_GNSS_SDR_configuration.conf
;
[GNSS-SDR]
;######### INITIAL RECEIVER POSITIION ######
;GNSS-SDR.init_latitude_deg=40.74846557442795
;GNSS-SDR.init_longitude_deg=-73.98593961814200
;GNSS-SDR.init_altitude_m=329.11968943169342
GNSS-SDR.init_latitude_deg=41.27481478485936
GNSS-SDR.init_longitude_deg=1.98753271588628
GNSS-SDR.init_altitude_m=25
;######### GLOBAL OPTIONS ##################
;internal_fs_hz: Internal signal sampling frequency after the signal conditioning stage [Hz].
GNSS-SDR.internal_fs_hz=2000000
;######### CONTROL_THREAD CONFIG ############
ControlThread.wait_for_flowgraph=false
;######### SUPL RRLP GPS assistance configuration #####
GNSS-SDR.SUPL_gps_enabled=true
GNSS-SDR.SUPL_read_gps_assistance_xml=false
GNSS-SDR.SUPL_gps_ephemeris_server=supl.nokia.com
GNSS-SDR.SUPL_gps_ephemeris_port=7275
GNSS-SDR.SUPL_gps_acquisition_server=supl.google.com
GNSS-SDR.SUPL_gps_acquisition_port=7275
GNSS-SDR.SUPL_MCC=217
GNSS-SDR.SUPL_MNS=7
GNSS-SDR.SUPL_LAC=861
GNSS-SDR.SUPL_CI=40184
;######### SIGNAL_SOURCE CONFIG ############
;#implementation: Use [File_Signal_Source] or [UHD_Signal_Source] or [GN3S_Signal_Source] or [Rtlsdr_Signal_Source]
SignalSource.implementation=File_Signal_Source
SignalSource.AGC_enabled=false
;#filename: path to file with the captured GNSS signal samples to be processed
SignalSource.filename=/media/DATALOGGER_/signals/Agilent GPS Generator/New York/2msps.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=2000000
;#freq: RF front-end center frequency in [Hz]
SignalSource.freq=1575420000
;#gain: Front-end Gain in [dB]
SignalSource.gain=40
SignalSource.rf_gain=40
SignalSource.if_gain=5
;#subdevice: UHD subdevice specification (for USRP1 use A:0 or B:0)
SignalSource.subdevice=B:0
;#samples: Number of samples to be processed. Notice that 0 indicates the entire file.
SignalSource.samples=0
;#repeat: Repeat the processing file. Disable this option in this version
SignalSource.repeat=false
;#dump: Dump the Signal source data to a file. Disable this option in this version
SignalSource.dump=false
SignalSource.dump_filename=../data/signal_source.dat
;######### SIGNAL_CONDITIONER CONFIG ############
;## It holds blocks to change data type, filter and resample input data.
;#implementation: Use [Pass_Through] or [Signal_Conditioner]
;#[Pass_Through] disables this block and the [DataTypeAdapter], [InputFilter] and [Resampler] blocks
;#[Signal_Conditioner] enables this block. Then you have to configure [DataTypeAdapter], [InputFilter] and [Resampler] blocks
SignalConditioner.implementation=Signal_Conditioner
;######### DATA_TYPE_ADAPTER CONFIG ############
;## Changes the type of input data. Please disable it in this version.
;#implementation: Use [Ishort_To_Complex] or [Pass_Through]
DataTypeAdapter.implementation=Pass_Through
;#dump: Dump the filtered data to a file.
DataTypeAdapter.dump=false
;#dump_filename: Log path and filename.
DataTypeAdapter.dump_filename=../data/data_type_adapter.dat
;######### INPUT_FILTER CONFIG ############
;## Filter the input data. Can be combined with frequency translation for IF signals
;#implementation: Use [Pass_Through] or [Fir_Filter] or [Freq_Xlating_Fir_Filter]
;#[Pass_Through] disables this block
;#[Fir_Filter] enables a FIR Filter
;#[Freq_Xlating_Fir_Filter] enables FIR filter and a composite frequency translation that shifts IF down to zero Hz.
InputFilter.implementation=Freq_Xlating_Fir_Filter
;#dump: Dump the filtered data to a file.
InputFilter.dump=false
;#dump_filename: Log path and filename.
InputFilter.dump_filename=../data/input_filter.dat
;#The following options are used in the filter design of Fir_Filter and Freq_Xlating_Fir_Filter implementation.
;#These options are based on parameters of gnuradio's function: gr_remez.
;#These function calculates the optimal (in the Chebyshev/minimax sense) FIR filter inpulse reponse given a set of band edges, the desired reponse on those bands, and the weight given to the error in those bands.
;#input_item_type: Type and resolution for input signal samples. Use only gr_complex in this version.
InputFilter.input_item_type=gr_complex
;#outut_item_type: Type and resolution for output filtered signal samples. Use only gr_complex in this version.
InputFilter.output_item_type=gr_complex
;#taps_item_type: Type and resolution for the taps of the filter. Use only float in this version.
InputFilter.taps_item_type=float
;#number_of_taps: Number of taps in the filter. Increasing this parameter increases the processing time
InputFilter.number_of_taps=5
;#number_of _bands: Number of frequency bands in the filter.
InputFilter.number_of_bands=2
;#bands: frequency at the band edges [ b1 e1 b2 e2 b3 e3 ...].
;#Frequency is in the range [0, 1], with 1 being the Nyquist frequency (Fs/2)
;#The number of band_begin and band_end elements must match the number of bands
InputFilter.band1_begin=0.0
;InputFilter.band1_end=0.8
InputFilter.band1_end=0.85
InputFilter.band2_begin=0.90
InputFilter.band2_end=1.0
;#ampl: desired amplitude at the band edges [ a(b1) a(e1) a(b2) a(e2) ...].
;#The number of ampl_begin and ampl_end elements must match the number of bands
InputFilter.ampl1_begin=1.0
InputFilter.ampl1_end=1.0
InputFilter.ampl2_begin=0.0
InputFilter.ampl2_end=0.0
;#band_error: weighting applied to each band (usually 1).
;#The number of band_error elements must match the number of bands
InputFilter.band1_error=1.0
InputFilter.band2_error=1.0
;#filter_type: one of "bandpass", "hilbert" or "differentiator"
InputFilter.filter_type=bandpass
;#grid_density: determines how accurately the filter will be constructed.
;The minimum value is 16; higher values are slower to compute the filter.
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=2000000
InputFilter.IF=0
InputFilter.decimation_factor=1
;######### RESAMPLER CONFIG ############
;## Resamples the input data.
;#implementation: Use [Pass_Through] or [Direct_Resampler]
;#[Pass_Through] disables this block
Resampler.implementation=Pass_Through
;######### ACQUISITION GLOBAL CONFIG ############
;#dump: Enable or disable the acquisition internal data file logging [true] or [false]
Acquisition.dump=false
;#filename: Log path and filename
Acquisition.dump_filename=./acq_dump.dat
;#item_type: Type and resolution for each of the signal samples. Use only gr_complex in this version.
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.sampled_ms=1
;#implementation: Acquisition algorithm selection for this channel: [GPS_L1_CA_PCPS_Acquisition] or [Galileo_E1_PCPS_Ambiguous_Acquisition]
Acquisition.implementation=GPS_L1_CA_PCPS_Acquisition
;#threshold: Acquisition threshold
Acquisition.threshold=40
;#doppler_max: Maximum expected Doppler shift [Hz]
Acquisition.doppler_max=10000
;#doppler_max: Maximum expected Doppler shift [Hz]
Acquisition.doppler_min=-10000
;#doppler_step Doppler step in the grid search [Hz]
Acquisition.doppler_step=250
;#maximum dwells
Acquisition.max_dwells=2

View File

@ -20,4 +20,4 @@ add_subdirectory(algorithms)
add_subdirectory(core)
add_subdirectory(main)
add_subdirectory(tests)
#add_subdirectory(utils)
add_subdirectory(utils)

View File

@ -19,7 +19,8 @@
set(ACQ_ADAPTER_SOURCES
galileo_e1_pcps_ambiguous_acquisition.cc
gps_l1_ca_pcps_acquisition.cc
gps_l1_ca_pcps_assisted_acquisition.cc
gps_l1_ca_pcps_assisted_acquisition.cc
gps_l1_ca_pcps_acquisition_fine_doppler.cc
)
include_directories(

View File

@ -0,0 +1,186 @@
/*!
* \file gps_l1_ca_pcps_acquisition.cc
* \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
* GPS L1 C/A Signals
* \authors <ul>
* <li> Javier Arribas, 2011. jarribas(at)cttc.es
* <li> Luis Esteve, 2012. luis(at)epsilon-formacion.com
* </ul>
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (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 "gps_l1_ca_pcps_acquisition_fine_doppler.h"
#include "gps_sdr_signal_processing.h"
#include "GPS_L1_CA.h"
#include "configuration_interface.h"
#include <iostream>
#include <gnuradio/io_signature.h>
#include <glog/log_severity.h>
#include <glog/logging.h>
using google::LogMessage;
GpsL1CaPcpsAcquisitionFineDoppler::GpsL1CaPcpsAcquisitionFineDoppler(
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)
{
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", 2048000);
if_ = configuration->property(role + ".ifreq", 0);
dump_ = configuration->property(role + ".dump", false);
doppler_max_ = configuration->property(role + ".doppler_max", 5000);
doppler_min_ = configuration->property(role + ".doppler_min", -5000);
sampled_ms_ = configuration->property(role + ".sampled_ms", 1);
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 -------------------------
vector_length_ = round(fs_in_
/ (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS));
code_= new gr_complex[vector_length_];
if (item_type_.compare("gr_complex") == 0)
{
item_size_ = sizeof(gr_complex);
acquisition_cc_ = pcps_make_acquisition_fine_doppler_cc(max_dwells_,sampled_ms_,
doppler_max_, doppler_min_, if_, fs_in_, vector_length_, queue_,
dump_, dump_filename_);
}
else
{
LOG_AT_LEVEL(WARNING) << item_type_
<< " unknown acquisition item type";
}
}
GpsL1CaPcpsAcquisitionFineDoppler::~GpsL1CaPcpsAcquisitionFineDoppler()
{
delete[] code_;
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_channel(unsigned int channel)
{
channel_ = channel;
acquisition_cc_->set_channel(channel_);
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_threshold(float threshold)
{
threshold_ = threshold;
acquisition_cc_->set_threshold(threshold_);
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_doppler_max(unsigned int doppler_max)
{
doppler_max_ = doppler_max;
acquisition_cc_->set_doppler_max(doppler_max_);
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_doppler_step(unsigned int doppler_step)
{
doppler_step_ = doppler_step;
acquisition_cc_->set_doppler_step(doppler_step_);
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_channel_queue(
concurrent_queue<int> *channel_internal_queue)
{
channel_internal_queue_ = channel_internal_queue;
acquisition_cc_->set_channel_queue(channel_internal_queue_);
}
void GpsL1CaPcpsAcquisitionFineDoppler::set_gnss_synchro(Gnss_Synchro* gnss_synchro)
{
gnss_synchro_ = gnss_synchro;
acquisition_cc_->set_gnss_synchro(gnss_synchro_);
}
signed int GpsL1CaPcpsAcquisitionFineDoppler::mag()
{
return acquisition_cc_->mag();
}
void GpsL1CaPcpsAcquisitionFineDoppler::init(){
gps_l1_ca_code_gen_complex_sampled(code_, gnss_synchro_->PRN, fs_in_, 0);
acquisition_cc_->set_local_code(code_);
acquisition_cc_->init();
}
void GpsL1CaPcpsAcquisitionFineDoppler::reset()
{
acquisition_cc_->set_active(true);
}
void GpsL1CaPcpsAcquisitionFineDoppler::connect(boost::shared_ptr<gr::top_block> top_block)
{
//nothing to disconnect, now the tracking uses gr_sync_decimator
}
void GpsL1CaPcpsAcquisitionFineDoppler::disconnect(boost::shared_ptr<gr::top_block> top_block)
{
//nothing to disconnect, now the tracking uses gr_sync_decimator
}
boost::shared_ptr<gr::basic_block> GpsL1CaPcpsAcquisitionFineDoppler::get_left_block()
{
return acquisition_cc_;
}
boost::shared_ptr<gr::basic_block> GpsL1CaPcpsAcquisitionFineDoppler::get_right_block()
{
return acquisition_cc_;
}

View File

@ -0,0 +1,154 @@
/*!
* \file gps_l1_ca_pcps_acquisition_fine_doppler.h
* \brief Adapts a PCPS acquisition block with fine Doppler estimation to an AcquisitionInterface for
* GPS L1 C/A signals
* \authors <ul>
* <li> Javier Arribas, 2013. jarribas(at)cttc.es
* </ul> *
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (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_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_
#define GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_
#include "gnss_synchro.h"
#include "acquisition_interface.h"
#include "pcps_acquisition_fine_doppler_cc.h"
#include <gnuradio/msg_queue.h>
#include <gnuradio/blocks/stream_to_vector.h>
class ConfigurationInterface;
/*!
* \brief This class Adapts a PCPS acquisition block with fine Doppler estimation to an AcquisitionInterface for
* GPS L1 C/A signals
*/
class GpsL1CaPcpsAcquisitionFineDoppler: public AcquisitionInterface
{
public:
GpsL1CaPcpsAcquisitionFineDoppler(ConfigurationInterface* configuration,
std::string role, unsigned int in_streams,
unsigned int out_streams, boost::shared_ptr<gr::msg_queue> queue);
virtual ~GpsL1CaPcpsAcquisitionFineDoppler();
std::string role()
{
return role_;
}
/*!
* \brief Returns "GPS_L1_CA_PCPS_Assisted_Acquisition"
*/
std::string implementation()
{
return "GPS_L1_CA_PCPS_Acquisition_Fine_Doppler";
}
size_t item_size()
{
return item_size_;
}
void connect(boost::shared_ptr<gr::top_block> top_block);
void disconnect(boost::shared_ptr<gr::top_block> top_block);
boost::shared_ptr<gr::basic_block> get_left_block();
boost::shared_ptr<gr::basic_block> 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 Returns the maximum peak of grid search
*/
signed int mag();
/*!
* \brief Restart acquisition algorithm
*/
void reset();
private:
pcps_acquisition_fine_doppler_cc_sptr acquisition_cc_;
size_t item_size_;
std::string item_type_;
unsigned int vector_length_;
//unsigned int satellite_;
unsigned int channel_;
float threshold_;
int doppler_max_;
unsigned int doppler_step_;
int doppler_min_;
unsigned int sampled_ms_;
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_;
};
#endif /* GNSS_SDR_GPS_L1_CA_PCPS_ACQUISITION_FINE_DOPPLER_H_ */

View File

@ -19,6 +19,7 @@
set(ACQ_GR_BLOCKS_SOURCES
pcps_acquisition_cc.cc
pcps_assisted_acquisition_cc.cc
pcps_acquisition_fine_doppler_cc.cc
)
include_directories(

View File

@ -0,0 +1,526 @@
/*!
* \file pcps_assisted_acquisition_cc.cc
* \brief This class implements a Parallel Code Phase Search Acquisition with multi-dwells and fine Doppler estimation
* \authors <ul>
* <li> Javier Arribas, 2013. jarribas(at)cttc.es
* </ul>
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (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 "pcps_acquisition_fine_doppler_cc.h"
#include "gnss_signal_processing.h"
#include "gps_sdr_signal_processing.h"
#include "control_message_factory.h"
#include "gps_acq_assist.h"
#include <gnuradio/io_signature.h>
#include <sstream>
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <volk/volk.h>
#include "nco_lib.h"
#include "concurrent_map.h"
#include <algorithm> // std::rotate
extern concurrent_map<Gps_Acq_Assist> global_gps_acq_assist_map;
using google::LogMessage;
pcps_acquisition_fine_doppler_cc_sptr pcps_make_acquisition_fine_doppler_cc(
int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq,
long fs_in, int samples_per_ms, boost::shared_ptr<gr::msg_queue> queue, bool dump,
std::string dump_filename)
{
return pcps_acquisition_fine_doppler_cc_sptr(
new pcps_acquisition_fine_doppler_cc(max_dwells, sampled_ms, doppler_max, doppler_min, freq,
fs_in, samples_per_ms, queue, dump, dump_filename));
}
pcps_acquisition_fine_doppler_cc::pcps_acquisition_fine_doppler_cc(
int max_dwells, unsigned int sampled_ms, int doppler_max, int doppler_min, long freq,
long fs_in, int samples_per_ms, boost::shared_ptr<gr::msg_queue> queue, bool dump,
std::string dump_filename) :
gr::block("pcps_acquisition_fine_doppler_cc",
gr::io_signature::make(1, 1, sizeof(gr_complex)),
gr::io_signature::make(0, 0, sizeof(gr_complex)))
{
d_sample_counter = 0; // SAMPLE COUNTER
d_active = false;
d_queue = queue;
d_freq = freq;
d_fs_in = fs_in;
d_samples_per_ms = samples_per_ms;
d_sampled_ms = sampled_ms;
d_config_doppler_max = doppler_max;
d_config_doppler_min=doppler_min;
d_fft_size = d_sampled_ms * d_samples_per_ms;
// HS Acquisition
d_max_dwells= max_dwells;
d_gnuradio_forecast_samples=d_fft_size;
d_input_power = 0.0;
d_state=0;
d_disable_assist=false;
//todo: do something if posix_memalign fails
if (posix_memalign((void**)&d_carrier, 16, d_fft_size * sizeof(gr_complex)) == 0){};
if (posix_memalign((void**)&d_fft_codes, 16, d_fft_size * sizeof(gr_complex)) == 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;
}
void pcps_acquisition_fine_doppler_cc::set_doppler_step(unsigned int doppler_step)
{
d_doppler_step = doppler_step;
}
void pcps_acquisition_fine_doppler_cc::free_grid_memory()
{
for (int i=0;i<d_num_doppler_points;i++)
{
delete[] d_grid_data[i];
delete[] d_grid_doppler_wipeoffs[i];
}
delete d_grid_data;
}
pcps_acquisition_fine_doppler_cc::~pcps_acquisition_fine_doppler_cc()
{
free(d_carrier);
free(d_fft_codes);
delete d_ifft;
delete d_fft_if;
if (d_dump)
{
d_dump_file.close();
}
}
void pcps_acquisition_fine_doppler_cc::set_local_code(std::complex<float> * code)
{
memcpy(d_fft_if->get_inbuf(),code,sizeof(gr_complex)*d_fft_size);
}
void pcps_acquisition_fine_doppler_cc::init()
{
d_gnss_synchro->Acq_delay_samples = 0.0;
d_gnss_synchro->Acq_doppler_hz = 0.0;
d_gnss_synchro->Acq_samplestamp_samples = 0;
d_input_power = 0.0;
d_state=0;
d_fft_if->execute(); // We need the FFT of local code
//Conjugate the local code
volk_32fc_conjugate_32fc_a(d_fft_codes,d_fft_if->get_outbuf(),d_fft_size);
}
void pcps_acquisition_fine_doppler_cc::forecast (int noutput_items,
gr_vector_int &ninput_items_required)
{
ninput_items_required[0] = d_gnuradio_forecast_samples ; //set the required available samples in each call
}
void pcps_acquisition_fine_doppler_cc::get_assistance()
{
Gps_Acq_Assist gps_acq_assisistance;
if (global_gps_acq_assist_map.read(this->d_gnss_synchro->PRN,gps_acq_assisistance)==true)
{
//TODO: use the LO tolerance here
if (gps_acq_assisistance.dopplerUncertainty>=1000)
{
d_doppler_max=gps_acq_assisistance.d_Doppler0+gps_acq_assisistance.dopplerUncertainty*2;
d_doppler_min=gps_acq_assisistance.d_Doppler0-gps_acq_assisistance.dopplerUncertainty*2;
}else{
d_doppler_max=gps_acq_assisistance.d_Doppler0+1000;
d_doppler_min=gps_acq_assisistance.d_Doppler0-1000;
}
this->d_disable_assist=false;
std::cout<<"Acq assist ENABLED for GPS SV "<<this->d_gnss_synchro->PRN<<" (Doppler max,Doppler min)=("
<<d_doppler_max<<","<<d_doppler_min<<")"<<std::endl;
}else{
this->d_disable_assist=true;
//std::cout<<"Acq assist DISABLED for GPS SV "<<this->d_gnss_synchro->PRN<<std::endl;
}
}
void pcps_acquisition_fine_doppler_cc::reset_grid()
{
d_well_count=0;
for (int i=0;i<d_num_doppler_points;i++)
{
for (unsigned int j=0;j<d_fft_size;j++)
{
d_grid_data[i][j]=0.0;
}
}
}
void pcps_acquisition_fine_doppler_cc::redefine_grid()
{
if (this->d_disable_assist==true)
{
d_doppler_max=d_config_doppler_max;
d_doppler_min=d_config_doppler_min;
}
// Create the search grid array
d_num_doppler_points=floor(std::abs(d_doppler_max-d_doppler_min)/d_doppler_step);
d_grid_data=new float*[d_num_doppler_points];
for (int i=0;i<d_num_doppler_points;i++)
{
if (posix_memalign((void**)&d_grid_data[i], 16, d_fft_size * sizeof(float)) == 0){};
}
// create the carrier Doppler wipeoff signals
int doppler_hz;
float phase_step_rad;
d_grid_doppler_wipeoffs=new gr_complex*[d_num_doppler_points];
for (int doppler_index=0;doppler_index<d_num_doppler_points;doppler_index++)
{
doppler_hz=d_doppler_min+d_doppler_step*doppler_index;
// doppler search steps
// compute the carrier doppler wipe-off signal and store it
phase_step_rad = (float)GPS_TWO_PI*doppler_hz / (float)d_fs_in;
d_grid_doppler_wipeoffs[doppler_index]=new gr_complex[d_fft_size];
fxp_nco(d_grid_doppler_wipeoffs[doppler_index], d_fft_size,0, phase_step_rad);
}
}
double pcps_acquisition_fine_doppler_cc::search_maximum()
{
float magt = 0.0;
float fft_normalization_factor;
int index_doppler = 0;
unsigned int tmp_intex_t;
unsigned int index_time = 0;
for (int i=0;i<d_num_doppler_points;i++)
{
volk_32f_index_max_16u_a(&tmp_intex_t,d_grid_data[i],d_fft_size);
if (d_grid_data[i][tmp_intex_t] > magt)
{
magt = d_grid_data[i][index_time];
index_doppler = i;
index_time = tmp_intex_t;
}
}
// Normalize the maximum value to correct the scale factor introduced by FFTW
fft_normalization_factor = (float)d_fft_size * (float)d_fft_size;
magt = magt / (fft_normalization_factor * fft_normalization_factor);
// 5- Compute the test statistics and compare to the threshold
d_test_statistics = 2 * d_fft_size * magt /(d_input_power*d_well_count);
// 4- record the maximum peak and the associated synchronization parameters
d_gnss_synchro->Acq_delay_samples = (double)index_time;
d_gnss_synchro->Acq_doppler_hz = (double)(index_doppler*d_doppler_step+d_doppler_min);
d_gnss_synchro->Acq_samplestamp_samples = d_sample_counter;
// Record results to file if required
if (d_dump)
{
std::stringstream filename;
std::streamsize n = 2 * sizeof(float) * (d_fft_size); // complex file write
filename.str("");
filename << "../data/test_statistics_" << d_gnss_synchro->System
<<"_" << d_gnss_synchro->Signal << "_sat_"
<< d_gnss_synchro->PRN << "_doppler_" << d_gnss_synchro->Acq_doppler_hz << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out
| std::ios::binary);
d_dump_file.write((char*)d_grid_data[index_doppler], n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
}
return d_test_statistics;
}
float pcps_acquisition_fine_doppler_cc::estimate_input_power(gr_vector_const_void_star &input_items)
{
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
// 1- Compute the input signal power estimation
float* p_tmp_vector;
if (posix_memalign((void**)&p_tmp_vector, 16, d_fft_size * sizeof(float)) == 0){};
volk_32fc_magnitude_squared_32f_u(p_tmp_vector, in, d_fft_size);
const float* p_const_tmp_vector=p_tmp_vector;
float power;
volk_32f_accumulator_s32f_a(&power, p_const_tmp_vector, d_fft_size);
free(p_tmp_vector);
return ( power / (float)d_fft_size);
}
int pcps_acquisition_fine_doppler_cc::compute_and_accumulate_grid(gr_vector_const_void_star &input_items)
{
// initialize acquisition algorithm
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
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;
// 2- Doppler frequency search loop
float* p_tmp_vector;
if (posix_memalign((void**)&p_tmp_vector, 16, d_fft_size * sizeof(float)) == 0){};
for (int doppler_index=0;doppler_index<d_num_doppler_points;doppler_index++)
{
// doppler search steps
// Perform the carrier wipe-off
volk_32fc_x2_multiply_32fc_u(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_codes, d_fft_size);
// compute the inverse FFT
d_ifft->execute();
// save the grid matrix delay file
volk_32fc_magnitude_squared_32f_a(p_tmp_vector, d_ifft->get_outbuf(), d_fft_size);
const float* old_vector=d_grid_data[doppler_index];
volk_32f_x2_add_32f_u(d_grid_data[doppler_index],old_vector,p_tmp_vector,d_fft_size);
}
free(p_tmp_vector);
return d_fft_size;
}
int pcps_acquisition_fine_doppler_cc::estimate_Doppler(gr_vector_const_void_star &input_items, int available_samples)
{
//1. generate local code aligned with the acquisition code phase estimation
gr_complex *code_replica;
if (posix_memalign((void**)&code_replica, 16, d_fft_size * sizeof(gr_complex)) == 0){};
gps_l1_ca_code_gen_complex_sampled(code_replica, d_gnss_synchro->PRN, d_fs_in, 0);
int shift_index=(int)d_gnss_synchro->Acq_delay_samples;
std::cout<<"shift_index="<<shift_index<<std::endl;
//std::rotate(code_replica,code_replica+shift_index,code_replica+available_samples);
//2. Perform code wipe-off
const gr_complex *in = (const gr_complex *)input_items[0]; //Get the input samples pointer
volk_32fc_x2_multiply_32fc_u(d_fft_if->get_inbuf(), in, code_replica, d_fft_size);
// 3. Perform the FFT
d_fft_if->execute();
// 4. Compute the magnitude and find the maximum
float* p_tmp_vector;
if (posix_memalign((void**)&p_tmp_vector, 16, d_fft_size * sizeof(float)) == 0){};
volk_32fc_magnitude_squared_32f_a(p_tmp_vector, d_fft_if->get_outbuf(), d_fft_size);
unsigned int tmp_index_freq;
volk_32f_index_max_16u_a(&tmp_index_freq,p_tmp_vector,d_fft_size);
float fftFreqBins[d_fft_size];
float curr_normal_freq=-1.0;
for (unsigned int i=0;i<d_fft_size;i++)
{
fftFreqBins[i]=(d_fs_in/2.0)*curr_normal_freq;
curr_normal_freq+=2/d_fft_size;
}
std::stringstream filename;
std::streamsize n = sizeof(gr_complex) * (d_fft_size);
filename.str("");
filename << "../data/code_prn_" << d_gnss_synchro->PRN << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out
| std::ios::binary);
d_dump_file.write((char*)code_replica, n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
filename.str("");
filename << "../data/signal_prn_" << d_gnss_synchro->PRN << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out
| std::ios::binary);
d_dump_file.write((char*)in, n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
n = sizeof(float) * (d_fft_size);
filename.str("");
filename << "../data/fft_prn_" << d_gnss_synchro->PRN << ".dat";
d_dump_file.open(filename.str().c_str(), std::ios::out
| std::ios::binary);
d_dump_file.write((char*)p_tmp_vector, n); //write directly |abs(x)|^2 in this Doppler bin?
d_dump_file.close();
std::cout<<"FFT maximum present at "<<fftFreqBins[tmp_index_freq]<<" [Hz]"<<std::endl;
return d_fft_size;
}
int pcps_acquisition_fine_doppler_cc::general_work(int noutput_items,
gr_vector_int &ninput_items, gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
/*!
* TODO: High sensitivity acquisition algorithm:
* State Mechine:
* S0. StandBy. If d_active==1 -> S1
* S1. GetAssist. Define search grid with assistance information. Reset grid matrix -> S2
* S2. ComputeGrid. Perform the FFT acqusition doppler and delay grid.
* Accumulate the search grid matrix (#doppler_bins x #fft_size)
* Compare maximum to threshold and decide positive or negative
* If T>=gamma -> S4 else
* If d_well_count<max_dwells -> S2
* else if !disable_assist -> S3
* else -> S5.
* S3. RedefineGrid. Open the grid search to unasisted acquisition. Reset counters and grid. -> S2
* S4. Positive_Acq: Send message and stop acq -> S0
* S5. Negative_Acq: Send message and stop acq -> S0
*/
switch (d_state)
{
case 0: // S0. StandBy
if (d_active==true) d_state=1;
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
case 1: // S1. GetAssist
get_assistance();
redefine_grid();
reset_grid();
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
d_state=2;
break;
case 2: // S2. ComputeGrid
int consumed_samples;
consumed_samples=compute_and_accumulate_grid(input_items);
d_well_count++;
if (d_well_count>=d_max_dwells)
{
d_state=3;
}
d_sample_counter+=consumed_samples;
consume_each(consumed_samples);
break;
case 3: // Compute test statistics and decide
d_input_power=estimate_input_power(input_items);
d_test_statistics=search_maximum();
if (d_test_statistics > d_threshold)
{
d_state=5; //perform fine doppler estimation
}else{
if (d_disable_assist==false)
{
d_disable_assist=true;
//std::cout<<"Acq assist DISABLED for GPS SV "<<this->d_gnss_synchro->PRN<<std::endl;
d_state=4;
}else{
d_state=7; //negative acquisition
}
}
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
break;
case 4: // RedefineGrid
free_grid_memory();
redefine_grid();
reset_grid();
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
d_state=2;
break;
case 5: // Fine doppler estimation
DLOG(INFO) << "Performing fine Doppler estimation";
//estimate_Doppler(input_items, ninput_items[0]); //disabled in repo
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
d_state=6;
break;
case 6: // Positive_Acq
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) << "input signal power " << d_input_power;
d_active = false;
// Send message to channel queue //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
d_channel_internal_queue->push(1); // 1-> positive acquisition
free_grid_memory();
// consume samples to not block the GNU Radio flowgraph
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
d_state=0;
break;
case 7: // Negative_Acq
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) << "input signal power " << d_input_power;
d_active = false;
// Send message to channel queue //0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
d_channel_internal_queue->push(2); // 2-> negative acquisition
free_grid_memory();
// consume samples to not block the GNU Radio flowgraph
d_sample_counter += ninput_items[0]; // sample counter
consume_each(ninput_items[0]);
d_state=0;
break;
default:
d_state=0;
break;
}
return 0;
}

View File

@ -0,0 +1,246 @@
/*!
* \file pcps_assisted_acquisition_cc.h
* \brief This class implements a Parallel Code Phase Search Acquisition with multi-dwells and fine Doppler estimation
*
* Acquisition strategy (Kay Borre book + CFAR threshold).
* <ol>
* <li> Compute the input signal power estimation
* <li> Doppler serial search loop
* <li> Perform the FFT-based circular convolution (parallel time search)
* <li> Record the maximum peak and the associated synchronization parameters
* <li> Compute the test statistics and compare to the threshold
* <li> Declare positive or negative acquisition using a message queue
* </ol>
*
* Kay Borre book: K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
* "A Software-Defined GPS and Galileo Receiver. A Single-Frequency
* Approach", Birkha user, 2007. pp 81-84
*
* \authors <ul>
* <li> Javier Arribas, 2013. jarribas(at)cttc.es
* </ul>
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (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_PCPS_acquisition_fine_doppler_cc_H_
#define GNSS_SDR_PCPS_acquisition_fine_doppler_cc_H_
#include <fstream>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
#include <gnuradio/gr_complex.h>
#include <gnuradio/fft/fft.h>
#include <queue>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include "concurrent_queue.h"
#include "gnss_synchro.h"
class pcps_acquisition_fine_doppler_cc;
typedef boost::shared_ptr<pcps_acquisition_fine_doppler_cc>
pcps_acquisition_fine_doppler_cc_sptr;
pcps_acquisition_fine_doppler_cc_sptr
pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long freq, long fs_in, int samples_per_ms,
boost::shared_ptr<gr::msg_queue> 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 pcps_acquisition_fine_doppler_cc: public gr::block
{
private:
friend pcps_acquisition_fine_doppler_cc_sptr
pcps_make_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long freq, long fs_in,
int samples_per_ms, boost::shared_ptr<gr::msg_queue> queue, bool dump,
std::string dump_filename);
pcps_acquisition_fine_doppler_cc(int max_dwells, unsigned int sampled_ms,
int doppler_max, int doppler_min, long freq, long fs_in,
int samples_per_ms, boost::shared_ptr<gr::msg_queue> queue, bool dump,
std::string dump_filename);
void calculate_magnitudes(gr_complex* fft_begin, int doppler_shift,
int doppler_offset);
int compute_and_accumulate_grid(gr_vector_const_void_star &input_items);
int estimate_Doppler(gr_vector_const_void_star &input_items, int available_samples);
float estimate_input_power(gr_vector_const_void_star &input_items);
double search_maximum();
void get_assistance();
void reset_grid();
void redefine_grid();
void free_grid_memory();
long d_fs_in;
long d_freq;
int d_samples_per_ms;
int d_max_dwells;
unsigned int d_doppler_resolution;
int d_gnuradio_forecast_samples;
float d_threshold;
std::string d_satellite_str;
int d_doppler_max;
int d_doppler_min;
int d_config_doppler_max;
int d_config_doppler_min;
int d_num_doppler_points;
int d_doppler_step;
unsigned int d_sampled_ms;
unsigned int d_fft_size;
unsigned long int d_sample_counter;
gr_complex* d_carrier;
gr_complex* d_fft_codes;
float** d_grid_data;
gr_complex** d_grid_doppler_wipeoffs;
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_input_power;
float d_test_statistics;
boost::shared_ptr<gr::msg_queue> d_queue;
concurrent_queue<int> *d_channel_internal_queue;
std::ofstream d_dump_file;
int d_state;
bool d_active;
bool d_disable_assist;
int d_well_count;
bool d_dump;
unsigned int d_channel;
std::string d_dump_filename;
public:
/*!
* \brief Default destructor.
*/
~pcps_acquisition_fine_doppler_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_test_statistics;
}
/*!
* \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);
/*!
* \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);
void forecast (int noutput_items, gr_vector_int &ninput_items_required);
};
#endif /* pcps_acquisition_fine_doppler_cc*/

View File

@ -46,4 +46,4 @@ include_directories(
)
add_library(gnss_sp_libs ${GNSS_SPLIBS_SOURCES})
target_link_libraries(gnss_sp_libs ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FFT_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES})
target_link_libraries(gnss_sp_libs ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FFT_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} gnss_rx)

View File

@ -60,7 +60,9 @@ RtlsdrSignalSource::RtlsdrSignalSource(ConfigurationInterface* configuration,
// RTLSDR Driver parameters
AGC_enabled_ = configuration->property(role + ".AGC_enabled",true);
freq_ = configuration->property(role + ".freq", GPS_L1_FREQ_HZ);
gain_ = configuration->property(role + ".gain", (double)50.0);
gain_ = configuration->property(role + ".gain", (double)40.0);
rf_gain_ = configuration->property(role + ".rf_gain", (double)40.0);
if_gain_ = configuration->property(role + ".if_gain", (double)40.0);
sample_rate_ = configuration->property(role + ".sampling_frequency", (double)2.0e6);
item_type_ = configuration->property(role + ".item_type", default_item_type);
@ -98,7 +100,9 @@ RtlsdrSignalSource::RtlsdrSignalSource(ConfigurationInterface* configuration,
else
{
rtlsdr_source_->set_gain_mode(false);
rtlsdr_source_->set_gain(gain_);
rtlsdr_source_->set_gain(gain_,0);
rtlsdr_source_->set_if_gain(rf_gain_,0);
rtlsdr_source_->set_bb_gain(if_gain_,0);
std::cout << boost::format("Actual RX Gain: %f dB...") % rtlsdr_source_->get_gain() << std::endl;
LOG(INFO) << boost::format("Actual RX Gain: %f dB...") % rtlsdr_source_->get_gain();
}

View File

@ -87,6 +87,8 @@ private:
double freq_;
double gain_;
double if_gain_;
double rf_gain_;
std::string item_type_;
size_t item_size_;

View File

@ -484,10 +484,10 @@ void ControlThread::gps_utc_model_data_collector()
if (global_gps_utc_model_map.read(0,gps_utc_old))
{
// TODO: Check the UTC MODEL timestamp. If it is newer, then update the UTC MODEL
global_gps_utc_model_map.write(0,gps_utc_old);
global_gps_utc_model_map.write(0,gps_utc);
}else{
// insert new ephemeris record
global_gps_utc_model_map.write(0,gps_utc_old);
global_gps_utc_model_map.write(0,gps_utc);
}
}
}

19
src/utils/CMakeLists.txt Normal file
View File

@ -0,0 +1,19 @@
# Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
#
# 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/>.
#
add_subdirectory(front-end-cal)

View File

@ -0,0 +1,52 @@
# Copyright (C) 2012-2013 (see AUTHORS file for a list of contributors)
#
# 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/>.
#
set(FRONT_END_CAL_SOURCES
front_end_cal.cc
)
include_directories(
${CMAKE_SOURCE_DIR}/src/core/system_parameters
${CMAKE_SOURCE_DIR}/src/core/interfaces
${CMAKE_SOURCE_DIR}/src/core/receiver
${CMAKE_SOURCE_DIR}/src/core/libs
${CMAKE_SOURCE_DIR}/src/core/libs/supl
${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-rrlp
${CMAKE_SOURCE_DIR}/src/core/libs/supl/asn-supl
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/adapters
${CMAKE_SOURCE_DIR}/src/algorithms/acquisition/gnuradio_blocks
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}
${GNURADIO_CORE_INCLUDE_DIRS}
${GNURADIO_GRUEL_INCLUDE_DIRS}
${ARMADILLO_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
)
add_library(front_end_cal_lib ${FRONT_END_CAL_SOURCES})
target_link_libraries(front_end_cal_lib ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FFT_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${ARMADILLO_LIBRARIES} gnss_rx gnss_sp_libs)
add_definitions( -DGNSS_SDR_VERSION="${VERSION}" )
add_executable(front-end-cal ${CMAKE_CURRENT_SOURCE_DIR}/main.cc)
target_link_libraries(front-end-cal ${Boost_LIBRARIES} ${GNURADIO_RUNTIME_LIBRARIES} ${GNURADIO_BLOCKS_LIBRARIES} ${GNURADIO_FFT_LIBRARIES} ${GNURADIO_FILTER_LIBRARIES} ${GFlags_LIBS} ${GLOG_LIBRARIES} ${ARMADILLO_LIBRARIES} gnss_rx gnss_sp_libs front_end_cal_lib)
install(TARGETS front-end-cal
DESTINATION ${CMAKE_SOURCE_DIR}/install
)

View File

@ -0,0 +1,417 @@
#include <exception>
#include <boost/filesystem.hpp>
#include <gflags/gflags.h>
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/lexical_cast.hpp>
#include "file_configuration.h"
#include "gps_navigation_message.h"
#include "gps_ephemeris.h"
#include "gps_almanac.h"
#include "gps_iono.h"
#include "gps_utc_model.h"
#include "gnss_sdr_supl_client.h"
#include <sys/time.h>
#include <ctime>
#include <memory>
#include <math.h>
#include "front_end_cal.h"
extern concurrent_map<Gps_Ephemeris> global_gps_ephemeris_map;
extern concurrent_map<Gps_Iono> global_gps_iono_map;
extern concurrent_map<Gps_Utc_Model> global_gps_utc_model_map;
extern concurrent_map<Gps_Almanac> global_gps_almanac_map;
extern concurrent_map<Gps_Acq_Assist> global_gps_acq_assist_map;
FrontEndCal::FrontEndCal()
{
}
FrontEndCal::~FrontEndCal()
{
}
bool FrontEndCal::read_assistance_from_XML()
{
gnss_sdr_supl_client supl_client_ephemeris_;
std::string eph_xml_filename="gps_ephemeris.xml";
std::cout<< "SUPL: Try read GPS ephemeris from XML file "<<eph_xml_filename<<std::endl;
if (supl_client_ephemeris_.load_ephemeris_xml(eph_xml_filename)==true)
{
std::map<int,Gps_Ephemeris>::iterator gps_eph_iter;
for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin();
gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end();
gps_eph_iter++)
{
std::cout<<"SUPL: Read XML Ephemeris for GPS SV "<<gps_eph_iter->first<<std::endl;
std::cout << "New Ephemeris record inserted with Toe="<<gps_eph_iter->second.d_Toe<<" and GPS Week="<<gps_eph_iter->second.i_GPS_week<<std::endl;
global_gps_ephemeris_map.write(gps_eph_iter->second.i_satellite_PRN,gps_eph_iter->second);
}
return true;
}else{
std::cout<< "ERROR: SUPL client error reading XML"<<std::endl;
return false;
}
}
int FrontEndCal::Get_SUPL_Assist()
{
//#########GNSS Asistence #################################
gnss_sdr_supl_client supl_client_acquisition_;
gnss_sdr_supl_client supl_client_ephemeris_;
int supl_mcc; // Current network MCC (Mobile country code), 3 digits.
int supl_mns; //Current network MNC (Mobile Network code), 2 or 3 digits.
int supl_lac; // Current network LAC (Location area code),16 bits, 1-65520 are valid values.
int supl_ci; // Cell Identity (16 bits, 0-65535 are valid values).
// GNSS Assistance configuration
int error=0;
bool enable_gps_supl_assistance=configuration_->property("GNSS-SDR.SUPL_gps_enabled",false);
if (enable_gps_supl_assistance==true)
//SUPL SERVER TEST. Not operational yet!
{
DLOG(INFO) << "SUPL RRLP GPS assistance enabled!"<<std::endl;
std::string default_acq_server="supl.nokia.com";
std::string default_eph_server="supl.google.com";
supl_client_ephemeris_.server_name=configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_server",default_acq_server);
supl_client_acquisition_.server_name=configuration_->property("GNSS-SDR.SUPL_gps_acquisition_server",default_eph_server);
supl_client_ephemeris_.server_port=configuration_->property("GNSS-SDR.SUPL_gps_ephemeris_port",7275);
supl_client_acquisition_.server_port=configuration_->property("GNSS-SDR.SUPL_gps_acquisition_port",7275);
supl_mcc=configuration_->property("GNSS-SDR.SUPL_MCC",244);
supl_mns=configuration_->property("GNSS-SDR.SUPL_MNS",5);
std::string default_lac="0x59e2";
std::string default_ci="0x31b0";
try {
supl_lac = boost::lexical_cast<int>(configuration_->property("GNSS-SDR.SUPL_LAC",default_lac));
} catch(boost::bad_lexical_cast &) {
supl_lac=0x59e2;
}
try {
supl_ci = boost::lexical_cast<int>(configuration_->property("GNSS-SDR.SUPL_CI",default_ci));
} catch(boost::bad_lexical_cast &) {
supl_ci=0x31b0;
}
bool SUPL_read_gps_assistance_xml=configuration_->property("GNSS-SDR.SUPL_read_gps_assistance_xml",false);
if (SUPL_read_gps_assistance_xml==true)
{
// read assistance from file
read_assistance_from_XML();
}else{
// Request ephemeris from SUPL server
supl_client_ephemeris_.request=1;
DLOG(INFO) << "SUPL: Try read GPS ephemeris from SUPL server.."<<std::endl;
error=supl_client_ephemeris_.get_assistance(supl_mcc,supl_mns,supl_lac,supl_ci);
if (error==0)
{
std::map<int,Gps_Ephemeris>::iterator gps_eph_iter;
for(gps_eph_iter = supl_client_ephemeris_.gps_ephemeris_map.begin();
gps_eph_iter != supl_client_ephemeris_.gps_ephemeris_map.end();
gps_eph_iter++)
{
DLOG(INFO) <<"SUPL: Received Ephemeris for GPS SV "<<gps_eph_iter->first<<std::endl;
DLOG(INFO) << "New Ephemeris record inserted with Toe="<<gps_eph_iter->second.d_Toe<<" and GPS Week="<<gps_eph_iter->second.i_GPS_week<<std::endl;
global_gps_ephemeris_map.write(gps_eph_iter->second.i_satellite_PRN,gps_eph_iter->second);
}
//Save ephemeris to XML file
std::string eph_xml_filename="gps_ephemeris.xml";
if (supl_client_ephemeris_.save_ephemeris_xml(eph_xml_filename)==true)
{
DLOG(INFO) <<"SUPL: XML Ephemeris file created"<<std::endl;
}
}else{
DLOG(INFO) << "ERROR: SUPL client for Ephemeris returned "<<error<<std::endl;
DLOG(INFO) << "Please check internet connection and SUPL server configuration"<<error<<std::endl;
}
// Request almanac , IONO and UTC Model
supl_client_ephemeris_.request=0;
DLOG(INFO) << "SUPL: Try read Almanac, Iono, Utc Model, Ref Time and Ref Location from SUPL server.."<<std::endl;
error=supl_client_ephemeris_.get_assistance(supl_mcc,supl_mns,supl_lac,supl_ci);
if (error==0)
{
std::map<int,Gps_Almanac>::iterator gps_alm_iter;
for(gps_alm_iter = supl_client_ephemeris_.gps_almanac_map.begin();
gps_alm_iter != supl_client_ephemeris_.gps_almanac_map.end();
gps_alm_iter++)
{
DLOG(INFO) <<"SUPL: Received Almanac for GPS SV "<<gps_alm_iter->first<<std::endl;
global_gps_almanac_map.write(gps_alm_iter->first,gps_alm_iter->second);
}
if (supl_client_ephemeris_.gps_iono.valid==true)
{
DLOG(INFO) <<"SUPL: Received GPS Iono"<<std::endl;
global_gps_iono_map.write(0,supl_client_ephemeris_.gps_iono);
}
if (supl_client_ephemeris_.gps_utc.valid==true)
{
DLOG(INFO) <<"SUPL: Received GPS UTC Model"<<std::endl;
global_gps_utc_model_map.write(0,supl_client_ephemeris_.gps_utc);
}
}else{
DLOG(INFO) << "ERROR: SUPL client for Almanac returned "<<error<<std::endl;
DLOG(INFO) << "Please check internet connection and SUPL server configuration"<<error<<std::endl;
}
// Request acquisition assistance
supl_client_acquisition_.request=2;
DLOG(INFO) << "SUPL: Try read Acquisition assistance from SUPL server.."<<std::endl;
error=supl_client_acquisition_.get_assistance(supl_mcc,supl_mns,supl_lac,supl_ci);
if (error==0)
{
std::map<int,Gps_Acq_Assist>::iterator gps_acq_iter;
for(gps_acq_iter = supl_client_acquisition_.gps_acq_map.begin();
gps_acq_iter != supl_client_acquisition_.gps_acq_map.end();
gps_acq_iter++)
{
DLOG(INFO) <<"SUPL: Received Acquisition assistance for GPS SV "<<gps_acq_iter->first<<std::endl;
DLOG(INFO) << "New acq assist record inserted"<<std::endl;
global_gps_acq_assist_map.write(gps_acq_iter->second.i_satellite_PRN,gps_acq_iter->second);
}
}else{
DLOG(INFO) << "ERROR: SUPL client for Acquisition assistance returned "<<error<<std::endl;
DLOG(INFO) << "Please check internet connection and SUPL server configuration"<<error<<std::endl;
}
}
}
return error;
}
void FrontEndCal::set_configuration(ConfigurationInterface *configuration)
{
configuration_= configuration;
}
void FrontEndCal::get_ephemeris()
{
bool read_ephemeris_from_xml=configuration_->property("GNSS-SDR.read_eph_from_xml",false);
if (read_ephemeris_from_xml==true)
{
std::cout<< "Trying to read ephemeris from XML file"<<std::endl;
if (read_assistance_from_XML()==false)
{
std::cout<< "ERROR: Could not read Ephemeris file: Trying to get ephemeris from SUPL client.."<<std::endl;
Get_SUPL_Assist();
}
}else{
std::cout<< "Trying to read ephemeris from SUPL server"<<std::endl;
Get_SUPL_Assist();
}
}
arma::vec FrontEndCal::lla2ecef(arma::vec lla)
{
// % LLA2ECEF Convert geodetic coordinates to Earth-centered Earth-fixed
// % (ECEF) coordinates.
// % P = LLA2ECEF( LLA ) converts an M-by-3 array of geodetic coordinates
// % (latitude, longitude and altitude), LLA, to an M-by-3 array of ECEF
// % coordinates, P. LLA is in [degrees degrees meters]. P is in meters.
// % The default ellipsoid planet is WGS84.
// WGS84 flattening
double f;
f = 1/298.257223563;
// WGS84 equatorial radius
double R;
R = 6378137;
double phi,lambda;
arma::vec ellipsoid="0.0 0.0";
phi=(lla(0)/360.0)*GPS_TWO_PI;
lambda=(lla(1)/360.0)*GPS_TWO_PI;
ellipsoid(0)=R;
ellipsoid(1)=sqrt(1-(1-f)*(1-f));
arma::vec ecef="0.0 0.0 0.0 0.0";
ecef = geodetic2ecef(phi, lambda,lla(3),ellipsoid);
return ecef;
}
arma::vec FrontEndCal::geodetic2ecef(double phi, double lambda, double h, arma::vec ellipsoid)
{
//%GEODETIC2ECEF Convert geodetic to geocentric (ECEF) coordinates
//%
//% [X, Y, Z] = GEODETIC2ECEF(PHI, LAMBDA, H, ELLIPSOID) converts geodetic
//% point locations specified by the coordinate arrays PHI (geodetic
//% latitude in radians), LAMBDA (longitude in radians), and H (ellipsoidal
//% height) to geocentric Cartesian coordinates X, Y, and Z. The geodetic
//% coordinates refer to the reference ellipsoid specified by ELLIPSOID (a
//% row vector with the form [semimajor axis, eccentricity]). H must use
//% the same units as the semimajor axis; X, Y, and Z will be expressed in
//% these units also.
//%
//% The geocentric Cartesian coordinate system is fixed with respect to the
//% Earth, with its origin at the center of the ellipsoid and its X-, Y-,
//% and Z-axes intersecting the surface at the following points:
//%
//% PHI LAMBDA
//% X-axis: 0 0 (Equator at the Prime Meridian)
//% Y-axis: 0 pi/2 (Equator at 90-degrees East)
//% Z-axis: pi/2 0 (North Pole)
//%
//% A common synonym is Earth-Centered, Earth-Fixed coordinates, or ECEF.
//%
//% See also ECEF2GEODETIC, ECEF2LV, GEODETIC2GEOCENTRICLAT, LV2ECEF.
//% Copyright 2004-2009 The MathWorks, Inc.
//% $Revision: 1.1.6.4 $ $Date: 2009/04/15 23:34:46 $
//% Reference
//% ---------
//% Paul R. Wolf and Bon A. Dewitt, "Elements of Photogrammetry with
//% Applications in GIS," 3rd Ed., McGraw-Hill, 2000 (Appendix F-3).
double a;
a = ellipsoid(0);
double e2;
e2 = ellipsoid(1)*ellipsoid(1);
double sinphi,cosphi;
sinphi = sin(phi);
cosphi = cos(phi);
double N;
N = a / sqrt(1 - e2 * sinphi*sinphi);
arma::vec ecef="0.0 0.0 0.0 0.0";
ecef(0) = (N + h) * cosphi * cos(lambda);
ecef(1) = (N + h) * cosphi * sin(lambda);
ecef(2)= (N*(1 - e2) + h) * sinphi;
return ecef;
}
double FrontEndCal::estimate_doppler_from_eph(unsigned int PRN, double TOW, double lat, double lon, double height)
{
int num_secs=10;
double step_secs=0.5;
//Observer position ECEF
arma::vec obs_ecef= "0.0 0.0 0.0 0.0";
arma::vec lla = "0.0 0.0 0.0 0.0";
lla(0)=lat;
lla(1)=lon;
lla(2)=height;
obs_ecef=lla2ecef(lla);
//Satellite positions ECEF
std::map<int,Gps_Ephemeris> eph_map;
eph_map=global_gps_ephemeris_map.get_map_copy();
std::map<int,Gps_Ephemeris>::iterator eph_it;
eph_it=eph_map.find(PRN);
if (eph_it!=eph_map.end())
{
arma::vec SV_pos_ecef = "0.0 0.0 0.0 0.0";
double obs_time_start,obs_time_stop;
obs_time_start=TOW-num_secs/2;
obs_time_stop=TOW+num_secs/2;
int n_points=round((obs_time_stop-obs_time_start)/step_secs);
arma::vec ranges=arma::zeros(n_points,1);
double obs_time=obs_time_start;
for (int i=0;i<n_points;i++)
{
eph_it->second.satellitePosition(obs_time);
SV_pos_ecef(0)=eph_it->second.d_satpos_X;
SV_pos_ecef(1)=eph_it->second.d_satpos_Y;
SV_pos_ecef(2)=eph_it->second.d_satpos_Z;
// SV distances to observer (true range)
ranges(i)=arma::norm(SV_pos_ecef-obs_ecef,2);
obs_time+=step_secs;
}
//Observer to satellite radial velocity
//Numeric derivative: Positive slope means that the distance from obs to
//satellite is increasing
arma::vec obs_to_sat_velocity;
obs_to_sat_velocity=(ranges.subvec(1,(n_points-1))-ranges.subvec(0,(n_points-2)))/step_secs;
//Doppler equations are formulated accounting for positive velocities if the
//tx and rx are aproaching to each other. So, the satellite velocity must
//be redefined as:
obs_to_sat_velocity=-obs_to_sat_velocity;
//Doppler estimation
arma::vec Doppler_Hz;
Doppler_Hz=(obs_to_sat_velocity/GPS_C_m_s)*GPS_L1_FREQ_HZ;
double mean_Doppler_Hz;
mean_Doppler_Hz=arma::mean(Doppler_Hz);
return mean_Doppler_Hz;
return 0;
}else{
throw(1);
}
}
void FrontEndCal::GPS_L1_front_end_model_E4000(double f_bb_true_Hz,double f_bb_meas_Hz,double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm )
{
// % Inputs:
// % f_bb_true_Hz - Ideal output frequency in baseband [Hz]
// % f_in_bb_meas_Hz - measured output frequency in baseband [Hz]
// %
// % Outputs:
// % estimated_fs_Hz - Sampling frequency estimation based on the
// % measurements and the front-end model
// % estimated_f_if_bb_Hz - Equivalent bb if frequency estimation based on the
// % measurements and the front-end model
// Front-end TUNNER Elonics E4000 + RTL2832 sampler
//For GPS L1 1575.42 MHz
double f_osc_n=28.8e6;
//PLL registers settings (according to E4000 datasheet)
double N=109;
double Y=65536;
double X=26487;
double R=2;
// Obtained RF center frequency
double f_rf_pll;
f_rf_pll=(f_osc_n*(N+X/Y))/R;
// RF frequency error caused by fractional PLL roundings
double f_bb_err_pll;
f_bb_err_pll=GPS_L1_FREQ_HZ-f_rf_pll;
// Measured F_rf error
double f_rf_err;
f_rf_err=(f_bb_meas_Hz-f_bb_true_Hz)-f_bb_err_pll;
double f_osc_err_hz;
f_osc_err_hz=(f_rf_err*R)/(N+X/Y);
// OJO,segun los datos gnss, la IF positiva hace disminuir la fs!!
f_osc_err_hz=-f_osc_err_hz;
*f_osc_err_ppm=f_osc_err_hz/(f_osc_n/1e6);
double frac;
frac=fs_nominal_hz/f_osc_n;
*estimated_fs_Hz=frac*(f_osc_n+f_osc_err_hz);
*estimated_f_if_Hz=f_rf_err;
}

View File

@ -0,0 +1,20 @@
#include "concurrent_map.h"
#include "armadillo"
class FrontEndCal
{
private:
ConfigurationInterface *configuration_;
arma::vec lla2ecef(arma::vec lla);
arma::vec geodetic2ecef(double phi, double lambda, double h, arma::vec ellipsoid);
public:
bool read_assistance_from_XML();
int Get_SUPL_Assist();
void set_configuration(ConfigurationInterface *configuration);
void get_ephemeris();
double estimate_doppler_from_eph(unsigned int PRN, double TOW, double lat, double lon, double height);
void GPS_L1_front_end_model_E4000(double f_bb_true_Hz,double f_bb_meas_Hz,double fs_nominal_hz, double *estimated_fs_Hz, double *estimated_f_if_Hz, double *f_osc_err_ppm );
FrontEndCal();
~FrontEndCal();
};

View File

@ -0,0 +1,435 @@
/*!
* \file main.cc
* \brief Main file of the Front-end calibration program.
* \author Javier Arribas, 2013. jarribas(at)cttc.es
*
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (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 FRONT_END_CAL_VERSION
#define FRONT_END_CAL_VERSION "0.0.1"
#endif
#include <exception>
#include <boost/filesystem.hpp>
#include <gflags/gflags.h>
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <gnuradio/msg_queue.h>
#include <gnuradio/top_block.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/blocks/head.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/file_sink.h>
#include <queue>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <vector>
#include "concurrent_map.h"
#include "file_configuration.h"
#include "gps_l1_ca_pcps_acquisition_fine_doppler.h"
#include "gnss_signal.h"
#include "gnss_synchro.h"
#include "gnss_block_factory.h"
#include "gps_navigation_message.h"
#include "gps_ephemeris.h"
#include "gps_almanac.h"
#include "gps_iono.h"
#include "gps_utc_model.h"
#include "gnss_sdr_supl_client.h"
#include <sys/time.h>
#include <ctime>
#include <memory>
#include "front_end_cal.h"
using google::LogMessage;
DECLARE_string(log_dir);
DEFINE_string(config_file, "../conf/gnss-sdr.conf",
"Path to the file containing the configuration parameters");
concurrent_queue<Gps_Ephemeris> global_gps_ephemeris_queue;
concurrent_queue<Gps_Iono> global_gps_iono_queue;
concurrent_queue<Gps_Utc_Model> global_gps_utc_model_queue;
concurrent_queue<Gps_Almanac> global_gps_almanac_queue;
concurrent_queue<Gps_Acq_Assist> global_gps_acq_assist_queue;
concurrent_map<Gps_Ephemeris> global_gps_ephemeris_map;
concurrent_map<Gps_Iono> global_gps_iono_map;
concurrent_map<Gps_Utc_Model> global_gps_utc_model_map;
concurrent_map<Gps_Almanac> global_gps_almanac_map;
concurrent_map<Gps_Acq_Assist> global_gps_acq_assist_map;
bool stop;
concurrent_queue<int> channel_internal_queue;
GpsL1CaPcpsAcquisitionFineDoppler *acquisition;
Gnss_Synchro *gnss_synchro;
std::vector<Gnss_Synchro> gnss_sync_vector;
void wait_message()
{
while (!stop)
{
int message;
channel_internal_queue.wait_and_pop(message);
//std::cout<<"Acq mesage rx="<<message<<std::endl;
switch (message)
{
case 1: // Positive acq
gnss_sync_vector.push_back(*gnss_synchro);
acquisition->reset();
break;
case 2: // negative acq
acquisition->reset();
break;
case 3:
stop=true;
break;
default:
break;
}
}
}
bool front_end_capture(ConfigurationInterface *configuration)
{
gr::top_block_sptr top_block;
GNSSBlockFactory block_factory;
boost::shared_ptr<gr::msg_queue> queue;
queue = gr::msg_queue::make(0);
top_block = gr::make_top_block("Acquisition test");
GNSSBlockInterface *source;
source=block_factory.GetSignalSource(configuration, queue);
GNSSBlockInterface *conditioner;
conditioner=block_factory.GetSignalConditioner(configuration,queue);
gr::block_sptr sink;
sink = gr::blocks::file_sink::make(sizeof(gr_complex), "tmp_capture.dat");
//--- Find number of samples per spreading code ---
long fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
int samples_per_code = round(fs_in_
/ (GPS_L1_CA_CODE_RATE_HZ / GPS_L1_CA_CODE_LENGTH_CHIPS));
int nsamples=samples_per_code*50;
int skip_samples=fs_in_; // skip 5 seconds
gr::block_sptr head = gr::blocks::head::make(sizeof(gr_complex), nsamples);
gr::block_sptr skiphead = gr::blocks::skiphead::make(sizeof(gr_complex), skip_samples);
try{
source->connect(top_block);
conditioner->connect(top_block);
top_block->connect(source->get_right_block(), 0, conditioner->get_left_block(), 0);
top_block->connect(conditioner->get_right_block(), 0, skiphead, 0);
top_block->connect(skiphead, 0,head, 0);
top_block->connect(head, 0, sink, 0);
top_block->run();
}catch(std::exception& e)
{
std::cout<<"Failure connecting the GNU Radio blocks "<<e.what()<<std::endl;
return false;
}
delete conditioner;
delete source;
return true;
}
int main(int argc, char** argv)
{
const std::string intro_help(
std::string("\n RTL-SDR E4000 RF fornt-end center frequency and sampling rate calibration tool that uses GPS signals\n")
+
"Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)\n"
+
"This program comes with ABSOLUTELY NO WARRANTY;\n"
+
"See COPYING file to see a copy of the General Public License\n \n");
google::SetUsageMessage(intro_help);
google::SetVersionString(FRONT_END_CAL_VERSION);
google::ParseCommandLineFlags(&argc, &argv, true);
std::cout << "Initializing... Please wait." << std::endl;
google::InitGoogleLogging(argv[0]);
if (FLAGS_log_dir.empty())
{
std::cout << "Logging will be done at "
<< "/tmp"
<< std::endl
<< "Use gnss-sdr --log_dir=/path/to/log to change that."
<< std::endl;
}
else
{
const boost::filesystem::path p (FLAGS_log_dir);
if (!boost::filesystem::exists(p))
{
std::cout << "The path "
<< FLAGS_log_dir
<< " does not exist, attempting to create it"
<< std::endl;
boost::filesystem::create_directory(p);
}
std::cout << "Logging with be done at "
<< FLAGS_log_dir << std::endl;
}
// 0. Instantiate the FrontEnd Calibration class
FrontEndCal front_end_cal;
// 1. Load configuration parameters from config file
ConfigurationInterface *configuration;
configuration= new FileConfiguration(FLAGS_config_file);
front_end_cal.set_configuration(configuration);
// Capture file
if (front_end_capture(configuration))
{
std::cout<<"Front-end RAW samples captured"<<std::endl;
}else{
std::cout<<"Failure capturing front-end samples"<<std::endl;
}
// 3. Setup GNU Radio flowgraph (RTL-SDR -> Acquisition_10m)
gr::top_block_sptr top_block;
boost::shared_ptr<gr::msg_queue> queue;
queue = gr::msg_queue::make(0);
top_block = gr::make_top_block("Acquisition test");
// Satellite signal definition
gnss_synchro=new Gnss_Synchro();
gnss_synchro->Channel_ID=0;
gnss_synchro->System = 'G';
std::string signal = "1C";
signal.copy(gnss_synchro->Signal,2,0);
gnss_synchro->PRN=1;
long fs_in_ = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
GNSSBlockFactory block_factory;
acquisition = new GpsL1CaPcpsAcquisitionFineDoppler(configuration, "Acquisition", 1, 1, queue);
acquisition->set_channel(1);
acquisition->set_gnss_synchro(gnss_synchro);
acquisition->set_channel_queue(&channel_internal_queue);
acquisition->set_threshold(configuration->property("Acquisition.threshold", 0.0));
acquisition->set_doppler_max(configuration->property("Acquisition.doppler_max", 10000));
acquisition->set_doppler_step(configuration->property("Acquisition.doppler_step", 250));
gr::block_sptr source;
source = gr::blocks::file_source::make(sizeof(gr_complex), "tmp_capture.dat");
//gr_basic_block_sptr head = gr_make_head(sizeof(gr_complex), nsamples);
//gr_head_sptr head_sptr = boost::dynamic_pointer_cast<gr_head>(head);
//head_sptr->set_length(nsamples);
//head_sptr->reset();
try{
acquisition->connect(top_block);
top_block->connect(source, 0, acquisition->get_left_block(), 0);
}catch(std::exception& e)
{
std::cout<<"Failure connecting the GNU Radio blocks "<<std::endl;
}
// 4. Run the flowgraph
std::map<int,double> doppler_measurements_map;
std::map<int,double> cn0_measurements_map;
boost::thread ch_thread;
// record startup time
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
bool start_msg=true;
for (unsigned int PRN=1;PRN<33;PRN++)
{
gnss_synchro->PRN=PRN;
acquisition->set_gnss_synchro(gnss_synchro);
acquisition->init();
acquisition->reset();
stop=false;
ch_thread = boost::thread(wait_message);
top_block->run();
if (start_msg==true)
{
std::cout<<"Searchig for GPS Satellites..."<<std::endl;
std::cout<<"[";
start_msg=false;
}
if (gnss_sync_vector.size()>0)
{
std::cout<<" "<<PRN<<" ";
double doppler_measurement_hz=0;
for (std::vector<Gnss_Synchro>::iterator it = gnss_sync_vector.begin() ; it != gnss_sync_vector.end(); ++it)
{
doppler_measurement_hz+=(*it).Acq_doppler_hz;
//std::cout << "Doppler (SV=" << (*it).PRN<<")="<<(*it).Acq_doppler_hz<<"[Hz]"<<std::endl;
}
doppler_measurement_hz=doppler_measurement_hz/gnss_sync_vector.size();
doppler_measurements_map.insert(std::pair<int,double>(PRN,doppler_measurement_hz));
}else{
std::cout<<" . ";
}
channel_internal_queue.push(3);
ch_thread.join();
gnss_sync_vector.clear();
boost::dynamic_pointer_cast<gr::blocks::file_source>(source)->seek(0,0);
std::cout.flush();
}
std::cout<<"]"<<std::endl;
// report the elapsed time
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
std::cout << "Total signal acquisition run time "
<< ((double)(end - begin))/1000000.0
<< " [seconds]" << std::endl;
// 5. Get visible GPS satellites (positive acquisitions with Doppler measurements)
// 2. Get SUPL information from server: Ephemeris record, assistance info and TOW
front_end_cal.get_ephemeris();
// 6. Compute Doppler estimations
//find TOW from SUPL assistance
double current_TOW=0;
if (global_gps_ephemeris_map.size()>0)
{
std::map<int,Gps_Ephemeris> Eph_map;
Eph_map=global_gps_ephemeris_map.get_map_copy();
current_TOW=Eph_map.begin()->second.d_TOW;
std::cout<<"Current TOW obtained from SUPL assistance = "<<current_TOW<<std::endl;
}else{
std::cout<<"Unable to get Ephemeris SUPL assistance. TOW is unknown!"<<std::endl;
}
//Get user position from config file (or from SUPL using GSM Cell ID)
double lat_deg = configuration->property("GNSS-SDR.init_latitude_deg", 41.0);
double lon_deg = configuration->property("GNSS-SDR.init_longitude_deg", 2.0);
double altitude_m = configuration->property("GNSS-SDR.init_altitude_m", 100);
std::map<int,double> f_if_estimation_Hz_map;
std::map<int,double> f_fs_estimation_Hz_map;
std::map<int,double> f_ppm_estimation_Hz_map;
for (std::map<int,double>::iterator it = doppler_measurements_map.begin() ; it != doppler_measurements_map.end(); ++it)
{
std::cout << "Doppler measured for (SV=" << it->first<<")="<<it->second<<" [Hz]"<<std::endl;
try{
double doppler_estimated_hz;
doppler_estimated_hz=front_end_cal.estimate_doppler_from_eph(it->first,current_TOW,lat_deg,lon_deg,altitude_m);
std::cout << "Doppler estimated for (SV=" << it->first<<")="<<doppler_estimated_hz<<" [Hz]"<<std::endl;
// 7. Compute front-end IF and sampling frequency estimation
// Compare with the measurements and compute clock drift using FE model
double estimated_fs_Hz, estimated_f_if_Hz,f_osc_err_ppm;
front_end_cal.GPS_L1_front_end_model_E4000(doppler_estimated_hz,it->second,fs_in_, &estimated_fs_Hz, &estimated_f_if_Hz, &f_osc_err_ppm );
f_if_estimation_Hz_map.insert(std::pair<int,double>(it->first,estimated_f_if_Hz));
f_fs_estimation_Hz_map.insert(std::pair<int,double>(it->first,estimated_fs_Hz));
f_ppm_estimation_Hz_map.insert(std::pair<int,double>(it->first,f_osc_err_ppm));
}catch(int ex)
{
std::cout<<"Eph not found for SV "<<it->first<<std::endl;
}
}
// FINAL FE estimations
double mean_f_if_Hz=0;
double mean_fs_Hz=0;
double mean_osc_err_ppm=0;
int n_elements=f_if_estimation_Hz_map.size();
for (std::map<int,double>::iterator it = f_if_estimation_Hz_map.begin() ; it != f_if_estimation_Hz_map.end(); ++it)
{
mean_f_if_Hz+=(*it).second;
mean_fs_Hz+=f_fs_estimation_Hz_map.find((*it).first)->second;
mean_osc_err_ppm+=f_ppm_estimation_Hz_map.find((*it).first)->second;
}
mean_f_if_Hz/=n_elements;
mean_fs_Hz/=n_elements;
mean_osc_err_ppm/=n_elements;
std::cout <<std::setiosflags(std::ios::fixed)<<std::setprecision(2)<<"FE parameters estimation for Elonics E4000 Front-End:"<<std::endl;
std::cout<<"Sampling frequency ="<<mean_fs_Hz<<" [Hz]"<<std::endl;
std::cout<<"IF bias present in baseband="<<mean_f_if_Hz<<" [Hz]"<<std::endl;
std::cout<<"Reference oscillator error ="<<mean_osc_err_ppm<<" [ppm]"<<std::endl;
// 8. Generate GNSS-SDR config file.
delete configuration;
delete acquisition;
delete gnss_synchro;
google::ShutDownCommandLineFlags();
std::cout << "GNSS-SDR program ended." << std::endl;
// if (global_gps_acq_assist_map.size()>0)
// {
// std::map<int,Gps_Acq_Assist> Acq_Assist_map;
// Acq_Assist_map=global_gps_acq_assist_map.get_map_copy();
// current_TOW=Acq_Assist_map.begin()->second.d_TOW;
// std::cout<<"Current TOW obtained from acquisition assistance = "<<current_TOW<<std::endl;
// }else{
// std::cout<<"Unable to get acquisition assistance information. TOW is unknown!"<<std::endl;
// }
}