16

In the book "Computational Fourier Optics, A Matlab Tutorial" by David Voelz, it is written that a call to fftshift is needed before a call to fft or ifft, but in the MATLAB documentation of fftshift it's only written that this command

rearranges the outputs of fft, fft2, and fftn by moving the zero-frequency component to the center of the array.

There is no mention in documentation that this command should be called before the call to fft, and I saw some examples that call fft without a call to fftshift beforehand.

My question is: Whether or not fftshift needed to be called before a call to fft or ifft?

If fftshift doesn't need to be called before a call to fft, and only after a call to fft, then when should we use (if at all) the command ifftshift with relation to a calculation of the fft of a data set?

Adriaan
  • 17,741
  • 7
  • 42
  • 75
user4861528
  • 467
  • 1
  • 5
  • 20
  • Then a call to fft returns the same result whether or not you called fftshift beforehand ? How is it possible ? – user4861528 Aug 23 '15 at 13:20

7 Answers7

12

The matlab fft only computes half of the frequency spectrum (positive frequencies and the zero frequency if your number of samples is odd) in order to save computation time. Then, the second half of the frequency spectrum (which is the complex conjugate of the first half) is just added at the end of this vector.

So what you get after a fft is the following vector:

 0 1 2 3 ... Fs/2   -Fs/2 ... -3 -2 -1
<----------------> <------------------>
  positive freq        negative freq

where Fs is the frequency sample.

Now, what fftshift does is just shifting the negative frequency bins (2nd part of the frequency spectrum) at the beginning of your vector so that you can display a nice frequency spectrum starting at -Fs/2 and ending at +Fs/2. The shifted vector becomes:

 -Fs/2 ... -3 -2 -1   0 1 2 3 ... Fs/2
<------------------> <---------------->
    negative freq      positive freq

So, to answer your question, no you don't need to use fftshift after or before a call to fft or ifft. But if you used a fftshift on your vector, you should undo it by applying an ifftshift or fftshift. (I think both calls are equivalent.)

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Tikoloche
  • 351
  • 1
  • 14
  • 2
    What computations MATLAB does to produce the FFT output is irrelevant. The output of the FFT is given by the definition of the DFT, which has frequencies k=0..N-1. There are no "negative frequencies" in this output. The DFT is periodic, meaning that the value at k=0 is identical to the value at k=N, and at k=-N+1. Some people prefer to look at the output for k=-N/2..N/2, the `fftshift` function provides that ability. `ifftshift` is not the same as `fftshift`, their function differs for odd-sized input. – Cris Luengo Feb 27 '21 at 00:29
  • There's a nice discussion about fftshift and ifftshift in the Appendix and Comments on [this page](https://thepythoncodingbook.com/2021/08/30/2d-fourier-transform-in-python-and-fourier-synthesis-of-images/). Even though this is for numpy, I think it would apply to Matlab too. – ahmadh Nov 30 '22 at 17:08
5

If you read onwards in the documentation on fftshift: "It is useful for visualizing a Fourier transform with the zero-frequency component in the middle of the spectrum."

The shift is not necessary to perform the fft, but it is handy to visualise the Fourier transform. Whether to use fftshift or not is thus dependent upon whether you want to visualise your transform or not.

Adriaan
  • 17,741
  • 7
  • 42
  • 75
  • I guess when you transform your array for plotting and assign that over your original array instead of in a separate variable. – Adriaan Aug 23 '15 at 13:08
  • Then a call to fft returns the same result whether or not you called fftshift beforehand ? How is it possible ? – user4861528 Aug 23 '15 at 13:21
  • I just told you that: you shifted your transform for plotting and then want to shift your array back for further manipulation. But you can better assign the transform to a separate array and then not use the back transform but the original array. – Adriaan Aug 23 '15 at 13:24
3

Note that ifftshift is different than fftshift because it shifts the negative back to the positive. Assume a simple 3 bin unit impulse in frequency domain before fftshift

[0, exp(-jw1), exp(-(jw1-pi)=exp(-jw1+pi)];

fftshift gives

[exp(-jw1+pi)], 0, exp(-jw1)];

you can see the discontinuity in phase. If you perform ifftshift, negative freq is shifted back to positive:

[0, exp(-jw1), exp(-jw1+pi)];

whereas, fftshift again gives:

[exp(-jw1), exp(-jw1+pi), 0];

one can see the phase monotonicity is not the same, (aka, fftshift-ifftshift case gives [decrease, increase] and fftshift-fftshift case gives [increase, decrease] in phase).

Adriaan
  • 17,741
  • 7
  • 42
  • 75
Jun Ouyang
  • 31
  • 2
2

Given the title of the book you are studying, I assume you are working with images. Then the proper way is to call both fftshift and ifftshift before and after you call [i]fft.

Your code should look like

spectrum = fftshift(fft2(ifftshift(myimage))

It is quite the same when applying the inverse Fourier transform

myimage = fftshift(ifft2(ifftshift(spectrum))
1

The simple answer is call to fftshift not needed before a call to fft. fftshift does not influence the calculation of Fast fourier transform. fftshift rearranges values inside a matrix. For eg:

cameraman = imread('cameraman.tif');
fftshifted_cameraman = fftshift(cameraman);
subplot(1,2,1); imshow(cameraman); title('Cameraman');
subplot(1,2,2); imshow(fftshifted_cameraman); title('FFTShifted Cameraman');
NSredar
  • 11
  • 3
0

It depends on what you are going to do with the transformed data. If you don't perform an fftshift before transforming, the fft result will have every other value multiplied by -1. This doesn't matter if you plan to view the magnitude or magnitude squared of the result. However, if you plan to compare adjacent spectral values and phase is important, you'll need to apply fftshift before transforming to avoid the alternating sign.

0

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;