1

MFCC を生成するための三角フィルターを作成しようとしています。私は IPP 6 に基づく既存のコードを持っていますが、IPP 8 が進行中であるため、機能し、現在サポートされていない古いライブラリに依存しない実装を取得したいと考えています。

関連するメルスケールの中心周波数を生成しました(さらに両端に2つ)。

次に、次のようにフィルターを作成しようとしています。

std::vector< std::vector< float > > ret;
int numFilters  = freqPositions.size() - 2;

for( int f = 1; f < numFilters + 1; f++ )
{
    float freqLow   = freqPositions[f - 1];
    float freqMid   = freqPositions[f];
    float freqHigh  = freqPositions[f + 1];

    float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples + 1);
    float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples + 1);
    float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples + 1);

    std::vector< float > fbank;
    for( int s = 0; s < (numSamples + 1); s++ )
    {
        if      ( s >= binLow && s < binMid )
        {
            const float fAmpl   = (s - binLow) / (float)(binMid - binLow);
            fbank.push_back( fAmpl );
        }
        else if ( s >= binMid && s <= binHigh )
        {
            const float fAmpl   = 1.0f - ((s - binMid) / (float)(binHigh - binMid));
            fbank.push_back( fAmpl );
        }
        else
        {
            fbank.push_back( 0.0f );
        }

    }

    ret.push_back( fbank );
}

次に、上記のベクトルを FFT の結果 (ビン 0 は 0Hz または DC オフセット ビン) で部分的に乗算し、それらを合計します (基本的にドット積)。

これはかなりうまく機能しているように見えますが、IPP と比較して得られる結果は、少し心配になるほど大きく異なります。

私が間違っていることはありますか?

全体のプロセスは、FFT を取得し、返された複素ベクトル (std::abs) の大きさを計算し、上記のように計算されたフィルター バンクを適用することで構成されます。コードは次のとおりです。

std::vector< float > ApplyFilterBanks( std::vector< std::vector< float > >& filterBanks, std::vector< float >& fftMags )
{
    std::vector< float > ret;
    for( int fb = 0; fb < (int)filterBanks.size(); fb++ )
    {
        float res = 0.0f;
        Vec::Dot( res, &filterBanks[fb].front(), &fftMags.front(), filterBanks[fb].size() );
        ret.push_back( res );
    }
    return ret;
}

{
    const int kFFTSize      = 1 << mFFT.GetFFTOrder();
    const int kFFTSizeDiv2  = kFFTSize >> 1;
    std::vector< float > audioToFFT;
    audioToFFT.reserve( kFFTSize );
    std::copy( pAudio, pAudio + numSamples, std::back_inserter( audioToFFT ) );
    audioToFFT.resize( kFFTSize );

    std::vector< float > hammingWindow( numSamples );
    Vec::BuildHammingWindow( hammingWindow );
    Vec::Multiply( &audioToFFT.front(), &audioToFFT.front(), &hammingWindow.front(), numSamples );

    std::vector< std::complex< float > > fftResult( kFFTSize + 1 );

    // FFT the incoming audio.
    mFFT.ForwardFFT( &fftResult.front(), &audioToFFT.front(), kFFTSize );

    // Calculate the magnitudes of the resulting FFT.
    Vec::Magnitude( &audioToFFT.front(), &fftResult.front(), kFFTSizeDiv2 + 1 );
    //Vec::Multiply( &audioToFFT.front(), &audioToFFT.front(), &audioToFFT.front(), kFFTSizeDiv2 + 1 );

    // Apply the MFCC filter banks.
    std::vector< float > filtered   = ApplyFilterBanks( mFilterBanks, audioToFFT );
}

これは、シリーズ 1 が私の MFCC で、シリーズ 2 が IPP のプロットです。

私の MFCC と IPP の比較

ログとリフターの段階 (IPP と同じように動作することが確認されています) の後、結果はさらに間違っています。

どんなアイデアや指針も大歓迎です!

編集: IPP 関数に関するドキュメントがここにあることを指摘しておく必要があります。

http://software.intel.com/sites/products/documentation/hpc/ipp/ipps/ipps_ch8/functn_MelFBankInitAlloc.html

これは数学を示しているようです。ただし、正確には yk と ck が何であるかはわかりません...

4

1 に答える 1

1

わかりました、私は今、問題をより良くしました。

最初に2つの問題が見つかりました:

float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples + 1);
float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples + 1);
float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples + 1);

次のようにする必要があります。

float binLow    = (freqLow  / (sampleRate / 2)) * (numSamples);
float binMid    = (freqMid  / (sampleRate / 2)) * (numSamples);
float binHigh   = (freqHigh / (sampleRate / 2)) * (numSamples);

2 つ目は、メル スペースの歩数を正しく計算していませんでした。私は次のことをしていました:

const float melStep     = melDiff / (numFilterBanks + 2);

私がやるべきだったとき:

const float melStep     = melDiff / (numFilterBanks + 1);

私の結果は、同一ではありませんが、より良い対応を示しています。

伐採前およびリフター済みの MFCC

そして最終的な MFCC:

最終MFCC

于 2013-09-20T19:44:33.860 に答える