【问题标题】:Android jTransforms, finding and understanding base frequencyAndroid jTransforms,查找和理解基频
【发布时间】:2014-01-30 18:36:21
【问题描述】:

所以我正在开发一个吉他调音器应用程序,并且我正在努力使用 FFT 来找到基本频率。这是我“尝试”从 PCM 声音阵列数据 [] 中查找频率的代码,大小为 4160(bufferSize),采样率为 8000 Hz

  DoubleFFT_1D fft1d = new DoubleFFT_1D(bufferSize); 
            double[] fftBuffer = new double[bufferSize*2]; 
            double[] magnitude = new double[bufferSize/2];

            // copy real input data to complex FFT buffer
            for(int i = 0; i < bufferSize-1; ++i){
                fftBuffer[2*i] = data[i];
                fftBuffer[2*i+1] = 0;
            }

            //perform  FFT on fft[] buffer
            fft1d.realForward(fftBuffer);

            // calculate power spectrum (magnitude) values from fft[]
            for(int i = 0; i < (bufferSize/2)-1; ++i) {

                double real =  (2 * fftBuffer[i]);
                double imaginary =  (2 * fftBuffer[i] + 1);
                magnitude[i] = Math.sqrt( real*real + imaginary*imaginary ); 

            }
            // find largest peak in power spectrum
            for(int i = 0; i < (bufferSize/2)-1; ++i) {
            if(magnitude[i] > maxVal){
                maxVal = (int) magnitude[i];           
                binNo = i;                  
                }   
            }
            // convert index of largest peak to frequency
            freq = 8000 * binNo/bufferSize;

其中大部分内容是基于在本网站上找到的类似问题的示例和答案,因此我对这一切的理解充其量只是粗略。

在使用音高发生器测试我的程序时,返回的频率值似乎变化很大。

我想知道我的代码中是否有任何明显的缺陷,或者我对过程的理解,以及任何指向正确方向的指针

【问题讨论】:

    标签: java android fft


    【解决方案1】:

    第一件事:

    使用

                double real =  fftBuffer[2*i])
                double imaginary =  fftBuffer[2*i + 1];
    

    因为这些是索引计算,而不是值的转换。

    你能给出realForward描述的链接吗?


    第二:如果你使用realForward,那么缓冲区不会与零交错,但你必须注意第一个频率。

    如果您在缓冲区中使用虚部为 0 的复数构造方法,则必须使用 complexForward FFT 方法。这不需要特别注意第一个频率。


    第三,为了避免频率检测中的伪影,请将窗口函数应用于您的信号段。即,淡入淡出。


    真实转发:

    输入时:

    buf[0]=x[0], buf[1]=x[1] etc. 
    buf[2n-1]=x[2n-1], 
    

    对于偶数 N=2n 个样本。

    输出:

    buf[0]=a[0], buf[1]=a[n], b[0]=0=b[n],
    
    buf[2]=a[1], buf[3]=b[1], 
    buf[4]=a[2], buf[5]=b[2], 
    etc., 
    buf[2n-2]=a[n-1], buf[2n-1]=b[n-1]
    

    complexForward: (N=2n 如果与上面相比)

    输入时:

    buf[0]=x[0], buf[1]=0,
    buf[2]=x[1], buf[3]=0,
    ... ,
    buf[2N-2]=x[N-1], buf[2N-1]=0
    

    输出时:

    buf[0]=a[0], buf[1]=b[0], 
    buf[2]=a[1], buf[3]=b[1],
    buf[4]=a[2], buf[5]=b[2],
     ... ,
    buf[2N-2]=a[N-1], buf[2N-1]=b[N-1],
    

    对于这个真实输入,a[N-k]=a[k] 和 b[N-k]=-b[k],所以大约一半的值是冗余的。

    【讨论】:

    • 窗口化是我接下来要解决的问题,但我不确定缺少窗口是否会产生如此大量的结果(100-3000ish,对于 330hz 音调)。会去看看我能不能得到一些结果。
    • 您必须首先纠正前两个基本错误才能获得任何可用的结果。
    • 更正了计算以找到幅度!我对你所说的“第一频率”有点困惑?只是检查一下,使用 realForward,我应该跳过创建复杂缓冲区,而使用 complexForward 我应该包含它?
    • 是的,我认为是这样,所以我有点跳过应用窗口,可能应该在 OP 中提到
    • 是的,无论是使用 complexForward 的复数缓冲区还是使用 realForward 的实数数组以及结果的打包格式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 2016-01-14
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多