adding somehow reverb to a 2D array with python - python

I got a simple 2D array of values like this :
[simple array]
and I want to add reverb to it (I don't know how to call it other way) in order for it to look like this, basicly with a damping/smooth effect on y values but only on +x :
[with reverb]
I tried to check with scipy as i'm already using it to smooth values but didn't found out how to do it.
does anybody has an idea ?

You could try a Finite impulse response filter, though it's not clear if it's exactly what you need.
This was produced by the script below.
I've assumed, given your figures, that your data is actually 1-dimensional (a "line" of numbers, not a "rectangle").
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
npts = 50
# FIR with falling sawtooth impulse response
b = np.linspace(1,0,npts,endpoint=False)
u = np.zeros(3 * npts)
u[0] = 1
u[npts + 10] = 1
u[npts + 10 + npts//2] = 1
y = signal.lfilter(b, [1], u)
fig, ax = plt.subplots(2)
ax[0].stem(u)
ax[0].set_ylabel('input')
ax[1].stem(y)
ax[1].set_ylabel('output')
plt.show()

Related

Convolution of two arrays using scipy

I have two Numpy (complex) arrays A[t],B[t] defined over a grid of points "t". These two arrays are convolved in a way such that I want a third array C[y] = (A*B)(y), where "y" needs to be exactly the same points as the "t" grid. The point is that both A and B need to be integrated from -\infty to \infty according to the standard convolution operation.
Im using scipy.signal.convolve for this, and I would also like to use the fftconvolve since my arrays are supposed to be big enough. However, when I try the module on a minimal working code, I seem to be doing things very wrong. Here is a piece of the code, where I choose A(t) = exp( -t**2 ) and B(t) = exp(-t). The convolution of these two functions in Mathematica gives:
C[y] = \integral_{-\infty}^{\infty} dt A[t]B[ y- t ] = sqrt(pi)*exp( 0.25 - y )
But then I try this in Python and get very wrong results:
import scipy.signal as scp
import numpy as np
import matplotlib.pyplot as plt
delta = 0.001
t = np.arange(1000)*delta
a = np.exp( -t**2 )
b = np.exp( -t )
c = scp.convolve(a, b, mode='same')*delta
d = np.sqrt(np.pi)*np.exp( 0.25 - t )
plt.plot(np.arange(len(c)) * delta, c)
plt.plot(t[::50], d[::50], 'o')
As far as I understood, the "same" mode allows for evaluation over the same points of the original grids, but this doesn't seem to be the case... Any help is greatly appreciated!

Plancks Law, Frequency figures

I want to plot the frequency version of planck's law. I first tried to do this independently:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
%matplotlib inline
# Planck's Law
# Constants
h = 6.62607015*(10**-34) # J*s
c = 299792458 # m * s
k = 1.38064852*(10**-23) # J/K
T = 20 # K
frequency_range = np.linspace(10**-19,10**19,1000000)
def plancks_law(nu):
a = (2*h*nu**3) / (c**2)
e_term = np.exp(h*nu/(k*T))
brightness = a /(e_term - 1)
return brightness
plt.plot(frequency_range,plancks_law(frequency_range))
plt.gca().set_xlim([1*10**-16 ,1*10**16 ])
plt.gca().invert_xaxis()
This did not work, I have an issue with scaling somehow. My next idea was to attempt to use this person's code from this question: Plancks Formula for Blackbody spectrum
import matplotlib.pyplot as plt
import numpy as np
h = 6.626e-34
c = 3.0e+8
k = 1.38e-23
def planck_f(freq, T):
a = 2.0*h*(freq**3)
b = h*freq/(k*T)
intensity = a/( (c**2 * (np.exp(b) - 1.0) ))
return intensity
# generate x-axis in increments from 1nm to 3 micrometer in 1 nm increments
# starting at 1 nm to avoid wav = 0, which would result in division by zero.
wavelengths = np.arange(1e-9, 3e-6, 1e-9)
frequencies = np.arange(3e14, 3e17, 1e14, dtype=np.float64)
intensity4000 = planck_f(frequencies, 4000.)
plt.gca().invert_xaxis()
This didn't work, because I got a divide by zero error. Except that I don't see where there is a division by zero, the denominator shouldn't ever be zero since the exponential term shouldn't ever be equal to one. I chose the frequencies to be the conversions of the wavelength values from the example code.
Can anyone help fix the problem or explain how I can get planck's law for frequency instead of wavelength?
You can not safely handle such large numbers; even for comparably "small" values of b = h*freq/(k*T) your float64 will overflow, e.g np.exp(709.)=8.218407461554972e+307 is ok, but np.exp(710.)=inf. You'll have to adjust your units (exponents) accordingly to avoid this!
Note that this is also the case in the other question you linked to, if you insert print( np.exp(b)[:10] ) within the definition of planck(), you can examine the first ten evaluated b's and you'll see the overflow in the first few occurrences. In any case, simply use the answer posted within the other question, but convert the x-axis in plt.plot(wavelengths, intensity) to frequency (i hope you know how to get from one to the other) :-)

Using FFT for 3D array representation of 2D field

I need to obtain the fourier transform of a complex field. I'm using python.
My input is a 2D snapshot of the electric field in the xy-plane.
I currently have a 3D array F[x][y][z] where F[x][y][0] contains the real component and F[x][y]1 contains the complex component of the field.
My current code is very simple and does this:
result=np.fft.fftn(F)
result=np.fft.fftshift(result)
I have the following questions:
1) Does this correctly compute the fourier transform of the field, or should the field be entered as a 2D matrix with each element containing both the real and imaginary component instead?
2) I entered the complex component values of the field using the real multiple only (i.e if the complex value is 6i I entered 6), is this correct or should this be entered as a complex value instead (i.e. entered as '6j')?
3) As this is technically a 2D input field, should I use np.fft.fft2 instead? Doing this means the output is not centered in the middle.
4) The output does not look like what I'd expect the fourier transform of F to look like, and I'm unsure what I'm doing wrong.
Full example code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
x, y = np.meshgrid(np.linspace(-1,1,100), np.linspace(-1,1,100))
d = np.sqrt(x*x+y*y)
sigma, mu = .35, 0.0
g1 = np.exp(-( (d-mu)**2 / ( 2.0 * sigma**2 ) ) )
F=np.empty(shape=(300,300,2),dtype=complex)
for x in range(0,300):
for y in range(0,300):
if y<50 or x<100 or y>249 or x>199:
F[x][y][0]=g1[0][0]
F[x][y][1]=0j
elif y<150:
F[x][y][0]=g1[x-100][y-50]
F[x][y][1]=0j
else:
F[x][y][0]=g1[x-100][y-150]
F[x][y][1]=0j
F_2D=np.empty(shape=(300,300))
for x in range(0,300):
for y in range(0,300):
F_2D[x][y]=np.absolute(F[x][y][0])+np.absolute(F[x][y][1])
plt.imshow(F_2D)
plt.show()
result=np.fft.fftn(F)
result=np.fft.fftshift(result)
result_2D=np.empty(shape=(300,300))
for x in range(0,300):
for y in range(0,300):
result_2D[x][y]=np.absolute(result[x][y][0])+np.absolute(result[x][y][1])
plt.imshow(result_2D)
plt.show()
plotting F gives this:
With np.fft.fftn, the image shown at the end is:
And with np.fft.fft2:
Neither of these look like what I would expect the fourier transform of F to look like.
I add here another answer, suitable to the added code.
The answer is still np.fft.fft2(). Here's an example. I modified the code slightly. To verify that we need fft2 I discarded one of the blobs, and then we know that a single Gaussian blob should transform into a Gaussian blob (with a certain phase, that's not shown when plotting absolute value). I also decreased the standard deviation so that the frequency response will widen a little.
Code:
import numpy as np
import matplotlib.pyplot as plt
x, y = np.meshgrid(np.linspace(-1,1,100), np.linspace(-1,1,100))
d = np.sqrt(x**2+y**2)
sigma, mu = .1, 0.0
g1 = np.exp(-( (d-mu)**2 / ( 2.0 * sigma**2 ) ) )
N = 300
positions = [ [150,100] ]#, [150,200] ]
sz2 = [int(x/2) for x in g1.shape]
F_2D = np.zeros([N,N])
for x0,y0 in positions:
F_2D[ x0-sz2[0]: x0+sz2[0], y0-sz2[1]:y0+sz2[1] ] = g1 + 1j*0.
result = np.fft.fftshift(np.fft.fft2(F_2D))
plt.subplot(211); plt.imshow(F_2D)
plt.subplot(212); plt.imshow(np.absolute(result))
plt.title('$\sigma$=.1')
plt.show()
Result:
To get back to the original problem, we need only change
positions = [ [150,100] , [150,200] ]
and sigma=.35 instead of sigma=.1.
You should use complex numpy variables (by using 1j) and use fft2. For example:
N = 16
x0 = np.random.randn(N,N,2)
x = x0[:,:,0] + 1j*x0[:,:,1]
X = np.fft.fft2(x)
Using fftn on x0 will do a 3D FFT, and using fft will do vector-wise 1D FFT.

Bifurcation diagram

I want to draw a Bifurcation diagram of quadratic map in python.
Basically its a plot of x_{n+1}=x_n^2-c and it should look like http://static.sewanee.edu/Physics/PHYSICS123/image99.gif
But I am newbie so I am not sure do I make it right.
My code
import numpy as n
import scipy as s
import pylab as p
xa=0.252
xb=1.99
C=n.linspace(xa,0.001,xb)
iter=100
Y=n.zeros((len(X),iteracje))
i=1
Y0=1
for Y0 in iter:
Y(i+1)=Y0^2-C
for Y0 in iter:
Y(i+1)=Y0^2-C
p.plot(C,Y)
p.show()
My problem is that I don't know how properly write these for loop properly.
Here is some modified code (partial explanation below)
import numpy as n
import scipy as s
import pylab as p
xa=0.252
xb=1.99
C=n.linspace(xa,xb,100)
print C
iter=1000
Y = n.ones(len(C))
for x in xrange(iter):
Y = Y**2 - C #get rid of early transients
for x in xrange(iter):
Y = Y**2 - C
p.plot(C,Y, '.', color = 'k', markersize = 2)
p.show()
First, the linspace command had the wrong format. help(s.linspace) will give you insight into the syntax. The first two arguments are start and stop. The third is how many values. I then made Y a numpy array of the same length as C, but whose values were all 1. Your Y0 was simply the number 1, and it never changed. Then I did some iteration to get past the initial conditions. Then did more iteration plotting each value.
To really understand what I've done, you'll have to look at how numpy handles calculations with arrays.

Integrated for loop to calculate values over a grid/mesh

I am fairly new to python, and I am trying to plot a contour plot of water surface over a 2d mesh.
At the moment the code is running but I am not getting the right solution. I have checked the formula carefully and I am fairly confident that the issue is with my loops.
I want the code to run for each point on my mesh based on their x and y coordinates.
The mesh is 100 x 100 resulting in 10000 nodes. I have posted my code below, I believe the problem is with the integrated for loops. Any advice on what I might be able to try would be great.
Apologies for the length of code...
import numpy as np
import matplotlib.pyplot as plt
import math
import sys
from math import sqrt
import decimal
t=0
n=5
l=100000
d=100
g=9.81
nx, ny = (100,100)
x5 = np.linspace(-100000,100000,nx)
y5 = np.linspace(-100000,100000,ny)
xv,yv = np.meshgrid(x5,y5)
x = np.arange(-100000,100000,2000)
y = np.arange(-100000,100000,2000)
c=np.arange(len(x))
x2=np.arange(len(x))
y2=np.arange(len(x))
t59=np.arange (1,10001,1)
h=np.arange(len(t59))
om2=1.458*(10**-4.0)
phi=52
phirad=phi*(math.pi/180)
f=om2*math.sin(phirad)
A=(((d+n)**2.0)-(d**2.0))/(((d+n)**2.0)+(d**2.0))
w=(((8*g*d)/(l**2))+(f**2))**0.5
a=((1-(A**2.0))**0.5)/(1-(A*math.cos(w*t)))
b=(((1-(A**2.0))/(1-(A*math.cos(w*t)))**2.0)-1)
l2=l**2.0
for i in range (len(x)):
for j in range (len(y)):
h[i]=d*(a-1-((((x[i]**2.0)+(y[j]**2.0))/l2)*b))
h5=np.reshape(h,(100,100))
plt.figure(1)
plt.contourf(x5,y5,h5)
plt.colorbar()
plt.show()
Ok apologies I didn't make myself very clear. So I'm hoping to achieve a parabolic basin output with h values varying between roughly -10 and 10. Instead I am getting enormous values and the completely wrong shape. I thought the for loop needed to be more like:
for i in range (len(x)):
for j in range (len(y)):
h[i][j]=d*(a-1-((((x[i][j]**2.0)+(y[i][j]**2.0))/l2)*b))
Is that clearer? Let me know if not.
The first thing is that the complete loop is not necessary.
h = d * (a - 1 - (x[None,:]**2 + y[:,None]**2) / 12 * b)
Here the magic comes with the None in indexing. x[None, :] means "x as a row vector copied to as many rows as needed and y[:, None] means "y as a column vector copied to as many columns as needed`.
This might be easiest to understand with an example:
import numpy as np
x = np.arange(5)
y = np.arange(0,50,10)
print x, y, x[None,:] + y[:, None]
The one-liner above gives:
Some manual calculations show this should be rather ok.
d = 100
a = 1.05
b = 0.1025
For a corner point at (1e5, 1e5), we have 2e10 in the addition, so the values do not look badly off.

Categories