I'm trying to understand how fft in python works (or in general).
When I have a signal that is recorded for a few seconds I can only display one second of that FFT.
Is there a way to take all of the data and averaged this out?
I did this before in LabView.
Can any one help?
Here is an example code that I'm using.
from numpy import linspace, sin, pi, log10, average, arange
from matplotlib.pyplot import plot, show, figure
from numpy.fft import fft, fftfreq
N = 1000 * 60 * 4
dt = 1 / 1000
x = linspace(0, N*dt, N)
freq = linspace(10, 200, N)
sinsweep = sin(x*freq)
mavg = [average(sinsweep[i*60:(i+1)*60]) for i in range(int(N/60))]
plot(freq, sinsweep, '.')
plot(linspace(10, 200, int(N/60)), mavg, '.')
f = figure()
t = arange(60)
sp = fft(mavg, n=60)
freq = fftfreq(t.shape[-1])
plot(sp.imag)
show()
I give some modification to your code, to obtain a beautiful spectrum. First I increase the number of points to verify Shannon criterion. And some tricks to
improve speed.
from numpy import linspace, sin, pi, log10, average, arange
from matplotlib.pyplot import plot, show, figure
from numpy.fft import fft, fftfreq
close()
N = 10000 * 60 * 4
dt = 1 / 10000
t = arange(0, N*dt, dt)
freq = linspace(10, 200, N)
sinsweep = sin(t*freq)
mavg = sinsweep.reshape(-1,60).mean(1)
tm=t[::60]
figure('signal')
plot(tm, mavg)
sp = fft(mavg)
freq = fftfreq(tm.size,dt*60)
valid=freq>0
figure('spectrum')
plot(freq[valid],abs(sp[valid]))
show()
for
Is it what you expected ?
Related
i'm trying to get the frequency of a signal via fourier transform but it's not able to recognize it (sets the peak to f=0). Maybe something is wrong in my code (FULL reprudible code at the end of the page):
PF = fft.fft(Y[0,:])/Npoints #/Npoints to get the true amplitudes
ZF = fft.fft(Y[1,:])/Npoints
freq = fft.fftfreq(Npoints,deltaT)
PF = fft.fftshift(PF) #change of ordering so that the frequencies are increasing
ZF = fft.fftshift(ZF)
freq = fft.fftshift(freq)
plt.plot(freq, np.abs(PF))
plt.show()
plt.plot(T,Y[0,:])
plt.show()
where Npoints is the number of intervals (points) and deltaT is the time spacing of the intervals. You can see that the peak is at f=0
I show also a plot of Y[0,:] (my signal) over time where it's clear that the signal has a characteristic frequency
FULL REPRUDICIBLE CODE
import numpy as np
import matplotlib.pyplot as plt
#numerical integration
from scipy.integrate import solve_ivp
import scipy.fft as fft
r=0.5
g=0.4
e=0.6
H=0.6
m=0.15
#define a vector of K between 0 and 4 with 50 componets
K=np.arange(0.1,4,0.4)
tsteps=np.arange(7200,10000,5)
Npoints=len(tsteps)
deltaT=2800/Npoints #sample spacing
for k in K :
i=0
def RmAmodel(t,y):
return [r*y[0]*(1-y[0]/k)-g*y[0]/(y[0]+H)*y[1], e*g*y[0]/(y[1]+H)*y[1]-m*y[1]]
sol = solve_ivp(RmAmodel, [0,10000], [3,3], t_eval=tsteps) #t_eval specify the points where the solution is desired
T=sol.t
Y=sol.y
vk=[]
for i in range(Npoints):
vk.append(k)
XYZ=[vk,Y[0,:],Y[1,:]]
#check periodicity over P and Z with fourier transform
#try Fourier analysis just for the last value of K
PF = fft.fft(Y[0,:])/Npoints #/Npoints to get the true amplitudes
ZF = fft.fft(Y[1,:])/Npoints
freq = fft.fftfreq(Npoints,deltaT)
PF = fft.fftshift(PF) #change of ordering so that the frequencies are increasing
ZF = fft.fftshift(ZF)
freq = fft.fftshift(freq)
plt.plot(T,Y[0,:])
plt.show()
plt.plot(freq, np.abs(PF))
plt.show()
I can't pinpoint where the problem is. It looks like there is some problem in the fft code. Anyway, I have little time so I will just put a sample code I made before. You can use it as reference or copy-paste it. It should work.
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq
fs = 1000 #sampling frequency
T = 1/fs #sampling period
N = int((1 / T) + 1) #number of sample points for 1 second
t = np.linspace(0, 1, N) #time array
pi = np.pi
sig1 = 1 * np.sin(2*pi*10*t)
sig2 = 2 * np.sin(2*pi*30*t)
sig3 = 3 * np.sin(2*pi*50*t)
#generate signal
signal = sig1 + sig2 + sig3
#plot signal
plt.plot(t, signal)
plt.show()
signal_fft = fft(signal) #getting fft
f2 = np.abs(signal_fft / N) #full spectrum
f1 = f2[:N//2] #half spectrum
f1[1:] = 2*f1[1:] #actual amplitude
freq = fs * np.linspace(0,N/2,int(N/2)) / N #frequency array
#plot fft result
plt.plot(freq, f1)
plt.xlim(0,100)
plt.show()
I'm trying to calculate Frequency Modulation (radio context) for a given audio file (12 seconds), I managed to do it on a sine wave with the following formula:
fm = np.sin(TWO_PI * (fc + b * data) * t)
Where fc is the Carrier Frequency, b is the Modulation index, data is the audio file and t is the time vector.
But I can't seem to get it to work on the audio file,
this is what I have so far:
As you can see, you can't really understand when the frequency changes, I can zoom in but that's not really reliable and confusing I would be happy to hear other ways.
Here is my full code:
import scipy.io.wavfile
import matplotlib.pyplot as plt
import numpy as np
def generateSignalFM(t,data):
TWO_PI = 2 * np.pi
fc = 10000
b = 5
fm = np.sin(TWO_PI * (fc + b * np.array(data)) * t) # calculaying frequency modulation
fig, axs = plt.subplots(nrows=2, ncols=1)
fig.tight_layout()
axs[1].plot(t,fm)
axs[1].set_xlabel("Time(s)")
axs[1].set_ylabel("Amplitude")
axs[1].set_title("Modulated Signal (FM)")
axs[0].plot(t,data)
axs[0].set_xlabel("Time(s)")
axs[0].set_ylabel("Amplitude")
axs[0].set_title("Original Signal")
plt.show()
samplerate, data = scipy.io.wavfile.read("musicSample.wav")
sample_for = 12
start_time = 30*samplerate # start from 30 seconds
end_time = start_time + (samplerate * sample_for) # sample for 1 second
split_data= data[start_time:end_time]
time = np.arange(0,sample_for,1/samplerate) #sample 1 second
You can see your signal's PSD after modulation by using "welch" algorithm. You can do it by scipy.signal.welch and something like this will be shown:
This is the example for fc = 100 and sampleRate=1000
To see this, you should use the following context in your code:
import scipy.signal as ss
FM = ss.welch(fm, fs=sampleRate, nperseg=2048, noverlap=1024, nfft=2048)
axs[0].plot(FM[0],FM[1])
I test an FFT on a square signal (100Hz, 0V-5V) of 50% duty cycle and i don't understand why my DC offset is huge ?
In theory it should be 2.5V ?
Thanks,
Best regards.
The fundamental is ok and others harmonics are correct.
square signal 100Hz, TTL compatible 0V-5V, 50% duty cycle
FFT, DC offset problem, fundamental ok, harmonics ok
from scipy.fftpack import fft
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
#
# configuration
# time analyse = L * (1/Fsample)
#
L = 512 # lenght buffer
Fsample = 2000 # frequency sample
Fsignal = 100 # frequency
#********************************
# perdiode sample
Tsample = 1.0/Fsample
# time vector, start = 0s, stop = 0.1024s, step = (0.1024s / (1/Fe))
t = np.linspace(0.0, L*Tsample, L)
# signal definition, DC offet = 2.5V, Amplitude = 2.5V
signal = 2.5 + 2.5*signal.square(2 * np.pi * Fsignal * t, 0.5)
# plot time signal
plt.subplot(2,1,1)
plt.plot(t, signal)
# fft of time signal
yf = fft(signal)
# time vector of fft
xf = np.linspace(0.0, 1.0/(2.0*Tsample), L//2)
# plot spectral
plt.subplot(2,1,2)
plt.plot(xf, 2.0/L * np.abs(yf[0:L//2]))
On the last line, the normalization factor was wrong.
It was not 2/L but 1/L.
The correct normalization factor plt.plot(xf, 1.0/L * np.abs(yf[0:L//2]))
The code work fine now !
FFT correct amplitude
I tried to filter some signal with fft.
The signal I am working on is quite complicated and im not really experienced in this topic.
That's why I created a simple sin wave 3Hz and tried to cut off the 3 Hz.
and so far, so good
import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fftfreq, irfft, rfft
t = np.linspace(0, 2*np.pi, 1000, endpoint=True)
f = 3.0 # Frequency in Hz
A = 100.0 # Amplitude in Unit
s = A * np.sin(2*np.pi*f*t) # Signal
dt = t[1] - t[0] # Sample Time
W = fftfreq(s.size, d=dt)
f_signal = rfft(s)
cut_f_signal = f_signal.copy()
cut_f_signal[(np.abs(W)>3)] = 0 # cut signal above 3Hz
cs = irfft(cut_f_signal)
fig = plt.figure(figsize=(10,5))
plt.plot(s)
plt.plot(cs)
What i expected
What i got
I don't really know where the noise is coming from.
I think it is some basic stuff, but i dont get it.
Can someone explain to to me?
Edit
Just further information
Frequency
yf = fft(s)
N = s.size
xf = np.linspace(0, fa/2, N/2, endpoint=True)
fig, ax = plt.subplots()
ax.plot(xf,(2.0/N * np.abs(yf[:N//2])))
plt.xlabel('Frequency ($Hz$)')
plt.ylabel('Amplitude ($Unit$)')
plt.show()
You could change the way you create your signal and use a sample frequency:
fs = 1000
t = np.linspace(0, 1000 / fs, 1000, endpoint=False) # 1000 samples
f = 3.0 # Frequency in Hz
A = 100.0 # Amplitude in Unit
s = A * np.sin(2*np.pi*f*t) # Signal
dt = 1/fs
And here the whole code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fftfreq, irfft, rfft
fs = 1000
t = np.linspace(0, 1000 / fs, 1000, endpoint=False)
f = 3.0 # Frequency in Hz
A = 100.0 # Amplitude in Unit
s = A * np.sin(2*np.pi*f*t) # Signal
dt = 1/fs
W = fftfreq(s.size, d=dt)
f_signal = rfft(s)
cut_f_signal = f_signal.copy()
cut_f_signal[(np.abs(W)>3)] = 0 # cut signal above 3Hz
cs = irfft(cut_f_signal)
fig = plt.figure(figsize=(10,5))
plt.plot(s)
plt.plot(cs)
And with f = 3.0 Hz and (np.abs(W) >= 3):
And with f = 1.0 Hz:
Just some additional information about why A. As solution works better than yours:
A. A's model doesn't include any non-integer frequencies in its Solution and after filtering out the higher frequencies the result looks like:
1.8691714842589136e-12 * exp(2*pi*n*t*0.0)
1.033507502555532e-12 * exp(2*pi*n*t*1.0)
2.439774536202658e-12 * exp(2*pi*n*t*2.0)
-8.346741339115191e-13 * exp(2*pi*n*t*3.0)
-5.817427588021649e-15 * exp(2*pi*n*t*-3.0)
4.476938066992472e-14 * exp(2*pi*n*t*-2.0)
-3.8680170177940454e-13 * exp(2*pi*n*t*-1.0)
while your solution includes components like:
...
177.05936105690256 * exp(2*pi*n*t*1.5899578814880346)
339.28717376420747 * exp(2*pi*n*t*1.7489536696368382)
219.76658524130005 * exp(2*pi*n*t*1.9079494577856417)
352.1094590251063 * exp(2*pi*n*t*2.0669452459344453)
267.23939871205346 * exp(2*pi*n*t*2.2259410340832484)
368.3230130593005 * exp(2*pi*n*t*2.384936822232052)
321.0888818355804 * exp(2*pi*n*t*2.5439326103808555)
...
Please refer to this question regarding possible side effects of zeroing FFT bins out.
I'm trying to write a code that plots the elliptical paths of an object using the equation for the ellipse r=a(1-e^2)/(1+e*cos(theta)). I'd also like this data to be put into an array for other use.
from numpy import *#Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
from pylab import *
a = 5
e = 0.3
theta = 0
while theta <= 2*pi:
r = (a*(1-e**2))/(1+e*cos(theta))
print("r = ",r,"theta = ",theta)
plt.polar(theta, r)
theta += pi/180
plt.show()
The code spits out correct values for r and theta, but the plot is blank. The polar plot window appears, but there is nothing plotted.
Please help. Thanks in advance.
Do not call plt.polar once for every point. Instead, call it once, with all the data as input:
import numpy as np #Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
cos = np.cos
pi = np.pi
a = 5
e = 0.3
theta = np.linspace(0,2*pi, 360)
r = (a*(1-e**2))/(1+e*cos(theta))
plt.polar(theta, r)
print(np.c_[r,theta])
plt.show()
By the way, numpy can do the calculation as a two-liner, instead of using a while-loop:
theta = np.linspace(0,2*pi, 360) # 360 equally spaced values between 0 and 2*pi
r = (a*(1-e**2))/(1+e*cos(theta))
This defines theta and r as numpy arrays (rather than single values).
I think you need to do points.append([theta,r]) then at the end plt.polar(points) ... that makes a kinda neat design too
from numpy import *#Imports Python mathematical functions library
import matplotlib.pyplot as plt #Imports plot library
from pylab import *
a = 5
e = 0.3
theta = 0
points = []
while theta <= 2*pi:
r = (a*(1-e**2))/(1+e*cos(theta))
print("r = ",r,"theta = ",theta)
points.append((theta, r))
theta += pi/180
#plt.polar(points) #this is cool but probably not what you want
plt.polar(*zip(*points))
plt.show()