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.
|
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, FreqT > | value_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... | |
Waveform & | operator= (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... | |
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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 and its inverse
must be unitary – that is, they must satisfy the composition criteria
(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.
|
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.