In this notebook, we're going to visualize the data obtained by a Fourier transform in an uncommon way: we will use both the absolute magnitude and the phase in the same plot. I've come across this way of displaying the information associated with Fourier transforms while studying a non-linear optics course on Coursera.
In this post, we proceed in the following way:
interact
)Below, I show a frequency analysis example found on the internet to generate a time signal, which is then used as input data for the Fourier transform. The time signal is plotted next to the frequency transform.
%matplotlib inline
from pylab import *
# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / 800.0
x = linspace(0.0, N*T, N)
y = sin(100.0 * 2.0 * pi * x) + 0.5*sin(80.0 * 2.0*pi*x)
yf = fft(y)
xf = linspace(0.0, 1.0/(2.0*T), N/2)
subplot(211)
title("time signal")
plot(x, y)
xlabel("time")
grid()
subplot(212)
title("frequency data")
plot(xf, 2.0/N * abs(yf[0:N/2]))
grid()
xlabel("frequency")
tight_layout()
While the time signal is very complex, and yields no information to the naked eye, the Fourier transform shows that the signal is a simple sum of two sinusoids, the first one having a frequency of 50 Hz and the second a frequency of 80 Hz.
Another comment relating to the previous representation is that only the modulus of the Fourier transform is used in the plot. A more complete representation of the data can be achieved using the phase information. This would look like this:
subplot(211)
title('modulus of Fourier transform')
plot(xf, 2.0/N * abs(yf[0:N/2]))
grid()
subplot(212)
title('phase of Fourier transform')
plot(xf, angle(yf[0:N/2]))
grid()
tight_layout()
But we can do better than the last plot! Why not use the phase of the transform to color the module plot (this is what was done during the non-linear optics class)? We will use this example as a starting point and build a colored Fourier transform based on polygons built upon the frequency transformed data.
We start with a simple example, where we plot rectangles for each element in a curve. We make use of the Rectangle
patch that is built-in with matplotlib
.
import matplotlib.patches as patches
import matplotlib.colors as colors
fig = plt.figure()
ax = fig.add_subplot(111)
norm = colors.Normalize(0, 11)
for i in range(11): # loop for first half of pyramid
color = cm.jet(norm(i))
patch = patches.Rectangle((i, 0), 1, i, facecolor=color, edgecolor=color)
ax.add_patch(patch)
for i in range(1, 10): # loop for second half of pyramid
color = cm.jet(norm(10 - i))
patch = patches.Rectangle((10 + i, 0), 1, 10 - i, facecolor=color, edgecolor=color)
ax.add_patch(patch)
# we need to scale the axes to display the figure properly
xlim(0, 21)
ylim(0, 10)
(0, 10)
As you can see, the height of each bar is responsible for its color.
We can now move on to a more general function that will use Polygon
as a drawing primitive, so that we can position each polygon at different left and right heights.
import matplotlib.patches as patches
import matplotlib.colors as colors
def plot_fft_with_phase(ax, xf, yf):
phases = angle(yf)
norm = colors.Normalize(phases.min(), phases.max())
for left, right, ampl_left, ampl_right, phase in zip(xf[:-1], xf[1:], yf[:-1], yf[1:], phases):
color = cm.jet(norm(phase))
xy = array([[left, 0], [left, abs(ampl_left)], [right, abs(ampl_right)], [right, 0]])
patch = patches.Polygon(xy, facecolor=color, edgecolor=color)
ax.add_patch(patch)
return (xf.min(), xf.max(), abs(yf).min(), abs(yf).max())
We can test this function on our example data:
fig = plt.figure()
ax = fig.add_subplot(111)
xmin, xmax, ymin, ymax = plot_fft_with_phase(ax, xf, 2.0/N * (yf[0:N/2]))
xlim(xmin, xmax)
ylim(ymin, ymax)
(3.8487731520338761e-17, 0.96980162341340059)
As one can see, an interesting property of the phase is shown in the plot above: there is a phase change at the first frequency in the signal as well as in the second one.
Let's apply our visualization technique to some time signals. Below, we generated a frequency modulated pulse and interactively select its parameters.
from IPython.html.widgets import interact
def impulse_signal(t, f, tau, phase=0):
return cos(2 * pi * f * t + phase) * exp(-t**2/tau**2)
t = linspace(-10, 10, 200)
s = impulse_signal(t, 1, 2)
plot(t, s)
[<matplotlib.lines.Line2D at 0x107b23e48>]
def plot_with_colors(f, tau, userxmax=None, phase=0):
fig = figure()
ax = fig.add_subplot(211)
t = linspace(-10, 10, 500)
s = impulse_signal(t, f, tau, phase=phase)
ax.plot(t, s)
ax2 = fig.add_subplot(212)
yf = fft(s)
xf = fftfreq(yf.size, t[1] - t[0])
xmin, xmax, ymin, ymax = plot_fft_with_phase(ax2, xf, yf)
if userxmax != None:
xlim(0, userxmax)
else:
xlim(xmin, xmax)
ylim(ymin, ymax)
interact(plot_with_colors,
f=(1, 3, 0.1),
tau=(.1, 3, 0.1),
userxmax=(1, 5, 0.1),
phase=(0, 3.14, 0.1))
This is it. This way of visualizing Fourier transforms can be helpful, depending on your data.
This post was entirely written using the IPython notebook. You can see a static view or download this notebook with the help of nbviewer at 20141217_PhaseColoredFFT.ipynb.