I am trying to calculate the power spectral density step by step using numpy FFT and comparing it to the PSD calculated by pylab PSD. Difference b/w plots of both methods can be visualized from in figures below.
#*************************PSD using pylab PSD**************************
import math
from rtlsdr import RtlSdr
import pylab as mpl
import numpy as np
import pandas as pd
sdr = RtlSdr()
sdr.rs = 2.4e6
sdr.fc = 935e6
sdr.gain = 40
samplest = ()
psd_scant = ()
psd_logt = ()
samples = sdr.read_samples(256*1024)
psd_scan, f=mpl.psd(samples, NFFT=1024, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6)
psd_log = 10*np.log10(psd_scan)```
#*************************Step by Step PSD using FFT**************************
n=256
x= np.array_split(samples, n)
xdf = pd.DataFrame(x)
xdft =xdf.transpose()
NFFT = 1024
xfft = np.fft.fft(xdft, n=1024, axis=0)[:1024, :]
xfftt=xfft.transpose()
PSD = np.abs(xfftt)**2
PSD_log = 10*np.log10(PSD)
PSD_shifted = np.fft.fftshift(PSD_log)
Final = PSD_shifted.mean(axis=0)
plt.xlabel('Frequency'); plt.ylabel('PSD')
plt.grid('on')
plt.plot(f,Final)
Pylab PSD
PSD using FFT
**Hints/ Help required **
To compute the manual PSD plot same as pylab PSD will be appreciated.
How the y axis can be corrected.
Related
I have four cosines with frequencies 400e-3, 500e-3, 600e-3 and 700e-3 and I am trying to do the FFT of them but under the time I need, I cannot distinguish the four. Is there a way to distinguish the peaks without changing the tmax time of 1.76 and the frequencies?
import numpy as np
import scipy.fftpack
from scipy.fftpack import fftfreq
from scipy.fft import fft
import matplotlib.pyplot as plt
t = np.linspace(0,1.76,2400)
f = [400e-3, 500e-3, 600e-3, 700e-3] # these are the frequencies
yy = 0
for i in f:
y = 0.5*np.cos(2*np.pi*i*t)
yy = yy + y
plt.figure(0)
plt.plot(t, yy)
f = fftfreq(len(t), np.diff(t)[0])
yf = fft(yy)
plt.figure(1)
plt.plot(f[:t.size//2], np.abs(yf[:t.size//2]))
plt.show()
Here are the results:
The solution was to increase tmax of
t = np.linspace(0,1.76,2400)
i.e. 1.76. FFT makes bins the size of 1/tmax and the small tmax is, the bigger the bins are leading to less resolution.
How to find Shift phase between two sinusoids in Python.
For example, I created two sinusoid with phase shift 180 radian (Visually). Can we calculate the phase shift in python script if we know only graph_1 and graph_2?
import matplotlib.pyplot as plt
import numpy as np
data=[]
def sin (f):
x=np.array(range(1,200))
y = 10*np.sin((0.1*x)+f)
return (y)
import matplotlib.pyplot as plt
graph_1 = sin(3.12)
graph_2 = sin(0)
plt.plot(graph_1 ,graph_2)
plt.show()
Please see the image here
I tried to generate an uniform distribution of random integeres on a given interval (it's unimportant whether it contains its upper limit or not) with python. I used the next snippet of code to do so and plot the result:
import numpy as np
import matplotlib.pyplot as plt
from random import randint
propsedPython = np.random.randint(0,32767,8388602)%2048
propsedPythonNoMod = np.random.randint(0,2048,8388602)
propsedPythonNoModIntegers = np.random.random_integers(0,2048,8388602)
propsedPythonNoModRandInt = np.empty(8388602)
for i in range(8388602):
propsedPythonNoModRandInt[i] = randint(0,2048)
plt.figure(figsize=[16,10])
plt.title(r'distribution $\rho_{prop}$ off all the python simulated proposed indices')
plt.xlabel(r'indices')
plt.ylabel(r'$\rho_{prop}$')
plt.yscale('log')
plt.hist(propsedPython,bins=1000,histtype='step',label=r'np.random.randint(0,32767,8388602)%2048')
plt.hist(propsedPythonNoMod,bins=1000,histtype='step',label=r'np.random.randint(0,2048,8388602')
plt.hist(propsedPythonNoModIntegers,bins=1000,histtype='step',label=r'np.random.random_integers(0,2048,8388602)')
plt.hist(propsedPythonNoModRandInt,bins=1000,histtype='step',label=r'for i in range(8388602):propsedPythonNoModRandInt[i] = randint(0,2048)')
plt.legend(loc=0)
The resulting plot is: Could somebody point me in the right direction why these spikes appear in al the different cases and or gives some advice which routine to use to got uniformly distributed random integers?
Thanks a lot!
Mmm...
I used new NumPy rng facility, and graph looks ok to me.
Code
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng()
N = 1024*500
hist = np.zeros(2048, dtype=np.int32)
q = rng.integers(0, 2048, dtype=np.int32, size=N, endpoint=False)
for k in range(0, N):
hist[q[k]] += 1
x = np.arange(0, 2048, dtype=np.int32)
fig, ax = plt.subplots()
ax.stem(x, hist, markerfmt=' ')
plt.show()
and graph
I'm creating a sine wave of 100Hz and trying to plot it's stft :
import scipy.io
import numpy as np
import librosa
import librosa.display
#%matplotlib notebook
import matplotlib.pyplot as plt
A = 1 # Amplitude
f0 = 100 # frequency
Fs = f0 * 800 # Sampling frequency
t = np.arange(Fs) / float(Fs)
X = np.sin(2*np.pi*t*f0)
plt.plot(t, X)
plt.xlabel("Time")
plt.ylabel("Amplitude")
plt.show()
D = np.abs(librosa.stft(X))
librosa.display.specshow(librosa.amplitude_to_db(D,ref=np.max),y_axis='log', x_axis='time')
I was expecting a single line at 100Hz instead.
Also, how can I plot Frequency(X-axis) vs Amplitude(Y-axis) graph to see a peak at 100Hz?
You need to pass the sample rate to specshow, using the sr keyword argument. Otherwise it will default to 22kHz, which will give wrong results.
D = np.abs(librosa.stft(X))
db = librosa.amplitude_to_db(D,ref=np.max)
librosa.display.specshow(db, sr=Fs, y_axis='log', x_axis='time')
on my Raspberry PI 4, I have a xlsx file which I scan with :df = pd.read_excel('')
This is a dataset of a pressure sensor with 146651 rows x 1 columns. I want to perform a fft for this dataset, but if I plot the fft I get a curve exact the same to the time signal (moved on the x-axis???).
So what is the problem?
import numpy as np
import matplotlib.pyplot as plt
from scipy import fftpack
import pandas as pd
# Import csv file
df = pd.read_excel('/home/pi/Downloads/test_11.12.19_500_neuHz.xlsx', skiprows=1)
print(df)
sig_fft = fftpack.fft(df)
power = np.abs(sig_fft)
print (power)
sample_freq = fftpack.fftfreq(df.size, 0.02)
plt.figure(figsize=(6,5))
plt.plot(sample_freq, power)
plt.show()
graph
Your input data must be in a single row. Currently, your FFT is applied to all rows individually, which means the output for any given row is the mean of the single cell signal, therefore, your output is the same as your input.
#data is one column
df = pd.DataFrame([4,5,4])
df
fft = fftpack.fft(df)
fft
# output = input => wrong
#data as one row
df = pd.DataFrame({'0':[4],'1':[5],'2':[4]})
df
fft = fftpack.fft(df)
fft
# right
Now I am performing the fft in another way. But how can I scale the frequency and the magnitude axis.
import numpy as np
import matplotlib.pyplot as plt
import scipy
from scipy.fftpack import fft
import pandas as pd
import math
from tkinter import filedialog
from tkinter import *
#choose csv file
root = Tk()
root.filename = filedialog.askopenfilename ( initialdir = "/home/pi", title = "Datei auswählen", filetypes = (("Comma Seperated Values (CSV)", "*.csv"), ("Alle Dateien", "*.*")) )
# Import csv file
df = pd.read_csv(root.filename, delimiter = ';')
#convert Voltage to Bar
df_echt = df/0.01
#preparation for fft
df_neu = df.as_matrix()
time = df_neu[:,0]
voltage = df_neu[:,0]/df_neu[:,0].max()
df_tr = df_neu.T
#fft
amplitude = np.fft.rfft (voltage)
freq = np.fft.rfftfreq(len(time),np.diff(time)[0])
#plot time signal and fft
plt.plot( np.absolute(amplitude), lw = 0.5)
plt.figure (2)
plt.plot (df_echt)
plt.legend (df)
plt.show()
FFT graph
So how do I scale the axises?