Skip to content
Snippets Groups Projects
Unverified Commit 94761ee4 authored by Tobias Winchen's avatar Tobias Winchen Committed by GitHub
Browse files

Merge pull request #22 from MPIfR-BDG/sk_tests

Spectral Kurtosis Feature
parents bf1daac9 0aef88f5
Branches
Tags
No related merge requests found
Showing
with 1367 additions and 1 deletion
......@@ -16,6 +16,8 @@ set(psrdada_cpp_effelsberg_edd_src
src/EDDRoach.cpp
src/EDDRoach_merge.cpp
src/ScaledTransposeTFtoTFT.cu
src/SKRfiReplacementCuda.cu
src/SpectralKurtosisCuda.cu
src/Tools.cu
src/Unpacker.cu
src/VLBI.cu
......
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENTCUDA_CUH
#define PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENTCUDA_CUH
#include "psrdada_cpp/common.hpp"
#include <thrust/device_vector.h>
#include <thrust/complex.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
class SKRfiReplacementCuda{
public:
/**
* @brief constructor
*/
SKRfiReplacementCuda();
/**
* @brief destructor
*/
~SKRfiReplacementCuda();
/**
* @brief Replaces RFI data with data generated using statistics of data from chosen number of clean_windows.
*
* @param(in) rfi_status rfi_status of input data stream
* @param(in & out) data Data on which RFI has to be replaced. Returns the same but with RFI replaced.
* @param(in) clean_windows number of clean windows used for computing data statistics.
*/
void replace_rfi_data(const thrust::device_vector<int> &rfi_status,
thrust::device_vector<thrust::complex<float>> &data,
std::size_t clean_windows = 5, cudaStream_t stream=0);
private:
thrust::device_vector<int> _rfi_window_indices;
thrust::device_vector<int> _clean_window_indices;
thrust::device_vector<thrust::complex <float>> _clean_data;
};
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENTCUDA_CUH
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDA_CUH
#define PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDA_CUH
#include "psrdada_cpp/common.hpp"
#include <thrust/device_vector.h>
#include <thrust/complex.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
#define BLOCK_DIM 1024
struct RFIStatistics{
thrust::device_vector<int> rfi_status;
float rfi_fraction;
};
class SpectralKurtosisCuda{
public:
/**
* @brief constructor
*
* @param(in) nchannels number of channels.
* @param(in) window_size number of samples per window.
* @param(in) sk_min minimum value of spectral kurtosis.
* @param(in) sk_max maximum value of spectral kurtosis.
*/
SpectralKurtosisCuda(std::size_t nchannels, std::size_t window_size, float sk_min = 0.8,
float sk_max = 1.2);
~SpectralKurtosisCuda();
/**
* @brief computes spectral kurtosis for the given data using thrust calls and returns its rfi statistics.
* This is used to compare and verify the results generated by compute_sk - an optimized kernel implementation.
*
* @param(in) data input data
* @param(out) stats RFI statistics
*
*/
void compute_sk_thrust(thrust::device_vector<thrust::complex<float>> const& data, RFIStatistics &stats, cudaStream_t _stream = 0);
/**
* @brief computes spectral kurtosis (using optimized kernel function) for the given data and returns its rfi statistics.
*
* @param(in) data input data
* @param(out) stats RFI statistics
*
*/
void compute_sk(thrust::device_vector<thrust::complex<float>> &data, RFIStatistics &stats, cudaStream_t _stream = 0);
private:
/**
* @brief initializes the data members of the class.
*
* */
void init();
std::size_t _nchannels; //number of channels
std::size_t _window_size; //window size
std::size_t _nwindows; //number of windows
std::size_t _sample_size; //size of input data
float _sk_min, _sk_max;
thrust::device_vector<float> _d_s1, _d_s2;
};
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDA_CUH
#include "psrdada_cpp/effelsberg/edd/SKRfiReplacementCuda.cuh"
#include <thrust/reduce.h>
#include <thrust/transform.h>
#include <thrust/copy.h>
#include <thrust/random/normal_distribution.h>
#include <thrust/random/linear_congruential_engine.h>
#include <nvToolsExt.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
struct mean_subtraction_square{
const float mean;
mean_subtraction_square(float _mean) :mean(_mean) {}
__host__ __device__
float operator() (thrust::complex<float> val) const{
float x = val.real() - mean;
return (x * x);
}
};
struct generate_replacement_data{
float normal_dist_mean, normal_dist_std;
generate_replacement_data(float mean, float std)
: normal_dist_mean(mean),
normal_dist_std(std)
{};
__host__ __device__
thrust::complex<float> operator() (unsigned int n) const{
thrust::minstd_rand gen;
thrust::random::normal_distribution<float> dist(normal_dist_mean, normal_dist_std);
gen.discard(n);
return thrust::complex<float> (dist(gen), dist(gen));
}
};
SKRfiReplacementCuda::SKRfiReplacementCuda() {
BOOST_LOG_TRIVIAL(debug) << "Creating new SKRfiReplacementCuda instance..\n";
}
SKRfiReplacementCuda::~SKRfiReplacementCuda() {
BOOST_LOG_TRIVIAL(debug) << "Destroying SKRfiReplacementCuda instance..\n";
}
void SKRfiReplacementCuda::replace_rfi_data(const thrust::device_vector<int> &rfi_status,
thrust::device_vector<thrust::complex<float>> &data,
std::size_t clean_windows, cudaStream_t stream) {
nvtxRangePushA("replace_rfi_data");
thrust::cuda::par.on(stream);
thrust::device_vector<thrust::complex<float>> replacement_data;
//initialize data members of the class
BOOST_LOG_TRIVIAL(debug) << "getting RFI window indices..\n";
_rfi_window_indices.resize(thrust::count(rfi_status.begin(), rfi_status.end(), 1));
thrust::copy_if(thrust::make_counting_iterator<int>(0),
thrust::make_counting_iterator<int>(rfi_status.size()),
rfi_status.begin(),
_rfi_window_indices.begin(),
thrust::placeholders::_1 == 1);
BOOST_LOG_TRIVIAL(debug) << "getting clean window indices..\n";
size_t _nclean_windows = thrust::count(rfi_status.begin(), rfi_status.end(), 0);
_clean_window_indices.resize(_nclean_windows);
thrust::copy_if(thrust::make_counting_iterator<int>(0),
thrust::make_counting_iterator<int>(rfi_status.size()),
rfi_status.begin(),
_clean_window_indices.begin(),
thrust::placeholders::_1 == 0);
if(_nclean_windows < rfi_status.size()){
//RFI present and not in all windows
if (_nclean_windows < clean_windows) {
clean_windows = _nclean_windows;
}
BOOST_LOG_TRIVIAL(debug) << "collecting clean data from chosen number of clean windows..\n";
std::size_t _window_size = data.size() / rfi_status.size();
_clean_data.resize(clean_windows * _window_size);
for(std::size_t ii = 0; ii < clean_windows; ii++){
std::size_t window_index = _clean_window_indices[ii];
std::size_t ibegin = window_index * _window_size;
std::size_t iend = ibegin + _window_size - 1;
std::size_t jj = ii * _window_size;
thrust::copy((data.begin() + ibegin), (data.begin() + iend), (_clean_data.begin() + jj));
BOOST_LOG_TRIVIAL(debug) <<"clean_win_index = " << window_index
<< " ibegin = " << ibegin << " iend = " << iend;
}
BOOST_LOG_TRIVIAL(debug) << "computing statistics of clean data..\n";
//The distribution of both real and imag are expected to ahve same mean and standard deviation.
//Therefore computing _ref_mean, _ref_sd for real distribution only.
std::size_t length = _clean_data.size();
float _ref_mean = (thrust::reduce(_clean_data.begin(), _clean_data.end(), thrust::complex<float> (0.0f, 0.0f))). real() / length;
float _ref_sd = std::sqrt(thrust::transform_reduce(_clean_data.begin(), _clean_data.end(), mean_subtraction_square(_ref_mean),
0.0f, thrust::plus<float> ()) / length);
BOOST_LOG_TRIVIAL(debug) << "DataStatistics mean = " << _ref_mean
<< " sd = " << _ref_sd;
//Replacing RFI
thrust::counting_iterator<unsigned int> sequence_index_begin(0);
nvtxRangePushA("replace_rfi_datai_loop");
for(std::size_t ii = 0; ii < _rfi_window_indices.size(); ii++){
std::size_t index = _rfi_window_indices[ii] * _window_size;
thrust::transform(sequence_index_begin, (sequence_index_begin + _window_size),
(data.begin() + index), generate_replacement_data(_ref_mean, _ref_sd));
}
nvtxRangePop();
}
nvtxRangePop();
}
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/SpectralKurtosisCuda.cuh"
#include <thrust/transform.h>
#include <thrust/iterator/discard_iterator.h>
#include <nvToolsExt.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
struct compute_power{
__host__ __device__
float operator()(thrust::complex<float> z)
{
return (thrust::abs(z) * thrust::abs(z));
}
};
struct power_square{
__host__ __device__
float operator()(thrust::complex<float> z)
{
float abs = thrust::abs(z);
float power = abs * abs;
return (power * power);
}
};
struct check_rfi{
const std::size_t M; //_window_size
const float sk_min;
const float sk_max;
check_rfi(std::size_t m, float min, float max)
: M(m),
sk_min(min),
sk_max(max)
{}
__host__ __device__
float operator() (float s1, float s2) const {
float sk = ((M + 1) / (M - 1)) * (((M * s2) / (s1 * s1)) - 1);
return ((sk < sk_min) || (sk > sk_max)) ;
}
};
__device__ int rfi_count = 0;
__device__ void warpReduce(volatile float *shmem_ptr1, volatile float *shmem_ptr2, int tid){
shmem_ptr1[tid] += shmem_ptr1[tid + 32];
shmem_ptr2[tid] += shmem_ptr2[tid + 32];
shmem_ptr1[tid] += shmem_ptr1[tid + 16];
shmem_ptr2[tid] += shmem_ptr2[tid + 16];
shmem_ptr1[tid] += shmem_ptr1[tid + 8];
shmem_ptr2[tid] += shmem_ptr2[tid + 8];
shmem_ptr1[tid] += shmem_ptr1[tid + 4];
shmem_ptr2[tid] += shmem_ptr2[tid + 4];
shmem_ptr1[tid] += shmem_ptr1[tid + 2];
shmem_ptr2[tid] += shmem_ptr2[tid + 2];
shmem_ptr1[tid] += shmem_ptr1[tid + 1];
shmem_ptr2[tid] += shmem_ptr2[tid + 1];
}
__global__ void compute_sk_kernel(const thrust::complex<float>* __restrict__ data, std::size_t sample_size, std::size_t window_size,
float sk_max, float sk_min, int* __restrict__ rfi_status)
{
volatile __shared__ float s1[BLOCK_DIM];
volatile __shared__ float s2[BLOCK_DIM];
int l_index = threadIdx.x;
float pow = 0.0f;
float pow_sq = 0.0f;
s1[l_index] = 0.0f;
s2[l_index] = 0.0f;
for(int thread_offset = l_index; thread_offset < window_size; thread_offset += blockDim.x){
int g_index = thread_offset + blockIdx.x * window_size;
pow = thrust::abs(data[g_index]) * thrust::abs(data[g_index]);
pow_sq = pow * pow;
s1[l_index] += pow;
s2[l_index] += pow_sq;
}
__syncthreads();
for(int s = blockDim.x / 2; s > 32; s >>= 1){
if(l_index < s){
s1[l_index] += s1[l_index + s];
s2[l_index] += s2[l_index + s];
}
__syncthreads();
}
if(l_index < 32) warpReduce(s1, s2, l_index);
if(l_index == 0){
float sk = ((window_size + 1) / (window_size - 1)) *(((window_size * s2[0]) / (s1[0] * s1[0])) - 1);
rfi_status[blockIdx.x] = (int) ((sk < sk_min) || (sk > sk_max));
if (rfi_status[blockIdx.x] == 1) atomicAdd(&rfi_count, 1);
}
}
SpectralKurtosisCuda::SpectralKurtosisCuda(std::size_t nchannels, std::size_t window_size, float sk_min, float sk_max)
: _nchannels(nchannels),
_window_size(window_size),
_sk_min(sk_min),
_sk_max(sk_max)
{
BOOST_LOG_TRIVIAL(debug) << "Creating new SpectralKurtosisCuda instance... \n";
}
SpectralKurtosisCuda::~SpectralKurtosisCuda()
{
BOOST_LOG_TRIVIAL(debug) << "Destroying SpectralKurtosisCuda instance... \n";
}
void SpectralKurtosisCuda::init()
{
if((_sample_size % _window_size) != 0){
BOOST_LOG_TRIVIAL(error) << "Sample(data) size " << _sample_size <<" is not a multiple of _window_size "
<< _window_size <<". Give different window size.\n";
throw std::runtime_error("Data(sample) size is not a multiple of window_size. Give different window size. \n");
}
_nwindows = _sample_size /_window_size;
}
void SpectralKurtosisCuda::compute_sk_thrust(const thrust::device_vector<thrust::complex<float>> &data, RFIStatistics &stats, cudaStream_t _stream){
nvtxRangePushA("compute_sk");
thrust::cuda::par.on(_stream);
_sample_size = data.size();
BOOST_LOG_TRIVIAL(debug) << "Computing SK (thrust version) for sample_size " << _sample_size
<< " and window_size " << _window_size <<".\n";
//initializing class variables
init();
_d_s1.resize(_nwindows);
_d_s2.resize(_nwindows);
//computing _d_s1 for all windows
nvtxRangePushA("compute_sk_reduce_by_key_call");
thrust::reduce_by_key(thrust::device,
thrust::make_transform_iterator(thrust::counting_iterator<int> (0), (thrust::placeholders::_1 / _window_size)),
thrust::make_transform_iterator(thrust::counting_iterator<int> (_sample_size - 1), (thrust::placeholders::_1 / _window_size)),
thrust::make_transform_iterator(data.begin(), compute_power()),
thrust::discard_iterator<int>(),
_d_s1.begin());
//computing _d_s2 for all windows
thrust::reduce_by_key(thrust::device,
thrust::make_transform_iterator(thrust::counting_iterator<int> (0), (thrust::placeholders::_1 / _window_size)),
thrust::make_transform_iterator(thrust::counting_iterator<int> (_sample_size - 1), (thrust::placeholders::_1 / _window_size)),
thrust::make_transform_iterator(data.begin(), power_square()),
thrust::discard_iterator<int>(),
_d_s2.begin());
nvtxRangePop();
//computes SK and checks the threshold to detect RFI.
stats.rfi_status.resize(_nwindows);
nvtxRangePushA("compute_sk_thrust_transform_reduce");
thrust::transform(_d_s1.begin(), _d_s1.end(), _d_s2.begin(), stats.rfi_status.begin(), check_rfi(_window_size, _sk_min, _sk_max));
stats.rfi_fraction = thrust::reduce(stats.rfi_status.begin(), stats.rfi_status.end(), 0.0f) / _nwindows;
nvtxRangePop();
BOOST_LOG_TRIVIAL(info) << "RFI fraction: " << stats.rfi_fraction;
nvtxRangePop();
}
void SpectralKurtosisCuda::compute_sk(thrust::device_vector<thrust::complex<float>> &data, RFIStatistics &stats, cudaStream_t _stream){
nvtxRangePushA("compute_sk_kernel");
_sample_size = data.size();
BOOST_LOG_TRIVIAL(debug) << "Computing SK (kernel version) for sample_size " << _sample_size
<< " and window_size " << _window_size <<".\n";
//initializing variables
init();
stats.rfi_status.resize(_nwindows);
int *k_rfi_status = thrust::raw_pointer_cast(stats.rfi_status.data());
thrust::complex<float> *k_data = thrust::raw_pointer_cast(data.data());
nvtxRangePushA("compute_sk_kernel_call");
compute_sk_kernel<<<_nwindows, BLOCK_DIM, 0, _stream>>> (k_data, _sample_size, _window_size, _sk_max, _sk_min, k_rfi_status);
cudaDeviceSynchronize();
nvtxRangePop();
nvtxRangePushA("compute_sk_kernel_rfi_fraction");
int nrfiwindows = 0;
cudaMemcpyFromSymbol(&nrfiwindows, rfi_count, sizeof(int));
stats.rfi_fraction = (float)nrfiwindows / _nwindows;
int reset_rfi_count = 0;
cudaMemcpyToSymbol(rfi_count, &reset_rfi_count, sizeof(int));
nvtxRangePop();
BOOST_LOG_TRIVIAL(info) << "RFI fraction: " << stats.rfi_fraction;
nvtxRangePop();
}
} //edd
} //effelsberg
} //psrdada_cpp
......@@ -12,8 +12,13 @@ set(gtest_edd_src
src/ScaledTransposeTFtoTFTTester.cu
src/VLBITest.cu
src/EDDPolnMergeTester.cpp
src/SKTestVector.cpp
src/SpectralKurtosis.cpp
src/SKRfiReplacement.cpp
src/SpectralKurtosisTester.cpp
src/SpectralKurtosisCudaTester.cu
)
cuda_add_executable(gtest_edd ${gtest_edd_src} )
target_link_libraries(gtest_edd ${PSRDADA_CPP_EFFELSBERG_EDD_LIBRARIES} ${CUDA_CUFFT_LIBRARIES} -lcublas)
target_link_libraries(gtest_edd ${PSRDADA_CPP_EFFELSBERG_EDD_LIBRARIES} ${CUDA_CUFFT_LIBRARIES} -lcublas -lnvToolsExt -L/usr/local/cuda-11.0/lib64/)
add_test(gtest_edd gtest_edd --test_data "${CMAKE_CURRENT_LIST_DIR}/data")
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENT_HPP
#define PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENT_HPP
#include "psrdada_cpp/common.hpp"
#include <vector>
#include <complex>
#include <algorithm>
#include <numeric>
#include <random>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
#define DEFAULT_NUM_CLEAN_WINDOWS 1 //number of clean windows used for computing DataStatistics
struct DataStatistics
{
float r_mean, r_sd, i_mean, i_sd;
};
class SKRfiReplacement{
public:
/**
* @brief constructor
*
* @param(in) rfi_status rfi_status of input data
*
*/
SKRfiReplacement(const std::vector<int> &rfi_status);
/**
* @brief destructor
*/
~SKRfiReplacement();
/**
* @brief Replaces data in rfi_windows with replacement data (generated using statistics of data from clean_windows).
*
* @param(in & out) data Data on which RFI has to be replaced. Returns the same but with RFI replaced.
*/
void replace_rfi_data(std::vector<std::complex<float>> &data);
private:
/**
* @brief Initializes data members of the class
*/
void init();
/**
* @brief Gets indices of clean windows, _clean_window_indices
*/
void get_clean_window_indices();
/**
* @brief Gets indices of RFI windows, _rfi_window_indices
*/
void get_rfi_window_indices();
/**
* @brief Computes statistics for the given input data. Here it is the data from few clean windows.
*
* @param(in) data data from default number of clean windows.
* @param(out) stats DataStatistics of input data
*/
void compute_data_statistics(const std::vector<std::complex<float>> &data, DataStatistics &stats);
/**
* @brief Gathers data from DEFAULT_NUM_CLEAN_WINDOW number of clean windows and computes its statistics
*
* @param(in) data actual data
* @param(out) ref_data_statistics Statistics of data from clean windows
*/
void get_clean_data_statistics(const std::vector<std::complex<float>> &data,
DataStatistics &ref_data_statistics);
/**
* @brief Generates replacement data using clean window data statistics
*
* @param(in) stats data statistics
* @param(out) replacement_data replacement data of size = _window_size generated using input stats.
*/
void generate_replacement_data(const DataStatistics &stats, std::vector<std::complex<float>> &replacement_data);
std::vector<int> _rfi_status;
std::size_t _window_size;
std::size_t _nwindows, _nrfi_windows, _nclean_windows;
std::vector<int> _rfi_window_indices;
std::vector<int> _clean_window_indices;
};
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SKRFIREPLACEMENT_HPP
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SKTESTVECTOR_HPP
#define PSRDADA_CPP_EFFELSBERG_EDD_SKTESTVECTOR_HPP
#include "psrdada_cpp/common.hpp"
#include <complex>
#include <vector>
#include <functional>
#include <numeric>
#include <random>
#include <algorithm>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
#define DEFAULT_MEAN 0 //default mean for normal ditribution test vector
#define DEFAULT_STD 0.5 //default standard deviation for normal ditribution test vector
class SKTestVector{
public:
/**
* @param sample_size size of test vector
* window_size number of samples in a window
* with_rfi Flag to include RFI in test vector
* rfi_frequency frequency of RFI
* rfi_amplitude amplitude of RFI
* mean mean for normal distribution test vector
* std standard deviation for normal distribution test vector
*/
SKTestVector(std::size_t sample_size, std::size_t window_size, bool with_rfi, float rfi_frequency,
float rfi_amplitude, float mean = DEFAULT_MEAN, float std = DEFAULT_STD);
~SKTestVector();
/**
* @brief generates test vector
*
* @detail The test vector is a normal distribution vector and contains RFI if the flag with_rfi is set to true.
*
* @param rfi_windows vector of window indices on which the RFI has to be added.
* test_samples output test vector
*/
void generate_test_vector(std::vector<int> const& rfi_windows, std::vector<std::complex<float>> &test_samples);
private:
/**
* @brief generates a normal distribution vector for the default or given mean and standard deviation.
*
* @param samples output normal distribution test vector
*
*/
void generate_normal_distribution_vector(std::vector<std::complex<float>> &samples);
/**
* @brief generates rfi signal of frequency = _rfi_frequency and size = _window_size
*
* @param rfi_samples output RFI vector
*
*/
void generate_rfi_vector(std::vector<std::complex<float>> &rfi_samples);
std::size_t _sample_size;
std::size_t _window_size;
bool _with_rfi;
float _rfi_frequency;
float _rfi_amplitude;
float _mean;
float _std;
};
} //test
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SKTESTVECTOR_HPP
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSIS_HPP
#define PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSIS_HPP
#include "psrdada_cpp/common.hpp"
#include <complex>
#include <vector>
#include <numeric>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
struct RFIStatistics{
std::vector<int> rfi_status;
float rfi_fraction;
};
class SpectralKurtosis{
public:
/**
* @brief constructor
*
* @param nchannels number of channels.
* window_size number of samples per window.
* sk_min minimum value of spectral kurtosis.
* sk_max maximum value of spectral kurtosis.
*/
SpectralKurtosis(std::size_t nchannels, std::size_t window_size, float sk_min = 0.9,
float sk_max = 1.1);
~SpectralKurtosis();
/**
* @brief computes spectral kurtosis for the given data and returns its rfi statistics.
*
* @param data input data
* stats RFI statistics
*
*/
void compute_sk(std::vector<std::complex<float>> const& data, RFIStatistics& stats);
private:
std::size_t _nchannels; //number of channels
std::size_t _window_size; //window size
std::size_t _nwindows; //number of windows
std::size_t _sample_size; //size of input data
float _sk_min, _sk_max;
std::vector<float> _p1, _p2, _s1, _s2, _sk;
/**
* @brief initializes the data members of the class.
*
* */
void init();
};
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSIS_HPP
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDATESTER_CUH
#define PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDATESTER_CUH
#include "psrdada_cpp/common.hpp"
#include "psrdada_cpp/effelsberg/edd/test/SKTestVector.hpp"
#include "psrdada_cpp/effelsberg/edd/SpectralKurtosisCuda.cuh"
#include "psrdada_cpp/effelsberg/edd/SKRfiReplacementCuda.cuh"
#include "thrust/host_vector.h"
#include "thrust/device_vector.h"
#include <gtest/gtest.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
class SpectralKurtosisCudaTester: public ::testing::Test
{
public:
SpectralKurtosisCudaTester();
~SpectralKurtosisCudaTester();
/**
* @brief creates SKTestVector class instance and generates test vector
*
*/
void test_vector_generation(std::size_t sample_size, std::size_t window_size, bool with_rfi,
float rfi_freq, float rfi_amp, const std::vector<int> &rfi_window_indices,
std::vector<std::complex<float>> &samples);
/**
* @brief creates SpectralKurtosis class instance and computes spectral kurtosis
*
*/
void sk_computation(std::size_t nch,std::size_t window_size,
const std::vector<std::complex<float>> &samples,
RFIStatistics &stat);
protected:
void SetUp() override;
void TearDown() override;
};
} //test
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISCUDATESTER_CUH
#ifndef PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISTESTER_HPP
#define PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISTESTER_HPP
#include "psrdada_cpp/common.hpp"
#include "psrdada_cpp/effelsberg/edd/test/SKRfiReplacement.hpp"
#include "psrdada_cpp/effelsberg/edd/test/SpectralKurtosis.hpp"
#include "psrdada_cpp/effelsberg/edd/test/SKTestVector.hpp"
#include <gtest/gtest.h>
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
class SpectralKurtosisTester: public ::testing::Test
{
public:
SpectralKurtosisTester();
~SpectralKurtosisTester();
/**
* @brief creates SKTestVector class instance and generates test vector
*
*/
void test_vector_generation(std::size_t sample_size, std::size_t window_size, bool with_rfi,
float rfi_freq, float rfi_amp, const std::vector<int> &rfi_window_indices,
std::vector<std::complex<float>> &samples);
/**
* @brief creates SpectralKurtosis class instance and computes spectral kurtosis
*
*/
void sk_computation(std::size_t nch,std::size_t window_size,
const std::vector<std::complex<float>> &samples,
RFIStatistics &stat);
protected:
void SetUp() override;
void TearDown() override;
};
} //test
} //edd
} //effelsberg
} //psrdada_cpp
#endif //PSRDADA_CPP_EFFELSBERG_EDD_SPECTRALKURTOSISTESTER_HPP
#include "ReadData.hpp"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd{
ReadData::ReadData(std::string filename)
: _filename(filename)
{
}
void ReadData::read_file(){
std::vector<char> x;
std::ifstream dada_file;
std::size_t length;
dada_file.open(_filename);
if(dada_file.is_open()){
dada_file.seekg(0, dada_file.end);
length = dada_file.tellg();
length -= DADA_HDR_SIZE;
dada_file.seekg(DADA_HDR_SIZE);
x.resize(length);
dada_file.read((char *) &x[0], length);
}
dada_file.close();
_sample_size=length/4;
_pol0.resize(_sample_size);
_pol1.resize(_sample_size);
std::size_t offset;
for(int i=0; i<_sample_size; i++){
offset = i*4;
_pol0[i]=std::complex<float>(x[offset], x[offset+1]);
_pol1[i]=std::complex<float>(x[offset+2], x[offset+3]);
}
}
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/test/SKRfiReplacement.hpp"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
SKRfiReplacement::SKRfiReplacement(const std::vector<int> &rfi_status)
: _rfi_status(rfi_status)
{
BOOST_LOG_TRIVIAL(info) << "Creating new SKRfiReplacement instance..\n";
}
SKRfiReplacement::~SKRfiReplacement()
{
BOOST_LOG_TRIVIAL(info) << "Destroying SKRfiReplacement instance..\n";
}
void SKRfiReplacement::init()
{
BOOST_LOG_TRIVIAL(info) << "initializing data_members of SKRfiReplacement class..\n";
_nwindows = _rfi_status.size();
_rfi_window_indices.reserve(_nwindows);
get_rfi_window_indices();
_clean_window_indices.reserve(_nwindows);
get_clean_window_indices();
}
void SKRfiReplacement::get_rfi_window_indices()
{
_nrfi_windows = std::count(_rfi_status.begin(), _rfi_status.end(), 1);
_rfi_window_indices.resize(_nrfi_windows);
std::size_t iter = 0;
for(std::size_t index = 0; index < _nrfi_windows; index++){
_rfi_window_indices[index] = std::distance(_rfi_status.begin(),
max_element((_rfi_status.begin() + iter), _rfi_status.end()));
iter = _rfi_window_indices[index] + 1;
}
}
void SKRfiReplacement::get_clean_window_indices()
{
_nclean_windows = std::count(_rfi_status.begin(), _rfi_status.end(), 0);
_clean_window_indices.resize(DEFAULT_NUM_CLEAN_WINDOWS);
std::size_t iter = 0;
for(std::size_t index = 0; index < DEFAULT_NUM_CLEAN_WINDOWS; index++){
_clean_window_indices[index] = std::distance(_rfi_status.begin(),
min_element((_rfi_status.begin() + iter), _rfi_status.end()));
iter = _clean_window_indices[index] + 1;
}
}
void SKRfiReplacement::get_clean_data_statistics(const std::vector<std::complex<float>> &data,
DataStatistics &ref_data_statistics)
{
_window_size = data.size() / _nwindows;
std::vector<std::complex<float>> clean_data(DEFAULT_NUM_CLEAN_WINDOWS * _window_size);
for(std::size_t ii = 0; ii < DEFAULT_NUM_CLEAN_WINDOWS; ii++){
std::size_t window_index = _clean_window_indices[ii];
std::size_t ibegin = window_index * _window_size;
std::size_t iend = ibegin + _window_size - 1;
std::size_t jj = ii * _window_size;
std::copy((data.begin() + ibegin), (data.begin() + iend), (clean_data.begin() + jj));
BOOST_LOG_TRIVIAL(debug) <<"clean_win_index = " << window_index
<< " ibegin = " << ibegin << " iend = " << iend;
}
compute_data_statistics(clean_data, ref_data_statistics);
}
void SKRfiReplacement::compute_data_statistics(const std::vector<std::complex<float>> &data, DataStatistics &stats)
{
std::size_t length = data.size();
std::complex<float> sum = std::accumulate(data.begin(), data.end(), std::complex<float> (0, 0));
stats.r_mean = sum.real() / length;
stats.i_mean = sum.imag() / length;
std::vector<float> vreal(length), vimag(length), rdiff(length), idiff(length);
for(std::size_t ii = 0; ii < length; ii++){
vreal[ii] = data[ii].real();
vimag[ii] = data[ii].imag();
}
std::transform(vreal.begin(), vreal.end(), rdiff.begin(), std::bind2nd(std::minus<float>(), stats.r_mean));
std::transform(vimag.begin(), vimag.end(), idiff.begin(), std::bind2nd(std::minus<float>(), stats.i_mean));
stats.r_sd = std::sqrt((float)std::inner_product(rdiff.begin(), rdiff.end(), rdiff.begin(), 0.0f) / length);
stats.i_sd = std::sqrt((float)std::inner_product(idiff.begin(), idiff.end(), idiff.begin(), 0.0f) / length);
BOOST_LOG_TRIVIAL(debug) << "DataStatistics r_mean = " << stats.r_mean
<< " r_sd = " << stats.r_sd
<< " i_mean = " << stats.i_mean
<< " i_sd = " << stats.r_sd;
}
void SKRfiReplacement::generate_replacement_data(const DataStatistics &stats, std::vector<std::complex<float>> &replacement_data)
{
BOOST_LOG_TRIVIAL(info) << "generating replacement data..\n";
replacement_data.resize(_window_size);
std::default_random_engine gen(1);
std::normal_distribution<float> rdist(stats.r_mean, stats.r_sd);
std::normal_distribution<float> idist(stats.i_mean, stats.i_sd);
for(std::size_t index = 0; index < _window_size; index++){
replacement_data[index] = std::complex<float>(rdist(gen), idist(gen));
}
}
void SKRfiReplacement::replace_rfi_data(std::vector<std::complex<float>> &data)
{
DataStatistics stats;
std::vector<std::complex<float>> replacement_data;
//initialize data members of the class
init();
//RFI present and not in all windows
if((_nrfi_windows > 0) && (_nrfi_windows < _nwindows)){
get_clean_data_statistics(data, stats);
generate_replacement_data(stats, replacement_data);
//Replacing RFI
for(std::size_t ii = 0; ii < _nrfi_windows; ii++){
std::size_t index = _rfi_window_indices[ii] * _window_size;
std::copy(replacement_data.begin(), replacement_data.end(), (data.begin() +index));
}
}
}
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/test/SKTestVector.hpp"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
SKTestVector::SKTestVector(std::size_t sample_size, std::size_t window_size, bool with_rfi,
float rfi_frequency, float rfi_amplitude, float mean, float std)
: _sample_size(sample_size),
_window_size(window_size),
_with_rfi(with_rfi),
_rfi_frequency(rfi_frequency),
_rfi_amplitude(rfi_amplitude),
_mean(mean),
_std(std)
{
BOOST_LOG_TRIVIAL(debug) << "Creating SKTestVector instance..\n";
}
SKTestVector::~SKTestVector()
{
BOOST_LOG_TRIVIAL(debug) << "Destroying SKTestVector instance..\n";
}
void SKTestVector::generate_normal_distribution_vector(std::vector<std::complex<float>> &samples)
{
samples.resize(_sample_size);
//normal distribution seed
std::default_random_engine gen(14);
//generating normal distribution samples
BOOST_LOG_TRIVIAL(debug) << "generating normal distribution samples for mean: " << _mean
<< " and standard deviation: " << _std << "\n";
std::normal_distribution<float> norm_dist(_mean, _std);
//Complex vector
for(std::size_t index = 0; index < _sample_size; index++){
samples[index] = std::complex<float>((norm_dist(gen) - _mean), (norm_dist(gen) - _mean));
}
}
void SKTestVector::generate_rfi_vector(std::vector<std::complex<float>> &rfi_vector)
{
rfi_vector.resize(_window_size);
BOOST_LOG_TRIVIAL(debug) << "generating rfi samples of size: " << _window_size;
for(std::size_t t = 0; t < _window_size; t++){
rfi_vector[t] = _rfi_amplitude * std::exp(std::complex<float> (0, 1) *
float(2 * M_PI * _rfi_frequency * t));
}
}
void SKTestVector::generate_test_vector(std::vector<int> const& rfi_window_indices, std::vector<std::complex<float>> &test_vector)
{
test_vector.resize(_sample_size);
generate_normal_distribution_vector(test_vector);
BOOST_LOG_TRIVIAL(debug) << "generating test vector" ;
if(_with_rfi){
BOOST_LOG_TRIVIAL(debug) << " with RFI\n";
std::vector<std::complex<float>> rfi_vector(_window_size);
generate_rfi_vector(rfi_vector);
int nwindows = rfi_window_indices.size();
BOOST_LOG_TRIVIAL(debug) <<"adding rfi in windows.." << "\n";
for(int win = 0; win < nwindows; win++){
int istart = rfi_window_indices[win] * _window_size;
int iend = istart + _window_size;
BOOST_LOG_TRIVIAL(debug) << " " << rfi_window_indices[win];
std::transform((test_vector.begin() + istart), (test_vector.begin() + iend), rfi_vector.begin(),
(test_vector.begin() + istart), std::plus<std::complex<float>>());
}
}
}
} //test
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/test/SpectralKurtosis.hpp"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
SpectralKurtosis::SpectralKurtosis(std::size_t nchannels, std::size_t window_size, float sk_min, float sk_max)
: _nchannels(nchannels),
_window_size(window_size),
_sk_min(sk_min),
_sk_max(sk_max)
{
BOOST_LOG_TRIVIAL(debug) << "Creating new SpectralKurtosis instance..\n";
}
SpectralKurtosis::~SpectralKurtosis()
{
BOOST_LOG_TRIVIAL(debug) << "Destroying SpectralKurtosis instance..\n";
}
void SpectralKurtosis::init()
{
if((_sample_size % _window_size) != 0){
BOOST_LOG_TRIVIAL(error) << "Sample size " << _sample_size <<" is not a multiple of window_size "
<< _window_size <<". Give different window size.\n";
throw std::runtime_error("sample size is not a multiple of window_size. Give different window size\n");
}
_nwindows = _sample_size / _window_size;
_p1.resize(_sample_size);
_p2.resize(_sample_size);
_s1.resize(_sample_size);
_s2.resize(_sample_size);
_sk.resize(_sample_size);
}
void SpectralKurtosis::compute_sk(std::vector<std::complex<float>> const& data, RFIStatistics& stats)
{
_sample_size = data.size();
BOOST_LOG_TRIVIAL(debug) << "Computing SK for sample_size " << _sample_size
<< " and window_size " << _window_size <<"\n";
//initializing variables
init();
//computing sk
for(std::size_t samp_idx = 0; samp_idx < _sample_size; samp_idx++){
float x = abs(data[samp_idx]);
_p1[samp_idx] = x * x; //power
_p2[samp_idx] = _p1[samp_idx] * _p1[samp_idx];
}
stats.rfi_status.resize(_nwindows * _nchannels);
float sk_factor = (_window_size + 1) / (_window_size - 1);
for(std::size_t window_idx = 0; window_idx < _nwindows; window_idx++){
std::size_t r1 = window_idx * _window_size;
std::size_t r2 = r1 + _window_size - 1;
_s1[window_idx] = std::accumulate((_p1.begin() + r1), (_p1.begin() + r2), 0.0f);
_s2[window_idx] = std::accumulate((_p2.begin() + r1), (_p2.begin() + r2), 0.0f);
//computing SK for the window
_sk[window_idx] = sk_factor * (((_window_size * _s2[window_idx]) / (_s1[window_idx] * _s1[window_idx])) - 1);
//Updating RFI status for that window
stats.rfi_status[window_idx] = ((_sk[window_idx] > _sk_max) || (_sk[window_idx] < _sk_min));
}
stats.rfi_fraction = std::accumulate(stats.rfi_status.begin(), stats.rfi_status.end(), 0.0f) / _nwindows;
BOOST_LOG_TRIVIAL(info) << "RFI fraction: " << stats.rfi_fraction;
}
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/test/SpectralKurtosisCudaTester.cuh"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
SpectralKurtosisCudaTester:: SpectralKurtosisCudaTester():
::testing::Test()
{
}
SpectralKurtosisCudaTester::~SpectralKurtosisCudaTester()
{
}
void SpectralKurtosisCudaTester::SetUp()
{
}
void SpectralKurtosisCudaTester::TearDown()
{
}
void SpectralKurtosisCudaTester::test_vector_generation(std::size_t sample_size, std::size_t window_size,
bool with_rfi, float rfi_freq, float rfi_amp,
const std::vector<int> &rfi_window_indices,
std::vector<std::complex<float>> &samples)
{
float m = 0;
float std = 1;
SKTestVector tv(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, m, std);
tv.generate_test_vector(rfi_window_indices, samples);
}
void SpectralKurtosisCudaTester::sk_computation(std::size_t nch, std::size_t window_size,
const std::vector<std::complex<float>> &samples,
RFIStatistics &stat)
{
thrust::host_vector<thrust::complex<float>> h_samples(samples);
thrust::device_vector<thrust::complex<float>> d_samples(h_samples);
float sk_min = 0.8;
float sk_max = 1.2;
SpectralKurtosisCuda sk(nch, window_size, sk_min, sk_max);
sk.compute_sk(d_samples, stat);
}
TEST_F(SpectralKurtosisCudaTester, sk_window_size_check)
{
std::vector<int> rfi_window_indices{};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 4000;
std::size_t window_size = 150;
bool with_rfi = 0;
float rfi_freq = 0;
float rfi_amp = 0;
test_vector_generation(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
EXPECT_THROW(sk_computation(nch, window_size, samples, stat), std::runtime_error);
}
TEST_F(SpectralKurtosisCudaTester, sk_withoutRFI)
{
std::vector<int> rfi_window_indices{};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 40000;
std::size_t window_size = 400;
bool with_rfi = 0;
float rfi_freq = 0;
float rfi_amp = 0;
test_vector_generation(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
sk_computation(nch, window_size, samples, stat);
float expected_rfi_fraction = 0;
EXPECT_EQ(expected_rfi_fraction, stat.rfi_fraction);
}
TEST_F(SpectralKurtosisCudaTester, sk_withRFI)
{
std::vector<int> rfi_window_indices{3, 4, 6, 7, 8, 20, 30, 40, 45, 75};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 40000;
std::size_t window_size = 400;
bool with_rfi = 1;
float rfi_freq = 30;
float rfi_amp = 10;
test_vector_generation(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
sk_computation(nch, window_size, samples, stat);
float expected_rfi_fraction = (rfi_window_indices.size()/float(sample_size/window_size));
EXPECT_EQ(expected_rfi_fraction, stat.rfi_fraction);
}
TEST_F(SpectralKurtosisCudaTester, sk_RFIreplacement)
{
std::size_t sample_size = 128* 1024 * 1024;
std::size_t window_size = 1024 * 2;
//Test vector generation
std::vector<int> rfi_window_indices{3, 4, 6, 7, 8, 20, 30, 40, 45, 75};
std::vector<std::complex<float>> samples;
bool with_rfi = 1;
float rfi_freq = 30;
float rfi_amp = 10;
test_vector_generation(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, rfi_window_indices, samples);
//SK computation
thrust::host_vector<thrust::complex<float>> h_samples(samples);
thrust::device_vector<thrust::complex<float>> d_samples(h_samples);
float sk_min = 0.8;
float sk_max = 1.2;
std::size_t nch = 1;
SpectralKurtosisCuda sk(nch, window_size, sk_min, sk_max);
RFIStatistics stat;
sk.compute_sk(d_samples, stat);
//RFI replacement
BOOST_LOG_TRIVIAL(info) <<"RFI replacement..\n";
SKRfiReplacementCuda rr;
rr.replace_rfi_data(stat.rfi_status, d_samples);
//SK computation after RFI replacement
BOOST_LOG_TRIVIAL(info) <<"computing SK after replacing the RFI data..\n";
sk.compute_sk(d_samples, stat);
float expected_val_after_rfi_replacement = 0;
EXPECT_EQ(expected_val_after_rfi_replacement, stat.rfi_fraction);
}
TEST_F(SpectralKurtosisCudaTester, sk_kernel)
{
std::size_t sample_size = 160000000;
std::size_t window_size = 2000;
std::size_t nwindows = sample_size / window_size;
//Test vector generation
std::vector<int> rfi_window_indices{1, 4, 6, 7, 8, 20, 30, 40, 45, 75};
std::vector<std::complex<float>> samples;
bool with_rfi = 1;
float rfi_freq = 30;
float rfi_amp = 10;
test_vector_generation(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, rfi_window_indices, samples);
//SK computation
thrust::host_vector<thrust::complex<float>> h_samples(samples);
thrust::device_vector<thrust::complex<float>> d_samples(h_samples);
std::size_t nch = 1;
SpectralKurtosisCuda sk(nch, window_size);
RFIStatistics stat, stat_k;
sk.compute_sk_thrust(d_samples, stat);
sk.compute_sk(d_samples, stat_k);
for (int ii = 0; ii < nwindows; ii++){
EXPECT_EQ(stat.rfi_status[ii], stat_k.rfi_status[ii]);
}
EXPECT_EQ(stat.rfi_fraction, stat_k.rfi_fraction);
//RFI replacement
BOOST_LOG_TRIVIAL(info) <<"RFI replacement..\n";
SKRfiReplacementCuda rr;
std::size_t clean_windows = 100; //no. of clean windows used for computing data statistics
rr.replace_rfi_data(stat_k.rfi_status, d_samples, clean_windows);
//SK computation after RFI replacement
BOOST_LOG_TRIVIAL(info) <<"computing SK after replacing the RFI data..\n";
sk.compute_sk(d_samples, stat_k);
float expected_val_after_rfi_replacement = 0;
EXPECT_EQ(expected_val_after_rfi_replacement, stat_k.rfi_fraction);
}
} //test
} //edd
} //effelsberg
} //psrdada_cpp
#include "psrdada_cpp/effelsberg/edd/test/SpectralKurtosisTester.hpp"
namespace psrdada_cpp {
namespace effelsberg {
namespace edd {
namespace test {
SpectralKurtosisTester:: SpectralKurtosisTester():
::testing::Test()
{
}
SpectralKurtosisTester::~SpectralKurtosisTester()
{
}
void SpectralKurtosisTester::SetUp()
{
}
void SpectralKurtosisTester::TearDown()
{
}
void SpectralKurtosisTester::test_vector_generation(std::size_t sample_size, std::size_t window_size,
bool with_rfi, float rfi_freq, float rfi_amp,
const std::vector<int> &rfi_window_indices,
std::vector<std::complex<float>> &samples)
{
float m = 5;
float std = 1;
SKTestVector tv(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, m, std);
tv.generate_test_vector(rfi_window_indices, samples);
}
void SpectralKurtosisTester::sk_computation(std::size_t nch, std::size_t window_size,
const std::vector<std::complex<float>> &samples,
RFIStatistics &stat)
{
float sk_min = 0.8;
float sk_max = 1.2;
SpectralKurtosis sk(nch, window_size, sk_min, sk_max);
sk.compute_sk(samples, stat);
}
TEST_F(SpectralKurtosisTester, sk_window_size_check)
{
std::vector<int> rfi_window_indices{};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 4000;
std::size_t window_size = 150;
test_vector_generation(sample_size, window_size, 0, 0, 0, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
EXPECT_THROW(sk_computation(nch, window_size, samples, stat), std::runtime_error);
}
TEST_F(SpectralKurtosisTester, sk_withoutRFI)
{
std::vector<int> rfi_window_indices{};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 4000;
std::size_t window_size = 400;
test_vector_generation(sample_size, window_size, 0, 0, 0, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
sk_computation(nch, window_size, samples, stat);
float expected_rfi_fraction = 0;
EXPECT_EQ(expected_rfi_fraction, stat.rfi_fraction);
}
TEST_F(SpectralKurtosisTester, sk_withRFI)
{
std::vector<int> rfi_window_indices{3, 4, 6, 7, 8, 20, 30, 40};
std::vector<std::complex<float>> samples;
std::size_t sample_size = 40000;
std::size_t window_size = 400;
test_vector_generation(sample_size, window_size, 1, 10, 30, rfi_window_indices, samples);
RFIStatistics stat;
std::size_t nch = 1;
sk_computation(nch, window_size, samples, stat);
float expected_rfi_fraction = (rfi_window_indices.size()/float(sample_size/window_size)) + 0.01;
EXPECT_EQ(expected_rfi_fraction, stat.rfi_fraction); //To check: fails inspite of actual and expected values being same.
}
TEST_F(SpectralKurtosisTester, sk_replacement)
{
//Test vector
bool with_rfi = 1;
std::size_t sample_size = 40000;
std::size_t window_size = 400;
float rfi_freq = 10;
float rfi_amp = 30;
float mean = 5;
float std = 2;
SKTestVector tv(sample_size, window_size, with_rfi, rfi_freq, rfi_amp, mean, std);
std::vector<int> rfi_window_indices{1, 2, 3, 4, 6, 7, 8, 9, 20, 30, 40};
std::vector<std::complex<float>> samples;
tv.generate_test_vector(rfi_window_indices, samples); //generating test vector
//SK
std::size_t nch = 1;
float sk_min = 0.8;
float sk_max = 1.2;
RFIStatistics stat;
SpectralKurtosis sk(nch, window_size, sk_min, sk_max);
sk.compute_sk(samples, stat); //computing SK
float expected_rfi_fraction = (rfi_window_indices.size()/float(sample_size/window_size)) + 0.01;
EXPECT_EQ(expected_rfi_fraction, stat.rfi_fraction);
//RFI replacement
BOOST_LOG_TRIVIAL(info) <<"RFI replacement \n";
SKRfiReplacement rr(stat.rfi_status);
rr.replace_rfi_data(samples);
//SK computation after RFI replacement
BOOST_LOG_TRIVIAL(info) <<"computing SK after RFI replacement.. \n";
sk.compute_sk(samples, stat); //computing SK
float expected_val_after_rfi_replacement = 0;
EXPECT_EQ(expected_val_after_rfi_replacement, stat.rfi_fraction);
}
} //test
} //edd
} //effelsberg
} //psrdada_cpp
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment