Fourier Transform Using Numpy - python

I'm trying to calculate the Fourier Transform of the following Gaussian:
# sample spacing
dx = 1.0 / 1000.0
# Points
x1 = -5
x2 = 5
x = np.arange(x1, x2, dx)
def light_intensity():
return 10*sp.stats.norm.pdf(x, 0, 1)+0.1*np.random.randn(x.size)
fig, ax = plt.subplots()
ax.plot(x,light_intensity())
I create a new array in the spacial frequency domain (Fourier Transform of Gaussian is a Gaussian so these values should be similar). I plot and get this:
fig, ax = plt.subplots()
xf = np.arange(x1,x2,dx)
yf= np.fft.fftshift(light_intensity())
ax.plot(xf,np.abs(yf))
Why is it splitting into two peaks?

Advice:
use np.fft.fft
fft starts at 0 Hz
normalize/rescale
Complete example:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
def norm_fft(y, T, max_freq=None):
N = y.shape[0]
Nf = N // 2 if max_freq is None else int(max_freq * T)
xf = np.linspace(0.0, 0.5 * N / T, N // 2)
yf = 2.0 / N * np.fft.fft(y)
return xf[:Nf], yf[:Nf]
def generate_signal(x, signal_gain=10.0, noise_gain=0.0):
signal = norm.pdf(x, 0, 1)
noise = np.random.randn(x.size)
return signal_gain * signal + noise_gain * noise
# Signal parameters
x1 = 0.0
x2 = 5.0
N = 10000
T = x2 - x1
# Generate signal data
x = np.linspace(x1, x2, N)
y = generate_signal(x)
# Apply FFT
xf, yf = norm_fft(y, T, T / np.pi)
# Plot
fig, ax = plt.subplots(2)
ax[0].plot(x, y)
ax[1].plot(xf, np.abs(yf))
plt.show()
Or, with noise:
Plots with symmetry
Alternatively, if you want to enjoy the symmetry in the frequency domain:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
def norm_sym_fft(y, T, max_freq=None):
N = y.shape[0]
b = N if max_freq is None else int(max_freq * T + N // 2)
a = N - b
xf = np.linspace(-0.5 * N / T, 0.5 * N / T, N)
yf = 2.0 / N * np.fft.fftshift(np.fft.fft(y))
return xf[a:b], yf[a:b]
def generate_signal(x, signal_gain=10.0, noise_gain=0.0):
signal = norm.pdf(x, 0, 1)
noise = np.random.randn(x.size)
return signal_gain * signal + noise_gain * noise
# Signal parameters
x1 = -10.0
x2 = 10.0
N = 10000
T = x2 - x1
# Generate signal data
x = np.linspace(x1, x2, N)
y = generate_signal(x)
# Apply FFT
xf, yf = norm_sym_fft(y, T, 4 / np.pi)
# Plot
fig, ax = plt.subplots(2)
ax[0].plot(x, y)
ax[1].plot(xf, np.abs(yf))
plt.show()
Or, with noise:

First, use np.fft.fft to computes the Fourier Transform then use np.fft.fftshift to shift the zero-frequency component to the center of the spectrum.
Replace the second part of your code with:
xf = np.arange(x1,x2,dx)
yf = np.fft.fft(light_intensity())
yfft = np.fft.fftshift(np.abs(yf))
fig,ax = plt.subplots(1,2,figsize=(10,5))
ax[0].plot(xf,light_intensity())
ax[1].plot(xf,yfft)
ax[1].set_xlim(-0.05,0.05)
plt.show()
This is the result:

Related

Simulate a rotating equal triangle by Python

can anyone help me, i stuck at the last step
[]
this is my code. then for the last step to rotate it, i didnt know what should i do to rotate the triangle
This is the perfect case for an animation:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from matplotlib.animation import FuncAnimation
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
to=np.arange(0,2*np.pi,0.01)
x = r * np.cos(np.radians(theta))
y = r * np.sin(np.radians(theta))
xo = r * np.cos(to); yo = r * np.sin(to)
fig, ax = plt.subplots()
ax.plot(xo,yo)
# create artists: they will be used to update the position
# of the points being rendered
triangle, = ax.plot(x,y)
vertices = ax.scatter(x,y)
lim = r * 1.25
ax.set_xlim([-lim, lim]);ax.set_ylim([-lim, lim])
ax.set_aspect("equal")
w = 2
T = 2 * np.pi / w
# this defines the time steps of the animation
dt = np.linspace(0, 10 * T, num=500)
def animate(i):
x = r * np.cos(np.radians(theta) + w * dt[i])
y = r * np.sin(np.radians(theta) + w * dt[i])
# update the position of the points to be rendered
triangle.set_data(x, y)
vertices.set_offsets(np.stack([x, y]).T)
ax.set_title("Rotation #%s" % int(w * dt[i] / (2 * np.pi) + 1))
ani = FuncAnimation(fig, animate, frames=len(dt), repeat=False)
plt.show()
Check this out..
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
w = 2
T = 2*np.pi/w
dt = np.linspace(0, 10*T, num=10) #increase num for more finely distributed rotations.
for d in dt:
to=np.arange(0,2*np.pi,0.01)
x = r*np.sin(np.radians(theta + d))
y=r*np.cos(np.radians(theta + d))
xo=r*np.sin(to);yo=r*np.cos(to)
plt.plot(xo,yo)
plt.plot(x,y)
plt.scatter(x,y)
plt.xlim([-1, 1]);plt.ylim([-1,1])

Color point by distance from origin

Here is a Hopf torus created in Python with PyVista:
import numpy as np
import pyvista as pv
A = 0.44
n = 3
def Gamma(t):
alpha = np.pi/2 - (np.pi/2-A)*np.cos(n*t)
beta = t + A*np.sin(2*n*t)
return np.array([
np.sin(alpha) * np.cos(beta),
np.sin(alpha) * np.sin(beta),
np.cos(alpha)
])
def HopfInverse(p, phi):
return np.array([
(1+p[2])*np.cos(phi),
p[0]*np.sin(phi) - p[1]*np.cos(phi),
p[0]*np.cos(phi) + p[1]*np.sin(phi),
(1+p[2])*np.sin(phi)
]) / np.sqrt(2*(1+p[2]))
def Stereo(q):
return 2*q[0:3] / (1-q[3])
def F(t, phi):
return Stereo(HopfInverse(Gamma(t), phi))
angle = np.linspace(0, 2*np.pi, 300)
angle2 = np.linspace(0, np.pi, 150)
theta, phi = np.meshgrid(angle, angle2)
x, y, z = F(theta, phi)
# Display the mesh
grid = pv.StructuredGrid(x, y, z)
grid.plot(smooth_shading=True)
I would like to add a palette of colors to this surface. The torus is centered at the origin (0,0,0). I would like to have a color in function of the distance to the origin.
With Matplotlib, I do:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.colors as mcolors
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
A = 0.44
n = 3
......
colorfunction = (X**2+Y**2+Z**2)
norm = mcolors.Normalize(colorfunction.min(),colorfunction.max())
# Display the mesh
fig = plt.figure()
ax = fig.gca(projection = '3d')
ax.plot_surface(z, x, y, rstride = 1, cstride = 1, facecolors=cm.jet(norm(colorfunction)))
plt.show()
EDIT
I have a solution, but I don't control the colors:
grid = pv.StructuredGrid(x, y, z)
grid['Data'] = grid.points
grid.plot(smooth_shading=True, scalars="Data")
As a side note, at least to me it's clearer to compute the magnitude of the points yourself and set those as scalars (rather than relying on the magnitude of vector data as scalars for colour mapping, even though this is supported and valid).
What you're missing is just a choice of colourmap. The default, just like with matplotlib, is viridis. Instead it seems you want jet (although I'd recommend against this; perceptually uniform colourmaps are preferable in most cases for data visualization):
import numpy as np
import pyvista as pv
A = 0.44
n = 3
def Gamma(t):
alpha = np.pi/2 - (np.pi/2-A)*np.cos(n*t)
beta = t + A*np.sin(2*n*t)
return np.array([
np.sin(alpha) * np.cos(beta),
np.sin(alpha) * np.sin(beta),
np.cos(alpha)
])
def HopfInverse(p, phi):
return np.array([
(1+p[2])*np.cos(phi),
p[0]*np.sin(phi) - p[1]*np.cos(phi),
p[0]*np.cos(phi) + p[1]*np.sin(phi),
(1+p[2])*np.sin(phi)
]) / np.sqrt(2*(1+p[2]))
def Stereo(q):
return 2*q[0:3] / (1-q[3])
def F(t, phi):
return Stereo(HopfInverse(Gamma(t), phi))
angle = np.linspace(0, 2 * np.pi, 300)
theta, phi = np.meshgrid(angle, angle)
x, y, z = F(theta, phi)
grid = pv.StructuredGrid(x, y, z)
# convert to PolyData and clean to remove the seam
cleaned_poly = grid.extract_geometry().clean(tolerance=1e-6)
# add distance from origin as scalars
cleaned_poly.point_data['distance'] = np.linalg.norm(cleaned_poly.points, axis=1)
# this also makes these the default scalars
cleaned_poly.plot(smooth_shading=True, cmap='jet') # but don't use jet if possible

How to extract a 2D plane from a 3D numpy meshgrid

[TLDR]:
Essentially my question boils down to how one can extract the 2d data of a plane from a 3D numpy meshgrid
[Detailed Description]:
I am calculating the electric field of two (or more) point charges. I did this in 2D and can plot the results via matplotlib using quiver or streamplot
import numpy as np
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
for q, qxi, qyi in zip(charges,qx,qy):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
sumEx += Ex
sumEy += Ey
# PLOT
fig = plt.figure()
ax = fig.add_subplot(111)
ax.streamplot(X,Y,sumEx,sumEy)
plt.show()
This produces the correct results
I can easily extend this to 3D
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
eps_0 = 8e-12
fac = (1./(4*np.pi*eps_0))
charges = [1.0,-1.0]
qx = [-2.0,2.0]
qy = [0.0,0.0]
qz = [0.0,0.0]
# GRID
gridsize = 4.0
N = 11
X,Y,Z = np.meshgrid( np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N),
np.linspace(-gridsize,gridsize,N))
# CALC E-FIELD
sumEx = np.zeros_like(X)
sumEy = np.zeros_like(Y)
sumEz = np.zeros_like(Z)
for q, qxi, qyi, qzi in zip(charges,qx,qy,qz):
dist_vec_x = X - qxi
dist_vec_y = Y - qyi
dist_vec_z = Z - qzi
dist = np.sqrt(dist_vec_x**2 + dist_vec_y**2 + dist_vec_z**2)
Ex = fac * q * (dist_vec_x/dist**3)
Ey = fac * q * (dist_vec_y/dist**3)
Ez = fac * q * (dist_vec_z/dist**3)
sumEx += Ex
sumEy += Ey
sumEz += Ez
# PLOT
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(X,Y,Z,sumEx,sumEy,sumEz, pivot='middle', normalize=True)
plt.show()
This also yields the correct result when plotted in 3D (as far as I can tell)
But for some reason I can not figure out how to extract the data from one x-y plane from the generated 3D numpy mesh. I thought I could just do something like
zplane = round(N/2)
ax.quiver(X,Y,sumEx[:,:,zplane],sumEy[:,:,zplane])
but this does not do the trick. Does anyone know the proper way here?
Remove projection='3d' and index X and Y:
fig = plt.figure()
ax = fig.gca()
zplane = round(N / 2)
ax.quiver(X[:, :, zplane], Y[:, :, zplane], sumEx[:, :, zplane], sumEy[:, :, zplane])
plt.show()
If you select a specific zplane your plot is no longer a 3D-plot.

How can I plot a spectrogram of a signal by computing the power spectrum on binned windows?

Here I can generate a signal:
import numpy as np
from matplotlib import pyplot as plt
from numpy.lib import stride_tricks
import seaborn as sns
sns.set(style = "darkgrid" )
fs = 48000.0
t = np.arange(0, 10, 1.0/fs) # 0 to 10 sec at 48k samples per second
f0 = 1000
phi = np.pi/2 # pi/2
x = 0 # initial x
f = [500, 100, 40, 1] #vector of frequencies
A = [1, 0.5, 0.25, 0.1] #vector of amplitudes
for i in range(0, len(f)):
x = x + A[i] * np.sin(2 * np.pi * f[i] * t + phi) #add waves
x = x + max(x) # shift plot upwards
plt.plot(t, x)
plt.axis([0, .05, 0, max(x)])
plt.xlabel('time')
plt.ylabel('amplitude')
plt.show()
Here I can plot the power spectrum of the entire signal:
time_step = 1/fs
ps = np.abs(np.fft.fft(x))**2
freqs = np.fft.fftfreq(x.size, time_step)
idx = np.argsort(freqs)
plt.plot(freqs[idx], 256*ps[idx]/max(ps[idx])) # set max to 256 for later image plotting purposes
plt.xlabel('frequency')
plt.ylabel('power')
plt.show()
Next I want to generate a spectrogram, represented as an image of frequency (y-axis) and time (x-axis), but I am new to fourier analysis and am confused about how to use a window function (rectangular, hamming, hanning, etc) during this stage. Is there a proper way to do this so that a window function of my choosing can be used to break up the signal in time?
add this:
M = 5000
overlap = 500
unique = M - overlap
han = np.hanning(M)
f_border = 2*max(f)
for i in range(0, x.shape[0], unique):
if i + M > x.shape[0]:
break
curr_x = x[i:i+M]
y = 10*np.log10(np.abs(np.fft.fft(curr_x*han))**2)
if i == 0:
freqs = np.fft.fftfreq(curr_x.size, time_step)
idx = np.argsort(freqs)
freqs = freqs[idx]
idx2 = np.where(np.logical_and(freqs > 0, freqs < f_border))[0]
y = y[idx][idx2][np.newaxis].T
try:
stereogram = np.hstack([stereogram, y])
except NameError:
stereogram = y
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(stereogram)
yticks = ax.get_yticks()[1:-1]
plt.yticks(yticks, (yticks * f_border/yticks[-1]).astype('str'))
plt.ylabel('frequency')
plt.xlabel('time')
plt.show()
or you can use matplotlib.pyplot.specgram see: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.specgram

Plotting multiple 2d curves with matplotlib in 3d

I'm trying to plot a fourier series of a triangular wave with matplotlib.
I've managed to plot the elements on top of each other in 2d, but I'd like to plot them in 3d instead, as that makes it more easy to see.
Here's the plot my current code generates
triangular wave
Here's an image of what I'd like to plot, but for the triangular wave instead of a square wave.
square wave
Here's the current code
%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
import scipy as sp
x1 = np.arange(0, L / 2.0, 0.01)
x2 = np.arange(L/2.0,L,0.01)
x = np.concatenate((x1,x2))
y1 = 2* x1
y2 = 2*(1 - x2)
triangle_y = np.concatenate((y1,y2))
L = 1;
def triangle_function(x, L):
'''given x, returns y as defined by the triangle function defined in the range 0 <= x <= L
'''
if x< 0:
print 'Error: the value of x should be between 0 and L'
y = None
elif x<L/2.0:
y = 2*x
elif x <= L:
y = 2*(1 - x)
else:
print 'Error: the value of x should be between 0 and L'
y = None
return y
def projection_integrand(x, n, L):
'''The inputs to the function are:
x ---> vector of x values.
n ---> the n-number associated to the sine functions
L --> L, upper limit of integration
'''
sine_function = np.sin(n * np.pi * x / np.double(L)) # this is the sine function sin(n*pi*x/L)
integrand = (2.0 / L) * sine_function * triangle_function(x, L) # this is the product of the two functions, with the 2/L factor
#return(sine_function*f_x)
return integrand
from scipy.integrate import quad
n_max = 5
x = np.arange(0, L, 0.01) # x vector
triangle_approx = np.zeros(len(x))
func_list = []
for n in range(1, n_max + 1):
c_n = quad(projection_integrand, 0, L, (n, L))
sin_arg = n* np.pi*x/np.double(L)
current = c_n[0]* np.sin(sin_arg)
triangle_approx += current
func_list.append(current)
from mpl_toolkits.mplot3d import Axes3D
plt.hold(True)
plt.plot(x, func_list[0])
plt.plot(x, func_list[1])
plt.plot(x, func_list[2])
plt.plot(x, func_list[3])
plt.plot(x, func_list[4])
plt.plot(x, triangle_approx)
plt.plot(x, triangle_y)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('approximating the triangle function as a sum of sines, n = 1 ...' + str(n_max))
plt.legend(['approximation', 'triangle function'])
plt.show()
I have found a way based on this matplotlib official example.
Add this code below your code and you will get something close to what you want:
fig = plt.figure()
ax = fig.gca(projection='3d')
z = np.array([1.0 for point in x])
for n, armonic in enumerate(func_list):
ax.plot(x, armonic, z*n, label='armonic{}'.format(n))
ax.legend()
plt.show()

Categories

Resources