KissFFT вперед/назад выдает шум, почему?

Я пытаюсь использовать KissFFT изначально в java-приложении, но прямой/обратный входной сигнал не возвращается должным образом: амплитуда сигнала почти отсутствует. Если я уберу коэффициент масштабирования (деление на 2N), результатом будет гармонический шум. Может ли кто-нибудь обнаружить ошибку?

Вот прямой вызов (скопирован из GDX, так что все должно быть в порядке!):

JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_spectrum(JNIEnv* env, jclass clazz, jlong handle, jshortArray obj_samples, jfloatArray obj_spectrum) {
    short* samples = (short*)env->GetPrimitiveArrayCritical(obj_samples, 0);
    float* spectrum = (float*)env->GetPrimitiveArrayCritical(obj_spectrum, 0);

        KissFFT* fft = (KissFFT*)handle;
        kiss_fftr( fft->forwardConfig, (kiss_fft_scalar*)samples, fft->spectrum );

        int len = fft->numSamples / 2 + 1;
        for( int i = 0; i < len; i++ )
        {
            float re = scale(fft->spectrum[i].r) * fft->numSamples;
            float im = scale(fft->spectrum[i].i) * fft->numSamples;

            if( i > 0 )
                spectrum[i] = sqrtf(re*re + im*im);
            else
                spectrum[i] = sqrtf(re*re + im*im);
        }

    env->ReleasePrimitiveArrayCritical(obj_samples, samples, 0);
    env->ReleasePrimitiveArrayCritical(obj_spectrum, spectrum, 0);

}

А вот и обратное (написано мной, возможно, с ошибкой ;)):

JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_inverse(JNIEnv* env, jclass clazz, jlong handle, jshortArray obj_samples) {
    short* shortSamples = (short*)env->GetPrimitiveArrayCritical(obj_samples, 0);

//@line:108

        KissFFT* fft = (KissFFT*)handle;
        kiss_fft_cpx out[fft->numSamples];

        kiss_fftri( fft->inverseConfig, fft->spectrum, (kiss_fft_scalar*)out );

        for (int i=0; i < fft->numSamples; i++) {
            shortSamples[i] = (out[i].r) / (fft->numSamples*2);
        }

    env->ReleasePrimitiveArrayCritical(obj_samples, shortSamples, 0);

}

person cmbryan    schedule 09.06.2012    source источник


Ответы (3)


По запросу protectedmember, вот более полный пример (во всяком случае, на нативной стороне). В итоге я немного изменил код libgdx (используя v.0.9.4). Я также скомпилировал с плавающей запятой, а не с фиксированной точкой, так как последняя вносила шум квантования при инверсии. Этот код должен работать для любого (поскольку kiss_fft_scalar адаптируется к короткому или плавающему в зависимости от флага компилятора), но не тестировался повторно с фиксированным, так как я обнаружил, что это бесполезно для серии fft->ifft .

Мне любопытно узнать, добились ли вы успеха, дайте мне знать!

(Обратите внимание, что этот код после libgdx находится под лицензией Apache 2.0!)

#include <com.badlogic.gdx.audio.analysis.KissFFT.h>

#include <kissfft/kiss_fftr.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

struct KissFFT
{
    kiss_fftr_cfg forwardConfig;
    kiss_fftr_cfg inverseConfig;
    kiss_fft_cpx* spectrum;
    int numSamples;
    int spectrumSize;
};

JNIEXPORT jlong JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_create(JNIEnv* env, jclass clazz, jint numSamples) {

    KissFFT* fft = new KissFFT();
    fft->forwardConfig = kiss_fftr_alloc(numSamples,0,NULL,NULL);
    fft->inverseConfig = kiss_fftr_alloc(numSamples,1,NULL,NULL);
    fft->spectrum = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * numSamples);
    fft->numSamples = numSamples;
    fft->spectrumSize = numSamples/2+1;
    return (jlong)fft;
}

JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_destroy(JNIEnv* env, jclass clazz, jlong handle) {

    KissFFT* fft = (KissFFT*)handle;
    free(fft->forwardConfig);
    free(fft->inverseConfig);
    free(fft->spectrum);
    free(fft);  
}

JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_spectrum(JNIEnv* env, jclass clazz, jlong handle, jfloatArray obj_samples, jfloatArray obj_mags) {

    kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetPrimitiveArrayCritical(obj_samples, 0);
    float* mags = (float*)env->GetPrimitiveArrayCritical(obj_mags, 0);

    KissFFT* fft = (KissFFT*) handle;

    kiss_fftr(fft->forwardConfig, samples, fft->spectrum);

    for(int i=0;i<fft->spectrumSize;i++) {
        mags[i] = hypotf(fft->spectrum[i].r,fft->spectrum[i].i);
    }

    env->ReleasePrimitiveArrayCritical(obj_samples, samples, 0);
    env->ReleasePrimitiveArrayCritical(obj_mags, mags, 0);
}

JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_inverse(JNIEnv* env, jclass clazz, jlong handle, jfloatArray obj_samples) {
    kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetPrimitiveArrayCritical(obj_samples, 0);

    KissFFT* fft = (KissFFT*)handle;

    kiss_fftri( fft->inverseConfig, fft->spectrum, samples );

    for(int i=0;i<fft->numSamples;i++) {
        samples[i] = samples[i] / (float)fft->numSamples;
    }

    env->ReleasePrimitiveArrayCritical(obj_samples, samples, 0);

}
person cmbryan    schedule 29.06.2012
comment
Это действительно полезно, но почему эта строка: samples[i] = samples[i] / (float)fft->numSamples;? - person neevek; 06.04.2016

См. мой ответ на аналогичный вопрос.

или из файла Kissfft README:

        Q: Why don't I get the output I expect?
        A: The two most common causes of this are
                1) scaling : is there a constant multiplier between what you got and what you want?
                2) mixed build environment -- all code must be compiled with same preprocessor
                definitions for FIXED_POINT and kiss_fft_scalar

person Mark Borgerding    schedule 10.06.2012
comment
Спасибо, Марк, проблема исправлена, но ваш совет по масштабированию также был полезен! - person cmbryan; 11.06.2012

Упс! Нашел проблему. Я должен был сделать обратное преобразование прямо в короткий массив:

kiss_fftri( fft->inverseConfig, fft->spectrum, shortSamples );
person cmbryan    schedule 10.06.2012