#ifndef LMATH_SPECTRUM_SIGNOISE_H
#define LMATH_SPECTRUM_SIGNOISE_H

#include "lmath_window.h"

#ifdef __cplusplus
extern "C" {
#endif

/** Контекст для рассчета сперктральных параметров с помощью lmath_spectrum_signoise_calc() */
typedef struct st_lmath_spectrum_signoise_ctx *t_lmath_spectrum_signoise_ctx;


/** Флаги, определяющие, какие результирующие параметры будут рассчитаны
 * при вызове lmath_spectrum_signoise_calc() / lmath_spectrum_signoise() */
typedef  enum {
    LMATH_SIGNOISE_FLAGS_CALC_SNR   = 1 << 0, /**< Признак необходимости расчета SNR */
    LMATH_SIGNOISE_FLAGS_CALC_THD   = 1 << 1, /**< Признак необходимости расчета THD */
    LMATH_SIGNOISE_FLAGS_CALC_SINAD = 1 << 2, /**< Признак необходимости расчета SINAD */
    LMATH_SIGNOISE_FLAGS_CALC_SFDR  = 1 << 3, /**< Признак необходимости расчета SFDR */
    LMATH_SIGNOISE_FLAGS_CALC_ENOB  = 1 << 4, /**< Признак необходимости расчета ENOB */
} t_lmath_signoise_flags;

/** Рассчитанные значения, по одному из спектральных компонент сигнала */
typedef  struct {
    double power; /**< Мощность */
    double maxBinValue; /**< Максимальное значение отсчета в спектре */
}  t_lmath_sepctral_component;

/** Результаты вычисления спектральных параметров */
typedef struct {
    t_lmath_sepctral_component signal; /**< Значение спектральной составляющей,
                                            относящейся к рассматриваемому сигналу */
    t_lmath_sepctral_component harms; /**< Значение спектральной составляющей,
                                            относящейся к гармоникам рассматриваемого
                                            сигнала */
    t_lmath_sepctral_component noise; /**< Значение спектральной составляющей,
                                            относящейся к шуму (все вне сигнала и
                                            гармоник) */

    struct {
        double SNR;  /**< Значение отношения сигнал/шум в дБ */
        double THD;  /**< Значение Total Harmonic Distortion:
                          гармоники/сигнал дБ */
        double SINAD;/**< Значение signal-to-noise-and-distortion
                          ratio: сигнал/(шум+гармоники) дБ. */
        double SFDR; /**< Значение spurious free dynamic range:
                          макс. отсчет сигнала/макс. отсчет вне сигнала дБ */
        double ENOB; /**< Значение количества эффективных бит:
                          (SINAD - 1.76) / 6.02 */
    } params;
} t_lmath_spectrum_signoise_result;

/***************************************************************************//**
    Создание контекста для рассчета спектральных параметров для заданной
    частоты исходного сигнала и заданнных параметров спектра.
    В случае повторных рассчетов одних и тех же параметров для одной частоты
    и одних и тех же параметров спектра данная функция возвоялет один раз рассчитать
    расположение гармоник в спектре и использовать его для последующих вызовов
    lmath_spectrum_signoise_calc().
    По завершению работы необходимо вызвать lmath_spectrum_signoise_ctx_destroy().

    @param[in]  fft_size        Количество точек в спектре
    @param[in]  df              Изменение частоты между соседними отсчетами
                                спектра в Гц
    @param[in]  winpar          Указатель на структуру с параметрами
                                примененного перед вычислением спектра окна.
    @param[in]  peak_freq       Частота основного сигнала. Должна соответствовать
                                 отсчету с номером не меньше чем freq_span/2.
    @param[in]  harm_cnt        Количество гармоник (включая основную), используемых
                                при расчете.
    @param[in]  flags           Набор флагов из #t_lmath_signoise_flags,
                                определяющих, какие параметры рассчитывать.
    @return                     Созданный контекст или NULL при ошибках входных
                                парамтеров или ошибке выделения памяти.
*******************************************************************************/
t_lmath_spectrum_signoise_ctx lmath_spectrum_signoise_ctx_create(
        int fft_size,  double df, const t_lmath_window_params *winpar,
         double peak_freq, int harm_cnt, unsigned flags);

/***************************************************************************//**
   Удаление контекста, созданного с помощью lmath_spectrum_signoise_ctx_create().
   @param ctx удаляемый контекст.
 *******************************************************************************/
void lmath_spectrum_signoise_ctx_destroy(t_lmath_spectrum_signoise_ctx ctx);

/***************************************************************************//**
    Вычисление значений сигнала/гармоник/шума в спектре и расчет производных
    параметров от данных составляющих с использованием созданного ранее с помощью
    lmath_spectrum_signoise_ctx_create() контекста.

   @param ctx             Контекст, созданный с помощью lmath_spectrum_signoise_ctx_create()
   @param amp_spectrum    Амплитудный спектр входного сигнала. Количество значений
                          должно соответсвовать параметру fft_size при создании контекста.
   @param result          При успешном выполнении в данную структуру сохраняются
                                    рассчитанные значения.
   @return                Код ошибки
 *******************************************************************************/
t_lmath_errs lmath_spectrum_signoise_calc(const t_lmath_spectrum_signoise_ctx ctx,
                                          const double *amp_spectrum,
                                          t_lmath_spectrum_signoise_result *result);


/***************************************************************************//**
    Вычисление значений сигнала/гармоник/шума в спектре и расчет производных
    параметров от данных составляющих.
    Упрощенная версия без явного создания контекста. Позволяет выполнить все действия
    одним вызовом, но каждый раз выполняет создание контекста и рассчет местоположения
    гармоник в спектре.
    Внутри себя функция выполняет последовательность вызовов:
    - lmath_spectrum_signoise_ctx_create()
    - lmath_spectrum_signoise_calc()
    - lmath_spectrum_signoise_destroy()

    @param[in]  amp_spectrum    Амплитудный спектр входного сигнала
    @param[in]  fft_size        Количество точек в спектре
    @param[in]  df              Изменение частоты между соседними отсчетами
                                  спектра в Гц
    @param[in]  winpar          Указатель на структуру с параметрами
                                   примененного перед вычислением спектра окна.
    @param[in]  peak_freq       Частота основного сигнала. Должна соответствовать
                                   отсчету с номером не меньше чем freq_span/2.
    @param[in]  harm_cnt        Количество гармоник (включая основную), используемых
                                    при расчете.
    @param[in]  flags           Набор флагов из #t_lmath_signoise_flags,
                                    определяющих, какие параметры рассчитывать.
    @param[out]  result         При успешном выполнении в данную структуру сохраняются
                                    рассчитанные значения.
    @return                     Код ошибки
*******************************************************************************/
t_lmath_errs lmath_spectrum_signoise(const double *amp_spectrum, int fft_size,  double df,
                                     const t_lmath_window_params *winpar,
                                     double peak_freq, int harm_cnt,
                                     unsigned flags,
                                     t_lmath_spectrum_signoise_result *result);
#ifdef __cplusplus
}
#endif

#endif // LMATH_SPECTRUM_SIGNOISE_H
