2

iPodライブラリのスペクトルアプリのiPhone / iPod音楽ライブラリから周波数を取得しようとしています.reading-audio-samples-via-avassetreaderでオーディオサンプルを取得し、次にusing-the-apple-fft-and-を使用していますAccelerator-frameworkApple vDSP Samplesを使用していますが、どういうわけか私はどこか間違っていて、周波数を計算できません。

ステップバイステップ:

  • 音声サンプルを読む
  • ハニング窓
  • fftを計算する

これは、iPod mp3 ライブラリから周波数を取得する正しい方法ですか?

これが私のコードです:

static COMPLEX_SPLIT    A;  
static FFTSetup         setupReal;  
static uint32_t         log2n, n, nOver2;  
static int32_t          stride;  
static float            *obtainedReal;  
static float            scale;  

+ (void)initialize  
{  
    log2n = 10;  
   n = 1 << log2n;  

    stride = 1;  
    nOver2 = n / 2;  
    A.realp = (float *) malloc(nOver2 * sizeof(float));  
    A.imagp = (float *) malloc(nOver2 * sizeof(float));  

    obtainedReal = (float *) malloc(n * sizeof(float));  
    setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);  
}  


- (float) performAcceleratedFastFourierTransForAudioBuffer:(AudioBufferList)ioData   
{     
    NSUInteger * sampleIn = (NSUInteger *)ioData.mBuffers[0].mData;
    for (int i = 0; i < nOver2; i++) {
    double multiplier = 0.5 * (1 - cos(2*M_PI*i/nOver2-1));
        A.realp[i] = multiplier * sampleIn[i];
        A.imagp[i] = 0;
    }

    memset(ioData.mBuffers[0].mData, 0, ioData.mBuffers[0].mDataByteSize);  
    vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD);  

    vDSP_zvmags(&A, 1, A.realp, 1, nOver2);           

    scale = (float) 1.0 / (2 * n);  

    vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);  
    vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);  

    vDSP_ztoc(&A, 1, (COMPLEX *)obtainedReal, 2, nOver2);  

    int peakIndex = 0;  
    for (size_t i=1; i < nOver2-1; ++i) {  
        if ((obtainedReal[i] > obtainedReal[i-1]) && (obtainedReal[i] > obtainedReal[i+1]))         
        {  
            peakIndex = i;  
            break;  
        }  
    }  

    //here I don't know how to calculate frequency with my data   
    float frequency = obtainedReal[peakIndex-1] / 44100 / n;

    vDSP_destroy_fftsetup(setupReal);  
    free(obtainedReal);  
    free(A.realp);  
    free(A.imagp);  

    return frequency;  
}  

私は1.4857571.332233私の最初の周波数として

4

1 に答える 1

3

FFT の複素数入力への変換に問題があるように見えます。 vDSP_ctoz()は、実数成分と虚数成分が 2 つのバッファー (1 つは実数、もう 1 つは虚数) にインターリーブされるバッファーを分割します。その関数への入力は、にキャストされた実際のデータのように見えますCOMPLEX。これは、入力バッファがvDSP_ctoz()必要な長さの半分にすぎず、バッファ サイズを超えるガベージ データが変換されていることを意味します。

長さを作成sampleOut2*nて他のすべての値(実部)を設定するか、さらに良いことに、をバイパスしvDSP_ctoz()て入力データを直接コピーしてゼロ A.realpに設定する必要があります。インターリーブされた複雑なデータを生成するソースに接続する場合にのみ必要です。A.imagpvDSP_ctoz()

編集

vDSP のドキュメントでは、実数から複素数へのインプレース fft の実際の入力は、偶数サンプルimagpと奇数サンプルを含む分割複素数形式にフォーマットする必要があると記載されているため、最初の提案は間違っていたと思いrealpます。vDSP ライブラリを実際に使用したことはありませんが、他の多くの FFT ライブラリに精通しているため、その詳細を見逃していました。

At that pointA.realpへの呼び出しの後に使用して、ピークを見つけることができるはずです。これには、スカラーである FFT 出力の 2 乗の大きさが含まれている必要があります。スケーリングを行う場合は、mag2 操作の前に行う必要がありますが、ピークを探すだけであれば必要ない場合があります。vDSP_zvmags(&A, 1, A.realp, 1, nOver2);A.realp

FFT 出力で表される実際の周波数を取得するには、次の式を使用します。

F = (i * Fs) / N,   i=0,1,...,N/2

どこ

iは FFT 出力バッファのインデックスです Fsはオーディオのサンプリング レート Nです FFT の長さです

したがって、計算は次のようになります。

float frequency = (peakIndex * 44100) / n;

後半は冗長であるため、vDSP は実際の入力の入力スペクトルの前半のみを返すことに注意してください。したがって、FFT 出力は から0までの周波数を表しますFs/2

もう1つの注意点は、FFT出力がスムーズではなく、多くの振動が発生することが多いため、ピーク検出アルゴリズムがうまく機能するかどうかはわかりません. 隣接する 2 つのサンプルが低い最初のサンプルを取得しているだけです。単一のピークを見つけたいだけの場合は、出力全体の最大マグニチュードを見つけるだけの方がよいでしょう。複数のピークを見つけたい場合は、より高度な操作を行う必要があります。

于 2011-05-03T14:19:05.990 に答える