Here is a MATLAB script I use to test basic sound analysis functions of MATLAB including fftshift()
in displaying the output of fft()
.
if ~exist('inputFile', 'var')
inputFile = 'vibe.wav';
end
[inputBuffer, Fs] = audioread(inputFile);
fileSize = length(inputBuffer);
numSamples = 2.^(ceil(log2(fileSize))); % round up to nearest power of 2
x = zeros(numSamples, 1); % zero pad if necessary
x(1:fileSize) = inputBuffer(:,1); % if multi-channel, use left channel only
clear inputBuffer; % free this memory
clear fileSize;
t = linspace(0, (numSamples-1)/Fs, numSamples)';
f = linspace(-Fs/2, Fs/2 - Fs/numSamples, numSamples)';
X = fft(x);
plot(t, x);
xlabel('time (seconds)');
ylabel('amplitude');
title(['time-domain plot of ' inputFile]);
sound(x, Fs); % play the sound
pause;
% display both positive and negative frequency spectrum
plot(f, real(fftshift(X)));
xlabel('frequency (Hz)');
ylabel('real part');
title(['real part frequency-domain plot of ' inputFile]);
pause;
plot(f, imag(fftshift(X)));
xlabel('frequency (Hz)');
ylabel('imag part');
title(['imag part frequency-domain plot of ' inputFile]);
pause;
plot(f, abs(fftshift(X))); % linear amplitude by linear freq plot
xlabel('frequency (Hz)');
ylabel('amplitude');
title(['abs frequency-domain plot of ' inputFile]);
pause;
plot(f, 20*log10(abs(fftshift(X))+1.0e-10)); % dB by linear freq plot
xlabel('frequency (Hz)');
ylabel('amplitude (dB)');
title(['dB frequency-domain plot of ' inputFile]);
pause;
% display only positive frequency spectrum for log frequency scale
semilogx(f(numSamples/2+2:numSamples), 20*log10(abs(X(2:numSamples/2)))); % dB by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('amplitude (dB)');
title(['dB vs. log freq, frequency-domain plot of ' inputFile]);
pause;
semilogx(f(numSamples/2+2:numSamples), (180/pi)*angle(X(2:numSamples/2))); % phase by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('phase (degrees)');
title(['phase vs. log freq, frequency-domain plot of ' inputFile]);
pause;
%
% this is an alternate method of unwrapping phase
%
% phase = cumsum([angle(X(1)); angle( X(2:numSamples/2) ./ X(1:numSamples/2-1) ) ]);
% semilogx(f(numSamples/2+2:numSamples), phase(2:numSamples/2)); % unwrapped phase by log freq plot
%
semilogx(f(numSamples/2+2:numSamples), unwrap(angle(X(2:numSamples/2)))); % unwrapped phase by log freq plot
xlabel('frequency (Hz), log scale');
ylabel('unwrapped phase (radians)');
title(['unwrapped phase vs. log freq, frequency-domain plot of ' inputFile]);
If you were windowing segments of audio and passing them to the FFT, then you should use fftshift()
on the input to the FFT to define the center of the windowed segment as the t=0 point.
[x_input, Fs] = audioread('vibe.wav'); % load time-domain input
N = 2*floor(length(x_input)/2); % make sure N is even
x = x_input(1:N);
t = linspace(-N/2, N/2-1, N); % values of time in units of samples
omega = linspace(-pi, pi*(1-2/N), N); % values of (normalized) angular frequency
X = fftshift( fft( fftshift( x.*hamming(length(x)) ) ) );
[X_max k_max] = max( abs(X) );
figure(1);
plot(t, x, 'g');
figure(2);
plot(omega, abs(X), 'b');
hold on;
plot(omega(k_max), X_max, 'or');
hold off;