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
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
2018-05-13 20:49:11 +00:00
* Copyright ( C ) 2010 - 2018 ( 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
2018-05-13 20:49:11 +00:00
* along with GNSS - SDR . If not , see < https : //www.gnu.org/licenses/>.
2011-10-01 18:45:20 +00:00
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2018-02-07 07:43:44 +00:00
# include "pcps_acquisition.h"
2018-12-03 09:05:47 +00:00
# include "GLONASS_L1_L2_CA.h" // for GLONASS_TWO_PI
2018-03-26 13:06:14 +00:00
# include "GPS_L1_CA.h" // for GPS_TWO_PI
2018-10-30 11:04:59 +00:00
# include "gnss_sdr_create_directory.h"
# include <boost/filesystem/path.hpp>
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>
2018-04-29 00:51:50 +00:00
# include <volk_gnsssdr/volk_gnsssdr.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-06-19 10:59:54 +00:00
pcps_acquisition_sptr pcps_make_acquisition ( const Acq_Conf & conf_ )
2011-10-01 18:45:20 +00:00
{
2018-04-04 15:03:49 +00:00
return pcps_acquisition_sptr ( new pcps_acquisition ( conf_ ) ) ;
2011-10-01 18:45:20 +00:00
}
2016-04-26 16:54:32 +00:00
2018-06-19 10:59:54 +00:00
pcps_acquisition : : pcps_acquisition ( const Acq_Conf & conf_ ) : gr : : block ( " pcps_acquisition " ,
2018-08-08 13:02:29 +00:00
gr : : io_signature : : make ( 1 , 1 , conf_ . it_size ) ,
2018-07-19 14:26:51 +00:00
gr : : io_signature : : make ( 0 , 0 , conf_ . it_size ) )
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-04-04 15:03:49 +00:00
acq_parameters = conf_ ;
2018-08-12 22:54:23 +00:00
d_sample_counter = 0ULL ; // SAMPLE COUNTER
2011-10-01 18:45:20 +00:00
d_active = false ;
2018-06-21 10:21:35 +00:00
d_positive_acq = 0 ;
2013-08-28 17:17:57 +00:00
d_state = 0 ;
2018-08-12 22:54:23 +00:00
d_old_freq = 0LL ;
d_num_noncoherent_integrations_counter = 0U ;
2018-07-10 14:25:16 +00:00
d_consumed_samples = acq_parameters . sampled_ms * acq_parameters . samples_per_ms * ( acq_parameters . bit_transition_flag ? 2 : 1 ) ;
2018-07-15 02:12:20 +00:00
if ( acq_parameters . sampled_ms = = acq_parameters . ms_per_code )
2018-07-10 14:25:16 +00:00
{
d_fft_size = d_consumed_samples ;
}
else
{
d_fft_size = d_consumed_samples * 2 ;
}
2018-08-08 13:02:29 +00:00
// d_fft_size = next power of two? ////
2011-10-01 18:45:20 +00:00
d_mag = 0 ;
d_input_power = 0.0 ;
2018-08-12 22:54:23 +00:00
d_num_doppler_bins = 0U ;
2015-05-15 01:02:45 +00:00
d_threshold = 0.0 ;
2018-08-12 22:54:23 +00:00
d_doppler_step = 0U ;
2018-04-04 12:59:28 +00:00
d_doppler_center_step_two = 0.0 ;
2015-05-15 01:02:45 +00:00
d_test_statistics = 0.0 ;
2018-08-12 22:54:23 +00:00
d_channel = 0U ;
2018-04-04 15:03:49 +00:00
if ( conf_ . it_size = = sizeof ( gr_complex ) )
2018-03-03 01:03:39 +00:00
{
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-04-04 15:03:49 +00:00
if ( acq_parameters . bit_transition_flag )
2018-02-05 06:31:34 +00:00
{
2018-07-10 14:25:16 +00:00
d_fft_size = d_consumed_samples * 2 ;
2018-07-10 05:45:49 +00:00
acq_parameters . max_dwells = 1 ; // Activation of acq_parameters.bit_transition_flag invalidates the value of acq_parameters.max_dwells
2018-02-05 06:31:34 +00:00
}
2015-08-06 08:34:25 +00:00
2018-07-10 14:25:16 +00:00
d_tmp_buffer = static_cast < float * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( float ) , volk_gnsssdr_get_alignment ( ) ) ) ;
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 ( ) ) ) ;
2018-07-10 14:25:16 +00:00
d_input_signal = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , 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
2018-12-03 09:05:47 +00:00
d_gnss_synchro = nullptr ;
2018-04-04 12:59:28 +00:00
d_grid_doppler_wipeoffs = nullptr ;
d_grid_doppler_wipeoffs_step_two = nullptr ;
2018-07-08 11:26:30 +00:00
d_magnitude_grid = nullptr ;
2017-08-24 11:32:37 +00:00
d_worker_active = false ;
2018-07-10 14:25:16 +00:00
d_data_buffer = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_consumed_samples * 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
{
2018-07-10 14:25:16 +00:00
d_data_buffer_sc = static_cast < lv_16sc_t * > ( volk_gnsssdr_malloc ( d_consumed_samples * sizeof ( lv_16sc_t ) , volk_gnsssdr_get_alignment ( ) ) ) ;
2018-02-07 07:43:44 +00:00
}
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 ( ) ;
2018-08-09 10:47:20 +00:00
narrow_grid_ = arma : : fmat ( ) ;
2018-04-04 12:59:28 +00:00
d_step_two = false ;
2018-08-09 10:47:20 +00:00
d_num_doppler_bins_step2 = acq_parameters . num_doppler_bins_step2 ;
2018-10-30 11:04:59 +00:00
2018-07-10 15:43:05 +00:00
d_samplesPerChip = acq_parameters . samples_per_chip ;
2018-08-12 22:54:23 +00:00
d_buffer_count = 0U ;
2018-07-10 05:45:49 +00:00
// todo: CFAR statistic not available for non-coherent integration
if ( acq_parameters . max_dwells = = 1 )
{
d_use_CFAR_algorithm_flag = acq_parameters . use_CFAR_algorithm_flag ;
}
else
{
d_use_CFAR_algorithm_flag = false ;
}
2018-10-30 11:04:59 +00:00
d_dump_number = 0LL ;
d_dump_channel = acq_parameters . dump_channel ;
d_dump = acq_parameters . dump ;
d_dump_filename = acq_parameters . dump_filename ;
if ( d_dump )
{
std : : string dump_path ;
// Get path
2018-12-03 17:17:21 +00:00
if ( d_dump_filename . find_last_of ( ' / ' ) ! = std : : string : : npos )
2018-10-30 11:04:59 +00:00
{
2018-12-03 17:17:21 +00:00
std : : string dump_filename_ = d_dump_filename . substr ( d_dump_filename . find_last_of ( ' / ' ) + 1 ) ;
dump_path = d_dump_filename . substr ( 0 , d_dump_filename . find_last_of ( ' / ' ) ) ;
2018-10-30 11:04:59 +00:00
d_dump_filename = dump_filename_ ;
}
else
{
dump_path = std : : string ( " . " ) ;
}
if ( d_dump_filename . empty ( ) )
{
d_dump_filename = " acquisition " ;
}
// remove extension if any
2018-12-03 17:17:21 +00:00
if ( d_dump_filename . substr ( 1 ) . find_last_of ( ' . ' ) ! = std : : string : : npos )
2018-10-30 11:04:59 +00:00
{
2018-12-03 17:17:21 +00:00
d_dump_filename = d_dump_filename . substr ( 0 , d_dump_filename . find_last_of ( ' . ' ) ) ;
2018-10-30 11:04:59 +00:00
}
d_dump_filename = dump_path + boost : : filesystem : : path : : preferred_separator + d_dump_filename ;
// create directory
if ( ! gnss_sdr_create_directory ( dump_path ) )
{
std : : cerr < < " GNSS-SDR cannot create dump file for the Acquisition block. Wrong permissions? " < < std : : endl ;
d_dump = false ;
}
}
2011-10-01 18:45:20 +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 )
{
2018-08-10 18:34:03 +00:00
for ( uint32_t i = 0 ; i < d_num_doppler_bins ; i + + )
2013-10-01 20:32:04 +00:00
{
2016-08-18 12:17:02 +00:00
volk_gnsssdr_free ( d_grid_doppler_wipeoffs [ i ] ) ;
2018-07-08 11:26:30 +00:00
volk_gnsssdr_free ( d_magnitude_grid [ i ] ) ;
2013-10-01 20:32:04 +00:00
}
2013-07-23 18:03:07 +00:00
delete [ ] d_grid_doppler_wipeoffs ;
2018-07-08 11:26:30 +00:00
delete [ ] d_magnitude_grid ;
2013-07-23 18:03:07 +00:00
}
2018-04-04 15:03:49 +00:00
if ( acq_parameters . make_2_steps )
2018-04-04 12:59:28 +00:00
{
2018-08-10 18:34:03 +00:00
for ( uint32_t i = 0 ; i < d_num_doppler_bins_step2 ; i + + )
2018-04-04 12:59:28 +00:00
{
volk_gnsssdr_free ( d_grid_doppler_wipeoffs_step_two [ i ] ) ;
}
delete [ ] d_grid_doppler_wipeoffs_step_two ;
}
2016-08-18 12:17:02 +00:00
volk_gnsssdr_free ( d_fft_codes ) ;
volk_gnsssdr_free ( d_magnitude ) ;
2018-07-08 11:26:30 +00:00
volk_gnsssdr_free ( d_tmp_buffer ) ;
2018-07-10 14:25:16 +00:00
volk_gnsssdr_free ( d_input_signal ) ;
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-12-05 15:50:32 +00:00
void pcps_acquisition : : set_resampler_latency ( uint32_t latency_samples )
{
gr : : thread : : scoped_lock lock ( d_setlock ) ; // require mutex with work function called by the scheduler
acq_parameters . resampler_latency_samples = latency_samples ;
}
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
2018-08-12 22:54:23 +00:00
d_old_freq = 0LL ;
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
2018-04-04 15:03:49 +00:00
if ( acq_parameters . bit_transition_flag )
2016-04-10 08:29:25 +00:00
{
2018-08-10 18:34:03 +00:00
int32_t 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
{
2018-07-15 02:12:20 +00:00
if ( acq_parameters . sampled_ms = = acq_parameters . ms_per_code )
2018-07-10 14:25:16 +00:00
{
memcpy ( d_fft_if - > get_inbuf ( ) , code , sizeof ( gr_complex ) * d_consumed_samples ) ;
}
else
{
std : : fill_n ( d_fft_if - > get_inbuf ( ) , d_fft_size - d_consumed_samples , gr_complex ( 0.0 , 0.0 ) ) ;
memcpy ( d_fft_if - > get_inbuf ( ) + d_consumed_samples , code , sizeof ( gr_complex ) * d_consumed_samples ) ;
}
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
{
2018-06-06 15:25:03 +00:00
d_old_freq + = DFRQ1_GLO * GLONASS_PRN . at ( d_gnss_synchro - > PRN ) ;
LOG ( INFO ) < < " Trying to acquire SV PRN " < < d_gnss_synchro - > PRN < < " with freq " < < d_old_freq < < " in Glonass Channel " < < GLONASS_PRN . at ( d_gnss_synchro - > PRN ) < < std : : endl ;
2017-06-05 23:22:46 +00:00
return true ;
}
2018-12-03 21:08:19 +00:00
if ( strcmp ( d_gnss_synchro - > Signal , " 2G " ) = = 0 )
2018-03-24 18:42:04 +00:00
{
2018-06-06 15:25:03 +00:00
d_old_freq + = DFRQ2_GLO * GLONASS_PRN . at ( d_gnss_synchro - > PRN ) ;
LOG ( INFO ) < < " Trying to acquire SV PRN " < < d_gnss_synchro - > PRN < < " with freq " < < d_old_freq < < " in Glonass Channel " < < GLONASS_PRN . at ( d_gnss_synchro - > PRN ) < < std : : endl ;
2018-03-24 18:42:04 +00:00
return true ;
}
2018-12-04 12:20:49 +00:00
return false ;
2017-06-05 23:22:46 +00:00
}
2016-04-10 08:29:25 +00:00
2018-08-10 18:34:03 +00:00
void pcps_acquisition : : update_local_carrier ( gr_complex * carrier_vector , int32_t correlator_length_samples , float freq )
2016-02-25 17:21:30 +00:00
{
2018-12-03 16:58:18 +00:00
float phase_step_rad ;
if ( acq_parameters . use_automatic_resampler )
{
phase_step_rad = GPS_TWO_PI * freq / static_cast < float > ( acq_parameters . resampled_fs ) ;
}
else
{
phase_step_rad = GPS_TWO_PI * freq / static_cast < float > ( acq_parameters . fs_in ) ;
}
2016-03-20 23:38:08 +00:00
float _phase [ 1 ] ;
2018-08-12 22:54:23 +00:00
_phase [ 0 ] = 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 ;
2018-08-21 09:50:39 +00:00
d_gnss_synchro - > Acq_doppler_step = 0U ;
2012-10-19 16:00:40 +00:00
d_gnss_synchro - > Acq_delay_samples = 0.0 ;
d_gnss_synchro - > Acq_doppler_hz = 0.0 ;
2018-08-12 22:54:23 +00:00
d_gnss_synchro - > Acq_samplestamp_samples = 0ULL ;
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-08-11 09:42:07 +00:00
d_num_doppler_bins = static_cast < uint32_t > ( std : : ceil ( static_cast < double > ( static_cast < int32_t > ( acq_parameters . doppler_max ) - static_cast < int32_t > ( - acq_parameters . doppler_max ) ) / static_cast < double > ( d_doppler_step ) ) ) ;
2013-10-01 20:32:04 +00:00
// Create the carrier Doppler wipeoff signals
2019-02-11 20:13:02 +00:00
if ( d_grid_doppler_wipeoffs = = nullptr )
{
d_grid_doppler_wipeoffs = new gr_complex * [ d_num_doppler_bins ] ;
}
2018-09-17 09:30:42 +00:00
if ( acq_parameters . make_2_steps & & ( d_grid_doppler_wipeoffs_step_two = = nullptr ) )
2013-07-23 18:03:07 +00:00
{
2018-08-09 10:47:20 +00:00
d_grid_doppler_wipeoffs_step_two = new gr_complex * [ d_num_doppler_bins_step2 ] ;
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins_step2 ; doppler_index + + )
2018-04-04 15:03:49 +00:00
{
d_grid_doppler_wipeoffs_step_two [ doppler_index ] = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
}
2013-07-23 18:03:07 +00:00
}
2018-07-08 11:26:30 +00:00
2018-09-17 09:30:42 +00:00
if ( d_magnitude_grid = = nullptr )
{
d_magnitude_grid = new float * [ d_num_doppler_bins ] ;
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
{
d_grid_doppler_wipeoffs [ doppler_index ] = static_cast < gr_complex * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( gr_complex ) , volk_gnsssdr_get_alignment ( ) ) ) ;
d_magnitude_grid [ doppler_index ] = static_cast < float * > ( volk_gnsssdr_malloc ( d_fft_size * sizeof ( float ) , volk_gnsssdr_get_alignment ( ) ) ) ;
}
}
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
2018-04-04 12:59:28 +00:00
{
2018-08-10 18:34:03 +00:00
for ( uint32_t k = 0 ; k < d_fft_size ; k + + )
2018-07-12 18:32:05 +00:00
{
d_magnitude_grid [ doppler_index ] [ k ] = 0.0 ;
}
2018-08-11 09:42:07 +00:00
int32_t doppler = - static_cast < int32_t > ( acq_parameters . doppler_max ) + d_doppler_step * doppler_index ;
2018-06-06 15:25:03 +00:00
update_local_carrier ( d_grid_doppler_wipeoffs [ doppler_index ] , d_fft_size , d_old_freq + doppler ) ;
2018-04-04 12:59:28 +00:00
}
2018-07-12 18:32:05 +00:00
2017-08-24 11:32:37 +00:00
d_worker_active = false ;
2018-01-23 11:28:29 +00:00
2018-10-30 11:04:59 +00:00
if ( d_dump )
2018-02-05 06:31:34 +00:00
{
2018-08-10 18:34:03 +00:00
uint32_t effective_fft_size = ( acq_parameters . bit_transition_flag ? ( d_fft_size / 2 ) : d_fft_size ) ;
2018-02-05 06:31:34 +00:00
grid_ = arma : : fmat ( effective_fft_size , d_num_doppler_bins , arma : : fill : : zeros ) ;
2018-08-09 10:47:20 +00:00
narrow_grid_ = arma : : fmat ( effective_fft_size , d_num_doppler_bins_step2 , arma : : fill : : zeros ) ;
2018-02-05 06:31:34 +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 : : update_grid_doppler_wipeoffs ( )
2017-06-05 23:22:46 +00:00
{
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
2013-07-23 18:03:07 +00:00
{
2018-08-11 09:42:07 +00:00
int32_t doppler = - static_cast < int32_t > ( acq_parameters . doppler_max ) + d_doppler_step * doppler_index ;
2018-06-06 15:25:03 +00:00
update_local_carrier ( d_grid_doppler_wipeoffs [ doppler_index ] , d_fft_size , d_old_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
2018-07-08 11:26:30 +00:00
2018-04-04 12:59:28 +00:00
void pcps_acquisition : : update_grid_doppler_wipeoffs_step2 ( )
{
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins_step2 ; doppler_index + + )
2018-04-04 12:59:28 +00:00
{
2018-08-09 10:47:20 +00:00
float doppler = ( static_cast < float > ( doppler_index ) - static_cast < float > ( floor ( d_num_doppler_bins_step2 / 2.0 ) ) ) * acq_parameters . doppler_step2 ;
2018-04-04 12:59:28 +00:00
update_local_carrier ( d_grid_doppler_wipeoffs_step_two [ doppler_index ] , d_fft_size , d_doppler_center_step_two + doppler ) ;
}
}
2015-02-10 18:30:15 +00:00
2018-07-08 11:26:30 +00:00
2018-08-10 18:34:03 +00:00
void pcps_acquisition : : set_state ( int32_t 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 ;
2018-08-12 22:54:23 +00:00
d_gnss_synchro - > Acq_samplestamp_samples = 0ULL ;
2018-08-21 09:50:39 +00:00
d_gnss_synchro - > Acq_doppler_step = 0U ;
2016-04-10 08:29:25 +00:00
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
{
2018-08-08 13:02:29 +00:00
// Declare positive acquisition using a message port
// 0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
2017-04-12 15:04:51 +00:00
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 ;
2018-06-22 10:30:30 +00:00
d_positive_acq = 1 ;
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
{
2018-08-08 13:02:29 +00:00
// Declare negative acquisition using a message port
// 0=STOP_CHANNEL 1=ACQ_SUCCEES 2=ACQ_FAIL
2017-04-12 15:04:51 +00:00
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 ;
2018-06-22 10:30:30 +00:00
d_positive_acq = 0 ;
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-08-10 18:34:03 +00:00
void pcps_acquisition : : dump_results ( int32_t effective_fft_size )
2018-06-20 18:48:43 +00:00
{
2018-06-21 06:05:33 +00:00
d_dump_number + + ;
2018-10-30 11:04:59 +00:00
std : : string filename = d_dump_filename ;
2018-06-21 06:05:33 +00:00
filename . append ( " _ " ) ;
filename . append ( 1 , d_gnss_synchro - > System ) ;
filename . append ( " _ " ) ;
filename . append ( 1 , d_gnss_synchro - > Signal [ 0 ] ) ;
filename . append ( 1 , d_gnss_synchro - > Signal [ 1 ] ) ;
filename . append ( " _ch_ " ) ;
filename . append ( std : : to_string ( d_channel ) ) ;
filename . append ( " _ " ) ;
filename . append ( std : : to_string ( d_dump_number ) ) ;
filename . append ( " _sat_ " ) ;
filename . append ( std : : to_string ( d_gnss_synchro - > PRN ) ) ;
filename . append ( " .mat " ) ;
2018-12-03 09:05:47 +00:00
mat_t * matfp = Mat_CreateVer ( filename . c_str ( ) , nullptr , MAT_FT_MAT73 ) ;
if ( matfp = = nullptr )
2018-06-20 18:48:43 +00:00
{
2018-06-21 06:05:33 +00:00
std : : cout < < " Unable to create or open Acquisition dump file " < < std : : endl ;
2018-10-30 11:04:59 +00:00
//acq_parameters.dump = false;
2018-06-21 06:05:33 +00:00
}
else
{
size_t dims [ 2 ] = { static_cast < size_t > ( effective_fft_size ) , static_cast < size_t > ( d_num_doppler_bins ) } ;
2018-06-24 09:05:58 +00:00
matvar_t * matvar = Mat_VarCreate ( " acq_grid " , MAT_C_SINGLE , MAT_T_SINGLE , 2 , dims , grid_ . memptr ( ) , 0 ) ;
2018-06-21 06:05:33 +00:00
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
dims [ 0 ] = static_cast < size_t > ( 1 ) ;
dims [ 1 ] = static_cast < size_t > ( 1 ) ;
matvar = Mat_VarCreate ( " doppler_max " , MAT_C_UINT32 , MAT_T_UINT32 , 1 , dims , & acq_parameters . doppler_max , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " doppler_step " , MAT_C_UINT32 , MAT_T_UINT32 , 1 , dims , & d_doppler_step , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
2018-06-21 10:21:35 +00:00
matvar = Mat_VarCreate ( " d_positive_acq " , MAT_C_INT32 , MAT_T_INT32 , 1 , dims , & d_positive_acq , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
2018-12-03 15:25:11 +00:00
auto aux = static_cast < float > ( d_gnss_synchro - > Acq_doppler_hz ) ;
2018-06-21 10:21:35 +00:00
matvar = Mat_VarCreate ( " acq_doppler_hz " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & aux , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
aux = static_cast < float > ( d_gnss_synchro - > Acq_delay_samples ) ;
matvar = Mat_VarCreate ( " acq_delay_samples " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & aux , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " test_statistic " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & d_test_statistics , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " threshold " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & d_threshold , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " input_power " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & d_input_power , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
matvar = Mat_VarCreate ( " sample_counter " , MAT_C_UINT64 , MAT_T_UINT64 , 1 , dims , & d_sample_counter , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
2018-06-24 09:05:58 +00:00
matvar = Mat_VarCreate ( " PRN " , MAT_C_UINT32 , MAT_T_UINT32 , 1 , dims , & d_gnss_synchro - > PRN , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
2018-08-09 10:47:20 +00:00
matvar = Mat_VarCreate ( " num_dwells " , MAT_C_UINT32 , MAT_T_UINT32 , 1 , dims , & d_num_noncoherent_integrations_counter , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
if ( acq_parameters . make_2_steps )
{
dims [ 0 ] = static_cast < size_t > ( effective_fft_size ) ;
dims [ 1 ] = static_cast < size_t > ( d_num_doppler_bins_step2 ) ;
matvar = Mat_VarCreate ( " acq_grid_narrow " , MAT_C_SINGLE , MAT_T_SINGLE , 2 , dims , narrow_grid_ . memptr ( ) , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
dims [ 0 ] = static_cast < size_t > ( 1 ) ;
dims [ 1 ] = static_cast < size_t > ( 1 ) ;
matvar = Mat_VarCreate ( " doppler_step_narrow " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & acq_parameters . doppler_step2 , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
aux = d_doppler_center_step_two - static_cast < float > ( floor ( d_num_doppler_bins_step2 / 2.0 ) ) * acq_parameters . doppler_step2 ;
matvar = Mat_VarCreate ( " doppler_grid_narrow_min " , MAT_C_SINGLE , MAT_T_SINGLE , 1 , dims , & aux , 0 ) ;
Mat_VarWrite ( matfp , matvar , MAT_COMPRESSION_ZLIB ) ; // or MAT_COMPRESSION_NONE
Mat_VarFree ( matvar ) ;
}
2018-06-21 06:05:33 +00:00
Mat_Close ( matfp ) ;
2018-06-20 18:48:43 +00:00
}
}
2018-07-10 05:45:49 +00:00
2018-08-10 18:34:03 +00:00
float pcps_acquisition : : max_to_input_power_statistic ( uint32_t & indext , int32_t & doppler , float input_power , uint32_t num_doppler_bins , int32_t doppler_max , int32_t doppler_step )
2018-07-09 15:56:47 +00:00
{
2018-07-10 05:45:49 +00:00
float grid_maximum = 0.0 ;
2018-08-12 22:54:23 +00:00
uint32_t index_doppler = 0U ;
uint32_t tmp_intex_t = 0U ;
uint32_t index_time = 0U ;
2018-07-10 05:45:49 +00:00
float fft_normalization_factor = static_cast < float > ( d_fft_size ) * static_cast < float > ( d_fft_size ) ;
2018-07-09 15:56:47 +00:00
2018-07-10 05:48:08 +00:00
// Find the correlation peak and the carrier frequency
2018-08-10 18:34:03 +00:00
for ( uint32_t i = 0 ; i < num_doppler_bins ; i + + )
2018-07-10 05:45:49 +00:00
{
volk_gnsssdr_32f_index_max_32u ( & tmp_intex_t , d_magnitude_grid [ i ] , d_fft_size ) ;
if ( d_magnitude_grid [ i ] [ tmp_intex_t ] > grid_maximum )
{
grid_maximum = d_magnitude_grid [ i ] [ tmp_intex_t ] ;
index_doppler = i ;
index_time = tmp_intex_t ;
}
}
indext = index_time ;
2018-07-13 09:50:31 +00:00
if ( ! d_step_two )
{
2018-08-11 09:42:07 +00:00
doppler = - static_cast < int32_t > ( doppler_max ) + doppler_step * static_cast < int32_t > ( index_doppler ) ;
2018-07-13 09:50:31 +00:00
}
else
{
2018-08-11 09:42:07 +00:00
doppler = static_cast < int32_t > ( d_doppler_center_step_two + ( static_cast < float > ( index_doppler ) - static_cast < float > ( floor ( d_num_doppler_bins_step2 / 2.0 ) ) ) * acq_parameters . doppler_step2 ) ;
2018-07-13 09:50:31 +00:00
}
2018-07-10 05:45:49 +00:00
float magt = grid_maximum / ( fft_normalization_factor * fft_normalization_factor ) ;
return magt / input_power ;
}
2018-08-10 18:34:03 +00:00
float pcps_acquisition : : first_vs_second_peak_statistic ( uint32_t & indext , int32_t & doppler , uint32_t num_doppler_bins , int32_t doppler_max , int32_t doppler_step )
2018-07-10 05:45:49 +00:00
{
// Look for correlation peaks in the results
// Find the highest peak and compare it to the second highest peak
// The second peak is chosen not closer than 1 chip to the highest peak
float firstPeak = 0.0 ;
2018-08-12 22:54:23 +00:00
uint32_t index_doppler = 0U ;
uint32_t tmp_intex_t = 0U ;
uint32_t index_time = 0U ;
2018-07-10 05:45:49 +00:00
// Find the correlation peak and the carrier frequency
2018-08-10 18:34:03 +00:00
for ( uint32_t i = 0 ; i < num_doppler_bins ; i + + )
2018-07-09 15:56:47 +00:00
{
volk_gnsssdr_32f_index_max_32u ( & tmp_intex_t , d_magnitude_grid [ i ] , d_fft_size ) ;
if ( d_magnitude_grid [ i ] [ tmp_intex_t ] > firstPeak )
{
firstPeak = d_magnitude_grid [ i ] [ tmp_intex_t ] ;
index_doppler = i ;
index_time = tmp_intex_t ;
}
}
indext = index_time ;
2018-07-13 09:50:31 +00:00
if ( ! d_step_two )
{
2018-08-11 09:42:07 +00:00
doppler = - static_cast < int32_t > ( doppler_max ) + doppler_step * static_cast < int32_t > ( index_doppler ) ;
2018-07-13 09:50:31 +00:00
}
else
{
2018-08-11 09:42:07 +00:00
doppler = static_cast < int32_t > ( d_doppler_center_step_two + ( static_cast < float > ( index_doppler ) - static_cast < float > ( floor ( d_num_doppler_bins_step2 / 2.0 ) ) ) * acq_parameters . doppler_step2 ) ;
2018-07-13 09:50:31 +00:00
}
2018-07-09 15:56:47 +00:00
2018-07-10 05:45:49 +00:00
// Find 1 chip wide code phase exclude range around the peak
2018-07-10 15:43:05 +00:00
int32_t excludeRangeIndex1 = index_time - d_samplesPerChip ;
int32_t excludeRangeIndex2 = index_time + d_samplesPerChip ;
2018-07-09 15:56:47 +00:00
2018-07-10 05:45:49 +00:00
// Correct code phase exclude range if the range includes array boundaries
2018-07-09 15:56:47 +00:00
if ( excludeRangeIndex1 < 0 )
{
excludeRangeIndex1 = d_fft_size + excludeRangeIndex1 ;
}
2018-08-11 09:42:07 +00:00
else if ( excludeRangeIndex2 > = static_cast < int32_t > ( d_fft_size ) )
2018-07-09 15:56:47 +00:00
{
excludeRangeIndex2 = excludeRangeIndex2 - d_fft_size ;
}
int32_t idx = excludeRangeIndex1 ;
memcpy ( d_tmp_buffer , d_magnitude_grid [ index_doppler ] , d_fft_size ) ;
do
{
d_tmp_buffer [ idx ] = 0.0 ;
idx + + ;
2019-02-11 20:13:02 +00:00
if ( idx = = static_cast < int32_t > ( d_fft_size ) )
{
idx = 0 ;
}
2018-07-09 15:56:47 +00:00
}
while ( idx ! = excludeRangeIndex2 ) ;
2018-07-10 05:45:49 +00:00
// Find the second highest correlation peak in the same freq. bin ---
2018-07-09 15:56:47 +00:00
volk_gnsssdr_32f_index_max_32u ( & tmp_intex_t , d_tmp_buffer , d_fft_size ) ;
float secondPeak = d_tmp_buffer [ tmp_intex_t ] ;
2018-07-10 05:45:49 +00:00
// Compute the test statistics and compare to the threshold
2018-07-09 15:56:47 +00:00
return firstPeak / secondPeak ;
}
2018-06-20 18:48:43 +00:00
2018-08-10 18:34:03 +00:00
void pcps_acquisition : : acquisition_core ( uint64_t 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-08-08 13:02:29 +00:00
// Initialize acquisition algorithm
2018-08-10 18:34:03 +00:00
int32_t doppler = 0 ;
2018-08-12 22:54:23 +00:00
uint32_t indext = 0U ;
2018-08-10 18:34:03 +00:00
int32_t effective_fft_size = ( acq_parameters . bit_transition_flag ? d_fft_size / 2 : d_fft_size ) ;
2018-03-03 01:03:39 +00:00
if ( d_cshort )
{
2018-07-10 14:25:16 +00:00
volk_gnsssdr_16ic_convert_32fc ( d_data_buffer , d_data_buffer_sc , d_consumed_samples ) ;
}
memcpy ( d_input_signal , d_data_buffer , d_consumed_samples * sizeof ( gr_complex ) ) ;
if ( d_fft_size > d_consumed_samples )
{
2018-08-10 18:34:03 +00:00
for ( uint32_t i = d_consumed_samples ; i < d_fft_size ; i + + )
2018-07-10 14:25:16 +00:00
{
d_input_signal [ i ] = gr_complex ( 0.0 , 0.0 ) ;
}
2018-03-03 01:03:39 +00:00
}
2018-07-10 14:25:16 +00:00
const gr_complex * in = d_input_signal ; // Get the input samples pointer
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 ;
2018-07-08 11:26:30 +00:00
d_num_noncoherent_integrations_counter + + ;
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: "
2018-04-04 15:03:49 +00:00
< < d_threshold < < " , doppler_max: " < < acq_parameters . doppler_max
2018-02-05 06:31:34 +00:00
< < " , doppler_step: " < < d_doppler_step
2018-07-10 05:45:49 +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 ( ) ;
2018-07-10 05:45:49 +00:00
2018-07-10 14:25:16 +00:00
if ( d_use_CFAR_algorithm_flag or acq_parameters . bit_transition_flag )
2018-01-09 15:43:38 +00:00
{
2018-07-10 05:45:49 +00:00
// Compute the input signal power estimation
2018-07-10 06:47:04 +00:00
volk_32fc_magnitude_squared_32f ( d_tmp_buffer , in , d_fft_size ) ;
volk_32f_accumulator_s32f ( & d_input_power , d_tmp_buffer , d_fft_size ) ;
2018-01-09 15:43:38 +00:00
d_input_power / = static_cast < float > ( d_fft_size ) ;
}
2018-07-10 05:45:49 +00:00
// Doppler frequency grid loop
2018-04-04 12:59:28 +00:00
if ( ! d_step_two )
2018-01-09 15:43:38 +00:00
{
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins ; doppler_index + + )
2018-04-04 12:59:28 +00:00
{
2018-07-10 05:45:49 +00:00
// Remove Doppler
2018-04-04 12:59:28 +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-07-10 05:45:49 +00:00
// Perform the FFT-based convolution (parallel time search)
2018-04-04 12:59:28 +00:00
// Compute the FFT of the carrier wiped--off incoming signal
d_fft_if - > execute ( ) ;
2017-10-03 11:47:55 +00:00
2018-07-10 05:45:49 +00:00
// Multiply carrier wiped--off, Fourier transformed incoming signal with the local FFT'd code reference
2018-04-04 12:59:28 +00:00
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-07-10 05:45:49 +00:00
// Compute the inverse FFT
2018-04-04 12:59:28 +00:00
d_ifft - > execute ( ) ;
2017-10-03 11:47:55 +00:00
2018-07-10 05:45:49 +00:00
// Compute squared magnitude (and accumulate in case of non-coherent integration)
2018-04-04 15:03:49 +00:00
size_t offset = ( acq_parameters . bit_transition_flag ? effective_fft_size : 0 ) ;
2018-07-08 11:26:30 +00:00
if ( d_num_noncoherent_integrations_counter = = 1 )
{
volk_32fc_magnitude_squared_32f ( d_magnitude_grid [ doppler_index ] , d_ifft - > get_outbuf ( ) + offset , effective_fft_size ) ;
}
else
{
volk_32fc_magnitude_squared_32f ( d_tmp_buffer , d_ifft - > get_outbuf ( ) + offset , effective_fft_size ) ;
volk_32f_x2_add_32f ( d_magnitude_grid [ doppler_index ] , d_magnitude_grid [ doppler_index ] , d_tmp_buffer , effective_fft_size ) ;
}
2018-04-04 12:59:28 +00:00
// Record results to file if required
2018-10-30 11:04:59 +00:00
if ( d_dump and d_channel = = d_dump_channel )
2018-04-04 12:59:28 +00:00
{
2018-07-08 11:26:30 +00:00
memcpy ( grid_ . colptr ( doppler_index ) , d_magnitude_grid [ doppler_index ] , sizeof ( float ) * effective_fft_size ) ;
2018-01-09 15:43:38 +00:00
}
}
2018-07-10 05:45:49 +00:00
// Compute the test statistic
if ( d_use_CFAR_algorithm_flag )
2018-07-09 15:56:47 +00:00
{
2018-07-13 09:50:31 +00:00
d_test_statistics = max_to_input_power_statistic ( indext , doppler , d_input_power , d_num_doppler_bins , acq_parameters . doppler_max , d_doppler_step ) ;
2018-07-09 15:56:47 +00:00
}
2018-07-10 05:45:49 +00:00
else
{
2018-07-13 09:50:31 +00:00
d_test_statistics = first_vs_second_peak_statistic ( indext , doppler , d_num_doppler_bins , acq_parameters . doppler_max , d_doppler_step ) ;
2018-07-10 05:45:49 +00:00
}
2018-12-03 16:58:18 +00:00
if ( acq_parameters . use_automatic_resampler )
{
//take into account the acquisition resampler ratio
d_gnss_synchro - > Acq_delay_samples = static_cast < double > ( std : : fmod ( static_cast < float > ( indext ) , acq_parameters . samples_per_code ) ) * acq_parameters . resampler_ratio ;
2018-12-05 15:50:32 +00:00
d_gnss_synchro - > Acq_delay_samples - = static_cast < double > ( acq_parameters . resampler_latency_samples ) ; //account the resampler filter latency
2018-12-03 16:58:18 +00:00
d_gnss_synchro - > Acq_doppler_hz = static_cast < double > ( doppler ) ;
d_gnss_synchro - > Acq_samplestamp_samples = rint ( static_cast < double > ( samp_count ) * acq_parameters . resampler_ratio ) ;
}
else
{
d_gnss_synchro - > Acq_delay_samples = static_cast < double > ( std : : fmod ( static_cast < float > ( indext ) , acq_parameters . samples_per_code ) ) ;
d_gnss_synchro - > Acq_doppler_hz = static_cast < double > ( doppler ) ;
d_gnss_synchro - > Acq_samplestamp_samples = samp_count ;
}
2018-04-04 12:59:28 +00:00
}
else
{
2018-08-10 18:34:03 +00:00
for ( uint32_t doppler_index = 0 ; doppler_index < d_num_doppler_bins_step2 ; doppler_index + + )
2018-01-23 11:28:29 +00:00
{
2018-04-04 12:59:28 +00:00
volk_32fc_x2_multiply_32fc ( d_fft_if - > get_inbuf ( ) , in , d_grid_doppler_wipeoffs_step_two [ doppler_index ] , d_fft_size ) ;
2018-08-08 13:02:29 +00:00
// Perform the FFT-based convolution (parallel time search)
2018-04-04 12:59:28 +00:00
// 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 ( d_ifft - > get_inbuf ( ) , d_fft_if - > get_outbuf ( ) , d_fft_codes , d_fft_size ) ;
// compute the inverse FFT
d_ifft - > execute ( ) ;
2018-04-04 15:03:49 +00:00
size_t offset = ( acq_parameters . bit_transition_flag ? effective_fft_size : 0 ) ;
2018-07-13 09:50:31 +00:00
if ( d_num_noncoherent_integrations_counter = = 1 )
2018-02-05 06:31:34 +00:00
{
2018-07-13 09:50:31 +00:00
volk_32fc_magnitude_squared_32f ( d_magnitude_grid [ doppler_index ] , d_ifft - > get_outbuf ( ) + offset , effective_fft_size ) ;
2018-02-05 06:31:34 +00:00
}
2018-07-13 09:50:31 +00:00
else
2018-06-20 18:48:43 +00:00
{
2018-07-13 09:50:31 +00:00
volk_32fc_magnitude_squared_32f ( d_tmp_buffer , d_ifft - > get_outbuf ( ) + offset , effective_fft_size ) ;
volk_32f_x2_add_32f ( d_magnitude_grid [ doppler_index ] , d_magnitude_grid [ doppler_index ] , d_tmp_buffer , effective_fft_size ) ;
2018-06-20 18:48:43 +00:00
}
2018-08-09 10:47:20 +00:00
// Record results to file if required
2018-10-30 11:04:59 +00:00
if ( d_dump and d_channel = = d_dump_channel )
2018-08-09 10:47:20 +00:00
{
memcpy ( narrow_grid_ . colptr ( doppler_index ) , d_magnitude_grid [ doppler_index ] , sizeof ( float ) * effective_fft_size ) ;
}
2017-08-24 11:32:37 +00:00
}
2018-07-13 09:50:31 +00:00
// Compute the test statistic
if ( d_use_CFAR_algorithm_flag )
{
2018-08-11 09:42:07 +00:00
d_test_statistics = max_to_input_power_statistic ( indext , doppler , d_input_power , d_num_doppler_bins_step2 , static_cast < int32_t > ( d_doppler_center_step_two - ( static_cast < float > ( d_num_doppler_bins_step2 ) / 2.0 ) * acq_parameters . doppler_step2 ) , acq_parameters . doppler_step2 ) ;
2018-07-13 09:50:31 +00:00
}
else
{
2018-08-11 09:42:07 +00:00
d_test_statistics = first_vs_second_peak_statistic ( indext , doppler , d_num_doppler_bins_step2 , static_cast < int32_t > ( d_doppler_center_step_two - ( static_cast < float > ( d_num_doppler_bins_step2 ) / 2.0 ) * acq_parameters . doppler_step2 ) , acq_parameters . doppler_step2 ) ;
2018-07-13 09:50:31 +00:00
}
2018-12-03 16:58:18 +00:00
if ( acq_parameters . use_automatic_resampler )
{
//take into account the acquisition resampler ratio
d_gnss_synchro - > Acq_delay_samples = static_cast < double > ( std : : fmod ( static_cast < float > ( indext ) , acq_parameters . samples_per_code ) ) * acq_parameters . resampler_ratio ;
2018-12-05 15:50:32 +00:00
d_gnss_synchro - > Acq_delay_samples - = static_cast < double > ( acq_parameters . resampler_latency_samples ) ; //account the resampler filter latency
2018-12-03 16:58:18 +00:00
d_gnss_synchro - > Acq_doppler_hz = static_cast < double > ( doppler ) ;
d_gnss_synchro - > Acq_samplestamp_samples = rint ( static_cast < double > ( samp_count ) * acq_parameters . resampler_ratio ) ;
d_gnss_synchro - > Acq_doppler_step = acq_parameters . doppler_step2 ;
}
else
{
d_gnss_synchro - > Acq_delay_samples = static_cast < double > ( std : : fmod ( static_cast < float > ( indext ) , acq_parameters . samples_per_code ) ) ;
d_gnss_synchro - > Acq_doppler_hz = static_cast < double > ( doppler ) ;
d_gnss_synchro - > Acq_samplestamp_samples = samp_count ;
d_gnss_synchro - > Acq_doppler_step = acq_parameters . doppler_step2 ;
}
2018-01-09 15:43:38 +00:00
}
2018-07-10 05:45:49 +00:00
2018-01-09 15:43:38 +00:00
lk . lock ( ) ;
2018-04-04 15:03:49 +00:00
if ( ! acq_parameters . bit_transition_flag )
2018-01-09 15:43:38 +00:00
{
if ( d_test_statistics > d_threshold )
{
d_active = false ;
2018-04-04 15:03:49 +00:00
if ( acq_parameters . make_2_steps )
2018-04-04 12:59:28 +00:00
{
2018-04-04 15:03:49 +00:00
if ( d_step_two )
{
send_positive_acquisition ( ) ;
d_step_two = false ;
d_state = 0 ; // Positive acquisition
}
else
{
d_step_two = true ; // Clear input buffer and make small grid acquisition
2018-08-09 10:47:20 +00:00
d_num_noncoherent_integrations_counter = 0 ;
d_positive_acq = 0 ;
2018-04-04 15:03:49 +00:00
d_state = 0 ;
}
2018-04-04 12:59:28 +00:00
}
else
{
2018-04-04 15:03:49 +00:00
send_positive_acquisition ( ) ;
d_state = 0 ; // Positive acquisition
2018-04-04 12:59:28 +00:00
}
2018-01-09 15:43:38 +00:00
}
2018-08-09 10:47:20 +00:00
else
{
d_buffer_count = 0 ;
d_state = 1 ;
}
2018-07-08 11:26:30 +00:00
if ( d_num_noncoherent_integrations_counter = = acq_parameters . max_dwells )
2018-01-09 15:43:38 +00:00
{
2019-02-11 20:13:02 +00:00
if ( d_state ! = 0 )
{
send_negative_acquisition ( ) ;
}
2018-01-09 15:43:38 +00:00
d_state = 0 ;
d_active = false ;
2018-04-04 12:59:28 +00:00
d_step_two = false ;
2018-01-09 15:43:38 +00:00
}
}
else
{
2018-04-04 15:03:49 +00:00
d_active = false ;
if ( d_test_statistics > d_threshold )
2017-09-16 13:57:50 +00:00
{
2018-04-04 15:03:49 +00:00
if ( acq_parameters . make_2_steps )
2017-10-03 11:47:55 +00:00
{
2018-04-04 12:59:28 +00:00
if ( d_step_two )
{
send_positive_acquisition ( ) ;
d_step_two = false ;
d_state = 0 ; // Positive acquisition
}
else
{
d_step_two = true ; // Clear input buffer and make small grid acquisition
2018-08-12 22:54:23 +00:00
d_num_noncoherent_integrations_counter = 0U ;
2018-04-04 12:59:28 +00:00
d_state = 0 ;
}
2017-10-03 11:47:55 +00:00
}
2018-01-09 15:43:38 +00:00
else
2017-10-03 11:47:55 +00:00
{
2018-04-04 15:03:49 +00:00
send_positive_acquisition ( ) ;
d_state = 0 ; // Positive acquisition
2017-10-03 11:47:55 +00:00
}
2017-09-16 13:57:50 +00:00
}
2018-04-04 15:03:49 +00:00
else
{
d_state = 0 ; // Negative acquisition
d_step_two = false ;
send_negative_acquisition ( ) ;
}
2017-10-03 11:47:55 +00:00
}
2017-09-16 13:55:56 +00:00
d_worker_active = false ;
2018-07-08 11:26:30 +00:00
if ( ( d_num_noncoherent_integrations_counter = = acq_parameters . max_dwells ) or ( d_positive_acq = = 1 ) )
2018-06-21 10:21:35 +00:00
{
2018-07-08 11:26:30 +00:00
// Record results to file if required
2018-10-30 11:04:59 +00:00
if ( d_dump and d_channel = = d_dump_channel )
2018-07-08 11:26:30 +00:00
{
pcps_acquisition : : dump_results ( effective_fft_size ) ;
}
2018-08-12 22:54:23 +00:00
d_num_noncoherent_integrations_counter = 0U ;
2018-07-08 11:26:30 +00:00
d_positive_acq = 0 ;
2018-07-12 18:32:05 +00:00
// Reset grid
2018-08-10 18:34:03 +00:00
for ( uint32_t i = 0 ; i < d_num_doppler_bins ; i + + )
2018-07-12 18:32:05 +00:00
{
2018-08-10 18:34:03 +00:00
for ( uint32_t k = 0 ; k < d_fft_size ; k + + )
2018-07-12 18:32:05 +00:00
{
d_magnitude_grid [ i ] [ k ] = 0.0 ;
}
}
2018-06-21 10:21:35 +00:00
}
2017-09-16 13:55:56 +00:00
}
2018-04-13 09:07:58 +00:00
2018-12-03 16:58:18 +00:00
// Called by gnuradio to enable drivers, etc for i/o devices.
bool pcps_acquisition : : start ( )
{
d_sample_counter = 0ULL ;
return true ;
}
2018-04-13 09:07:58 +00:00
int pcps_acquisition : : general_work ( int noutput_items __attribute__ ( ( unused ) ) ,
gr_vector_int & ninput_items , gr_vector_const_void_star & input_items ,
gr_vector_void_star & output_items __attribute__ ( ( unused ) ) )
{
/*
* By J . Arribas , L . Esteve and M . Molina
* Acquisition strategy ( Kay Borre book + CFAR threshold ) :
* 1. Compute the input signal power estimation
* 2. Doppler serial search loop
* 3. Perform the FFT - based circular convolution ( parallel time search )
* 4. Record the maximum peak and the associated synchronization parameters
* 5. Compute the test statistics and compare to the threshold
* 6. Declare positive or negative acquisition using a message port
*/
gr : : thread : : scoped_lock lk ( d_setlock ) ;
if ( ! d_active or d_worker_active )
{
2018-06-29 11:39:17 +00:00
if ( ! acq_parameters . blocking_on_standby )
2018-06-28 15:39:37 +00:00
{
2018-08-11 09:42:07 +00:00
d_sample_counter + = static_cast < uint64_t > ( ninput_items [ 0 ] ) ;
2018-06-28 15:39:37 +00:00
consume_each ( ninput_items [ 0 ] ) ;
}
2018-04-13 09:07:58 +00:00
if ( d_step_two )
{
d_doppler_center_step_two = static_cast < float > ( d_gnss_synchro - > Acq_doppler_hz ) ;
update_grid_doppler_wipeoffs_step2 ( ) ;
d_state = 0 ;
d_active = true ;
}
return 0 ;
}
switch ( d_state )
{
case 0 :
{
2018-08-08 13:02:29 +00:00
// Restart acquisition variables
2018-04-13 09:07:58 +00:00
d_gnss_synchro - > Acq_delay_samples = 0.0 ;
d_gnss_synchro - > Acq_doppler_hz = 0.0 ;
2018-08-12 22:54:23 +00:00
d_gnss_synchro - > Acq_samplestamp_samples = 0ULL ;
2018-08-21 09:50:39 +00:00
d_gnss_synchro - > Acq_doppler_step = 0U ;
2018-04-13 09:07:58 +00:00
d_mag = 0.0 ;
d_input_power = 0.0 ;
d_test_statistics = 0.0 ;
d_state = 1 ;
2018-08-12 22:54:23 +00:00
d_buffer_count = 0U ;
2018-06-29 11:39:17 +00:00
if ( ! acq_parameters . blocking_on_standby )
2018-06-28 15:39:37 +00:00
{
2018-08-11 09:42:07 +00:00
d_sample_counter + = static_cast < uint64_t > ( ninput_items [ 0 ] ) ; // sample counter
2018-06-28 15:39:37 +00:00
consume_each ( ninput_items [ 0 ] ) ;
}
2018-04-13 09:07:58 +00:00
break ;
}
case 1 :
{
2018-08-10 18:34:03 +00:00
uint32_t buff_increment ;
2018-04-13 09:07:58 +00:00
if ( d_cshort )
{
2018-12-03 15:25:11 +00:00
const auto * in = reinterpret_cast < const lv_16sc_t * > ( input_items [ 0 ] ) ; // Get the input samples pointer
2018-08-08 13:02:29 +00:00
if ( ( ninput_items [ 0 ] + d_buffer_count ) < = d_consumed_samples )
{
buff_increment = ninput_items [ 0 ] ;
}
else
{
buff_increment = d_consumed_samples - d_buffer_count ;
}
memcpy ( & d_data_buffer_sc [ d_buffer_count ] , in , sizeof ( lv_16sc_t ) * buff_increment ) ;
2018-04-13 09:07:58 +00:00
}
else
{
2018-12-03 15:25:11 +00:00
const auto * in = reinterpret_cast < const gr_complex * > ( input_items [ 0 ] ) ; // Get the input samples pointer
2018-08-08 13:02:29 +00:00
if ( ( ninput_items [ 0 ] + d_buffer_count ) < = d_consumed_samples )
{
buff_increment = ninput_items [ 0 ] ;
}
else
{
buff_increment = d_consumed_samples - d_buffer_count ;
}
memcpy ( & d_data_buffer [ d_buffer_count ] , in , sizeof ( gr_complex ) * buff_increment ) ;
}
// If buffer will be full in next iteration
if ( d_buffer_count > = d_consumed_samples )
{
d_state = 2 ;
2018-04-13 09:07:58 +00:00
}
2018-08-08 13:02:29 +00:00
d_buffer_count + = buff_increment ;
2018-08-11 09:42:07 +00:00
d_sample_counter + = static_cast < uint64_t > ( buff_increment ) ;
2018-08-08 13:02:29 +00:00
consume_each ( buff_increment ) ;
break ;
}
case 2 :
{
// Copy the data to the core and let it know that new data is available
2018-04-13 09:07:58 +00:00
if ( acq_parameters . 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 ;
}
2018-08-08 13:02:29 +00:00
consume_each ( 0 ) ;
2018-08-12 22:54:23 +00:00
d_buffer_count = 0U ;
2018-04-13 09:07:58 +00:00
break ;
}
}
return 0 ;
}