The goal is to display a nice waterfall from an existing fft
Start from an existing fft which can be found at https://docs.scipy.org/doc/scipy/reference/tutorial/fftpack.html
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from scipy.fftpack import fft
from mpl_toolkits.mplot3d import Axes3D
N = 600
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()
The result is the expected spectrum. Now we want to plot a waterfall as depicted at https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#wireframe-plots
We want something like that :
x, y = (xf, np.arange(N))
X,Y=np.meshgrid(x,y)
Z = yf
Axes3D.plot_wireframe(X, Y, Z,rstride=1,cstride=len(xf), lw=.5, alpha=0.5)
plt.show()
where X is the freq range of the Fft, Y the plot number axis and Z the 2D array with Fft data. But we get this error :
TypeError: plot_wireframe() missing 1 required positional argument: 'Z'
What is the problem ?
Thanks for the help.
To display a waterfall, you need a 2D array of FFTs (usually of different time windows), not just one FFT result.
Related
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:
The following code example from this site illustrates the use of SciPy FFTpack. I am aware that the Fourier transformation in the real-valued case is symmetrical and therefore only the values of 0:N/2 are used in the representation. Unfortunately, I do not understand why these values are scaled with the factor 2.0/N. I would be very pleased to receive an explanation or a hint.
from scipy.fftpack import fft
# Number of sample points
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()
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()
Im currently working on graphing a square wave in python using numpy and pylot.
How would I plot a square wave function over multiple periods of T?
I currently have:
from scipy import signal
import numpy as np
from scipy.fftpack import fft
#Initialize Parameters
p_0 = 2
A = np.sqrt(1/(2*p_0))
t = [-A,A]
plt.plot(t,[A,A])
plt.show()
which just gives me a straight line.
The end game is to take the Fourier transform of the square wave function
You could use the square function from scipy.signal
from scipy import signal
import matplotlib.pyplot as plt
t = np.linspace(0, 1, 500, endpoint=False)
plt.plot(t, signal.square(2 * np.pi * 5 * t),'b')
plt.ylim(-2, 2)
plt.grid()
plt.show()
This code below will do the trick:
import math, numpy
from matplotlib import pyplot as plt
x = numpy.linspace(0, 10, 1000)
y = numpy.array([1 if math.floor(2 * t) % 2 == 0 else 0 for t in x])
plt.plot(x,y)
plt.show()
If the math.floor(2 * t) % 2 == 0 returns True plot 1 else plot 0.
Output:
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: