mirror of
https://github.com/mborgerding/kissfft.git
synced 2025-06-04 01:28:23 -04:00
Added FFT from real input. Improved documentation.
This commit is contained in:
parent
0395af753e
commit
1fbc2b6ab4
80
kissfft.hh
80
kissfft.hh
@ -22,7 +22,7 @@ class kissfft
|
|||||||
_twiddles.resize(_nfft);
|
_twiddles.resize(_nfft);
|
||||||
const scalar_type phinc = (_inverse?2:-2)* acos( (scalar_type) -1) / _nfft;
|
const scalar_type phinc = (_inverse?2:-2)* acos( (scalar_type) -1) / _nfft;
|
||||||
for (std::size_t i=0;i<_nfft;++i)
|
for (std::size_t i=0;i<_nfft;++i)
|
||||||
_twiddles[i] = std::exp( cpx_type(0,i*phinc) );
|
_twiddles[i] = exp( cpx_type(0,i*phinc) );
|
||||||
|
|
||||||
//factorize
|
//factorize
|
||||||
//start factoring out 4's, then 2's, then 3,5,7,9,...
|
//start factoring out 4's, then 2's, then 3,5,7,9,...
|
||||||
@ -44,12 +44,90 @@ class kissfft
|
|||||||
}while(n>1);
|
}while(n>1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the complex Discrete Fourier Transform.
|
||||||
|
///
|
||||||
|
/// The size of the passed arrays must be passed in the constructor.
|
||||||
|
/// The sum of the squares of the absolute values in the @c dst
|
||||||
|
/// array will be @c N times the sum of the squares of the absolute
|
||||||
|
/// values in the @c src array, where @c N is the size of the array.
|
||||||
|
/// In other words, the l_2 norm of the resulting array will be
|
||||||
|
/// @c sqrt(N) times as big as the l_2 norm of the input array.
|
||||||
|
/// This is also the case when the inverse flag is set in the
|
||||||
|
/// constructor. Hence when applying the same transform twice, but with
|
||||||
|
/// the inverse flag changed the second time, then the result will
|
||||||
|
/// be equal to the original input times @c N.
|
||||||
void transform( const cpx_type * src,
|
void transform( const cpx_type * src,
|
||||||
cpx_type * dst ) const
|
cpx_type * dst ) const
|
||||||
{
|
{
|
||||||
kf_work(0, dst, src, 1,1);
|
kf_work(0, dst, src, 1,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the Discrete Fourier Transform (DFT) of a real input
|
||||||
|
/// of size @c 2*N.
|
||||||
|
///
|
||||||
|
/// The 0-th and N-th value of the DFT are real numbers. These are
|
||||||
|
/// stored in @c dst[0].real() and @c dst[1].imag() respectively.
|
||||||
|
/// The remaining DFT values up to the index N-1 are stored in
|
||||||
|
/// @c dst[1] to @c dst[N-1].
|
||||||
|
/// The other half of the DFT values can be calculated from the
|
||||||
|
/// symmetry relation
|
||||||
|
/// @code
|
||||||
|
/// DFT(src)[2*N-k] == conj( DFT(src)[k] );
|
||||||
|
/// @endcode
|
||||||
|
/// The same scaling factors as in @c transform() apply.
|
||||||
|
///
|
||||||
|
/// @note For this to work, the types @c scalar_type and @c cpx_type
|
||||||
|
/// must fulfill the following requirements:
|
||||||
|
///
|
||||||
|
/// For any object @c z of type @c cpx_type,
|
||||||
|
/// @c reinterpret_cast<scalar_type(&)[2]>(z)[0] is the real part of @c z and
|
||||||
|
/// @c reinterpret_cast<scalar_type(&)[2]>(z)[1] is the imaginary part of @c z.
|
||||||
|
/// For any pointer to an element of an array of @c cpx_type named @c p
|
||||||
|
/// and any valid array index @c i, @c reinterpret_cast<T*>(p)[2*i]
|
||||||
|
/// is the real part of the complex number @c p[i], and
|
||||||
|
/// @c reinterpret_cast<T*>(p)[2*i+1] is the imaginary part of the
|
||||||
|
/// complex number @c p[i].
|
||||||
|
///
|
||||||
|
/// Since C++11, these requirements are guaranteed to be satisfied for
|
||||||
|
/// @c scalar_types being @c float, @c double or @c long @c double
|
||||||
|
/// together with @c cpx_type being @c std::complex<scalar_type>.
|
||||||
|
void transform_real( const scalar_type * src,
|
||||||
|
cpx_type * dst ) const
|
||||||
|
{
|
||||||
|
const std::size_t N = _nfft;
|
||||||
|
if ( N == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// perform complex FFT
|
||||||
|
transform( reinterpret_cast<const cpx_type*>(src), dst );
|
||||||
|
|
||||||
|
// post processing for k = 0 and k = N
|
||||||
|
dst[0] = cpx_type( dst[0].real() + dst[0].imag(),
|
||||||
|
dst[0].real() - dst[0].imag() );
|
||||||
|
|
||||||
|
// post processing for all the other k = 1, 2, ..., N-1
|
||||||
|
const scalar_type pi = acos( (scalar_type) -1);
|
||||||
|
const scalar_type half_phi_inc = ( _inverse ? pi : -pi ) / N;
|
||||||
|
const cpx_type twiddle_mul = exp( cpx_type(0, half_phi_inc) );
|
||||||
|
for ( std::size_t k = 1; 2*k < N; ++k )
|
||||||
|
{
|
||||||
|
const cpx_type w = 0.5 * cpx_type(
|
||||||
|
dst[k].real() + dst[N-k].real(),
|
||||||
|
dst[k].imag() - dst[N-k].imag() );
|
||||||
|
const cpx_type z = 0.5 * cpx_type(
|
||||||
|
dst[k].imag() + dst[N-k].imag(),
|
||||||
|
-dst[k].real() + dst[N-k].real() );
|
||||||
|
const cpx_type twiddle =
|
||||||
|
k % 2 == 0 ?
|
||||||
|
_twiddles[k/2] :
|
||||||
|
_twiddles[k/2] * twiddle_mul;
|
||||||
|
dst[ k] = w + twiddle * z;
|
||||||
|
dst[N-k] = conj( w - twiddle * z );
|
||||||
|
}
|
||||||
|
if ( N % 2 == 0 )
|
||||||
|
dst[N/2] = conj( dst[N/2] );
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void kf_work( std::size_t stage,
|
void kf_work( std::size_t stage,
|
||||||
cpx_type * Fout,
|
cpx_type * Fout,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user