Waveform
Waveform is a C++ header-only library which represents both the time and the frequency domains of a waveform/signal as a single object, transforming using FFTW automatically when needed.
 All Classes Namespaces Functions Typedefs Friends Groups
FftwTransform_test.cpp
1 #include <iostream>
2 #include <fstream>
3 #include <vector>
4 #include <complex>
5 #include <iterator>
6 #include <algorithm>
7 #include <functional>
8 
9 
10 #include <boost/range.hpp>
11 #include <boost/range/algorithm.hpp>
12 
13 #include <FftwTransform.hpp>
14 #include <Waveform.hpp>
15 
16 #include <gtest/gtest.h>
17 
18 
19 #include <boost/archive/text_iarchive.hpp>
20 //#include <boost/archive/text_oarchive.hpp>
21 #include <boost/serialization/vector.hpp>
22 #include <boost/serialization/complex.hpp>
23 
24 
25 /*
26  To Do:
27 
28  [ ] Use Global Environment functionality for the test arrays loaded from files
29  [ ] Use type-parameterized tests so that any container can be tested without
30  needing to duplicate code
31  [ ] Use value-parameterized tests so that test arrays can be individually passed
32  to the tests for verification
33  */
34 
35 
36 
37 namespace {
38 
39 template <typename T>
40 std::vector<T>
41 parse_dat_file (std::string fileName)
42 {
43  std::ifstream ifs(fileName.c_str());
44  assert(ifs.good());
45 
46 
47  std::vector<T> result { std::istream_iterator<T>(ifs)
48  , std::istream_iterator<T>() };
49 
50  return result;
51 }
52 
53 
54 class FftwTransformTest : public ::testing::Test {
55  protected:
56 
57  FftwTransformTest()
58  {
59 
60  }
61 
62  virtual
63  ~FftwTransformTest()
64  {
65 
66  }
67 
68  virtual
69  void
70  SetUp()
71  {
72  /*
73  fDomain_.resize(tDomain_.size());
74 
75 
76  std::ofstream ofst("bs_FftwTransformTest_tDomain_.txt");
77  boost::archive::text_oarchive oat (ofst);
78  oat & tDomain_;
79 
80  std::ofstream ofsf("bs_FftwTransformTest_fDomain_.txt");
81  boost::archive::text_oarchive oaf (ofsf);
82  oaf & fDomain_;
83  */
84 
85  std::ifstream ifst("test_data/bs_FftwTransformTest_tDomain_.txt");
86  boost::archive::text_iarchive iat (ifst);
87  iat & tDomain_;
88 
89  std::ifstream ifsf("test_data/bs_FftwTransformTest_fDomain_.txt");
90  boost::archive::text_iarchive iaf (ifsf);
91  iaf & fDomain_;
92 
93 
94  stepFn1024_real = parse_dat_file<double>("test_data/stepFn1024_real.dat");
95  stepFn1024_complex = parse_dat_file<std::complex<double> >("test_data/stepFn1024_complex.dat");
96 
97  diracFn1024_real = parse_dat_file<double>("test_data/diracFn1024_real.dat");
98  diracFn1024_complex = parse_dat_file<std::complex<double> >("test_data/diracFn1024_complex.dat");
99 
100  triangleFn1024_real = parse_dat_file<double>("test_data/triangleFn1024_real.dat");
101  triangleFn1024_complex = parse_dat_file<std::complex<double> >("test_data/triangleFn1024_complex.dat");
102 
103  squareFn1024_real = parse_dat_file<double>("test_data/squareFn1024_real.dat");
104  squareFn1024_complex = parse_dat_file<std::complex<double> >("test_data/squareFn1024_complex.dat");
105 
106 
107  testArrays_real.push_back(stepFn1024_real);
108  testArrays_real.push_back(diracFn1024_real);
109  testArrays_real.push_back(triangleFn1024_real);
110  testArrays_real.push_back(squareFn1024_real);
111 
112  testArrays_complex.push_back(stepFn1024_complex);
113  testArrays_complex.push_back(diracFn1024_complex);
114  testArrays_complex.push_back(triangleFn1024_complex);
115  testArrays_complex.push_back(squareFn1024_complex);
116 
117 
118  /*
119  for (auto ar : testArrays_real)
120  std::cout << ar.size() << std::endl;
121 
122  for (auto ar : testArrays_complex)
123  std::cout << ar.size() << std::endl;
124  */
125 
126  }
127 
128  virtual
129  void
130  TearDown()
131  {
132 
133  }
134 
135  //blah
136 
137  double nearVal = 0.00001;
138 
139  std::vector<double> tDomain_;
140 
141 
142  std::vector< std::complex<double> > fDomain_;
143 
144 
145 
146  std::vector<double> stepFn1024_real;
147  std::vector< std::complex<double> > stepFn1024_complex;
148 
149  std::vector<double> diracFn1024_real;
150  std::vector< std::complex<double> > diracFn1024_complex;
151 
152  std::vector<double> triangleFn1024_real;
153  std::vector< std::complex<double> > triangleFn1024_complex;
154 
155  std::vector<double> squareFn1024_real;
156  std::vector< std::complex<double> > squareFn1024_complex;
157 
158  std::vector< std::vector<double> > testArrays_real;
159  std::vector< std::vector<std::complex<double> > > testArrays_complex;
160 
161 };
162 
163 
164 
165 /*
166 typedef testing::Types<Fftw3_Dft_1d, Fftw3_Dft_1d_Normalized> Implementations;
167 TYPED_TEST_CASE(FftwTransformTest, Implementations);
168 */
169 
170 TEST_F(FftwTransformTest, CTor1)
171 {
172  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
173 
174  std::vector< std::complex<double> > fresult (tDomain_.size() / 2 + 1);
175  FftwTransform myFT = FftwTransform(tDomain_.begin(), tDomain_.end(), fresult.begin());
176 
177  myFT.exec_transform();
178 
179 
180  for (unsigned iter (0); iter < fresult.size(); ++iter)
181  {
182  /*
183  EXPECT_DOUBLE_EQ( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)) ) << "\t@\t" << iter;
184  EXPECT_DOUBLE_EQ( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)) ) << "\t@\t" << iter;
185  */
186 
187  EXPECT_NEAR( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
188  EXPECT_NEAR( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
189 
190  }
191 }
192 
193 
194 TEST_F(FftwTransformTest, CTor2)
195 {
196 
197  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
198 
199  std::vector< std::complex<double> > fresult (tDomain_.size() / 2 + 1);
200  FftwTransform myFT = FftwTransform(tDomain_, fresult);
201 
202 
203  myFT.exec_transform();
204 
205 
206  for (unsigned iter (0); iter < fresult.size(); ++iter)
207  {
208  /*
209  EXPECT_DOUBLE_EQ( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)) ) << "\t@\t" << iter;
210  EXPECT_DOUBLE_EQ( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)) ) << "\t@\t" << iter;
211  */
212 
213  EXPECT_NEAR( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
214  EXPECT_NEAR( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
215 
216  }
217 
218 
219 }
220 
221 
222 
223 TEST_F(FftwTransformTest, FwTrans)
224 {
225  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
226 
227  std::vector< std::complex<double> > fresult (tDomain_.size() / 2 + 1);
228  FftwTransform myFT = FftwTransform(tDomain_.begin(), tDomain_.end(), fresult.begin());
229 
230  myFT.exec_transform();
231 
232 
233  for (unsigned iter (0); iter < fresult.size(); ++iter)
234  {
235  /*
236  EXPECT_DOUBLE_EQ( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)) ) << "\t@\t" << iter;
237  EXPECT_DOUBLE_EQ( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)) ) << "\t@\t" << iter;
238  */
239 
240  EXPECT_NEAR( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
241  EXPECT_NEAR( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
242 
243  }
244 
245 
246 /*
247  std::cout << "Time Domain:" << std::endl;
248  boost::copy(tDomain_, std::ostream_iterator< double >(std::cout, "\n"));
249 
250  std::cout << std::endl << std::endl
251  << "Freq Domain:" << std::endl;
252 
253  boost::copy(fDomain_, std::ostream_iterator< std::complex<double> >(std::cout, "\n"));
254  */
255 
256 
257 }
258 
259 
260 TEST_F(FftwTransformTest, FwTransTestArrays)
261 {
262  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
263 
264  //double new_nearVal = nearVal * 1.;
265 
266  for (std::size_t iter_array (0); iter_array < testArrays_real.size(); ++iter_array) {
267  std::vector< std::complex<double> > fresult (testArrays_real.at(iter_array).size() / 2 + 1);
268 
269  FftwTransform myFT = FftwTransform(testArrays_real.at(iter_array).begin(), testArrays_real.at(iter_array).end(), fresult.begin());
270 
271  myFT.exec_transform();
272 
273  EXPECT_EQ (fresult.size(), testArrays_complex.at(iter_array).size()) << iter_array;
274 
275  for (unsigned iter (0); iter < fresult.size(); ++iter)
276  {
277  /*
278  EXPECT_DOUBLE_EQ( std::real(fresult.at(iter)), std::real(fDomain_.at(iter)) ) << "\t@\t" << iter;
279  EXPECT_DOUBLE_EQ( std::imag(fresult.at(iter)), std::imag(fDomain_.at(iter)) ) << "\t@\t" << iter;
280  */
281 
282  EXPECT_NEAR( std::real(fresult.at(iter)), std::real(testArrays_complex.at(iter_array).at(iter)), nearVal ) << "\t@\t" << iter;
283  EXPECT_NEAR( std::imag(fresult.at(iter)), std::imag(testArrays_complex.at(iter_array).at(iter)), nearVal ) << "\t@\t" << iter;
284 
285  }
286  }
287 }
288 
289 
290 
291 TEST_F(FftwTransformTest, InvTrans)
292 {
293 
294  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
295 
296  //std::vector<double> tresult ( 2 * (fDomain_.size() - 1) );
297  std::vector<double> tresult (tDomain_.size());
298  FftwTransform myFT = FftwTransform(tresult.begin(), tresult.end(), fDomain_.begin());
299 
300  myFT.exec_inverse_transform();
301 
302  ASSERT_EQ( tresult.size(), tDomain_.size()) << "\tfDomain size:\t" << fDomain_.size();
303 
304 
305  for (auto& val : tresult)
306  {
307  val /= double(tresult.size());
308  }
309 
310  for (unsigned iter (0); iter < tresult.size(); ++iter)
311  {
312  EXPECT_NEAR( tresult.at(iter), tDomain_.at(iter), nearVal ) << "\t@\t" << iter << "\tFactor:\t" << tresult.at(iter) / tDomain_.at(iter);
313  }
314 
315 }
316 
317 
318 
319 TEST_F(FftwTransformTest, ParameterForWaveform)
320 {
321  //std::vector< std::complex<double> > fresult (tDomain_.size() / 2 + 1);
322 
323  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
324 
326  , std::vector< std::complex<double> >
327  , FftwTransform
328  > myWfm (tDomain_);
329 
330  EXPECT_EQ(tDomain_.size(), myWfm.size());
331 
332 
333  for (unsigned iter (0); iter < myWfm.size(); ++iter)
334  {
335  EXPECT_EQ(tDomain_.at(iter), myWfm.GetConstTimeSeries().at(iter));
336  }
337 }
338 
339 
340 
341 TEST_F(FftwTransformTest, FwdTransformInWaveform)
342 {
343 
344  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
345 
346  //std::vector< std::complex<double> > fresult (tDomain_.size() / 2 + 1);
347 
349  , std::vector< std::complex<double> >
350  , FftwTransform
351  > myWfm (tDomain_);
352 
353  myWfm.GetConstFreqSpectrum();
354 
355  // Because fDomain comes from Mathematica, there are around twice the number of bins as in FFTW
356  EXPECT_EQ(fDomain_.size() / 2 + 1, myWfm.GetConstFreqSpectrum().size());
357 
358  for (unsigned iter (0); iter < myWfm.GetConstFreqSpectrum().size(); ++iter)
359  {
360 
361  EXPECT_NEAR( std::real(myWfm.GetConstFreqSpectrum().at(iter)), std::real(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
362  EXPECT_NEAR( std::imag(myWfm.GetConstFreqSpectrum().at(iter)), std::imag(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
363 
364  }
365 }
366 
367 TEST_F(FftwTransformTest, RvsTransformInWaveform)
368 {
369 
370  typedef Waveform::Transform::Fftw3_Dft_1d FftwTransform;
371 
372  std::vector<std::complex<double> > fDomainProper (fDomain_.begin(), fDomain_.begin() + 131);
373 
375  , std::vector< std::complex<double> >
376  , FftwTransform
377  > myWfm (fDomainProper);
378 
379  myWfm.GetConstTimeSeries();
380 
381  /*
382  for (unsigned iter (0); iter < myWfm.GetConstFreqSpectrum().size(); ++iter)
383  {
384  EXPECT_NEAR( std::real(myWfm.GetConstFreqSpectrum().at(iter)), std::real(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
385  EXPECT_NEAR( std::imag(myWfm.GetConstFreqSpectrum().at(iter)), std::imag(fDomain_.at(iter)), nearVal ) << "\t@\t" << iter;
386  }
387  */
388 
389 
390  //std::transform(myWfm.beginTime(), myWfm.endTime(), myWfm.beginTime(), [](auto x){return x/myWfm.size()});
391 
392  for (auto& val : myWfm.GetTimeSeries())
393  {
394  val /= myWfm.size();
395  }
396 
397  EXPECT_EQ(tDomain_.size(), myWfm.GetConstTimeSeries().size());
398 
399  for (unsigned iter (0); iter < myWfm.GetConstTimeSeries().size(); ++iter)
400  {
401  EXPECT_NEAR(myWfm.GetTimeSeries().at(iter), tDomain_.at(iter), nearVal) << "\t@\t" << iter;
402  }
403 }
404 
405 
406 } // namespace
407 
408 int
409 main (int argc, char** argv)
410 {
411  ::testing::InitGoogleTest(&argc, argv);
412  return RUN_ALL_TESTS();
413 }
414 
415 
Waveform class: Transform as-needed between time and freq domains.
Definition: Waveform.hpp:131