#ifndef LMATH_FFT_H
#define LMATH_FFT_H

#include "lmath_defs.h"
#include "lmath_phase.h"
#include "lmath_window.h"
#ifdef __cplusplus
extern "C" {
#endif

/***************************************************************************//**
    Расчет амплитудного и фазового спектра входного сигнала.
    Упрощенная функция, не требующая отдельного создания контекста, но
    при этом не позволяющая вынести затраты на расчет постоянных параметров
    вне основного цикла обработки. Амплитудный спектр возвращается в
    значениях пиковой аплитуды гармоники.

    @param[in] src      Массив с отсчетами исходного временного сигнала
    @param[in] size     Количество отсчетов во входном массиве
    @param[in] dt       Интервал времени между отсчетами входного сигнала в
                          секундах
    @param[in] flags    Резерв
    @param[out] amp     В этот массив сохраняется рассчитанный амплитудный
                          спектр размером size/2 + 1 элементов. Может быть NULL.
    @param[out] pha     В этот массив сохраняется рассчитанный фазовый
                          спектр размером size/2 + 1 элементов. Может быть NULL.
    @param[out] df      В этой переменной возвращается изменение частоты между
                          соседними отсчетами рассчитанных спектров в Гц.
                          Может быть NULL.
    @return             Код ошибки
    ***************************************************************************/
t_lmath_errs lmath_amp_pha_spectrum_peak(const double *src, int size, double dt, int flags,
                                         t_lmath_phase_mode pha_mode,
                                         double *amp, double *pha, double *df);
/* Аналогично lmath_amp_pha_spectrum_peak(), но возвращает амплитудный спектр в
   rms */
t_lmath_errs lmath_amp_pha_spectrum_rms(const double *src, int size, double dt, int flags,
                                        t_lmath_phase_mode pha_mode,
                                        double *amp, double *pha, double *df);


/** Непрозрачная указатель на структуру, содержащую необходимую информацию
   для расчета комплексного преобразования Фурье из действительного сигнала */
typedef struct st_lmath_fft_r2c_ctx *t_lmath_fft_r2c_ctx;

/***************************************************************************//**
    Создание контекста для расчета преобразования Фурье входного действительного
    сигнала заданного размера. Рассчитывает все параметры, не зависящие от
    самого входного сигнала.
    Создает также буфер для входного сигнала.
    Данная функция не является потокобезопасной, если не была вызвана функция
    fftw_make_planner_thread_safe() (из FFTW версии 3.3.5 или выше)
    @param[in]  size    Количество точек во входном сигнале к которому будет
                        применяться fft
    @param[in]  flags   Флаги (резерв)
    @return             Созданный контекст или нулевой указатель, если не
                        удалось создать.
 ******************************************************************************/
t_lmath_fft_r2c_ctx lmath_fft_r2c_ctx_create(int size, int flags);

/***************************************************************************//**
    Уничтожение ранее созданного с помощью lmath_fft_r2c_ctx_create()
    контекста.
    @param[in] ctx     Контекст расчета FFT
 ******************************************************************************/
void lmath_fft_r2c_ctx_destroy(t_lmath_fft_r2c_ctx ctx);

/***************************************************************************//**
    Получение указателя на буфер для входного сигнала, к которому будет применяться
    преобразование Фурье.
    @param[in] ctx     Контекст расчета FFT
    @return            Указетель на начало буфера
 ******************************************************************************/
double *lmath_fft_r2c_ctx_in_buf(const t_lmath_fft_r2c_ctx ctx);
/***************************************************************************//**
    Получение размера буфера в точках для входного сигнала, к которому будет
    применяться преобразование Фурье. Это значение соответствует заданному
    при создании контекста.
    @param[in] ctx     Контекст расчета FFT
    @return            Размер буфера в точках
 ******************************************************************************/
int lmath_fft_r2c_ctx_in_size(const t_lmath_fft_r2c_ctx ctx);
/***************************************************************************//**
    Получение размера буфера для результата преобразования Фурье в точках.
    @param[in] ctx     Контекст расчета FFT
    @return            Размер буфера в точках
 ******************************************************************************/
int lmath_fft_r2c_ctx_fft_size(const t_lmath_fft_r2c_ctx ctx);
/***************************************************************************//**
    Получение шага по частоте на основе шага по времени, который получится в
    результате расчета преобразования Фурье. Если время задано в секундах, то результат
    будет в Герцах.
    @param[in] ctx     Контекст расчета FFT
    @return            Величина шага по частоте
 ******************************************************************************/
double lmath_fft_r2c_ctx_df(const t_lmath_fft_r2c_ctx ctx, double dt);

/***************************************************************************//**
    Расчет амплитудно-фазового спектра на основе ранее созданного контекста
    и входного действительного сигнала, помещенного во входной буфер,
    который можно получить с помощью lmath_fft_r2c_ctx_in_buf().
    Выполняется нормализация амплитудного спектра. Каждый элемент - амплитуда
    (пиковое значение) соответсвующей гармоники.
    Выходные массивы должны быть достаточного размера для сохранения
    lmath_fft_r2c_ctx_fft_size() точек.
    В качестве любого массива может быть передан нулевой указатель, если нужно
    рассчитать только амплитудный или только фазовый спектр.

    @param[in] ctx     Контекст расчета FFT
    @param[out] amp     В этот массив сохраняется рассчитанный амплитудный
                          спектр размером lmath_fft_r2c_ctx_fft_size()
                          элементов.  Может быть NULL.
    @param[out] pha     В этот массив сохраняется рассчитанный фазовый
                          спектр размером lmath_fft_r2c_ctx_fft_size()
                          элементов. Может быть NULL.
    @return             Код ошибки
 ******************************************************************************/
t_lmath_errs lmath_fft_r2c_calc_amp_pha_spectrum_peak(t_lmath_fft_r2c_ctx ctx,
                                                      t_lmath_phase_mode pha_mode,
                                                      double *amp, double *pha);


/***************************************************************************//**
    Расчет амплитудно-фазового спектра на основе ранее созданного контекста
    и входного действительного сигнала. Аналогичен lmath_fft_r2c_calc_amp_pha_spectrum_peak(),
    но в амплитудном спектре каждый элемент представляет собой RMS соответствующей
    гармоники (постоянная составляющая остается такой же)

    @param[in] ctx     Контекст расчета FFT
    @param[out] amp     В этот массив сохраняется рассчитанный амплитудный
                          спектр RMS сигнала размером lmath_fft_r2c_ctx_fft_size()
                          элементов.  Может быть NULL.
    @param[out] pha     В этот массив сохраняется рассчитанный фазовый
                          спектр размером lmath_fft_r2c_ctx_fft_size()
                          элементов. Может быть NULL.
    @return             Код ошибки
 ******************************************************************************/
t_lmath_errs lmath_fft_r2c_calc_amp_pha_spectrum_rms(t_lmath_fft_r2c_ctx ctx,
                                                     t_lmath_phase_mode pha_mode,
                                                     double *amp, double *pha);


#ifdef __cplusplus
}
#endif

#endif // LMATH_FFT_H
