The discrete cosine transform(DCT) is a popular choice for spectral analysis in audio, video, image compression algorithms. This is primarily due its efficient "spectral compaction" property in comparison with Fast Fourier Transform(FFT). Is there a way to measure approximate "spectral compaction-gain" (if its appropriate to term) - say "X" times - achieved by using DCT on data instead of FFT?
2 Answers
In Discrete-Time Signal Processing by Oppenheim, chapter 8.5, there is a quantification of mean squared error by setting coefficients to 0 for both DCT and DFT:
From this, you can of course calculate the percentages as you see fit. This particular analysis was done for signal:
$$x[n] = a^n\cos(\omega_0n + \phi)$$
with following transforms:
If you wish to play with this example here's the code. It gives both the MSE and the amount of energy preserved after reconstruction.
%% Signal to analyse
N = 32; % Must be even!
a = 0.9;
w0 = 0.1*pi;
n = 1:N;
x = a.^n.*cos(w0*n);
plot(n, x)
%% Calculate transforms
Xdft = fft(x);
Xdct = dct(x);
%% Plot
figure(1)
subplot(3,1,1)
stem(0:N/2, real(Xdft(1:N/2+1)))
title("Real part of DFT")
subplot(3,1,2)
stem(0:N/2, imag(Xdft(1:N/2+1)))
title("Imaginary part of DFT")
subplot(3,1,3)
stem(0:N-1, Xdct)
title("DCT")
%% Compact and measure
mseDFT = []; % Mean Squared Error
mseDCT = [];
energyDFT = []; % Energy preserved
energyDCT = [];
%In case of DFT we must zero 1,3,5,... bins starting from Nyquist
for m=1:N/2
xRec = dftReconstructCompact(Xdft, m);
mseDFT(m) = mean(abs(x-xRec).^2);
energyDFT(m) = norm(xRec) / norm(x);
end
for m=1:N
xRec = dctReconstructCompact(Xdct, m);
mseDCT(m) = mean(abs(x-xRec).^2);
energyDCT(m) = norm(xRec) / norm(x);
end
%% Plot the errors
figure(2)
plot(1:N, mseDCT, '-x')
hold on
plot(1:2:N, mseDFT, '-o')
grid on
legend({"DCT", "DFT"})
title("MSE between original and truncated")
figure(3)
plot(1:N, energyDCT, '-x')
hold on
plot(1:2:N, energyDFT, '-o')
grid on
legend({"DCT", "DFT"})
title("Energy Preserved after truncation")
%% Helper functions
function xRec = dftReconstructCompact(X, m)
% Zero-out 2*m-1 points from the DFT (starting from Nyquist bin and move
% left and right from there) then reconstruct the time domain signal.
Nyq = length(X)/2+1;
X(Nyq-m+1:Nyq+m-1) = 0;
xRec = ifft(X);
end
function xRec = dctReconstructCompact(X, m)
% Starting from the highest bin, zero out `m` values and reconstruct
% the time domain signal.
N = length(X);
X(N-m+1:N) = 0;
xRec = idct(X);
end
My copy of MATLAB documents the dct() function by a first example showing how many coefficients are required to represent 99% of the energy of a signal. I guess you could extend that example code to also do fft() or possibly pca()?