/* SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * Frv - Frame vector library
 *
 * Copyright © 2001-2021 Laboratoire d'Annecy de physique des particules - CNRS
 * Copyright © 2019-2021 Institut pluridisciplinaire Hubert CURIEN - CNRS
 *
 * This library 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 2 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

/*--------------------------------------------- FrvFDFilter.h  Mar 21, 2010 */

#if !defined(FRVFDF)
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define FRVFDF
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

#ifdef __cplusplus
extern "C" {
#endif

#include "FrameL.h"
#include "FrvBuf.h"

typedef struct FrvFDFilter     FrvFDFilter;
typedef struct FrvFDFilterOut  FrvFDFilterOut;
typedef struct FrvFDFHole      FrvFDFHole;
typedef struct FrvFDFTFBin     FrvFDFTFBin;
typedef struct FrvFDFilter2    FrvFDFilter2;
typedef struct FrvFDFPhaseBump FrvFDFPhaseBump;

struct FrvFDFilter{
  char *name;              /* optinal name */
  double  gain;              /* gainapply for the filter in the active band  */
  double  delay;        /**< input buffer delay (second)                     */
  int     nData;        /**< number of points for data FFT                   */
  int     first;        /**< tell if the ouput vector is already produced    */
  FrvBuf *buffer;       /**< buffer for input data                           */
  FrVect *windowIn;     /**< tapering window applied on input data           */
  FrVect *fftInput;     /**< vector holding input data * tapering window     */
  FrVect *fft;          /**< vector holding the data fft(FFTW order)         */
  FrVect *fftTF;        /**< vector holding the data fft *TF (FFTW order)    */
  void   *plan_for;     /**< plan for forward FFT (type is in fact fftw_plan)*/
  FrvFDFHole *hole;     /**< linked list of hole in the TF                   */
  FrvFDFilter2 *filter2;/**< linked list of filter2 in the TF                */
  FrvFDFTFBin *tfBins;  /**< linked list of point for a empirical TF         */
  FrvFDFTFBin *tfBinLast; /**< last entry of the linked list of point        */
  FrvFDFPhaseBump *phaseBump;  /**< linked list of empirical "phase bumps"        */
  FrVect *tf;           /**< hold the complex TF representation(FFTW order)  */
  FrVect *tfModulus;    /**< modulus of the TF                               */
  FrVect *tfPhase;      /**< phase of the TF                                 */
  FrvFDFilterOut *fOut; /**< output structure                                */
  FrVect *dTF;          /**< TF variation if needed                          */
  FrvFDFilter *next;
};

struct FrvFDFilterOut{
  double sampleRateOut;/**< output sampling rate; if zero=input frequency   */
  double freqStart;    /* starting frequency or zero if no HP filter        */
  FrVect *windowOut;    /**< window applied on output data                   */
  FrVect *fftResized;   /**< vector holding the resized fft (FFTW order)     */
  FrVect *fftOut;       /**< vector holding output data of the fft           */
  FrVect *output1;       /**< vector holding output data of the fft           */
  FrVect *output2;       /**< vector holding output data of the fft           */
  FrVect *last;         /**< vector holding output data                      */
  FrVect *output;       /**< vector holding output data                      */
  void   *plan_back;    /**< plan for backward FFT(type is in fact fftw_plan)*/
  double  deadZone;     /* zone supressed if SKIP = .5 */
};

struct FrvFDFHole{
  double fMin;
  double fMax;
  double scale;
  double delay;
  FrvFDFHole *next;
  };

struct FrvFDFTFBin{
  double freq;
  double scale;
  double phase;
  FrvFDFTFBin *next;
  };

struct FrvFDFPhaseBump{
  double freq;
  double width;
  double dPhi;
  FrvFDFPhaseBump *next;
  };

struct FrvFDFilter2{
  double fStart;             /* minimal frequency to apply the filter        */
  double scale;              /* scale factor before the minimal frequency    */
  double delay;              /* delay apply before freqStart                 */
  double a0;                 /* filter coefficients (see definition below)   */
  double a1;                 /* filter coefficients (see definition below)   */
  double a2;                 /* filter coefficients (see definition below)   */
  double b0;                 /* filter coefficients (see definition below)   */
  double b1;                 /* filter coefficients (see definition below)   */
  double b2;                 /* filter coefficients (see definition below)   */
  FrvFDFilter2 *next;
};

/*
  How does it work? For frequencies above freqStart,
  The transfer function (Laplace transform s=i*w) is:

                Yout(s)     a2 * s**2 + a1 * s + a0
                ------- =  -------------------------
                Yinp(s)     b2 * s**2 + b1 * s + b0

    Example 1 : first order low-pass filter at f0 with unity gain at dc
                a2=0.  a1=0.  a0=1.  b2=0.  b1=1/(2*pi*f0)  b0=1. 

    Example 2 : second order low-pass filter at f0 with quality factor Q 
                and unity gain at dc (e.g. pendulum)
                a2=0. a1=0. a0=1. b2=1/(2*pi*f0)**2  b1=1/(2*pi*f0*Q)  b0=1

    Example 3 : integrator with time constant t
                a2=0. a1=0. a0=1. b2=0. b1=t b0=0.
*/    

FrvFDFilter *FrvFDFilterNew(double freqMax, double gain ,
                            double delay, double freqOut);

int FrvFDFilterAddHole(FrvFDFilter *fdf, 
                       double fMin, double fMax, 
                       double scale, double delay);
FrvFDFTFBin* FrvFDFilterAddTFBin(FrvFDFilter *fdf,
			double freq, double scale, double phase);
int FrvFDFilterAddFilter2(FrvFDFilter *fdf,
			  double fStart, double scale, double delay,
                          double a2, double a1, double a0,
                          double b2, double b1, double b0);

int     FrvFDFilterAddPole (FrvFDFilter *fdf, double freq, double q);
int     FrvFDFilterAddZero (FrvFDFilter *fdf, double freq, double q);
int     FrvFDFilterAddPhaseBump(FrvFDFilter *fdf, 
				double freq, double width, double dPhi);
  /*
int     FrvFDFilterAddNotch(FrvFDFilter *fdf, double freq);
  */
int     FrvFDFilterBuildTFBin(FrvFDFilter *fdf);
FrvFDFilterOut* FrvFDFilterOutNew(double sampleRate);
FrvFDFilterOut* FrvFDFilterOutNewHP(double sampleRate, double freqStart);
int             FrvFDFilterOutInit (FrvFDFilterOut *fOut, FrVect *fftTF);
void            FrvFDFilterOutProc (FrvFDFilterOut *fOut, FrVect *fftTF, 
                                              double scale);
int     FrvFDFilterInit   (FrvFDFilter *fdf, FrVect *data);
void    FrvFDFilterSetName(FrvFDFilter *fdf, char *name);
int     FrvFDFilterSetSkip(FrvFDFilter *fdf, double skip);
double  FrvFDFilterPhaseAt(FrvFDFilter *fdf,  double freq);
int     FrvFDFilterProc   (FrvFDFilter *fdf, FrVect *data);
int     FrvFDFilterProcFFT(FrvFDFilter *fdf, FrVect *vect);
int     FrvFDFilterProcTF (FrvFDFilter *fdf);
void*   FrvFDFilterFree(FrvFDFilter *fdf);

#ifdef __cplusplus
}
#endif

#endif
