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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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";
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user