DiscreteFourierTransform API 及FFT(快速傅里叶变化)总结

来源:互联网 发布:js字符串去掉换行符 编辑:程序博客网 时间:2024/05/23 02:00

public class DiscreteFourierTransform extends BaseDataProcessor



本类的注释翻译:

计算一个输入序列的离散傅里叶变换(DFT)时,使用的快速傅里叶变换(FFT).傅里叶变换是一个把信号放入其频率(成分)分析的过程。在语音中,我们不是分析整个语音连续的语音即整个持续期的语音,而是分析音频数据的一个窗口(帧)。这个窗口是对输入信号进行滑动汉明窗口处理的结果。因为在语音识别中振幅比相位重要的的多,所有本类返回的是那个数据窗口的能量谱而非复数谱。在返回频谱中的每一个值代表那个窗口的特殊(特定)频率的强度。

一般(默认)情况,FFT的点数是一个最接近于2的幂的数,此数等于或大于数据输入窗口的采样数。FFT的点数也能被用户通过本类的属性的设置(PROP_NUMBER_FFT_POINTS)来定义.

返回的功率谱的长度为FFT的点数除2再加1。显然输入的信号是实数,FFT是对称的,在整个矢量中包含的信息已经在矢量的前半部分中呈现了。



计算 输入序列的离散傅里叶变换,使用了FFT。

本类的属性:

@S4Integer(defaultValue = -1)

public static final String PROP_NUMBER_FFT_POINTS =“numberFftPoints”;为fft的点数。

@S4Boolean(defaultValue = false)

public static final String PROP_INVERT =“invert”;是否为反(逆)FFT。

private boolean isNumberFftPointsSet;

    private int numberFftPoints;

    private int logBase2NumberFftPoints;

    private int numberDataPoints;

    private boolean invert;

    private Complex[]weightFft;

    private Complex[]inputFrame;

    private Complex[]from;

    private Complex[]to;

    private ComplexweightFftTimesFrom2;

private Complex tempComplex;

本类的构造方法:

public DiscreteFourierTransform(int numberFftPoints, boolean invert );非空构造方法,初始化了属性。包括logger,numberFftPoints,invert,isNumberFftPointsSet

public DiscreteFourierTransform();空构造方法,不会对属性进行任何设置。

本类的方法:

public void newProperties(PropertySheet ps);只对属性进行重新设置。与非空构造方法对属性的设置作用一样。

public void initialize();初始化本处理器的前一处理器,并根据isNumberFftPointsSet来决定是否初始化FFT

private void initializeFFT();初始化FFT计算所必须的数据结构。默认情况下,FFT的点数是512,这就意味着我们在复数域中每一次循环(对窗口而言)需要计算512个值。复数共轭对将会产生相同的能量,因此我们仅需要计算0到255个傅里叶变换值。

private void computeLogBase2(int numberFftPoints);通过计算及检查余数来确保FFT的点数是一个2的幂的数。在此方法中,实际上使用的是移位和取模运算来确保fft点数。同时logBase2NumberFftPoints最终为。如果fft点数为默认的512,则logBase2NumberFftPoints等于9.

private void createWeightFft(int numberFftPoints,boolean invert);初始化weigthFFt矢量(为傅里叶变化的指数部分)。WeightFFt[k]=w^k,其中w= exp(-2 *PI *i / N),其中i是一个复数数字(复数标记),i * i = -1,在有些地方i被写成了j。其中N为FFT的点数。因为w是一个复数,那么w的实部Re(weightFft[k])= cos ( -2 * PI * k /N),虚部为Im(weightFft[k]) = sin ( -2 * PI * k / N)。

由于所要计算的是能量谱,k的取值范围为(0,N-1)。对于k=1和k=N-1,显然其FFT的共轭对称的。我们知道共轭复数其能量是相同的都为实部的平方加上虚部的平方的和。显然我们只需要计算0到(int)N/2个k的傅里叶变换就行了。所以只需要这么多个的指数部分,即0到(int)N/2个复数。for (int k = 0; k <(numberFftPoints >> 1); k++) {

            weightFft[k] = new Complex(Math.cos(w * k), Math.sin(w* k));

        }

我们知道,傅里叶变换与反傅里叶变化的在指数部分的不同仅是符号的不同,即本方法中的w和-w的区别。

private void initComplexArrays();初始化在FFT计算过程中必须的复数数组。即inputframe,from,to三个复数数组,数组的长度都为FFT的点数,三个复数的实部和虚部都设置为0.

private  static intgetNumberFftPoints(intnumberSamples);numberSamples即为上一处理器得到的一个doubledata中含有的采样数即为一个窗口的采样数。本方法就根据采样数来返回FFT的点数,此点数为一个2的幂的数,但是此点数是大于或等于采样数的,即又最接近。不管咋样都FFT的最少的可能点数为1。

private DoubleData process(DoubleData input);处理数据,从输入数据产生能量谱。Input为输入的帧(窗口)。返回的为doubledata中含有的是此输入帧的能量谱。在方法中为实际的输入序列产生复数输入序列,即把实数输入序列变为复数输入序列。如果窗口的长度即帧的采样数(窗口采样数)大于FFT的点数,我们采用的是先取下相同长度的窗口数转换成复数,存入长度为FFT点数的复数数组中后,再剩余的采样数存入一个复数数组中,从下标0开始,从点数数组中取相同长度的复数与之相加,在存入点数数组中。用数学式表示为:

for (i=numberFftPoints; i < in.length; i++) {

                tempComplex.set(in[i], 0.0f);

                inputFrame[i %numberFftPoints].addComplex

                        (inputFrame[i %numberFftPoints], tempComplex);

           }

如果窗口的长度即帧的采样数(窗口采样数)小于FFT的点数,我们对输入序列缺少的那部分进行填充0处理,即0填充处理。

2,把输入窗口的数据放入长度为fft点数的复数数组后,创建一个长度为点数一半的double数组用来存储一帧经fft处理后的能量谱。

 3,对数据进行处理,并返回由能量谱构成的doubledata。



[java] view plain copy
print?
  1. private void butterflyStage(Complex[] from,Complex[] to,int numberFftPoints,int currentDistance);对FFT的计算采用的基2的蝶形的计算方法,计算在fft蝶形中的一次蝶形。蝶形名字的出现是因为这个方法的计算的计算元素是以对的形式出现的,并且计算的流图(输出”0”来自于输入”0”和”1”,输出”1”来自于输入”0”和”1”)跟蝶形是很相似的。我们重复蝶形的次数为log_2(numberFftPoints)次,通过每次调用的参数currentDistance除以2,并检测其是否仍大于0,来迭代实现。From为每次迭代(蝶形计算)的输入系列,to为输出系列。numberFftPoints为FFT的点数,currentDistance在蝶形中元素之间的距离。  
  2.   
  3. private void butterflyStage(Complex[] from,  
  4.                                 Complex[] to,  
  5.                                 int numberFftPoints,  
  6.                                 int currentDistance) {  
  7.         int ndx1From;  
  8.         int ndx2From;  
  9.         int ndx1To;  
  10.         int ndx2To;  
  11.         int ndxWeightFft;  
  12.   
  13.         if (currentDistance > 0) {  
  14.   
  15.             int twiceCurrentDistance = 2 * currentDistance;  
  16.   
  17.             for (int s = 0; s < currentDistance; s++) {  
  18.                 ndx1From = s;  
  19.                 ndx2From = s + currentDistance;  
  20.                 ndx1To = s;  
  21.                 ndx2To = s + (numberFftPoints >> 1);  
  22.                 ndxWeightFft = 0;  
  23.                 while (ndxWeightFft < (numberFftPoints >> 1)) {  
  24.                     /** 
  25.                      * <b>weightFftTimesFrom2 = weightFft[k]   </b> 
  26.                      * <b>                      *from[ndx2From]</b> 
  27.                      */  
  28.                     weightFftTimesFrom2.multiplyComplex  
  29.                             (weightFft[ndxWeightFft], from[ndx2From]);  
  30.                     /** 
  31.                      * <b>to[ndx1To] = from[ndx1From]       </b> 
  32.                      * <b>             + weightFftTimesFrom2</b> 
  33.                      */  
  34.                     to[ndx1To].addComplex  
  35.                             (from[ndx1From], weightFftTimesFrom2);  
  36.                     /** 
  37.                      * <b>to[ndx2To] = from[ndx1From]       </b> 
  38.                      * <b>             - weightFftTimesFrom2</b> 
  39.                      */  
  40.                     to[ndx2To].subtractComplex  
  41.                             (from[ndx1From], weightFftTimesFrom2);  
  42.                     ndx1From += twiceCurrentDistance;  
  43.                     ndx2From += twiceCurrentDistance;  
  44.                     ndx1To += currentDistance;  
  45.                     ndx2To += currentDistance;  
  46.                     ndxWeightFft += currentDistance;  
  47.                 }  
  48.             }  
  49.   
  50.             /** 
  51.              * This call’d better be the last call in this block, so when 
  52.              * it returns we go straight into the return line below. 
  53.              * 
  54.              * We switch the <i>to</i> and <i>from</i> variables, 
  55.              * the total number of points remains the same, and 
  56.              * the <i>currentDistance</i> is divided by 2. 
  57.              */  
  58.             butterflyStage(to, from, numberFftPoints, (currentDistance >> 1));  
  59.         }  
  60.         }  
private void butterflyStage(Complex[] from,Complex[] to,int numberFftPoints,int currentDistance);对FFT的计算采用的基2的蝶形的计算方法,计算在fft蝶形中的一次蝶形。蝶形名字的出现是因为这个方法的计算的计算元素是以对的形式出现的,并且计算的流图(输出”0”来自于输入”0”和”1”,输出”1”来自于输入”0”和”1”)跟蝶形是很相似的。我们重复蝶形的次数为log_2(numberFftPoints)次,通过每次调用的参数currentDistance除以2,并检测其是否仍大于0,来迭代实现。From为每次迭代(蝶形计算)的输入系列,to为输出系列。numberFftPoints为FFT的点数,currentDistance在蝶形中元素之间的距离。private void butterflyStage(Complex[] from,                                Complex[] to,                                int numberFftPoints,                                int currentDistance) {        int ndx1From;        int ndx2From;        int ndx1To;        int ndx2To;        int ndxWeightFft;        if (currentDistance > 0) {            int twiceCurrentDistance = 2 * currentDistance;            for (int s = 0; s < currentDistance; s++) {                ndx1From = s;                ndx2From = s + currentDistance;                ndx1To = s;                ndx2To = s + (numberFftPoints >> 1);                ndxWeightFft = 0;                while (ndxWeightFft < (numberFftPoints >> 1)) {                    /**                     * <b>weightFftTimesFrom2 = weightFft[k]   </b>                     * <b>                      *from[ndx2From]</b>                     */                    weightFftTimesFrom2.multiplyComplex                            (weightFft[ndxWeightFft], from[ndx2From]);                    /**                     * <b>to[ndx1To] = from[ndx1From]       </b>                     * <b>             + weightFftTimesFrom2</b>                     */                    to[ndx1To].addComplex                            (from[ndx1From], weightFftTimesFrom2);                    /**                     * <b>to[ndx2To] = from[ndx1From]       </b>                     * <b>             - weightFftTimesFrom2</b>                     */                    to[ndx2To].subtractComplex                            (from[ndx1From], weightFftTimesFrom2);                    ndx1From += twiceCurrentDistance;                    ndx2From += twiceCurrentDistance;                    ndx1To += currentDistance;                    ndx2To += currentDistance;                    ndxWeightFft += currentDistance;                }            }            /**             * This call'd better be the last call in this block, so when             * it returns we go straight into the return line below.             *             * We switch the <i>to</i> and <i>from</i> variables,             * the total number of points remains the same, and             * the <i>currentDistance</i> is divided by 2.             */            butterflyStage(to, from, numberFftPoints, (currentDistance >> 1));        }        }


转:http://blog.csdn.net/taiyb/article/details/46315665