1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-12-05 16:18:06 +00:00

Merge branch 'codeless' into prs_codeless

This commit is contained in:
Cillian O'Driscoll
2015-12-03 09:50:41 +00:00
10 changed files with 1864 additions and 3 deletions

View File

@@ -0,0 +1,66 @@
/*!
* \file accumulate_array.h
* \brief Class providing functionality similar to Matlab's accumarray
* \authors Cillian O'Driscoll 2015. cillian.odriscoll(at)gmail.com
*
* This function accumulates data from an input vector, into an output
* vector, according to the indices provided by an index vector.
*
* e.g.
*
* Input:
* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
*
* Index Vec:
* 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3
*
* Output:
* Before:
* 0, 0, 0, 0, 0
* After:
* 3, 18, 15, 42, 0
*
* Note accumulate_array does not zero the output vector
*
* -------------------------------------------------------------------------
*
* 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/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_ACCUMULATE_ARRAY_H_
#define GNSS_SDR_ACCUMULATE_ARRAY_H_
template< typename T >
void accumulate_array( const T *input_vec, const int *index_vec, T *output_vec, int num_samples )
{
const int *curr_index = index_vec;
const T *curr_input = input_vec;
for( unsigned int ii = 0; ii < num_samples; ++ii )
{
output_vec[ *curr_index++ ] += *curr_input++;
}
}
#endif

View File

@@ -0,0 +1,379 @@
/*!
* \file code_resampler.h
* \brief Class providing a number of code resampling options
* \authors Cillian O'Driscoll 2015. cillian.odriscoll(at)gmail.com
*
* Class interface for code resampling. Code resampling is characterised by
* resampling an array that is constant over each element (called a chip).
* The code frequency is called the chip rate, the code phase is a floating
* point value indicating the current chip value between 0 and L -1 where
* L is the code length
*
* -------------------------------------------------------------------------
*
* 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/>.
*
* -------------------------------------------------------------------------
*/
#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
*
*
*/
template< typename T >
class CodeResamplerInterface
{
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,
int num_samples,
std::vector< T * > resampled_codes ) = 0;
};
/*!
* \brief Simple generic implementation of code resampling. Most accurate
* and most expensive
*/
template< typename T >
class CodeResamplerGeneric : public CodeResamplerInterface<T>
{
public:
/*!
* Resample the code computing the code phases exactly for each desired
* output.
*/
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 i = 0; i < init_code_phase.size(); ++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];
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 )
{
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 = static_cast< int >(tcode_chips);
*curr_sample = orig_code[associated_chip_index];
tcode_chips += code_phase_step;
++curr_sample;
}
tcode_chips = std::fmod( tcode_chips, code_length );
}
}
}
};
/*!
* \brief Code resampler that forces the code spacing to the nearest integer
* number of samples
*/
template< typename T >
class CodeResamplerIntegerChipSpacing : public CodeResamplerInterface<T>
{
public:
CodeResamplerIntegerChipSpacing( boost::shared_ptr< CodeResamplerInterface<T> > core_resampler )
: d_core_resampler( core_resampler )
{};
/*!
* 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,
int num_samples,
std::vector< T * > resampled_codes )
{
double earliest_code_phase = init_code_phase[0];
std::vector< int > code_phase_offsets_samples( init_code_phase.size(), 0 );
for( int i = 1; i < init_code_phase.size(); ++i )
{
code_phase_offsets_samples[i] = round(
( init_code_phase[i] - earliest_code_phase ) / code_phase_step
);
}
int total_samples = num_samples + code_phase_offsets_samples.back();
// Now we call the generic implementation for the earliest code phase
// and copy for the later code phases:
std::vector< T * > dummy_resampled_codes(1, resampled_codes[0] );
std::vector< double > dummy_init_code_phase(1, init_code_phase[0] );
d_core_resampler->resample_code( orig_code, code_length,
dummy_init_code_phase, code_phase_step,
total_samples, dummy_resampled_codes );
// Loop over the desired outputs:
for( int i = 1; i < init_code_phase.size(); ++i )
{
// Copy the shifted 'early' code to the later codes:
memcpy( resampled_codes[i], resampled_codes[0] + code_phase_offsets_samples[i],
num_samples * sizeof( T ) );
// Upate the init_code_phase parameter to reflect the true code phases
init_code_phase[i] = init_code_phase[0] + code_phase_offsets_samples[i]*code_phase_step;
}
}
private:
// A code resampler to do the basic resampling on the earliest code phase
boost::shared_ptr< CodeResamplerInterface<T> > d_core_resampler;
};
/*!
* \brief Code resampler that uses 64 bit fixed point arithmetic */
template< typename T, unsigned FRAC_LEN = 32 >
class CodeResamplerFxpt64 : public CodeResamplerInterface<T>
{
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,
int num_samples,
std::vector< T * > resampled_codes )
{
int64_t code_phase_step_fxp = double_to_fxpt64( code_phase_step );
// Loop over the desired outputs:
for( int i = 0; i < init_code_phase.size(); ++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 );
int j = 0;
while( j < num_samples )
{
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

@@ -0,0 +1,366 @@
/*!
* \file subcarrier_resampler.h
* \brief Class providing a number of subcarrier resampling options
* \authors Cillian O'Driscoll 2015. cillian.odriscoll(at)gmail.com
*
* Class interface for subcarrier resampling.
*
* -------------------------------------------------------------------------
*
* 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/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SUBCARRIER_RESAMPLER_H_
#define GNSS_SDR_SUBCARRIER_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 subcarrier resampler
*
*
*/
template< typename T >
class SubcarrierResamplerInterface
{
public:
/*!
* Actually perform the code resampling.
*/
virtual void resample_subcarrier( std::vector< double > &init_subcarrier_phase_cycles,
double &subcarrier_phase_step,
int num_samples,
std::vector< T * > resampled_subcarriers,
bool is_cosine_phased = false) = 0;
protected:
static const std::vector< T > d_subcarrier_table;
};
template< typename T >
const std::vector< T > SubcarrierResamplerInterface< T >::d_subcarrier_table =
{ static_cast< T >( 1.0 ), static_cast<T >( -1.0 ) };
/*!
* \brief Simple generic implementation of subcarrier resampling. Most accurate
* and most expensive
*/
template< typename T >
class SubcarrierResamplerGeneric : public SubcarrierResamplerInterface<T>
{
public:
/*!
* Resample the subcarrier computing the subcarrier phases exactly for each desired
* output.
*/
virtual void resample_subcarrier( std::vector< double > &init_subcarrier_phase_cycles,
double &subcarrier_phase_step,
int num_samples,
std::vector< T * > resampled_subcarriers,
bool is_cosine_phased = false)
{
double subcarrier_phase_step_halfcycles = 2.0 * subcarrier_phase_step;
// Loop over the desired outputs:
for( int i = 0; i < init_subcarrier_phase_cycles.size(); ++i )
{
double tsubcarrier_halfcycles = std::fmod( 2.0*init_subcarrier_phase_cycles[i], 2.0);
if( tsubcarrier_halfcycles < 0.0 )
{
tsubcarrier_halfcycles += 2.0;
}
if( is_cosine_phased )
{
tsubcarrier_halfcycles += 0.5; // add a 1/4 cycle for cosine phasing
}
T *curr_sample = resampled_subcarriers[i];
int64_t int_phase;
for( int j = 0; j < num_samples; ++j )
{
int_phase = static_cast< int64_t >( tsubcarrier_halfcycles );
//*curr_sample = static_cast< T >( 1.0 - 2.0 *( int_phase & 0x01 ) );
*curr_sample = this->d_subcarrier_table[ int_phase & 0x01 ];
tsubcarrier_halfcycles += subcarrier_phase_step;
++curr_sample;
}
}
}
};
/*!
* \brief Code resampler that forces the code spacing to the nearest integer
* number of samples
*/
template< typename T >
class SubcarrierResamplerIntegerSampleSpacing : public SubcarrierResamplerInterface<T>
{
public:
SubcarrierResamplerIntegerSampleSpacing( boost::shared_ptr< SubcarrierResamplerInterface<T> > core_resampler )
: d_core_resampler( core_resampler )
{};
/*!
* Resample the subcarrier computing the subcarrier phases exactly for the latest output
* and forcing all others to be integer shifts of the latest value*/
virtual void resample_subcarrier( std::vector< double > &init_subcarrier_phase_cycles,
double &subcarrier_phase_step,
int num_samples,
std::vector< T * > resampled_subcarriers,
bool is_cosine_phased = false)
{
double earliest_subcarrier_phase = init_subcarrier_phase_cycles[0];
std::vector< int > subcarrier_phase_offsets_samples( init_subcarrier_phase_cycles.size(), 0 );
for( int i = 1; i < init_subcarrier_phase_cycles.size(); ++i )
{
subcarrier_phase_offsets_samples[i] = round(
( init_subcarrier_phase_cycles[i] - earliest_subcarrier_phase ) / subcarrier_phase_step
);
}
int total_samples = num_samples + subcarrier_phase_offsets_samples.back();
// Now we call the generic implementation for the earliest code phase
// and copy for the later code phases:
std::vector< T * > dummy_resampled_subcarriers(1, resampled_subcarriers[0] );
std::vector< double > dummy_init_subcarrier_phase(1, init_subcarrier_phase_cycles[0] );
d_core_resampler->resample_subcarrier(
dummy_init_subcarrier_phase, subcarrier_phase_step,
total_samples, dummy_resampled_subcarriers, is_cosine_phased );
// Loop over the desired outputs:
for( int i = 1; i < init_subcarrier_phase_cycles.size(); ++i )
{
// Copy the shifted 'early' code to the later codes:
memcpy( resampled_subcarriers[i], resampled_subcarriers[0] +
subcarrier_phase_offsets_samples[i],
num_samples * sizeof( T ) );
// Upate the init_subcarrier_phase parameter to reflect the true code phases
init_subcarrier_phase_cycles[i] = init_subcarrier_phase_cycles[0] +
subcarrier_phase_offsets_samples[i]*subcarrier_phase_step;
}
}
private:
// A code resampler to do the basic resampling on the earliest code phase
boost::shared_ptr< SubcarrierResamplerInterface<T> > d_core_resampler;
};
/*!
* \brief Code resampler that uses 64 bit fixed point arithmetic */
template< typename T, unsigned FRAC_LEN = 32 >
class SubcarrierResamplerFxpt64 : public SubcarrierResamplerInterface<T>
{
public:
/*!
* Resample the code using 64-bit fixed point arithmetic
*/
virtual void resample_subcarrier( std::vector< double > &init_subcarrier_phase_cycles,
double &subcarrier_phase_step,
int num_samples,
std::vector< T * > resampled_subcarriers,
bool is_cosine_phased = false)
{
int64_t subcarrier_phase_step_fxp = double_to_fxpt64( 2.0*subcarrier_phase_step );
// Loop over the desired outputs:
for( int i = 0; i < init_subcarrier_phase_cycles.size(); ++i )
{
double tsubcarrier_halfcycles = std::fmod( 2.0*init_subcarrier_phase_cycles[i], 2 );
if( tsubcarrier_halfcycles < 0.0 )
{
tsubcarrier_halfcycles += 2.0;
}
if( is_cosine_phased )
{
tsubcarrier_halfcycles += 0.5;
}
int64_t subcarrier_phase_fxp = double_to_fxpt64( tsubcarrier_halfcycles, FRAC_LEN );
T *curr_sample = resampled_subcarriers[i];
init_subcarrier_phase_cycles[i] = fxpt64_to_double( subcarrier_phase_fxp )/2.0;
for( int j = 0 ; j < num_samples; ++j )
{
//*curr_sample = static_cast< T >( 1 - 2*( (subcarrier_phase_fxp>>FRAC_LEN) & 0x01 ) );
*curr_sample = this->d_subcarrier_table[ ( subcarrier_phase_fxp >> FRAC_LEN ) & 0x01 ];
subcarrier_phase_fxp += subcarrier_phase_step_fxp;
++curr_sample;
}
}
subcarrier_phase_step = fxpt64_to_double( subcarrier_phase_step_fxp ) / 2.0;
}
};
/*!
* \brief Code resampler that uses a fixed number of replicas in memory*/
template< typename T >
class SubcarrierResamplerMemoryStore : public SubcarrierResamplerInterface<T>
{
public:
SubcarrierResamplerMemoryStore(
double nominal_subcarrier_phase_step,
unsigned int maximum_num_samples,
double subcarrier_spacing_cycles )
: d_nominal_subcarrier_phase_step( nominal_subcarrier_phase_step ),
d_subcarrier_spacing_cycles( subcarrier_spacing_cycles )
{
int num_replicas = static_cast< int >(
std::ceil( 1.0 /
d_subcarrier_spacing_cycles ) );
// Resize the storage:
d_subcarrier_phase_offsets.resize( num_replicas );
d_replica_store.resize( num_replicas );
// Use a generic resampler to generate the local replica store:
SubcarrierResamplerGeneric<T> baseResampler;
double curr_offset = 0.0;
for( int ii = 0; ii < num_replicas; ++ii )
{
d_subcarrier_phase_offsets[ii] = curr_offset;
curr_offset += d_subcarrier_spacing_cycles;
d_replica_store[ii] = static_cast< T *>( volk_malloc(
2*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_subcarrier(
d_subcarrier_phase_offsets, d_nominal_subcarrier_phase_step, 2*maximum_num_samples,
d_replica_store, false );
};
~SubcarrierResamplerMemoryStore()
{
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_subcarrier( std::vector< double > &init_subcarrier_phase_cycles,
double &subcarrier_phase_step,
int num_samples,
std::vector< T * > resampled_subcarriers,
bool is_cosine_phased = false)
{
// Loop over the desired outputs:
for( int ii = 0; ii < init_subcarrier_phase_cycles.size(); ++ii )
{
int offset_ind = 0;
double delta_offset = std::numeric_limits<double>::infinity();
double desired_subcarrier_phase = init_subcarrier_phase_cycles[ii];
if( is_cosine_phased )
{
desired_subcarrier_phase += 0.25;
}
double desired_subcarrier_phase_mod_one_chip = std::fmod( desired_subcarrier_phase, 1.0 );
if( desired_subcarrier_phase_mod_one_chip < 0.0 )
{
desired_subcarrier_phase_mod_one_chip += 1.0;
}
double achieved_subcarrier_phase = 0.0;
for( int jj = 0; jj < d_subcarrier_phase_offsets.size(); ++jj )
{
double abs_diff = std::abs( desired_subcarrier_phase_mod_one_chip - d_subcarrier_phase_offsets[jj] );
if( abs_diff < delta_offset )
{
delta_offset = abs_diff;
offset_ind = jj;
achieved_subcarrier_phase = desired_subcarrier_phase - desired_subcarrier_phase_mod_one_chip
+ d_subcarrier_phase_offsets[jj];
}
}
if( is_cosine_phased )
{
achieved_subcarrier_phase -= 0.25;
}
init_subcarrier_phase_cycles[ii] = achieved_subcarrier_phase;
memcpy( resampled_subcarriers[ii], d_replica_store[offset_ind],
num_samples * sizeof( T ) );
}
subcarrier_phase_step = d_nominal_subcarrier_phase_step;
}
private:
double d_nominal_subcarrier_phase_step;
double d_subcarrier_spacing_cycles;
std::vector< double > d_subcarrier_phase_offsets;
std::vector< T * > d_replica_store;
};
#endif

View File

@@ -49,6 +49,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/core/system_parameters
${CMAKE_SOURCE_DIR}/src/core/interfaces
${CMAKE_SOURCE_DIR}/src/core/receiver
${CMAKE_SOURCE_DIR}/src/algorithms/libs
${VOLK_INCLUDE_DIRS}
${GLOG_INCLUDE_DIRS}
${GFlags_INCLUDE_DIRS}

View File

@@ -40,6 +40,7 @@
#define LV_HAVE_SSE3
#include "volk_cw_epl_corr.h"
#endif
#include "accumulate_array.h"
unsigned long Correlator::next_power_2(unsigned long v)
@@ -228,7 +229,6 @@ void Correlator::Carrier_rotate_and_VEPL_volk(int signal_length_samples,
volk_free(bb_signal);
}
void Correlator::Carrier_rotate_and_DE_volk(int signal_length_samples,
const gr_complex* input,
gr_complex *phase_as_complex,
@@ -295,3 +295,130 @@ void Correlator::Carrier_rotate_and_DPE_volk(int signal_length_samples,
volk_free(subcarrier_wipeoff);
volk_free(code_wipeoff);
}
void Correlator::Carrier_rotate_and_EPL_codeless(int signal_length_samples,
const gr_complex* input,
gr_complex *phase_as_complex,
gr_complex phase_inc_as_complex,
const int *E_code_phases,
const int *P_code_phases,
const int *L_code_phases,
gr_complex* E_out,
gr_complex* P_out,
gr_complex* L_out,
int code_length )
{
gr_complex* bb_signal = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* accum_early = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_early, accum_early+code_length, 0.0 );
gr_complex* accum_prompt = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_prompt, accum_prompt+code_length, 0.0 );
gr_complex* accum_late = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_late, accum_late+code_length, 0.0 );
volk_32fc_s32fc_x2_rotator_32fc(bb_signal, input, phase_inc_as_complex, phase_as_complex, signal_length_samples);
// Now we do an accumulation of the input by code phase bins:
accumulate_array< gr_complex >( bb_signal, E_code_phases, accum_early, signal_length_samples );
accumulate_array< gr_complex >( bb_signal, P_code_phases, accum_prompt, signal_length_samples );
accumulate_array< gr_complex >( bb_signal, L_code_phases, accum_late, signal_length_samples );
// Now sum the squares of the partial sums: this is implemented as a simple
// dot product
volk_32fc_x2_dot_prod_32fc(E_out, accum_early, accum_early, code_length);
volk_32fc_x2_dot_prod_32fc(P_out, accum_prompt, accum_prompt, code_length);
volk_32fc_x2_dot_prod_32fc(L_out, accum_late, accum_late, code_length);
volk_free(bb_signal);
volk_free(accum_early);
volk_free(accum_prompt);
volk_free(accum_late);
}
void Correlator::Carrier_rotate_and_VEPL_codeless(int signal_length_samples,
const gr_complex* input,
gr_complex *phase_as_complex,
gr_complex phase_inc_as_complex,
const int *VE_code_phases,
const int *E_code_phases,
const int *P_code_phases,
const int *L_code_phases,
const int *VL_code_phases,
const gr_complex *VE_subcarrier,
const gr_complex *E_subcarrier,
const gr_complex *P_subcarrier,
const gr_complex *L_subcarrier,
const gr_complex *VL_subcarrier,
gr_complex* VE_out,
gr_complex* E_out,
gr_complex* P_out,
gr_complex* L_out,
gr_complex* VL_out,
int code_length)
{
gr_complex* bb_signal = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* ve_subcarrier_wipeoff = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* e_subcarrier_wipeoff = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* p_subcarrier_wipeoff = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* l_subcarrier_wipeoff = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* vl_subcarrier_wipeoff = static_cast<gr_complex*>(volk_malloc(signal_length_samples * sizeof(gr_complex), volk_get_alignment()));
gr_complex* accum_very_early = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_very_early, accum_very_early+code_length, 0.0 );
gr_complex* accum_early = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_early, accum_early+code_length, 0.0 );
gr_complex* accum_prompt = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_prompt, accum_prompt+code_length, 0.0 );
gr_complex* accum_late = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_late, accum_late+code_length, 0.0 );
gr_complex* accum_very_late = static_cast<gr_complex*>(volk_malloc(code_length* sizeof(gr_complex), volk_get_alignment()));
std::fill( accum_very_late, accum_very_late+code_length, 0.0 );
// 1) Carrier wipe-off
volk_32fc_s32fc_x2_rotator_32fc(bb_signal, input, phase_inc_as_complex, phase_as_complex, signal_length_samples);
// 2) Subcarrier wipe-off
volk_32fc_x2_multiply_32fc( ve_subcarrier_wipeoff, bb_signal, VE_subcarrier, signal_length_samples );
volk_32fc_x2_multiply_32fc( e_subcarrier_wipeoff, bb_signal, E_subcarrier, signal_length_samples );
volk_32fc_x2_multiply_32fc( p_subcarrier_wipeoff, bb_signal, P_subcarrier, signal_length_samples );
volk_32fc_x2_multiply_32fc( l_subcarrier_wipeoff, bb_signal, L_subcarrier, signal_length_samples );
volk_32fc_x2_multiply_32fc( vl_subcarrier_wipeoff, bb_signal, VL_subcarrier, signal_length_samples );
// 3) Do an accumulation of the input by code phase bins:
accumulate_array< gr_complex >( ve_subcarrier_wipeoff, VE_code_phases, accum_very_early, signal_length_samples );
accumulate_array< gr_complex >( e_subcarrier_wipeoff, E_code_phases, accum_early, signal_length_samples );
accumulate_array< gr_complex >( p_subcarrier_wipeoff, P_code_phases, accum_prompt, signal_length_samples );
accumulate_array< gr_complex >( l_subcarrier_wipeoff, L_code_phases, accum_late, signal_length_samples );
accumulate_array< gr_complex >( vl_subcarrier_wipeoff, VL_code_phases, accum_very_late, signal_length_samples );
// 4) Now sum the squares of the partial sums: this is implemented as a simple
// dot product
volk_32fc_x2_dot_prod_32fc(VE_out, accum_very_early, accum_very_early, code_length);
volk_32fc_x2_dot_prod_32fc(E_out, accum_early, accum_early, code_length);
volk_32fc_x2_dot_prod_32fc(P_out, accum_prompt, accum_prompt, code_length);
volk_32fc_x2_dot_prod_32fc(L_out, accum_late, accum_late, code_length);
volk_32fc_x2_dot_prod_32fc(VL_out, accum_very_late, accum_very_late, code_length);
volk_free(bb_signal);
volk_free(ve_subcarrier_wipeoff);
volk_free(e_subcarrier_wipeoff);
volk_free(p_subcarrier_wipeoff);
volk_free(l_subcarrier_wipeoff);
volk_free(vl_subcarrier_wipeoff);
volk_free(accum_very_early);
volk_free(accum_early);
volk_free(accum_prompt);
volk_free(accum_late);
volk_free(accum_very_late);
}

View File

@@ -134,6 +134,39 @@ public:
gr_complex* P_subcarrier_L_code_out,
gr_complex* P_code_PQ_subcarrier_out );
void Carrier_rotate_and_EPL_codeless(int signal_length_samples,
const gr_complex* input,
gr_complex *phase_as_complex,
gr_complex phase_inc_as_complex,
const int *E_code_phases,
const int *P_code_phases,
const int *L_code_phases,
gr_complex* E_out,
gr_complex* P_out,
gr_complex* L_out,
int code_length);
void Carrier_rotate_and_VEPL_codeless(int signal_length_samples,
const gr_complex* input,
gr_complex *phase_as_complex,
gr_complex phase_inc_as_complex,
const int *VE_code_phases,
const int *E_code_phases,
const int *P_code_phases,
const int *L_code_phases,
const int *VL_code_phases,
const gr_complex *VE_subcarrier,
const gr_complex *E_subcarrier,
const gr_complex *P_subcarrier,
const gr_complex *L_subcarrier,
const gr_complex *VL_subcarrier,
gr_complex* VE_out,
gr_complex* E_out,
gr_complex* P_out,
gr_complex* L_out,
gr_complex* VL_out,
int code_length);
private:
unsigned long next_power_2(unsigned long v);
};

View File

@@ -368,6 +368,42 @@ 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
${CMAKE_CURRENT_SOURCE_DIR}/arithmetic/subcarrier_resampler_test.cc
${CMAKE_CURRENT_SOURCE_DIR}/arithmetic/accumulate_array_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,129 @@
/*!
* \file accumulate_array_test.cc
* \brief This file implements tests for accumulate_array
* \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 "accumulate_array.h"
#include "code_resampler.h"
#include <complex>
#include <ctime>
#include <sys/time.h>
#include <armadillo>
#include <gtest/gtest.h>
typedef std::vector< float > real_vec;
typedef std::vector< std::complex< float > > cplx_vec;
TEST(AccumulateArrayTest, FunctionalTest )
{
real_vec input_vec( 13 );
std::iota( input_vec.begin(), input_vec.end(), 0 );
std::vector< int > index_vec = { 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3 };
real_vec output_vec( 5, 0.0 );
accumulate_array( &input_vec[0], &index_vec[0], &output_vec[0], 13 );
real_vec expected_output = { 3, 18, 15, 42, 0 };
for( unsigned int ii = 0; ii < expected_output.size(); ++ii )
{
ASSERT_FLOAT_EQ( output_vec[ii], expected_output[ii] );
}
}
TEST(AccumulateArrayTest, ComplexTest )
{
double fs = 6e6;
double fc = 1.023e6;
double T = 0.001;
double code_phase_step = fc/fs;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
cplx_vec output_vec( 1023, 0.0 );
std::vector< int > code_phases( 1023 );
std::iota( code_phases.begin(), code_phases.end(), 0 );
CodeResamplerGeneric< int > the_resampler;
std::vector< int > index_vec( _num_samples );
std::vector< int* > _resampled_code_phases;
_resampled_code_phases.resize(1);
_resampled_code_phases[0] = &index_vec[0];
std::vector< double > _desired_code_phases;
_desired_code_phases.resize(1);
_desired_code_phases[0] = 0;
the_resampler.resample_code( &code_phases[0], 1023, _desired_code_phases,
code_phase_step, _num_samples, _resampled_code_phases );
int iterations = 1000;
arma::cx_mat rv = arma::randn< arma::cx_mat >( _num_samples, iterations );
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i = 0; i < iterations; i++)
{
cplx_vec input_vec = arma::conv_to< cplx_vec >::from( rv.col( i ) );
accumulate_array( &input_vec[0], &index_vec[0], &output_vec[0], _num_samples );
}
gettimeofday(&tv, NULL);
long long int end = tv.tv_sec * 1000000 + tv.tv_usec;
ASSERT_LE(0, end - begin);
std::cout << "Accumulate_array completed in " << (end - begin) << " microseconds" << std::endl;
}

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 );
}

View File

@@ -0,0 +1,356 @@
/*!
* \file subcarrier_resampler_test.cc
* \brief This file implements tests for resampling subcarriers
* \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 "subcarrier_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_subcarrier_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_subcarrier_replicas( std::vector< std::complex< float > * > &replicas )
{
for( int i = 0; i < replicas.size(); ++i )
{
volk_free( replicas[i] );
}
}
TEST(SubcarrierResamplerTest, SubcarrierResamplerGeneric )
{
unsigned int _num_replicas = 3;
double fs = 12e6;
double fsub = 6*1.023e6;
double subcarrier_phase_step = fsub/fs;
double subcarrier_spacing_cycles = 0.125;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_subcarriers;
_resampled_subcarriers.resize(_num_replicas);
std::vector< double > _desired_subcarrier_phases;
_desired_subcarrier_phases.resize(_num_replicas);
allocate_subcarrier_replicas( _resampled_subcarriers, _num_samples );
SubcarrierResamplerGeneric< 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_subcarrier_phase = static_cast< double >( i ) - subcarrier_spacing_cycles;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_subcarrier_phases[j] = current_subcarrier_phase;
current_subcarrier_phase += subcarrier_spacing_cycles;
}
the_resampler.resample_subcarrier( _desired_subcarrier_phases,
subcarrier_phase_step, _num_samples, _resampled_subcarriers,
i % 2 == 1 );
}
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_subcarrier_replicas( _resampled_subcarriers );
}
TEST(SubcarrierResamplerTest, SubcarrierResamplerIntegerSampleSpacing )
{
std::complex<float>* _orig_subcarrier = 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 subcarrier_phase_step = fc/fs;
double subcarrier_spacing_cycles = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_subcarriers;
_resampled_subcarriers.resize(_num_replicas);
std::vector< double > _desired_subcarrier_phases;
_desired_subcarrier_phases.resize(_num_replicas);
allocate_subcarrier_replicas( _resampled_subcarriers, _num_samples );
SubcarrierResamplerIntegerSampleSpacing< std::complex< float > > the_resampler(
boost::shared_ptr< SubcarrierResamplerInterface< std::complex<float> > >(
new SubcarrierResamplerGeneric< 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_subcarrier_phase = static_cast< double >( i ) - subcarrier_spacing_cycles;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_subcarrier_phases[j] = current_subcarrier_phase;
current_subcarrier_phase += subcarrier_spacing_cycles;
}
the_resampler.resample_subcarrier( _desired_subcarrier_phases,
subcarrier_phase_step, _num_samples, _resampled_subcarriers,
i % 2 == 1 );
}
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_subcarrier_replicas( _resampled_subcarriers );
}
TEST(SubcarrierResamplerTest, SubcarrierResamplerFxpt64 )
{
std::complex<float>* _orig_subcarrier = 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 subcarrier_phase_step = fc/fs;
double subcarrier_spacing_cycles = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_subcarriers;
_resampled_subcarriers.resize(_num_replicas);
std::vector< double > _desired_subcarrier_phases;
_desired_subcarrier_phases.resize(_num_replicas);
allocate_subcarrier_replicas( _resampled_subcarriers, _num_samples );
SubcarrierResamplerFxpt64< 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_subcarrier_phase = static_cast< double >( i ) - subcarrier_spacing_cycles;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_subcarrier_phases[j] = current_subcarrier_phase;
current_subcarrier_phase += subcarrier_spacing_cycles;
}
the_resampler.resample_subcarrier( _desired_subcarrier_phases,
subcarrier_phase_step, _num_samples, _resampled_subcarriers,
i % 2 == 1 );
}
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_subcarrier_replicas( _resampled_subcarriers );
}
TEST(SubcarrierResamplerTest, SubcarrierResamplerIntegerSampleSpacingFxpt64 )
{
std::complex<float>* _orig_subcarrier = 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 subcarrier_phase_step = fc/fs;
double subcarrier_spacing_cycles = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_subcarriers;
_resampled_subcarriers.resize(_num_replicas);
std::vector< double > _desired_subcarrier_phases;
_desired_subcarrier_phases.resize(_num_replicas);
allocate_subcarrier_replicas( _resampled_subcarriers, _num_samples );
SubcarrierResamplerIntegerSampleSpacing< std::complex< float > > the_resampler(
boost::shared_ptr< SubcarrierResamplerInterface< std::complex<float> > >(
new SubcarrierResamplerFxpt64< 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_subcarrier_phase = static_cast< double >( i ) - subcarrier_spacing_cycles;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_subcarrier_phases[j] = current_subcarrier_phase;
current_subcarrier_phase += subcarrier_spacing_cycles;
}
the_resampler.resample_subcarrier( _desired_subcarrier_phases,
subcarrier_phase_step, _num_samples, _resampled_subcarriers,
i % 2 == 1 );
}
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_subcarrier_replicas( _resampled_subcarriers );
}
TEST(SubcarrierResamplerTest, SubcarrierResamplerMemoryStore )
{
std::complex<float>* _orig_subcarrier = 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 subcarrier_phase_step = fc/fs;
double subcarrier_spacing_cycles = 0.5;
double T = 0.001;
int _num_samples = static_cast< int >(
std::ceil( T * fs )
);
std::vector< std::complex<float>* > _resampled_subcarriers;
_resampled_subcarriers.resize(_num_replicas);
std::vector< double > _desired_subcarrier_phases;
_desired_subcarrier_phases.resize(_num_replicas);
allocate_subcarrier_replicas( _resampled_subcarriers, _num_samples );
SubcarrierResamplerMemoryStore< std::complex< float > > the_resampler(
subcarrier_phase_step, _num_samples, 0.1 );
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_subcarrier_phase = static_cast< double >( i ) - subcarrier_spacing_cycles;
for( int j = 0; j < _num_replicas; ++j )
{
_desired_subcarrier_phases[j] = current_subcarrier_phase;
current_subcarrier_phase += subcarrier_spacing_cycles;
}
the_resampler.resample_subcarrier( _desired_subcarrier_phases,
subcarrier_phase_step, _num_samples, _resampled_subcarriers,
i % 2 == 1 );
}
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_subcarrier_replicas( _resampled_subcarriers );
}