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
Public Types | Public Member Functions | Friends | List of all members
PS::Waveform< TimeContainer, FreqContainer, TransformT > Class Template Reference

Waveform class: Transform as-needed between time and freq domains. More...

#include <Waveform.hpp>

Public Types

enum  DomainSpecifier { TimeDomain, FreqDomain, EitherDomain }
 
typedef TimeContainer::value_type TimeT
 The type of the time domain.
 
typedef FreqContainer::value_type FreqT
 The type of the frequency domain.
 
typedef std::pair< TimeT, FreqTvalue_type
 The "type" of the Waveform, inspired by std::map.
 
typedef
TimeContainer::allocator_type 
TimeAllocT
 The allocator type of the time domain container.
 
typedef
FreqContainer::allocator_type 
FreqAllocT
 The allocator type of the frequency domain container.
 
typedef TimeContainer::iterator TimeIterator
 The iterator type of the time domain container.
 
typedef FreqContainer::iterator FreqIterator
 The iterator type of the frequency domain container.
 
typedef
TimeContainer::const_iterator 
TimeConstIterator
 The const iterator type of the time domain container.
 
typedef
FreqContainer::const_iterator 
FreqConstIterator
 The const iterator type of the frequency domain container.
 

Public Member Functions

 Waveform (const std::size_t count)
 Fill constructor.
 
 Waveform (const Waveform &toCopy)
 Copy constructor.
 
 Waveform (const TimeContainer &toCopy)
 Time domain copy constructor.
 
 Waveform (const FreqContainer &toCopy)
 Frequency domain copy constructor.
 
 ~Waveform (void)
 Default destructor.
 
std::size_t GetSize (void)
 Returns the size of the time domain container. More...
 
std::size_t size (void)
 Returns the size of the time domain container.
 
const TimeContainer & GetConstTimeSeries (void)
 Returns constant reference to the time domain container. More...
 
const FreqContainer & GetConstFreqSpectrum (void)
 Returns constant reference to the frequency domain container. More...
 
TimeContainer & GetTimeSeries (void)
 Returns mutable reference to the time domain container. More...
 
FreqContainer & GetFreqSpectrum (void)
 Returns mutable reference to the frequency domain container. More...
 
int ValidateDomain (const DomainSpecifier toValidate)
 Validate and ensure that the specified domain is up-to-date. More...
 
Waveformoperator= (Waveform rhs)
 Copy-assignment operator. More...
 
 Waveform (Waveform &&rhs)
 Move constructor (C++11) More...
 

Friends

void swap (Waveform &first, Waveform &second)
 Swaps two values without throwing. More...
 

Detailed Description

template<typename TimeContainer, typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
class PS::Waveform< TimeContainer, FreqContainer, TransformT >

Waveform class: Transform as-needed between time and freq domains.

The Waveform class allows automatic transform (via FFTW) between time and frequency domains.

Upon instantiation, one domain is made "active", and the other domain will not be calculated until requested.

When one domain is modified, the other domain will be invalidated and must be recalculated upon next request.

After a transform is completed, both domains will be valid until one is modified.

Definition at line 131 of file Waveform.hpp.

Constructor & Destructor Documentation

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
PS::Waveform< TimeContainer, FreqContainer, TransformT >::Waveform ( Waveform< TimeContainer, FreqContainer, TransformT > &&  rhs)
inline

Move constructor (C++11)

When rhs is just an rvalue, C++11 can make use of move semantics, instead of copying values from memory to memory, the references are swapped, in the exact same way they were for the copy assignment operator.

This particular function also uses constructor delegation, a feature which is not present for all compiler's implementations of C++11.

Definition at line 557 of file Waveform.hpp.

Member Function Documentation

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
const FreqContainer& PS::Waveform< TimeContainer, FreqContainer, TransformT >::GetConstFreqSpectrum ( void  )
inline

Returns constant reference to the frequency domain container.

Pass "EitherDomain" because domain will not be modified. Unfortunately the const keyword cannot be used here, because ValidateDomain(...) could modify the class.

If enough thought went into it, there could be a way to separate these cases and use overloading between the non-const and const member methods.

Definition at line 300 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
const TimeContainer& PS::Waveform< TimeContainer, FreqContainer, TransformT >::GetConstTimeSeries ( void  )
inline

Returns constant reference to the time domain container.

Pass "EitherDomain" because domain will not be modified.

Unfortunately the const keyword cannot be used here, because ValidateDomain(...) could modify the class.

If enough thought went into it, there could be a way to separate these cases and use overloading between the non-const and const member methods.

Definition at line 285 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
FreqContainer& PS::Waveform< TimeContainer, FreqContainer, TransformT >::GetFreqSpectrum ( void  )
inline

Returns mutable reference to the frequency domain container.

If the frequency domain is not valid, the forward transform will automatically calculate the appropriate values behind the scenes, given the valid time domain; returns when complete.

Definition at line 322 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
std::size_t PS::Waveform< TimeContainer, FreqContainer, TransformT >::GetSize ( void  )
inline

Returns the size of the time domain container.

<This function seems redundant and will likely be removed. Use Waveform::size() instead, since it's STL-compliant (though this class is difficult to design 100% in line with the STL idioms)>

Definition at line 263 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
TimeContainer& PS::Waveform< TimeContainer, FreqContainer, TransformT >::GetTimeSeries ( void  )
inline

Returns mutable reference to the time domain container.

If the time domain is not valid, the inverse/reverse transform will automatically calculate the appropriate values behind the scenes, given the valid frequency domain; returns when complete.

Definition at line 311 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
Waveform& PS::Waveform< TimeContainer, FreqContainer, TransformT >::operator= ( Waveform< TimeContainer, FreqContainer, TransformT >  rhs)
inline

Copy-assignment operator.

We need to make sure that copy assignment is without errors, and we can do that using the copy-and-swap idiom.

The values of the lhs and rhs are swapped, not even requiring a check for self-assignment.

Because the operator accepts rhs by value (and mutable), once inside the function rhs is an rvalue, which means that after the two are swapped, the swapped-away object is a temporary rvalue at the end of the scope, destroyed just as the previous value of rhs is returned as "*this", so there is no opportunity for something to throw after the old value was destroyed.

No need to worry about explicit calls to delete/ delete [], and the compiler can basically optimize away the entire transaction using Return Value Optimization (RVO)

Definition at line 539 of file Waveform.hpp.

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
int PS::Waveform< TimeContainer, FreqContainer, TransformT >::ValidateDomain ( const DomainSpecifier  toValidate)
inline

Validate and ensure that the specified domain is up-to-date.

This function is responsible for properly performing transforms based on which domain(s) are valid as well as the domain which was requested by the programmer.

As a reminder, DomainSpecifier is an enumeration which can be set to one of 3 unique values: TimeDomain, FreqDomain, EitherDomain.

The variable validDomain_ maintains the current state of the system. Each of the values of validDomain_ and their meaning are described below:

TimeDomain      the time domain array timeSeries_ is valid,
                while the contents of freqSpectrum_ should be
                assumed to be out of date / invalid.

FreqDomain      the freq domain array freqSpectrum_ is valid,
                while the contents of timeSeries_ should be
                assumed to be out of date / invalid.

EitherDomain    this has to meanings, both of which ultimately
                can be treated the same way:
                    1:  The last domain requested was done so
                        using one of the "Const" accessor
                        functions, so both of the domain arrays
                        may be read and modified from this
                        state.
                    2:  The Waveform was just constructed and
                        neither of the domain arrays contain
                        "useful" (useful to the user)
                        information. This means that either of
                        the domain arrays may be written to
                        without worrying about the validity of
                        the other domain. However, this also
                        means that neither of the domain arrays
                        can be read to provide valid data, but
                        since the user just initialized the
                        object they should be aware in any
                        circumstance that the arrays contain
                        only garbage.

The function parameter toValidate can take on those same three values, this time with slightly different meanings:

TimeDomain      the time domain array was requested and
                transforms should be performed as needed in
                order to validate the domain.

FreqDomain      the freq domain array was requested and
                transforms should be performed as needed in
                order to validate the domain.

EitherDomain    the request for one of the domain arrays was
                of the "Const" variety, so no matter which
                domain the user wanted, both domain arrays
                will be valid after the call. Using
                EitherDomain like this allows the
                implementation to be much simpler.

Because this is the core mechanism of the library, it's important to note that the use of EitherDomain like this is fundamentally reliant on the transform class used for the Waveform classes' template parameter TransformT providing two functions which (along with the dataset) form a group (by the definition of group theory). This means that the transform $\mathcal{F}$ and its inverse $\mathcal{F}^{-1}$ must be unitary – that is, they must satisfy the composition criteria

$\mathcal{F}^{-1} \circ \mathcal{F} (x) = id (x)$

(which is of course the definition of an inverse function!)

This may seem obvious given the mathematical definition of, say, the Fourier transform, but one of the most popular implementations, FFTW3 (http://www.fftw.org), does not provide real-to-complex forward- and inverse-transform functions which are true inverses of the other – the inverse transform of the "...dft_r2c_1d" transform function is the "...dft_c2r_1d" function which results in a scaled inverse. These transforms could be called "scaled unitary" or, but must be rescaled in order to function properly in this library.

You can use transforms which are involutary functions (such as the Laplace transform) by defining both "exec_transform()" and "exec_inverse_transform()" (both are required functions of a compatible TransformT class) to simply call the same function for both.

Definition at line 450 of file Waveform.hpp.

Friends And Related Function Documentation

template<typename TimeContainer , typename FreqContainer = TimeContainer, typename TransformT = PlaceholderTransformClass>
void swap ( Waveform< TimeContainer, FreqContainer, TransformT > &  first,
Waveform< TimeContainer, FreqContainer, TransformT > &  second 
)
friend

Swaps two values without throwing.

Because timeSeries_ and freqSpectrum_ are large container objects, there's a good chance that an overloaded swap function was written for them.

In the event that swap was not specialized for one of the member object types, we bring std::swap into the scope so that way all swap functions may be found using unqualified lookup.

This is necessary for the overloads to work. The concept is coined "Argument-Dependant Lookup", or ADL.

None of the swaps should throw, but the order in which the member objects are swapped could still matter.

It's also possible that the transform_ object doesn't need to have any state of its own and only wrap functions, but I'm not sure if there is an easy way to attempt that.

Definition at line 500 of file Waveform.hpp.


The documentation for this class was generated from the following file: