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

Remove build and data folders, move tests and utils to the base of the source tree

This commit is contained in:
Carles Fernandez
2024-10-04 11:55:09 +02:00
parent 5be2971c9b
commit 825037592a
251 changed files with 154 additions and 179 deletions

View File

@@ -0,0 +1,55 @@
/*!
* \file bayesian_estimation_test.cc
* \brief This file implements feasibility test for the BCE library.
* \author Gerald LaMountain, 2018. gerald(at)ece.neu.edu
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "bayesian_estimation.h"
#include <armadillo>
#include <gtest/gtest.h>
#include <random>
#define BAYESIAN_TEST_N_TRIALS 100
#define BAYESIAN_TEST_ITER 10000
TEST(BayesianEstimationPositivityTest, BayesianPositivityTest)
{
Bayesian_estimator bayes;
arma::vec bayes_mu = arma::zeros(1, 1);
int bayes_nu = 0;
int bayes_kappa = 0;
arma::mat bayes_Psi = arma::ones(1, 1);
arma::vec input = arma::zeros(1, 1);
// -- Perform initializations ------------------------------
std::random_device r;
std::default_random_engine e1(r());
std::normal_distribution<float> normal_dist(0, 5);
for (int k = 0; k < BAYESIAN_TEST_N_TRIALS; k++)
{
bayes.init(bayes_mu, bayes_kappa, bayes_nu, bayes_Psi);
for (int n = 0; n < BAYESIAN_TEST_ITER; n++)
{
input(0) = static_cast<double>(normal_dist(e1));
bayes.update_sequential(input);
arma::mat output = bayes.get_Psi_est();
double output0 = output(0, 0);
ASSERT_EQ(output0 > 0.0, true);
}
}
}

View File

@@ -0,0 +1,281 @@
/*!
* \file cpu_multicorrelator_real_codes_test.cc
* \brief This file implements timing tests for the FFT.
* \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "GPS_L1_CA.h"
#include "cpu_multicorrelator_real_codes.h"
#include "gps_sdr_signal_replica.h"
#include <gnuradio/gr_complex.h>
#include <gtest/gtest.h>
#include <volk_gnsssdr/volk_gnsssdr_alloc.h>
#include <chrono>
#include <complex>
#include <cstdint>
#include <random>
#include <thread>
#if USE_GLOG_AND_GFLAGS
#include <gflags/gflags.h>
DEFINE_int32(cpu_multicorrelator_real_codes_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test");
DEFINE_int32(cpu_multicorrelator_real_codes_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test");
#else
#include <absl/flags/flag.h>
ABSL_FLAG(int32_t, cpu_multicorrelator_real_codes_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test");
ABSL_FLAG(int32_t, cpu_multicorrelator_real_codes_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test");
#endif
void run_correlator_cpu_real_codes(Cpu_Multicorrelator_Real_Codes* correlator,
float d_rem_carrier_phase_rad,
float d_carrier_phase_step_rad,
float d_code_phase_step_chips,
float d_code_phase_rate_step_chips,
float d_rem_code_phase_chips,
int correlation_size)
{
#if USE_GLOG_AND_GFLAGS
for (int k = 0; k < FLAGS_cpu_multicorrelator_real_codes_iterations_test; k++)
#else
for (int k = 0; k < absl::GetFlag(FLAGS_cpu_multicorrelator_real_codes_iterations_test); k++)
#endif
{
correlator->Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
d_code_phase_rate_step_chips,
correlation_size);
}
}
TEST(CpuMulticorrelatorRealCodesTest, MeasureExecutionTime)
{
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::time_point<std::chrono::system_clock> end;
std::chrono::duration<double> elapsed_seconds(0);
#if USE_GLOG_AND_GFLAGS
int max_threads = FLAGS_cpu_multicorrelator_real_codes_max_threads_test;
#else
int max_threads = absl::GetFlag(FLAGS_cpu_multicorrelator_real_codes_max_threads_test);
#endif
std::vector<std::thread> thread_pool;
std::vector<Cpu_Multicorrelator_Real_Codes*> correlator_pool(max_threads);
unsigned int correlation_sizes[3] = {2048, 4096, 8192};
double execution_times[3];
float* d_ca_code;
gr_complex* in_cpu;
gr_complex* d_correlator_outs;
int d_n_correlator_taps = 3;
int d_vector_length = correlation_sizes[2]; // max correlation size to allocate all the necessary memory
float* d_local_code_shift_chips;
// allocate host memory
// Get space for a vector with the C/A code replica sampled 1x/chip
d_ca_code = static_cast<float*>(volk_gnsssdr_malloc(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(float), volk_gnsssdr_get_alignment()));
in_cpu = static_cast<gr_complex*>(volk_gnsssdr_malloc(2 * d_vector_length * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
// correlator outputs (scalar)
d_n_correlator_taps = 3; // Early, Prompt, and Late
d_correlator_outs = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
for (int n = 0; n < d_n_correlator_taps; n++)
{
d_correlator_outs[n] = gr_complex(0, 0);
}
d_local_code_shift_chips = static_cast<float*>(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment()));
// Set TAPs delay values [chips]
float d_early_late_spc_chips = 0.5;
d_local_code_shift_chips[0] = -d_early_late_spc_chips;
d_local_code_shift_chips[1] = 0.0;
d_local_code_shift_chips[2] = d_early_late_spc_chips;
// --- Perform initializations ------------------------------
// local code resampler on GPU
// generate local reference (1 sample per chip)
gps_l1_ca_code_gen_float(own::span<float>(d_ca_code, static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(float)), 1, 0);
// generate inut signal
std::random_device r;
std::default_random_engine e1(r());
std::uniform_real_distribution<float> uniform_dist(0, 1);
for (int n = 0; n < 2 * d_vector_length; n++)
{
in_cpu[n] = std::complex<float>(uniform_dist(e1), uniform_dist(e1));
}
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n] = new Cpu_Multicorrelator_Real_Codes();
correlator_pool[n]->init(d_vector_length, d_n_correlator_taps);
correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_cpu);
correlator_pool[n]->set_local_code_and_taps(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips);
}
float d_rem_carrier_phase_rad = 0.0;
float d_carrier_phase_step_rad = 0.1;
float d_code_phase_step_chips = 0.3;
float d_code_phase_rate_step_chips = 0.00001;
float d_rem_code_phase_chips = 0.4;
EXPECT_NO_THROW(
for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) {
for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++)
{
std::cout << "Running " << current_max_threads << " concurrent correlators\n";
start = std::chrono::system_clock::now();
// create the concurrent correlator threads
for (int current_thread = 0; current_thread < current_max_threads; current_thread++)
{
thread_pool.emplace_back(run_correlator_cpu_real_codes,
correlator_pool[current_thread],
d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_code_phase_rate_step_chips,
d_rem_code_phase_chips,
correlation_sizes[correlation_sizes_idx]);
}
// wait the threads to finish they work and destroy the thread objects
for (auto& t : thread_pool)
{
t.join();
}
thread_pool.clear();
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
#if USE_GLOG_AND_GFLAGS
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(FLAGS_cpu_multicorrelator_real_codes_iterations_test);
#else
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(absl::GetFlag(FLAGS_cpu_multicorrelator_real_codes_iterations_test));
#endif
std::cout << "CPU Multicorrelator (real codes) execution time for length=" << correlation_sizes[correlation_sizes_idx]
<< " : " << execution_times[correlation_sizes_idx] << " [s]\n";
}
});
volk_gnsssdr_free(d_local_code_shift_chips);
volk_gnsssdr_free(d_correlator_outs);
volk_gnsssdr_free(d_ca_code);
volk_gnsssdr_free(in_cpu);
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n]->free();
}
}
TEST(CpuMulticorrelatorRealCodesTest, MeasureExecutionTimeAlloc)
{
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::time_point<std::chrono::system_clock> end;
std::chrono::duration<double> elapsed_seconds(0);
#if USE_GLOG_AND_GFLAGS
int max_threads = FLAGS_cpu_multicorrelator_real_codes_max_threads_test;
#else
int max_threads = absl::GetFlag(FLAGS_cpu_multicorrelator_real_codes_max_threads_test);
#endif
std::vector<std::thread> thread_pool;
std::vector<Cpu_Multicorrelator_Real_Codes*> correlator_pool(max_threads);
unsigned int correlation_sizes[3] = {2048, 4096, 8192};
double execution_times[3];
volk_gnsssdr::vector<float> d_ca_code(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS));
int d_n_correlator_taps = 3;
int d_vector_length = correlation_sizes[2]; // max correlation size to allocate all the necessary memory
volk_gnsssdr::vector<gr_complex> in_cpu(2 * d_vector_length);
// correlator outputs (scalar)
d_n_correlator_taps = 3; // Early, Prompt, and Late
volk_gnsssdr::vector<gr_complex> d_correlator_outs(d_n_correlator_taps, gr_complex(0.0, 0.0));
volk_gnsssdr::vector<float> d_local_code_shift_chips(d_n_correlator_taps);
// Set TAPs delay values [chips]
float d_early_late_spc_chips = 0.5;
d_local_code_shift_chips[0] = -d_early_late_spc_chips;
d_local_code_shift_chips[1] = 0.0;
d_local_code_shift_chips[2] = d_early_late_spc_chips;
// --- Perform initializations ------------------------------
// local code resampler on GPU
// generate local reference (1 sample per chip)
gps_l1_ca_code_gen_float(d_ca_code, 1, 0);
// generate inut signal
std::random_device r;
std::default_random_engine e1(r());
std::uniform_real_distribution<float> uniform_dist(0, 1);
for (int n = 0; n < 2 * d_vector_length; n++)
{
in_cpu[n] = std::complex<float>(uniform_dist(e1), uniform_dist(e1));
}
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n] = new Cpu_Multicorrelator_Real_Codes();
correlator_pool[n]->init(d_vector_length, d_n_correlator_taps);
correlator_pool[n]->set_input_output_vectors(d_correlator_outs.data(), in_cpu.data());
correlator_pool[n]->set_local_code_and_taps(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code.data(), d_local_code_shift_chips.data());
}
float d_rem_carrier_phase_rad = 0.0;
float d_carrier_phase_step_rad = 0.1;
float d_code_phase_step_chips = 0.3;
float d_code_phase_rate_step_chips = 0.00001;
float d_rem_code_phase_chips = 0.4;
EXPECT_NO_THROW(
for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) {
for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++)
{
std::cout << "Running " << current_max_threads << " concurrent correlators\n";
start = std::chrono::system_clock::now();
// create the concurrent correlator threads
for (int current_thread = 0; current_thread < current_max_threads; current_thread++)
{
thread_pool.emplace_back(run_correlator_cpu_real_codes,
correlator_pool[current_thread],
d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_code_phase_rate_step_chips,
d_rem_code_phase_chips,
correlation_sizes[correlation_sizes_idx]);
}
// wait the threads to finish they work and destroy the thread objects
for (auto& t : thread_pool)
{
t.join();
}
thread_pool.clear();
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
#if USE_GLOG_AND_GFLAGS
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(FLAGS_cpu_multicorrelator_real_codes_iterations_test);
#else
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(absl::GetFlag(FLAGS_cpu_multicorrelator_real_codes_iterations_test));
#endif
std::cout << "CPU Multicorrelator (real codes) execution time for length=" << correlation_sizes[correlation_sizes_idx]
<< " : " << execution_times[correlation_sizes_idx] << " [s]\n";
}
});
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n]->free();
}
}

View File

@@ -0,0 +1,272 @@
/*!
* \file fft_length_test.cc
* \brief This file implements timing tests for the FFT.
* \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "GPS_L1_CA.h"
#include "cpu_multicorrelator.h"
#include "gps_sdr_signal_replica.h"
#include <gnuradio/gr_complex.h>
#include <gtest/gtest.h>
#include <volk_gnsssdr/volk_gnsssdr_alloc.h>
#include <chrono>
#include <complex>
#include <random>
#include <thread>
#if USE_GLOG_AND_GFLAGS
DEFINE_int32(cpu_multicorrelator_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test");
DEFINE_int32(cpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test");
#else
ABSL_FLAG(int32_t, cpu_multicorrelator_iterations_test, 100, "Number of averaged iterations in CPU multicorrelator test timing test");
ABSL_FLAG(int32_t, cpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in CPU multicorrelator test timing test");
#endif
void run_correlator_cpu(Cpu_Multicorrelator* correlator,
float d_rem_carrier_phase_rad,
float d_carrier_phase_step_rad,
float d_code_phase_step_chips,
float d_rem_code_phase_chips,
int correlation_size)
{
#if USE_GLOG_AND_GFLAGS
for (int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++)
#else
for (int k = 0; k < absl::GetFlag(FLAGS_cpu_multicorrelator_iterations_test); k++)
#endif
{
correlator->Carrier_wipeoff_multicorrelator_resampler(d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
correlation_size);
}
}
TEST(CpuMulticorrelatorTest, MeasureExecutionTime)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
#if USE_GLOG_AND_GFLAGS
int max_threads = FLAGS_cpu_multicorrelator_max_threads_test;
#else
int max_threads = absl::GetFlag(FLAGS_cpu_multicorrelator_max_threads_test);
#endif
std::vector<std::thread> thread_pool;
std::vector<Cpu_Multicorrelator*> correlator_pool(max_threads);
unsigned int correlation_sizes[3] = {2048, 4096, 8192};
double execution_times[3];
gr_complex* d_ca_code;
gr_complex* in_cpu;
gr_complex* d_correlator_outs;
int d_n_correlator_taps = 3;
int d_vector_length = correlation_sizes[2]; // max correlation size to allocate all the necessary memory
float* d_local_code_shift_chips;
// allocate host memory
// Get space for a vector with the C/A code replica sampled 1x/chip
d_ca_code = static_cast<gr_complex*>(volk_gnsssdr_malloc(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
in_cpu = static_cast<gr_complex*>(volk_gnsssdr_malloc(2 * d_vector_length * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
// correlator outputs (scalar)
d_n_correlator_taps = 3; // Early, Prompt, and Late
d_correlator_outs = static_cast<gr_complex*>(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(gr_complex), volk_gnsssdr_get_alignment()));
for (int n = 0; n < d_n_correlator_taps; n++)
{
d_correlator_outs[n] = gr_complex(0, 0);
}
d_local_code_shift_chips = static_cast<float*>(volk_gnsssdr_malloc(d_n_correlator_taps * sizeof(float), volk_gnsssdr_get_alignment()));
// Set TAPs delay values [chips]
float d_early_late_spc_chips = 0.5;
d_local_code_shift_chips[0] = -d_early_late_spc_chips;
d_local_code_shift_chips[1] = 0.0;
d_local_code_shift_chips[2] = d_early_late_spc_chips;
// -- Perform initializations ------------------------------
// local code resampler on GPU
// generate local reference (1 sample per chip)
gps_l1_ca_code_gen_complex(own::span<gr_complex>(d_ca_code, static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex)), 1, 0);
// generate inut signal
std::random_device r;
std::default_random_engine e1(r());
std::uniform_real_distribution<float> uniform_dist(0, 1);
for (int n = 0; n < 2 * d_vector_length; n++)
{
in_cpu[n] = std::complex<float>(uniform_dist(e1), uniform_dist(e1));
}
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n] = new Cpu_Multicorrelator();
correlator_pool[n]->init(d_vector_length, d_n_correlator_taps);
correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_cpu);
correlator_pool[n]->set_local_code_and_taps(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code, d_local_code_shift_chips);
}
float d_rem_carrier_phase_rad = 0.0;
float d_carrier_phase_step_rad = 0.1;
float d_code_phase_step_chips = 0.3;
float d_rem_code_phase_chips = 0.4;
EXPECT_NO_THROW(
for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) {
for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++)
{
std::cout << "Running " << current_max_threads << " concurrent correlators\n";
start = std::chrono::system_clock::now();
// create the concurrent correlator threads
for (int current_thread = 0; current_thread < current_max_threads; current_thread++)
{
thread_pool.emplace_back(run_correlator_cpu,
correlator_pool[current_thread],
d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
correlation_sizes[correlation_sizes_idx]);
}
// wait the threads to finish they work and destroy the thread objects
for (auto& t : thread_pool)
{
t.join();
}
thread_pool.clear();
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
#if USE_GLOG_AND_GFLAGS
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(FLAGS_cpu_multicorrelator_iterations_test);
#else
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(absl::GetFlag(FLAGS_cpu_multicorrelator_iterations_test));
#endif
std::cout << "CPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx]
<< " : " << execution_times[correlation_sizes_idx] << " [s]\n";
}
});
volk_gnsssdr_free(d_local_code_shift_chips);
volk_gnsssdr_free(d_correlator_outs);
volk_gnsssdr_free(d_ca_code);
volk_gnsssdr_free(in_cpu);
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n]->free();
}
}
TEST(CpuMulticorrelatorTest, MeasureExecutionTimeAlloc)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
#if USE_GLOG_AND_GFLAGS
int max_threads = FLAGS_cpu_multicorrelator_max_threads_test;
#else
int max_threads = absl::GetFlag(FLAGS_cpu_multicorrelator_max_threads_test);
#endif
std::vector<std::thread> thread_pool;
std::vector<Cpu_Multicorrelator*> correlator_pool(max_threads);
unsigned int correlation_sizes[3] = {2048, 4096, 8192};
double execution_times[3];
int d_n_correlator_taps = 3;
int d_vector_length = correlation_sizes[2]; // max correlation size to allocate all the necessary memory
// allocate host memory
// Get space for a vector with the C/A code replica sampled 1x/chip
volk_gnsssdr::vector<gr_complex> d_ca_code(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS));
volk_gnsssdr::vector<gr_complex> in_cpu(2 * d_vector_length);
// correlator outputs (scalar)
d_n_correlator_taps = 3; // Early, Prompt, and Late
volk_gnsssdr::vector<gr_complex> d_correlator_outs(d_n_correlator_taps, gr_complex(0.0, 0.0));
volk_gnsssdr::vector<float> d_local_code_shift_chips(d_n_correlator_taps);
// Set TAPs delay values [chips]
float d_early_late_spc_chips = 0.5;
d_local_code_shift_chips[0] = -d_early_late_spc_chips;
d_local_code_shift_chips[1] = 0.0;
d_local_code_shift_chips[2] = d_early_late_spc_chips;
// -- Perform initializations ------------------------------
// local code resampler on GPU
// generate local reference (1 sample per chip)
gps_l1_ca_code_gen_complex(d_ca_code, 1, 0);
// generate inut signal
std::random_device r;
std::default_random_engine e1(r());
std::uniform_real_distribution<float> uniform_dist(0, 1);
for (int n = 0; n < 2 * d_vector_length; n++)
{
in_cpu[n] = std::complex<float>(uniform_dist(e1), uniform_dist(e1));
}
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n] = new Cpu_Multicorrelator();
correlator_pool[n]->init(d_vector_length, d_n_correlator_taps);
correlator_pool[n]->set_input_output_vectors(d_correlator_outs.data(), in_cpu.data());
correlator_pool[n]->set_local_code_and_taps(static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS), d_ca_code.data(), d_local_code_shift_chips.data());
}
float d_rem_carrier_phase_rad = 0.0;
float d_carrier_phase_step_rad = 0.1;
float d_code_phase_step_chips = 0.3;
float d_rem_code_phase_chips = 0.4;
EXPECT_NO_THROW(
for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) {
for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++)
{
std::cout << "Running " << current_max_threads << " concurrent correlators\n";
start = std::chrono::system_clock::now();
// create the concurrent correlator threads
for (int current_thread = 0; current_thread < current_max_threads; current_thread++)
{
thread_pool.emplace_back(run_correlator_cpu,
correlator_pool[current_thread],
d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
correlation_sizes[correlation_sizes_idx]);
}
// wait the threads to finish they work and destroy the thread objects
for (auto& t : thread_pool)
{
t.join();
}
thread_pool.clear();
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
#if USE_GLOG_AND_GFLAGS
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(FLAGS_cpu_multicorrelator_iterations_test);
#else
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(absl::GetFlag(FLAGS_cpu_multicorrelator_iterations_test));
#endif
std::cout << "CPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx]
<< " : " << execution_times[correlation_sizes_idx] << " [s]\n";
}
});
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n]->free();
}
}

View File

@@ -0,0 +1,148 @@
/*!
* \file cubature_filter_test.cc
* \brief This file implements numerical accuracy test for the CKF library.
* \author Gerald LaMountain, 2019. gerald(at)ece.neu.edu
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "nonlinear_tracking.h"
#include <armadillo>
#include <gtest/gtest.h>
#include <random>
#define CUBATURE_TEST_N_TRIALS 1000
#define CUBATURE_TEST_TOLERANCE 0.01
class TransitionModel : public ModelFunction
{
public:
explicit TransitionModel(const arma::mat& kf_F) : coeff_mat(kf_F){};
arma::vec operator()(const arma::vec& input) override { return coeff_mat * input; };
private:
arma::mat coeff_mat;
};
class MeasurementModel : public ModelFunction
{
public:
explicit MeasurementModel(const arma::mat& kf_H) : coeff_mat(kf_H){};
arma::vec operator()(const arma::vec& input) override { return coeff_mat * input; };
private:
arma::mat coeff_mat;
};
TEST(CubatureFilterComputationTest, CubatureFilterTest)
{
CubatureFilter kf_cubature;
arma::vec kf_x;
arma::mat kf_P_x;
arma::vec kf_x_pre;
arma::mat kf_P_x_pre;
arma::vec ckf_x_pre;
arma::mat ckf_P_x_pre;
arma::vec kf_x_post;
arma::mat kf_P_x_post;
arma::vec ckf_x_post;
arma::mat ckf_P_x_post;
arma::mat kf_F;
arma::mat kf_H;
arma::mat kf_Q;
arma::mat kf_R;
arma::vec eta;
arma::vec nu;
arma::vec kf_y;
arma::mat kf_P_y;
arma::mat kf_K;
ModelFunction* transition_function;
ModelFunction* measurement_function;
// -- Perform initializations ------------------------------
std::random_device r;
std::default_random_engine e1(r());
std::normal_distribution<float> normal_dist(0, 5);
std::uniform_real_distribution<float> uniform_dist(0.1, 5.0);
std::uniform_int_distribution<> uniform_dist_int(1, 5);
uint8_t nx = 0;
uint8_t ny = 0;
for (uint16_t k = 0; k < CUBATURE_TEST_N_TRIALS; k++)
{
nx = static_cast<uint8_t>(uniform_dist_int(e1));
ny = static_cast<uint8_t>(uniform_dist_int(e1));
kf_x = arma::randn<arma::vec>(nx, 1);
kf_P_x_post = 5.0 * arma::diagmat(arma::randu<arma::vec>(nx, 1));
kf_x_post = arma::mvnrnd(kf_x, kf_P_x_post);
kf_cubature.initialize(kf_x_post, kf_P_x_post);
// Prediction Step
kf_F = arma::randu<arma::mat>(nx, nx);
kf_Q = arma::diagmat(arma::randu<arma::vec>(nx, 1));
transition_function = new TransitionModel(kf_F);
arma::mat ttx = (*transition_function)(kf_x_post);
kf_cubature.predict_sequential(kf_x_post, kf_P_x_post, transition_function, kf_Q);
ckf_x_pre = kf_cubature.get_x_pred();
ckf_P_x_pre = kf_cubature.get_P_x_pred();
kf_x_pre = kf_F * kf_x_post;
kf_P_x_pre = kf_F * kf_P_x_post * kf_F.t() + kf_Q;
EXPECT_TRUE(arma::approx_equal(ckf_x_pre, kf_x_pre, "absdiff", CUBATURE_TEST_TOLERANCE));
EXPECT_TRUE(arma::approx_equal(ckf_P_x_pre, kf_P_x_pre, "absdiff", CUBATURE_TEST_TOLERANCE));
// Update Step
kf_H = arma::randu<arma::mat>(ny, nx);
kf_R = arma::diagmat(arma::randu<arma::vec>(ny, 1));
eta = arma::mvnrnd(arma::zeros<arma::vec>(nx, 1), kf_Q);
nu = arma::mvnrnd(arma::zeros<arma::vec>(ny, 1), kf_R);
kf_y = kf_H * (kf_F * kf_x + eta) + nu;
measurement_function = new MeasurementModel(kf_H);
kf_cubature.update_sequential(kf_y, kf_x_pre, kf_P_x_pre, measurement_function, kf_R);
ckf_x_post = kf_cubature.get_x_est();
ckf_P_x_post = kf_cubature.get_P_x_est();
kf_P_y = kf_H * kf_P_x_pre * kf_H.t() + kf_R;
kf_K = (kf_P_x_pre * kf_H.t()) * arma::inv(kf_P_y);
kf_x_post = kf_x_pre + kf_K * (kf_y - kf_H * kf_x_pre);
kf_P_x_post = (arma::eye(nx, nx) - kf_K * kf_H) * kf_P_x_pre;
EXPECT_TRUE(arma::approx_equal(ckf_x_post, kf_x_post, "absdiff", CUBATURE_TEST_TOLERANCE));
EXPECT_TRUE(arma::approx_equal(ckf_P_x_post, kf_P_x_post, "absdiff", CUBATURE_TEST_TOLERANCE));
delete transition_function;
delete measurement_function;
}
}

View File

@@ -0,0 +1,174 @@
/*!
* \file discriminator_test.cc
* \brief This file implements tests for the tracking discriminators
* \author Cillian O'Driscoll, 2019. cillian.odriscoll(at)gmail.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "tracking_discriminators.h"
#include <gtest/gtest.h>
#include <cmath>
#include <vector>
double BpskCorrelationFunction(double offset_in_chips)
{
double abs_tau = std::abs(offset_in_chips);
if (abs_tau > 1.0)
{
return 0.0;
}
return 1.0 - abs_tau;
}
TEST(DllNcEMinusLNormalizedTest, Bpsk)
{
std::vector<gr_complex> complex_amplitude_vector = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
std::vector<double> spacing_vector = {0.5, 0.25, 0.1, 0.01};
std::vector<double> error_vector = {0.0, 0.01, 0.1, 0.25, -0.25, -0.1, -0.01};
for (auto A : complex_amplitude_vector)
{
for (auto spacing : spacing_vector)
{
for (auto err : error_vector)
{
gr_complex E = A * static_cast<float>(BpskCorrelationFunction(err - spacing));
gr_complex L = A * static_cast<float>(BpskCorrelationFunction(err + spacing));
double disc_out = dll_nc_e_minus_l_normalized(E, L, spacing);
if (std::abs(err) < 2.0 * spacing)
{
EXPECT_NEAR(disc_out, err, 1e-4) << " Spacing: " << spacing;
}
else
{
EXPECT_TRUE(err * disc_out >= 0.0);
}
if (spacing != 0.5 and err != 0.0)
{
double disc_out_old = dll_nc_e_minus_l_normalized(E, L);
EXPECT_NE(disc_out_old, err);
}
}
}
}
}
TEST(DllNcEMinusLNormalizedTest, SinBoc11)
{
std::vector<gr_complex> complex_amplitude_vector = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
std::vector<double> spacing_vector = {0.75, 0.6666, 5.0 / 12.0, 0.25, 1.0 / 6.0, 0.01};
std::vector<double> error_vector = {0.0, 0.01, 0.1, 0.25, -0.25, -0.1, -0.01};
for (auto A : complex_amplitude_vector)
{
for (auto spacing : spacing_vector)
{
double corr_slope = -CalculateSlopeAbs(&SinBocCorrelationFunction<1, 1>, spacing);
double y_intercept = GetYInterceptAbs(&SinBocCorrelationFunction<1, 1>, spacing);
for (auto err : error_vector)
{
gr_complex E = A * static_cast<float>(SinBocCorrelationFunction<1, 1>(err - spacing));
gr_complex L = A * static_cast<float>(SinBocCorrelationFunction<1, 1>(err + spacing));
double disc_out = dll_nc_e_minus_l_normalized(E, L, spacing, corr_slope, y_intercept);
double corr_slope_at_err = -CalculateSlopeAbs(&SinBocCorrelationFunction<1, 1>, spacing + err);
double corr_slope_at_neg_err = -CalculateSlopeAbs(&SinBocCorrelationFunction<1, 1>, spacing - err);
bool in_linear_region = (std::abs(err) < spacing) and (std::abs(corr_slope_at_err - corr_slope_at_neg_err) < 0.01);
double norm_factor = (y_intercept - corr_slope * spacing) / spacing;
if (in_linear_region)
{
EXPECT_NEAR(disc_out, err, 1e-4) << " Spacing: " << spacing << ", slope : " << corr_slope << ", y_intercept: " << y_intercept << ", norm: " << norm_factor << " E: " << E << ", L: " << L;
if (norm_factor != 0.5 and err != 0.0)
{
double disc_out_old = dll_nc_e_minus_l_normalized(E, L);
EXPECT_NE(disc_out_old, err) << " Spacing: " << spacing << ", slope : " << corr_slope << ", y_intercept: " << y_intercept << ", norm: " << norm_factor << " E: " << E << ", L: " << L;
}
}
}
}
}
}
TEST(CosBocCorrelationFunction, FixedPoints)
{
double res = CosBocCorrelationFunction<1, 1>(0.0);
EXPECT_NEAR(res, 1.0, 1e-4);
res = CosBocCorrelationFunction<1, 1>(0.2);
EXPECT_NEAR(res, 0.0, 1e-4);
res = CosBocCorrelationFunction<1, 1>(0.25);
EXPECT_NEAR(res, -0.25, 1e-4);
res = CosBocCorrelationFunction<1, 1>(0.5);
EXPECT_NEAR(res, -0.5, 1e-4);
res = CosBocCorrelationFunction<1, 1>(0.75);
EXPECT_NEAR(res, 0.25, 1e-4);
res = CosBocCorrelationFunction<1, 1>(1.0);
EXPECT_NEAR(res, 0.0, 1e-4);
res = CosBocCorrelationFunction<1, 1>(-0.2);
EXPECT_NEAR(res, 0.0, 1e-4);
res = CosBocCorrelationFunction<1, 1>(-0.5);
EXPECT_NEAR(res, -0.5, 1e-4);
res = CosBocCorrelationFunction<1, 1>(-0.75);
EXPECT_NEAR(res, 0.25, 1e-4);
res = CosBocCorrelationFunction<1, 1>(-1.0);
EXPECT_NEAR(res, 0.0, 1e-4);
}
TEST(DllNcEMinusLNormalizedTest, CosBoc11)
{
std::vector<gr_complex> complex_amplitude_vector = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}};
std::vector<double> spacing_vector = {0.875, 0.588, 0.1, 0.01};
std::vector<double> error_vector = {0.0, 0.01, 0.1, 0.25, -0.25, -0.1, -0.01};
for (auto A : complex_amplitude_vector)
{
for (auto spacing : spacing_vector)
{
double corr_slope = -CalculateSlopeAbs(&CosBocCorrelationFunction<1, 1>, spacing);
double y_intercept = GetYInterceptAbs(&CosBocCorrelationFunction<1, 1>, spacing);
for (auto err : error_vector)
{
gr_complex E = A * static_cast<float>(CosBocCorrelationFunction<1, 1>(err - spacing));
gr_complex L = A * static_cast<float>(CosBocCorrelationFunction<1, 1>(err + spacing));
double disc_out = dll_nc_e_minus_l_normalized(E, L, spacing, corr_slope, y_intercept);
double corr_slope_at_err = -CalculateSlopeAbs(&CosBocCorrelationFunction<1, 1>, spacing + err);
double corr_slope_at_neg_err = -CalculateSlopeAbs(&CosBocCorrelationFunction<1, 1>, spacing - err);
bool in_linear_region = (std::abs(err) < spacing) and (std::abs(corr_slope_at_err - corr_slope_at_neg_err) < 0.01);
double norm_factor = (y_intercept - corr_slope * spacing) / spacing;
if (in_linear_region)
{
EXPECT_NEAR(disc_out, err, 1e-4) << " Spacing: " << spacing << ", slope : " << corr_slope << ", y_intercept: " << y_intercept << ", norm: " << norm_factor << " E: " << E << ", L: " << L;
if (norm_factor != 0.5 and err != 0.0)
{
double disc_out_old = dll_nc_e_minus_l_normalized(E, L);
EXPECT_NE(disc_out_old, err) << " Spacing: " << spacing << ", slope : " << corr_slope << ", y_intercept: " << y_intercept << ", norm: " << norm_factor << " E: " << E << ", L: " << L;
}
}
}
}
}
}

View File

@@ -0,0 +1,196 @@
/*!
* \file galileo_e1_dll_pll_veml_tracking_test.cc
* \brief This class implements a tracking test for GalileoE1DllPllVemlTracking
* class based on some input parameters.
* \author Luis Esteve, 2012. luis(at)epsilon-formacion.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "galileo_e1_dll_pll_veml_tracking.h"
#include "gnss_block_factory.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "in_memory_configuration.h"
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <chrono>
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
class GalileoE1DllPllVemlTrackingInternalTest : public ::testing::Test
{
protected:
GalileoE1DllPllVemlTrackingInternalTest()
: item_size(sizeof(gr_complex))
{
factory = std::make_shared<GNSSBlockFactory>();
config = std::make_shared<InMemoryConfiguration>();
}
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<GNSSBlockFactory> factory;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
int message{0};
bool stop{false};
};
void GalileoE1DllPllVemlTrackingInternalTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'E';
std::string signal = "1B";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 11;
config->set_property("GNSS-SDR.internal_fs_sps", "8000000");
config->set_property("Tracking_1B.implementation", "Galileo_E1_DLL_PLL_VEML_Tracking");
config->set_property("Tracking_1B.item_type", "gr_complex");
config->set_property("Tracking_1B.dump", "false");
config->set_property("Tracking_1B.dump_filename", "../data/veml_tracking_ch_");
config->set_property("Tracking_1B.early_late_space_chips", "0.15");
config->set_property("Tracking_1B.very_early_late_space_chips", "0.6");
config->set_property("Tracking_1B.pll_bw_hz", "30.0");
config->set_property("Tracking_1B.dll_bw_hz", "2.0");
}
TEST_F(GalileoE1DllPllVemlTrackingInternalTest, Instantiate)
{
init();
auto tracking = factory->GetBlock(config.get(), "Tracking_1B", 1, 1);
EXPECT_STREQ("Galileo_E1_DLL_PLL_VEML_Tracking", tracking->implementation().c_str());
}
TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ConnectAndRun)
{
int fs_in = 8000000;
int nsamples = 40000000;
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::time_point<std::chrono::system_clock> end;
std::chrono::duration<double> elapsed_seconds(0);
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
// Example using smart pointers and the block factory
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config.get(), "Tracking_1B", 1, 1);
std::shared_ptr<GalileoE1DllPllVemlTracking> tracking = std::dynamic_pointer_cast<GalileoE1DllPllVemlTracking>(trk_);
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0));
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
std::cout << "Processed " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}
TEST_F(GalileoE1DllPllVemlTrackingInternalTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::time_point<std::chrono::system_clock> end;
std::chrono::duration<double> elapsed_seconds(0);
// int num_samples = 40000000; // 4 Msps
// unsigned int skiphead_sps = 24000000; // 4 Msps
int num_samples = 80000000; // 8 Msps
unsigned int skiphead_sps = 8000000; // 8 Msps
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
// Example using smart pointers and the block factory
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config.get(), "Tracking_1B", 1, 1);
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_);
// gnss_synchro.Acq_delay_samples = 1753; // 4 Msps
// gnss_synchro.Acq_doppler_hz = -9500; // 4 Msps
gnss_synchro.Acq_delay_samples = 17256; // 8 Msps
gnss_synchro.Acq_doppler_hz = -8750; // 8 Msps
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
std::string path = std::string(TEST_PATH);
std::string file = path + "signal_samples/GSoC_CTTC_capture_2012_07_26_4Msps_4ms.dat";
const char* file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false);
gr::blocks::skiphead::sptr skip_head = gr::blocks::skiphead::make(sizeof(gr_complex), skiphead_sps);
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), num_samples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, skip_head, 0);
top_block->connect(skip_head, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
std::cout << "Tracked " << num_samples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,144 @@
/*!
* \file galileo_e1_dll_pll_veml_tracking_test.cc
* \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Marc Sales, 2014. marcsales92(at)gmail.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "galileo_e5a_dll_pll_tracking.h"
#include "gnss_block_factory.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "in_memory_configuration.h"
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <chrono>
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
class GalileoE5aTrackingTest : public ::testing::Test
{
protected:
GalileoE5aTrackingTest()
{
factory = std::make_shared<GNSSBlockFactory>();
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
stop = false;
message = 0;
gnss_synchro = Gnss_Synchro();
}
~GalileoE5aTrackingTest() = default;
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<GNSSBlockFactory> factory;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
bool stop;
int message;
};
void GalileoE5aTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'E';
std::string signal = "5X";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 11;
config->set_property("GNSS-SDR.internal_fs_sps", "32000000");
config->set_property("Tracking_5X.implementation", "Galileo_E5a_DLL_PLL_Tracking");
config->set_property("Tracking_5X.item_type", "gr_complex");
config->set_property("Tracking_5X.dump", "false");
config->set_property("Tracking_5X.dump_filename", "../data/e5a_tracking_ch_");
config->set_property("Tracking_5X.early_late_space_chips", "0.5");
config->set_property("Tracking_5X.order", "2");
config->set_property("Tracking_5X.pll_bw_hz", "20.0");
config->set_property("Tracking_5X.dll_bw_hz", "5.0");
config->set_property("Tracking_5X.pll_bw_narrow_hz", "2.0");
config->set_property("Tracking_5X.pll_bw_narrow_hz", "2.0");
config->set_property("Tracking_5X.ti_ms", "1");
}
TEST_F(GalileoE5aTrackingTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
int fs_in = 32000000;
int nsamples = 32000000 * 5;
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
// Example using smart pointers and the block factory
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config.get(), "Tracking_5X", 1, 1);
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_);
// REAL
gnss_synchro.Acq_delay_samples = 10; // 32 Msps
// gnss_synchro.Acq_doppler_hz = 3500; // 32 Msps
gnss_synchro.Acq_doppler_hz = 2000; // 500 Hz resolution
// gnss_synchro.Acq_samplestamp_samples = 98000;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0));
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,143 @@
/*!
* \file galileo_e5b_dll_pll_tracking_test.cc
* \brief This class implements a tracking test for Galileo_E5b_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Piyush Gupta, 2020. piyush04111999@gmail.com
* \note Code added as part of GSoC 2020 Program.
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "galileo_e5b_dll_pll_tracking.h"
#include "gnss_block_factory.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "in_memory_configuration.h"
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <chrono>
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
class GalileoE5bTrackingTest : public ::testing::Test
{
protected:
GalileoE5bTrackingTest()
{
factory = std::make_shared<GNSSBlockFactory>();
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
stop = false;
message = 0;
gnss_synchro = Gnss_Synchro();
}
~GalileoE5bTrackingTest() = default;
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<GNSSBlockFactory> factory;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
bool stop;
int message;
};
void GalileoE5bTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'E';
std::string signal = "7X";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 11;
config->set_property("GNSS-SDR.internal_fs_sps", "32000000");
config->set_property("Tracking_7X.implementation", "Galileo_E5b_DLL_PLL_Tracking");
config->set_property("Tracking_7X.item_type", "gr_complex");
config->set_property("Tracking_7X.dump", "false");
config->set_property("Tracking_7X.dump_filename", "../data/e5b_tracking");
config->set_property("Tracking_7X.early_late_space_chips", "0.5");
config->set_property("Tracking_7X.order", "2");
config->set_property("Tracking_7X.pll_bw_hz", "20.0");
config->set_property("Tracking_7X.dll_bw_hz", "5.0");
config->set_property("Tracking_7X.pll_bw_narrow_hz", "2.0");
config->set_property("Tracking_7X.pll_bw_narrow_hz", "2.0");
config->set_property("Tracking_7X.ti_ms", "1");
}
TEST_F(GalileoE5bTrackingTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
int fs_in = 32000000;
int nsamples = fs_in * 5;
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
// Example using smart pointers and the block factory
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config.get(), "Tracking_7X", 1, 1);
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_);
// REAL
gnss_synchro.Acq_delay_samples = 10; // 32 Msps
gnss_synchro.Acq_doppler_hz = 2000; // 500 Hz resolution
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0));
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,201 @@
/*!
* \file glonass_l1_ca_dll_pll_c_aid_tracking_test.cc
* \brief This class implements a tracking test for GLONASS_L1_CA_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com
* \author Luis Esteve, 2017. luis(at)epsilon-formacion.com
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "glonass_l1_ca_dll_pll_c_aid_tracking.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "in_memory_configuration.h"
#include "tracking_interface.h"
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <pmt/pmt.h>
#include <chrono>
#include <utility>
#if HAS_GENERIC_LAMBDA
#else
#include <boost/bind/bind.hpp>
#endif
#if PMT_USES_BOOST_ANY
namespace wht = boost;
#else
namespace wht = std;
#endif
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class GlonassL1CaDllPllCAidTrackingTest_msg_rx;
using GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr = gnss_shared_ptr<GlonassL1CaDllPllCAidTrackingTest_msg_rx>;
GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make();
class GlonassL1CaDllPllCAidTrackingTest_msg_rx : public gr::block
{
private:
friend GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make();
void msg_handler_channel_events(const pmt::pmt_t msg);
GlonassL1CaDllPllCAidTrackingTest_msg_rx();
public:
int rx_message;
~GlonassL1CaDllPllCAidTrackingTest_msg_rx(); //!< Default destructor
};
GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr GlonassL1CaDllPllCAidTrackingTest_msg_rx_make()
{
return GlonassL1CaDllPllCAidTrackingTest_msg_rx_sptr(new GlonassL1CaDllPllCAidTrackingTest_msg_rx());
}
void GlonassL1CaDllPllCAidTrackingTest_msg_rx::msg_handler_channel_events(const pmt::pmt_t msg)
{
try
{
int64_t message = pmt::to_long(std::move(msg));
rx_message = message;
}
catch (const wht::bad_any_cast& e)
{
LOG(WARNING) << "msg_handler_channel_events Bad any_cast: " << e.what();
rx_message = 0;
}
}
GlonassL1CaDllPllCAidTrackingTest_msg_rx::GlonassL1CaDllPllCAidTrackingTest_msg_rx() : gr::block("GlonassL1CaDllPllCAidTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"),
#if HAS_GENERIC_LAMBDA
[this](auto&& PH1) { msg_handler_channel_events(PH1); });
#else
#if USE_BOOST_BIND_PLACEHOLDERS
boost::bind(&GlonassL1CaDllPllCAidTrackingTest_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
#else
boost::bind(&GlonassL1CaDllPllCAidTrackingTest_msg_rx::msg_handler_channel_events, this, _1));
#endif
#endif
rx_message = 0;
}
GlonassL1CaDllPllCAidTrackingTest_msg_rx::~GlonassL1CaDllPllCAidTrackingTest_msg_rx() = default;
// ###########################################################
class GlonassL1CaDllPllCAidTrackingTest : public ::testing::Test
{
protected:
GlonassL1CaDllPllCAidTrackingTest()
{
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
gnss_synchro = Gnss_Synchro();
}
~GlonassL1CaDllPllCAidTrackingTest() = default;
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
};
void GlonassL1CaDllPllCAidTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'R';
std::string signal = "1G";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 11;
config->set_property("GNSS-SDR.internal_fs_sps", "6625000");
config->set_property("Tracking_1G.implementation", "GLONASS_L1_CA_DLL_PLL_C_Aid_Tracking");
config->set_property("Tracking_1G.item_type", "gr_complex");
config->set_property("Tracking_1G.dump", "false");
config->set_property("Tracking_1G.dump_filename", "./tracking_ch_");
config->set_property("Tracking_1G.early_late_space_chips", "0.5");
config->set_property("Tracking_1G.order", "2");
config->set_property("Tracking_1G.pll_bw_hz", "2");
config->set_property("Tracking_1G.dll_bw_hz", "0.5");
}
TEST_F(GlonassL1CaDllPllCAidTrackingTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
int fs_in = 6625000;
int nsamples = fs_in * 4e-3 * 2;
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
std::shared_ptr<TrackingInterface> tracking = std::make_shared<GlonassL1CaDllPllCAidTracking>(config.get(), "Tracking_1G", 1, 1);
auto msg_rx = GlonassL1CaDllPllCAidTrackingTest_msg_rx_make();
gnss_synchro.Acq_delay_samples = 1343;
gnss_synchro.Acq_doppler_hz = -2750;
// gnss_synchro.Acq_doppler_hz = -2750;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
std::string path = std::string(TEST_PATH);
std::string file = path + "signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin";
const char* file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false);
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
// TODO: Verify tracking results
std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,207 @@
/*!
* \file glonass_l1_ca_dll_pll_tracking_test.cc
* \brief This class implements a tracking test for GLONASS_L1_CA_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Gabriel Araujo, 2017. gabriel.araujo.5000(at)gmail.com
* \author Luis Esteve, 2017. luis(at)epsilon-formacion.com
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "glonass_l1_ca_dll_pll_tracking.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "in_memory_configuration.h"
#include "tracking_interface.h"
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <pmt/pmt.h>
#include <chrono>
#include <utility>
#if HAS_GENERIC_LAMBDA
#else
#include <boost/bind/bind.hpp>
#endif
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
#if PMT_USES_BOOST_ANY
namespace wht = boost;
#else
namespace wht = std;
#endif
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class GlonassL1CaDllPllTrackingTest_msg_rx;
using GlonassL1CaDllPllTrackingTest_msg_rx_sptr = gnss_shared_ptr<GlonassL1CaDllPllTrackingTest_msg_rx>;
GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make();
class GlonassL1CaDllPllTrackingTest_msg_rx : public gr::block
{
private:
friend GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make();
void msg_handler_channel_events(const pmt::pmt_t msg);
GlonassL1CaDllPllTrackingTest_msg_rx();
public:
int rx_message;
~GlonassL1CaDllPllTrackingTest_msg_rx(); //!< Default destructor
};
GlonassL1CaDllPllTrackingTest_msg_rx_sptr GlonassL1CaDllPllTrackingTest_msg_rx_make()
{
return GlonassL1CaDllPllTrackingTest_msg_rx_sptr(new GlonassL1CaDllPllTrackingTest_msg_rx());
}
void GlonassL1CaDllPllTrackingTest_msg_rx::msg_handler_channel_events(const pmt::pmt_t msg)
{
try
{
int64_t message = pmt::to_long(std::move(msg));
rx_message = message;
}
catch (const wht::bad_any_cast& e)
{
LOG(WARNING) << "msg_handler_channel_events Bad any_cast: " << e.what();
rx_message = 0;
}
}
GlonassL1CaDllPllTrackingTest_msg_rx::GlonassL1CaDllPllTrackingTest_msg_rx() : gr::block("GlonassL1CaDllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"),
#if HAS_GENERIC_LAMBDA
[this](auto&& PH1) { msg_handler_channel_events(PH1); });
#else
#if USE_BOOST_BIND_PLACEHOLDERS
boost::bind(&GlonassL1CaDllPllTrackingTest_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
#else
boost::bind(&GlonassL1CaDllPllTrackingTest_msg_rx::msg_handler_channel_events, this, _1));
#endif
#endif
rx_message = 0;
}
GlonassL1CaDllPllTrackingTest_msg_rx::~GlonassL1CaDllPllTrackingTest_msg_rx() = default;
// ###########################################################
class GlonassL1CaDllPllTrackingTest : public ::testing::Test
{
protected:
GlonassL1CaDllPllTrackingTest()
{
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
gnss_synchro = Gnss_Synchro();
}
~GlonassL1CaDllPllTrackingTest() = default;
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
};
void GlonassL1CaDllPllTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'R';
std::string signal = "1G";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 11;
config->set_property("GNSS-SDR.internal_fs_sps", "6625000");
config->set_property("Tracking_1G.implementation", "GLONASS_L1_CA_DLL_PLL_Tracking");
config->set_property("Tracking_1G.item_type", "gr_complex");
config->set_property("Tracking_1G.dump", "false");
config->set_property("Tracking_1G.dump_filename", "./tracking_ch_");
config->set_property("Tracking_1G.early_late_space_chips", "0.5");
config->set_property("Tracking_1G.order", "2");
config->set_property("Tracking_1G.pll_bw_hz", "2");
config->set_property("Tracking_1G.dll_bw_hz", "0.5");
}
TEST_F(GlonassL1CaDllPllTrackingTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
int fs_in = 6625000;
int nsamples = fs_in * 4e-3 * 2;
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
std::shared_ptr<TrackingInterface> tracking = std::make_shared<GlonassL1CaDllPllTracking>(config.get(), "Tracking_1G", 1, 1);
auto msg_rx = GlonassL1CaDllPllTrackingTest_msg_rx_make();
gnss_synchro.Acq_delay_samples = 1343;
gnss_synchro.Acq_doppler_hz = -2750;
// gnss_synchro.Acq_doppler_hz = -2750;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
gr::analog::sig_source_c::sptr sin_source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0));
std::string path = std::string(TEST_PATH);
std::string file = path + "signal_samples/NT1065_GLONASS_L1_20160831_fs6625e6_if0e3_4ms.bin";
const char* file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false);
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
// TODO: Verify tracking results
std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,662 @@
/*!
* \file gps_l1_ca_dll_pll_tracking_test_fpga.cc
* \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Marc Majoral, 2017. mmajoral(at)cttc.cat
* \author Javier Arribas, 2017. jarribas(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "GPS_L1_CA.h"
#include "gnss_block_interface.h"
#include "gnss_synchro.h"
#include "gps_l1_ca_dll_pll_tracking_fpga.h"
#include "in_memory_configuration.h"
#include "interleaved_byte_to_complex_short.h"
#include "signal_generator_flags.h"
#include "tracking_dump_reader.h"
#include "tracking_interface.h"
#include "tracking_true_obs_reader.h"
#include <armadillo>
#include <boost/thread.hpp> // to test the FPGA we have to create a simultaneous task to send the samples using the DMA and stop the test
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/interleaved_char_to_complex.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <pmt/pmt.h>
#include <chrono>
#include <cstdio> // FPGA read input file
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <unistd.h>
#include <utility>
#if USE_GLOG_AND_GFLAGS
#include <gflags/gflags.h>
#include <glog/logging.h>
#else
#include <absl/flags/flag.h>
#include <absl/log/log.h>
#endif
#if HAS_GENERIC_LAMBDA
#else
#include <boost/bind/bind.hpp>
#endif
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
#if PMT_USES_BOOST_ANY
namespace wht = boost;
#else
namespace wht = std;
#endif
#define DMA_TRACK_TRANSFER_SIZE 2046 // DMA transfer size for tracking
#define MIN_SAMPLES_REMAINING 20000 // number of remaining samples in the DMA that causes the CPU to stop the flowgraph (it has to be a bit alrger than 2x max packet size)
#define FIVE_SECONDS 5000000 // five seconds in microseconds
void send_tracking_gps_input_samples(FILE *rx_signal_file,
int num_remaining_samples, const gr::top_block_sptr &top_block)
{
int num_samples_transferred = 0; // number of samples that have been transferred to the DMA so far
static int flowgraph_stopped = 0; // flag to indicate if the flowgraph is stopped already
char *buffer_DMA; // temporary buffer to store the samples to be sent to the DMA
int dma_descr; // DMA descriptor
dma_descr = open("/dev/loop_tx", O_WRONLY);
if (dma_descr < 0)
{
std::cerr << "Can't open loop device\n";
return;
}
buffer_DMA = reinterpret_cast<char *>(malloc(DMA_TRACK_TRANSFER_SIZE));
if (!buffer_DMA)
{
std::cerr << "Memory error!\n";
close(dma_descr);
return;
}
while (num_remaining_samples > 0)
{
if (num_remaining_samples < MIN_SAMPLES_REMAINING)
{
if (flowgraph_stopped == 0)
{
// stop top module
top_block->stop();
flowgraph_stopped = 1;
}
}
if (num_remaining_samples > DMA_TRACK_TRANSFER_SIZE)
{
size_t result = fread(buffer_DMA, DMA_TRACK_TRANSFER_SIZE, 1, rx_signal_file);
if (result != DMA_TRACK_TRANSFER_SIZE)
{
std::cerr << "Error reading from DMA\n";
}
assert(DMA_TRACK_TRANSFER_SIZE == write(dma_descr, &buffer_DMA[0], DMA_TRACK_TRANSFER_SIZE));
num_remaining_samples = num_remaining_samples - DMA_TRACK_TRANSFER_SIZE;
num_samples_transferred = num_samples_transferred + DMA_TRACK_TRANSFER_SIZE;
}
else
{
size_t result = fread(buffer_DMA, num_remaining_samples, 1, rx_signal_file);
if (static_cast<int>(result) != num_remaining_samples)
{
std::cerr << "Error reading from DMA\n";
}
assert(num_remaining_samples == write(dma_descr, &buffer_DMA[0], num_remaining_samples));
num_samples_transferred = num_samples_transferred + num_remaining_samples;
num_remaining_samples = 0;
}
}
free(buffer_DMA);
close(dma_descr);
}
// thread that sends the samples to the FPGA
void sending_thread(const gr::top_block_sptr &top_block, const char *file_name)
{
// file descriptor
FILE *rx_signal_file; // file descriptor
int file_length; // length of the file containing the received samples
rx_signal_file = fopen(file_name, "rb");
if (!rx_signal_file)
{
std::cerr << "Unable to open file!\n";
return;
}
fseek(rx_signal_file, 0, SEEK_END);
file_length = ftell(rx_signal_file);
fseek(rx_signal_file, 0, SEEK_SET);
usleep(FIVE_SECONDS); // wait for some time to give time to the other thread to program the device
// send_tracking_gps_input_samples(dma_descr, rx_signal_file, file_length);
send_tracking_gps_input_samples(rx_signal_file, file_length, top_block);
fclose(rx_signal_file);
}
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class GpsL1CADllPllTrackingTestFpga_msg_rx;
using GpsL1CADllPllTrackingTestFpga_msg_rx_sptr = gnss_shared_ptr<GpsL1CADllPllTrackingTestFpga_msg_rx>;
GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make();
class GpsL1CADllPllTrackingTestFpga_msg_rx : public gr::block
{
private:
friend GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make();
void msg_handler_channel_events(const pmt::pmt_t &msg);
GpsL1CADllPllTrackingTestFpga_msg_rx();
public:
int rx_message{0};
~GpsL1CADllPllTrackingTestFpga_msg_rx() override; //!< Default destructor
};
GpsL1CADllPllTrackingTestFpga_msg_rx_sptr GpsL1CADllPllTrackingTestFpga_msg_rx_make()
{
return GpsL1CADllPllTrackingTestFpga_msg_rx_sptr(
new GpsL1CADllPllTrackingTestFpga_msg_rx());
}
void GpsL1CADllPllTrackingTestFpga_msg_rx::msg_handler_channel_events(const pmt::pmt_t &msg)
{
try
{
int64_t message = pmt::to_long(msg);
rx_message = message;
}
catch (const wht::bad_any_cast &e)
{
LOG(WARNING) << "msg_handler_channel_events Bad any_cast: " << e.what();
rx_message = 0;
}
}
GpsL1CADllPllTrackingTestFpga_msg_rx::GpsL1CADllPllTrackingTestFpga_msg_rx()
: gr::block("GpsL1CADllPllTrackingTestFpga_msg_rx",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"),
#if HAS_GENERIC_LAMBDA
[this](auto &&PH1) { msg_handler_channel_events(PH1); });
#else
#if USE_BOOST_BIND_PLACEHOLDERS
boost::bind(&GpsL1CADllPllTrackingTestFpga_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
#else
boost::bind(&GpsL1CADllPllTrackingTestFpga_msg_rx::msg_handler_channel_events, this, _1));
#endif
#endif
}
GpsL1CADllPllTrackingTestFpga_msg_rx::~GpsL1CADllPllTrackingTestFpga_msg_rx() = default;
// ###########################################################
class GpsL1CADllPllTrackingTestFpga : public ::testing::Test
{
public:
std::string generator_binary;
std::string p1;
std::string p2;
std::string p3;
std::string p4;
std::string p5;
#if USE_GLOG_AND_GFLAGS
const int baseband_sampling_freq = FLAGS_fs_gen_sps;
std::string filename_rinex_obs = FLAGS_filename_rinex_obs;
std::string filename_raw_data = FLAGS_filename_raw_data;
#else
const int baseband_sampling_freq = absl::GetFlag(FLAGS_fs_gen_sps);
std::string filename_rinex_obs = absl::GetFlag(FLAGS_filename_rinex_obs);
std::string filename_raw_data = absl::GetFlag(FLAGS_filename_raw_data);
#endif
int configure_generator();
int generate_signal();
void check_results_doppler(arma::vec &true_time_s, arma::vec &true_value,
arma::vec &meas_time_s, arma::vec &meas_value);
void check_results_acc_carrier_phase(arma::vec &true_time_s,
arma::vec &true_value, arma::vec &meas_time_s, arma::vec &meas_value);
void check_results_codephase(arma::vec &true_time_s, arma::vec &true_value,
arma::vec &meas_time_s, arma::vec &meas_value);
GpsL1CADllPllTrackingTestFpga() : item_size(sizeof(gr_complex))
{
config = std::make_shared<InMemoryConfiguration>();
gnss_synchro = Gnss_Synchro();
}
~GpsL1CADllPllTrackingTestFpga() override = default;
void configure_receiver();
gr::top_block_sptr top_block;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
};
int GpsL1CADllPllTrackingTestFpga::configure_generator()
{
// Configure signal generator
#if USE_GLOG_AND_GFLAGS
generator_binary = FLAGS_generator_binary;
p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file;
if (FLAGS_dynamic_position.empty())
{
p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10);
}
else
{
p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position);
}
p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output
p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps]
#else
generator_binary = absl::GetFlag(FLAGS_generator_binary);
p1 = std::string("-rinex_nav_file=") + absl::GetFlag(FLAGS_rinex_nav_file);
if (absl::GetFlag(FLAGS_dynamic_position).empty())
{
p2 = std::string("-static_position=") + absl::GetFlag(FLAGS_static_position) + std::string(",") + std::to_string(absl::GetFlag(FLAGS_duration) * 10);
}
else
{
p2 = std::string("-obs_pos_file=") + std::string(absl::GetFlag(FLAGS_dynamic_position));
}
p3 = std::string("-rinex_obs_file=") + absl::GetFlag(FLAGS_filename_rinex_obs); // RINEX 2.10 observation file output
p4 = std::string("-sig_out_file=") + absl::GetFlag(FLAGS_filename_raw_data); // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps]
#endif
return 0;
}
int GpsL1CADllPllTrackingTestFpga::generate_signal()
{
int child_status;
char *const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0],
&p4[0], &p5[0], nullptr};
int pid;
if ((pid = fork()) == -1)
{
perror("fork err");
}
else if (pid == 0)
{
execv(&generator_binary[0], parmList);
std::cout << "Return not expected. Must be an execv err.\n";
std::terminate();
}
waitpid(pid, &child_status, 0);
std::cout << "Signal and Observables RINEX and RAW files created.\n";
return 0;
}
void GpsL1CADllPllTrackingTestFpga::configure_receiver()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'G';
std::string signal = "1C";
signal.copy(gnss_synchro.Signal, 2, 0);
#if USE_GLOG_AND_GFLAGS
gnss_synchro.PRN = FLAGS_test_satellite_PRN;
#else
gnss_synchro.PRN = absl::GetFlag(FLAGS_test_satellite_PRN);
#endif
config->set_property("GNSS-SDR.internal_fs_sps",
std::to_string(baseband_sampling_freq));
// Set Tracking
config->set_property("Tracking_1C.implementation",
"GPS_L1_CA_DLL_PLL_Tracking_FPGA");
config->set_property("Tracking_1C.item_type", "cshort");
config->set_property("Tracking_1C.dump", "true");
config->set_property("Tracking_1C.dump_filename", "./tracking_ch_");
config->set_property("Tracking_1C.pll_bw_hz", "30.0");
config->set_property("Tracking_1C.dll_bw_hz", "2.0");
config->set_property("Tracking_1C.early_late_space_chips", "0.5");
config->set_property("Tracking_1C.devicename", "/dev/uio");
config->set_property("Tracking_1C.device_base", "1");
}
void GpsL1CADllPllTrackingTestFpga::check_results_doppler(arma::vec &true_time_s,
arma::vec &true_value, arma::vec &meas_time_s, arma::vec &meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse
<< ", mean=" << error_mean << ", stdev=" << sqrt(error_var)
<< " (max,min)=" << max_error << "," << min_error << " [Hz]"
<< '\n';
std::cout.precision(ss);
}
void GpsL1CADllPllTrackingTestFpga::check_results_acc_carrier_phase(
arma::vec &true_time_s, arma::vec &true_value, arma::vec &meas_time_s,
arma::vec &meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK acc carrier phase RMSE=" << rmse
<< ", mean=" << error_mean << ", stdev=" << sqrt(error_var)
<< " (max,min)=" << max_error << "," << min_error << " [Hz]"
<< '\n';
std::cout.precision(ss);
}
void GpsL1CADllPllTrackingTestFpga::check_results_codephase(
arma::vec &true_time_s, arma::vec &true_value, arma::vec &meas_time_s,
arma::vec &meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK code phase RMSE=" << rmse
<< ", mean=" << error_mean << ", stdev=" << sqrt(error_var)
<< " (max,min)=" << max_error << "," << min_error << " [Chips]"
<< '\n';
std::cout.precision(ss);
}
TEST_F(GpsL1CADllPllTrackingTestFpga, ValidationOfResultsFpga)
{
configure_generator();
// DO not generate signal raw signal samples and observations RINEX file by default
// generate_signal();
std::chrono::time_point<std::chrono::system_clock> start;
std::chrono::time_point<std::chrono::system_clock> end;
std::chrono::duration<double> elapsed_seconds(0);
configure_receiver();
// open true observables log file written by the simulator
Tracking_True_Obs_Reader true_obs_data;
#if USE_GLOG_AND_GFLAGS
int test_satellite_PRN = FLAGS_test_satellite_PRN;
#else
int test_satellite_PRN = absl::GetFlag(FLAGS_test_satellite_PRN);
#endif
std::cout << "Testing satellite PRN=" << test_satellite_PRN << '\n';
std::string true_obs_file = std::string("./gps_l1_ca_obs_prn");
true_obs_file.append(std::to_string(test_satellite_PRN));
true_obs_file.append(".dat");
ASSERT_NO_THROW(
{
if (true_obs_data.open_obs_file(true_obs_file) == false)
{
throw std::exception();
};
})
<< "Failure opening true observables file";
top_block = gr::make_top_block("Tracking test");
// std::shared_ptr<GpsL1CaDllPllCAidTrackingFpga> tracking = std::make_shared<GpsL1CaDllPllCAidTrackingFpga> (config.get(), "Tracking_1C", 1, 1);
std::shared_ptr<GpsL1CaDllPllTrackingFpga> tracking = std::make_shared<GpsL1CaDllPllTrackingFpga>(config.get(), "Tracking_1C", 1, 1);
auto msg_rx = GpsL1CADllPllTrackingTestFpga_msg_rx_make();
// load acquisition data based on the first epoch of the true observations
ASSERT_NO_THROW(
{
if (true_obs_data.read_binary_obs() == false)
{
throw std::exception();
};
})
<< "Failure reading true observables file";
// restart the epoch counter
true_obs_data.restart();
std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz
<< " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips
<< '\n';
gnss_synchro.Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD_S;
gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW(
{
tracking->set_channel(gnss_synchro.Channel_ID);
})
<< "Failure setting channel.";
ASSERT_NO_THROW(
{
tracking->set_gnss_synchro(&gnss_synchro);
})
<< "Failure setting gnss_synchro.";
ASSERT_NO_THROW(
{
tracking->connect(top_block);
})
<< "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW(
{
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
})
<< "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
// assemble again the file name in a null terminated string (not available by default in the main program flow)
std::string file = "./" + filename_raw_data;
const char *file_name = file.c_str();
// start thread that sends the DMA samples to the FPGA
boost::thread t{sending_thread, top_block, file_name};
EXPECT_NO_THROW(
{
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
// tracking->reset(); // unlock the channel
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
})
<< "Failure running the top_block.";
// wait until child thread terminates
t.join();
// check results
// load the true values
int64_t nepoch = true_obs_data.num_epochs();
std::cout << "True observation epochs=" << nepoch << '\n';
arma::vec true_timestamp_s = arma::zeros(nepoch, 1);
arma::vec true_acc_carrier_phase_cycles = arma::zeros(nepoch, 1);
arma::vec true_Doppler_Hz = arma::zeros(nepoch, 1);
arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1);
arma::vec true_tow_s = arma::zeros(nepoch, 1);
int64_t epoch_counter = 0;
while (true_obs_data.read_binary_obs())
{
true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s;
true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles;
true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz;
true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips;
true_tow_s(epoch_counter) = true_obs_data.tow;
epoch_counter++;
}
// load the measured values
Tracking_Dump_Reader trk_dump;
ASSERT_NO_THROW(
{
if (trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")) == false)
{
throw std::exception();
};
})
<< "Failure opening tracking dump file";
nepoch = trk_dump.num_epochs();
std::cout << "Measured observation epochs=" << nepoch << '\n';
arma::vec trk_timestamp_s = arma::zeros(nepoch, 1);
arma::vec trk_acc_carrier_phase_cycles = arma::zeros(nepoch, 1);
arma::vec trk_Doppler_Hz = arma::zeros(nepoch, 1);
arma::vec trk_prn_delay_chips = arma::zeros(nepoch, 1);
epoch_counter = 0;
while (trk_dump.read_binary_obs())
{
trk_timestamp_s(epoch_counter) = static_cast<double>(trk_dump.PRN_start_sample_count) / static_cast<double>(baseband_sampling_freq);
trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / TWO_PI;
trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz;
double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast<double>(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast<double>(baseband_sampling_freq), 1.0e-3) / 1.0e-3);
trk_prn_delay_chips(epoch_counter) = delay_chips;
epoch_counter++;
}
// Align initial measurements and cut the tracking pull-in transitory
double pull_in_offset_s = 1.0;
arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first");
trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1);
trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1);
trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1);
trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1);
check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz);
check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips);
check_results_acc_carrier_phase(true_timestamp_s,
true_acc_carrier_phase_cycles, trk_timestamp_s,
trk_acc_carrier_phase_cycles);
std::cout << "Signal tracking completed in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,673 @@
/*!
* \file gps_l1_ca_gaussian_tracking_test.cc
* \brief This class implements a tracking test for GPS_L1_CA_Gaussian_Tracking
* implementation based on some input parameters.
* \author Carles Fernandez, 2018
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "GPS_L1_CA.h"
#include "gnss_block_factory.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_filesystem.h"
#include "gnss_sdr_flags.h"
#include "gnuplot_i.h"
#include "in_memory_configuration.h"
#include "signal_generator_flags.h"
#include "test_flags.h"
#include "tracking_dump_reader.h"
#include "tracking_interface.h"
#include "tracking_true_obs_reader.h"
#include <armadillo>
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/interleaved_char_to_complex.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <pmt/pmt.h>
#include <chrono>
#include <iomanip>
#include <unistd.h>
#include <utility>
#include <vector>
#if HAS_GENERIC_LAMBDA
#else
#include <boost/bind/bind.hpp>
#endif
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
#if PMT_USES_BOOST_ANY
namespace wht = boost;
#else
namespace wht = std;
#endif
#if USE_GLOG_AND_GFLAGS
DEFINE_bool(plot_gps_l1_gaussian_tracking_test, false, "Plots results of GpsL1CAGaussianTrackingTest with gnuplot");
#else
ABSL_FLAG(bool, plot_gps_l1_gaussian_tracking_test, false, "Plots results of GpsL1CAGaussianTrackingTest with gnuplot");
#endif
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class GpsL1CAGaussianTrackingTest_msg_rx;
using GpsL1CAGaussianTrackingTest_msg_rx_sptr = gnss_shared_ptr<GpsL1CAGaussianTrackingTest_msg_rx>;
GpsL1CAGaussianTrackingTest_msg_rx_sptr GpsL1CAGaussianTrackingTest_msg_rx_make();
class GpsL1CAGaussianTrackingTest_msg_rx : public gr::block
{
private:
friend GpsL1CAGaussianTrackingTest_msg_rx_sptr GpsL1CAGaussianTrackingTest_msg_rx_make();
void msg_handler_channel_events(const pmt::pmt_t msg);
GpsL1CAGaussianTrackingTest_msg_rx();
public:
int rx_message;
~GpsL1CAGaussianTrackingTest_msg_rx(); //!< Default destructor
};
GpsL1CAGaussianTrackingTest_msg_rx_sptr GpsL1CAGaussianTrackingTest_msg_rx_make()
{
return GpsL1CAGaussianTrackingTest_msg_rx_sptr(new GpsL1CAGaussianTrackingTest_msg_rx());
}
void GpsL1CAGaussianTrackingTest_msg_rx::msg_handler_channel_events(const pmt::pmt_t msg)
{
try
{
long int message = pmt::to_long(std::move(msg));
rx_message = message;
}
catch (const wht::bad_any_cast& e)
{
LOG(WARNING) << "msg_handler_channel_events Bad any_cast: " << e.what();
rx_message = 0;
}
}
GpsL1CAGaussianTrackingTest_msg_rx::GpsL1CAGaussianTrackingTest_msg_rx() : gr::block("GpsL1CAGaussianTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"),
#if HAS_GENERIC_LAMBDA
[this](auto&& PH1) { msg_handler_channel_events(PH1); });
#else
#if USE_BOOST_BIND_PLACEHOLDERS
boost::bind(&GpsL1CAGaussianTrackingTest_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
#else
boost::bind(&GpsL1CAGaussianTrackingTest_msg_rx::msg_handler_channel_events, this, _1));
#endif
#endif
rx_message = 0;
}
GpsL1CAGaussianTrackingTest_msg_rx::~GpsL1CAGaussianTrackingTest_msg_rx() = default;
// ###########################################################
class GpsL1CAGaussianTrackingTest : public ::testing::Test
{
public:
std::string generator_binary;
std::string p1;
std::string p2;
std::string p3;
std::string p4;
std::string p5;
std::string implementation = "GPS_L1_CA_Gaussian_Tracking";
#if USE_GLOG_AND_GFLAGS
const int baseband_sampling_freq = FLAGS_fs_gen_sps;
std::string filename_rinex_obs = FLAGS_filename_rinex_obs;
std::string filename_raw_data = FLAGS_filename_raw_data;
#else
const int baseband_sampling_freq = absl::GetFlag(FLAGS_fs_gen_sps);
std::string filename_rinex_obs = absl::GetFlag(FLAGS_filename_rinex_obs);
std::string filename_raw_data = absl::GetFlag(FLAGS_filename_raw_data);
#endif
int configure_generator();
int generate_signal();
void check_results_doppler(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value);
void check_results_acc_carrier_phase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value);
void check_results_codephase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value);
GpsL1CAGaussianTrackingTest()
{
factory = std::make_shared<GNSSBlockFactory>();
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
gnss_synchro = Gnss_Synchro();
}
~GpsL1CAGaussianTrackingTest() = default;
void configure_receiver();
gr::top_block_sptr top_block;
std::shared_ptr<GNSSBlockFactory> factory;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
};
int GpsL1CAGaussianTrackingTest::configure_generator()
{
#if USE_GLOG_AND_GFLAGS
// Configure signal generator
generator_binary = FLAGS_generator_binary;
p1 = std::string("-rinex_nav_file=") + FLAGS_rinex_nav_file;
if (FLAGS_dynamic_position.empty())
{
p2 = std::string("-static_position=") + FLAGS_static_position + std::string(",") + std::to_string(FLAGS_duration * 10);
}
else
{
p2 = std::string("-obs_pos_file=") + std::string(FLAGS_dynamic_position);
}
p3 = std::string("-rinex_obs_file=") + FLAGS_filename_rinex_obs; // RINEX 2.10 observation file output
p4 = std::string("-sig_out_file=") + FLAGS_filename_raw_data; // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps]
#else
// Configure signal generator
generator_binary = absl::GetFlag(FLAGS_generator_binary);
p1 = std::string("-rinex_nav_file=") + absl::GetFlag(FLAGS_rinex_nav_file);
if (absl::GetFlag(FLAGS_dynamic_position).empty())
{
p2 = std::string("-static_position=") + absl::GetFlag(FLAGS_static_position) + std::string(",") + std::to_string(absl::GetFlag(FLAGS_duration) * 10);
}
else
{
p2 = std::string("-obs_pos_file=") + std::string(absl::GetFlag(FLAGS_dynamic_position));
}
p3 = std::string("-rinex_obs_file=") + absl::GetFlag(FLAGS_filename_rinex_obs); // RINEX 2.10 observation file output
p4 = std::string("-sig_out_file=") + absl::GetFlag(FLAGS_filename_raw_data); // Baseband signal output file. Will be stored in int8_t IQ multiplexed samples
p5 = std::string("-sampling_freq=") + std::to_string(baseband_sampling_freq); // Baseband sampling frequency [MSps]
#endif
return 0;
}
int GpsL1CAGaussianTrackingTest::generate_signal()
{
int child_status;
char* const parmList[] = {&generator_binary[0], &generator_binary[0], &p1[0], &p2[0], &p3[0], &p4[0], &p5[0], nullptr};
int pid;
if ((pid = fork()) == -1)
{
perror("fork err");
}
else if (pid == 0)
{
execv(&generator_binary[0], parmList);
std::cout << "Return not expected. Must be an execv err.\n";
std::terminate();
}
waitpid(pid, &child_status, 0);
std::cout << "Signal and Observables RINEX and RAW files created.\n";
return 0;
}
void GpsL1CAGaussianTrackingTest::configure_receiver()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'G';
std::string signal = "1C";
signal.copy(gnss_synchro.Signal, 2, 0);
#if USE_GLOG_AND_GFLAGS
gnss_synchro.PRN = FLAGS_test_satellite_PRN;
#else
gnss_synchro.PRN = absl::GetFlag(FLAGS_test_satellite_PRN);
#endif
config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq));
// Set Tracking
config->set_property("Tracking_1C.implementation", implementation);
config->set_property("Tracking_1C.item_type", "gr_complex");
#if USE_GLOG_AND_GFLAGS
if (FLAGS_dll_bw_hz != 0.0)
{
config->set_property("Tracking_1C.dll_bw_hz", std::to_string(FLAGS_dll_bw_hz));
}
#else
if (absl::GetFlag(FLAGS_dll_bw_hz) != 0.0)
{
config->set_property("Tracking_1C.dll_bw_hz", std::to_string(absl::GetFlag(FLAGS_dll_bw_hz)));
}
#endif
else
{
config->set_property("Tracking_1C.dll_bw_hz", "2.0");
}
config->set_property("Tracking_1C.early_late_space_chips", "0.5");
config->set_property("Tracking_1C.extend_correlation_ms", "1");
config->set_property("Tracking_1C.dump", "true");
config->set_property("Tracking_1C.dump_filename", "./tracking_ch_");
}
void GpsL1CAGaussianTrackingTest::check_results_doppler(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK Doppler RMSE=" << rmse
<< ", mean=" << error_mean
<< ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]\n";
std::cout.precision(ss);
}
void GpsL1CAGaussianTrackingTest::check_results_acc_carrier_phase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK acc carrier phase RMSE=" << rmse
<< ", mean=" << error_mean
<< ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Hz]\n";
std::cout.precision(ss);
}
void GpsL1CAGaussianTrackingTest::check_results_codephase(arma::vec& true_time_s,
arma::vec& true_value,
arma::vec& meas_time_s,
arma::vec& meas_value)
{
// 1. True value interpolation to match the measurement times
arma::vec true_value_interp;
arma::uvec true_time_s_valid = find(true_time_s > 0);
true_time_s = true_time_s(true_time_s_valid);
true_value = true_value(true_time_s_valid);
arma::uvec meas_time_s_valid = find(meas_time_s > 0);
meas_time_s = meas_time_s(meas_time_s_valid);
meas_value = meas_value(meas_time_s_valid);
arma::interp1(true_time_s, true_value, meas_time_s, true_value_interp);
// 2. RMSE
arma::vec err;
err = meas_value - true_value_interp;
arma::vec err2 = arma::square(err);
double rmse = sqrt(arma::mean(err2));
// 3. Mean err and variance
double error_mean = arma::mean(err);
double error_var = arma::var(err);
// 4. Peaks
double max_error = arma::max(err);
double min_error = arma::min(err);
// 5. report
std::streamsize ss = std::cout.precision();
std::cout << std::setprecision(10) << "TRK code phase RMSE=" << rmse
<< ", mean=" << error_mean
<< ", stdev=" << sqrt(error_var) << " (max,min)=" << max_error << "," << min_error << " [Chips]\n";
std::cout.precision(ss);
}
TEST_F(GpsL1CAGaussianTrackingTest, ValidationOfResults)
{
// Configure the signal generator
configure_generator();
// Generate signal raw signal samples and observations RINEX file
#if USE_GLOG_AND_GFLAGS
if (FLAGS_disable_generator == false)
{
generate_signal();
}
#else
if (absl::GetFlag(FLAGS_disable_generator) == false)
{
generate_signal();
}
#endif
std::chrono::time_point<std::chrono::system_clock> start, end;
configure_receiver();
// open true observables log file written by the simulator
Tracking_True_Obs_Reader true_obs_data;
#if USE_GLOG_AND_GFLAGS
int test_satellite_PRN = FLAGS_test_satellite_PRN;
#else
int test_satellite_PRN = absl::GetFlag(FLAGS_test_satellite_PRN);
#endif
std::cout << "Testing satellite PRN=" << test_satellite_PRN << '\n';
std::string true_obs_file = std::string("./gps_l1_ca_obs_prn");
true_obs_file.append(std::to_string(test_satellite_PRN));
true_obs_file.append(".dat");
ASSERT_EQ(true_obs_data.open_obs_file(true_obs_file), true) << "Failure opening true observables file";
top_block = gr::make_top_block("Tracking test");
std::shared_ptr<GNSSBlockInterface> trk_ = factory->GetBlock(config.get(), "Tracking_1C", 1, 1);
std::shared_ptr<TrackingInterface> tracking = std::dynamic_pointer_cast<TrackingInterface>(trk_); // std::make_shared<GpsL1CaDllPllCAidTracking>(config.get(), "Tracking_1C", 1, 1);
auto msg_rx = GpsL1CAGaussianTrackingTest_msg_rx_make();
// load acquisition data based on the first epoch of the true observations
ASSERT_EQ(true_obs_data.read_binary_obs(), true)
<< "Failure reading true tracking dump file.\n"
#if USE_GLOG_AND_GFLAGS
<< "Maybe sat PRN #" + std::to_string(FLAGS_test_satellite_PRN) +
#else
<< "Maybe sat PRN #" + std::to_string(absl::GetFlag(FLAGS_test_satellite_PRN)) +
#endif
" is not available?";
// restart the epoch counter
true_obs_data.restart();
std::cout << "Initial Doppler [Hz]=" << true_obs_data.doppler_l1_hz << " Initial code delay [Chips]=" << true_obs_data.prn_delay_chips << '\n';
gnss_synchro.Acq_delay_samples = (GPS_L1_CA_CODE_LENGTH_CHIPS - true_obs_data.prn_delay_chips / GPS_L1_CA_CODE_LENGTH_CHIPS) * baseband_sampling_freq * GPS_L1_CA_CODE_PERIOD_S;
gnss_synchro.Acq_doppler_hz = true_obs_data.doppler_l1_hz;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
std::string file = "./" + filename_raw_data;
const char* file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(int8_t), file_name, false);
gr::blocks::interleaved_char_to_complex::sptr gr_interleaved_char_to_complex = gr::blocks::interleaved_char_to_complex::make();
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, gr_interleaved_char_to_complex, 0);
top_block->connect(gr_interleaved_char_to_complex, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
}) << "Failure running the top_block.";
// check results
// load the true values
long int nepoch = true_obs_data.num_epochs();
std::cout << "True observation epochs=" << nepoch << '\n';
arma::vec true_timestamp_s = arma::zeros(nepoch, 1);
arma::vec true_acc_carrier_phase_cycles = arma::zeros(nepoch, 1);
arma::vec true_Doppler_Hz = arma::zeros(nepoch, 1);
arma::vec true_prn_delay_chips = arma::zeros(nepoch, 1);
arma::vec true_tow_s = arma::zeros(nepoch, 1);
long int epoch_counter = 0;
while (true_obs_data.read_binary_obs())
{
true_timestamp_s(epoch_counter) = true_obs_data.signal_timestamp_s;
true_acc_carrier_phase_cycles(epoch_counter) = true_obs_data.acc_carrier_phase_cycles;
true_Doppler_Hz(epoch_counter) = true_obs_data.doppler_l1_hz;
true_prn_delay_chips(epoch_counter) = true_obs_data.prn_delay_chips;
true_tow_s(epoch_counter) = true_obs_data.tow;
epoch_counter++;
}
// load the measured values
Tracking_Dump_Reader trk_dump;
ASSERT_EQ(trk_dump.open_obs_file(std::string("./tracking_ch_0.dat")), true)
<< "Failure opening tracking dump file";
nepoch = trk_dump.num_epochs();
std::cout << "Measured observation epochs=" << nepoch << '\n';
// trk_dump.restart();
arma::vec trk_timestamp_s = arma::zeros(nepoch, 1);
arma::vec trk_acc_carrier_phase_cycles = arma::zeros(nepoch, 1);
arma::vec trk_Doppler_Hz = arma::zeros(nepoch, 1);
arma::vec trk_prn_delay_chips = arma::zeros(nepoch, 1);
std::vector<double> prompt;
std::vector<double> early;
std::vector<double> late;
std::vector<double> promptI;
std::vector<double> promptQ;
epoch_counter = 0;
while (trk_dump.read_binary_obs())
{
trk_timestamp_s(epoch_counter) = static_cast<double>(trk_dump.PRN_start_sample_count) / static_cast<double>(baseband_sampling_freq);
trk_acc_carrier_phase_cycles(epoch_counter) = trk_dump.acc_carrier_phase_rad / TWO_PI;
trk_Doppler_Hz(epoch_counter) = trk_dump.carrier_doppler_hz;
double delay_chips = GPS_L1_CA_CODE_LENGTH_CHIPS - GPS_L1_CA_CODE_LENGTH_CHIPS * (fmod((static_cast<double>(trk_dump.PRN_start_sample_count) + trk_dump.aux1) / static_cast<double>(baseband_sampling_freq), 1.0e-3) / 1.0e-3);
trk_prn_delay_chips(epoch_counter) = delay_chips;
epoch_counter++;
prompt.push_back(trk_dump.abs_P);
early.push_back(trk_dump.abs_E);
late.push_back(trk_dump.abs_L);
promptI.push_back(trk_dump.prompt_I);
promptQ.push_back(trk_dump.prompt_Q);
}
// Align initial measurements and cut the tracking pull-in transitory
double pull_in_offset_s = 1.0;
arma::uvec initial_meas_point = arma::find(trk_timestamp_s >= (true_timestamp_s(0) + pull_in_offset_s), 1, "first");
trk_timestamp_s = trk_timestamp_s.subvec(initial_meas_point(0), trk_timestamp_s.size() - 1);
trk_acc_carrier_phase_cycles = trk_acc_carrier_phase_cycles.subvec(initial_meas_point(0), trk_acc_carrier_phase_cycles.size() - 1);
trk_Doppler_Hz = trk_Doppler_Hz.subvec(initial_meas_point(0), trk_Doppler_Hz.size() - 1);
trk_prn_delay_chips = trk_prn_delay_chips.subvec(initial_meas_point(0), trk_prn_delay_chips.size() - 1);
check_results_doppler(true_timestamp_s, true_Doppler_Hz, trk_timestamp_s, trk_Doppler_Hz);
check_results_codephase(true_timestamp_s, true_prn_delay_chips, trk_timestamp_s, trk_prn_delay_chips);
check_results_acc_carrier_phase(true_timestamp_s, true_acc_carrier_phase_cycles, trk_timestamp_s, trk_acc_carrier_phase_cycles);
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "Signal tracking completed in " << elapsed_seconds.count() << " seconds.\n";
#if USE_GLOG_AND_GFLAGS
if (FLAGS_plot_gps_l1_gaussian_tracking_test == true)
{
const std::string gnuplot_executable(FLAGS_gnuplot_executable);
#else
if (absl::GetFlag(FLAGS_plot_gps_l1_gaussian_tracking_test) == true)
{
const std::string gnuplot_executable(absl::GetFlag(FLAGS_gnuplot_executable));
#endif
if (gnuplot_executable.empty())
{
std::cout << "WARNING: Although the flag plot_gps_l1_tracking_test has been set to TRUE,\n";
std::cout << "gnuplot has not been found in your system.\n";
std::cout << "Test results will not be plotted.\n";
}
else
{
try
{
fs::path p(gnuplot_executable);
fs::path dir = p.parent_path();
const std::string& gnuplot_path = dir.native();
Gnuplot::set_GNUPlotPath(gnuplot_path);
std::vector<double> timevec;
double t = 0.0;
for (auto it = prompt.begin(); it != prompt.end(); it++)
{
timevec.push_back(t);
t = t + GPS_L1_CA_CODE_PERIOD_S;
}
Gnuplot g1("linespoints");
#if USE_GLOG_AND_GFLAGS
g1.set_title("GPS L1 C/A signal tracking correlators' output (satellite PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
#else
g1.set_title("GPS L1 C/A signal tracking correlators' output (satellite PRN #" + std::to_string(absl::GetFlag(FLAGS_test_satellite_PRN)) + ")");
#endif
g1.set_grid();
g1.set_xlabel("Time [s]");
g1.set_ylabel("Correlators' output");
g1.cmd("set key box opaque");
#if USE_GLOG_AND_GFLAGS
auto decimate = static_cast<unsigned int>(FLAGS_plot_decimate);
#else
auto decimate = static_cast<unsigned int>(absl::GetFlag(FLAGS_plot_decimate));
#endif
g1.plot_xy(timevec, prompt, "Prompt", decimate);
g1.plot_xy(timevec, early, "Early", decimate);
g1.plot_xy(timevec, late, "Late", decimate);
g1.savetops("Correlators_outputs");
g1.savetopdf("Correlators_outputs", 18);
#if USE_GLOG_AND_GFLAGS
if (FLAGS_show_plots)
#else
if (absl::GetFlag(FLAGS_show_plots))
#endif
{
g1.showonscreen(); // window output
}
else
{
g1.disablescreen();
}
Gnuplot g2("points");
#if USE_GLOG_AND_GFLAGS
g2.set_title("Constellation diagram (satellite PRN #" + std::to_string(FLAGS_test_satellite_PRN) + ")");
#else
g2.set_title("Constellation diagram (satellite PRN #" + std::to_string(absl::GetFlag(FLAGS_test_satellite_PRN)) + ")");
#endif
g2.set_grid();
g2.set_xlabel("Inphase");
g2.set_ylabel("Quadrature");
g2.cmd("set size ratio -1");
g2.plot_xy(promptI, promptQ);
g2.savetops("Constellation");
g2.savetopdf("Constellation", 18);
#if USE_GLOG_AND_GFLAGS
if (FLAGS_show_plots)
#else
if (absl::GetFlag(FLAGS_show_plots))
#endif
{
g2.showonscreen(); // window output
}
else
{
g2.disablescreen();
}
}
catch (const GnuplotException& ge)
{
std::cout << ge.what() << '\n';
}
}
}
}

View File

@@ -0,0 +1,210 @@
/*!
* \file gps_l2_m_dll_pll_tracking_test.cc
* \brief This class implements a tracking test for Galileo_E5a_DLL_PLL_Tracking
* implementation based on some input parameters.
* \author Javier Arribas, 2015. jarribas(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2012-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "concurrent_queue.h"
#include "gnss_block_interface.h"
#include "gnss_sdr_valve.h"
#include "gnss_synchro.h"
#include "gps_l2_m_dll_pll_tracking.h"
#include "in_memory_configuration.h"
#include "tracking_interface.h"
#include <gnuradio/analog/sig_source_waveform.h>
#include <gnuradio/blocks/file_source.h>
#include <gnuradio/blocks/null_sink.h>
#include <gnuradio/blocks/skiphead.h>
#include <gnuradio/top_block.h>
#include <gtest/gtest.h>
#include <pmt/pmt.h>
#include <chrono>
#include <utility>
#if HAS_GENERIC_LAMBDA
#else
#include <boost/bind/bind.hpp>
#endif
#ifdef GR_GREATER_38
#include <gnuradio/analog/sig_source.h>
#else
#include <gnuradio/analog/sig_source_c.h>
#endif
#if PMT_USES_BOOST_ANY
namespace wht = boost;
#else
namespace wht = std;
#endif
// ######## GNURADIO BLOCK MESSAGE RECEVER #########
class GpsL2MDllPllTrackingTest_msg_rx;
using GpsL2MDllPllTrackingTest_msg_rx_sptr = gnss_shared_ptr<GpsL2MDllPllTrackingTest_msg_rx>;
GpsL2MDllPllTrackingTest_msg_rx_sptr GpsL2MDllPllTrackingTest_msg_rx_make();
class GpsL2MDllPllTrackingTest_msg_rx : public gr::block
{
private:
friend GpsL2MDllPllTrackingTest_msg_rx_sptr GpsL2MDllPllTrackingTest_msg_rx_make();
void msg_handler_channel_events(const pmt::pmt_t msg);
GpsL2MDllPllTrackingTest_msg_rx();
public:
int rx_message;
~GpsL2MDllPllTrackingTest_msg_rx(); //!< Default destructor
};
GpsL2MDllPllTrackingTest_msg_rx_sptr GpsL2MDllPllTrackingTest_msg_rx_make()
{
return GpsL2MDllPllTrackingTest_msg_rx_sptr(new GpsL2MDllPllTrackingTest_msg_rx());
}
void GpsL2MDllPllTrackingTest_msg_rx::msg_handler_channel_events(const pmt::pmt_t msg)
{
try
{
int64_t message = pmt::to_long(std::move(msg));
rx_message = message;
}
catch (const wht::bad_any_cast& e)
{
LOG(WARNING) << "msg_handler_channel_events Bad any_cast: " << e.what();
rx_message = 0;
}
}
GpsL2MDllPllTrackingTest_msg_rx::GpsL2MDllPllTrackingTest_msg_rx() : gr::block("GpsL2MDllPllTrackingTest_msg_rx", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0))
{
this->message_port_register_in(pmt::mp("events"));
this->set_msg_handler(pmt::mp("events"),
#if HAS_GENERIC_LAMBDA
[this](auto&& PH1) { msg_handler_channel_events(PH1); });
#else
#if USE_BOOST_BIND_PLACEHOLDERS
boost::bind(&GpsL2MDllPllTrackingTest_msg_rx::msg_handler_channel_events, this, boost::placeholders::_1));
#else
boost::bind(&GpsL2MDllPllTrackingTest_msg_rx::msg_handler_channel_events, this, _1));
#endif
#endif
rx_message = 0;
}
GpsL2MDllPllTrackingTest_msg_rx::~GpsL2MDllPllTrackingTest_msg_rx() = default;
// ###########################################################
class GpsL2MDllPllTrackingTest : public ::testing::Test
{
protected:
GpsL2MDllPllTrackingTest()
{
config = std::make_shared<InMemoryConfiguration>();
item_size = sizeof(gr_complex);
gnss_synchro = Gnss_Synchro();
}
~GpsL2MDllPllTrackingTest() = default;
void init();
std::shared_ptr<Concurrent_Queue<pmt::pmt_t>> queue;
gr::top_block_sptr top_block;
std::shared_ptr<InMemoryConfiguration> config;
Gnss_Synchro gnss_synchro;
size_t item_size;
};
void GpsL2MDllPllTrackingTest::init()
{
gnss_synchro.Channel_ID = 0;
gnss_synchro.System = 'G';
std::string signal = "2S";
signal.copy(gnss_synchro.Signal, 2, 0);
gnss_synchro.PRN = 7;
config->set_property("GNSS-SDR.internal_fs_sps", "5000000");
config->set_property("Tracking_2S.item_type", "gr_complex");
config->set_property("Tracking_2S.dump", "false");
config->set_property("Tracking_2S.dump_filename", "../data/L2m_tracking_ch_");
config->set_property("Tracking_2S.implementation", "GPS_L2_M_DLL_PLL_Tracking");
config->set_property("Tracking_2S.early_late_space_chips", "0.5");
config->set_property("Tracking_2S.order", "2");
config->set_property("Tracking_2S.pll_bw_hz", "2");
config->set_property("Tracking_2S.dll_bw_hz", "0.5");
}
TEST_F(GpsL2MDllPllTrackingTest, ValidationOfResults)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0.0);
int fs_in = 5000000;
int nsamples = fs_in * 9;
init();
queue = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
top_block = gr::make_top_block("Tracking test");
std::shared_ptr<TrackingInterface> tracking = std::make_shared<GpsL2MDllPllTracking>(config.get(), "Tracking_2S", 1, 1);
auto msg_rx = GpsL2MDllPllTrackingTest_msg_rx_make();
gnss_synchro.Acq_delay_samples = 1;
gnss_synchro.Acq_doppler_hz = 1200;
gnss_synchro.Acq_samplestamp_samples = 0;
ASSERT_NO_THROW({
tracking->set_channel(gnss_synchro.Channel_ID);
}) << "Failure setting channel.";
ASSERT_NO_THROW({
tracking->set_gnss_synchro(&gnss_synchro);
}) << "Failure setting gnss_synchro.";
ASSERT_NO_THROW({
tracking->connect(top_block);
}) << "Failure connecting tracking to the top_block.";
ASSERT_NO_THROW({
// gr::analog::sig_source_c::sptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000, 1, gr_complex(0));
std::string path = std::string(TEST_PATH);
std::string file = path + "signal_samples/gps_l2c_m_prn7_5msps.dat";
const char* file_name = file.c_str();
gr::blocks::file_source::sptr file_source = gr::blocks::file_source::make(sizeof(gr_complex), file_name, false);
auto valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue.get());
gr::blocks::null_sink::sptr sink = gr::blocks::null_sink::make(sizeof(Gnss_Synchro));
top_block->connect(file_source, 0, valve, 0);
top_block->connect(valve, 0, tracking->get_left_block(), 0);
top_block->connect(tracking->get_right_block(), 0, sink, 0);
top_block->msg_connect(tracking->get_right_block(), pmt::mp("events"), msg_rx, pmt::mp("events"));
}) << "Failure connecting the blocks of tracking test.";
tracking->start_tracking();
EXPECT_NO_THROW({
start = std::chrono::system_clock::now();
top_block->run(); // Start threads and wait
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
}) << "Failure running the top_block.";
// TODO: Verify tracking results
std::cout << "Tracked " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds\n";
}

View File

@@ -0,0 +1,167 @@
/*!
* \file fft_length_test.cc
* \brief This file implements timing tests for the FFT.
* \author Carles Fernandez-Prades, 2016. cfernandez(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "GPS_L1_CA.h"
#include "cuda_multicorrelator.h"
#include "gps_sdr_signal_replica.h"
#include <chrono>
#include <complex>
#include <cstdint>
#include <cuda.h>
#include <cuda_profiler_api.h>
#include <cuda_runtime.h>
#include <thread>
#if USE_GLOG_AND_GFLAGS
DEFINE_int32(gpu_multicorrelator_iterations_test, 1000, "Number of averaged iterations in GPU multicorrelator test timing test");
DEFINE_int32(gpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in GPU multicorrelator test timing test");
#else
ABSL_FLAG(int32_t, gpu_multicorrelator_iterations_test, 1000, "Number of averaged iterations in GPU multicorrelator test timing test");
ABSL_FLAG(int32_t, gpu_multicorrelator_max_threads_test, 12, "Number of maximum concurrent correlators in GPU multicorrelator test timing test");
#endif
void run_correlator_gpu(cuda_multicorrelator* correlator,
float d_rem_carrier_phase_rad,
float d_carrier_phase_step_rad,
float d_code_phase_step_chips,
float d_rem_code_phase_chips,
int correlation_size,
int d_n_correlator_taps)
{
#if USE_GLOG_AND_GFLAGS
for (int k = 0; k < FLAGS_cpu_multicorrelator_iterations_test; k++)
#else
for (int k = 0; k < absl::GetFlag(FLAGS_cpu_multicorrelator_iterations_test); k++)
#endif
{
correlator->Carrier_wipeoff_multicorrelator_resampler_cuda(d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
correlation_size,
d_n_correlator_taps);
}
}
TEST(GpuMulticorrelatorTest, MeasureExecutionTime)
{
std::chrono::time_point<std::chrono::system_clock> start, end;
std::chrono::duration<double> elapsed_seconds(0);
#if USE_GLOG_AND_GFLAGS
int max_threads = FLAGS_gpu_multicorrelator_max_threads_test;
#else
int max_threads = absl::GetFlag(FLAGS_gpu_multicorrelator_max_threads_test);
#endif
std::vector<std::thread> thread_pool;
cuda_multicorrelator* correlator_pool[max_threads];
unsigned int correlation_sizes[3] = {2048, 4096, 8192};
double execution_times[3];
gr_complex* d_ca_code;
gr_complex* in_gpu;
gr_complex* d_correlator_outs;
int d_n_correlator_taps = 3;
int d_vector_length = correlation_sizes[2]; // max correlation size to allocate all the necessary memory
float* d_local_code_shift_chips;
// Set GPU flags
cudaSetDeviceFlags(cudaDeviceMapHost);
// allocate host memory
// pinned memory mode - use special function to get OS-pinned memory
d_n_correlator_taps = 3; // Early, Prompt, and Late
// Get space for a vector with the C/A code replica sampled 1x/chip
cudaHostAlloc(reinterpret_cast<void**>(&d_ca_code), (static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS) * sizeof(gr_complex)), cudaHostAllocMapped | cudaHostAllocWriteCombined);
// Get space for the resampled early / prompt / late local replicas
cudaHostAlloc(reinterpret_cast<void**>(&d_local_code_shift_chips), d_n_correlator_taps * sizeof(float), cudaHostAllocMapped | cudaHostAllocWriteCombined);
cudaHostAlloc(reinterpret_cast<void**>(&in_gpu), 2 * d_vector_length * sizeof(gr_complex), cudaHostAllocMapped | cudaHostAllocWriteCombined);
// correlator outputs (scalar)
cudaHostAlloc(reinterpret_cast<void**>(&d_correlator_outs), sizeof(gr_complex) * d_n_correlator_taps, cudaHostAllocMapped | cudaHostAllocWriteCombined);
// --- Perform initializations ------------------------------
// local code resampler on GPU
// generate local reference (1 sample per chip)
gps_l1_ca_code_gen_complex(own::span<gr_complex>(d_ca_code, static_cast<int>(GPS_L1_CA_CODE_LENGTH_CHIPS)), 1, 0);
// generate inut signal
for (int n = 0; n < 2 * d_vector_length; n++)
{
in_gpu[n] = std::complex<float>(static_cast<float>(rand()) / static_cast<float>(RAND_MAX), static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
}
// Set TAPs delay values [chips]
float d_early_late_spc_chips = 0.5;
d_local_code_shift_chips[0] = -d_early_late_spc_chips;
d_local_code_shift_chips[1] = 0.0;
d_local_code_shift_chips[2] = d_early_late_spc_chips;
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n] = new cuda_multicorrelator();
correlator_pool[n]->init_cuda_integrated_resampler(d_vector_length, GPS_L1_CA_CODE_LENGTH_CHIPS, d_n_correlator_taps);
correlator_pool[n]->set_input_output_vectors(d_correlator_outs, in_gpu);
}
float d_rem_carrier_phase_rad = 0.0;
float d_carrier_phase_step_rad = 0.1;
float d_code_phase_step_chips = 0.3;
float d_rem_code_phase_chips = 0.4;
EXPECT_NO_THROW(
for (int correlation_sizes_idx = 0; correlation_sizes_idx < 3; correlation_sizes_idx++) {
for (int current_max_threads = 1; current_max_threads < (max_threads + 1); current_max_threads++)
{
std::cout << "Running " << current_max_threads << " concurrent correlators\n";
start = std::chrono::system_clock::now();
// create the concurrent correlator threads
for (int current_thread = 0; current_thread < current_max_threads; current_thread++)
{
// cudaProfilerStart();
thread_pool.push_back(std::thread(run_correlator_gpu,
correlator_pool[current_thread],
d_rem_carrier_phase_rad,
d_carrier_phase_step_rad,
d_code_phase_step_chips,
d_rem_code_phase_chips,
correlation_sizes[correlation_sizes_idx],
d_n_correlator_taps));
// cudaProfilerStop();
}
// wait the threads to finish they work and destroy the thread objects
for (auto& t : thread_pool)
{
t.join();
}
thread_pool.clear();
end = std::chrono::system_clock::now();
elapsed_seconds = end - start;
#if USE_GLOG_AND_GFLAGS
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(FLAGS_gpu_multicorrelator_iterations_test);
#else
execution_times[correlation_sizes_idx] = elapsed_seconds.count() / static_cast<double>(absl::GetFlag(FLAGS_gpu_multicorrelator_iterations_test));
#endif
std::cout << "GPU Multicorrelator execution time for length=" << correlation_sizes[correlation_sizes_idx] << " : " << execution_times[correlation_sizes_idx] << " [s]\n";
}
});
cudaFreeHost(in_gpu);
cudaFreeHost(d_correlator_outs);
cudaFreeHost(d_local_code_shift_chips);
cudaFreeHost(d_ca_code);
for (int n = 0; n < max_threads; n++)
{
correlator_pool[n]->free_cuda();
}
}

View File

@@ -0,0 +1,206 @@
/*!
* \file tracking_loop_filter_test.cc
* \brief This file implements tests for the general loop filter
* \author Cillian O'Driscoll, 2015. cillian.odriscoll(at)gmail.com
*
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "tracking_loop_filter.h"
#include <gtest/gtest.h>
#include <cstddef>
TEST(TrackingLoopFilterTest, FirstOrderLoop)
{
int loop_order = 1;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = false;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
theFilter.initialize(0.0);
float g1 = noise_bandwidth * 4.0;
float result = 0.0;
for (float i : sample_data)
{
result = theFilter.apply(i);
EXPECT_FLOAT_EQ(result, i * g1);
}
}
TEST(TrackingLoopFilterTest, FirstOrderLoopWithLastIntegrator)
{
int loop_order = 1;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = true;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
std::vector<float> expected_out = {0.0, 0.0, 0.01, 0.02, 0.02, 0.02};
theFilter.initialize(0.0);
float result = 0.0;
for (size_t i = 0; i < sample_data.size(); ++i)
{
result = theFilter.apply(sample_data[i]);
EXPECT_NEAR(result, expected_out[i], 1e-4);
}
}
TEST(TrackingLoopFilterTest, SecondOrderLoop)
{
int loop_order = 2;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = false;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
std::vector<float> expected_out = {0.0, 0.0, 13.37778, 0.0889, 0.0889, 0.0889};
theFilter.initialize(0.0);
float result = 0.0;
for (size_t i = 0; i < sample_data.size(); ++i)
{
result = theFilter.apply(sample_data[i]);
EXPECT_NEAR(result, expected_out[i], 1e-4);
}
}
TEST(TrackingLoopFilterTest, SecondOrderLoopWithLastIntegrator)
{
int loop_order = 2;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = true;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
std::vector<float> expected_out = {0.0, 0.0, 0.006689, 0.013422, 0.013511, 0.013600};
theFilter.initialize(0.0);
float result = 0.0;
for (size_t i = 0; i < sample_data.size(); ++i)
{
result = theFilter.apply(sample_data[i]);
EXPECT_NEAR(result, expected_out[i], 1e-4);
}
}
TEST(TrackingLoopFilterTest, ThirdOrderLoop)
{
int loop_order = 3;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = false;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
std::vector<float> expected_out = {0.0, 0.0, 15.31877, 0.04494, 0.04520, 0.04546};
theFilter.initialize(0.0);
float result = 0.0;
for (size_t i = 0; i < sample_data.size(); ++i)
{
result = theFilter.apply(sample_data[i]);
EXPECT_NEAR(result, expected_out[i], 1e-4);
}
}
TEST(TrackingLoopFilterTest, ThirdOrderLoopWithLastIntegrator)
{
int loop_order = 3;
float noise_bandwidth = 5.0;
float update_interval = 0.001;
bool include_last_integrator = true;
Tracking_loop_filter theFilter(update_interval,
noise_bandwidth,
loop_order,
include_last_integrator);
EXPECT_EQ(theFilter.get_noise_bandwidth(), noise_bandwidth);
EXPECT_EQ(theFilter.get_update_interval(), update_interval);
EXPECT_EQ(theFilter.get_include_last_integrator(), include_last_integrator);
EXPECT_EQ(theFilter.get_order(), loop_order);
std::vector<float> sample_data = {0.0, 0.0, 1.0, 0.0, 0.0, 0.0};
std::vector<float> expected_out = {0.0, 0.0, 0.007659, 0.015341, 0.015386, 0.015432};
theFilter.initialize(0.0);
float result = 0.0;
for (size_t i = 0; i < sample_data.size(); ++i)
{
result = theFilter.apply(sample_data[i]);
EXPECT_NEAR(result, expected_out[i], 1e-4);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
/*!
* \file unscented_filter_test.cc
* \brief This file implements numerical accuracy test for the CKF library.
* \author Gerald LaMountain, 2019. gerald(at)ece.neu.edu
*
* -----------------------------------------------------------------------------
*
* GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
* This file is part of GNSS-SDR.
*
* Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "nonlinear_tracking.h"
#include <armadillo>
#include <gtest/gtest.h>
#include <random>
#define UNSCENTED_TEST_N_TRIALS 10
#define UNSCENTED_TEST_TOLERANCE 10
class TransitionModelUKF : public ModelFunction
{
public:
explicit TransitionModelUKF(const arma::mat& kf_F) { coeff_mat = kf_F; };
arma::vec operator()(const arma::vec& input) override { return coeff_mat * input; };
private:
arma::mat coeff_mat;
};
class MeasurementModelUKF : public ModelFunction
{
public:
explicit MeasurementModelUKF(const arma::mat& kf_H) { coeff_mat = kf_H; };
arma::vec operator()(const arma::vec& input) override { return coeff_mat * input; };
private:
arma::mat coeff_mat;
};
TEST(UnscentedFilterComputationTest, UnscentedFilterTest)
{
UnscentedFilter kf_unscented;
arma::vec kf_x;
arma::mat kf_P_x;
arma::vec kf_x_pre;
arma::mat kf_P_x_pre;
arma::vec ukf_x_pre;
arma::mat ukf_P_x_pre;
arma::vec kf_x_post;
arma::mat kf_P_x_post;
arma::vec ukf_x_post;
arma::mat ukf_P_x_post;
arma::mat kf_F;
arma::mat kf_H;
arma::mat kf_Q;
arma::mat kf_R;
arma::vec eta;
arma::vec nu;
arma::vec kf_y;
arma::mat kf_P_y;
arma::mat kf_K;
ModelFunction* transition_function;
ModelFunction* measurement_function;
// -- Perform initializations ------------------------------
std::random_device r;
std::default_random_engine e1(r());
std::normal_distribution<float> normal_dist(0, 5);
std::uniform_real_distribution<float> uniform_dist(0.1, 5.0);
std::uniform_int_distribution<> uniform_dist_int(1, 5);
uint8_t nx = 0;
uint8_t ny = 0;
for (uint16_t k = 0; k < UNSCENTED_TEST_N_TRIALS; k++)
{
nx = static_cast<uint8_t>(uniform_dist_int(e1));
ny = static_cast<uint8_t>(uniform_dist_int(e1));
kf_x = arma::randn<arma::vec>(nx, 1);
kf_P_x_post = 5.0 * arma::diagmat(arma::randu<arma::vec>(nx, 1));
kf_x_post = arma::mvnrnd(kf_x, kf_P_x_post);
kf_unscented.initialize(kf_x_post, kf_P_x_post);
// Prediction Step
kf_F = arma::randu<arma::mat>(nx, nx);
kf_Q = arma::diagmat(arma::randu<arma::vec>(nx, 1));
transition_function = new TransitionModelUKF(kf_F);
arma::mat ttx = (*transition_function)(kf_x_post);
kf_unscented.predict_sequential(kf_x_post, kf_P_x_post, transition_function, kf_Q);
ukf_x_pre = kf_unscented.get_x_pred();
ukf_P_x_pre = kf_unscented.get_P_x_pred();
kf_x_pre = kf_F * kf_x_post;
kf_P_x_pre = kf_F * kf_P_x_post * kf_F.t() + kf_Q;
EXPECT_TRUE(arma::approx_equal(ukf_x_pre, kf_x_pre, "absdiff", UNSCENTED_TEST_TOLERANCE));
EXPECT_TRUE(arma::approx_equal(ukf_P_x_pre, kf_P_x_pre, "absdiff", UNSCENTED_TEST_TOLERANCE));
// Update Step
kf_H = arma::randu<arma::mat>(ny, nx);
kf_R = arma::diagmat(arma::randu<arma::vec>(ny, 1));
eta = arma::mvnrnd(arma::zeros<arma::vec>(nx, 1), kf_Q);
nu = arma::mvnrnd(arma::zeros<arma::vec>(ny, 1), kf_R);
kf_y = kf_H * (kf_F * kf_x + eta) + nu;
measurement_function = new MeasurementModelUKF(kf_H);
kf_unscented.update_sequential(kf_y, kf_x_pre, kf_P_x_pre, measurement_function, kf_R);
ukf_x_post = kf_unscented.get_x_est();
ukf_P_x_post = kf_unscented.get_P_x_est();
kf_P_y = kf_H * kf_P_x_pre * kf_H.t() + kf_R;
kf_K = (kf_P_x_pre * kf_H.t()) * arma::inv(kf_P_y);
kf_x_post = kf_x_pre + kf_K * (kf_y - kf_H * kf_x_pre);
kf_P_x_post = (arma::eye(nx, nx) - kf_K * kf_H) * kf_P_x_pre;
EXPECT_TRUE(arma::approx_equal(ukf_x_post, kf_x_post, "absdiff", UNSCENTED_TEST_TOLERANCE));
EXPECT_TRUE(arma::approx_equal(ukf_P_x_post, kf_P_x_post, "absdiff", UNSCENTED_TEST_TOLERANCE));
delete transition_function;
delete measurement_function;
}
}