Let's simulate sinusoids of two frequencies using the following Matlab code:
fs = 1000; t = 0 : 1/fs : 1 - 1/fs; f1 = 3; f2 = 3.5; x1 = cos(2*pi*f1*t); x2 = cos(2*pi*f2*t); L1 = length(x1); L2 = length(x2);
If I take the FFT of the first signal using:
X1 = fft(x1);
and plot the resulting magnitude spectrum using:
figure; subplot(2, 1, 1); plot(t, x1) subplot(2, 1, 2); plot([-L1/2 : (L1/2 -1)]*fs/L1, fftshift(abs(X1)))
I find that the resulting magnitude spectrum exactly matches what I would expect (i.e. frequencies of $\pm$ 3 Hz have a height of 500 - which is 0.5*L1 times the magnitude of the 3 Hz component - and all other frequencies have a height of 0).
When I produce the same plot for x2, I find that the spectral energy has been distributed over frequencies around 3-4 Hz, resulting in a decrease in the magnitude of the peak at 3 Hz from 500 to around 320:
X2 = fft(x2); figure; subplot(2, 1, 1); plot(t, x2) subplot(2, 1, 2); plot([-L2/2 : (L2/2 -1)]*fs/L2, fftshift(abs(X2)))
From my understanding, this is due to the way that the DFT operates: it correlates sinusoids that have an integer number of cycles over the length of the signal with the signal. Since x2 has 3.5 cycles over its 1000 samples, neither a sinusoid of 3 Hz nor one of 4 Hz can exactly match the signal, although these two frequencies are the closest of all frequencies. Hence, we see large peaks at both of these frequencies.
If I zero-pad the signal, however, with 1000 additional zeros, I am able to find a 3.5 Hz component because the sinusoid that has 7 cycles in 2000 samples (with each sample corresponding to 1/1000 = 0.001 s) corresponds to a 3.5 Hz sinusoid (since we always scale the bins by fs/L = 1000/2000 = 0.5; so 0.5*7 = 3.5 Hz), and this exactly matches the signal in the first 1 second. Moreover, the magnitude of the peak is now 500, which matches the magnitude of the peak found for the 3 Hz signal without zero-padding.
x2 = [x2 zeros(1, 1000)]; X2 = fft(x2); L2 = length(x2); t_zeropad = [0:L2-1]/fs; figure; subplot(2, 1, 1); plot(t_zeropad, x2) subplot(2, 1, 2); plot([-L2/2 : (L2/2 -1)]*fs/L2, fftshift(abs(X2)))
This leads to a several related questions:
- What gives rise to the side lobes in the third figure? It's not because of the discontinuity at t = 1 because the effect is still present when the input signal is changed from cosine to sine, which makes the signal continuous at t = 1.
- By what factor do you scale the magnitude of the FFT by when you've zero-padded your signal? I know that for a sinusoidal signal that has not been zero padded and for which the number of cycles of the sinusoid within the length of the signal is an integer, you divide the magnitude by L/2. So in the first example, you'd divide 500 by (1000/2) to get 1, which matches the amplitude of the cosine wave. After zero-padding, the length of the signal is now 2000, so L/2 would be 1000, which means the peak amplitude in the magnitude plot would be 0.5. Should this scaling factor change when you zero pad?
- Does the factor change when the sinusoid does not evenly fit within the number of samples being analyzed, when you are dealing with a signal that is a linear combination of multiple sinusoids, or when you are dealing with a more complex signal (e.g. e(-t))?
- If someone just gave you a signal and didn't tell you whether zero-padding had been done or not, how would you be able to tell by what factor to scale the magnitude of the FFT to compute the amplitudes of the frequency components?
- Lastly, I noticed that if you zero-pad the signal x1, which has a frequency of 3 Hz, by 1000 samples, and take the FFT, we again see that at a frequency of 3 Hz, the magnitude is 500; that the spectral energy is spread out near 3 Hz; and that there are side lobes present (see figure below). With the original signal though (not zero-padded), I did not have these artifacts. This leads me to believe that, in a sense, zero-padding adds noise because, based on the magnitude spectrum, you are introducing frequency components which are not actually present. Is this a sensible way of thinking about this? Does this mean that you should not zero-pad unless you "have to," and if so, how do you know whether you have to or not? By how much should you zero-pad?