2011-10-01 18:45:20 +00:00
/*!
2018-02-07 07:43:44 +00:00
* \ file pcps_acquisition . cc
2012-09-12 15:03:38 +00:00
* \ brief This class implements a Parallel Code Phase Search Acquisition
* \ authors < ul >
* < li > Javier Arribas , 2011. jarribas ( at ) cttc . es
* < li > Luis Esteve , 2012. luis ( at ) epsilon - formacion . com
2013-07-23 18:03:07 +00:00
* < li > Marc Molina , 2013. marc . molina . pena @ gmail . com
2017-10-03 11:47:55 +00:00
* < li > Cillian O ' Driscoll , 2017. cillian ( at ) ieee . org
2012-09-12 15:03:38 +00:00
* < / ul >
2011-10-01 18:45:20 +00:00
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
2017-10-03 11:47:55 +00:00
* Copyright ( C ) 2010 - 2017 ( see AUTHORS file for a list of contributors )
2011-10-01 18:45:20 +00:00
*
* 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
2015-01-08 18:49:59 +00:00
* ( at your option ) any later version .
2011-10-01 18:45:20 +00:00
*
* 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/>.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2018-02-07 07:43:44 +00:00
# include "pcps_acquisition.h"
2018-03-03 01:03:39 +00:00
# include "GPS_L1_CA.h" // for GPS_TWO_PI
# include "GLONASS_L1_CA.h" // for GLONASS_TWO_PI
2011-10-01 18:45:20 +00:00
# include <glog/logging.h>
2018-02-05 06:31:34 +00:00
# include <gnuradio/io_signature.h>
# include <matio.h>
2012-09-04 14:29:07 +00:00
# include <volk/volk.h>
2018-02-26 02:15:53 +00:00
# include <cstring>
2016-01-04 21:56:52 +00:00
2011-10-01 18:45:20 +00:00
using google : : LogMessage ;
2018-02-07 07:43:44 +00:00
pcps_acquisition_sptr pcps_make_acquisition (
2018-03-03 01:03:39 +00:00
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 , bool use_CFAR_algorithm_flag ,
bool dump , bool blocking ,
std : : string dump_filename , size_t it_size )
2011-10-01 18:45:20 +00:00
{
2018-02-07 07:43:44 +00:00
return pcps_acquisition_sptr (
2018-03-03 01:03:39 +00:00
new pcps_acquisition ( sampled_ms , max_dwells , doppler_max , freq , fs_in , samples_per_ms ,
samples_per_code , bit_transition_flag , use_CFAR_algorithm_flag , dump , blocking , dump_filename , it_size ) ) ;
2011-10-01 18:45:20 +00:00
}
2016-04-26 16:54:32 +00:00
2018-02-07 07:43:44 +00:00
pcps_acquisition : : pcps_acquisition (
2018-03-03 01:03:39 +00:00
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 , bool use_CFAR_algorithm_flag ,
bool dump , bool blocking ,
std : : string dump_filename , size_t it_size ) : gr : : block ( " pcps_acquisition " ,
gr : : io_signature : : make ( 1 , 1 , it_size * sampled_ms * samples_per_ms * ( bit_transition_flag ? 2 : 1 ) ) ,
gr : : io_signature : : make ( 0 , 0 , it_size * sampled_ms * samples_per_ms * ( bit_transition_flag ? 2 : 1 ) ) )
2011-10-01 18:45:20 +00:00
{
2016-04-15 14:33:41 +00:00
this - > message_port_register_out ( pmt : : mp ( " events " ) ) ;
2018-03-03 01:03:39 +00:00
d_sample_counter = 0 ; // SAMPLE COUNTER
2011-10-01 18:45:20 +00:00
d_active = false ;
2013-08-28 17:17:57 +00:00
d_state = 0 ;
2011-10-01 18:45:20 +00:00
d_freq = freq ;
2017-07-18 20:57:05 +00:00
d_old_freq = freq ;
2011-10-01 18:45:20 +00:00
d_fs_in = fs_in ;
d_samples_per_ms = samples_per_ms ;
2013-07-23 18:03:07 +00:00
d_samples_per_code = samples_per_code ;
2011-10-01 18:45:20 +00:00
d_sampled_ms = sampled_ms ;
2013-08-28 17:17:57 +00:00
d_max_dwells = max_dwells ;
d_well_count = 0 ;
2011-10-01 18:45:20 +00:00
d_doppler_max = doppler_max ;
d_fft_size = d_sampled_ms * d_samples_per_ms ;
d_mag = 0 ;
d_input_power = 0.0 ;
2013-07-23 18:03:07 +00:00
d_num_doppler_bins = 0 ;
2013-08-28 17:17:57 +00:00
d_bit_transition_flag = bit_transition_flag ;
2016-04-10 08:29:25 +00:00
d_use_CFAR_algorithm_flag = use_CFAR_algorithm_flag ;
2015-05-15 01:02:45 +00:00
d_threshold = 0.0 ;
2016-05-10 23:39:11 +00:00
d_doppler_step = 0 ;
2015-05-15 01:02:45 +00:00
d_code_phase = 0 ;
d_test_statistics = 0.0 ;
d_channel = 0 ;
2018-03-03 01:03:39 +00:00
if ( it_size = = sizeof ( gr_complex ) )
{
d_cshort = false ;
}
else
{
d_cshort = true ;
}
2015-08-06 08:34:25 +00:00
// COD:
// Experimenting with the overlap/save technique for handling bit trannsitions
// The problem: Circular correlation is asynchronous with the received code.
// In effect the first code phase used in the correlation is the current
// estimate of the code phase at the start of the input buffer. If this is 1/2
// of the code period a bit transition would move all the signal energy into
// adjacent frequency bands at +/- 1/T where T is the integration time.
//
// We can avoid this by doing linear correlation, effectively doubling the
// size of the input buffer and padding the code with zeros.
2018-03-03 01:03:39 +00:00
if ( d_bit_transition_flag )
2018-02-05 06:31:34 +00:00
{
d_fft_size * = 2 ;
2018-03-03 01:03:39 +00:00
d_max_dwells = 1 ; //Activation of d_bit_transition_flag invalidates the value of d_max_dwells
2018-02-05 06:31:34 +00:00
}
2015-08-06 08:34:25 +00:00
2016-08-18 12:17:02 +00:00
d_fft_codes = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
d_magnitude = static_cast < float * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( float ) , volk_gnsssdr_get_alignment ( ) ) ) ;
2011-10-01 18:45:20 +00:00
// Direct FFT
2012-11-25 11:15:11 +00:00
d_fft_if = new gr : : fft : : fft_complex ( d_fft_size , true ) ;
2011-10-01 18:45:20 +00:00
// Inverse FFT
2012-11-25 11:15:11 +00:00
d_ifft = new gr : : fft : : fft_complex ( d_fft_size , false ) ;
2011-10-01 18:45:20 +00:00
2012-10-19 16:00:40 +00:00
// For dumping samples into a file
2012-01-16 18:27:31 +00:00
d_dump = dump ;
d_dump_filename = dump_filename ;
2015-05-19 20:11:31 +00:00
d_gnss_synchro = 0 ;
d_grid_doppler_wipeoffs = 0 ;
2017-08-24 11:32:37 +00:00
d_blocking = blocking ;
d_worker_active = false ;
d_data_buffer = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
2018-03-03 01:03:39 +00:00
if ( d_cshort )
2018-02-07 07:43:44 +00:00
{
d_data_buffer_sc = static_cast < lv_16sc_t * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( lv_16sc_t ) , volk_gnsssdr_get_alignment ( ) ) ) ;
}
2018-02-08 11:49:53 +00:00
else
{
d_data_buffer_sc = nullptr ;
}
2018-01-23 11:28:29 +00:00
grid_ = arma : : fmat ( ) ;
2011-10-01 18:45:20 +00:00
}
2016-04-10 08:29:25 +00:00
2018-02-07 07:43:44 +00:00
pcps_acquisition : : ~ pcps_acquisition ( )
2012-10-19 16:00:40 +00:00
{
2013-07-23 18:03:07 +00:00
if ( d_num_doppler_bins > 0 )
{
2013-10-01 20:32:04 +00:00
for ( unsigned int i = 0 ; i < d_num_doppler_bins ; i + + )
{
2016-08-18 12:17:02 +00:00
volk_gnsssdr_free ( d_grid_doppler_wipeoffs [ i ] ) ;
2013-10-01 20:32:04 +00:00
}
2013-07-23 18:03:07 +00:00
delete [ ] d_grid_doppler_wipeoffs ;
}
2016-08-18 12:17:02 +00:00
volk_gnsssdr_free ( d_fft_codes ) ;
volk_gnsssdr_free ( d_magnitude ) ;
2012-10-19 16:00:40 +00:00
delete d_ifft ;
delete d_fft_if ;
2018-01-23 11:28:29 +00:00
volk_gnsssdr_free ( d_data_buffer ) ;
2018-03-03 01:03:39 +00:00
if ( d_cshort )
{
volk_gnsssdr_free ( d_data_buffer_sc ) ;
}
2011-10-01 18:45:20 +00:00
}
2016-04-10 08:29:25 +00:00
2018-03-03 01:03:39 +00:00
void pcps_acquisition : : set_local_code ( std : : complex < float > * code )
2012-07-12 21:17:37 +00:00
{
2017-07-18 20:57:05 +00:00
// reset the intermediate frequency
d_freq = d_old_freq ;
2017-06-05 23:22:46 +00:00
// This will check if it's fdma, if yes will update the intermediate frequency and the doppler grid
2018-03-03 01:03:39 +00:00
if ( is_fdma ( ) )
2017-06-05 23:22:46 +00:00
{
update_grid_doppler_wipeoffs ( ) ;
}
2015-08-06 08:34:25 +00:00
// COD
// Here we want to create a buffer that looks like this:
// [ 0 0 0 ... 0 c_0 c_1 ... c_L]
// where c_i is the local code and there are L zeros and L chips
2018-03-03 01:03:39 +00:00
gr : : thread : : scoped_lock lock ( d_setlock ) ; // require mutex with work function called by the scheduler
if ( d_bit_transition_flag )
2016-04-10 08:29:25 +00:00
{
2017-10-03 11:47:55 +00:00
int offset = d_fft_size / 2 ;
2018-03-03 01:03:39 +00:00
std : : fill_n ( d_fft_if - > get_inbuf ( ) , offset , gr_complex ( 0.0 , 0.0 ) ) ;
2016-05-13 03:16:59 +00:00
memcpy ( d_fft_if - > get_inbuf ( ) + offset , code , sizeof ( gr_complex ) * offset ) ;
2017-08-29 07:20:38 +00:00
}
else
2016-05-13 03:16:59 +00:00
{
memcpy ( d_fft_if - > get_inbuf ( ) , code , sizeof ( gr_complex ) * d_fft_size ) ;
2016-04-10 08:29:25 +00:00
}
2017-10-03 11:47:55 +00:00
2018-03-03 01:03:39 +00:00
d_fft_if - > execute ( ) ; // We need the FFT of local code
2014-09-10 01:15:01 +00:00
volk_32fc_conjugate_32fc ( d_fft_codes , d_fft_if - > get_outbuf ( ) , d_fft_size ) ;
2012-07-12 21:17:37 +00:00
}
2012-01-16 18:27:31 +00:00
2016-04-10 08:29:25 +00:00
2018-02-07 07:43:44 +00:00
bool pcps_acquisition : : is_fdma ( )
2017-06-05 23:22:46 +00:00
{
// Dealing with FDMA system
2018-03-03 01:03:39 +00:00
if ( strcmp ( d_gnss_synchro - > Signal , " 1G " ) = = 0 )
2017-06-05 23:22:46 +00:00
{
2017-09-09 19:44:35 +00:00
d_freq + = DFRQ1_GLO * GLONASS_PRN . at ( d_gnss_synchro - > PRN ) ;
LOG ( INFO ) < < " Trying to acquire SV PRN " < < d_gnss_synchro - > PRN < < " with freq " < < d_freq < < " in Glonass Channel " < < GLONASS_PRN . at ( d_gnss_synchro - > PRN ) < < std : : endl ;
2017-06-05 23:22:46 +00:00
return true ;
}
else
{
return false ;
}
}
2016-04-10 08:29:25 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : update_local_carrier ( gr_complex * carrier_vector , int correlator_length_samples , float freq )
2016-02-25 17:21:30 +00:00
{
2016-03-20 00:45:01 +00:00
float phase_step_rad = GPS_TWO_PI * freq / static_cast < float > ( d_fs_in ) ;
2016-03-20 23:38:08 +00:00
float _phase [ 1 ] ;
_phase [ 0 ] = 0 ;
2018-03-03 01:03:39 +00:00
volk_gnsssdr_s32f_sincos_32fc ( carrier_vector , - phase_step_rad , _phase , correlator_length_samples ) ;
2016-02-25 17:21:30 +00:00
}
2016-04-10 08:29:25 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : init ( )
2011-10-01 18:45:20 +00:00
{
2016-04-08 13:10:46 +00:00
d_gnss_synchro - > Flag_valid_acquisition = false ;
d_gnss_synchro - > Flag_valid_symbol_output = false ;
d_gnss_synchro - > Flag_valid_pseudorange = false ;
d_gnss_synchro - > Flag_valid_word = false ;
2016-04-07 16:25:45 +00:00
2012-10-19 16:00:40 +00:00
d_gnss_synchro - > Acq_delay_samples = 0.0 ;
d_gnss_synchro - > Acq_doppler_hz = 0.0 ;
d_gnss_synchro - > Acq_samplestamp_samples = 0 ;
2011-11-26 14:20:47 +00:00
d_mag = 0.0 ;
2011-10-01 18:45:20 +00:00
d_input_power = 0.0 ;
2018-03-03 01:03:39 +00:00
d_num_doppler_bins = static_cast < unsigned int > ( std : : ceil ( static_cast < double > ( static_cast < int > ( d_doppler_max ) - static_cast < int > ( - d_doppler_max ) ) / static_cast < double > ( d_doppler_step ) ) ) ;
2013-10-01 20:32:04 +00:00
// Create the carrier Doppler wipeoff signals
2013-07-23 18:03:07 +00:00
d_grid_doppler_wipeoffs = new gr_complex * [ d_num_doppler_bins ] ;
2014-09-10 01:15:01 +00:00
2014-01-12 20:07:38 +00:00
for ( unsigned int doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
2013-07-23 18:03:07 +00:00
{
2016-08-18 12:17:02 +00:00
d_grid_doppler_wipeoffs [ doppler_index ] = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
2014-09-12 18:23:39 +00:00
int doppler = - static_cast < int > ( d_doppler_max ) + d_doppler_step * doppler_index ;
2016-02-25 17:21:30 +00:00
update_local_carrier ( d_grid_doppler_wipeoffs [ doppler_index ] , d_fft_size , d_freq + doppler ) ;
2013-07-23 18:03:07 +00:00
}
2017-08-24 11:32:37 +00:00
d_worker_active = false ;
2018-01-23 11:28:29 +00:00
2018-03-03 01:03:39 +00:00
if ( d_dump )
2018-02-05 06:31:34 +00:00
{
unsigned int effective_fft_size = ( d_bit_transition_flag ? ( d_fft_size / 2 ) : d_fft_size ) ;
grid_ = arma : : fmat ( effective_fft_size , d_num_doppler_bins , arma : : fill : : zeros ) ;
}
2011-10-01 18:45:20 +00:00
}
2012-01-16 18:27:31 +00:00
2015-02-10 18:30:15 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : update_grid_doppler_wipeoffs ( )
2017-06-05 23:22:46 +00:00
{
2014-01-12 20:07:38 +00:00
for ( unsigned int doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
2013-07-23 18:03:07 +00:00
{
2016-08-18 12:17:02 +00:00
d_grid_doppler_wipeoffs [ doppler_index ] = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
2014-09-12 18:23:39 +00:00
int doppler = - static_cast < int > ( d_doppler_max ) + d_doppler_step * doppler_index ;
2016-02-25 17:21:30 +00:00
update_local_carrier ( d_grid_doppler_wipeoffs [ doppler_index ] , d_fft_size , d_freq + doppler ) ;
2013-07-23 18:03:07 +00:00
}
2011-10-01 18:45:20 +00:00
}
2012-01-16 18:27:31 +00:00
2015-02-10 18:30:15 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : set_state ( int state )
2016-04-10 08:29:25 +00:00
{
2018-03-03 01:03:39 +00:00
gr : : thread : : scoped_lock lock ( d_setlock ) ; // require mutex with work function called by the scheduler
2016-04-10 08:29:25 +00:00
d_state = state ;
if ( d_state = = 1 )
{
d_gnss_synchro - > Acq_delay_samples = 0.0 ;
d_gnss_synchro - > Acq_doppler_hz = 0.0 ;
d_gnss_synchro - > Acq_samplestamp_samples = 0 ;
d_well_count = 0 ;
d_mag = 0.0 ;
d_input_power = 0.0 ;
d_test_statistics = 0.0 ;
2018-01-09 15:43:38 +00:00
d_active = true ;
2016-04-10 08:29:25 +00:00
}
else if ( d_state = = 0 )
2018-03-03 01:03:39 +00:00
{
}
2016-04-10 08:29:25 +00:00
else
{
LOG ( ERROR ) < < " State can only be set to 0 or 1 " ;
}
}
2015-02-10 18:30:15 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : send_positive_acquisition ( )
2017-04-12 15:04:51 +00:00
{
// 6.1- Declare positive acquisition using a message port
//0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
DLOG ( INFO ) < < " positive acquisition "
2017-10-03 11:47:55 +00:00
< < " , satellite " < < d_gnss_synchro - > System < < " " < < d_gnss_synchro - > PRN
< < " , sample_stamp " < < d_sample_counter
< < " , test statistics value " < < d_test_statistics
< < " , test statistics threshold " < < d_threshold
< < " , code phase " < < d_gnss_synchro - > Acq_delay_samples
< < " , doppler " < < d_gnss_synchro - > Acq_doppler_hz
< < " , magnitude " < < d_mag
< < " , input signal power " < < d_input_power ;
2017-04-12 15:04:51 +00:00
this - > message_port_pub ( pmt : : mp ( " events " ) , pmt : : from_long ( 1 ) ) ;
}
2017-08-19 00:33:54 +00:00
2018-02-07 07:43:44 +00:00
void pcps_acquisition : : send_negative_acquisition ( )
2017-04-12 15:04:51 +00:00
{
// 6.2- Declare negative acquisition using a message port
//0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
DLOG ( INFO ) < < " negative acquisition "
2017-10-03 11:47:55 +00:00
< < " , satellite " < < d_gnss_synchro - > System < < " " < < d_gnss_synchro - > PRN
< < " , sample_stamp " < < d_sample_counter
< < " , test statistics value " < < d_test_statistics
< < " , test statistics threshold " < < d_threshold
< < " , code phase " < < d_gnss_synchro - > Acq_delay_samples
< < " , doppler " < < d_gnss_synchro - > Acq_doppler_hz
< < " , magnitude " < < d_mag
< < " , input signal power " < < d_input_power ;
2017-04-12 15:04:51 +00:00
this - > message_port_pub ( pmt : : mp ( " events " ) , pmt : : from_long ( 2 ) ) ;
}
2017-08-19 00:33:54 +00:00
2018-02-07 07:43:44 +00:00
int pcps_acquisition : : general_work ( int noutput_items __attribute__ ( ( unused ) ) ,
2018-03-03 01:03:39 +00:00
gr_vector_int & ninput_items , gr_vector_const_void_star & input_items ,
gr_vector_void_star & output_items __attribute__ ( ( unused ) ) )
2011-10-01 18:45:20 +00:00
{
2012-01-16 18:27:31 +00:00
/*
2013-10-01 20:32:04 +00:00
* By J . Arribas , L . Esteve and M . Molina
2012-01-16 18:27:31 +00:00
* Acquisition strategy ( Kay Borre book + CFAR threshold ) :
2011-12-27 21:21:12 +00:00
* 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
2016-05-09 14:44:54 +00:00
* 6. Declare positive or negative acquisition using a message port
2011-10-01 18:45:20 +00:00
*/
2018-01-09 15:43:38 +00:00
gr : : thread : : scoped_lock lk ( d_setlock ) ;
2018-03-03 01:03:39 +00:00
if ( ! d_active | | d_worker_active )
2018-01-09 15:43:38 +00:00
{
d_sample_counter + = d_fft_size * ninput_items [ 0 ] ;
consume_each ( ninput_items [ 0 ] ) ;
return 0 ;
}
2018-03-03 01:03:39 +00:00
switch ( d_state )
2012-01-16 18:27:31 +00:00
{
2018-03-03 01:03:39 +00:00
case 0 :
{
//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 :
{
// Copy the data to the core and let it know that new data is available
if ( d_cshort )
{
memcpy ( d_data_buffer_sc , input_items [ 0 ] , d_fft_size * sizeof ( lv_16sc_t ) ) ;
}
else
{
memcpy ( d_data_buffer , input_items [ 0 ] , d_fft_size * sizeof ( gr_complex ) ) ;
}
if ( d_blocking )
{
lk . unlock ( ) ;
acquisition_core ( d_sample_counter ) ;
}
else
{
gr : : thread : : thread d_worker ( & pcps_acquisition : : acquisition_core , this , d_sample_counter ) ;
d_worker_active = true ;
}
d_sample_counter + = d_fft_size ;
consume_each ( 1 ) ;
break ;
}
2018-01-09 15:43:38 +00:00
}
return 0 ;
2011-10-01 18:45:20 +00:00
}
2015-08-06 08:34:25 +00:00
2017-10-03 11:47:55 +00:00
2018-03-03 01:03:39 +00:00
void pcps_acquisition : : acquisition_core ( unsigned long int samp_count )
2017-08-24 11:32:37 +00:00
{
2018-01-09 15:43:38 +00:00
gr : : thread : : scoped_lock lk ( d_setlock ) ;
2017-08-24 11:32:37 +00:00
2018-01-09 15:43:38 +00:00
// initialize acquisition algorithm
int doppler ;
uint32_t indext = 0 ;
float magt = 0.0 ;
2018-03-03 01:03:39 +00:00
const gr_complex * in = d_data_buffer ; //Get the input samples pointer
int effective_fft_size = ( d_bit_transition_flag ? d_fft_size / 2 : d_fft_size ) ;
if ( d_cshort )
{
volk_gnsssdr_16ic_convert_32fc ( d_data_buffer , d_data_buffer_sc , d_fft_size ) ;
}
2018-01-09 15:43:38 +00:00
float fft_normalization_factor = static_cast < float > ( d_fft_size ) * static_cast < float > ( d_fft_size ) ;
2017-08-24 11:32:37 +00:00
2018-01-09 15:43:38 +00:00
d_input_power = 0.0 ;
d_mag = 0.0 ;
d_well_count + + ;
2017-08-24 11:32:37 +00:00
2018-01-09 15:43:38 +00:00
DLOG ( INFO ) < < " Channel: " < < d_channel
2018-02-05 06:31:34 +00:00
< < " , doing acquisition of satellite: " < < d_gnss_synchro - > System < < " " < < d_gnss_synchro - > PRN
< < " ,sample stamp: " < < samp_count < < " , threshold: "
< < d_threshold < < " , doppler_max: " < < d_doppler_max
< < " , doppler_step: " < < d_doppler_step
2018-03-03 01:03:39 +00:00
< < " , use_CFAR_algorithm_flag: " < < ( d_use_CFAR_algorithm_flag ? " true " : " false " ) ;
2017-08-24 11:32:37 +00:00
2018-01-09 15:43:38 +00:00
lk . unlock ( ) ;
if ( d_use_CFAR_algorithm_flag )
{
// 1- (optional) Compute the input signal power estimation
volk_32fc_magnitude_squared_32f ( d_magnitude , in , d_fft_size ) ;
volk_32f_accumulator_s32f ( & d_input_power , d_magnitude , d_fft_size ) ;
d_input_power / = static_cast < 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 = - static_cast < int > ( d_doppler_max ) + d_doppler_step * doppler_index ;
2017-08-24 11:32:37 +00:00
2018-01-09 15:43:38 +00:00
volk_32fc_x2_multiply_32fc ( d_fft_if - > get_inbuf ( ) , in , d_grid_doppler_wipeoffs [ doppler_index ] , d_fft_size ) ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
// 3- Perform the FFT-based convolution (parallel time search)
// Compute the FFT of the carrier wiped--off incoming signal
d_fft_if - > execute ( ) ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
// 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 ( d_ifft - > get_inbuf ( ) , d_fft_if - > get_outbuf ( ) , d_fft_codes , d_fft_size ) ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
// compute the inverse FFT
d_ifft - > execute ( ) ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
// Search maximum
2018-03-03 01:03:39 +00:00
size_t offset = ( d_bit_transition_flag ? effective_fft_size : 0 ) ;
2018-01-09 15:43:38 +00:00
volk_32fc_magnitude_squared_32f ( d_magnitude , d_ifft - > get_outbuf ( ) + offset , effective_fft_size ) ;
volk_gnsssdr_32f_index_max_32u ( & indext , d_magnitude , effective_fft_size ) ;
magt = d_magnitude [ indext ] ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
if ( d_use_CFAR_algorithm_flag )
{
// Normalize the maximum value to correct the scale factor introduced by FFTW
magt = d_magnitude [ indext ] / ( fft_normalization_factor * fft_normalization_factor ) ;
}
// 4- record the maximum peak and the associated synchronization parameters
if ( d_mag < magt )
{
d_mag = magt ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
if ( ! d_use_CFAR_algorithm_flag )
2017-10-03 11:47:55 +00:00
{
2018-01-09 15:43:38 +00:00
// Search grid noise floor approximation for this doppler line
volk_32f_accumulator_s32f ( & d_input_power , d_magnitude , effective_fft_size ) ;
d_input_power = ( d_input_power - d_mag ) / ( effective_fft_size - 1 ) ;
2017-10-03 11:47:55 +00:00
}
2018-01-09 15:43:38 +00:00
// 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 )
2017-10-03 11:47:55 +00:00
{
2018-01-09 15:43:38 +00:00
d_gnss_synchro - > Acq_delay_samples = static_cast < double > ( indext % d_samples_per_code ) ;
d_gnss_synchro - > Acq_doppler_hz = static_cast < double > ( doppler ) ;
2018-01-10 10:08:06 +00:00
d_gnss_synchro - > Acq_samplestamp_samples = samp_count ;
2017-10-03 11:47:55 +00:00
2018-01-09 15:43:38 +00:00
// 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 )
2018-01-23 11:28:29 +00:00
{
2018-02-05 06:31:34 +00:00
memcpy ( grid_ . colptr ( doppler_index ) , d_magnitude , sizeof ( float ) * effective_fft_size ) ;
2018-03-03 01:03:39 +00:00
if ( doppler_index = = ( d_num_doppler_bins - 1 ) )
2018-02-05 06:31:34 +00:00
{
std : : string filename = d_dump_filename ;
filename . append ( " _ " ) ;
filename . append ( 1 , d_gnss_synchro - > System ) ;
filename . append ( " _ " ) ;
filename . append ( 1 , d_gnss_synchro - > Signal [ 0 ] ) ;
filename . append ( 1 , d_gnss_synchro - > Signal [ 1 ] ) ;
filename . append ( " _sat_ " ) ;
filename . append ( std : : to_string ( d_gnss_synchro - > PRN ) ) ;
filename . append ( " .mat " ) ;
mat_t * matfp = Mat_CreateVer ( filename . c_str ( ) , NULL , MAT_FT_MAT73 ) ;
2018-03-03 01:03:39 +00:00
if ( matfp = = NULL )
2018-02-05 06:31:34 +00:00
{
std : : cout < < " Unable to create or open Acquisition dump file " < < std : : endl ;
d_dump = false ;
}
else
{
size_t dims [ 2 ] = { static_cast < size_t > ( effective_fft_size ) , static_cast < size_t > ( d_num_doppler_bins ) } ;
matvar_t * matvar = Mat_VarCreate ( " grid " , MAT_C_SINGLE , MAT_T_SINGLE , 2 , dims , grid_ . memptr ( ) , 0 ) ;
2018-03-03 01:03:39 +00:00
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
2018-02-05 06:31:34 +00:00
Mat_VarFree ( matvar ) ;
dims [ 0 ] = static_cast < size_t > ( 1 ) ;
dims [ 1 ] = static_cast < size_t > ( 1 ) ;
matvar = Mat_VarCreate ( " doppler_max " , MAT_C_SINGLE , MAT_T_UINT32 , 1 , dims , & d_doppler_max , 0 ) ;
2018-03-03 01:03:39 +00:00
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
2018-02-05 06:31:34 +00:00
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " doppler_step " , MAT_C_SINGLE , MAT_T_UINT32 , 1 , dims , & d_doppler_step , 0 ) ;
2018-03-03 01:03:39 +00:00
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
2018-02-05 06:31:34 +00:00
Mat_VarFree ( matvar ) ;
Mat_Close ( matfp ) ;
}
}
2017-08-24 11:32:37 +00:00
}
2018-01-09 15:43:38 +00:00
}
lk . lock ( ) ;
if ( ! d_bit_transition_flag )
{
if ( d_test_statistics > d_threshold )
{
2018-03-03 01:03:39 +00:00
d_state = 0 ; // Positive acquisition
2018-01-09 15:43:38 +00:00
d_active = false ;
send_positive_acquisition ( ) ;
}
else if ( d_well_count = = d_max_dwells )
{
d_state = 0 ;
d_active = false ;
send_negative_acquisition ( ) ;
}
}
else
{
2018-03-03 01:03:39 +00:00
if ( d_well_count = = d_max_dwells ) // d_max_dwells = 2
2017-09-16 13:57:50 +00:00
{
2017-10-03 11:47:55 +00:00
if ( d_test_statistics > d_threshold )
{
2018-03-03 01:03:39 +00:00
d_state = 0 ; // Positive acquisition
2017-10-03 11:47:55 +00:00
d_active = false ;
send_positive_acquisition ( ) ;
}
2018-01-09 15:43:38 +00:00
else
2017-10-03 11:47:55 +00:00
{
2018-03-03 01:03:39 +00:00
d_state = 0 ; // Negative acquisition
2017-10-03 11:47:55 +00:00
d_active = false ;
send_negative_acquisition ( ) ;
}
2017-09-16 13:57:50 +00:00
}
2017-10-03 11:47:55 +00:00
}
2017-09-16 13:55:56 +00:00
d_worker_active = false ;
}