This thread started with one question about zero-padding the Discrete Fourier Transform (DFT) and the answers and comments brought up many points on other related concepts including the Continuous Fourier Series (CFS), Continuous Time Fourier Transform (CTFT), windowing, and possibly many others. As might be expected for a thread with so many comments and additional questions in the comments, it might be hard to follow how all of the concepts relate and flow to each other. Consequently, I thought it might be good to show exactly that, at least for some of these of these concepts.
I'm posting this as its own answer because I wasn't sure it would flow nicely as a comment in any of the other answers.
Define a simple, continuous-time signal
x(t) = 12*sin(2*Pi/T1*t) + 4*cos(2*Pi/T2*t);
x(t) is the sum of two periodic signals. Because the ratio T1/T2 is a rational number, we know that x(t) is periodic. By inspection, its fundamental period is
which we can verify by
Because x(t) is periodic, its CTFT is a train of scaled Dirac delta functions at the fundamental frequency (1/6 Hz) and its harmonics. In this case, we only get non-zero harmonics at f = +-1/3 and f = +-1/2
X(f) = expand(fourier(x(t),t,2*Pi*f))
X(f) =
Because x(t) is periodic, it has an exponential CFS represenation. The CFS coefficients as a function of n are computed by
C(n) = int(x(t)*exp(-1j*2*Pi*n/T*t),t,0,T)/T
C(n) =
Or, we could have used fourier to compute them just as well. Because the integrand in int has n as a parameter, it doesn't capture the special cases where abs(n) = 2 or abs(n) =3. Clean that up and C(n) is pretty simple C(n) = piecewise(n == npole,limit(C(n),n,npole),C(n));
C(n) = simplify(C(n))
C(n) =
The CFS coefficients are exactly the cofficients in the impulse train that defines X(f), a fact that will be taken advantage of below.
Plot the amplitudes of the four CFS coefficients.
stem(nval/T,abs(C(nval)))
Because we are using the exponential CFS, the amplitudes of C(n) and C(-n) are each 1/2 of the amplitude of the corresponding harmonic. Therefore, the plot tells us that the amplitude of the harmonic at 1/2 Hz is 12 and at 1/3 Hz is 4, which is exactly what we expect based on the definition of x(t).
Suppose we only have available to us a portion of x(t). The next step shows how Fourier analysis can still extract the amplitude information from the signal.
Define a window function that covers the portion of the signal that we have for processing. The triangular window function (for illustration) is parameterized by the number of periods of x(t) that it covers.
w(t,numperiod) = triangularPulse(0,numperiod*T,t);
Suppose we have 10 periods of x(t)
The CTFT of the window signal is
W(f) = simplify(fourier(w(t,nperiod),t,2*Pi*f));
Because w(t) covers a significant number of periods, its bandwidth in the frequency domain looks small relative to the frequency spacing between harmonics of x(t)
fplot(abs(W(f)),[-0.3 0.3]);
xline( double( 1/2/T),'r', '1/(2T)');
xline( double(-1/2/T),'r','-1/(2T)');
The peak of W(f) at f = 0 is
which is also area under the window.
int(w(t,nperiod),t,0,nperiod*T)
Apply the window to x(t) and compute the CTFT of the result
xw(t) = x(t)*w(t,nperiod);
XW(f) = fourier(xw(t),t,2*Pi*f);
Multiplication in the time domain corresponds to convolution in the frequency domain. Convolution of W(f) with the Dirac delta functions in X(f) correponds to shifting W(f) to the corresponding harmonics and multiplying by the corresponding Dirac coefficients. But those Dirac coefficients are just the CFS coefficients. Therefore, we can just as easily express the CTFT of xw(t) directly as
XWalt(f) = sum(C(nval).*W(f-nval/T));
Show that XW(f) and XWalt(f) are equivalent.
fplot(matlabFunction(abs(XW(f))),[-1 1]);
fplot(matlabFunction(abs(XWalt(f))),[-1 1]);
Because the bandwidth of W(f) is small relative to the harmonic spacing, XW(f) is essentially composed of replicas of W(f) shifted to the harmonic frequencies and scaled by the CFS coefficients. This result suggests that we can recover the amplitudes of C(n) at the harmonic frequencies by simply dividing XW(f) by W0.
stem(nval/T,abs(C(nval)))
If all we have is the blue curve, we would surmise that the underlying periodic signal is composed of two sinusoids at 1/2 Hz and 1/3 Hz with amplitudes 12 and 4 respectively.
With that framework in continuous-time, now move to discrete-time.
Define functions to evaluate numerically (not stricly necessary, just runs a bit faster than evaluating in symbolic and converting)
xfunc = matlabFunction(x(t));
wfunc = matlabFunction(w(t,numperiod),'Vars',[t numperiod]);
Assume a sampling period of
The number of samples to cover that many periods is
N = nperiod*double(T)/Ts;
and the associated time samples are
Evaluate the x(t) and w(t) at the sample times.
wval = wfunc(tval,nperiod);
Compute the DFT
XWdft= fftshift(fft(xval.*wval));
fval = ceil(linspace(-nfft/2,nfft/2-1,nfft))/nfft/Ts;
Now, to plot the DFT with the appropriate scaling, we need to divide out the effect of the window function. In discrete-time, without any other scaling on the output of fft, that corresoponds to dividing by the sum of the window samples stem(fval,abs(XWdft)/sum(wval));
If we had used a rectangular window, then sum(wval) = N and we'd just divide by N.
Overlay with the scaled version of XW(f)
The scaled DFT samples are essentially frequency domain samples of the XW(f)/W0 (in general, this relationship is only approximate where the approximation gets better as Ts gets smaller and N gets larger).
Zoom in to see things a little better
Because the DFT samples effectively recover XW(f)/W0, we again know the harmonic frequencies and the corresponding amplitudes.
Four DFT samples lay exactly on the harmonic frequencies because of how N was computed to cover exactly 10 periods for the given the value of Ts. In general, we cannot guarantee the data covers an integer number of periods; after all, the period is what we are trying to determine.
Also, the selection of Ts in this example is such that x[n] = x(n*Ts) is periodic in discrete-time.
Suppose we have bit more than 10 periods of samples.
N = round(nperiod*double(T)/Ts);
Going through the same process
wval = wfunc(tval,nperiod);
XWdft= fftshift(fft(xval.*wval));
fval = ceil(linspace(-nfft/2,nfft/2-1,nfft))/nfft/Ts;
stem(fval,abs(XWdft)/sum(wval));
shows that the DFT samples are not so "nice," particularly around 1/3 Hz, which is basically halfway between two DFT samples.
Now, we finally get to the original question about zero padding, which we can use to fill in DFT samples in the frequency domain
N = round(nperiod*double(T)/Ts);
wval = wfunc(tval,nperiod);
XWdft= fftshift(fft(xval.*wval,2^14));
fval = ceil(linspace(-nfft/2,nfft/2-1,nfft))/nfft/Ts;
stem(fval,abs(XWdft)/sum(wval));
As has been stated repeatedly, zero padding has no impact on the unscaled amplitude spectrum, and we recover the correct scaled amplitude spectrum as long as we divide by sum(wval), not the number of samples in DFT (2^14 in this instance). The zero padding recovers the information we seek, which is that the harmonics are somewhere very near 1/2 Hz and 1/3 Hz, with amplitudes nearly 12 and 4 respectively.
Although it looks like the DFT samples are samples of XW(f), that's not true because XW(f) is based on a 60 second window and the DFT sampes are based on a 60 + 6/4 = 61.5 second window, which has a slightly different CTFT. However, as long as the peak of CTFT of the window (whatever it may be) is at f = 0, the same process applies, i.e., using the peaks of XWdft(n)/sum(wval) to estimate the harmonic frequencies and amplitudes, as long as the DFT is normalized based on the actual window used, as done in this example.