sdr.plot.dft(x: ArrayLike, sample_rate: float | None = None, window: str | float | tuple | None = None, size: int | None = None, oversample: int | None = None, fast: bool = False, centered: bool = True, ax: Axes | None = None, type: 'plot' | 'stem' = 'plot', x_axis: 'freq' | 'bin' = 'freq', y_axis: 'complex' | 'mag' | 'mag^2' | 'db' = 'mag', diff: 'color' | 'line' = 'color', **kwargs)

Plots the discrete Fourier transform (DFT) of the time-domain signal \(x[n]\).

Parameters:
x: ArrayLike

The time-domain signal \(x[n]\).

sample_rate: float | None = None

The sample rate \(f_s\) of the signal in samples/s. If None, the x-axis will be labeled as “Normalized frequency”.

window: str | float | tuple | None = None

The SciPy window definition. See scipy.signal.windows.get_window() for details. If None, no window is applied.

size: int | None = None

The number of points to use for the DFT. If None, the length of the signal is used.

oversample: int | None = None

The factor to oversample the DFT. If None, the DFT is not oversampled. This is only considered if size is None.

fast: bool = False

Indicates whether to use the fast Fourier transform (FFT) algorithm. If True, the DFT size is set to the next power of 2.

centered: bool = True

Indicates whether to center the DFT about 0.

ax: Axes | None = None

The axis to plot on. If None, the current axis is used.

type: 'plot' | 'stem' = 'plot'

The type of plot to use.

x_axis: 'freq' | 'bin' = 'freq'

The x-axis scaling.

y_axis: 'complex' | 'mag' | 'mag^2' | 'db' = 'mag'

The y-axis scaling.

diff: 'color' | 'line' = 'color'

Indicates how to differentiate the real and imaginary parts of a complex signal. If "color", the real and imaginary parts will have different colors based on the current Matplotlib color cycle. If "line", the real part will have a solid line and the imaginary part will have a dashed line, and both lines will share the same color.

**kwargs

Additional keyword arguments to pass to the plotting function.

See also

sdr.plot.dtft

Notes

The discrete Fourier transform (DFT) is defined as

\[X[k] = \sum_{n=0}^{N-1} x[n] e^{-j 2 \pi k n / N},\]

where \(x[n]\) is the time-domain signal, \(X[k]\) is the DFT, \(k\) is the DFT frequency bin, and \(N\) is the number of samples in the DFT. The frequency corresponding to the k-th bin is \(\frac{k}{N} f_s\).

The DFT is a sampled version of the discrete-time Fourier transform (DTFT).

Examples

Create a tone whose frequency will straddle two DFT bins.

In [1]: n = 10  # samples

In [2]: f = 1.5 / n  # cycles/sample

In [3]: x = np.exp(1j * 2 * np.pi * f * np.arange(n))

In [4]: plt.figure(); \
   ...: sdr.plot.dft(x, x_axis="bin", type="stem");
   ...: 
../../_images/sdr_plot_dft_1.png

Plot the DFT against normalized frequency. Compare the DTFT, an oversampled DFT, and a critically sampled DFT. Notice that the critically sampled DFT has scalloping loss (difference between the true peak and the DFT peak) when the signal frequency does not align with a bin. Furthermore, the sidelobes are non-zero and large. This is known as spectral leakage – the spreading of a tone’s power from a single bins to all bins.

In [5]: plt.figure(); \
   ...: sdr.plot.dtft(x, color="k", label="DTFT"); \
   ...: sdr.plot.dft(x, oversample=4, type="stem", label="4x oversampled DFT"); \
   ...: sdr.plot.dft(x, type="stem", label="DFT");
   ...: 
../../_images/sdr_plot_dft_2.png

If a window is applied to the signal before the DFT is computed, the main lobe is widened and the sidelobes are reduced. Given the wider main lobe, the scalloping loss of the critically sampled DFT is also reduced. These benefits come at the cost of reduced frequency resolution.

In [6]: plt.figure(); \
   ...: sdr.plot.dtft(x, window="hamming", color="k", label="DTFT"); \
   ...: sdr.plot.dft(x, oversample=4, window="hamming", type="stem", label="4x oversampled DFT"); \
   ...: sdr.plot.dft(x, window="hamming", type="stem", label="DFT");
   ...: 
../../_images/sdr_plot_dft_3.png