Changing Amplitude & Frequency of numpy.sin(wt) in pylab - python

For part of another project, I just need to make a simple sine wave with some frequency f.
Changing "samples" gives some strange effects on the pylab plot and I just don't know why!
using samples=500 gives a plot with frequency = 1/50 Hz.
using samples=1000 gives a plot with frequency = 1/100 Hz.
then with larger samples like 5000 and 10000, the plotted wave changes amplitude along the t axis, in patterns.
import numpy as N
f = 10.
w = 2. * N.pi * f
time_interval = 100
samples = 5000
t = N.linspace(0, time_interval, samples)
y = N.sin(w * t)
pylab.plot(t, y)
pylab.show()
Any help here would be great! I just want a basic sine wave but can't even seem to do that!

I think you have a slight misconception with samples. It only gives the resolution of time. Try to plot with time_interval= 1 and vary the samples (Start with small values like 10 and increase it then gradually). You'll see.

To make eat's answer explicit, I set time_interval to 1, and varied samples, as he suggested:
import pylab
import numpy as N
f = 10.
w = 2. * N.pi * f
time_interval = 1
fig = pylab.figure()
for i, samples in enumerate((5, 50, 500, 5000)):
pylab.subplot(2, 2, i+1)
pylab.title('%i samples'%samples)
t = N.linspace(0, time_interval, samples)
y = N.sin(w * t)
pylab.plot(t, y, '.-')
fig.show()
50 samples is clearly not enough for a time_interval of 1; This is why 5000 isn't enough samples for a time_interval of 100.

Here's a basic example.
import pylab
x=pylab.arange(0,150,0.2)
y=pylab.sin(x);
pylab.plot(x,y)
pylab.show()
Look closely at the data being created:
x is an array (technically datatype = numpy.ndarray) from 0 to 149.8 with an interval of 0.2, i.e. type x to see array([0., 0.2, 0.4, ..., 149.8])
y is an array from sin(0) to sin(149.8), i.e. array([0., 0.198..., ..., -0.839...])

From the given parameters: Frequency, F = 10 Hz, Time period, T = 100 s and Number of samples for T = 100 s, N = 5000.
This implies, the No. of cycles = F * T = 10 * 100 = 1000. Let choose T = 10/F, to visualize 10 cycles. This means that we will get 10 cycles from the 10 Hz sine wave in 1 sec. This also means that we will have 5000 samples for the 10 cycles, or 500 samples per cycle which is quite a bit for replication of the signal.
import numpy as np
import matplotlib.pyplot as plt
F = 10
T = 10/F
Fs = 5000
Ts = 1./Fs
N = int(T/Ts)
t = np.linspace(0, T, N)
signal = np.sin(2*np.pi*F*t)
plt.plot(t, signal)
plt.show()

Related

scipy Fast fourier transform doesn't recognize the signal

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()

Plotting Multiple Realizations of a Stochastic Process in Python

I'm trying to plot the time evolution graph for Ornstein-Uhlenbeck Process, which is a stochastic process, and then find the probability distribution at each time steps. I'm able to plot the graph for 1000 realizations of the process. Each realization has a 1000 time step, with width of the time step as .001. I used a 1000 x 1000 array to store the data. Each rows hold value of each realizations. And column wise i-th columns correspond value at i-th time step for 1000 realizations.
Now I want bin results at each time steps together and then plot the probability distribution corresponding to each time step. I'm quite confused with doing it (I tried modifying code from IPython Cookbook, where they don't store each realizations in the memory).
The code that I made from the IPython Cookbook:
import numpy as np
import matplotlib.pyplot as plt
sigma = 1. # Standard deviation.
mu = 10. # Mean.
tau = .05 # Time constant.
dt = .001 # Time step.
T = 1. # Total time.
n = int(T / dt) # Number of time steps.
ntrails = 1000 # Number of Realizations.
t = np.linspace(0., T, n) # Vector of times.
sigmabis = sigma * np.sqrt(2. / tau)
sqrtdt = np.sqrt(dt)
x = np.zeros((ntrails,n)) # Vector containing all successive values of our process
for j in range (ntrails): # Euler Method
for i in range(n - 1):
x[j,i + 1] = x[j,i] + dt * (-(x[j,i] - mu) / tau) + sigmabis * sqrtdt * np.random.randn()
for k in range(ntrails): #plotting 1000 realizations
plt.plot(t, x[k])
# Time averaging of each time stamp using bin
# Really lost from this point onwrds.
bins = np.linspace(-2., 15., 100)
fig, ax = plt.subplots(1, 1, figsize=(12, 4))
for i in range(ntrails):
hist, _ = np.histogram(x[:,[i]], bins=bins)
ax.plot(hist)
Graph for 1000 realizations of Ornstein- Uhlenbeck Process:
Distribution generated from the code above:
I'm really lost with assigning of the bin value and plotting the histogram using it. I want to know whether my code is correct for plotting distributions corresponding to each time step, using bin. If not please tell me what modifications I need to make to my code.
The last for loop should iterate over n, not ntrails (which happen to be the same value here) but otherwise the code and plots look correct (apart from a few minor issues such as that is takes 101 breaks to get 100 bins so your code should probably read bins = np.linspace(-2., 15., 101)).
Your plots could be improved a bit though. A good guiding principle is to use as little ink as necessary to communicate the point that you are trying to make. You are always trying to plot all the data, which ends up obscuring your plots. Also, you could benefit from paying more attention to colour. Colour should carry meaning, or not be used at all.
Here would be my suggestions:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['axes.spines.top'] = False
mpl.rcParams['axes.spines.right'] = False
sigma = 1. # Standard deviation.
mu = 10. # Mean.
tau = .05 # Time constant.
dt = .001 # Time step.
T = 1 # Total time.
n = int(T / dt) # Number of time steps.
ntrails = 10000 # Number of Realizations.
t = np.linspace(0., T, n) # Vector of times.
sigmabis = sigma * np.sqrt(2. / tau)
sqrtdt = np.sqrt(dt)
x = np.zeros((ntrails,n)) # Vector containing all successive values of our process
for j in range(ntrails): # Euler Method
for i in range(n - 1):
x[j,i + 1] = x[j,i] + dt * (-(x[j,i] - mu) / tau) + sigmabis * sqrtdt * np.random.randn()
fig, ax = plt.subplots()
for k in range(200): # plotting fewer realizations shows the distribution better in this case
ax.plot(t, x[k], color='k', alpha=0.02)
# Really lost from this point onwards.
bins = np.linspace(-2., 15., 101) # you need 101 breaks to get 100 bins
fig, ax = plt.subplots(1, 1, figsize=(12, 4))
# plotting a smaller selection of time points spaced out using a log scale prevents
# the asymptotic approach to the mean from dominating the plot
for i in np.logspace(0, np.log10(n)-1, 21):
hist, _ = np.histogram(x[:,[int(i)]], bins=bins)
ax.plot(hist, color=plt.cm.plasma(i/20))
plt.show()

How to get a range of frequency bins for PSD

I am computing PSD of a signal, and I want the power from frequency range 0Hz to 20Hz. This is what i tried using linspace
df = pd.read_csv(path)
df = pd.DataFrame(df)
x = np.linspace(0, 20, 41)
dt = x[1] - x[0]
fs = 1 / dt
f,P = signal.welch(df, fs=5, nperseg=30, noverlap=5,axis=0)
Here, I get 6 frequency components from 0Hz to 2.5Hz, but I want to compute the power for frequency range till 20Hz
Can anyone help me here to do the same.
The PSD only goes from 0 to fs/2, you should specify the correct sample frequency in the fs parameter, 1024 in your case.
This example illustrates how to get the PSD for a sinusoidal signal:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import welch
Fs = 1024 # Hz
Ts = 1/Fs
time = np.arange(0, 2, Ts) # 2 seconds
freqs = [20, 50, 100] # frequencies in Hz
x = np.zeros(len(time))
for f in freqs:
x += np.sin(2 * np.pi * f * time)
plt.plot(x)
f, P = welch(x, fs=Fs)
plt.figure()
plt.stem(f, P)

Filtering signal frequency in Python

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.

Strange FFT output python

I am trying to take the FFT and plot it. Problem is, my code works for small frequencies (like 50) but doesn't work for the bigger frequencies I need. What is going on with my code?! I expect to see a spike at the frequency of the sine wave I input, but the spike is at different frequencies depending on the sample spacing I use.
bins = 600
ss = 2048
freq = 44100
centerfreq = freq*bins/ss
# Number of samplepoints
N = ss
# sample spacing
T = 1 / 800.
x = np.linspace(0.0, N*T, N)
y = sin(2*np.pi*centerfreq*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
plt.plot(xf, 2.0/N * np.abs(yf[0:N/2]), 'r')
The code is right, you need to brush up your Fourier Theory and Nyquist Sampling Theorem and make sure the numbers make sense. The problem is with your x-axis scale. The plot function plots the first item in x with the first item in y, if x is not scaled up to your expectations, you are in for a surprise. You also see this if you plot a sinusoidal signal (sine wave) and expect 'degrees' and you get radians for instance. Its your duty to scale it up well so that it lines up to your expectation.
Refer to this SO answer https://stackoverflow.com/a/25735436/2061422.
from scipy import *
from numpy import *
from pylab import * # imports for me to get going
bins = 600
ss = 2048
freq = 44100
centerfreq = freq*bins/ss
print centerfreq
# Number of samplepoints
N = ss
# sample spacing
T = 1. / freq # i have decreased the spacing considerably
x = np.linspace(0.0, N*T, N)
sample_spacing = x[1] - x[0] # but this is the real sample spacing
y = sin(2*np.pi*centerfreq*x)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
freqs = np.fft.fftfreq(len(y), sample_spacing) # read the manual on this fella.
plt.plot(freqs[:N/2], 1.0/N * np.abs(yf[0:N/2]), 'r')
plt.grid()
plt.show()

Categories

Resources