GPLIB++
TsSpectrum.h
Go to the documentation of this file.
1 #ifndef TSSPECTRUM_H
2 #define TSSPECTRUM_H
3 
4 #include "FatalException.h"
5 #include <fftw3.h>
6 #include "types.h"
7 #include <boost/bind.hpp>
8 #include <algorithm>
9 
10 namespace gplib
11  {
12 
13  /** \addtogroup tstools Time series analysis methods */
14  /* @{ */
15 
16  //! The class CTsSpectrum is used to calculate spectra from (real) time series data
17  /*! CTsSpectrum is basically a wrapper for the fftw3 functionality for real data
18  * it manages both the plans and the local data needed by fftw3. This class is not
19  * thread-safe. DO NOT use it within an openmp parallelized loop or any kind of threaded program.
20  */
21  class TsSpectrum
22  {
23  private:
24  //! FFTW3 provides facilities to speed up multiple calculations of similar data, MultiCalc determines whether we want to use this or just a simple fftw
25  bool MultiCalc;
26  //! If we called CalcSpectrum before this will be true, a fftw3 calculation plan exists that we might have to take care of
27  bool ExistsPlanForward;
28  //! If we called CalcTimeSeries before this will be true, a previous plan exists
29  bool ExistsPlanReverse;
30  //! What was the size of the last calculation
31  int oldsize;
32  //! fftw3 wants a raw C-array, one for the timedomain
33  double *timedomain;
34  //! the raw C-array fftw uses for the frequency domain
35  fftw_complex *freqdomain;
36  //! p_forward holds the plan for forward calculations
37  fftw_plan p_forward;
38  //! p_reverse holds the plan for reverse calculations
39  fftw_plan p_reverse;
40  //! A helper function that does some stuff to prepare calculations
41  void Prepare_Calculation(const int size);
42  //! finish up after time series calculations
43  void Finish_Calculation(const int size);
44  //! We have to Assign memory for the raw c-arrays of fftw3 in the beginning and when the layout/size changes
45  void AssignMem(const int size);
46  //! When we reassign Memory and on exit we have to destroy the old memory structure
47  void DestroyMem();
48  public:
49  //! The constructor is explicit to prohibit conversion from bool
50  /*! The construtor takes an optional boolean value as an argument, that determines whether we want to use fftw's multiple calculation
51  * This makes only sense if we do a lot of calculations in the same direction and with the same length
52  */
53  explicit TsSpectrum(bool WantMultiCalc = false);
54  virtual ~TsSpectrum();
55  //! The member function to calculate a spectrum from a time series
56  /*! Takes three iterators for input: beginning of input, end of input and beginning of output
57  * Make sure the structure pointed to by freqbegin can hold at least (tsend -tsbegin)/2 +1 elements
58  */
59  template<typename _InputIterator, typename _OutputIterator>
60  void CalcSpectrum(_InputIterator tsbegin, _InputIterator tsend,
61  _OutputIterator freqbegin, _OutputIterator freqend);
62  //! The member function to calculate a time series from (complex) spectra
63  /*! Takes three iterators for input: beginning of input, end of input and beginning of output
64  * Make sure the structure pointed to by tsbegin can hold at least (freqend -freqbegin)*2 - 2 elements
65  */
66  template<typename _InputIterator, typename _OutputIterator>
67  void CalcTimeSeries(_InputIterator freqbegin, _InputIterator freqend,
68  _OutputIterator tsbegin, _OutputIterator tsend);
69  };
70 
71  //! Calculate a spectrum from the input range given by tsbegin and tsend and write to output range given by freqbegin,freqend
72  /*! Calculate the fourier transform of a real valued time series. We specify the start and the end of both structures
73  * to be able to check that the output structure can hold enough elements.
74  * @param tsbegin The iterator to the start of the time series segment
75  * @param tsend The iterator to the end of the time series segment
76  * @param freqbegin The iterator to the start of the output structure, this has to be able to hold (tsend - tsbegin)/2 + 1 values
77  * @param freqend The iterator to the end of the output structure, this has to be able to hold (tsend - tsbegin)/2 + 1 values
78  */
79  template<typename _InputIterator, typename _OutputIterator>
80  void TsSpectrum::CalcSpectrum(_InputIterator tsbegin, _InputIterator tsend,
81  _OutputIterator freqbegin, _OutputIterator freqend)
82  {
83  const int size = distance(tsbegin, tsend); // We calculate the size of the time series
84  if (size < 0) // if negative we probably swapped iterators, throw error message
85  throw FatalException("Negative size of input in CalcSpectrum !");
86  if (distance(freqbegin, freqend) != size / 2 + 1)
87  throw FatalException(
88  "Time Series and Spectrum have incompatible size !");
89  Prepare_Calculation(size); // Do the necessary preparations for Spectra calculations
90  copy(tsbegin, tsend, timedomain); //copy data to ftw3 data structure
91  fftw_execute(p_forward); // do the calculation
92  for (int i = 0; i < size / 2 + 1; ++i, ++freqbegin)
93  //copy back, considering the different layout
94  *freqbegin = freqdomain[i][0] + I * freqdomain[i][1];
95  Finish_Calculation(size); // finish up
96  }
97  //! Calculate a times series from the input range given by freqbegin and freqend and write to output range given by tsbegin,tsend
98  /*! Calculate the inverse fourier transfrom from a given complex array/vector. We specify the start and the end of both structures
99  * to be able to check that the output structure can hold enough elements.
100  * @param freqbegin The iterator to the start of the structure holding the spectral elements
101  * @param freqend The iterator to the end of the structure holding the spectral elements
102  * @param tsbegin The iterator to the start of the output time series structure
103  * @param tsend The iterator to the end of the output time series structure
104  */
105  template<typename _InputIterator, typename _OutputIterator>
106  void TsSpectrum::CalcTimeSeries(_InputIterator freqbegin,
107  _InputIterator freqend, _OutputIterator tsbegin, _OutputIterator tsend)
108  {
109  if (freqbegin > freqend || tsbegin > tsend) // if beginning after end, there is something wrong, throw error
110  throw FatalException("Negative size of input in CalcTimeSeries !");
111  const int size = distance(tsbegin, tsend); // the logical size for fftw3 is the length of the time series, for us too
112  if (distance(freqbegin, freqend) != size / 2 + 1)
113  throw FatalException(
114  "Time Series and Spectrum have incompatible size !");
115  Prepare_Calculation(size); // prepare stuff for calculation
116  for (int i = 0; freqbegin != freqend; ++freqbegin, ++i) // copy frequency data into fftw3 c-array
117  {
118  freqdomain[i][0] = (*freqbegin).real();
119  freqdomain[i][1] = (*freqbegin).imag();
120  }
121  fftw_execute(p_reverse); // do calculation
122  double factor = 1. / double(size); // we have to normalize, so that back-and forward transformation yields the same result
123  //copy to output and multiply each element by factor
124  std::transform(timedomain, timedomain + size, tsbegin, boost::bind<
125  double>(std::multiplies<double>(), factor, _1));
126  Finish_Calculation(size); // finish up
127  }
128  /* @} */
129  }
130 #endif // CTSSPECTRUM_H
void CalcSpectrum(_InputIterator tsbegin, _InputIterator tsend, _OutputIterator freqbegin, _OutputIterator freqend)
The member function to calculate a spectrum from a time series.
Definition: TsSpectrum.h:80
The class CTsSpectrum is used to calculate spectra from (real) time series data.
Definition: TsSpectrum.h:21
void CalcTimeSeries(_InputIterator freqbegin, _InputIterator freqend, _OutputIterator tsbegin, _OutputIterator tsend)
The member function to calculate a time series from (complex) spectra.
Definition: TsSpectrum.h:106
const int size
Definition: perftest.cpp:14
TsSpectrum(bool WantMultiCalc=false)
The constructor is explicit to prohibit conversion from bool.
Definition: TsSpectrum.cpp:9
virtual ~TsSpectrum()
Definition: TsSpectrum.cpp:34
The basic exception class for all errors that arise in gplib.