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')
Related
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.
I'm trying to figure out why Mel scale spectrogram seems to have the wrong frequency scale. I generate a 4096Hz tone and plot it using librosa's display library, and the tone does not align with the known frequency? I'm obviously doing something wrong, can someone help? Thanks!
import numpy as np
import librosa.display
import matplotlib.pyplot as plt
sr = 44100
t = np.linspace(0, 1, sr)
y = 0.1 * np.sin(2 * np.pi * 4096 * t)
M = librosa.feature.melspectrogram(y=y, sr=sr)
M_db = librosa.power_to_db(M, ref=np.max)
librosa.display.specshow(M_db, y_axis='mel', x_axis='time')
plt.show()
When you compute the mel spectrogram using librosa.feature.melspectrogram(y=y, sr=sr) you implicitly create a mel filter using the parameters fmin=0 and fmax=sr/2 (see docs here). To correctly plot the spectrogram, librosa.display.specshow needs to know how it was created, i.e. what sample rate sr was used (to get the time axis right) and what frequency range was used to get the frequency axis right. While librosa.feature.melspectrogram defaults to 0 - sr/2, librosa.display.specshow unfortunately defaults to 0 - 11050 (see here). This describes librosa 0.8—I could imagine this changes in the future.
To get this to work correctly, explicitly add fmax parameters. To also get the time axis right, add the sr parameter to librosa.display.specshow:
import numpy as np
import librosa.display
import matplotlib.pyplot as plt
sr = 44100
t = np.linspace(0, 1, sr)
y = 0.1 * np.sin(2 * np.pi * 4096 * t)
M = librosa.feature.melspectrogram(y=y, sr=sr, fmax=sr/2)
M_db = librosa.power_to_db(M, ref=np.max)
librosa.display.specshow(M_db, sr=sr, y_axis='mel', x_axis='time', fmax=sr/2)
plt.show()
I want to denoise a signal using wavelets.
I have generated an ideal sine wave of two different frequencies and added noise to it.
Please let me know how to denoise the signal "I_as_fft_array_noise" as mentioned in the below code using wavelets.
Import Libraries
from scipy import signal
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
import pywt
import sys
Define the signal sine signal of 100Hz and 50Hz
Fs_fft = 1e4 # Sampling Frequency
Pi=np.pi
N1 = (1e5)/2
time1 = np.arange(N1) / float(Fs_fft)
f1 = 100
x1 = 1000*np.sin(2*Pi*f1*time1)
time2 = np.arange(N1,2*N1) / float(Fs_fft)
f2 = 50
x2 = 500*np.sin(2*Pi*f2*time2)
T_fft_array =np.concatenate((time1,time2))
I_as_fft_array = np.concatenate((x1,x2))
Adding noise using target SNR
Reference: adding noise to a signal in python
I_as_fft_array_watts = I_as_fft_array ** 2
I_as_fft_array_db = 10 * np.log10(I_as_fft_array_watts)
target_snr_db = 20
sig_avg_watts = np.mean(I_as_fft_array_watts)
sig_avg_db = 10 * np.log10(sig_avg_watts)
noise_avg_db = sig_avg_db - target_snr_db
noise_avg_watts = 10 ** (noise_avg_db / 10)
mean_noise = 0
noise_volts = np.random.normal(mean_noise, np.sqrt(noise_avg_watts), len(I_as_fft_array_watts))
I_as_fft_array_noise = I_as_fft_array + noise_volts
Plot ideal signal
plt.plot(T_fft_array , I_as_fft_array)
plt.title('Ideal Signal')
plt.ylabel('Current [A]')
plt.xlabel('Time [sec]')
plt.show()
Plot signal with noise
plt.plot(T_fft_array, I_as_fft_array_noise)
plt.title('Signal with noise')
plt.ylabel('Voltage (V)')
plt.xlabel('Time (s)')
plt.show()
I am trying to do an FFT on a .wav file that contains only a 1 kHz sin wave. When I plot the result, I expect the peak to be at the fundamental (1 kHz) but instead, I see the peak at what seems to be the 3rd harmonic (3 kHz). I have tried 2 other .wav files at 440 Hz and 2 kHz with the same result. I used a frequency counter to verify the .wav files contain the frequencies I expect.
For comparison, I use the commented code below to generate and plot a sin function which displays correctly.
import matplotlib.pyplot as plt
import numpy as np
import wave, struct
sound_file = wave.open('c:\downloads\SineWave_1000Hz.wav', 'r')
file_length = sound_file.getnframes()
data = sound_file.readframes(file_length)
data = struct.unpack('{n}h'.format(n=file_length), data)
data = np.array(data)
sound_file.close()
#x = np.linspace(0.0, 1, 600)
#y = np.sin(50.0 * 2.0*np.pi*x)
#yf = fft(y)
yf = fft(data)
plt.xlim(0, 4000)
plt.plot( np.abs(yf))
plt.grid()
plt.show()
I have two lists of float values, one for time and other for voltage values taken from an oscilloscope (I assume). I have to draw an amplitude spectrum plot, but i'm not exactly sure what function I need to use and what parameters I need to give it, I tried fft(u), but it didn't work.
Any help is appreciated, let me know if you need more info.
Use numpy.
As an example, let me show how I analysed the frequencies in a stereo WAV file;
First I read the data and separated it in the left and right channels;
import wave
import numpy as np
wr = wave.open('input.wav', 'r')
sz = 44100 # Read and process 1 second at a time.
da = np.fromstring(wr.readframes(sz), dtype=np.int16)
left, right = da[0::2], da[1::2]
Next I run a discrete fourier transform on it;
lf, rf = abs(np.fft.rfft(left)), abs(np.fft.rfft(right))
And we plot the left channel with mathplotlib;
import matplotlib.pyplot as plt
plt.figure(1)
a = plt.subplot(211)
r = 2**16/2
a.set_ylim([-r, r])
a.set_xlabel('time [s]')
a.set_ylabel('sample value [-]')
x = np.arange(44100)/44100
plt.plot(x, left)
b = plt.subplot(212)
b.set_xscale('log')
b.set_xlabel('frequency [Hz]')
b.set_ylabel('|amplitude|')
plt.plot(lf)
plt.savefig('sample-graph.png')
The graph looks something like this;
Here is the Frequency-Time spectrum of the signal, stored in the wave file
import wave
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
signal_wave = wave.open('voice.wav', 'r')
sample_frequency = 16000
data = np.fromstring(signal_wave.readframes(sample_frequency), dtype=np.int16)
sig = signal_wave.readframes(-1)
sig = np.fromstring(sig, 'Int16')
For the wave file
sig = sig[:]
For some segment of the wave file
sig = sig[25000:32000]
To plot spectrum of the signal wave file
plt.figure(1)
c = plt.subplot(211)
Pxx, freqs, bins, im = c.specgram(sig, NFFT=1024, Fs=16000, noverlap=900)
c.set_xlabel('Time')
c.set_ylabel('Frequency')
plt.show()