I try do a wavelet transform on a signal.
The signal is recorded with 500 Hz (: 500 datapoints per second). I just want to do a wavelet transform on 0.2 seconds of the signal (-> 100 datapoints).
I am really not sure how to define parameter "w" and also if the y-axis is scaled correctly? I cannot find anything in the documentation of scipy to "w".
My code and output looks as follows:
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
t, dt = np.linspace(0, 0.2, 100, retstep=True)
fs = 1/dt
w = 6.
sig = sig[0:100] # 0.2 seconds of the signal
freq = np.linspace(1, fs/2, 100)
widths = w*fs / (2*freq*np.pi)
cwtm = signal.cwt(sig, signal.morlet2, widths, w=w)
plt.pcolormesh(t, freq, np.abs(cwtm), cmap='jet', shading='gouraud')
plt.xlabel("Time")
plt.ylabel("Scale")
plt.show()
Output:
Bonus question: How would you interprete the output in two sentences?
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')
Below are two plots, of which I seek to reproduce the one on the left. The plot was produced in Spyder 3.3.6 - however, so was one on the right; i.e., I can no longer reproduce the plot. I used the same code both times - a simple plt.hist(bins=...) on some data - a minimal variant below. Tested w/ Inline, Automatic, Qt5, and Tkinter graphical backends, w/ 76.0 dpi - though I do not recall all other settings, which may have differed at the time.
How do I get histograms to look like the one on the left - a "looping gradient"?
Environ. info: Win-10 OS, GTX 1070, Spyder 3.3.6, Python 3.7.5, IPython 7.10.1, Matplotlib 3.1.1
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2)
x = 0.06*(np.random.uniform(-1, 1, 4000) + 0.05*np.random.randn(4000))
plt.hist(x, bins=400)
plt.gcf().set_size_inches(6, 1.2)
plt.box(None)
Tip: the default matplotlib blue is color=[0.121569, 0.466667, 0.705882]
A more complete answer w/ an explanation relative to #An0ther0ne's follows, but thanks to OP for showing the core of the method.
The idea is to fetch individual histogram bars, patches, and set their color via .set_facecolor() according to a gradient color scheme. We can generate such a scheme as a sine function centered about some "main color" to yield desired effect; matplotlib's default color, [0.121569, 0.466667, 0.705882], shall be used.
Lastly, bins_norm = bins / bins.max() normalizes bins to lie between -1 and 1, hence spanning twice the sinusoidal period, so we'll be using np.pi instead of 2*np.pi in np.sin().
Example:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(2)
x = 0.06*(np.random.uniform(-1, 1, 8000) + 0.05*np.random.randn(8000))
pretty_hist(x, 400, n_loops=8, alpha=0.9)
pretty_hist(x, 400, n_loops=16, alpha=1)
Function:
def pretty_hist(data, bins, n_loops=8, alpha=1, base_color=[0.121569, 0.466667, 0.705882]):
N, bins, patches = plt.hist(data, bins=bins, density=True)
bm = bins.max()
bins_norm = bins / bm
bc = base_color
for bin_norm, patch in zip(bins_norm, patches):
grad = np.sin(np.pi * n_loops * bin_norm) / 15 + .04
color = (bc[0] + grad, bc[1] + grad, bc[2] + grad, alpha)
patch.set_facecolor(color)
plt.gcf().set_size_inches(6, 1)
plt.box(None)
plt.show()
Introspection: we can see what grad is doing by recording it at each iteration and then plotting; for n_loops=8 and bins=400:
grads = []
bin_norm, patch in zip(bins_norm, patches):
grad = np.sin(np.pi * n_loops * bin_norm) / 15 + .04
grads.append(grad)
plt.plot(grads)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
np.random.seed(2)
x = 0.06*(np.random.uniform(-1, 1, 4000) + 0.05*np.random.randn(4000))
N, bins, patches = plt.hist(x, bins=400, density=True)
bm = bins.max()
fracs = bins / bm
for thisfrac, thispatch in zip(fracs, patches):
Green = np.abs(np.sin(thisfrac/bm)/2)
color = (0,Green,1,1)
thispatch.set_facecolor(color)
plt.gcf().set_size_inches(6, 1.2)
plt.box(None)
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()