Changes

Created page with "[https://www.python.org/ Python] and [https://matplotlib.org/ Matplotlib] are great tools for doing Science! In particular, I like to use the [https://www.spyder-ide.org/ Spyd..."
[https://www.python.org/ Python] and [https://matplotlib.org/ Matplotlib] are great tools for doing Science! In particular, I like to use the [https://www.spyder-ide.org/ Spyder IDE]. Matplotlib makes it easy to create graphs from datasets. In the world of [https://en.wikipedia.org/wiki/Digital_signal_processing DSP], an example of this usage is plotting sampled data sets in the time domain and frequency domain. However, by default your frequency domain plot's x-axis will simply be labelled with the indices of your sampled data array. In DSP it is often desirable to remap this range of indices (0 to N-1) to the frequencies of -Pi to Pi. Unfortunately there isn't a 1 step solution to this remapping. However, with a little bit of code you can accomplish this relatively easily.

The code below with show you how to go from this most basic graph of a DFT:

[[File:dft.png]]

to the much, prettier, shifted and relabeled graph of a DFT

[[File:Shifted_dft_-pi_to_pi.png]]

To remap your DFT so that it is centered about 0 frequency you can use the following <code>dft_shift</code> function.

<syntaxhighlight lang="python" line='line'>
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

# define dft_shift to center the DFT about 0. Make sure the final length is odd so 0 is at the center
def dft_shift(X):
N = len(X)
if (N % 2 == 0):
# even-length: return N+1 values
return np.arange(-int(N/2), int(N/2) + 1), np.concatenate((X[int(N/2):], X[:int(N/2)+1]))
else:
# odd-length: return N values
return np.arange(-int((N-1)/2), int((N-1)/2) + 1), np.concatenate((X[int((N+1)/2):], X[:int((N+1)/2)]))
</syntaxhighlight>

To change a matplotlib plot's x-axis to display from -Pi to Pi you can use the following lines of code. X is assumed to be your sampled data array
<syntaxhighlight lang="python" line='line'>
n_pi = np.linspace(-np.pi,np.pi,len(X)) # create array from -pi to pi that is the same length as your sampled data array
plt.xlim([-np.pi, np.pi]) # set x-axis display range from -Pi to Pi
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$\pi$']) # display ticks in pi format rather than 3.14 format
plt.stem(n_pi, abs(X)) # plot sampled data array X using n_pi as the indicies
</syntaxhighlight>

The complete Python script below puts it all together and walks you through graphing the same data in various formats.

<syntaxhighlight lang="python" line='line'>
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

# define dft_shift to center the DFT about 0. Make sure the final length is odd so 0 is at the center
def dft_shift(X):
N = len(X)
if (N % 2 == 0):
# even-length: return N+1 values
return np.arange(-int(N/2), int(N/2) + 1), np.concatenate((X[int(N/2):], X[:int(N/2)+1]))
else:
# odd-length: return N values
return np.arange(-int((N-1)/2), int((N-1)/2) + 1), np.concatenate((X[int((N+1)/2):], X[:int((N+1)/2)]))

# define the size of the figures
plt.rcParams["figure.figsize"] = (14,4)

# create simple baseband signal
N = 64
x = np.ones(N)

# plot x
plt.figure()
plt.title("baseband signal of 1s")
plt.stem(x)

# plot DFT(x) = X
X = np.fft.fft(x)
plt.figure()
plt.title("basic DFT")
plt.stem(abs(X))

# plot shifted X with default indicies
n,X_shift = dft_shift(X) # get the shifted version of X. n contains integer indicies centered about 0
plt.figure()
plt.title("shifted DFT with default indicies")
plt.stem(abs(X_shift)) # plot shifted X with "default" 0 to len(X_shift) indicies

# plot shifted X with n as indicies
n,X_shift = dft_shift(X) # get the shifted version of X. n contains integer indicies centered about 0
plt.figure()
plt.title("shifted DFT with n as indicies")
plt.stem(n, abs(X_shift)) # plot shifted X using n as indicies

# plot shifted X with plot scaled from -Pi to Pi (but still with integer indicies)
n,X_shift = dft_shift(X) # get the shifted version of X. n contain indicies centered about 0
plt.figure()
plt.title("shifted DFT from -Pi to Pi with n as indicies (notice only 7 points are plotted)")
plt.xlim([-np.pi, np.pi]) # x-axis display range from -Pi to Pi
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$\pi$']) # display ticks in pi format rather than 3.14 format
plt.stem(n, abs(X_shift)) # plot shifted X using n as the indicies

# plot shifted X with X-axis indicies from -Pi to Pi and plot scaled from -Po to Pi
n,X_shift = dft_shift(X) # get the shifted version of X. n contain indicies centered about 0
n_pi = np.linspace(-np.pi,np.pi,len(n)) # create array from -pi to pi that is the same length as n
plt.figure()
plt.title("shifted DFT from -Pi to Pi with n_pi as indicies")
plt.xlim([-np.pi, np.pi]) # x-axis display range from -Pi to Pi
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$\pi$']) # display ticks in pi format rather than 3.14 format
plt.stem(n_pi, abs(X_shift)) # plot shifted X using n_pi as the indicies
</syntaxhighlight>

=REFERENCES=
*Coursera Digital Signal Process [https://www.coursera.org/learn/dsp/ Course] developed by the [https://www.epfl.ch/en/ EPFL]
*Rougier's Matplotlib [https://github.com/rougier/matplotlib-tutorial Tutorial]