Eigen-unsupported  3.4.90 (git rev 9589cc4e7fd8e4538bedef80dd36c7738977a8be)
 
Loading...
Searching...
No Matches
FFT
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2009 Mark Borgerding mark a borgerding net
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
10#ifndef EIGEN_FFT_MODULE_H
11#define EIGEN_FFT_MODULE_H
12
13#include <complex>
14#include <vector>
15#include <map>
16#include "../../Eigen/Core"
17
80
81#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"
82
83// IWYU pragma: begin_exports
84
85#ifdef EIGEN_FFTW_DEFAULT
86// FFTW: faster, GPL -- incompatible with Eigen in LGPL form, bigger code size
87#include <fftw3.h>
88#include "src/FFT/ei_fftw_impl.h"
89namespace Eigen {
90// template <typename T> typedef struct internal::fftw_impl default_fft_impl; this does not work
91template <typename T>
92struct default_fft_impl : public internal::fftw_impl<T> {};
93} // namespace Eigen
94#elif defined EIGEN_MKL_DEFAULT
95// intel Math Kernel Library: fastest, free -- may be incompatible with Eigen in GPL form
96#include "src/FFT/ei_imklfft_impl.h"
97namespace Eigen {
98template <typename T>
99struct default_fft_impl : public internal::imklfft::imklfft_impl<T> {};
100} // namespace Eigen
101#elif defined EIGEN_POCKETFFT_DEFAULT
102// internal::pocketfft_impl: a heavily modified implementation of FFTPack, with many advantages.
103#include <pocketfft_hdronly.h>
104#include "src/FFT/ei_pocketfft_impl.h"
105namespace Eigen {
106template <typename T>
107struct default_fft_impl : public internal::pocketfft_impl<T> {};
108} // namespace Eigen
109#else
110// internal::kissfft_impl: small, free, reasonably efficient default, derived from kissfft
111#include "src/FFT/ei_kissfft_impl.h"
112namespace Eigen {
113template <typename T>
114struct default_fft_impl : public internal::kissfft_impl<T> {};
115} // namespace Eigen
116#endif
117
118// IWYU pragma: end_exports
119
120namespace Eigen {
121
122//
123template <typename T_SrcMat, typename T_FftIfc>
124struct fft_fwd_proxy;
125template <typename T_SrcMat, typename T_FftIfc>
126struct fft_inv_proxy;
127
128namespace internal {
129template <typename T_SrcMat, typename T_FftIfc>
130struct traits<fft_fwd_proxy<T_SrcMat, T_FftIfc> > {
131 typedef typename T_SrcMat::PlainObject ReturnType;
132};
133template <typename T_SrcMat, typename T_FftIfc>
134struct traits<fft_inv_proxy<T_SrcMat, T_FftIfc> > {
135 typedef typename T_SrcMat::PlainObject ReturnType;
136};
137} // namespace internal
138
139template <typename T_SrcMat, typename T_FftIfc>
140struct fft_fwd_proxy : public ReturnByValue<fft_fwd_proxy<T_SrcMat, T_FftIfc> > {
141 typedef DenseIndex Index;
142
143 fft_fwd_proxy(const T_SrcMat& src, T_FftIfc& fft, Index nfft) : m_src(src), m_ifc(fft), m_nfft(nfft) {}
144
145 template <typename T_DestMat>
146 void evalTo(T_DestMat& dst) const;
147
148 Index rows() const { return m_src.rows(); }
149 Index cols() const { return m_src.cols(); }
150
151 protected:
152 const T_SrcMat& m_src;
153 T_FftIfc& m_ifc;
154 Index m_nfft;
155};
156
157template <typename T_SrcMat, typename T_FftIfc>
158struct fft_inv_proxy : public ReturnByValue<fft_inv_proxy<T_SrcMat, T_FftIfc> > {
159 typedef DenseIndex Index;
160
161 fft_inv_proxy(const T_SrcMat& src, T_FftIfc& fft, Index nfft) : m_src(src), m_ifc(fft), m_nfft(nfft) {}
162
163 template <typename T_DestMat>
164 void evalTo(T_DestMat& dst) const;
165
166 Index rows() const { return m_src.rows(); }
167 Index cols() const { return m_src.cols(); }
168
169 protected:
170 const T_SrcMat& m_src;
171 T_FftIfc& m_ifc;
172 Index m_nfft;
173};
174
175template <typename T_Scalar, typename T_Impl = default_fft_impl<T_Scalar> >
176class FFT {
177 public:
178 typedef T_Impl impl_type;
179 typedef DenseIndex Index;
180 typedef typename impl_type::Scalar Scalar;
181 typedef typename impl_type::Complex Complex;
182
183 using Flag = int;
184 static constexpr Flag Default = 0;
185 static constexpr Flag Unscaled = 1;
186 static constexpr Flag HalfSpectrum = 2;
187 static constexpr Flag Speedy = 32767;
188
189 FFT(const impl_type& impl = impl_type(), Flag flags = Default) : m_impl(impl), m_flag(flags) {
190 eigen_assert((flags == Default || flags == Unscaled || flags == HalfSpectrum || flags == Speedy) &&
191 "invalid flags argument");
192 }
193
194 inline bool HasFlag(Flag f) const { return (m_flag & (int)f) == f; }
195
196 inline void SetFlag(Flag f) { m_flag |= (int)f; }
197
198 inline void ClearFlag(Flag f) { m_flag &= (~(int)f); }
199
200 inline void fwd(Complex* dst, const Scalar* src, Index nfft) {
201 m_impl.fwd(dst, src, static_cast<int>(nfft));
202 if (HasFlag(HalfSpectrum) == false) ReflectSpectrum(dst, nfft);
203 }
204
205 inline void fwd(Complex* dst, const Complex* src, Index nfft) { m_impl.fwd(dst, src, static_cast<int>(nfft)); }
206
207#if defined EIGEN_FFTW_DEFAULT || defined EIGEN_POCKETFFT_DEFAULT || defined EIGEN_MKL_DEFAULT
208 inline void fwd2(Complex* dst, const Complex* src, int n0, int n1) { m_impl.fwd2(dst, src, n0, n1); }
209#endif
210
211 template <typename Input_>
212 inline void fwd(std::vector<Complex>& dst, const std::vector<Input_>& src) {
213 if (NumTraits<Input_>::IsComplex == 0 && HasFlag(HalfSpectrum))
214 dst.resize((src.size() >> 1) + 1); // half the bins + Nyquist bin
215 else
216 dst.resize(src.size());
217 fwd(&dst[0], &src[0], src.size());
218 }
219
220 template <typename InputDerived, typename ComplexDerived>
221 inline void fwd(MatrixBase<ComplexDerived>& dst, const MatrixBase<InputDerived>& src, Index nfft = -1) {
222 typedef typename ComplexDerived::Scalar dst_type;
223 typedef typename InputDerived::Scalar src_type;
224 EIGEN_STATIC_ASSERT_VECTOR_ONLY(InputDerived)
225 EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
226 EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived, InputDerived) // size at compile-time
227 EIGEN_STATIC_ASSERT(
228 (internal::is_same<dst_type, Complex>::value),
229 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
230 EIGEN_STATIC_ASSERT(int(InputDerived::Flags) & int(ComplexDerived::Flags) & DirectAccessBit,
231 THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
232
233 if (nfft < 1) nfft = src.size();
234
235 Index dst_size = nfft;
236 if (NumTraits<src_type>::IsComplex == 0 && HasFlag(HalfSpectrum)) {
237 dst_size = (nfft >> 1) + 1;
238 }
239 dst.derived().resize(dst_size);
240
241 if (src.innerStride() != 1 || src.size() < nfft) {
242 Matrix<src_type, 1, Dynamic> tmp;
243 if (src.size() < nfft) {
244 tmp.setZero(nfft);
245 tmp.block(0, 0, src.size(), 1) = src;
246 } else {
247 tmp = src;
248 }
249 if (dst.innerStride() != 1) {
250 Matrix<dst_type, 1, Dynamic> out(1, dst_size);
251 fwd(&out[0], &tmp[0], nfft);
252 dst.derived() = out;
253 } else {
254 fwd(&dst[0], &tmp[0], nfft);
255 }
256 } else {
257 if (dst.innerStride() != 1) {
258 Matrix<dst_type, 1, Dynamic> out(1, dst_size);
259 fwd(&out[0], &src[0], nfft);
260 dst.derived() = out;
261 } else {
262 fwd(&dst[0], &src[0], nfft);
263 }
264 }
265 }
266
267 template <typename InputDerived>
268 inline fft_fwd_proxy<MatrixBase<InputDerived>, FFT<T_Scalar, T_Impl> > fwd(const MatrixBase<InputDerived>& src,
269 Index nfft = -1) {
270 return fft_fwd_proxy<MatrixBase<InputDerived>, FFT<T_Scalar, T_Impl> >(src, *this, nfft);
271 }
272
273 template <typename InputDerived>
274 inline fft_inv_proxy<MatrixBase<InputDerived>, FFT<T_Scalar, T_Impl> > inv(const MatrixBase<InputDerived>& src,
275 Index nfft = -1) {
276 return fft_inv_proxy<MatrixBase<InputDerived>, FFT<T_Scalar, T_Impl> >(src, *this, nfft);
277 }
278
279 inline void inv(Complex* dst, const Complex* src, Index nfft) {
280 m_impl.inv(dst, src, static_cast<int>(nfft));
281 if (HasFlag(Unscaled) == false) scale(dst, Scalar(1. / nfft), nfft); // scale the time series
282 }
283
284 inline void inv(Scalar* dst, const Complex* src, Index nfft) {
285 m_impl.inv(dst, src, static_cast<int>(nfft));
286 if (HasFlag(Unscaled) == false) scale(dst, Scalar(1. / nfft), nfft); // scale the time series
287 }
288
289 template <typename OutputDerived, typename ComplexDerived>
290 inline void inv(MatrixBase<OutputDerived>& dst, const MatrixBase<ComplexDerived>& src, Index nfft = -1) {
291 typedef typename ComplexDerived::Scalar src_type;
292 typedef typename ComplexDerived::RealScalar real_type;
293 typedef typename OutputDerived::Scalar dst_type;
294 const bool realfft = (NumTraits<dst_type>::IsComplex == 0);
295 EIGEN_STATIC_ASSERT_VECTOR_ONLY(OutputDerived)
296 EIGEN_STATIC_ASSERT_VECTOR_ONLY(ComplexDerived)
297 EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(ComplexDerived, OutputDerived) // size at compile-time
298 EIGEN_STATIC_ASSERT(
299 (internal::is_same<src_type, Complex>::value),
300 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
301 EIGEN_STATIC_ASSERT(int(OutputDerived::Flags) & int(ComplexDerived::Flags) & DirectAccessBit,
302 THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES)
303
304 if (nfft < 1) { // automatic FFT size determination
305 if (realfft && HasFlag(HalfSpectrum))
306 nfft = 2 * (src.size() - 1); // assume even fft size
307 else
308 nfft = src.size();
309 }
310 dst.derived().resize(nfft);
311
312 // check for nfft that does not fit the input data size
313 Index resize_input = (realfft && HasFlag(HalfSpectrum)) ? ((nfft / 2 + 1) - src.size()) : (nfft - src.size());
314
315 if (src.innerStride() != 1 || resize_input) {
316 // if the vector is strided, then we need to copy it to a packed temporary
317 Matrix<src_type, 1, Dynamic> tmp;
318 if (resize_input) {
319 size_t ncopy = (std::min)(src.size(), src.size() + resize_input);
320 tmp.setZero(src.size() + resize_input);
321 if (realfft && HasFlag(HalfSpectrum)) {
322 // pad at the Nyquist bin
323 tmp.head(ncopy) = src.head(ncopy);
324 tmp(ncopy - 1) = real(tmp(ncopy - 1)); // enforce real-only Nyquist bin
325 } else {
326 size_t nhead, ntail;
327 nhead = 1 + ncopy / 2 - 1; // range [0:pi)
328 ntail = ncopy / 2 - 1; // range (-pi:0)
329 tmp.head(nhead) = src.head(nhead);
330 tmp.tail(ntail) = src.tail(ntail);
331 if (resize_input <
332 0) { // shrinking -- create the Nyquist bin as the average of the two bins that fold into it
333 tmp(nhead) = (src(nfft / 2) + src(src.size() - nfft / 2)) * real_type(.5);
334 } else { // expanding -- split the old Nyquist bin into two halves
335 tmp(nhead) = src(nhead) * real_type(.5);
336 tmp(tmp.size() - nhead) = tmp(nhead);
337 }
338 }
339 } else {
340 tmp = src;
341 }
342
343 if (dst.innerStride() != 1) {
344 Matrix<dst_type, 1, Dynamic> out(1, nfft);
345 inv(&out[0], &tmp[0], nfft);
346 dst.derived() = out;
347 } else {
348 inv(&dst[0], &tmp[0], nfft);
349 }
350 } else {
351 if (dst.innerStride() != 1) {
352 Matrix<dst_type, 1, Dynamic> out(1, nfft);
353 inv(&out[0], &src[0], nfft);
354 dst.derived() = out;
355 } else {
356 inv(&dst[0], &src[0], nfft);
357 }
358 }
359 }
360
361 template <typename Output_>
362 inline void inv(std::vector<Output_>& dst, const std::vector<Complex>& src, Index nfft = -1) {
363 if (nfft < 1)
364 nfft = (NumTraits<Output_>::IsComplex == 0 && HasFlag(HalfSpectrum)) ? 2 * (src.size() - 1) : src.size();
365 dst.resize(nfft);
366 inv(&dst[0], &src[0], nfft);
367 }
368
369#if defined EIGEN_FFTW_DEFAULT || defined EIGEN_POCKETFFT_DEFAULT || defined EIGEN_MKL_DEFAULT
370 inline void inv2(Complex* dst, const Complex* src, int n0, int n1) {
371 m_impl.inv2(dst, src, n0, n1);
372 if (HasFlag(Unscaled) == false) scale(dst, 1. / (n0 * n1), n0 * n1);
373 }
374#endif
375
376 inline impl_type& impl() { return m_impl; }
377
378 private:
379 template <typename T_Data>
380 inline void scale(T_Data* x, Scalar s, Index nx) {
381#if 1
382 for (int k = 0; k < nx; ++k) *x++ *= s;
383#else
384 if (((ptrdiff_t)x) & 15)
385 Matrix<T_Data, Dynamic, 1>::Map(x, nx) *= s;
386 else
387 Matrix<T_Data, Dynamic, 1>::MapAligned(x, nx) *= s;
388 // Matrix<T_Data, Dynamic, Dynamic>::Map(x,nx) * s;
389#endif
390 }
391
392 inline void ReflectSpectrum(Complex* freq, Index nfft) {
393 // create the implicit right-half spectrum (conjugate-mirror of the left-half)
394 Index nhbins = (nfft >> 1) + 1;
395 for (Index k = nhbins; k < nfft; ++k) freq[k] = conj(freq[nfft - k]);
396 }
397
398 impl_type m_impl;
399 int m_flag;
400};
401
402template <typename T_SrcMat, typename T_FftIfc>
403template <typename T_DestMat>
404inline void fft_fwd_proxy<T_SrcMat, T_FftIfc>::evalTo(T_DestMat& dst) const {
405 m_ifc.fwd(dst, m_src, m_nfft);
406}
407
408template <typename T_SrcMat, typename T_FftIfc>
409template <typename T_DestMat>
410inline void fft_inv_proxy<T_SrcMat, T_FftIfc>::evalTo(T_DestMat& dst) const {
411 m_ifc.inv(dst, m_src, m_nfft);
412}
413
414} // namespace Eigen
415
416#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"
417
418#endif
const unsigned int DirectAccessBit
Namespace containing all symbols from the Eigen library.
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)