c++fftkissfft

kissfft - Inverse Real FFT gives NaN


The real inverse FFT gives me an array full of NaNs instead of floats.

kiss_fftri(conf,complex_array,output);

The complex_array is normal, nothing wrong with the values i guess.

kiss_fftr_cfg conf = kiss_fftr_alloc(size,1,NULL,NULL);

The conf should be fine too as far as I know.

Anything wrong with the size? I know that the output size of the forward FFT must be N/2 + 1 and the size above should be N.

I've already made an simple working example with audio convolution in the frequency domain and everything, but I've no idea whats happening here.


enter image description here enter image description here

NaNs and some samples of the , complex_array above.

The size parameter in my example is always 18750. Thats the number of samples. N / 2 + 1 is therefore 7876.

First I'm having a mono channel with 450k samples. Then I'm splitting it on 24 parts. Every part is now 18750 samples. With each of those samples I'm making an convolution with an impulse response. So basically the numbers I'm printing above are lets say the first 20 samples in each of the 24 rounds the for loop is going. Nothing wrong here I guess.

I even did on kiss_fftr_next_fast_size_real(size) and it stays the same so the size should be optimal.


Here's my convolution:

kiss_fft_cpx convolution(kiss_fft_cpx *a, kiss_fft_cpx *b, int size)
{
    kiss_fft_cpx r[size];
    memset(r,0,size*sizeof(kiss_fft_cpx));
    int skalar = size * 2; // for the normalisation
    for (int i = 0; i < size; ++i){
        r[i].r = ((a[i].r/skalar) * (b[i].r)/skalar) - ((a[i].i/skalar) * (b[i].i)/skalar);
        r[i].i = ((a[i].r/skalar) * (b[i].i)/skalar) + ((a[i].i/skalar) * (b[i].r)/skalar);
    }
    return r;
}

The size I input here via the argument is the N/2 + 1.


Solution

  • It's not kiss which causes the problem here. It is how the result array is (mis)handled.

    To really "keep it simple and stupid" (KISS), I recommend to use STL containers for your data instead of raw c++ arrays. This way, you can avoid the mistakes you did in the code. Namely returning the array you created on the stack.

    kiss_fft_cpx convolution(kiss_fft_cpx *a, kiss_fft_cpx *b, int size)
    

    ... bears various problems. The return type is just a complex number, not a series.

    I would change the signature of the function to:

    #include <vector>
    typedef std::vector<kiss_fft_cpx> complex_vector;
    void 
    convolution
    ( const kiss_fft_cpxy *a
    , const kiss_Fft_cpx *b
    , int size
    , complex_vector& result 
    );
    

    Then, in the code, you can indeed resize the result vector to the necessary size and use it just like a fixed size array as far as your convolution computation is concerned.

    {
        result.resize(size);
        // ... use as you did in your code: result[i] etc..
    }