FFT with different orders and their results

Hey.

I am currently developing a realtime FFT-analyzer and want to use the juce fft. Great and easy to use like all the other juce stuff. Thanks! :slight_smile:
But there is a little thing, I don’t understand. For testing, I use a simple sawtooth signal and pass it through the fft and for the tests I choosed different fft-orders.

Actually, I have expected results that are similar only that they have different resolutions, but they differ more than expected. especially the amplitudes are quite noticeable.Take a look at the image.

the left uses the fft order 10 and the right the fft order 14. The aplitudes with order 14 are much higher. First I thought, it was my window function and I deactivated it. so the signal is as pure straight saw. Why is the right one much higher?

Did you scale the magnitudes?

IIRC the magnitude of a frequency is the real part divided by the number of bins, but please double check.
It would explain, why you got a higher magnitude with a higher order FFT.

EDIT: I found the post that helped me back then: In what units does frequency fft return values?

2 Likes

thanks for your anwser but… i don’t get it. so I have…

.....
    fft.perform(source, output, false);

    for (int j = 0; j < frame->getSize(); j++)
    {
        mags[j] = getMagnitude(output[j]);
        phases[j] = getPhase(output[j]);
    }
....

and to get the mags and phases I am using the standard functions…

forcedinline static float getMagnitude(dsp::Complex<float>& harmonic)
{
	const float re = harmonic.real();
	const float im = harmonic.imag();
	return std::sqrt(re * re + im * im);
}

forcedinline static float getPhase(dsp::Complex<float>& harmonic)
{
	const float re = harmonic.real();
	const float im = harmonic.imag();
	return std::atan(im / re);
}

What do you exactly mean? If I divide the real by the nums of bins before I convert it into mags and phases, the mags in the visualizer are moving up and down over time (sure, i decreased the width of the circle in the img-real field). I also tried to divide the magnitude by the number of bins (and multiplied it with a factor, to see them again on the screen, cause they’re getting very tiny :smiley: ). So it doesn’t work for me. Something is missing. :thinking:

Divide the magnitude (both real and imaginary part) by the number of bins which is 2^order. Then your result should be scaled correctly.

By the way, did you know that you can simply use std::complex<float> as complex data type? Nothing technically wrong with what you are doing, but if you look into the juce dsp header you’ll find

namespace dsp
    {
        template <typename Type>
        using Complex = std::complex<Type>;
//...
    }

so dsp::Complex<float> is in fact a std::complex<float>. This means that you can simply use std::abs and std::arg instead of your own getMagnitude and getPhase implementations – no need to reinvent what’s already existing and often it is a good idea to use the std library implementations which might be optimized to the maximum :wink:

Okay. I get it. :man_facepalming: Thanks a lot, now the magnitudes are looking the same with different orders.

Thanks you. Will take a closer look at it. :wink: