Notes on FFT

MATLAB
Published

September 7, 2026

This note provides a practical workflow for computing FFT frequency, magnitude, and phase vectors for real-valued signals, including index formulas for both even and odd nfft.

Problem setup

  • A vector x with length L
  • A sample rate Fs
  • x is real-valued

Objectives

  • FFT result with chosen nfft
  • Unshifted FFT-bin frequency, magnitude, and phase vectors
  • Single-sided frequency, magnitude, and phase vectors for even nfft
  • Single-sided frequency, magnitude, and phase vectors for odd nfft

Method

FFT with nfft

Choosing nfft > L zero-pads the signal in time domain and decreases frequency-bin spacing. This densifies the displayed spectrum but does not increase the true resolving power set by record length and windowing.

Y = fft(x, nfft);

Unshifted FFT-bin spectrum (two-sided content)

Frequency

Use frequency resolution \(\Delta f = Fs / nfft\). This unshifted frequency axis runs from \(0\) to \(Fs-\Delta f\).

frequencyResolution = Fs/nfft;
frequencyVectorDoubleSided = (0:nfft-1)*frequencyResolution;

Magnitude

magnitudeDoubleSided = abs(Y)./L;

Phase

phase = angle(Y);

Why some bins are doubled

Key idea: you double only bins that lost a distinct mirror partner.

For real-valued signals, FFT bins satisfy conjugate symmetry: \(X[k] = X^*[N-k]\). When forming a single-sided spectrum, negative-frequency bins are omitted. Any positive-frequency bin that had a distinct negative-frequency partner should be doubled to preserve one-sided amplitude.

  • Never double DC (first bin), because it is self-paired.
  • For even nfft, never double Nyquist (Fs/2), because it is also self-paired.
  • Double only bins with a distinct partner on the discarded side.

Single-sided spectrum (even nfft)

Frequency

frequencyResolution = Fs/nfft;
frequencyVectorSingleSided_even = (0:nfft/2)*frequencyResolution;

Magnitude

Apply the mirror-partner rule above: do not multiply DC or Nyquist. Scale only bins 2 through end-1.

magnitudeSingleSided_even = magnitudeDoubleSided(1:nfft/2+1);
magnitudeSingleSided_even(2:end-1) = 2*magnitudeSingleSided_even(2:end-1);

Phase

phase_even = angle(Y(1:nfft/2+1));

Single-sided spectrum (odd nfft)

Frequency

frequencyResolution = Fs/nfft;
frequencyVectorSingleSided_odd = (0:(nfft-1)/2)*frequencyResolution;

Magnitude

Apply the mirror-partner rule above: do not multiply DC. For odd nfft there is no Nyquist bin, so scale bins 2 through end.

magnitudeSingleSided_odd = magnitudeDoubleSided(1:(nfft+1)/2);
magnitudeSingleSided_odd(2:end) = 2*magnitudeSingleSided_odd(2:end);

Phase

phase_odd = angle(Y(1:(nfft+1)/2));

Example

This example uses a signal with non-zero mean, one low-frequency sinusoid, and one high-frequency sinusoid.

clc; clear; close all;
Fs = 2001; % Hz
time = 0:1/Fs:2;
signalMean = 4;
signalLowFrequencyComponent = sin(2*pi*10*time + 45/180*pi);
signalHighFrequencyComponent = 0.1*cos(2*pi*94*time + pi*30/180);
signal = signalMean + signalLowFrequencyComponent + signalHighFrequencyComponent;
L = length(signal);

Even nfft calculations

nfft_even = 16384;
Y_even = fft(signal, nfft_even);
magnitudeDoubleSided_even = abs(Y_even)./L;
magnitudeSingleSided_even = magnitudeDoubleSided_even(1:nfft_even/2+1);
magnitudeSingleSided_even(2:end-1) = 2*magnitudeSingleSided_even(2:end-1);
frequencyResolution_even = Fs/nfft_even;
frequencyVectorSingleSided_even = (0:nfft_even/2)*frequencyResolution_even;
phase_even = angle(Y_even(1:nfft_even/2+1));

figure
subplot(2,1,1)
semilogy(frequencyVectorSingleSided_even, magnitudeSingleSided_even)
xlabel('Frequency [Hz]')
ylabel('Magnitude [-]')
axis tight

subplot(2,1,2)
plot(frequencyVectorSingleSided_even, phase_even*180/pi)
xlabel('Frequency [Hz]')
ylabel('Phase [deg]')
axis tight

Even nfft spectrum

Odd nfft calculations

nfft_odd = nfft_even + 1;
Y_odd = fft(signal, nfft_odd);
magnitudeDoubleSided_odd = abs(Y_odd)./L;
magnitudeSingleSided_odd = magnitudeDoubleSided_odd(1:(nfft_odd+1)/2);
magnitudeSingleSided_odd(2:end) = 2*magnitudeSingleSided_odd(2:end);
frequencyResolution_odd = Fs/nfft_odd;
frequencyVectorSingleSided_odd = (0:(nfft_odd-1)/2)*frequencyResolution_odd;
phase_odd = angle(Y_odd(1:(nfft_odd+1)/2));

figure
subplot(2,1,1)
semilogy(frequencyVectorSingleSided_odd, magnitudeSingleSided_odd)
xlabel('Frequency [Hz]')
ylabel('Magnitude [-]')
axis tight

subplot(2,1,2)
plot(frequencyVectorSingleSided_odd, phase_odd*180/pi)
xlabel('Frequency [Hz]')
ylabel('Phase [deg]')
axis tight

Odd nfft spectrum

Summary

Use this sequence each time:

  1. Choose nfft and compute Y = fft(x, nfft).
  2. Build unshifted FFT-bin vectors from Y.
  3. Build single-sided vectors by selecting half-spectrum and applying correct scaling: for even nfft, double bins 2:end-1; for odd nfft, double bins 2:end.
  4. Use even/odd indexing formulas that match nfft parity.