I looked into many examples of scipy.fft and numpy.fft. Specifically this example Scipy/Numpy FFT Frequency Analysis is very similar to what I want to do. Therefore, I used the same subplot positioning and everything looks very similar.
I want to import data from a file, which contains just one column to make my first test as easy as possible.
My code writes like this:
import numpy as np
import scipy as sy
import scipy.fftpack as syfp
import pylab as pyl
# Read in data from file here
array = np.loadtxt("data.csv")
length = len(array)
# Create time data for x axis based on array length
x = sy.linspace(0.00001, length*0.00001, num=length)
# Do FFT analysis of array
FFT = sy.fft(array)
# Getting the related frequencies
freqs = syfp.fftfreq(array.size, d=(x[1]-x[0]))
# Create subplot windows and show plot
pyl.subplot(211)
pyl.plot(x, array)
pyl.subplot(212)
pyl.plot(freqs, sy.log10(FFT), 'x')
pyl.show()
The problem is that I will always get my peak at exactly zero, which should not be the case at all. It really should appear at around 200 Hz.
With smaller range:
Still biggest peak at zero.
As already mentioned, it seems like your signal has a DC component, which will cause a peak at f=0. Try removing the mean with, e.g., arr2 = array - np.mean(array).
Furthermore, for analyzing signals, you might want to try plotting power spectral density.:
import matplotlib.pylab as plt
import matplotlib.mlab as mlb
Fs = 1./(d[1]- d[0]) # sampling frequency
plt.psd(array, Fs=Fs, detrend=mlb.detrend_mean)
plt.show()
Take a look at the documentation of plt.psd(), since there a quite a lot of options to fiddle with. For investigating the change of the spectrum over time, plt.specgram() comes in handy.
Related
I have a dataset a csv file representing a wave like shown below. I would like to find the frequency of oscillations, so I have done fft. But the output of fft is peak at zero. I am new to python and fft. So I am not sure what I am doing wrong.
The data is captured at 300Hz(300 data points in one second). The data set contains 6317 values.
[image1]
Every peak has a wave following it. Here is an example at data points from 250 to 350
[image2]
import matplotlib.pyplot as plt
import csv
import numpy as np
csvfile=open('./abc.csv')
csvreader=csv.reader(csvfile)
readdata=next(csvreader)
csvfile.close()
data=np.array([readdata],dtype='float')
data1=data.reshape(6317,)
sp = np.fft.fft(data1)
sp_mag=np.abs(sp)/data1.size
freq = np.fft.fftfreq(data1.shape[-1])
plt.subplot(2,1,1)
plt.plot(data1)
plt.subplot(2,1,2)
plt.plot(freq,sp_mag)
plt.show()
The csv is available here .
The frequency associated with first three and next 3 peaks is same. So in fft i expect two peaks t different frequency.
Any help is really appreciated. Kindly let me know if any other data is needed to answer this question.
The value of the FFT at 0 is proportional to the sum of the data. Probably the easiest fix is to subtract off the mean of the data before taking the FFT (assuming you don't care about the constant offset).
Adopting the notation from wikipedia
X[m] = sum[ x[n]*exp(-i*2*pi*n*m/N) ]
(X is the FFT, x is the original data)
For m=0, the exponential factors are all ==1, so X[0] == sum[x[n]] (for this convention on where to put the normalization factors).
I have a Python snippet of code I found. I used it to create useful Python code to extract the dominate frequency. I know the code works because I have used it with the default N and Nev values on some runs and received the same Strouhal number (St) as the sinusoidal method.
I am evaluating the frequency of a vortex street, so I don't have DC frequency, but I am getting "0.0". I tested the values of N and Nev when the code was working. I noticed the final result of the dominate frequency is very dependent on N.
I have looked at suggested posts, but they fall short. Here is the code. How do I adjust sample for linspace as my lift data increases?
#1/usr/bin/env python
import sys
import numpy as np
import scipy.fftpack as fftpack
import matplotlib.pyplot as plt
print("Hello World!")
N = 2500
Nev = 1000
data = np.loadtxt('CoefficientLiftData.dat', usecols= (0,3))
times = data[:,0]
length = int(len(times)/2)
forcez= data[:,1]
t = np.linspace(times[length], times[-1], N)
forcezint = np.interp(t, times, forcez)
fourier = fftpack.fft(forcezint[Nev-1:N-1])
frequencies = fftpack.fftfreq(forcezint[Nev-1:N-1].size, d=t[1]-t[0])
#print(frequencies)
freq = frequencies[np.argmax(np.abs(fourier))]
print(freq)
Did you have a look at this answer on how to choose the correct frequency scale? Additionally you should have a look on window functions, like the Tukey window to get the correct frequencies of your signal, if the signal is not equal at the interval boundaries.
Edit: And you could also have a look at this answer that gives detailed explanation on how to get proper results for an FFT analysis.
I have access scipy and want to create a FFT about simple Gaussian function which is exp(-t^2). And also it's well known that fourier transform of exp(−t^2) is √πexp(−π^2*k^2). But FFT of exp(-t^2) was not same as √πexp(−π^2*k^2).
I have tried the following code:
import scipy.fftpack as fft
from scipy import integrate
import numpy as np
import matplotlib.pyplot as plt
#FFT
N=int(1e+3)
T=0.01 #sample period
t = np.linspace(0,N*T, N)
h=np.exp(-t**2)
H_shift=2*np.abs(fft.fftshift(np.fft.fft(h)/N))
freq=fft.fftshift(fft.fftfreq(h.shape[0],t[1]-t[0]))
#Comparing FFT with fourier transform
def f(x):
return np.exp(-x**2)
def F(k):
return (np.pi**0.5)*np.exp((-np.pi**2)*(k**2))
plt.figure(num=1)
plt.plot(freq,F(freq),label=("Fourier Transform"))
plt.legend()
plt.figure(num=2)
plt.plot(freq,H_shift,label=("FFT"))
plt.legend()
plt.show()
#Checking Parseval's Theorm
S_h=integrate.simps(h**2,t)
#0.62665690150683084
S_H_s=integrate.simps(H_shift**2,freq)
#0.025215875346935791
S_F=integrate.simps(F(freq)**2,freq)
#1.2533141373154999
The graph I plotted is not same, also values of FFT do not follow Parseval's theorm. . It has to be S_H_s=S_h*2, but my result was not. I think that S_H_s which is result of FFT is wrong value Because of S_F=S_h*2.
Is there any problem in my code?? Help is greatly appreciated! Thanks in advance.
I suggest you plot your input signal h and verify that it looks like a Gaussian.
Spoiler alert: it doesn't, it is half a Gaussian!
By cutting it like this, you introduce a lot of high frequencies that you see in your plot.
To do this experiment correctly, follow this recipe to create your input signal:
t = np.linspace(-(N/2)*T,(N/2-1)*T, N)
h = np.exp(-t**2)
h = fft.ifftshift(h)
The ifftshift function serves to move the t=0 location to the leftmost array element. Note that t here is constructed carefully such that t=0 is exactly in the right place for this to work correctly, assuming an even-sized N. You can verify that fft.ifftshift(t)[0] is 0.0.
What I try is to filter my data with fft. I have a noisy signal recorded with 500Hz as a 1d- array. My high-frequency should cut off with 20Hz and my low-frequency with 10Hz.
What I have tried is:
fft=scipy.fft(signal)
bp=fft[:]
for i in range(len(bp)):
if not 10<i<20:
bp[i]=0
ibp=scipy.ifft(bp)
What I get now are complex numbers. So something must be wrong. What? How can I correct my code?
It's worth noting that the magnitude of the units of your bp are not necessarily going to be in Hz, but are dependent on the sampling frequency of signal, you should use scipy.fftpack.fftfreq for the conversion. Also if your signal is real you should be using scipy.fftpack.rfft. Here is a minimal working example that filters out all frequencies less than a specified amount:
import numpy as np
from scipy.fftpack import rfft, irfft, fftfreq
time = np.linspace(0,10,2000)
signal = np.cos(5*np.pi*time) + np.cos(7*np.pi*time)
W = fftfreq(signal.size, d=time[1]-time[0])
f_signal = rfft(signal)
# If our original signal time was in seconds, this is now in Hz
cut_f_signal = f_signal.copy()
cut_f_signal[(W<6)] = 0
cut_signal = irfft(cut_f_signal)
We can plot the evolution of the signal in real and fourier space:
import pylab as plt
plt.subplot(221)
plt.plot(time,signal)
plt.subplot(222)
plt.plot(W,f_signal)
plt.xlim(0,10)
plt.subplot(223)
plt.plot(W,cut_f_signal)
plt.xlim(0,10)
plt.subplot(224)
plt.plot(time,cut_signal)
plt.show()
There's a fundamental flaw in what you are trying to do here - you're applying a rectangular window in the frequency domain which will result in a time domain signal which has been convolved with a sinc function. In other words there will be a large amount of "ringing" in the time domain signal due to the step changes you have introduced in the frequency domain. The proper way to do this kind of frequency domain filtering is to apply a suitable window function in the frequency domain. Any good introductory DSP book should cover this.
I have some troubles when applying bandpass filter to signal in Python. Have tried the following to things:
Do the box window "by hand", i.e. do the FFT on the signal, apply the
filter with a box window and the do the IFFT to get back to the time
domain.
Use the scipy.signal module where I use firwin2 to construct the
filter and then lfilter to to the filtering.
Futhermore I have done the same filtering in the audio program Cool Edit and compared the result from the above two tests.
As can be seen (I am a new user so I can not post my png fig), the results from the FFT and scipy.signal are very different. When compare to the result from Cool edit, the FFT is close, however not identical. Code as below:
# imports
from pylab import *
import os
import scipy.signal as signal
# load data
tr=loadtxt('tr6516.txt',skiprows=1)
sr = 500 # [samples/s]
nf = sr/2.0 # Nyquist frequence
W = 512 # Window widht for filtering
N=float(8192) # Fourier settings
Ns = len(tr[:,0]) # Total number of samples
# Create inpulse responce from the filter
fv=12.25
w =0.5
r =0.5*w
Hz=[0, fv-w-r, fv-w, fv+w, fv+w+r, nf]
ff=[0, 0, 1, 1, 0, 0]
b = signal.firwin2(W,Hz,ff,nfreqs=N+1,nyq=nf)
SigFilter = signal.lfilter(b, 1, tr[:,1])
# Fourier transform
X1 = fft(tr[:,1],n=int(N))
X1 = fftshift(X1)
F1 = arange(-N/2.0,N/2.0)/N*sr
# Filter data
ff=[0,1,1,0]
fv=12.25
w =0.5
r =0.5*w
Hz=[fv-w-r,fv-w,fv+w,fv+w+r]
k1=interp(-F1,Hz,ff)+interp(F1,Hz,ff)
X1_f=X1*k1
X1_f=ifftshift(X1_f)
x1_f=ifft(X1_f,n=int(N))
Can anyone explain to me why this difference? The filtering in Cool edit has been done using the same settings as in scipy.signal (hanning window, window width 512). Or have I got this all totaly wrong.
Best regards,
Anders
Above code:
Compared with Cool Edit:
Small differences can be explained by the libraries using different algorithms that accumulate error slightly differently.
For example, if you compute the DFT using a radix-2 FFT, a split-radix FFT and an ordinary DFT, the results will all be slightly different. In fact the ordinary DFT has worse accuracy than all decent implementations of an FFT because it uses many more floating point operations, and thus it accumulates more error.
Could this explain the close (but not identical) results you are seeing?