Get all zeroes from matplotlib graph - python

How could I get a list of all the zeroes of a matplotlib graph? By zeroes I mean every coordinate where the y-value of my function is at 0 (very close to zero also works for what I'm trying to accomplish). My code and the graph it generates are down below.
THE .WAV FILE: https://drive.google.com/drive/folders/11nE0nyd9UPViicSIKNeiBqSNbdWGRbIl?usp=sharing
MY CODE:
from scipy.io import wavfile
import matplotlib.pyplot as plt
import numpy as np
samplerate, data = wavfile.read(r'C:\Users\jack_l\Downloads\louduntitled.wav')
length = data.shape[0] / samplerate
import matplotlib.pyplot as plt
import numpy as np
time = np.linspace(0., length, data.shape[0])
plt.plot(time, data[:, 1], label="Right channel")
plt.legend()
plt.xlabel("Time [s]")
plt.ylabel("Amplitude")
plt.show()
GRAPH:

I believe you want to find all times where the y-value is zero.
What about finding zero-crossings of the array data[:, 1] (here a), and use the returned indices to find the interpolated time values where y-value is zero.
CODE
import matplotlib.pyplot as plt
import numpy as np
from scipy.io import wavfile
# load data
samplerate, data = wavfile.read(r'C:\Users\jack_l\Downloads\louduntitled.wav')
length = data.shape[0] / samplerate
time = np.linspace(0., length, data.shape[0])
a = data[:, 1] # here put your data
zc_idxs = np.where(np.diff(np.sign(a)))[0] # indices of element before zero crossing
t_zero = []
for zc_i in zc_idxs: # interpolate each zero crossing
t1 = time[zc_i]
t2 = time[zc_i + 1]
a1 = a[zc_i]
a2 = a[zc_i + 1]
t_zero.append(t1 + (0 - a1) * ((t2 - t1) / (a2 - a1)))
plt.plot(time, a, label="Right channel")
plt.plot(t_zero, np.zeros((len(t_zero), 1)), 'o')

We can't access to your data, so I used the cos function to have a similar shape.
Here is my code that perform a linear interpolation (there's a small error due to the non-linear behavior of the cos function)
import numpy as np
n = 2000
x = np.linspace(0, 10, n)
y = np.cos(x)
res = []
is_positive = y[0] > 0
for i in range(n):
if y[i] == 0:
res.append(x[i])
elif (is_positive and y[i] < 0) or (not is_positive and y[i] > 0):
x_gap = x[i] - x[i-1]
coef_gap = y[i]/(y[i] - y[i-1])
res.append(x[i] + x_gap*coef_gap)
is_positive = not is_positive
analytic_res = [i*np.pi/2 for i in range(1,6,2)]
print(res)
print(analytic_res)
Output :
[1.5807794610537442, 4.722328378160516, 7.863877295269648]
[1.5707963267948966, 4.71238898038469, 7.853981633974483]
NB : if the very first value is zero, the code could have a weird behavior

Related

How do I create a better resolution on my plot with linspace?

i need to create a higher resolution of my plot with the linspace function but i can't figure out how to implement it into my code. Maybe someone has a better understanding of this and can help me.
import numpy as np
import matplotlib.pyplot as plt
N = np.array([1, 2, 3, 4])
c = np.array([1359,2136.6,2617.74,2630.16])
ct = c/1000
ct0 = 103.8348/1000
cmax = 2630.16/1000
n = N.size
A = np.zeros(n)
k = np.zeros(n)
for j in range(0,n):
A[j] = (ct[j] - ct0)/(cmax - ct0)
for j in range(0, n):
if j < 3:
k[j] = -(np.log(1 - A[j])) / N[j]
else:
k[j] = 1
MWk = np.mean(k)
Amod = np.zeros(n)
for j in range(0,n):
Amod[j] = 1 - np.exp((-N[j]) * MWk)
print(ct)
print(A)
print(k)
plt.xlabel("N")
plt.ylabel("Aufschlussgrad ")
plt.plot(N, A, "g", label = "Aufschlussgrad")
plt.plot(N, Amod, "k", label = "Modelfunktion")
plt.title("Hochdruckhomogenisator")
plt.legend()
plt.show()
There is no need to interpolate Amod, since it is a function you defined. On the other hand, it is necessary to perform an interpolation (either on A or on the original data c) in order to add more points to the graph. With only 4 or 5 points, the interpolation will not be very meaningful. In this case I choose to interpolate A.
The code was not taking profit of numpy's arrays, so I pythonized it a little (it looked like C)
import numpy as np
import matplotlib.pyplot as plt
def Amod(x, MWk):
return 1 - np.exp((-x) * MWk)
def k(x, A):
rv = -np.log(1 - A) / x
rv[np.nonzero(A==1)] = 1
return rv
# No real changes here: only a little 'pythonization'
N = np.array([1, 2, 3, 4])
c = np.array([1359,2136.6,2617.74,2630.16])
ct = c/1000
ct0 = 103.8348/1000
cmax = 2630.16/1000
n = N.size
A = (ct - ct0) / (cmax-ct0)
MWk = np.mean(k(N, A))
print(ct)
print(A)
print(k)
# we now interpolate A
# numpy's interpolation is linear... it is not useful for this case
from scipy.interpolate import interp1d
# interp1d returns a function that interpolates the data we provide
# in this case, i choose quadratic interpolation
A_interp_fun = interp1d(N, A, 'quadratic')
# Let's increase the number of points
new_x = np.linspace(N[0], N[-1])
A_xtra = A_interp_fun(new_x)
plt.xlabel("N")
plt.ylabel("Aufschlussgrad ")
plt.scatter(N, A, label = "Aufschlussgrad - data")
plt.plot(new_x, A_xtra, "g", label="Aufschlussgrad - interpolation")
plt.scatter(N, Amod(N, MWk), label="Modelfunktion - data")
plt.plot(new_x, Amod(new_x, MWk), "k", label="Modelfunktion - function")
plt.title("Hochdruckhomogenisator")
plt.legend()
plt.show()

How can I change the dimension of a cube with Python?

I have made the below in order to create a cube by giving different X, Y, Z values, but when I give for example (6,3,2) I don't receive 6 blocks on X-axis, 3 blocks on Y-axis, and 2 blocks on the Z-axis, but I received a cube 6x6x4, why?
import matplotlib.pyplot as plt
import numpy as np
def make(X,Y,Z):
x, y, z = np.indices((X,Y,Z))
cube2 = (x==0) & (y==0) & (z==0)
for i in range (X):
for j in range (Y):
for k in range(Z):
cube1 = (x==i) & (y==j) & (z==k)
cube2 = cube2|cube1
colors = np.ones(cube2.shape, dtype=object)
from matplotlib import cm
for i in range (X):
for j in range (Y):
for k in range(Z):
if 0<i<=3:
colors[i][j][k] = cm.gray(((i+j+k)/X),alpha=0.8)
elif 3<i<=6:
colors[i][j][k] = cm.winter(((i+j+k)/Y),alpha=0.8)
else:
colors[i][j][k] = cm.copper(((i+j+k)/Z),alpha=0.8)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.voxels(cube2, facecolors=colors, edgecolor=None)
plt.show()
make(6,3,2,)
I also need your help with something else. I have created a bezier line according to the code.
#bezier line
import numpy as np
import matplotlib.pyplot as plt
A = np.array([10,20])
B = np.array([15,8])
C = np.array([8,22])
A = A.reshape(2,1)
B = B.reshape(2,1)
C = C.reshape(2,1)
t = np.arange(0.0, 1.0, 0.1).reshape(1,-1)
P0 = A * t + (1 - t) * B
P1 = B * t + (1 - t) * C
Pfinal = P0 * t + (1 - t) * P1
x=np.transpose(Pfinal)
x1= x[:, 0]
print(x1)
plt.plot(x1)
Is it possible to implement this to the above first code in order to choose different colors instead of what I have done in the if statement? For example, on the Z axis at the right of this bezier line to have cm.winter colors, at the left cm.copper or something similar.
Your code produces the expected plots. I don't see a problem. This is not an answer but a means of showing you the plot I get with your code. What are you looking for?
make(6,3,2)

Python - performing FFT ignore DC offset from MEMS microphone

I'm trying to perform FFT of a wav file which results well, but in my plot I see huge amplitude at 0 Hz. I assumed it is a DC offset. My purpose is to ignore this DC offset in my plot or directly in code because it prevents me from seeing actual noises. In my example I record a noise around 6.1kHz, I can clearly see it, if I zoom at that point but in general view it is not observable because of the 0Hz amplitude. If you tell me how can ignore 0Hz (or DC bias) I will be glad.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import scipy.io.wavfile as wavfile
import scipy
import scipy.fftpack
import numpy as np
from matplotlib import pyplot as plt
fs_rate, signal = wavfile.read("file.wav")
print ("Frequency sampling", fs_rate)
l_audio = len(signal.shape)
print ("Channels", l_audio)
if l_audio == 2:
signal = signal.sum(axis=1) / 2
N = signal.shape[0]
print ("Complete Samplings N", N)
secs = N / float(fs_rate)
print ("secs", secs)
Ts = 1.0/fs_rate # sampling interval in time
print ("Timestep between samples Ts", Ts)
t = scipy.arange(0, secs, Ts) # time vector as scipy arange field / numpy.ndarray
FFT = abs(scipy.fft(signal))
FFT_side = FFT[range(N/4)] # one side FFT range
freqs = scipy.fftpack.fftfreq(signal.size, t[1]-t[0])
fft_freqs = np.array(freqs)
freqs_side = freqs[range(N/4)] # one side frequency range
fft_freqs_side = np.array(freqs_side)
print (abs(FFT_side))
plt.subplot(211)
p1 = plt.plot(t, signal, "g") # plotting the signal
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.subplot(212)
p2 = plt.plot(freqs_side, abs(FFT_side), "b") # plotting the positive fft spectrum
plt.xlabel('Frequency (Hz)')
plt.ylabel('Count single-sided')
plt.show()
A large offset is often indicative of not proper preprocessing of the signal. Common approaches include demeaning the data and dedrifting the data by using linear regression. Here is an example
from matplotlib.pyplot import *
from numpy import *
dt = 1/1000
T = 1
t = arange(0, T, dt)
n = t.size
y = sin(pi * t * 3) + 39 + 3 * t + random.rand(n)
from scipy import optimize
# subtract drift
lin = lambda x, a, b : a * x + b
coeff, _ = optimize.curve_fit(lin,t, y)
dmy= y- coeff[0] * t + coeff[0]
# compute power
fy = abs(fft.fft(y))[:n//2] ** 2
fyn= abs(fft.fft(dmy - dmy.mean()))[:n//2] ** 2 # NB demeaned
freq= linspace(0, T / dt, n//2) # get freqs
fig, ax = subplots(2, sharex = 'all')
for axi, data, label in zip(ax, [fy,fyn], 'raw processed'.split()):
axi.plot(freq, data)
axi.set(xlim = (0, 10), title = label)
axi.set_xlabel('freq')
subplots_adjust(hspace = .5)

Python for loops overwriting previous iteration

I am trying to create a numpy array of periodic squares such that when I use plt.imshow I will see a black square with periodic white squares. The array needs to be used later on for Fourier analysis. The imshow reference is just for visualisation of the problem.
I can create the black array and a single white square, but the issue I'm having is that every iteration is overwriting the last until I am left with only the last white square.
Code:
import numpy as np
import matplotlib.pyplot as plt
N = 500
x_wid = 10
y_wid = 10
grid = np.arange(1,N)
X_GRID, Y_GRID = np.meshgrid(grid, grid)
square = np.zeros([N, N])
for x_pos in np.arange(0, N, N/10):
for y_pos in np.arange(0, N, N/10):
square = np.logical_and((np.abs(X_GRID-x_pos) < x_wid/2),
(np.abs(Y_GRID-y_pos) < y_wid/2))
plt.imshow(square, cmap="gray")
plt.show()
The size of the original grid needs to be N so grid = np.arange(0,N). This will then have the same size as square allowing for a simple += in the for loop to 'append' with every iteration.
Code:
import numpy as np
import matplotlib.pyplot as plt
N = 500
x_wid = 10
y_wid = 10
grid = np.arange(0,N)
X_GRID, Y_GRID = np.meshgrid(grid, grid)
square = np.zeros([N, N])
final_square = np.zeros([N, N])
for x_pos in np.arange(0, N, N/10):
for y_pos in np.arange(0, N, N/10):
square = np.logical_and((np.abs(X_GRID-x_pos) < x_wid/2),
(np.abs(Y_GRID-y_pos) < y_wid/2))
final_square += square
plt.imshow(final_square, cmap="gray")
plt.show()

efficient discrete bayes filter for localization

I'm trying to implement a discrete bayes filter (i.e. histogram filter) for robot localization as described in 'Probabilistic Robotics' by Thrun, Burgard, and Fox. The model is a robot that moves in one dimensions, so the state vector is just the position and velocity. At each time step there is a random acceleration with mean of zero and variance of one.
I think that my implementation is accurate, but it runs slowly. I'm looping over indices of my probability density map which seems very inefficient, but I don't see how to vectorize this algorithm correctly. Any suggestions?
My code:
import matplotlib.pyplot as plt
import numpy as np
from math import pi, exp, sqrt
import matplotlib.cm as cm
N = 31
numsteps = 5
# set up grid
x = np.linspace(-10, 10, N)
v = np.linspace(-10, 10, N)
sp = (x[1] - x[0])/2
X, V = np.meshgrid(x, v)
# initial probability distribution is a delta function at origin
p0 = np.zeros(X.shape)
p0[N/2, N/2] = 1
plt.ion()
plt.imshow(p0, cmap = cm.Greys_r, interpolation='none')
plt.draw()
acc_var = 1 # Variance of random acceleration
for ii in range(numsteps):
print 'Step %d'%ii
p1 = np.zeros(X.shape)
for (i, j), p in np.ndenumerate(p0): #outer loop over configuration space
for (k,l), x in np.ndenumerate(X):
# new position is old position plus velocity
if X[i,j] > X[k,l] + V[k,l] - sp and X[i,j] <= X[k,l] + V[k,l] + sp:
# Bayesian update with random acceleration
p1[i,j] = p1[i,j] + exp(-0.5 * (V[i,j] - V[k,l])**2 / acc_var) / sqrt(2*pi*acc_var) * p0[k,l]
p0 = p1
plt.imshow(p1, cmap = cm.Greys_r, interpolation='none')
plt.draw()

Categories