diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc index 80d60991d..6a5ecc81a 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.cc @@ -38,7 +38,6 @@ #include #include #include -#include using google::LogMessage; @@ -60,7 +59,6 @@ Notch::Notch(float pfa, float p_c_factor, int length_, int n_segments_est, int n noise_pow_est = 0.0; this->p_c_factor = gr_complex(p_c_factor , 0); this->length_ = length_; //Set the number of samples per segment - set_output_multiple(length_); filter_state_ = false; //Initial state of the filter n_deg_fred = 2 * length_; //Number of dregrees of freedom n_segments = 0; @@ -73,6 +71,7 @@ Notch::Notch(float pfa, float p_c_factor, int length_, int n_segments_est, int n angle_ = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); power_spect = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); last_out = gr_complex(0,0); + d_fft = std::unique_ptr(new gr::fft::fft_complex(length_, true)); } @@ -83,6 +82,13 @@ Notch::~Notch() volk_free(power_spect); } +void Notch::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for(unsigned int aux = 0; aux < ninput_items_required.size(); aux++) + { + ninput_items_required[aux] = length_; + } +} int Notch::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) @@ -93,17 +99,14 @@ int Notch::general_work(int noutput_items, gr_vector_int &ninput_items __attribu lv_32fc_t dot_prod_; const gr_complex* in = reinterpret_cast(input_items[0]); gr_complex* out = reinterpret_cast(output_items[0]); - in++; - arma::cx_fvec signal_segment; - arma::cx_fvec signal_segment_fft; while((index_out + length_) < noutput_items) { if((n_segments < n_segments_est) && (filter_state_ == false)) { - signal_segment = arma::cx_fvec(in, length_); - signal_segment_fft = arma::fft(signal_segment); - volk_32fc_s32f_power_spectrum_32f(power_spect, signal_segment_fft.memptr(), 1.0, length_); + memcpy(d_fft->get_inbuf(), in, sizeof(gr_complex) * length_); + d_fft->execute(); + volk_32fc_s32f_power_spectrum_32f(power_spect, d_fft->get_outbuf(), 1.0, length_); volk_32f_s32f_calc_spectral_noise_floor_32f(&sig2dB, power_spect, 15.0, length_); sig2lin = std::pow(10.0, (sig2dB / 10.0)) / (static_cast(n_deg_fred) ); noise_pow_est = (static_cast(n_segments) * noise_pow_est + sig2lin) / (static_cast(n_segments + 1)); diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h index 5be7dfda6..127acc9d1 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_cc.h @@ -33,6 +33,8 @@ #include #include +#include +#include class Notch; @@ -64,6 +66,7 @@ private: gr_complex* c_samples; float* angle_; float* power_spect; + std::unique_ptr d_fft; public: @@ -71,6 +74,8 @@ public: ~Notch(); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc index 591e3f2e2..de224cdcd 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.cc @@ -38,7 +38,6 @@ #include #include #include -#include using google::LogMessage; @@ -47,7 +46,6 @@ notch_lite_sptr make_notch_filter_lite(float p_c_factor, float pfa, int length_, return notch_lite_sptr(new NotchLite(p_c_factor, pfa, length_, n_segments_est, n_segments_reset, n_segments_coeff)); } - NotchLite::NotchLite(float p_c_factor, float pfa, int length_, int n_segments_est, int n_segments_reset, int n_segments_coeff) : gr::block("NotchLite", gr::io_signature::make (1, 1, sizeof(gr_complex)), gr::io_signature::make (1, 1, sizeof(gr_complex))) @@ -76,15 +74,21 @@ NotchLite::NotchLite(float p_c_factor, float pfa, int length_, int n_segments_es angle1 = 0.0; angle2 = 0.0; power_spect = static_cast(volk_malloc(length_ * sizeof(float), volk_get_alignment())); - + d_fft = std::unique_ptr(new gr::fft::fft_complex(length_, true)); } - NotchLite::~NotchLite() { volk_free(power_spect); } +void NotchLite::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for(unsigned int aux = 0; aux < ninput_items_required.size(); aux++) + { + ninput_items_required[aux] = length_; + } +} int NotchLite::general_work(int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) @@ -95,17 +99,14 @@ int NotchLite::general_work(int noutput_items, gr_vector_int &ninput_items __att lv_32fc_t dot_prod_; const gr_complex* in = reinterpret_cast(input_items[0]); gr_complex* out = reinterpret_cast(output_items[0]); - in++; - arma::cx_fvec signal_segment; - arma::cx_fvec signal_segment_fft; while((index_out + length_) < noutput_items) { if((n_segments < n_segments_est) && (filter_state_ == false)) { - signal_segment = arma::cx_fvec(in, length_); - signal_segment_fft = arma::fft(signal_segment); - volk_32fc_s32f_power_spectrum_32f(power_spect, signal_segment_fft.memptr(), 1.0, length_); + memcpy(d_fft->get_inbuf(), in, sizeof(gr_complex) * length_); + d_fft->execute(); + volk_32fc_s32f_power_spectrum_32f(power_spect, d_fft->get_outbuf(), 1.0, length_); volk_32f_s32f_calc_spectral_noise_floor_32f(&sig2dB, power_spect, 15.0, length_); sig2lin = std::pow(10.0, (sig2dB / 10.0)) / static_cast(n_deg_fred); noise_pow_est = (static_cast(n_segments) * noise_pow_est + sig2lin) / static_cast(n_segments + 1); diff --git a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h index 2151a459f..cfe9df491 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h +++ b/src/algorithms/input_filter/gnuradio_blocks/notch_lite_cc.h @@ -33,6 +33,8 @@ #include #include +#include +#include class NotchLite; @@ -67,6 +69,7 @@ private: float angle1; float angle2; float* power_spect; + std::unique_ptr d_fft; public: @@ -74,6 +77,8 @@ public: ~NotchLite(); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); diff --git a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc index 8b75bbc38..c0a6249b0 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc +++ b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.cc @@ -53,7 +53,6 @@ pulse_blanking_cc::pulse_blanking_cc(float pfa, int length_, int n_segments_est, set_alignment(std::max(1, alignment_multiple)); this->pfa = pfa; this->length_ = length_; - set_output_multiple(length_); last_filtered = false; n_segments = 0; this->n_segments_est = n_segments_est; @@ -75,8 +74,15 @@ pulse_blanking_cc::~pulse_blanking_cc() volk_free(zeros_); } +void pulse_blanking_cc::forecast(int noutput_items __attribute__((unused)), gr_vector_int &ninput_items_required) +{ + for(unsigned int aux=0; aux < ninput_items_required.size(); aux++) + { + ninput_items_required[aux] = length_; + } +} -int pulse_blanking_cc::general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), +int pulse_blanking_cc::general_work (int noutput_items, gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const gr_complex* in = reinterpret_cast(input_items[0]); diff --git a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h index 7a19bf74e..b149bc72e 100644 --- a/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h +++ b/src/algorithms/input_filter/gnuradio_blocks/pulse_blanking_cc.h @@ -65,6 +65,8 @@ public: int general_work (int noutput_items __attribute__((unused)), gr_vector_int &ninput_items __attribute__((unused)), gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + }; #endif diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 4403d3616..f37753413 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -563,6 +563,9 @@ if(NOT ${ENABLE_PACKAGING}) add_executable(gnss_block_test ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/sources/file_signal_source_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/fir_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/adapter/pass_through_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/adapter/adapter_test.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/control-plane/gnss_block_factory_test.cc diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 36662fb67..b84fa312a 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -69,6 +69,7 @@ DECLARE_string(log_dir); #include "unit-tests/arithmetic/multiply_test.cc" #include "unit-tests/arithmetic/code_generation_test.cc" #include "unit-tests/arithmetic/fft_length_test.cc" +#include "unit-tests/arithmetic/fft_speed_test.cc" #include "unit-tests/control-plane/file_configuration_test.cc" #include "unit-tests/control-plane/in_memory_configuration_test.cc" @@ -86,6 +87,9 @@ DECLARE_string(log_dir); #include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc" #include "unit-tests/signal-processing-blocks/filter/fir_filter_test.cc" +#include "unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc" +#include "unit-tests/signal-processing-blocks/filter/notch_filter_test.cc" +#include "unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc" #include "unit-tests/signal-processing-blocks/resampler/direct_resampler_conditioner_cc_test.cc" diff --git a/src/tests/unit-tests/arithmetic/fft_speed_test.cc b/src/tests/unit-tests/arithmetic/fft_speed_test.cc new file mode 100644 index 000000000..fa1fd2826 --- /dev/null +++ b/src/tests/unit-tests/arithmetic/fft_speed_test.cc @@ -0,0 +1,81 @@ +/*! + * \file fft_speed_test.cc + * \brief This file implements timing tests for the Armadillo + * and GNU Radio FFT implementations + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +DEFINE_int32(fft_speed_iterations_test, 100, "Number of averaged iterations in FFT length timing test"); + +TEST(FFTSpeedTest, ArmadilloVSGNURadioExecutionTime) +{ + unsigned int d_fft_size; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds; + + unsigned int fft_sizes [19] = { 16, 25, 32, 45, 64, 95, 128, 195, 256, 325, 512, 785, 1024, 1503, 2048, 3127, 4096, 6349, 8192 }; + double d_execution_time; + EXPECT_NO_THROW( + for(int i = 0; i < 19; i++) + { + d_fft_size = fft_sizes[i]; + gr::fft::fft_complex* d_gr_fft; + d_gr_fft = new gr::fft::fft_complex(d_fft_size, true); + arma::arma_rng::set_seed_random(); + arma::cx_fvec d_arma_fft = arma::cx_fvec(d_fft_size).randn() + gr_complex(0.0, 1.0) * arma::cx_fvec(d_fft_size).randn(); + arma::cx_fvec d_arma_fft_result(d_fft_size); + memcpy(d_gr_fft->get_inbuf(), d_arma_fft.memptr(), sizeof(gr_complex) * d_fft_size); + + start = std::chrono::system_clock::now(); + for(int k = 0; k < FLAGS_fft_speed_iterations_test; k++) + { + d_gr_fft->execute(); + } + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + d_execution_time = elapsed_seconds.count() / static_cast(FLAGS_fft_speed_iterations_test); + std::cout << "GNU Radio FFT execution time for length = " << d_fft_size << " : " << d_execution_time * 1e6 << " [us]" << std::endl; + delete d_gr_fft; + + start = std::chrono::system_clock::now(); + for(int k = 0; k < FLAGS_fft_speed_iterations_test; k++) + { + d_arma_fft_result = arma::fft(d_arma_fft); + } + end = std::chrono::system_clock::now(); + elapsed_seconds = end - start; + d_execution_time = elapsed_seconds.count() / static_cast(FLAGS_fft_speed_iterations_test); + std::cout << "Armadillo FFT execution time for length = " << d_fft_size << " : " << d_execution_time * 1e6 << " [us]" << std::endl; + } + ); +} diff --git a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc index 3f6aee435..e2fcd9880 100644 --- a/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc +++ b/src/tests/unit-tests/control-plane/gnss_block_factory_test.cc @@ -155,6 +155,45 @@ TEST(GNSSBlockFactoryTest, InstantiateFreqXlatingFIRFilter) EXPECT_STREQ("Freq_Xlating_Fir_Filter", input_filter->implementation().c_str()); } +TEST(GNSSBlockFactoryTest, InstantiatePulseBlankingFilter) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Pulse_Blanking_Filter"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Pulse_Blanking_Filter", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Pulse_Blanking_Filter", input_filter->implementation().c_str()); +} + +TEST(GNSSBlockFactoryTest, InstantiateNotchFilter) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Notch_Filter"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Notch_Filter", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Notch_Filter", input_filter->implementation().c_str()); +} + +TEST(GNSSBlockFactoryTest, InstantiateNotchFilterLite) +{ + std::shared_ptr configuration = std::make_shared(); + gr::msg_queue::sptr queue = gr::msg_queue::make(0); + configuration->set_property("InputFilter.implementation", "Notch_Filter_Lite"); + + std::unique_ptr factory; + std::unique_ptr input_filter = factory->GetBlock(configuration, "InputFilter", "Notch_Filter_Lite", 1, 1); + + EXPECT_STREQ("InputFilter", input_filter->role().c_str()); + EXPECT_STREQ("Notch_Filter_Lite", input_filter->implementation().c_str()); +} + TEST(GNSSBlockFactoryTest, InstantiateDirectResampler) { std::shared_ptr configuration = std::make_shared(); diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc new file mode 100644 index 000000000..363ff89ce --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_lite_test.cc @@ -0,0 +1,169 @@ +/*! + * \file notch_filter_lite_test.cc + * \brief Implements Unit Test for the NotchFilterLite class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "in_memory_configuration.h" +#include "gnss_sdr_valve.h" +#include "notch_filter_lite.h" +#include "file_signal_source.h" + + +DEFINE_int32(notch_filter_lite_test_nsamples, 1000000 , "Number of samples to filter in the tests (max: 2147483647)"); + +class NotchFilterLiteTest: public ::testing::Test +{ +protected: + NotchFilterLiteTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_notch_filter_lite_test_nsamples; + } + ~NotchFilterLiteTest() + {} + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void NotchFilterLiteTest::init() +{ + config->set_property("InputFilter.pfa", "0.01"); + config->set_property("InputFilter.p_c_factor", "0.9"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void NotchFilterLiteTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(NotchFilterLiteTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new NotchFilterLite(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(NotchFilterLiteTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter lite test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(NotchFilterLiteTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter lite test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc new file mode 100644 index 000000000..f3997ecc2 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/notch_filter_test.cc @@ -0,0 +1,169 @@ +/*! + * \file notch_filter_test.cc + * \brief Implements Unit Test for the NotchFilter class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "in_memory_configuration.h" +#include "gnss_sdr_valve.h" +#include "notch_filter.h" +#include "file_signal_source.h" + + +DEFINE_int32(notch_filter_test_nsamples, 1000000 , "Number of samples to filter in the tests (max: 2147483647)"); + +class NotchFilterTest: public ::testing::Test +{ +protected: + NotchFilterTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_notch_filter_test_nsamples; + } + ~NotchFilterTest() + {} + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void NotchFilterTest::init() +{ + config->set_property("InputFilter.pfa", "0.01"); + config->set_property("InputFilter.p_c_factor", "0.9"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void NotchFilterTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(NotchFilterTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new NotchFilter(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(NotchFilterTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(NotchFilterTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Notch filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} diff --git a/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc new file mode 100644 index 000000000..f157bf3a6 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/filter/pulse_blanking_filter_test.cc @@ -0,0 +1,168 @@ +/*! + * \file pulse_blanking_filter_test.cc + * \brief Implements Unit Test for the PulseBlankingFilter class. + * \author Antonio Ramos, 2017. antonio.ramos(at)cttc.es + * + * ------------------------------------------------------------------------- + * + * Copyright (C) 2010-2017 (see AUTHORS file for a list of contributors) + * + * GNSS-SDR is a software defined Global Navigation + * Satellite Systems receiver + * + * This file is part of GNSS-SDR. + * + * GNSS-SDR is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GNSS-SDR is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNSS-SDR. If not, see . + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gnss_block_factory.h" +#include "gnss_block_interface.h" +#include "in_memory_configuration.h" +#include "gnss_sdr_valve.h" +#include "pulse_blanking_filter.h" +#include "file_signal_source.h" + + +DEFINE_int32(pb_filter_test_nsamples, 1000000 , "Number of samples to filter in the tests (max: 2147483647)"); + +class PulseBlankingFilterTest: public ::testing::Test +{ +protected: + PulseBlankingFilterTest() + { + queue = gr::msg_queue::make(0); + item_size = sizeof(gr_complex); + config = std::make_shared(); + nsamples = FLAGS_pb_filter_test_nsamples; + } + ~PulseBlankingFilterTest() + {} + + void init(); + void configure_gr_complex_gr_complex(); + boost::shared_ptr queue; + gr::top_block_sptr top_block; + std::shared_ptr config; + size_t item_size; + int nsamples; +}; + + +void PulseBlankingFilterTest::init() +{ + config->set_property("InputFilter.pfa", "0.04"); + config->set_property("InputFilter.length", "32"); + config->set_property("InputFilter.segments_est", "12500"); + config->set_property("InputFilter.segments_reset", "5000000"); +} + +void PulseBlankingFilterTest::configure_gr_complex_gr_complex() +{ + config->set_property("InputFilter.input_item_type", "gr_complex"); + config->set_property("InputFilter.output_item_type", "gr_complex"); +} + +TEST_F(PulseBlankingFilterTest, InstantiateGrComplexGrComplex) +{ + init(); + configure_gr_complex_gr_complex(); + std::unique_ptr filter(new PulseBlankingFilter(config.get(), "InputFilter", 1, 1)); + int res = 0; + if (filter) res = 1; + ASSERT_EQ(1, res); +} + +TEST_F(PulseBlankingFilterTest, ConnectAndRun) +{ + int fs_in = 4000000; + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Pulse Blanking filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + boost::shared_ptr source = gr::analog::sig_source_c::make(fs_in, gr::analog::GR_SIN_WAVE, 1000.0, 1.0, gr_complex(0.0)); + boost::shared_ptr valve = gnss_sdr_make_valve(sizeof(gr_complex), nsamples, queue); + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source, 0, valve, 0); + top_block->connect(valve, 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +} + + +TEST_F(PulseBlankingFilterTest, ConnectAndRunGrcomplex) +{ + std::chrono::time_point start, end; + std::chrono::duration elapsed_seconds(0); + top_block = gr::make_top_block("Pulse Blanking filter test"); + init(); + configure_gr_complex_gr_complex(); + std::shared_ptr filter = std::make_shared(config.get(), "InputFilter", 1, 1); + std::shared_ptr config2 = std::make_shared(); + + config2->set_property("Test_Source.samples", std::to_string(nsamples)); + config2->set_property("Test_Source.sampling_frequency", "4000000"); + std::string path = std::string(TEST_PATH); + std::string filename = path + "signal_samples/GPS_L1_CA_ID_1_Fs_4Msps_2ms.dat"; + config2->set_property("Test_Source.filename", filename); + config2->set_property("Test_Source.item_type", "gr_complex"); + config2->set_property("Test_Source.repeat", "true"); + + item_size = sizeof(gr_complex); + ASSERT_NO_THROW( { + filter->connect(top_block); + + boost::shared_ptr source(new FileSignalSource(config2.get(), "Test_Source", 1, 1, queue)); + source->connect(top_block); + + boost::shared_ptr null_sink = gr::blocks::null_sink::make(item_size); + + top_block->connect(source->get_right_block(), 0, filter->get_left_block(), 0); + top_block->connect(filter->get_right_block(), 0, null_sink, 0); + }) << "Failure connecting the top_block."<< std::endl; + + 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::endl; + std::cout << "Filtered " << nsamples << " gr_complex samples in " << elapsed_seconds.count() * 1e6 << " microseconds" << std::endl; +}