1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-08-31 09:57:58 +00:00

Added implementation of plain cordic class in tracking/libs. Added a corresponding test. The implementation is slower than standard sin and cos implementations, so it is not used in the receiver. The test will fail otherwise, indicating that this should be used instead of standard functions.

git-svn-id: https://svn.code.sf.net/p/gnss-sdr/code/trunk@142 64b25241-fba3-4117-9849-534c7e92360d
This commit is contained in:
Carles Fernandez
2012-01-25 01:57:28 +00:00
parent e37f6cd072
commit 0d598a7188
15 changed files with 329 additions and 70 deletions

View File

@@ -53,7 +53,7 @@ public:
bool set_headers(std::string filename);
bool print_position(gps_l1_ca_ls_pvt* position,bool print_average_values);
bool print_position(gps_l1_ca_ls_pvt* position, bool print_average_values);
bool close_file();

View File

@@ -369,9 +369,9 @@ int Gps_L1_Ca_Dll_Fll_Pll_Tracking_cc::general_work (int noutput_items, gr_vecto
P_out,
L_out);
d_Early=E_out[0];
d_Prompt=P_out[0];
d_Late=L_out[0];
d_Early = E_out[0];
d_Prompt = P_out[0];
d_Late = L_out[0];
free(E_out);
free(P_out);
free(L_out);

View File

@@ -184,7 +184,7 @@ private:
float d_acq_carrier_doppler_hz;
// correlator
correlator d_correlator;
Correlator d_correlator;
// FLL + PLL filter
float d_FLL_discriminator_hz; // This is a class variable because FLL needs to have memory

View File

@@ -0,0 +1,161 @@
#include <stdlib.h>
#include <math.h>
#include "cordic.h"
const double HALF_PI = 3.1415926535898 / 2;
const int INVALID_K = -1;
Cordic::Cordic(int max_L)
{
double K, dummy;
int L;
//CORDIC_TABLE *mp_cordic_table = NULL;
mp_cordic_table = (CORDIC_TABLE *) calloc(max_L + 1, sizeof(CORDIC_TABLE));
if (!mp_cordic_table)
{
/* failed to calloc table */
}
K = 1.0;
for (L = 0; L <= max_L; L++)
{
mp_cordic_table[L].K = K;
mp_cordic_table[L].phase_rads = (double) atan(K);
K *= 0.5;
}
m_max_L = max_L;
/* get m_mag_scale by getting the cordic magnitude with m_mag_scale = 1.0 */
m_mag_scale = 1.0;
Cordic::cordic_get_mag_phase(1.0, 0.0, m_mag_scale, dummy);
m_mag_scale = 1.0 / m_mag_scale;
}
Cordic::~Cordic ()
{
free(mp_cordic_table);
//mp_cordic_table = ((void *) 0); // nullptr
m_max_L = INVALID_K;
}
void Cordic::cordic_get_mag_phase(double I, double Q, double &p_mag, double &p_phase_rads)
{
int L;
double tmp_I, K, phase_rads, acc_phase_rads;
if (I < 0)
{
/* rotate by an initial +/- 90 degrees */
tmp_I = I;
if (Q > 0.0)
{
I = Q; /* subtract 90 degrees */
Q = -tmp_I;
acc_phase_rads = -HALF_PI;
}
else
{
I = -Q; /* add 90 degrees */
Q = tmp_I;
acc_phase_rads = HALF_PI;
}
}
else
{
acc_phase_rads = 0.0;
}
/* rotate using "1 + jK" factors */
for (L = 0; L <= m_max_L; L++)
{
K = mp_cordic_table[L].K;
phase_rads = mp_cordic_table[L].phase_rads;
tmp_I = I;
if (Q >= 0.0)
{
/* phase is positive: do negative rotation */
I += Q * K;
Q -= tmp_I * K;
acc_phase_rads -= phase_rads;
}
else
{
/* phase is negative: do positive rotation */
I -= Q * K;
Q += tmp_I * K;
acc_phase_rads += phase_rads;
}
}
p_phase_rads = -acc_phase_rads;
p_mag = I * m_mag_scale;
}
void Cordic::cordic_get_cos_sin(double desired_phase_rads, double &p_cos, double &p_sin)
{
double I, Q, tmp_I;
double acc_phase_rads, phase_rads, K;
int L;
/* start with +90, -90, or 0 degrees */
if (desired_phase_rads > HALF_PI)
{
I = 0.0;
Q = 1.0;
acc_phase_rads = HALF_PI;
}
else if (desired_phase_rads < -HALF_PI)
{
I = 0.0;
Q = -1.0;
acc_phase_rads = -HALF_PI;
}
else
{
I = 1.0;
Q = 0.0;
acc_phase_rads = 0.0;
}
/* rotate using "1 + jK" factors */
for (L = 0; L <= m_max_L; L++)
{
K = mp_cordic_table[L].K;
phase_rads = mp_cordic_table[L].phase_rads;
tmp_I = I;
if (desired_phase_rads - acc_phase_rads < 0.0)
{
/* do negative rotation */
I += Q * K;
Q -= tmp_I * K;
acc_phase_rads -= phase_rads;
}
else
{
/* do positive rotation */
I -= Q * K;
Q += tmp_I * K;
acc_phase_rads += phase_rads;
}
}
p_cos = I * m_mag_scale;
p_sin = Q * m_mag_scale;
}

View File

@@ -0,0 +1,77 @@
/*!
* \file cordic.h
* \brief Interface of the CORDIC (COordinate Rotation DIgital Computer) algorithm
* \author Carles Fernandez-Prades, 2012. cfernandez(at)cttc.es
*
* This is a modified implementation of the one found at
* http://www.dspguru.com/dsp/faqs/cordic
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2012 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_CORDIC_H_
#define GNSS_SDR_CORDIC_H_
typedef struct tagCORDIC_TABLE {
double K;
double phase_rads;
} CORDIC_TABLE;
class Cordic
{
public:
/*!
* \brief construct the CORDIC table which will be of size "largest_k + 1".
*/
Cordic(int largest_k);
/*!
* \brief Frees the CORDIC table's memory
*/
~Cordic();
/*!
* \brief Calculates the magnitude and phase of "I + jQ". p_phase_rads is in radians
*/
void cordic_get_mag_phase(double I, double Q, double &p_mag, double &p_phase_rads);
/* calculate the magnitude and phase of "I + jQ". phase is in radians */
/*!
* \brief Calculates the cosine and sine of the desired phase in radians
*/
void cordic_get_cos_sin(double desired_phase_rads, double &p_cos, double &p_sin);
private:
CORDIC_TABLE *mp_cordic_table;
int m_max_L;
double m_mag_scale;
};
#endif

View File

@@ -34,7 +34,7 @@
#include <gnuradio/gr_block.h>
#include "correlator.h"
unsigned long correlator::next_power_2(unsigned long v)
unsigned long Correlator::next_power_2(unsigned long v)
{
v--;
v |= v >> 1;
@@ -49,7 +49,7 @@ unsigned long correlator::next_power_2(unsigned long v)
void correlator::Carrier_wipeoff_and_EPL_generic(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out)
void Correlator::Carrier_wipeoff_and_EPL_generic(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out)
{
gr_complex bb_signal_sample(0,0);
@@ -73,7 +73,7 @@ void correlator::Carrier_wipeoff_and_EPL_generic(int signal_length_samples,const
void correlator::Carrier_wipeoff_and_EPL_volk(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out)
void Correlator::Carrier_wipeoff_and_EPL_volk(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out)
{
gr_complex* bb_signal;
gr_complex* input_aligned;
@@ -104,7 +104,7 @@ void correlator::Carrier_wipeoff_and_EPL_volk(int signal_length_samples,const gr
void correlator::cpu_arch_test_volk_32fc_x2_dot_prod_32fc_a()
void Correlator::cpu_arch_test_volk_32fc_x2_dot_prod_32fc_a()
{
//
struct volk_func_desc desc=volk_32fc_x2_dot_prod_32fc_a_get_func_desc();
@@ -140,7 +140,7 @@ void correlator::cpu_arch_test_volk_32fc_x2_dot_prod_32fc_a()
void correlator::cpu_arch_test_volk_32fc_x2_multiply_32fc_a()
void Correlator::cpu_arch_test_volk_32fc_x2_multiply_32fc_a()
{
//
struct volk_func_desc desc = volk_32fc_x2_multiply_32fc_a_get_func_desc();
@@ -176,7 +176,7 @@ void correlator::cpu_arch_test_volk_32fc_x2_multiply_32fc_a()
correlator::correlator ()
Correlator::Correlator ()
{
cpu_arch_test_volk_32fc_x2_dot_prod_32fc_a();
cpu_arch_test_volk_32fc_x2_multiply_32fc_a();
@@ -186,5 +186,5 @@ correlator::correlator ()
correlator::~correlator ()
Correlator::~Correlator ()
{}

View File

@@ -42,13 +42,13 @@
* \brief High optimized vector correlator class
*
*/
class correlator
class Correlator
{
public:
void Carrier_wipeoff_and_EPL_generic(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out);
void Carrier_wipeoff_and_EPL_volk(int signal_length_samples,const gr_complex* input, gr_complex* carrier,gr_complex* E_code, gr_complex* P_code, gr_complex* L_code,gr_complex* E_out, gr_complex* P_out, gr_complex* L_out);
correlator();
~correlator();
Correlator();
~Correlator();
private:
std::string volk_32fc_x2_multiply_32fc_a_best_arch;
std::string volk_32fc_x2_dot_prod_32fc_a_best_arch;

View File

@@ -5,4 +5,5 @@ obj CN_estimators : CN_estimators.cc ;
obj tracking_FLL_PLL_filter : tracking_FLL_PLL_filter.cc ;
obj tracking_2nd_PLL_filter : tracking_2nd_PLL_filter.cc ;
obj tracking_2nd_DLL_filter : tracking_2nd_DLL_filter.cc ;
obj correlator : correlator.cc ;
obj correlator : correlator.cc ;
obj cordic : cordic.cc ;

View File

@@ -42,6 +42,7 @@ exe gnss-sdr : main.cc
../algorithms/tracking/libs//tracking_2nd_PLL_filter
../algorithms/tracking/libs//tracking_2nd_DLL_filter
../algorithms/tracking/libs//correlator
../algorithms/tracking/libs//cordic
../core/libs//INIReader
../core/libs//ini
../core/libs//string_converter

View File

@@ -0,0 +1,51 @@
#include <iostream>
#include <math.h>
#include <gtest/gtest.h>
#include "cordic.h"
#include <sys/time.h>
TEST(Cordic_Test, StandardCIsFasterThanCordic)
{
int largest_k = 0;
Cordic* cordicPtr;
cordicPtr = new Cordic(largest_k);
double phase = 0.1;
double cos_phase1 = 0;
double sin_phase1 = 0;
double cos_phase2 = 0;
double sin_phase2 = 0;
double niter = 10000000;
struct timeval tv;
gettimeofday(&tv, NULL);
long long int begin1 = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i=0; i<niter; i++)
{
cordicPtr->cordic_get_cos_sin(phase, cos_phase1, sin_phase1);
}
gettimeofday(&tv, NULL);
long long int end1 = tv.tv_sec *1000000 + tv.tv_usec;
long long int begin2 = tv.tv_sec * 1000000 + tv.tv_usec;
for(int i=0; i<niter; i++)
{
cos_phase2 = cos(phase);
sin_phase2 = sin(phase);
}
gettimeofday(&tv, NULL);
long long int end2 = tv.tv_sec *1000000 + tv.tv_usec;
std::cout << "CORDIC sin =" << sin_phase2 << " computed in " << (end1-begin1) << " microseconds" << std::endl;
std::cout << "STD sin =" << sin(phase) << " computed in " << (end2-begin2) << " microseconds" << std::endl;
EXPECT_TRUE((end2-begin2) < (end1-begin1));
}

View File

@@ -11,26 +11,23 @@
* This class implements a Unit Test for the class GNSSBlockFactory.
*
*/
#include <gr_msg_queue.h>
#include <vector>
#include <gtest/gtest.h>
#include <gnuradio/gr_msg_queue.h>
#include <vector>
#include "in_memory_configuration.h"
#include "gnss_block_interface.h"
#include "gnss_block_factory.h"
TEST(GNSSBlockFactory, InstantiateChannels) {
TEST(GNSSBlockFactory, InstantiateChannels)
{
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("Channels.count", "2");
configuration->set_property("Channel1.implementation", "Pass_Through");
configuration->set_property("Channel1.item_type", "float");
configuration->set_property("Channel1.item_type", "gr_complex");
configuration->set_property("Channel1.vector_size", "1");
configuration->set_property("Channel2.implementation", "Pass_Through");
configuration->set_property("Channel2.item_type", "float");
configuration->set_property("Channel2.item_type", "gr_complex");
configuration->set_property("Channel2.vector_size", "1");
gr_msg_queue_sptr queue = gr_make_msg_queue(0);
@@ -48,7 +45,8 @@ TEST(GNSSBlockFactory, InstantiateChannels) {
delete channels;
}
TEST(GNSSBlockFactory, InstantiateSignalSource) {
TEST(GNSSBlockFactory, InstantiateSignalSource)
{
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("SignalSource.implementation", "FileSignalSource");

View File

@@ -1,29 +0,0 @@
/**
* Copyright notice
*/
/**
* Author: Carlos Avilés, 2010. carlos.avilesr(at)googlemail.com
*/
/**
* This class implements a Unit Test for the class Adder
*
*/
#include <gtest/gtest.h>
#include "adder.h"
#include "in_memory_configuration.h"
TEST(Adder, Instantiate) {
InMemoryConfiguration* config = new InMemoryConfiguration();
config->set_property("Test.item_type", "gr_complex");
Adder *adder = new Adder(config, "PVT", 4, 1);
delete adder;
}

View File

@@ -13,16 +13,13 @@
*/
#include <gr_msg_queue.h>
#include <vector>
#include <gtest/gtest.h>
#include "in_memory_configuration.h"
#include "gnss_block_interface.h"
#include "gnss_block_factory.h"
TEST(GNSSBlockFactory, InstantiateChannels) {
TEST(GNSS_Block_Factory_Test, InstantiateChannels) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("Channels.count", "2");
@@ -48,7 +45,7 @@ TEST(GNSSBlockFactory, InstantiateChannels) {
delete channels;
}
TEST(GNSSBlockFactory, InstantiateSignalSource) {
TEST(GNSS_Block_Factory_Test, InstantiateSignalSource) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("SignalSource.implementation", "File_Signal_Source");
@@ -65,7 +62,7 @@ TEST(GNSSBlockFactory, InstantiateSignalSource) {
delete signal_source;
}
TEST(GNSSBlockFactory, InstantiateWrongSignalSource) {
TEST(GNSS_Block_Factory_Test, InstantiateWrongSignalSource) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("SignalSource.implementation", "Pepito");
@@ -81,7 +78,7 @@ TEST(GNSSBlockFactory, InstantiateWrongSignalSource) {
delete factory;
}
TEST(GNSSBlockFactory, InstantiateSignalConditioner) {
TEST(GNSS_Block_Factory_Test, InstantiateSignalConditioner) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("SignalConditioner.implementation", "Pass_Through");
@@ -98,7 +95,7 @@ TEST(GNSSBlockFactory, InstantiateSignalConditioner) {
delete signal_conditioner;
}
TEST(GNSSBlockFactory, InstantiateWrongSignalConditioner) {
TEST(GNSS_Block_Factory_Test, InstantiateWrongSignalConditioner) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("SignalConditioner.implementation", "Pepito");
@@ -114,7 +111,7 @@ TEST(GNSSBlockFactory, InstantiateWrongSignalConditioner) {
delete factory;
}
TEST(GNSSBlockFactory, InstantiatePVT) {
TEST(GNSS_Block_Factory_Test, InstantiatePVT) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("PVT.implementation", "PassThrough");
@@ -131,7 +128,7 @@ TEST(GNSSBlockFactory, InstantiatePVT) {
delete pvt;
}
TEST(GNSSBlockFactory, InstantiateWrongPVT) {
TEST(GNSS_Block_Factory_Test, InstantiateWrongPVT) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("PVT.implementation", "Pepito");
@@ -147,7 +144,7 @@ TEST(GNSSBlockFactory, InstantiateWrongPVT) {
delete factory;
}
TEST(GNSSBlockFactory, InstantiateOutputFilter) {
TEST(GNSS_Block_Factory_Test, InstantiateOutputFilter) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("OutputFilter.implementation", "NullSinkOutputFilter");
@@ -164,7 +161,7 @@ TEST(GNSSBlockFactory, InstantiateOutputFilter) {
delete output_filter;
}
TEST(GNSSBlockFactory, InstantiateWrongOutputFilter) {
TEST(GNSS_Block_Factory_Test, InstantiateWrongOutputFilter) {
InMemoryConfiguration *configuration = new InMemoryConfiguration();
configuration->set_property("OutputFilter.implementation", "Pepito");

View File

@@ -43,6 +43,7 @@ exe run_tests : test_main.cc
../algorithms/tracking/libs//tracking_2nd_PLL_filter
../algorithms/tracking/libs//tracking_2nd_DLL_filter
../algorithms/tracking/libs//correlator
../algorithms/tracking/libs//cordic
../core/libs//INIReader
../core/libs//ini
../core/libs//string_converter

View File

@@ -46,19 +46,20 @@
#include "control_thread.h"
#include "control_thread/control_message_factory_test.cc"
//#include "control_thread/control_message_factory_test.cc"
//#include "control_thread/control_thread_test.cc"
#include "configuration/file_configuration_test.cc"
//#include "flowgraph/file_output_filter_test.cc"
//#include "flowgraph/file_signal_source_test.cc"
#include "flowgraph/pass_through_test.cc"
//#include "flowgraph/pass_through_test.cc"
//#include "flowgraph/gnss_flowgraph_test.cc"
//#include "gnss_block/file_output_filter_test.cc"
//#include "gnss_block/gnss_block_factory_test.cc"
#include "gnuradio_block/gnss_sdr_valve_test.cc"
#include "string_converter/string_converter_test.cc"
#include "arithmetic/complex_arithmetic_libc.cc"
#include "arithmetic/correlations_libc.cc"
#include "arithmetic/cordic_test.cc"
concurrent_queue<Gps_Navigation_Message> global_gps_nav_msg_queue;