TsSpectrum.h

Go to the documentation of this file.
00001 #ifndef TSSPECTRUM_H
00002 #define TSSPECTRUM_H
00003 
00004 #include "FatalException.h"
00005 #include <fftw3.h>
00006 #include "types.h"
00007 #include <boost/bind.hpp>
00008 #include <algorithm>
00009 
00010 namespace gplib
00011   {
00012 
00013     /** \addtogroup tstools Time series analysis methods */
00014     /* @{ */
00015 
00016     //! The class CTsSpectrum is used to calculate spectra from (real) time series data
00017     /*! CTsSpectrum is basically a wrapper for the fftw3 functionality for real data
00018      * it manages both the plans and the local data needed by fftw3. This class is not
00019      * thread-safe. DO NOT use it within an openmp parallelized loop or any kind of threaded program.
00020      */
00021     class TsSpectrum
00022       {
00023     private:
00024       //! FFTW3 provides facilities to speed up multiple calculations of similar data, MultiCalc determines whether we want to use this or just a simple fftw
00025       bool MultiCalc;
00026       //! If we called CalcSpectrum before this will be true, a fftw3 calculation plan exists that we might have to take care of
00027       bool ExistsPlanForward;
00028       //! If we called CalcTimeSeries before this will be true, a previous plan exists
00029       bool ExistsPlanReverse;
00030       //! What was the size of the last calculation
00031       int oldsize;
00032       //! fftw3 wants a raw C-array, one for the timedomain
00033       double *timedomain;
00034       //! the raw C-array fftw uses for the frequency domain
00035       fftw_complex *freqdomain;
00036       //! p_forward holds the plan for forward calculations
00037       fftw_plan p_forward;
00038       //! p_reverse holds the plan for reverse calculations
00039       fftw_plan p_reverse;
00040       //! A helper function that does some stuff to prepare  calculations
00041       void Prepare_Calculation(const int size);
00042       //! finish up after time series calculations
00043       void Finish_Calculation(const int size);
00044       //! We have to Assign memory for the raw c-arrays of fftw3 in the beginning and when the layout/size changes
00045       void AssignMem(const int size);
00046       //! When we reassign Memory and on exit we have to destroy the old memory structure
00047       void DestroyMem();
00048     public:
00049       //! The constructor is explicit to prohibit conversion from bool
00050       /*! The construtor takes an optional boolean value as an argument, that determines whether we want to use fftw's multiple calculation
00051        *  This makes only sense if we do a lot of calculations in the same direction and with the same length
00052        */
00053       explicit TsSpectrum(bool WantMultiCalc = false);
00054       virtual ~TsSpectrum();
00055       //! The member function to calculate a spectrum from a time series
00056       /*! Takes three iterators for input: beginning of input, end of input and beginning of output
00057        *  Make sure the structure pointed to by freqbegin can hold at least (tsend -tsbegin)/2 +1 elements
00058        */
00059       template<typename _InputIterator, typename _OutputIterator>
00060       void CalcSpectrum(_InputIterator tsbegin, _InputIterator tsend,
00061           _OutputIterator freqbegin, _OutputIterator freqend);
00062       //! The member function to calculate a time series from (complex) spectra
00063       /*! Takes three iterators for input: beginning of input, end of input and beginning of output
00064        *  Make sure the structure pointed to by tsbegin can hold at least (freqend -freqbegin)*2 - 2 elements
00065        */
00066       template<typename _InputIterator, typename _OutputIterator>
00067       void CalcTimeSeries(_InputIterator freqbegin, _InputIterator freqend,
00068           _OutputIterator tsbegin, _OutputIterator tsend);
00069       };
00070 
00071     //! Calculate a spectrum from the input range given by tsbegin and tsend and write to output range given by freqbegin,freqend
00072     /*! Calculate the fourier transform of a real valued time series. We specify the start and the end of both structures
00073      * to be able to check that the output structure can hold enough elements.
00074      * @param tsbegin The iterator to the start of the time series segment
00075      * @param tsend The iterator to the end of the time series segment
00076      * @param freqbegin The iterator to the start of the output structure, this has to be able to hold (tsend - tsbegin)/2 + 1 values
00077      * @param freqend The iterator to the end of the output structure, this has to be able to hold (tsend - tsbegin)/2 + 1 values
00078      */
00079     template<typename _InputIterator, typename _OutputIterator>
00080     void TsSpectrum::CalcSpectrum(_InputIterator tsbegin, _InputIterator tsend,
00081         _OutputIterator freqbegin, _OutputIterator freqend)
00082       {
00083         const int size = distance(tsbegin, tsend); // We calculate the size of the time series
00084         if (size < 0) // if negative we probably swapped iterators, throw error message
00085           throw FatalException("Negative size of input in CalcSpectrum !");
00086         if (distance(freqbegin, freqend) != size / 2 + 1)
00087           throw FatalException(
00088               "Time Series and Spectrum have incompatible size !");
00089         Prepare_Calculation(size); // Do the necessary preparations for Spectra calculations
00090         copy(tsbegin, tsend, timedomain); //copy data to ftw3 data structure
00091         fftw_execute(p_forward); // do the calculation
00092         for (int i = 0; i < size / 2 + 1; ++i, ++freqbegin)
00093           //copy back, considering the different layout
00094           *freqbegin = freqdomain[i][0] + I * freqdomain[i][1];
00095         Finish_Calculation(size); // finish up
00096       }
00097     //! Calculate a times series from the input range given by freqbegin and freqend and write to output range given by tsbegin,tsend
00098     /*! Calculate the inverse fourier transfrom from a given complex array/vector. We specify the start and the end of both structures
00099      * to be able to check that the output structure can hold enough elements.
00100      * @param freqbegin The iterator to the start of the structure holding the spectral elements
00101      * @param freqend The iterator to the end of the structure holding the spectral elements
00102      * @param tsbegin The iterator to the start of the output time series structure
00103      * @param tsend The iterator to the end of the output time series structure
00104      */
00105     template<typename _InputIterator, typename _OutputIterator>
00106     void TsSpectrum::CalcTimeSeries(_InputIterator freqbegin,
00107         _InputIterator freqend, _OutputIterator tsbegin, _OutputIterator tsend)
00108       {
00109         if (freqbegin > freqend || tsbegin > tsend) // if beginning after end, there is something wrong, throw error
00110           throw FatalException("Negative size of input in CalcTimeSeries !");
00111         const int size = distance(tsbegin, tsend); // the logical size for fftw3 is the length of the time series, for us too
00112         if (distance(freqbegin, freqend) != size / 2 + 1)
00113           throw FatalException(
00114               "Time Series and Spectrum have incompatible size !");
00115         Prepare_Calculation(size); // prepare stuff for calculation
00116         for (int i = 0; freqbegin != freqend; ++freqbegin, ++i) // copy frequency data into fftw3 c-array
00117           {
00118             freqdomain[i][0] = (*freqbegin).real();
00119             freqdomain[i][1] = (*freqbegin).imag();
00120           }
00121         fftw_execute(p_reverse); // do calculation
00122         double factor = 1. / double(size); // we have to normalize, so that back-and forward transformation yields the same result
00123         //copy to output and multiply each element by factor
00124         std::transform(timedomain, timedomain + size, tsbegin, boost::bind<
00125             double>(std::multiplies<double>(), factor, _1));
00126         Finish_Calculation(size); // finish up
00127       }
00128   /* @} */
00129   }
00130 #endif // CTSSPECTRUM_H

Generated on Tue May 4 16:52:15 2010 for GPLIB++ by  doxygen 1.5.8