JASPL  0.2
Just Another Signal Processing Library
test_jfft.h
1 #ifndef TEST_JFFT_H
2 #define TEST_JFFT_H
3 
4 //C System-Headers
5 //
6 //C++ System headers
7 #include <cmath>
8 #include <limits>
9 #include <iomanip>
10 #include <iostream>
11 #include <type_traits>
12 #include <algorithm>
13 #include <vector>
14 // FFTW Headers
15 //
16 // Boost Headers
17 //
18 // Google Test
19 #include <gtest/gtest.h>
20 //Project specific headers
21 #include "jfft.h"
22 #include "../jPlot/jplot.h"
23 
24 template<class T>
25 typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
26 almost_equal(T x, T y, int ulp) {
27  // the machine epsilon has to be scaled to the magnitude of the values used
28  // and multiplied by the desired precision in ULPs (units in the last place)
29  return std::abs(x-y) < std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
30  // unless the result is subnormal
31  || std::abs(x-y) < std::numeric_limits<T>::min();
32 }
33 
34 double sqr_sum( const std::vector< double >& signal ) {
35 
36  double tot = 0.0;
37 
38  for ( const auto& val : signal ) {
39  tot += val*val;
40  }
41 
42  return tot;
43 }
44 
45 double sum( const std::vector< double >& signal ) {
46 
47  double tot = 0.0;
48 
49  for ( const auto& val : signal ) {
50  tot += val;
51  }
52 
53  return tot;
54 }
55 
56 std::vector< double > build_test_signal( uint N ) {
57 
58  std::vector< double > sin_vect;
59  sin_vect.reserve( N );
60 
61  double N_f = static_cast<double>( N );
62 
63  for ( uint i = 0; i < N ; i++ ) {
64 
65  double x = static_cast< double >( i )/N_f;
66 
67  sin_vect.push_back( 0.25*std::sin( (5.0)*(2.0*M_PI)*x ) );
68  }
69 
70  return sin_vect;
71 }
72 
73 namespace jaspl {
74 
75 void TestJFFT( const uint signal_size ) {
76 
77  JFFT< std::vector< double > > fft_er( true );
78 
79  std::vector< double > signal = build_test_signal( signal_size );
80 
81  double time_series_tot_pow = sqr_sum( signal );
82 
83  plot( signal, "Times Series" );
84 
85  fft_er.SetUp( signal_size );
86 
87  std::vector< double > power_spectrum = fft_er.PowerSpectrum( signal );
88 
89  double power_spectrum_tot_pow = 2.0*sum( power_spectrum );
90 
91  std::for_each(power_spectrum.begin(), power_spectrum.end(), [=](double &x){std::sqrt(x); });
92 
93  plot( power_spectrum, "Power Spectrum" );
94 
95 
96  if( !almost_equal( time_series_tot_pow, power_spectrum_tot_pow, 2 ) ) {
97 
98  std::cout << "Parseval's theorem has been violated." << std::endl;
99 
100  std::cout << "Square sum of time series values: "
101  << time_series_tot_pow
102  << " Square sum of power spectrum values: "
103  << power_spectrum_tot_pow
104  << "\n"
105  << std::endl;
106 
107  std::cout << "Power spectrum differs by multiplicative factor of: "
108  << power_spectrum_tot_pow/time_series_tot_pow
109  << std::endl;
110 
111  } else {
112 
113  std::cout << "Parseval's theorem holds." << std::endl;
114 
115  std::cout << "Square sum of time series values: "
116  << time_series_tot_pow
117  << " Square sum of power spectrum values: "
118  << power_spectrum_tot_pow
119  << "\n"
120  << std::endl;
121  }
122 
123 }
124 
125 void RunTestJFFT() {
126 
127  for ( uint i = 2 ; i < std::pow( 2, 12 ); i *= 2 ) {
128 
129  std::cout << "Testing JFFT for signal of size "
130  << i
131  << std::endl;
132 
133  TestJFFT( i );
134  }
135 }
136 
137 }
138 
139 #endif // TEST_JFFT_H