Related
Before I present my problem, I want to apologize for those of you that feel this is more of a math post than a programming post. Neural networks are both mathematic and programming heavy, and I felt my problem was in the programming side. I have created a CNN from scratch in c++ (that works). For this reason, I feel as though the functions I use to create a convolution and a full convolution are correct. Programmatically below, I am going to show how I do the basic forward and backward of a CNN with a convolutional layer being the forward:
Matrix<float> cnn_forward(Matrix<float> weight, Matrix<float> prev){
Matrix<float> output = prev.convolute(weight);
return output;
}
And the backward pass (I am not using a bias or activation function in this case):
cnn_back cnn_backward(Matrix<float> a_prev, Matrix<float> dz, Matrix<float> kernel){
Matrix<float> rotated = kernel.rotate_180();
Matrix<float> dx = dz.convolute_full(rotated);
Matrix<float> dw = a_prev.convolute(dz);
cnn_back output;
output.dw = std::move(dw);
output.dx = std::move(dx);
return output;
}
Everything that I have seen online says that the transposed convolutional layer is just the reverse of the convolutional layer. So, I have tried implementing the following as the forward and backward passes of a transposed convolutional layer.
//forward
Matrix<float> fcn_forward(Matrix<float> weight, Matrix<float> prev){
Matrix<float> output = prev.convolute_full(weight.rotate_180());
return output;
}
//backward
fcn_back fcn_backward(Matrix<float> a_prev, Matrix<float> dz, Matrix<float> kernel){
Matrix<float> dx = dz.convolute(kernel);
Matrix<float> dw = dz.convolute(a_prev);
fcn_back output;
output.dw = std::move(dw);
output.dx = std::move(dx);
return output;
}
//again, not using a bias or activation function
My goal is to basically implement torch.nn.ConvTranspose2d from pytorch with 2 dimensional matrices. I was hoping to parallel it to the basic convolution formula that I have above.
~EDIT~
This would be the translation into python using numpy arrays which is pretty much an exact replica of my c++ code.
def convolute(X, W, strides=(1,1)):
new_row = (int)((X.shape[0] - W.shape[0])/strides[0] +1)
new_col = (int)((X.shape[1] - W.shape[1])/strides[1] +1)
out = np.zeros((new_row, new_col), dtype=float)
x_last = 0
y_last = 0
for x in range(0, X.shape[0]-(W.shape[0] - 1), strides[0]):
for y in range(0, X.shape[1]-(W.shape[1] - 1), strides[1]):
amt = 0.0
for i in range(0, W.shape[0]):
for j in range(0, W.shape[1]):
amt += W[i][j] * X[x+i][y+j]
out[x_last][y_last] = amt
y_last += 1
x_last += 1
y_last = 0
return out
def convolute_full(X, W, strides=(1, 1)):
row_num = (X.shape[0] - 1) * strides[0] + W.shape[0]
col_num = (X.shape[1] - 1) * strides[1] + W.shape[1]
output = np.zeros([row_num, col_num])
for i in range(0, X.shape[0]):
i_prime = i * strides[0]
for j in range(0, X.shape[1]):
j_prime = j * strides[1]
for k_row in range(W.shape[0]):
for k_col in range(W.shape[1]):
output[i_prime+k_row, j_prime+k_col] += W[k_row, k_col] * X[i, j]
return output
def get_errors(predicted, label):
return label - predicted
def fcn_forward(weight, prev):
rotated = np.rot90(np.rot90(weight))
output = convolute_full(prev, rotated)
return output
def fcn_backward(a_prev, dz, kernel):
dx = convolute(dz, kernel)
dw = convolute(dz, a_prev)
dx = np.clip(dx, 10, -10)
return dx, dw
def forward(weights, X_init):
values = []
values.append(X_init)
predicted = fcn_forward(weights[0], X_init)
values.append(predicted)
predicted = fcn_forward(weights[1], predicted)
values.append(predicted)
return values
def backward(weights, values, label, learningRate=0.001):
dz = get_errors(values[-1], label)
dx, dw = fcn_backward(values[-2], dz, weights[-1])
weights[-1] = weights[-1] - learningRate*dw
dz = dx
dx, dw = fcn_backward(values[-3], dz, weights[-2])
weights[-2] = weights[-2] - learningRate*dw
return weights
def train_example():
epoch = int(input("enter epoch: "))
#creating a random input
inp = np.random.randn(10,10)
#creating the weight matricies
weights = [np.random.randn(3,3), np.random.randn(3,3)]
#creating the wanted output
label = np.random.randn(14,14)
for i in range(0, epoch):
values = forward(weights, inp)
if(i == 0 or i == 1):
errors = get_errors(values[-1], label)
print("errors:")
print(errors)
print("error sum: ", np.sum(errors))
weights = backward(weights, values, label)
print("current prediction:")
print(values[-1])
print("label: ")
print(label)
errors = get_errors(values[-1], label)
print("errors:")
print(errors)
print("error sum at end of training: ", np.sum(errors))
Basically, this does not work. The weights are not corrected in the correct way. The errors only continue to get larger (the opposite of the wanted result). What is the correct way to forward and backward propagate a transposed convolutional layer?
EDIT
This is the answer for anyone wondering how it relates to my code above, due to #Bob's answer:
def convolute(X, W, strides=(1,1)):
new_row = (int)((X.shape[0] - W.shape[0])/strides[0] +1)
new_col = (int)((X.shape[1] - W.shape[1])/strides[1] +1)
out = np.zeros((new_row, new_col), dtype=float)
x_last = 0
y_last = 0
for x in range(0, X.shape[0]-(W.shape[0] - 1), strides[0]):
for y in range(0, X.shape[1]-(W.shape[1] - 1), strides[1]):
amt = 0.0
for i in range(0, W.shape[0]):
for j in range(0, W.shape[1]):
amt += W[i][j] * X[x+i][y+j]
out[x_last][y_last] = amt
y_last += 1
x_last += 1
y_last = 0
return out
#this is the same result as scipy.signal.convolute2d
def convolute_full(X, W, strides=(1, 1)):
row_num = (X.shape[0] - 1) * strides[0] + W.shape[0]
col_num = (X.shape[1] - 1) * strides[1] + W.shape[1]
output = np.zeros([row_num, col_num])
for i in range(0, X.shape[0]):
i_prime = i * strides[0]
for j in range(0, X.shape[1]):
j_prime = j * strides[1]
for k_row in range(W.shape[0]):
for k_col in range(W.shape[1]):
output[i_prime+k_row, j_prime+k_col] += W[k_row, k_col] * X[i, j]
return output
def convolute_full_backward(X, dZ, dW, strides=(1, 1)):
for i in range(0, X.shape[0]):
i_prime = i * strides[0]
for j in range(0, X.shape[1]):
j_prime = j * strides[1]
for k_row in range(dW.shape[0]):
for k_col in range(dW.shape[1]):
dW[k_row, k_col] += dZ[i_prime+k_row, j_prime+k_col] * X[i, j]
return dW
def get_errors(predicted, label):
return label - predicted
def fcn_forward(W, X):
rotated = np.rot90(np.rot90(W))
output = convolute_full(X, rotated)
return output
def fcn_backward(X, dZ, kernel):
dw = np.zeros(kernel.shape)
dw = convolute_full_backward(X, dZ, dw)
dw = np.rot90(np.rot90(dw))
dx = convolute(dZ, np.rot90(np.rot90(kernel)))
np.clip(dx, 10, -10)
return dx, dw
def forward(weights, X):
values = []
values.append(X)
predicted = fcn_forward(weights[0], X)
values.append(predicted)
predicted = fcn_forward(weights[1], predicted)
values.append(predicted)
return values
def backward(weights, values, label, learningRate=0.001):
dz = get_errors(values[-1], label)
dx, dw = fcn_backward(values[-2], dz, weights[-1])
weights[-1] = weights[-1] + learningRate*dw
dz = dx
dx, dw = fcn_backward(values[-3], dz, weights[-2])
#new apply dw:
weights[-2] = weights[-2] + learningRate*dw
return weights
def train_example():
epoch = int(input("please enter epoch: "))
inp = np.random.randn(10,10)
weights = [np.random.randn(3,3), np.random.randn(3,3)]
label = np.random.randn(14,14)
for i in range(0, epoch):
values = forward(weights, inp)
errors = get_errors(values[-1], label)
print("error sum at {} is: {}".format(i, np.sum(errors)))
weights = backward(weights, values, label)
errors = get_errors(values[-1], label)
print("error sum at end of training: ", np.sum(errors))
since your implementation has every scalar multiplication performed explicitly, the backward step can be done very clear. You keep all the loops unchanged, and when you see an update to your accumulator you compute the gradient for that.
import numpy as np
def convolute_full(X, W, strides=(1, 1)):
row_num = (X.shape[0] - 1) * strides[0] + W.shape[0]
col_num = (X.shape[1] - 1) * strides[1] + W.shape[1]
output = np.zeros([row_num, col_num])
for i in range(0, X.shape[0]):
i_prime = i * strides[0]
for j in range(0, X.shape[1]):
j_prime = j * strides[1]
for k_row in range(W.shape[0]):
for k_col in range(W.shape[1]):
output[i_prime+k_row, j_prime+k_col] += W[k_row, k_col] * X[i, j]
return output
def convolute_full_backward(X, dZ, dW, strides=(1, 1)):
row_num = (X.shape[0] - 1) * strides[0] + W.shape[0]
col_num = (X.shape[1] - 1) * strides[1] + W.shape[1]
output = np.zeros([row_num, col_num])
for i in range(0, X.shape[0]):
i_prime = i * strides[0]
for j in range(0, X.shape[1]):
j_prime = j * strides[1]
for k_row in range(W.shape[0]):
for k_col in range(W.shape[1]):
# Only this line changed compard to forward pass
dW[k_row, k_col] += dZ[i_prime+k_row, j_prime+k_col] * X[i, j]
def fcn_forward(X, W):
output = convolute_full(X, W[::-1,::-1])
return output
def fcn_backward(X, dZ, kernel_shape):
dW = np.zeros(kernel_shape)
convolute_full_backward(X, dZ, dW[::-1,::-1])
return dW
To validate I created a simple example with a linear loss function
X = np.random.randn(20, 20)
W = np.random.randn(5, 5)
Z = fcn_forward(X, W)
# pick a random loss with known gradient
dZ = np.random.randn(*Z.shape)
F = np.sum(Z * dZ)
dW = fcn_backward(X, dZ, W.shape)
# random perturbation
W_ = W + np.random.randn(*W.shape)
# expected change to the loss function
dF = np.sum(dW * (W_ - W))
Z_ = fcn_forward(X, W_)
F_ = np.sum(Z_ * dZ)
print('Predicted loss change: %f' % dF)
print('Actual loss change: %f' % (F_ - F))
Run and see.
I'm high school student, and I'm writing a report about profile velocity.
I don't know much about differential equations and Python, but I have to use both of them.
I'm trying to induce the velocity from (ma = mg - kv), and caculate a and s from v.
I caculated v successfully, but I have few questions.
import sympy
init_printing()
%matplotlib inline
(m, g, k, t) = symbols('m g k t')
v = Function('v')
deq = Eq( m*v(t).diff(t), m*g - k*v(t) )
eq = dsolve( deq, v(t) )
C1 = Symbol('C1')
C1_ic = solve( eq.rhs.subs( {t:0}), C1)[0]
r = expand(eq.subs({C1:C1_ic}))
the simple way to caculate C1 doesn't work
v(0) = 0
so I write
eq = dsolve( deq, ics={v(0):0})
but it has same result with
eq = dsolve( deq, v(t) )
how to caculate acc and draw a graph?
I try this code, but it doesn't work
a = diff(r, t)
r = dsolve( a, v(t))
r.subs({m:1, g:9.8, k:1})
plot( r , (t,0,100))
I don't get the same result from eq = dsolve( deq, ics={v(0):0}). Also you should declare m, g and k with positive=True.
In [50]: m, g, k = symbols('m g k', positive=True)
In [51]: t = Symbol('t')
In [52]: v = Function('v')
In [53]: deq = Eq( m*v(t).diff(t), m*g - k*v(t) )
In [54]: deq
Out[54]:
d
m⋅──(v(t)) = g⋅m - k⋅v(t)
dt
In [55]: dsolve(deq, v(t))
Out[55]:
k⋅(C₁ - t)
──────────
m
g⋅m + ℯ
v(t) = ─────────────────
k
In [56]: dsolve(deq, v(t), ics={v(0):0})
Out[56]:
⎛ m⋅log(g) m⋅log(m) ⅈ⋅π⋅m⎞
k⋅⎜-t + ──────── + ──────── + ─────⎟
⎝ k k k ⎠
────────────────────────────────────
m
g⋅m + ℯ
v(t) = ───────────────────────────────────────────
k
In [57]: sol = dsolve(deq, v(t), ics={v(0):0}).rhs
In [58]: sol.expand()
Out[58]:
-k⋅t
─────
m
g⋅m g⋅m⋅ℯ
─── - ──────────
k k
In [59]: factor_terms(sol.expand())
Out[59]:
⎛ -k⋅t ⎞
⎜ ─────⎟
⎜ m ⎟
g⋅m⋅⎝1 - ℯ ⎠
────────────────
k
You can compute and plot the acceleration like
In [62]: sol = factor_terms(sol.expand())
In [64]: a = sol.diff(t)
In [65]: a = sol.diff(t).subs({m:1, g:9.8, k:1})
In [66]: a
Out[66]:
-t
9.8⋅ℯ
In [67]: plot(a, (t, 0, 100))
I use odeint function to solve a coupled differential equations system and plot one of the variables (theta_i) after the system is solved. My variable (theta_i) comes from the equation:
theta_i = np.arctan2(g1,g2)
where g1 ang g2 are variables calculated in the same function. The results have to be between -pi and pi and they are supposed to look like this (plot from matlab simulation):
However, when I try to plot theta_i after odeint has finished I get this(plot from my python code):
which is really weird. When I print the values of theta_i right after its calcumation (still inside the function) they look correct (between -0.2 and 0.5), so it has to be something with the result's storing and my implementation of odeint. All the other variables that come from the odeint solution are correct. I searched similar posts but nobody had the same problem with me. What might be the problem here? I am new to python and I use python 2.7.12. Thank you in advance.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
added_mass_x = 0.03 # kg
added_mass_y = 0.04
mb = 0.3 # kg
m1 = mb-added_mass_x
m2 = mb-added_mass_y
l1 = 0.07 # m
l2 = 0.05 # m
J = 0.00050797 # kgm^2
Sa = 0.0110 # m^2
Cd = 2.44
Cl = 3.41
Kd = 0.000655 # kgm^2
r = 1000 # kg/m^3
c1 = 0.5*r*Sa*Cd
c2 = 0.5*r*Sa*Cl
c3 = 0.5*mb*(l1**2)
c4 = Kd/J
c5 = (1/(2*J))*(l1**2)*mb*l2
c6 = (1/(3*J))*(l1**3)*mb
theta_0 = 10*(np.pi/180) # rad
theta_A = 20*(np.pi/180) # rad
f = 2 # Hz
t = np.linspace(0,100,8000) # s
def direct(u,t):
vcx = u[0]
vcy = u[1]
wz = u[2]
psi = u[3]
x = u[4]
y = u[5]
vcx_i = u[6]
vcy_i = u[7]
psi_i = u[8]
wz_i = u[9]
theta_i = u[10]
theta_deg_i = u[11]
# Subsystem 1
omega = 2*np.pi*f # rad/s
theta = theta_0 + theta_A*np.sin(omega*t) # rad
theta_deg = (theta*180)/np.pi # deg
thetadotdot = -(omega**2)*theta_A*np.sin(omega*t) # rad/s^2
# Subsystem 2
vcxdot = (m2/m1)*vcy*wz-(c1/m1)*vcx*np.sqrt((vcx**2)+(vcy**2))+(c2/m1)*vcy*np.sqrt((vcx**2)+(vcy**2))*np.arctan2(vcy,vcx)-(c3/m1)*thetadotdot*np.sin(theta)
vcydot = -(m1/m2)*vcx*wz-(c1/m2)*vcy*np.sqrt((vcx**2)+(vcy**2))-(c2/m2)*vcx*np.sqrt((vcx**2)+(vcy**2))*np.arctan2(vcy,vcx)+(c3/m2)*thetadotdot*np.cos(theta)
wzdot = ((m1-m2)/J)*vcx*vcy-c4*wz*wz*np.sign(wz)-c5*thetadotdot*np.cos(theta)-c6*thetadotdot
psidot = wz
# Subsystem 3
xdotdot = vcxdot*np.cos(psi)-vcx*np.sin(psi)*wz+vcydot*np.sin(psi)+vcy*np.cos(psi)*wz # m/s^2
ydotdot = -vcxdot*np.sin(psi)-vcx*np.cos(psi)*wz+vcydot*np.cos(psi)-vcy*np.sin(psi)*wz # m/s^2
xdot = vcx*np.cos(psi)+vcy*np.sin(psi) # m/s
ydot = -vcx*np.sin(psi)+vcy*np.cos(psi) # m/s
# Subsystem 4
vcx_i = xdot*np.cos(psi_i)-ydot*np.sin(psi_i)
vcy_i = ydot*np.cos(psi_i)+xdot*np.sin(psi_i)
psidot_i = wz_i
vcxdot_i = xdotdot*np.cos(psi_i)-xdot*np.sin(psi_i)*psidot_i-ydotdot*np.sin(psi_i)-ydot*np.cos(psi_i)*psidot_i
vcydot_i = ydotdot*np.cos(psi_i)-ydot*np.sin(psi_i)*psidot_i+xdotdot*np.sin(psi_i)+xdot*np.cos(psi_i)*psidot_i
g1 = -(m1/c3)*vcxdot_i+(m2/c3)*vcy_i*wz_i-(c1/c3)*vcx_i*np.sqrt((vcx_i**2)+(vcy_i**2))+(c2/c3)*vcy_i*np.sqrt((vcx_i**2)+(vcy_i**2))*np.arctan2(vcy_i,vcx_i)
g2 = (m2/c3)*vcydot_i+(m1/c3)*vcx_i*wz_i+(c1/c3)*vcy_i*np.sqrt((vcx_i**2)+(vcy_i**2))+(c2/c3)*vcx_i*np.sqrt((vcx_i**2)+(vcy_i**2))*np.arctan2(vcy_i,vcx_i)
A = 12*np.sin(2*np.pi*f*t+np.pi) # eksiswsi tail_frequency apo simulink
if A>=0.1:
wzdot_i = ((m1-m2)/J)*vcx_i*vcy_i-c4*wz_i**2*np.sign(wz_i)-c5*g2-c6*np.sqrt((g1**2)+(g2**2))
elif A<-0.1:
wzdot_i = ((m1-m2)/J)*vcx_i*vcy_i-c4*wz_i**2*np.sign(wz_i)-c5*g2+c6*np.sqrt((g1**2)+(g2**2))
else:
wzdot_i = ((m1-m2)/J)*vcx_i*vcy_i-c4*wz_i**2*np.sign(wz)-c5*g2
if g2>0:
theta_i = np.arctan2(g1,g2)
elif g2<0 and g1>=0:
theta_i = np.arctan2(g1,g2)-np.pi
elif g2<0 and g1<0:
theta_i = np.arctan2(g1,g2)+np.pi
elif g2==0 and g1>0:
theta_i = -np.pi/2
elif g2==0 and g1<0:
theta_i = np.pi/2
elif g1==0 and g2==0:
theta_i = 0
theta_deg_i = (theta_i*180)/np.pi
#print theta_deg_i
return [vcxdot, vcydot, wzdot, psidot, xdot, ydot, vcxdot_i, vcydot_i, psidot_i, wzdot_i, theta_i, theta_deg_i]
# arxikes synthikes
vcx_0 = 0.1257
vcy_0 = 0
wz_0 = 0
psi_0 = 0
x_0 = 0
y_0 = 0
vcx_i_0 = 0.1257
vcy_i_0 = 0
psi_i_0 = 0
wz_i_0 = 0
theta_i_0 = 0.1745
theta_deg_i_0 = 9.866
u0 = [vcx_0, vcy_0, wz_0, psi_0, x_0, y_0, vcx_i_0, vcy_i_0, psi_i_0, wz_i_0, theta_i_0, theta_deg_i_0]
u = odeint(direct, u0, t, tfirst=False)
vcx = u[:,0]
vcy = u[:,1]
wz = u[:,2]
psi = u[:,3]
x = u[:,4]
y = u[:,5]
vcx_i = u[:,6]
vcy_i = u[:,7]
psi_i = u[:,8]
wz_i = u[:,9]
theta_i = u[:,10]
theta_deg_i = u[:,11]
print theta_i
plt.figure(17)
plt.plot(t,theta_i,'r-',linewidth=1,label='theta_i')
plt.xlabel('t [s]')
plt.title('theta_i [rad] (Main body CF)')
plt.legend()
plt.show()
The problem as you stated is that theta_i is not part of the gradient. When you formulate your direct, it should be of the form:
def direct(vector, t):
return vector_dot
The quickest and dirtiest solution (without cleaning the code) is to use the function you already defined:
theta_i = [direct(u_i, t_i)[10] for t_i, u_i in zip(t, u)]
I used a a shorter interval: t = np.linspace(0,10,8000). It yielded this:
EDIT: How to remove your theta from the integrator:
def direct(u, t):
# your original function as it is
def direct2(u,t):
return direct(u,t)[:9]
#now integrate the second function
u = odeint(direct2, u0, t)
Part of my assignment is to implement the Gradient Descent to find the best approximation of values c_1, c_2 and r_1 for the function
.
Given is only a list of 30 y-values corresponding to x from 0 to 30. I am implementing this in Enthought Canopy like this:
First I start with random values:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as pyplt
c1 = -0.1
c2 = 0.1
r1 = 0.1
x = np.linspace(0,29,30) #start,stop,numitems
y = c1*np.exp(r1*x) + (c1*x)**3.0 - (c2*x)**2.0
pyplt.plot(x,y)
values_x = np.linspace(0,29,30)
values_y = np.array([0.2, -0.142682939241718, -0.886680607211679, -2.0095087143494, -3.47583798747496, -5.24396052331554, -7.2690008846359, -9.50451068338581, -11.9032604272567, -14.4176327390446, -16.9998176236069, -19.6019094345634, -22.1759550265352, -24.6739776668383, -27.0479889096801, -29.2499944927101, -31.2319972651608, -32.945998641919, -34.3439993255969, -35.3779996651013, -35.9999998336943, -36.161999917415, -35.8159999589895, -34.9139999796348, -33.4079999898869, -31.249999994978, -28.3919999975061, -24.7859999987616, -20.383999999385, -15.1379999996945])
pyplt.plot(values_x,values_y)
The squared error is quite high:
def Error(y,y0):
return ( (1.0)*sum((y-y0)**2.0) )
print Error(y,values_y)
Now, to implement the gradient descent, I derived the partial derivative functions for c_1, c_2 and r_1 and implemented the Gradient Descent:
step_size = 0.0000005
accepted_Error = 50
dc1 = c1
dc2 = c2
dr1 = r1
y0 = values_y
previous_Error = 100000
left = True
for _ in range(1000):
gc1 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( -1*np.exp(dr1*x) - (3*(dc1**2)*(x**3)) ) )
gc2 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( 2*dc2*(x**2) ) )
gr1 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( -1*dc1*x*np.exp(dr1*x) ) )
dc1 = dc1 - step_size*gc1
dc2 = dc2 - step_size*gc2
dr1 = dr1 - step_size*gr1
y1 = dc1*np.exp(dr1*x) + (dc1*x)**3.0 - (dc2*x)**2.0
current_Error = Error(y0,y1)
if (current_Error > accepted_Error):
print currentError
else:
break
if (current_Error > previous_Error):
print currentError
print "DIVERGING"
break
if (current_Error==previous_Error):
print "CAN'T IMPROVE"
break
previous_Error = current_Error
However, the error is not improving at all, and I tried to vary the step size. Is there a mistake in my code?
I am trying to update my function arguments after each iteration but failed to do so. Kindly check my code because I am new to python language. My task is to calculate xps, (represents collection of positions) and v2ps, (represents collection of velocities) after each iteration and want to plot them against each other. Basic this program represents the collision of objects moving vertical down and one of object also collide with plane above which they are moving.
acc_grav = 10
m1 =float(input(" Input mass of ball one, m1: "))
m2 =float(input(" Input mass of ball two, m2: "))
time_steps =10000
num_coll_bounce = 0
num_ball_coll = 0
eps=1.e-6
def ball_coll(x1_old,v1_old,x2_old,v2_old,time_ball_coll):
v1 = v1_old - acc_grav*time_ball_coll
v2 = v2_old - acc_grav*time_ball_coll
x1 = x1_old + time_ball_coll*v1_old - 0.5*acc_grav*(time_ball_coll)**2
x2 = x2_old + time_ball_coll*v2_old - 0.5*acc_grav*(time_ball_coll)**2
v1_ball_coll = (v1*(m1-m2)+(2*m2*v2))/(m1+m2)
v2_ball_coll = (v2*(m2-m1)+(2*m1*v1))/(m1+m2)
cumlv2=v2
return [v1,v2,x1,x2,v1_ball_coll,v2_ball_coll]
def floor_coll(x1_old,v1_old,x2_old,v2_old,time_floor_coll):
v1 = v1_old - acc_grav*time_floor_coll
v2 = v2_old - acc_grav*time_floor_coll
x1 = 0 #at the time of bonuce
x2 = x2_old + time_floor_coll*v2_old - 0.5*acc_grav*time_floor_coll**2
#update velocities following rules for collision with walls
v1_bounce = -v1
v2_bounce = v2
return [v1,v2,x1,x2,v1_bounce,v2_bounce]
for i in range(0, 10):
x1_0 = 1
x2_0 = 3 - (i-1)*0.1
v1_0 = 2
v2_0 = 2*v1_0
xps = []
v2ps = []
for n in range (time_steps-1):
time_ball_coll = (x2_0-x1_0)/(v1_0 - v2_0)
time_floor_coll = (v1_0 + (v1_0**2 + 2*acc_grav*x1_0)**1/2)/acc_grav
if ((time_ball_coll - time_floor_coll)<eps and v1_0 - v2_0 > 0):
num_coll_bounce = num_coll_bounce + 1
num_ball_coll = num_ball_coll + 1
ball_coll(x1_0,v1_0,x2_0,v2_0,time_ball_coll)
#xps[n] = x2_0
#v2ps(n,num_ballcoll) = v2ini
xps.append(x2_0)
v2ps.append(v2_0)
else:
num_coll_bounce = num_coll_bounce + 1
floor_coll(x1_0,v1_0,x2_0,v2_0,time_floor_coll)
#x1_old,v1_old,x2_old,v2_old,time_floor_coll = dd2
x_1.append(x1_0)
x_2.append(x2_0)