Files
pip/libs/main/math/pifft.h
2026-03-12 14:46:57 +03:00

390 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\file pifft.h
//! \~\ingroup Math
//! \~\ingroup FFTW
//! \~\brief
//! \~english FFT, IFFT and Hilbert transformations
//! \~russian БПФ, ОБПФ и преобразования Гильберта
/*
PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations
Andrey Bychkov work.a.b@yandex.ru, Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup FFTW FFTW
//! \~\brief
//! \~english Optimized FFT support via libfftw3
//! \~russian Оптимизированный БПФ с помощью libfftw3
//!
//! \~\details
//! \~english \section cmake_module_FFTW Building with CMake
//! \~russian \section cmake_module_FFTW Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::FFTW)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides FFT using [libfftw3](https://fftw.org/)
//!
//! \~russian
//! Эти файлы обеспечивают БПФ с использованием [libfftw3](https://fftw.org/)
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PIFFT_H
#define PIFFT_H
#include "pimathcomplex.h"
#ifndef MICRO_PIP
# include "pip_fftw_export.h"
//! \~\ingroup Math
//! \~\ingroup FFTW
//! \~\brief
//! \~english Double-precision FFT helper that stores the last transform result.
//! \~russian Вспомогательный класс БПФ двойной точности, сохраняющий результат последнего преобразования.
class PIP_EXPORT PIFFT_double {
public:
//! \~english Constructs an empty transformer.
//! \~russian Создает пустой объект преобразования.
PIFFT_double();
//! \~english Calculates complex FFT for the input signal.
//! \~russian Вычисляет комплексное БПФ для входного сигнала.
PIVector<complexd> * calcFFT(const PIVector<complexd> & val);
//! \~english Calculates FFT for a real-valued input signal.
//! \~russian Вычисляет БПФ для вещественного входного сигнала.
PIVector<complexd> * calcFFT(const PIVector<double> & val);
//! \~english Calculates inverse FFT for a complex spectrum.
//! \~russian Вычисляет обратное БПФ для комплексного спектра.
PIVector<complexd> * calcFFTinverse(const PIVector<complexd> & val);
//! \~english Calculates the analytic signal using a Hilbert transform.
//! \~russian Вычисляет аналитический сигнал с помощью преобразования Гильберта.
PIVector<complexd> * calcHilbert(const PIVector<double> & val);
//! \~english Returns magnitudes of the last calculated result.
//! \~russian Возвращает модули последнего вычисленного результата.
PIVector<double> getAmplitude() const;
//! \~english Returns real parts of the last calculated result.
//! \~russian Возвращает действительные части последнего вычисленного результата.
PIVector<double> getReal() const;
//! \~english Returns imaginary parts of the last calculated result.
//! \~russian Возвращает мнимые части последнего вычисленного результата.
PIVector<double> getImag() const;
private:
PIVector<complexd> result;
typedef ptrdiff_t ae_int_t;
struct ftplan {
PIVector<int> plan;
PIVector<double> precomputed;
PIVector<double> tmpbuf;
PIVector<double> stackbuf;
};
ftplan curplan;
void fftc1d(const PIVector<complexd> & a, uint n);
void fftc1r(const PIVector<double> & a, uint n);
void fftc1dinv(const PIVector<complexd> & a, uint n);
void createPlan(uint n);
void ftbasegeneratecomplexfftplan(uint n, ftplan * plan);
void ftbase_ftbasegenerateplanrec(int n,
int tasktype,
ftplan * plan,
int * plansize,
int * precomputedsize,
int * planarraysize,
int * tmpmemsize,
int * stackmemsize,
ae_int_t stackptr,
int debugi = 0);
void ftbase_ftbaseprecomputeplanrec(ftplan * plan, int entryoffset, ae_int_t stackptr);
void ftbasefactorize(int n, int * n1, int * n2);
void ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int * best);
int ftbasefindsmooth(int n);
void ftbaseexecuteplan(PIVector<double> * a, int aoffset, int n, ftplan * plan);
void ftbaseexecuteplanrec(PIVector<double> * a, int aoffset, ftplan * plan, int entryoffset, ae_int_t stackptr);
void ftbase_internalcomplexlintranspose(PIVector<double> * a, int m, int n, int astart, PIVector<double> * buf);
void ftbase_ffticltrec(PIVector<double> * a, int astart, int astride, PIVector<double> * b, int bstart, int bstride, int m, int n);
void ftbase_internalreallintranspose(PIVector<double> * a, int m, int n, int astart, PIVector<double> * buf);
void ftbase_fftirltrec(PIVector<double> * a, int astart, int astride, PIVector<double> * b, int bstart, int bstride, int m, int n);
void ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2);
};
//! \~\ingroup Math
//! \~\ingroup FFTW
//! \~\brief
//! \~english Single-precision FFT helper that stores the last transform result.
//! \~russian Вспомогательный класс БПФ одинарной точности, сохраняющий результат последнего преобразования.
class PIP_EXPORT PIFFT_float {
public:
//! \~english Constructs an empty transformer.
//! \~russian Создает пустой объект преобразования.
PIFFT_float();
//! \~english Calculates complex FFT for the input signal.
//! \~russian Вычисляет комплексное БПФ для входного сигнала.
PIVector<complexf> * calcFFT(const PIVector<complexf> & val);
//! \~english Calculates FFT for a real-valued input signal.
//! \~russian Вычисляет БПФ для вещественного входного сигнала.
PIVector<complexf> * calcFFT(const PIVector<float> & val);
//! \~english Calculates inverse FFT for a complex spectrum.
//! \~russian Вычисляет обратное БПФ для комплексного спектра.
PIVector<complexf> * calcFFTinverse(const PIVector<complexf> & val);
//! \~english Calculates the analytic signal using a Hilbert transform.
//! \~russian Вычисляет аналитический сигнал с помощью преобразования Гильберта.
PIVector<complexf> * calcHilbert(const PIVector<float> & val);
//! \~english Returns magnitudes of the last calculated result.
//! \~russian Возвращает модули последнего вычисленного результата.
PIVector<float> getAmplitude() const;
//! \~english Returns real parts of the last calculated result.
//! \~russian Возвращает действительные части последнего вычисленного результата.
PIVector<float> getReal() const;
//! \~english Returns imaginary parts of the last calculated result.
//! \~russian Возвращает мнимые части последнего вычисленного результата.
PIVector<float> getImag() const;
private:
PIVector<complexf> result;
typedef ptrdiff_t ae_int_t;
struct ftplan {
PIVector<int> plan;
PIVector<float> precomputed;
PIVector<float> tmpbuf;
PIVector<float> stackbuf;
};
ftplan curplan;
void fftc1d(const PIVector<complexf> & a, uint n);
void fftc1r(const PIVector<float> & a, uint n);
void fftc1dinv(const PIVector<complexf> & a, uint n);
void createPlan(uint n);
void ftbasegeneratecomplexfftplan(uint n, ftplan * plan);
void ftbase_ftbasegenerateplanrec(int n,
int tasktype,
ftplan * plan,
int * plansize,
int * precomputedsize,
int * planarraysize,
int * tmpmemsize,
int * stackmemsize,
ae_int_t stackptr,
int debugi = 0);
void ftbase_ftbaseprecomputeplanrec(ftplan * plan, int entryoffset, ae_int_t stackptr);
void ftbasefactorize(int n, int * n1, int * n2);
void ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int * best);
int ftbasefindsmooth(int n);
void ftbaseexecuteplan(PIVector<float> * a, int aoffset, int n, ftplan * plan);
void ftbaseexecuteplanrec(PIVector<float> * a, int aoffset, ftplan * plan, int entryoffset, ae_int_t stackptr);
void ftbase_internalcomplexlintranspose(PIVector<float> * a, int m, int n, int astart, PIVector<float> * buf);
void ftbase_ffticltrec(PIVector<float> * a, int astart, int astride, PIVector<float> * b, int bstart, int bstride, int m, int n);
void ftbase_internalreallintranspose(PIVector<float> * a, int m, int n, int astart, PIVector<float> * buf);
void ftbase_fftirltrec(PIVector<float> * a, int astart, int astride, PIVector<float> * b, int bstart, int bstride, int m, int n);
void ftbase_ffttwcalc(PIVector<float> * a, int aoffset, int n1, int n2);
};
//! \~english Default FFT helper alias based on double precision.
//! \~russian Псевдоним стандартного FFT-помощника на базе двойной точности.
typedef PIFFT_double PIFFT;
//! \~english Double-precision FFT helper alias.
//! \~russian Псевдоним FFT-помощника двойной точности.
typedef PIFFT_double PIFFTd;
//! \~english Single-precision FFT helper alias.
//! \~russian Псевдоним FFT-помощника одинарной точности.
typedef PIFFT_float PIFFTf;
# ifndef CC_VC
# define _PIFFTW_H(type) \
class PIP_FFTW_EXPORT _PIFFTW_P_##type##_ { \
public: \
_PIFFTW_P_##type##_(); \
~_PIFFTW_P_##type##_(); \
const PIVector<complex<type>> & calcFFT(const PIVector<complex<type>> & in); \
const PIVector<complex<type>> & calcFFTR(const PIVector<type> & in); \
const PIVector<complex<type>> & calcFFTI(const PIVector<complex<type>> & in); \
void preparePlan(int size, int op); \
void * impl; \
};
_PIFFTW_H(float)
_PIFFTW_H(double)
_PIFFTW_H(ldouble)
//! \~\ingroup Math
//! \~\ingroup FFTW
//! \~\brief
//! \~english Thin wrapper over libfftw3 plans for a selected scalar type.
//! \~russian Тонкая обертка над планами libfftw3 для выбранного скалярного типа.
template<typename T>
class PIFFTW {
public:
//! \~english Constructs the backend object for the selected precision.
//! \~russian Создает внутренний объект для выбранной точности.
explicit PIFFTW() {
p = 0;
newP(p);
}
//! \~english Destroys the backend object and its cached plans.
//! \~russian Уничтожает внутренний объект и его кэшированные планы.
~PIFFTW() { deleteP(p); }
//! \~english Calculates complex FFT for the input signal.
//! \~russian Вычисляет комплексное БПФ для входного сигнала.
inline const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english Calculates FFT for a real-valued input signal.
//! \~russian Вычисляет БПФ для вещественного входного сигнала.
inline const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english Calculates inverse FFT for a complex spectrum.
//! \~russian Вычисляет обратное БПФ для комплексного спектра.
inline const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { return PIVector<complex<T>>().resize(in.size()); }
//! \~english Operation kind for precomputed FFTW plans.
//! \~russian Тип операции для заранее подготовленных планов FFTW.
enum FFT_Operation {
foReal /** \~english Forward transform for real input \~russian Прямое преобразование для вещественного входа */,
foComplex /** \~english Forward transform for complex input \~russian Прямое преобразование для комплексного входа */,
foInverse /** \~english Inverse complex transform \~russian Обратное комплексное преобразование */
};
//! \~english Prepares and caches a plan for the specified signal size and operation.
//! \~russian Подготавливает и кэширует план для указанного размера сигнала и операции.
inline void preparePlan(int size, FFT_Operation op) {}
private:
void operator=(const PIFFTW &);
PIFFTW(const PIFFTW &);
inline void newP(void *& _p) {}
inline void deleteP(void *& _p) {}
void * p;
};
template<>
inline const PIVector<complex<float>> & PIFFTW<float>::calcFFT(const PIVector<complex<float>> & in) {
return ((_PIFFTW_P_float_ *)p)->calcFFT(in);
}
template<>
inline const PIVector<complex<float>> & PIFFTW<float>::calcFFT(const PIVector<float> & in) {
return ((_PIFFTW_P_float_ *)p)->calcFFTR(in);
}
template<>
inline const PIVector<complex<float>> & PIFFTW<float>::calcFFTinverse(const PIVector<complex<float>> & in) {
return ((_PIFFTW_P_float_ *)p)->calcFFTI(in);
}
template<>
inline void PIFFTW<float>::preparePlan(int size, FFT_Operation op) {
((_PIFFTW_P_float_ *)p)->preparePlan(size, op);
}
template<>
inline void PIFFTW<float>::newP(void *& _p) {
_p = new _PIFFTW_P_float_();
}
template<>
inline void PIFFTW<float>::deleteP(void *& _p) {
if (_p) delete (_PIFFTW_P_float_ *)_p;
_p = 0;
}
//! \~english Single-precision FFTW wrapper.
//! \~russian Обертка FFTW одинарной точности.
typedef PIFFTW<float> PIFFTWf;
template<>
inline const PIVector<complex<double>> & PIFFTW<double>::calcFFT(const PIVector<complex<double>> & in) {
return ((_PIFFTW_P_double_ *)p)->calcFFT(in);
}
template<>
inline const PIVector<complex<double>> & PIFFTW<double>::calcFFT(const PIVector<double> & in) {
return ((_PIFFTW_P_double_ *)p)->calcFFTR(in);
}
template<>
inline const PIVector<complex<double>> & PIFFTW<double>::calcFFTinverse(const PIVector<complex<double>> & in) {
return ((_PIFFTW_P_double_ *)p)->calcFFTI(in);
}
template<>
inline void PIFFTW<double>::preparePlan(int size, FFT_Operation op) {
((_PIFFTW_P_double_ *)p)->preparePlan(size, op);
}
template<>
inline void PIFFTW<double>::newP(void *& _p) {
_p = new _PIFFTW_P_double_();
}
template<>
inline void PIFFTW<double>::deleteP(void *& _p) {
if (_p) delete (_PIFFTW_P_double_ *)_p;
_p = 0;
}
//! \~english Double-precision FFTW wrapper.
//! \~russian Обертка FFTW двойной точности.
typedef PIFFTW<double> PIFFTWd;
template<>
inline const PIVector<complex<ldouble>> & PIFFTW<ldouble>::calcFFT(const PIVector<complex<ldouble>> & in) {
return ((_PIFFTW_P_ldouble_ *)p)->calcFFT(in);
}
template<>
inline const PIVector<complex<ldouble>> & PIFFTW<ldouble>::calcFFT(const PIVector<ldouble> & in) {
return ((_PIFFTW_P_ldouble_ *)p)->calcFFTR(in);
}
template<>
inline const PIVector<complex<ldouble>> & PIFFTW<ldouble>::calcFFTinverse(const PIVector<complex<ldouble>> & in) {
return ((_PIFFTW_P_ldouble_ *)p)->calcFFTI(in);
}
template<>
inline void PIFFTW<ldouble>::preparePlan(int size, FFT_Operation op) {
((_PIFFTW_P_ldouble_ *)p)->preparePlan(size, op);
}
template<>
inline void PIFFTW<ldouble>::newP(void *& _p) {
_p = new _PIFFTW_P_ldouble_();
}
template<>
inline void PIFFTW<ldouble>::deleteP(void *& _p) {
if (_p) delete (_PIFFTW_P_ldouble_ *)_p;
_p = 0;
}
//! \~english Extended-precision FFTW wrapper.
//! \~russian Обертка FFTW расширенной точности.
typedef PIFFTW<ldouble> PIFFTWld;
# endif
#endif // MICRO_PIP
#endif // PIFFT_H