I am trying to get feature vectors from the coefficients I have generated. The spectra are decomposed using 8 levels and I am only choosing the coefficients of decomposed levels from 3 to 7. I have five simulated spectra and I am using 10 wavelet family types. I'd expect to get a feature_ vector of shape (5, 10, 5) but I am somewhat getting an error ValueError: setting an array element with a sequence. when I try to assign the decomposed coefficients at level 2-7.
Here is something close to my original data;
import pywt
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
x = np.linspace(0, 1, num=200)
signal1 = pd.DataFrame(np.sin(150 * np.pi * x**2))
signal2 = pd.DataFrame(np.sin(100 * np.pi * x**2 + 2))
signal3 = pd.DataFrame(np.sin(20 * np.pi * x**2 + 4))
signal4 = pd.DataFrame(np.sin(20 * np.pi * x**2 + 6))
signal5 = pd.DataFrame(np.sin(20 * np.pi * x**2 + 8))
# append the signals
signal = pd.concat([signal1, signal2, signal3, signal4, signal5], axis=0)
# split the signals
signal = np.array_split(signal, 5)
wavelet_list = ['db1', 'db4', 'sym6', 'sym8', 'coif2', 'coif3',\
'bior2.6', 'bior6.8', 'rbio2.6', 'rbio5.5']
feature_vector = np.zeros((5, 10, 5))
for spectra_index in range(5):
for wavelet_index, wavelet in enumerate(wavelet_list):
coeffs = pywt.wavedec(signal[spectra_index], wavelet=wavelet, level=8)
cA8, cD8, cD7, cD6, cD5, cD4, cD3, cD2, cD1 = coeffs
feature_vector[spectra_index, wavelet_index, :] = coeffs[2:7]
# plot the coefficients from level 3 to 7 for each wavelet and each spectrum
fig, axes = plt.subplots(nrows=len(coeffs[2:7]), ncols=1, figsize=(15, 45))
sns.set_style("whitegrid")
for j, ax in enumerate(axes.ravel(), start=1):
# plot the detail coefficients for level 3-7
ax.plot(coeffs[j])
# format the title to include the spectrum number, wavelet name, and level
# ax.set_title('Spectrum {} detail coeffiecients at level {} for {}'.format(spectra_index+1, j, wavelet))
Related
i have two time series discretized on log10 timestamps which i want to convolve with one another, using python. For linearly spaced time series i use scipy.signal.convole, which works just fine. Is there something similar for log10 discretization? The cut-off frequency is defined in terms of the standard deviation of the Gauss Kernel (sigma). The goal is to filter the log with the same cut-off frequency.
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as sg
f = lambda t : np.sin(2 * t) + np.sin(0.5 * t)
sigma = 1
kernel = lambda x : np.exp(-x**2 / (2 * sigma**2)) / (np.sqrt(2 * np.pi) * sigma)
# LINEAR DISCRETIZATION
t_linear = np.arange(0, 100, 0.01)
signal_linearly_discretized = f(t_linear)
t_kernel_linear = np.arange(-10, 10, 0.01)
kernel_linearly_discretized = kernel(t_kernel_linear)
# Filter by convolution of kernel and signal
signal_filtered_linear = np.convolve(kernel_linearly_discretized, signal_linearly_discretized,
mode="same") / np.sum(kernel_linearly_discretized)
# LOG DISCRETIZATION
t_log = np.logspace(0, 100, 1000)
signal_log_discretized = f(t_log)
"""
Filtering signal_log_discretized is unclear
"""
# Filter by convolution of kernel and signal
signal_filtered_linear = np.convolve(kernel_linearly_discretized, signal_linearly_discretized,
mode="same") / np.sum(kernel_linearly_discretized)
# Plotting of linear signal and filtered signal
fig, axes = plt.subplots(1, 2)
ax = axes[0]
ax.plot(t_linear, signal_linearly_discretized)
ax.set_title("signal")
ax = axes[1]
ax.plot(t_linear, signal_filtered_linear)
ax.set_title("signal filtered")
fig.tight_layout()
Above you can see the code that i would use to apply a Gauss filter to a linearly discretized signal. I want to perform the same (or a comparable) operation on the signal signal_log_discretized.
Thanks
Suppose I have a 2D Gaussian with pdf
I want to draw an ellipse corresponding to the level-set (contour)
Following here I know that I can replace the precision matrix with its eigendecomposition to obtain
where gamma is
Then to find coordinates of the points on the ellipse I would have to do
I tried plotting this but it is not working.
Plotting the Contours
from scipy.stats import multivariate_normal
import numpy as np
from numpy.linalg import eigh
import math
import matplotlib.pyplot as plt
# Target distribution
sx2 = 1.0
sy2 = 2.0
rho = 0.6
Sigma = np.array([[sx2, rho*math.sqrt(sx2)*math.sqrt(sy2)], [rho*math.sqrt(sx2)*math.sqrt(sy2), sy2]])
target = multivariate_normal(mean=np.zeros(2), cov=Sigma)
# Two different contours
xy = target.rvs()
xy2 = target.rvs()
# Values where to plot the density
x, y = np.mgrid[-2:2:0.1, -2:2:0.1]
zz = target.pdf(np.dstack((x, y)))
fig, ax = plt.subplots()
ax.contour(x,y, zz, levels=np.sort([target.pdf(xy), target.pdf(xy2)]))
ax.set_aspect("equal")
plt.show()
The code above shows the contour
Plotting the Ellipse
# Find gamma and perform eigendecomposition
gamma = math.log(1 / (4*(np.pi**2)*sx2*sy2*(1 - rho**2)*(target.pdf(xy)**2)))
eigenvalues, P = eigh(np.linalg.inv(Sigma))
# Compute u and v as per link using thetas from 0 to 2pi
thetas = np.linspace(0, 2*np.pi, 100)
uv = (gamma / np.sqrt(eigenvalues)) * np.hstack((np.cos(thetas).reshape(-1,1), np.sin(thetas).reshape(-1, 1)))
# Plot
plt.scatter(uv[:, 0], uv[:, 1])
However this clearly doesn't work.
You should square sx2 and sy2 in gamma.
gamma should be square rooted.
Multiply the resulting ellipse by P^-1 to get points in the original coordinate system. That's mentioned in the linked post. You have to convert back to the original coordinate system. I don't know actually how to code this, or if it actually works, so I leave the coding to you.
gamma = math.log(1 / (4*(np.pi**2)*(sx2**2)*(sy2**2)*(1 - rho**2)*(target.pdf(xy)**2)))
eigenvalues, P = eigh(np.linalg.inv(Sigma))
# Compute u and v as per link using thetas from 0 to 2pi
thetas = np.linspace(0, 2*np.pi, 100)
uv = (np.sqrt(gamma) / np.sqrt(eigenvalues)) * np.hstack((np.cos(thetas).reshape(-1,1), np.sin(thetas).reshape(-1, 1)))
orig_coord=np.linalg.inv(P) * uv #I don't how to code this in python
plt.scatter(orig_coord[:,0], orig_coord[:,1])
plt.show()
My attempt at coding it:
gamma = math.log(1 / (4*(np.pi**2)*(sx2**2)*(sy2**2)*(1 - rho**2)*(target.pdf(xy)**2)))
eigenvalues, P = eigh(np.linalg.inv(Sigma))
# Compute u and v as per link using thetas from 0 to 2pi
thetas = np.linspace(0, 2*np.pi, 100)
uv = (np.sqrt(gamma) / np.sqrt(eigenvalues)) * np.hstack((np.cos(thetas).reshape(-1,1), np.sin(thetas).reshape(-1, 1)))
orig_coord=np.zeros((100,2))
for i in range(len(uv)):
orig_coord[i,0]=np.matmul(np.linalg.inv(P), uv[i,:])[0]
orig_coord[i,1]=np.matmul(np.linalg.inv(P), uv[i,:])[1]
# Plot
plt.scatter(orig_coord[:, 0], orig_coord[:, 1])
gamma1 = math.log(1 / (4*(np.pi**2)*(sx2**2)*(sy2**2)*(1 - rho**2)*(target.pdf(xy2)**2)))
uv1 = (np.sqrt(gamma1) / np.sqrt(eigenvalues)) * np.hstack((np.cos(thetas).reshape(-1,1), np.sin(thetas).reshape(-1, 1)))
orig_coord1=np.zeros((100,2))
for i in range(len(uv)):
orig_coord1[i,0]=np.matmul(np.linalg.inv(P), uv1[i,:])[0]
orig_coord1[i,1]=np.matmul(np.linalg.inv(P), uv1[i,:])[1]
plt.scatter(orig_coord1[:, 0], orig_coord1[:, 1])
plt.axis([-2,2,-2,2])
plt.show()
Sometimes the plots don't work and you get the error invalid sqrt, but when it works it looks fine.
Using the code below I am able to create a sign wave
def normalizedAmp(signalX, hz):
'''extract correctly-normalized amplitude'''
signalAmp = np.abs(signalX[0:len(hz)])
signalAmp[1:] = 2*signalAmp[1:]
return signalAmp
def sinWav(amp, freq, time, phase=0):
return amp * np.sin(2 * np.pi * (freq * time - phase))
# simulation parameters
srate = 1000
time = {
0: np.arange(0, 4, 1/srate),
1: np.arange(4, 8, 1/srate),
2: np.arange(8, 12, 1/srate)
}
signal = sinWav(amp=0.25, freq=2, time=time[0])
plt.figure(figsize=(12,3))
# plot time-domain signal
plt.subplot2grid((1,3), (0,0))
plt.plot(time[0], signal)
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.title('Time domain')
I would like to create a sin wave which changes it's amplitude at time 4s, and 8s so that the sin wave looks like the image below
I know how to create each of the 3 sin waves in that img, but I don't know how to combine them into one.
I've tried to combine the first two by doing
np.concatenate(sinWav(amp=0.25, freq=2, time=time[0]), sinWav(amp=1, freq=2, time=time[0]))
and receive the error
ValueError: x and y must have same first dimension, but have shapes (4000,) and (8000,)
You can concatenate arrays by making a list of them as parameter to np.concatenate (e.g. np.concatenate([array1,array2,array3]) or as tuple: np.concatenate((array1,array2,array3))) :
import matplotlib.pyplot as plt
import numpy as np
def sinWav(amp, freq, time, phase=0):
return amp * np.sin(2 * np.pi * (freq * time - phase))
# simulation parameters
srate = 1000
time = {0: np.arange(0, 4, 1 / srate),
1: np.arange(4, 8, 1 / srate),
2: np.arange(8, 12, 1 / srate)}
signal = sinWav(amp=0.25, freq=2, time=time[0])
plt.figure(figsize=(12, 3))
# plot time-domain signal
plt.plot(np.concatenate([time[0], time[1], time[2]]),
np.concatenate([sinWav(amp=0.25, freq=2, time=time[0]),
sinWav(amp=1.0, freq=2, time=time[1]),
sinWav(amp=0.5, freq=2, time=time[2])]))
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.title('Time domain')
plt.tight_layout()
plt.show()
So i was trying this and I find it really unfeasible. I am not that aware about smart ways to do the following. Can somebody help ? Also inputs of lists are quite big.
This task was to create an image from the values generated by me.
center_star contains list of [x,y] pairs which are centers of various point like objects.
1800 value represents that image to be generated is of 1800x1800 pixel.
Sigma variable has value 2 by default.
final=[[0]*1800]*1800
for i in range(len(center_stars)):
xi=center_stars[i][0]
yi=center_stars[i][1]
print(i)
for j in range(1800):
for k in range(1800):
final[j][k]+=gauss_amplitude[i]*(math.e**((-1*((xi-j)**2+(yi-k)**2))/2*sigma*sigma))
Is there a smarter way to save time using some of the numpy operation and execute this piece of code in less time?
Something like that:
import math
import numpy as np
N = 1800
final = np.empty((N, N))
final1 = np.empty((N, N))
j = np.arange(N)
k = np.arange(N)
jj, kk = np.meshgrid(j, k)
sigma = 2.
s = 0.5 / (sigma * sigma)
for i in range(len(center_stars)):
xi = center_stars[i][0]
yi = center_stars[i][1]
final += gauss_amplitude[i] * np.exp(- ((xi - jj.T)**2 + (yi - kk.T)**2) * s)
# Code below is for comparison:
for j in range(N):
for k in range(N):
final1[j][k]+=gauss_amplitude[i] * (math.e** (-((xi-j)**2+(yi-k)**2)/(2*sigma*sigma)))
Besides, I assume you missed brackets around 2*sigma*sigma
you can try to compact your code like this:
Gauss=lambda i,j,k,xi,yi:gauss_amplitude[i]*(math.e**((-((xi-j)**2+(yi-k)**2))/(2*sigma*sigma)))
final=[[Gauss(i,j,k,x[0],x[1]) for j in range(1800) for k in range(1800)] for i,x in enumerate(center_starts)]
If your sigmas are all the same, you can achieve this with out any loop by using
scipy.signal.convolve2d.
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import convolve2d
from scipy.stats import multivariate_normal
sigma = 3
width = 200 # smaller than yours so you can see the single pixels
n_stars = 50
# draw some random stars
star_row = np.random.randint(0, width, n_stars)
star_col = np.random.randint(0, width, n_stars)
star_amplitude = np.random.normal(50, 10, n_stars)
# assign amplitudes to center pixel of stars
amplitudes = np.zeros((width, width))
amplitudes[star_row, star_col] = star_amplitude
# create 2d gaussian kernel
row = col = np.arange(-4 * sigma, 4 * sigma + 1)
grid = np.stack(np.meshgrid(row, col)).T
kernel = multivariate_normal(
[0, 0],
[[sigma**2, 0], [0, sigma**2]]
).pdf(grid)
kernel /= kernel.sum()
# convolve with 2d gaussian
final = convolve2d(amplitudes, kernel, mode='same')
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(9, 3))
img = ax1.imshow(amplitudes)
fig.colorbar(img, ax=ax1)
ax1.set_label('Before Convolution')
img = ax2.imshow(kernel)
fig.colorbar(img, ax=ax2)
ax2.set_label('Convolution Kernel')
img = ax3.imshow(final)
fig.colorbar(img, ax=ax3)
ax3.set_label('After Convolution')
fig.tight_layout()
fig.savefig('conv2d.png', dpi=300)
Result:
If the sigmas differ, you get a way with a single loop over the possible sigmas.
I want to read data from the file and plot the fft of it.
I have used the scipy's fft function to plot the fft of the synthetically generated signal data however while I am trying to save the generated signal data and plot the fft I am getting the peaks as I was getting but the value of the amplitude and frequency is off as compared to the Original plotting.I found problem with the second fft function. Can anyone help me with the same.
import numpy as np
import pandas as pd
import scipy
from scipy.fftpack import fft,fftfreq
import matplotlib.pyplot as plt
import csv
#Function to plot the raw data
def raw_plot(signals,time):
'''Plot the raw values in the time domain '''
plt.figure(0)
plt.plot(time,signals)
plt.xlabel("Time(s)")
plt.ylabel("Amplitude(g)")
plt.show()
#Function to plot the fft of the data
def fft_signal(signal, sampling_frequency, timestart, timeend):
T = 1 / sampling_frequency
N = (timeend - timestart) * sampling_frequency
x = np.linspace(0.0, 1.0 / (2.0 * T), int(N / 2))
# print("Values of X are :",x)
# print(len(x))
yr2 = fft(signal)
y2 = 2 / N * np.abs(yr2[0:int(N / 2)])
# amp_spec = abs(fft(signal))/N
# freq = np.linspace(0,2,num=N)
plt.figure(2)
plt.plot(x, y2)
plt.xlabel("Frequency")
plt.ylabel("Amplitude")
plt.show()
def fftsignal2(data, sampling_freq = 100, timestep = 1 ):
N = len(data)
FS = 1000
T= 1/FS
timestep = timestep
yr2 = fft(data)
y2 = 2 / N * np.abs(yr2[0:int(N / 2)])
# f= np.arange(0,N)*FS/N
# f= np.linspace(0,1.0/T,N)
frq = np.fft.fftfreq(N,d=timestep)
# f= np.linspace(0.0,int(N/2)*sampling_freq)
frq= frq[0:len(frq)//2]
print("Frequencies Length :",len(frq))
print("DATA LENGTH :",len(y2))
plt.figure(3)
plt.plot(frq,y2)
plt.xlabel("Frequency")
plt.ylabel("Amplitude")
plt.show()
Mag1_Hz = 70
Mag1_AMP = 10
Mag4_AMP = 60
Mag4_Hz= 50
Mag2_Hz = 20
Mag2_AMP = 8
time_start = 0
time_end = 4
Sampling_frequency = 100
No_of_samples = (time_end-time_start) * Sampling_frequency
time = np.linspace(time_start,time_end,No_of_samples)
#Generate the signals values
data_signal = Mag1_AMP * np.sin(2* np.pi * Mag1_Hz * time ) + Mag2_AMP * np.cos(2* np.pi * Mag2_Hz * time)
raw_plot(signals=data_signal[:800],time=time[:800])
fft_signal(data_signal,sampling_frequency=Sampling_frequency,timestart=time_start,timeend=time_end)
# for (time, datavalues) in zip(time,data_signal):
# with open("data_signals_27.csv","a",newline="") as file:
# writefile = csv.writer(file)
# print("Time%f,Data %f"%(time,datavalues))
# print(time,datavalues)
# writefile.writerow([time,datavalues])
fftsignal2(data= data_signal, sampling_freq= Sampling_frequency,timestep=2)
The peaks are coming right in the fft_signal function no 1 while I am trying to construct the fftsignal2 to plot the fft of the data so the peaks which I am getting is correct but the magnitude and frequency is off.I don't understand why ? Can anyone help me with that.