1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-09-13 08:16:03 +00:00

Added test for code_resampler - passing now

Also implemented a speedup for the bounds checking on
CodeResamplerGeneric and implemented bounds checking on CodeResamplerFxpt64
This commit is contained in:
Cillian O'Driscoll
2015-12-02 14:07:01 +00:00
parent ea162bacad
commit d08e634908
3 changed files with 611 additions and 20 deletions

View File

@@ -37,7 +37,13 @@
#ifndef GNSS_SDR_CODE_RESAMPLER_H_
#define GNSS_SDR_CODE_RESAMPLER_H_
#include <volk/volk.h>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <limits>
#include "fxpt64.h"
#include <cassert>
/*!
* \brief Interface for a generic code resampler
*
@@ -52,7 +58,7 @@ public:
* Actually perform the code resampling.
*/
virtual void resample_code( T const *orig_code, unsigned int code_length,
std::vector< double > &init_code_phase, double code_phase_step,
std::vector< double > &init_code_phase, double &code_phase_step,
int num_samples,
std::vector< T * > resampled_codes ) = 0;
};
@@ -70,22 +76,49 @@ public:
* output.
*/
virtual void resample_code( T const *orig_code, unsigned int code_length,
std::vector< double > &init_code_phase, double code_phase_step,
std::vector< double > &init_code_phase, double &code_phase_step,
int num_samples,
std::vector< T * > resampled_codes )
{
// Loop over the desired outputs:
for( int i = 0; i < init_code_phase.size(); ++i )
{
double tcode_chips = init_code_phase[i];
double tcode_chips = std::fmod( init_code_phase[i], code_length);
if( tcode_chips < 0.0 )
{
tcode_chips += static_cast< double >( code_length );
}
int associated_chip_index;
T *curr_sample = resampled_codes[i];
for( int j = 0; j < num_samples; ++j )
int j = 0;
// Here we lift the bounds checking out of the loop:
// This gave a performance improvement of about a factor 3.3
while( j < num_samples )
{
associated_chip_index = std::floor(std::fmod(tcode_chips , code_length_chips));
*curr_sample = orig_code[associated_chip_index];
tcode_chips = tcode_chips + code_phase_step_chips;
++curr_sample;
int num_samples_this_iter = num_samples;
int num_samples_at_rollover = j + std::floor(
( code_length - tcode_chips )/code_phase_step
) + 1;
if( num_samples_at_rollover < num_samples )
{
num_samples_this_iter = num_samples_at_rollover;
}
for( ; j < num_samples_this_iter; ++j )
{
associated_chip_index = std::floor(tcode_chips);
*curr_sample = orig_code[associated_chip_index];
tcode_chips += code_phase_step;
++curr_sample;
}
tcode_chips = std::fmod( tcode_chips, code_length );
}
}
}
@@ -108,7 +141,7 @@ public:
* Resample the code computing the code phases exactly for the latest output
* and forcing all others to be integer shifts of the latest value*/
virtual void resample_code( T const *orig_code, unsigned int code_length,
std::vector< double > &init_code_phase, double code_phase_step,
std::vector< double > &init_code_phase, double &code_phase_step,
int num_samples,
std::vector< T * > resampled_codes )
{
@@ -129,7 +162,7 @@ public:
std::vector< T * > dummy_resampled_codes(1, resampled_codes[0] );
std::vector< double > dummy_init_code_phase(1, init_code_phase[0] );
core_resampler->resample_code( orig_code, code_length,
d_core_resampler->resample_code( orig_code, code_length,
dummy_init_code_phase, code_phase_step,
total_samples, dummy_resampled_codes );
@@ -154,6 +187,7 @@ private:
/*!
* \brief Code resampler that uses 64 bit fixed point arithmetic */
template< typename T, unsigned FRAC_LEN = 32 >
class CodeResamplerFxpt64 : public CodeResamplerInterface<T>
{
@@ -162,7 +196,7 @@ public:
* Resample the code using 64-bit fixed point arithmetic
*/
virtual void resample_code( T const *orig_code, unsigned int code_length,
std::vector< double > &init_code_phase, double code_phase_step,
std::vector< double > &init_code_phase, double &code_phase_step,
int num_samples,
std::vector< T * > resampled_codes )
{
@@ -171,20 +205,175 @@ public:
// Loop over the desired outputs:
for( int i = 0; i < init_code_phase.size(); ++i )
{
int64_t code_phase_fxp = double_to_fxpt64( init_code_phase[i], FRAC_LEN );
T *curr_sample = resampled_codes[i];
double tcode_chips = std::fmod( init_code_phase[i], code_length );
if( tcode_chips < 0.0 )
{
tcode_chips += code_length;
}
int64_t code_phase_fxp = double_to_fxpt64( tcode_chips, FRAC_LEN );
T *curr_sample = resampled_codes[i];
init_code_phase[i] = fxpt64_to_double( code_phase_fxp );
for( int j = 0; j < num_samples; ++j )
int j = 0;
while( j < num_samples )
{
*curr_sample = orig_code[ code_phase_fxp >> FRAC_LEN ];
code_phase_fxp += code_phase_step_fxp;
++curr_sample;
int num_samples_this_iter = num_samples;
int num_samples_at_rollover = j + std::floor(
(static_cast<double>( code_length ) - fxpt64_to_double( code_phase_fxp )
)/code_phase_step
) + 1;
if( num_samples_at_rollover < num_samples )
{
num_samples_this_iter = num_samples_at_rollover;
}
for( ; j < num_samples_this_iter; ++j )
{
*curr_sample = orig_code[ code_phase_fxp >> FRAC_LEN ];
code_phase_fxp += code_phase_step_fxp;
++curr_sample;
}
assert( static_cast<int>(
fxpt64_to_double( code_phase_fxp - code_phase_step_fxp )
) < code_length );
code_phase_fxp -= ( static_cast< int64_t >( code_length ) << FRAC_LEN );
}
}
code_phase_step = fxpt64_to_double( code_phase_step_fxp );
}
};
/*!
* \brief Code resampler that uses a fixed number of replicas in memory*/
template< typename T >
class CodeResamplerMemoryStore : public CodeResamplerInterface<T>
{
public:
CodeResamplerMemoryStore( T const *orig_code,
unsigned int code_length,
double nominal_code_phase_step,
unsigned int maximum_num_samples,
double code_spacing_chips,
double maximum_code_offset_chips )
: d_nominal_code_phase_step( nominal_code_phase_step ),
d_code_spacing_chips( code_spacing_chips ),
d_maximum_code_offset_chips( maximum_code_offset_chips )
{
int num_replicas = static_cast< int >(
std::ceil( d_maximum_code_offset_chips /
d_code_spacing_chips ) );
// Resize the storage:
d_code_phase_offsets.resize( num_replicas );
d_replica_store.resize( num_replicas );
// Use a generic resampler to generate the local replica store:
CodeResamplerGeneric<T> baseResampler;
double curr_offset = 0.0;
for( int ii = 0; ii < num_replicas; ++ii )
{
d_code_phase_offsets[ii] = curr_offset;
curr_offset += d_code_spacing_chips;
d_replica_store[ii] = static_cast< T *>( volk_malloc(
maximum_num_samples * sizeof( T ),
volk_get_alignment() ) );
}
// Now we generate the codes to be at least twice as long as the maximum possible
baseResampler.resample_code( orig_code, code_length,
d_code_phase_offsets, d_nominal_code_phase_step, 2*maximum_num_samples,
d_replica_store );
};
~CodeResamplerMemoryStore()
{
for( unsigned int ii = 0; ii < d_replica_store.size(); ++ii )
{
volk_free( d_replica_store[ii] );
}
}
/*!
* Resample the code by choosing the local replicas that most closely match
* the code phase offsets required
*/
virtual void resample_code( T const *orig_code, unsigned int code_length,
std::vector< double > &init_code_phase, double &code_phase_step,
int num_samples,
std::vector< T * > resampled_codes )
{
// Loop over the desired outputs:
for( int ii = 0; ii < init_code_phase.size(); ++ii )
{
int offset_ind = 0;
double delta_offset = std::numeric_limits<double>::infinity();
double desired_code_phase = init_code_phase[ii];
double desired_code_phase_mod_one_chip = std::fmod( desired_code_phase, 1.0 );
if( desired_code_phase_mod_one_chip < 0.0 )
{
desired_code_phase_mod_one_chip += 1.0;
}
double achieved_code_phase = 0.0;
for( int jj = 0; jj < d_code_phase_offsets.size(); ++jj )
{
double abs_diff = std::abs( desired_code_phase_mod_one_chip - d_code_phase_offsets[jj] );
if( abs_diff < delta_offset )
{
delta_offset = abs_diff;
offset_ind = jj;
achieved_code_phase = desired_code_phase - desired_code_phase_mod_one_chip
+ d_code_phase_offsets[jj];
}
}
init_code_phase[ii] = achieved_code_phase;
int integer_offset = static_cast< int >( desired_code_phase - desired_code_phase_mod_one_chip );
memcpy( resampled_codes[ii], d_replica_store[offset_ind] + integer_offset*sizeof(T),
num_samples * sizeof( T ) );
}
code_phase_step = d_nominal_code_phase_step;
}
private:
double d_nominal_code_phase_step;
double d_maximum_code_offset_chips;
double d_code_spacing_chips;
std::vector< double > d_code_phase_offsets;
std::vector< T * > d_replica_store;
};
#endif

View File

@@ -366,6 +366,40 @@ else(NOT ${GTEST_DIR_LOCAL})
add_dependencies(trk_test gtest)
endif(NOT ${GTEST_DIR_LOCAL})
add_dependencies(check control_thread_test flowgraph_test gnss_block_test
gnuradio_block_test trk_test)
#####################
## Arithmetic test
add_executable(arithmetic_test
${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc
${CMAKE_CURRENT_SOURCE_DIR}/arithmetic/code_resampler_test.cc
)
if(NOT ${ENABLE_PACKAGING})
set_property(TARGET arithmetic_test PROPERTY EXCLUDE_FROM_ALL TRUE)
endif(NOT ${ENABLE_PACKAGING})
target_link_libraries(arithmetic_test ${Boost_LIBRARIES}
${GFLAGS_LIBS}
${GLOG_LIBRARIES}
${GTEST_LIBRARIES}
${GNURADIO_RUNTIME_LIBRARIES}
${GNURADIO_BLOCKS_LIBRARIES}
${GNURADIO_FILTER_LIBRARIES}
${GNURADIO_ANALOG_LIBRARIES}
gnss_sp_libs
gnss_rx
gnss_system_parameters
signal_generator_blocks
out_adapters
${VOLK_GNSSSDR_LIBRARIES} ${ORC_LIBRARIES}
)
add_test(arithmetic_test arithmetic_test)
if(NOT ${GTEST_DIR_LOCAL})
add_dependencies(arithmetic_test gtest-${gtest_RELEASE})
else(NOT ${GTEST_DIR_LOCAL})
add_dependencies(arithmetic_test gtest)
endif(NOT ${GTEST_DIR_LOCAL})
add_dependencies(check control_thread_test flowgraph_test gnss_block_test
gnuradio_block_test trk_test arithmetic_test)

View File

@@ -0,0 +1,368 @@
/*!
* \file code_generation_test.cc
* \brief This file implements tests for resampling codes
* \author Cillian O'Driscoll, 2015. cillian.odriscoll(at)gmail.com
*
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2015 (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 "code_resampler.h"
#include <complex>
#include <ctime>
#include <sys/time.h>
#include "gps_sdr_signal_processing.h"
#include "gnss_signal_processing.h"
#include <gtest/gtest.h>
void allocate_replicas( std::vector< std::complex< float > * >& replicas, int num_samples )
{
for( int i = 0; i < replicas.size(); ++i )
{
replicas[i] = static_cast< std::complex<float> *>(
volk_malloc( num_samples*sizeof( std::complex<float> ),
volk_get_alignment() )
);
}
}
void deallocate_replicas( std::vector< std::complex< float > * > &replicas )
{
for( int i = 0; i < replicas.size(); ++i )
{
volk_free( replicas[i] );
}
}
TEST(CodeResamplerTest, CodeResamplerGeneric )
{
std::complex<float>* _orig_code = new std::complex<float>[1023];
signed int _prn = 1;
unsigned int _chip_shift = 4;
unsigned int _num_replicas = 3;
double fs = 6e6;
double fc = 1.023e6;
double code_phase_step = fc/fs;
double code_spacing_chips = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_codes;
_resampled_codes.resize(_num_replicas);
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(_num_replicas);
gps_l1_ca_code_gen_complex( _orig_code, _prn, 0);
allocate_replicas( _resampled_codes, _num_samples );
CodeResamplerGeneric< std::complex< float > > the_resampler;
int iterations = 1000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
double current_code_phase = static_cast< double >( i ) - code_spacing_chips;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_code_phases[j] = current_code_phase;
current_code_phase += code_spacing_chips;
}
the_resampler.resample_code( _orig_code, 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_codes );
}
delete[] _orig_code;
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Resampling completed in " << (end - begin) << " microseconds" << std::endl;
deallocate_replicas( _resampled_codes );
}
TEST(CodeResamplerTest, CodeResamplerIntegerChipSpacing )
{
std::complex<float>* _orig_code = new std::complex<float>[1023];
signed int _prn = 1;
unsigned int _chip_shift = 4;
unsigned int _num_replicas = 3;
double fs = 6e6;
double fc = 1.023e6;
double code_phase_step = fc/fs;
double code_spacing_chips = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_codes;
_resampled_codes.resize(_num_replicas);
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(_num_replicas);
gps_l1_ca_code_gen_complex( _orig_code, _prn, 0);
allocate_replicas( _resampled_codes, _num_samples );
CodeResamplerIntegerChipSpacing< std::complex< float > > the_resampler(
boost::shared_ptr< CodeResamplerInterface< std::complex<float> > >(
new CodeResamplerGeneric< std::complex<float> >
));
int iterations = 1000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
double current_code_phase = static_cast< double >( i ) - code_spacing_chips;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_code_phases[j] = current_code_phase;
current_code_phase += code_spacing_chips;
}
the_resampler.resample_code( _orig_code, 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_codes );
}
delete[] _orig_code;
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Resampling completed in " << (end - begin) << " microseconds" << std::endl;
deallocate_replicas( _resampled_codes );
}
TEST(CodeResamplerTest, CodeResamplerFxpt64 )
{
std::complex<float>* _orig_code = new std::complex<float>[1023];
signed int _prn = 1;
unsigned int _chip_shift = 4;
unsigned int _num_replicas = 3;
double fs = 6e6;
double fc = 1.023e6;
double code_phase_step = fc/fs;
double code_spacing_chips = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_codes;
_resampled_codes.resize(_num_replicas);
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(_num_replicas);
gps_l1_ca_code_gen_complex( _orig_code, _prn, 0);
allocate_replicas( _resampled_codes, _num_samples );
CodeResamplerFxpt64< std::complex< float > > the_resampler;
int iterations = 1000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
double current_code_phase = static_cast< double >( i ) - code_spacing_chips;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_code_phases[j] = current_code_phase;
current_code_phase += code_spacing_chips;
}
the_resampler.resample_code( _orig_code, 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_codes );
}
delete[] _orig_code;
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Resampling completed in " << (end - begin) << " microseconds" << std::endl;
deallocate_replicas( _resampled_codes );
}
TEST(CodeResamplerTest, CodeResamplerIntegerChipSpacingFxpt64 )
{
std::complex<float>* _orig_code = new std::complex<float>[1023];
signed int _prn = 1;
unsigned int _chip_shift = 4;
unsigned int _num_replicas = 3;
double fs = 6e6;
double fc = 1.023e6;
double code_phase_step = fc/fs;
double code_spacing_chips = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_codes;
_resampled_codes.resize(_num_replicas);
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(_num_replicas);
gps_l1_ca_code_gen_complex( _orig_code, _prn, 0);
allocate_replicas( _resampled_codes, _num_samples );
CodeResamplerIntegerChipSpacing< std::complex< float > > the_resampler(
boost::shared_ptr< CodeResamplerInterface< std::complex<float> > >(
new CodeResamplerFxpt64< std::complex<float> >
));
int iterations = 1000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
double current_code_phase = static_cast< double >( i ) - code_spacing_chips;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_code_phases[j] = current_code_phase;
current_code_phase += code_spacing_chips;
}
the_resampler.resample_code( _orig_code, 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_codes );
}
delete[] _orig_code;
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Resampling completed in " << (end - begin) << " microseconds" << std::endl;
deallocate_replicas( _resampled_codes );
}
TEST(CodeResamplerTest, CodeResamplerMemoryStore )
{
std::complex<float>* _orig_code = new std::complex<float>[1023];
signed int _prn = 1;
unsigned int _chip_shift = 4;
unsigned int _num_replicas = 3;
double fs = 6e6;
double fc = 1.023e6;
double code_phase_step = fc/fs;
double code_spacing_chips = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_codes;
_resampled_codes.resize(_num_replicas);
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(_num_replicas);
gps_l1_ca_code_gen_complex( _orig_code, _prn, 0);
allocate_replicas( _resampled_codes, _num_samples );
CodeResamplerMemoryStore< std::complex< float > > the_resampler(
_orig_code, 1023, code_phase_step, _num_samples, 0.1, 1.0 );
int iterations = 1000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
double current_code_phase = static_cast< double >( i ) - code_spacing_chips;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_code_phases[j] = current_code_phase;
current_code_phase += code_spacing_chips;
}
the_resampler.resample_code( _orig_code, 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_codes );
}
delete[] _orig_code;
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Resampling completed in " << (end - begin) << " microseconds" << std::endl;
deallocate_replicas( _resampled_codes );
}