MATLAB Answers

Normalization of FFT output

21 views (last 30 days)
Vittorio Picco
Vittorio Picco on 11 Jun 2020
Commented: Vittorio Picco on 11 Jun 2020
In the FFT help for MATLAB R2018b there seems to be conflicting FFT normalization examples.
In the "Gaussian Pulse" example the time domain signal has lenght L and the FFT output has length n, n = nextpow2(L). The double-sided amplitude spectrum is normalized by n, i.e. the frequency domain number of points, P = abs(Y/n).
In the "Cosine Waves" examples, L and n are defined in the same way, but this time the double-sided amplitude spectrum is normalized by L, i.e the time domain number of points, P2 = abs(Y/L).
Why the difference? Which one is correct? Normalizing by the number of samples before or after zero-padding?

  0 Comments

Sign in to comment.

Answers (1)

David Goodmanson
David Goodmanson on 11 Jun 2020
Hello Vittorio,
In the gaussian case, the waveform has died down to zero each end (technically it's not zero, but it is smaller than realmin = 2.2251e-308 and hence becomes 0 in double precision). So adding more zeros at each end makes no difference to the waveform. Zero filling is almost always pointless in my opinion. It does affect normalization since you are dividing by n instead of L, but you do end up with an acceptable result.
The cosine case is different. Here you are transforming a continuous wave, a sum of cosines at three frequencies, and the idea is to find the amplitude of each component. Initially, the signal fills the entire time window. To get the correct amplitudes in the frequency domain, you divide the fft result by L (details below).
But it's important to note that L is not only the length of the array, it's also the number of points where the CW signal is nonzero. Once you zerofill, which is a terribly bad idea in this case, the former CW wave is cut off and you add zeros that contribute nothing to the height of the peaks in the transform. So you still need to dIvide by the original L. DIviding by n gives a result for amplitudes that is too small by a factor of L/n, which is the duty cycle of the signal in the new expanded time window.
** dividing by L: Suppose the time array (of length L) has array index m and array spacing delt. Consider a signal of frequency f0 and amplitude A. Then signal = A*exp(2*pi*i*f0*m*delt).
For the set of frequencies 'fn' in the frequency domain, each amplitude 'an' is
an = sum{m=0,L-1} A*exp(2*pi*i*f0*m*delt).*exp(-2*pi*i*fn*m*delt)
When fn matches f0, there is a sum of L identical terms that equal A, which produces L*A. So you have to divide by L to get back to an = A.
When zerofilling is done, there are still only L points that contribute to this sum, and the result is still L*A.
[the foregoing ignored some inessential off-by-one indexing issues].

  1 Comment

Vittorio Picco
Vittorio Picco on 11 Jun 2020
Thank you. I'll need to think about this a little longer. It totally makes sense about not zero-padding any signal that has not decayed to zero. It's somewhat different from my original question but I think probably more important, since normalization doesn't matter a whole lot if my FFT has been "corrupted" by the distortion instroduced by zero-filling. For my specific problem the signals go to zero in some cases but not all, so zero-padding is not a good idea and I'll end up normalizing by L no matter what.

Sign in to comment.

Tags

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by