FFT coefficients using python - python

I am a newbie in Signal Processing. In here, I want to ask how to get FFT coeffients from FFT from in python. This is the example of my code:
from scipy.fftpack import fft
# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/N * np.abs(yf[0:N/2]))
plt.grid()
plt.show()

Hmm I don't really know about signal processing either but maybe this works:
from scipy.signal import argrelmax
f = xf[scipy.signal.argrelmax(yf[0:N/2])]
Af = np.abs(yf[argrelmax(yf[0:N/2])])

Quoting #hotpaw, in this similar answer:
"The real and imaginary arrays, when put together, can represent a complex array. Every complex element of the complex array in the frequency domain can be considered a frequency coefficient, and has a magnitude sqrt(RR + II))".
So, the coefficients are the complex elements in the array returned by the fft function. Also, it is important to play with the size (the number) of the bins for the FFT function. It would make sense to test a bunch of values and pick the one that makes more sense to your application. Often, it is in the same magnitude of the number of samples. This was as assumed by most of the answers given, and produces great and reasonable results. In case one wants to explore that, here is my code version:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
fig = plt.figure(figsize=[14,4])
N = 600 # Number of samplepoints
Fs = 800.0
T = 1.0 / Fs # N_samps*T (#samples x sample period) is the sample spacing.
N_fft = 80 # Number of bins (chooses granularity)
x = np.linspace(0, N*T, N) # the interval
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x) # the signal
# removing the mean of the signal
mean_removed = np.ones_like(y)*np.mean(y)
y = y - mean_removed
# Compute the fft.
yf = scipy.fftpack.fft(y,n=N_fft)
xf = np.arange(0,Fs,Fs/N_fft)
##### Plot the fft #####
ax = plt.subplot(121)
pt, = ax.plot(xf,np.abs(yf), lw=2.0, c='b')
p = plt.Rectangle((Fs/2, 0), Fs/2, ax.get_ylim()[1], facecolor="grey", fill=True, alpha=0.75, hatch="/", zorder=3)
ax.add_patch(p)
ax.set_xlim((ax.get_xlim()[0],Fs))
ax.set_title('FFT', fontsize= 16, fontweight="bold")
ax.set_ylabel('FFT magnitude (power)')
ax.set_xlabel('Frequency (Hz)')
plt.legend((p,), ('mirrowed',))
ax.grid()
##### Close up on the graph of fft#######
# This is the same histogram above, but truncated at the max frequence + an offset.
offset = 1 # just to help the visualization. Nothing important.
ax2 = fig.add_subplot(122)
ax2.plot(xf,np.abs(yf), lw=2.0, c='b')
ax2.set_xticks(xf)
ax2.set_xlim(-1,int(Fs/6)+offset)
ax2.set_title('FFT close-up', fontsize= 16, fontweight="bold")
ax2.set_ylabel('FFT magnitude (power) - log')
ax2.set_xlabel('Frequency (Hz)')
ax2.hold(True)
ax2.grid()
plt.yscale('log')
Output:

Related

Plotting 2D Schrodinger equation on Python and be able to see a resonance at certain energy

I have a code to make about the 2D schrodinger equation time dependant. I was able to figure how to use the finites differences and I guess I was able to solve the 1D schrodinger equation. But know I have to plot my wave function in spherical coordinate (so in 2D?) and create an animation to observe a wave packet at certain energies (3.48 Hartree). It is suggested that E=k^2/2 So I used this to make my schrodinger equation energy dependant. The potential and deltak are given. I also need to make the wave packet propagatinf from r=15 to r=0, I think that I just need to insert a minus in my exponential in my psi0 which I did in the code below. Any idea or even explanation would be welcome
import numpy as np
from scipy import sparse
import matplotlib.pyplot as plt
import scipy.integrate as integrate
from matplotlib.animation import FuncAnimation
from matplotlib import animation
from IPython import display
dx = 0.02 # spatial separation
a= 15
x = np.arange(0.1, a, dx) # spatial grid points
deltak = 0.2 # center of initial gaussian wave-packet
E=3.48
x0= 2
A=1.0 / (deltak * np.sqrt(np.pi)) # normalization constant
hbar = 1
dt = 0.1 # time interval for snapshots
t0 = 0.0 # initial time
tf = 1.0 # final time
t_eval = np.arange(t0, tf, dt)
k = np.sqrt(2 * E)
Vx= 7.5 * x**2 * np.exp(-x)
def psi_t2(t,psi):
return (-1j * (((-0.5 * D2.dot(psi)) + V * psi)))
# Initial Wavefunction
psi0_ = np.sqrt(A) * np.exp(-(x-x0)**2 / (2.0 * deltak**2)) * np.exp(1j * -k * x)
# Solve the Initial Value Problem
sol_ = integrate.solve_ivp(psi_t2, t_span = [t0, tf], y0 = psi0_, t_eval = t_eval,method="RK23")
for i,t in enumerate (sol_.t):
plt.plot(x, np.abs(sol_.y[:,i])**2)
fig=plt.figure()
ax=plt.subplot(1,1,1)
#fig,ax = plt.subplots(figsize=(8,4))
ax.set_xlim(-5, 16)
ax.set_ylim(0, 5)
title = ax.set_title('')
line1, = ax.plot([], [], "k--")
line2, = ax.plot([], [])
def init():
line1.set_data(x, V)
return line1,
def animate(i):
line2.set_data(x, np.abs(sol_.y[:,i])**2)
#line2.set_data(x, np.real(sol.y[:, i]))
#line2.set_data(x, np.abs(psi))
title.set_text('Time = {0:1.3f}'.format(sol_.t[i])) #permet d'afficher le temps
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init,frames=len(sol_.t), interval=50, blit=True)
video = anim.to_html5_video()
html = display.HTML(video)
display.display(html)
plt.close()

Signal generation from "custom" fft

I am looking for a way to specify the shape of a frequency/amplitude plot (the result of an fft) by hand, so that I could use that to create a signal. I would think this would be a good way to generate a signal with multiple frequencies without having to superposition a number of sine/cosine curves. Is this possible?
I have tried working with ffts and iffts in scipy, in the case of a simple sine curve with a frequency of 50Hz I can plot the fft like:
from scipy.fft import fft, fftfreq, ifft
# Number of sample points
N = 600
# sample spacing
T = 1.0 / 800.0 # in seconds?
x = np.linspace(0.0, N*T, N, endpoint=False)
y = np.sin(50* 2 * np.pi * x) # np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = fft(y)
xf = fftfreq(N, T)[:N//2]
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))
plt.grid()
plt.show()
And I can use the inverse fast fourier transform ifft to reconstruct the sine curve by
f_inv = ifft(yf)
However, yf in looks like this:

How to limit frequency range using scipy FFT

I am using FFT do find the frequencies of a signal. I am only interested in a certain range of frequencies, between 1 and 4 Hz.
I have this code to compute frequencies:
from scipy.fft import rfft, rfftfreq, irfft
plt.plot(d)
plt.show()
N = len(d)
yf = rfft(d)
xf = rfftfreq(N, 1 / sample_rate) # 29
plt.plot(xf, np.abs(yf))
plt.show()
Which results in :
How do I modify my code so that xf and yf only correspond to frequencies in my desired range of 1-4 Hz, instead of the 0-15 seen in the plot?
You can use xlim feature of matplotlib to modify x axis.
Here is the example code that you can refer.
from scipy.fft import fft, fftfreq
import numpy as np
# Number of sample points
N = 600
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N, endpoint=False)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = fft(y)
xf = fftfreq(N, T)[:N//2]
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]),'b')
plt.plot()
plt.grid()
plt.show()
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]),'b')
plt.xlim(0,100) # you need this
plt.grid()
plt.show()

Filter out range of frequencies using band stop filter in Python and confirm it using Fourier Transform FFT

Supposing that I have following signal:
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(100.0 * 2.0*np.pi*x) + 0.2*np.sin(200 * 2.0*np.pi*x)
how can I filter out in example 100Hz using Band-stop filter in Python? In this signal there are peaks at 50Hz, 100Hz and 200Hz. It would be helpful it it could be visualized using FFT in order to confirm that this frequency has been filtered correctly.
Basing on answers from:
Plotting a Fast Fourier Transform in Python
and:
Bandstop filter
I wrote following code:
import pandas as pd
import time
from scipy.signal import lfilter
import matplotlib.pyplot as plt
import scipy
import numpy as np
# In the below lines data are being filtered using Bandstop filter
print("Filtering using Bandstop filter...")
start_filtering_bandstop = time.time()
# Define filtering parameters:
order = 2
fs = 800.0 # sample rate, Hz
lowcut = 90 # desired cutoff frequency of the filter, Hz
highcut = 110
# Define plots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 7))
# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / fs
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(100.0 * 2.0*np.pi*x) + 0.2*np.sin(200 * 2.0*np.pi*x) # You can put there pandas series too...
ax1.plot(x, y, label='Signal before filtering')
print("Calculating FFT, please wait...")
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
ax1.set_title('Signal')
ax2.set_title('FFT')
ax2.plot(xf, 2.0/N * np.abs(yf[:N//2]), label='Before filtering')
def butter_bandstop_filter(data, lowcut, highcut, fs, order):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = scipy.signal.butter(order, [low, high], btype='bandstop')#, fs, )
y = lfilter(b, a, data)
return y
print("Filtering signal, please wait...")
signal_filtered = butter_bandstop_filter(y, lowcut, highcut, fs, order)
ax1.plot(x, signal_filtered, label='Signal after filtering')
ax1.set(xlabel='X', ylabel='Signal values')
ax1.legend() # Don't forget to show the legend
ax1.set_xlim([0,0.8])
ax1.set_ylim([-1.5,2])
# Number of samplepoints
N = len(signal_filtered)
# sample spacing
T = 1.0 / fs
x = np.linspace(0.0, N*T, N)
y = signal_filtered
print("Calculating FFT after filtering, please wait...")
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
# Plot axes...
ax2.plot(xf, 2.0/N * np.abs(yf[:N//2]), label='After filtering')
ax2.set(xlabel='Frequency [Hz]', ylabel='Magnitude')
ax2.legend() # Don't forget to show the legend
plt.savefig('FFT_after_bandstop_filtering.png', bbox_inches='tight', dpi=300) # If dpi isn't set, the script execution will be faster
# Alternatively for immediate showing of plot:
# plt.show()
plt.close()
end_filtering_bandstop = time.time()
print("Data filtered using Bandstop filter in",round(end_filtering_bandstop - start_filtering_bandstop,2),"seconds!")
and obtained following plots:
As we can see, the 100Hz has been filtered out using band-stop filter.
Why magnitude for frequency 50 Hz decreased from 1 to 0.7 after Fast Fourier Transform?

How to map multiple heatmap plots on one radar plot in python?

I have three data distributions:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
a = np.load('A.npy')
b = np.load('B.npy')
c = np.load('C.npy')
plt.figure(figsize=(12,4))
plt.subplot(131)
plt.hist2d(a,b,bins=300,norm=LogNorm())
plt.xlabel('A')
plt.ylabel('B')
plt.subplot(132)
plt.hist2d(a,c,bins=300,norm=LogNorm())
plt.xlabel('A')
plt.ylabel('C')
plt.subplot(133)
plt.hist2d(b,c,bins=300,norm=LogNorm())
plt.xlabel('B')
plt.ylabel('C')
plt.show()
And here is the result:
Now, I want to represent all three plots on a radar plot to look something like this:
Any ideas?
First, the easier part, the plotting: I've used 3 times the same random data, shrinked (0..2pi -> 0..2/3pi) and shifted (0, 2/3pi, 4/3pi) them to get 3 big pizza parts:
import numpy as np
import matplotlib.pyplot as plt
parts = 3
ax = plt.subplot(111, polar=True)
shrink = 1./parts
for i in range(3):
# beginning and end angle of this part
start = i * 2/parts * np.pi
end = (i + 1) * 2/parts * np.pi
# Generate random data:
N = 10000
r = .5 + np.random.normal(size=N, scale=.2)
theta = (np.pi / 2 + np.random.normal(size=N, scale=.1))
# shift the data counterclockwise so that it fills the n-th part
theta += i * 2.*np.pi / parts
# Histogramming
nr = 50
ntheta = 200
r_edges = np.linspace(0, 1, nr + 1)
theta_edges = np.linspace(start, end, ntheta + 1)
H, _, _ = np.histogram2d(r, theta, [r_edges, theta_edges])
# Plot
Theta, R = np.meshgrid(theta_edges, r_edges)
ax.pcolormesh(Theta, R, H)
plt.show()
Now the harder part: You will still have to convert your points into radial values, I'm not sure how you define this for your coordinates, as a point has 3 dimensions but you want to map to 2d. I hope this helps!
My code is based on this 2d heatmap.

Categories