24 #include "cheetah/fft/test_utils/FftTester.h" 25 #include "cheetah/data/TimeSeries.h" 26 #include "cheetah/data/FrequencySeries.h" 27 #include "cheetah/data/ComplexTypeTraits.h" 28 #include "panda/Log.h" 29 #include "panda/TypeTraits.h" 40 template<
typename TraitsT
42 ,
typename OutputType>
43 class HasFftProcessMethod
46 template<
typename Algo>
47 using HasC2C_t = decltype(std::declval<Algo>().process(std::declval<typename TraitsT::DeviceType&>(),
48 std::declval<InputType const&>(),
49 std::declval<OutputType&>()
51 typedef typename TraitsT::Algo Algorithm;
54 static const bool value = panda::HasMethod<Algorithm, HasC2C_t>::value;
57 template<
typename TypeParam,
typename InputValueT,
typename OutputValueT>
58 using HasTime2Frequency = HasFftProcessMethod< TypeParam
59 , data::TimeSeries<
typename TypeParam::Arch
61 , data::FrequencySeries<
typename TypeParam::Arch
64 template<
typename TypeParam,
typename InputValueT,
typename OutputValueT>
65 using HasFrequency2Time = HasFftProcessMethod< TypeParam
66 , data::FrequencySeries<
typename TypeParam::Arch
68 , data::TimeSeries<
typename TypeParam::Arch
77 void process( TestDevice&
78 , data::TimeSeries<TestArch, float>
const&
79 , data::FrequencySeries<TestArch, std::complex<float>>&) {}
83 typedef TestDevice DeviceType;
84 typedef TestArch Arch;
87 static_assert(!HasTime2Frequency<TypeParam<A>,
float, std::complex<float>>::value,
"not detecting process method");
88 static_assert(HasTime2Frequency<TypeParam<B>,
float, std::complex<float>>::value,
"not detecting process method");
91 template<
class DerivedType,
typename TypeParam,
typename Enable=
void>
95 void exec(
typename TypeParam::DeviceType& device)
97 DerivedType::run_test(device);
101 template<
class DerivedType,
typename TypeParam>
102 struct R2C_Base<DerivedType, TypeParam
103 , typename
std::enable_if<
104 !HasTime2Frequency<TypeParam
105 , typename TypeParam::NumericalRep
106 , typename TypeParam::ComplexT
111 void exec(
typename TypeParam::DeviceType&)
113 std::cout <<
"Real to Complex FT not defined for this device";
117 template<
typename TypeParam,
class InputType,
class OutputType
118 ,
typename Enable=
void>
122 bool exec(TypeParam& traits
123 ,
typename TypeParam::DeviceType& device
124 , InputType
const& input
128 traits.api().process(device, input, output);
133 template<
typename TypeParam,
class InputType,
class OutputType>
134 struct ProcessHelper<TypeParam, InputType, OutputType
135 , typename
std::enable_if<
136 !HasFftProcessMethod<TypeParam, InputType, OutputType>::value>::type>
140 ,
typename TypeParam::DeviceType&
155 template<
typename TypeParam,
class InputType,
class OutputType>
156 bool process(TypeParam& traits
157 ,
typename TypeParam::DeviceType& device
158 , InputType
const& input
159 , OutputType& output)
161 return ProcessHelper<TypeParam, InputType, OutputType>::exec(traits, device, input, output);
166 template<
typename Algorithm,
typename NumericalT>
167 FftTesterTraits<Algorithm, NumericalT>::FftTesterTraits()
172 template<
typename Algorithm,
typename NumericalT>
173 fft::Fft& FftTesterTraits<Algorithm, NumericalT>::api()
178 template <
typename TestTraits>
179 FftTester<TestTraits>::FftTester()
180 : cheetah::utils::test::AlgorithmTester<TestTraits>()
184 template <
typename TestTraits>
185 FftTester<TestTraits>::~FftTester()
189 template<
typename TestTraits>
190 void FftTester<TestTraits>::SetUp()
195 template<
typename TestTraits>
196 void FftTester<TestTraits>::TearDown()
200 template<
typename TypeParam>
204 void run_test(
typename TypeParam::DeviceType& device)
207 typedef typename TypeParam::NumericalRep T;
208 typedef typename TypeParam::Arch Arch;
209 typedef typename TypeParam::ComplexT ComplexT;
215 std::size_t fft_len=TypeParam::fft_trial_length;
217 InputTypeHost data_in(data::TimeType(0.003 * data::seconds), fft_len);
218 std::fill(data_in.begin(), data_in.end(), 0);
219 InputType input(data_in, traits.template allocator<InputType>(device));
220 OutputType output(traits.template allocator<OutputType>(device));
221 traits.api().process(device, input, output);
222 ASSERT_EQ(output.size(), input.size()/2 + 1);
223 ASSERT_EQ(output.frequency_step().value(), (1.0f/(input.sampling_interval().value() * input.size())));
224 OutputTypeHost data_out(output);
225 for(
auto const& elm : data_out){
226 ASSERT_FLOAT_EQ(elm.real(), 0.0);
227 ASSERT_FLOAT_EQ(elm.imag(), 0.0);
231 InputType inverse(traits.template allocator<InputType>(device));
232 if(! process(traits, device, output, inverse))
234 std::cout <<
"Inverse transform not availaable - skipping test";
238 InputTypeHost inverse_host(inverse);
239 ASSERT_EQ(inverse_host.size(), data_in.size());
240 auto inv_it=inverse_host.begin();
242 for(
auto const& elm : data_in)
244 SCOPED_TRACE(std::to_string(count));
245 ASSERT_FLOAT_EQ(elm, *inv_it);
252 ALGORITHM_TYPED_TEST_P(
FftTester, fft_r2c_zero)
262 template<
typename TypeParam>
266 void run_test(
typename TypeParam::DeviceType& device)
269 typedef typename TypeParam::NumericalRep T;
270 typedef typename TypeParam::Arch Arch;
271 typedef typename TypeParam::ComplexT ComplexT;
277 std::size_t fft_len=TypeParam::fft_trial_length;
279 InputTypeHost data_in(data::TimeType(0.003 * data::seconds), fft_len);
280 *(data_in.begin())=1;
281 std::fill(data_in.begin()+1, data_in.end(), 0);
282 InputType input(data_in, traits.template allocator<InputType>(device));
283 OutputType output(traits.template allocator<OutputType>(device));
284 traits.api().process(device, input, output);
285 ASSERT_EQ(output.size(), input.size()/2 + 1);
286 ASSERT_EQ(output.frequency_step().value(), (1.0f/(input.sampling_interval().value() * input.size())));
287 OutputTypeHost data_out(output);
289 for(
auto const& elm : data_out){
290 SCOPED_TRACE(std::to_string(count));
291 ASSERT_FLOAT_EQ(round(elm.real()), 1);
292 ASSERT_FLOAT_EQ(round(elm.imag()), 0.0);
293 ASSERT_TRUE(std::abs(elm.real()-1.0) < 1e-6);
294 ASSERT_TRUE(std::abs(elm.imag()-0.0) < 1e-6);
299 InputType inverse(traits.template allocator<InputType>(device));
300 if(! process(traits, device, output, inverse))
302 std::cout <<
"Inverse transform not availaable - skipping test";
306 ASSERT_EQ(inverse.size(), 2*(output.size() - 1));
307 ASSERT_EQ(inverse.sampling_interval().value(), (1.0f/(output.frequency_step().value() * inverse.size())));
308 InputTypeHost inverse_host(inverse);
309 ASSERT_EQ(inverse_host.size(), data_in.size());
312 auto inv_it=inverse_host.begin();
314 for(
auto const& elm : data_in)
316 SCOPED_TRACE(std::to_string(count));
317 ASSERT_TRUE(std::abs(elm*output.size() - *inv_it) < TypeParam::accuracy()) <<
"expected:" << elm*output.size() <<
" got:" << *inv_it <<
" accuracy:" << TypeParam::accuracy();
324 ALGORITHM_TYPED_TEST_P(
FftTester, fft_r2c_c2r_delta)
335 template<
typename TypeParam>
339 void run_test(
typename TypeParam::DeviceType& device)
342 typedef typename TypeParam::NumericalRep T;
343 typedef typename TypeParam::Arch Arch;
344 typedef typename TypeParam::ComplexT ComplexT;
350 std::size_t fft_len=TypeParam::fft_trial_length;
352 InputTypeHost data_in(data::TimeType(0.003 * data::seconds), fft_len);
353 *(data_in.begin())=0;
354 *(data_in.begin()+1)=1;
355 std::fill(data_in.begin()+3, data_in.end(), 0);
356 InputType input(data_in, traits.template allocator<InputType>(device));
357 OutputType output(traits.template allocator<OutputType>(device));
358 traits.api().process(device, input, output);
359 ASSERT_EQ(output.size(), input.size()/2 + 1);
360 ASSERT_EQ(output.frequency_step().value(), (1.0f/(input.sampling_interval().value() * input.size())));
361 OutputTypeHost data_out(output);
363 for(
auto const& elm : data_out){
364 SCOPED_TRACE(std::to_string(count));
365 ASSERT_FLOAT_EQ((T)1, (T)round(sqrt(elm.real()*elm.real()+elm.imag()*elm.imag())));
366 ASSERT_TRUE(std::abs((T)(sqrt(elm.real()*elm.real()+elm.imag()*elm.imag()))-(T)1) < 1e-6);
371 ALGORITHM_TYPED_TEST_P(
FftTester, fft_r2c_shift)
376 template<
typename TypeParam,
typename Enable=
void>
381 void exec(
typename TypeParam::DeviceType& device)
384 typedef typename TypeParam::NumericalRep T;
385 typedef typename TypeParam::Arch Arch;
386 typedef typename TypeParam::ComplexT ComplexT;
390 InputType input(0.066 * data::seconds, 1024, traits.template allocator<InputType>(device));
391 OutputType output(traits.template allocator<OutputType>(device));
392 traits.api().process(device, input, output);
393 ASSERT_EQ(output.size(), input.size());
394 ASSERT_EQ(output.frequency_step().value(), (1.0f/(input.sampling_interval().value() * input.size())));
398 template<
typename TypeParam>
400 , typename
std::enable_if<
401 !HasTime2Frequency<TypeParam
402 , typename TypeParam::ComplexT
403 , typename TypeParam::ComplexT
408 void exec(
typename TypeParam::DeviceType&)
410 std::cout <<
"Complex to Complex FT not defined for this device";
414 ALGORITHM_TYPED_TEST_P(
FftTester, fft_c2c_fwd)
419 template<
typename TypeParam,
typename Enable=
void>
423 void exec(
typename TypeParam::DeviceType& device)
426 typedef typename TypeParam::NumericalRep T;
427 typedef typename TypeParam::Arch Arch;
428 typedef typename TypeParam::ComplexT ComplexT;
432 InputType input(0.0035 * data::hz, 1024, traits.template allocator<InputType>(device));
433 OutputType output(traits.template allocator<OutputType>(device));
434 traits.api().process(device, input, output);
435 ASSERT_EQ(output.size(), input.size());
436 ASSERT_EQ(output.sampling_interval().value(), (1.0f/(input.frequency_step().value() * output.size())));
440 template<
typename TypeParam>
442 , typename
std::enable_if<
443 !HasFrequency2Time<TypeParam
444 , typename TypeParam::ComplexT
445 , typename TypeParam::ComplexT
450 void exec(
typename TypeParam::DeviceType&)
452 std::cout <<
"Complex to Complex Inverse FT not defined for this device";
456 ALGORITHM_TYPED_TEST_P(
FftTester, fft_c2c_inv)
463 REGISTER_TYPED_TEST_CASE_P(
FftTester, fft_r2c_zero, fft_r2c_c2r_delta, fft_r2c_shift, fft_c2c_fwd, fft_c2c_inv);
A container of Fourier series data.
Some limits and constants for FLDO.
Class for time series data.
static void exec(typename TypeParam::DeviceType &device)
TimeSeries<Complex> -> FrequencySeries<Complex>