I wrote code for Runge-Kutta 4 for solving system of 3 ODEs
I think that it does not work fine for because I solved the system with Euler's method and I had have the following results
But with the RK4's code attached I get a very different result:
import matplotlib.pyplot as plt
umax = 0.53
Km = 0.12
Yxs = 0.4
S1f = 4
Yxp = 0.4
D=0.5 #
X1f=0.2
P1f=0.1
# Equations:
#du/dt=V(u,t)
def V(u,t):
X1, S1, P1, vx, vs, vp = u
return np.array([ vx,vs,vp,
D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1,
D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs,
D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp ])
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = (t[1]-t[0])/n
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3 ) + k4) / 6
return u, t
u, t = rk4(V, np.array([0., 0., 0. , 0., 1. , 0.]) , 0. , 40. , 4000)
x,y,z, vx,vs,vp = u.T
# plt.plot(t, x, t,y)
plt.plot(t, x, t,y,t,z)
plt.grid('on')
plt.show()
I have reviewed the code several times but I can't find the reason why the result is very different from the previous one
You should notice that the function V there will only be the variables X1, S1, P1 = u and the return vector as
np.array([D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1, D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs, D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp ])
So your code would look like the following
import numpy as np
import matplotlib.pyplot as plt
umax = 0.53
Km = 0.12
Yxs = 0.4
S1f = 4
Yxp = 0.4
D=0.5 # Para teissier 0<D<0.514
X1f=0.2
P1f=0.1
# Equations:
#du/dt=V(u,t)
def V(u,t):
X1, S1, P1 = u
return np.array([D*(X1f - X1)+(umax*(1-np.exp(-S1/Km)))*X1,D*(S1f - S1)-(umax*(1-np.exp(-S1/Km))*X1)/Yxs,D*(P1f - P1)+(umax*(1-np.exp(-S1/Km)))*X1*Yxp] )
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = (t[1]-t[0])
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3 ) + k4) / 6
return u, t
u, t = rk4(V, np.array([0., 0., 1. ]) , 0. , 40. , 4000)
x,y,z= u.T
fig = plt.figure() # create figure
plt.plot(t, x, linewidth = 2, label = 'Biomasa') # plot Y to t
plt.plot(t, y, linewidth = 2, label = 'Sustrato') # plot P to tplt.title('Title', fontsize = 12) # add some title to your plot
plt.plot(t, z, linewidth = 2, label = 'Producto') # plot P to tplt.title('Title', fontsize = 12) # add some title to your plot
plt.xlabel('t (en segundos)', fontsize = 12)
plt.ylabel('Biomasa, Sustrato, Producto', fontsize = 12)
plt.xticks(fontsize = 12)
plt.yticks(fontsize = 12)
plt.grid(True) # show grid
plt.legend()
plt.show()
Thus obtaining the graphics you want
You did too much in
h = (t[1]-t[0])/n
The difference t[1]-t[0] is already the step size, what you did makes it the step size for n^2 steps in the same interval.
Are the initial values really the same? In the first graph it does not look like all variables start at zero.
Related
I need help to solve a ODE system using odeint or any workaround that works. I`m trying to model a ODE system descriving the beheaviour of a cilinder on a mechanichal arm, using Lagrangian mechanics I got the following 2nd order ODE system:
$$\ddot{x} = x*\dot{\phi}^2 - g*(sin(\phi) +cos(\phi))$$
$$\ddot{\phi} = \frac{1}{2*\dot{x}*m_c}*(\frac{k*i}{x}-\frac{m_b*L*\dot{\phi}}{2}-g*cos(\phi)*(m_c*x-m_b*L/2))$$
Then I transformed it to a 4x4 1st order ODE system y linearized 2 equations aroun initial condition, to make it more "solveable".
In python I`wrote the folllowing:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# source: https://apmonitor.com/pdc/index.php/Main/SolveDifferentialEquations
g, mc, mb, k, L = (9.8, 0.5, 1.3, 2, 1.2)
def model(z, t, i, z0):
global g, mc, mb, k, L
#ODE variables
x1 = z[0]
y1 = z[1]
x2 = z[2]
y2 = z[3]
#ODE initial conditions
zx1 = z0[0]
zy1 = z0[1]
zx2 = z0[2]
zy2 = z0[3]
#Diferential for linealization around I.C.
dx1 = z[0]-z0[0]
dy1 = z[1]-z0[1]
dx2 = z[2]-z0[2]
dy2 = z[3]-z0[3]
def w1(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return zx2*zy1**2-g*(np.sin(zy2)+np.cos(zy2))
def w2(zx1, zy1, zx2, zy2):
global g, mc, mb, k, L
return 1/(2*zx1*mc)*((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))
dx2dt = x1
#dx1dt = x2*y1**2-g*(np.sin(y2)+np.cos(y2))
dx1dt = w1(zx1, zy1, zx2, zy2) + zy1**2*dx2+2*zx2 * \
zy1*dy1-g*(np.cos(zy2)-np.sin(zy2))*dy2
dy2dt = y1
#dy1dt = 1/(2*x1*mc)*((k*i)/(x2)-mb*y2*L/2-g*np.cos(y2*(mc*x2-mb*L/2)))
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
((k*i)/(zx2)-mb*zy2*L/2-g*np.cos(zy2*(mc*zx2-mb*L/2)))*dx1
+(k*i*np.log(abs(zx2))/(2*zx1*mc)-g*np.cos(zy2)*mc)*dx2-(mb*L) / \
(4*zx1*mc)*dy1+g*np.sin(zy2)*(mc*zx2-mb*L/2)*(2*zx1*mc)*dy2
dzdt = [dx1dt, dy1dt, dx2dt, dy2dt]
return dzdt
# initial condition
z0 = [0.01, 0.01, 0.8, np.pi/8]
# number of time points
n = 30
# time points
t = np.linspace(0, 1, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[:] = 1
# store solution
x1 = np.zeros(n)
y1 = np.zeros(n)
x2 = np.zeros(n)
y2 = np.zeros(n)
# record initial conditions
x1[0] = z0[0]
y1[0] = z0[1]
x2[0] = z0[2]
y2[0] = z0[3]
# solve ODE
for i in range(1, n):
# span for next time step
tspan = [t[i-1], t[i]]
# solve for next step
z = odeint(model, z0, tspan, args=((u[i], z0)) )
# store solution for plotting
if -np.pi/4 <= z[1][3] <= np.pi/4: # Angulo +/- Pi/4
u[i] = u[i-1] + 1
else:
u[i] = u[i-1]
if 0 <= z[1][2] <= L: # Se mantiene en el brazo
print("Se saliΓ³")
x1[i] = z[1][0]
y1[i] = z[1][1]
x1[i] = z[1][2]
y1[i] = z[1][3]
# Siguientes CI
z0 = z[1]
# plot results
plt.plot(t, u, 'g:', label='u(t)')
plt.plot(t, x2, 'b-', label='x(t)')
plt.plot(t, y2, 'r--', label='phi(t)')
plt.ylabel('Cilindro(x,phi)')
plt.xlabel('Tiempo(s)')
plt.legend(loc='best')
plt.show()
Then I`ve got the following error, telling me than too much accuracy is needed to solve my system:
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
lsoda-- repeated occurrences of illegal input
lsoda-- at start of problem, too much accuracy
requested for precision of machine.. see tolsf (=r1)
in above message, r1 = NaN
dy1dt = w2(zx1, zy1, zx2, zy2) - 1/(4*zx1**2*mc) * \
lsoda-- warning..internal t (=r1) and h (=r2) are
such that in the machine, t + h = t on the next step
(h = step size). solver will continue anyway
in above, r1 = 0.3448275862069D+00 r2 = 0.1555030227910D-28
Context: Convert an .iges to .vtk.
I have the following equation Ax^2+Bxy+Cy^2+Dx+Ey+F=0 representing a conic section.
The parameters A~F are given. I want to find points on the conic section, so that I can connect them with lines, and make a mesh.
The reason I need the points instead of just using matplotlib Ellipse is because I'm creating a mesh not a plot.
It is in 3 dimension space, but I first get points on xy plane, and use affine transformation to send it to 3 dim.
Question: How do I find points given an implicit equation?
To avoid spending too much time on this, I wrote some code that seems to handle general ellipses. It can be expanded for other conics, depending on what is needed.
The code takes in the coefficients of a general quadratic equation of an ellipse and a number of desired points to be generated on the ellipse and generates a set of points on the ellipse.
import numpy as np
def equation(conic, points):
'''
equation of a conic with coefficients 'conic'
applied to a matrix number_of_points x 3 whose each row is the coordinates
of each point
'''
c = np.array(conic)
x = np.array([points[:,0]**2, points[:, 0]*points[:,1], points[:,1]**2, points[:,0], points[:,1], np.ones(points.shape[0])])
return c.dot(x)
def equation_to_matrix(eq):
'''
eq[0]*x**2 + eq[1]*x*y + eq[2]*y**2 + eq[3]*x + eq[4]*y + eq[5] = 0
'''
return np.array([[2*eq[0], eq[1], eq[3]],
[ eq[1], 2*eq[2], eq[4]],
[ eq[3], eq[4], 2*eq[5]]]) / 2
def solve_quadratic(a, b, c):
'''
solves
ax^2 + bx + c = 0
'''
D = b**2 - 4*a*c
D = np.sqrt(D)
return (-b-D)/(2*a), (-b+D)/(2*a)
def eigen2(S):
'''
solves the eigen-decomposition problem
for a 2x2 symmetric matrix
'''
k1, k2 = solve_quadratic(1, -S[0,0]-S[1,1], S[0,0]*S[1,1] - S[0,1]*S[1,0])
u1 = np.array([-S[0,1], S[0,0]-k1, 0])
u1 = u1 / np.sqrt(u1.dot(u1))
u2 = np.array([-u1[1], u1[0], 0])
return np.array([k1, k2]), np.array([u1, u2, np.array([0,0,1])]).T
def center(conic_matrix):
center = np.linalg.solve(conic_matrix, np.array([0,0,1]))
return center/center[2]
def find_rotation_and_translation(conic_matrix):
'''
conic = c[0]x^2 + c[1]*xy + c[2]*y^2 + c[3]*x + c[4]*y + c[5] = 0
the result is rotation U such that U.T C U = diag
'''
k, U = eigen2(conic_matrix)
U[:,2] = center(conic_matrix)
return U, k
def find_transform(conic):
C = equation_to_matrix(conic)
U, k = find_rotation_and_translation(C)
C = (U.T).dot(C.dot(U))
C = - C / C[2,2]
k = np.array([1/np.sqrt(C[0,0]), 1/np.sqrt(C[1,1]), 1])
return U.dot(np.diag(k))
def generate_points_on(conic, num_points):
'''
conic = [c[0], c[1], c[2], c[3], c[4], c[5]]
coefficients of the qudaratic equation:
conic: c[0]x^2 + c[1]*xy + c[2]*y^2 + c[3]*x + c[4]*y + c[5] = 0
result is the affine transformation (scaling, rotation, translation)
that maps the unit circle to the ellipse defined by the coefficients
'conic'
'''
cos_ = np.cos(2*np.pi* np.arange(0, num_points)/ num_points)
sin_ = np.sin(2*np.pi* np.arange(0, num_points)/ num_points)
U = find_transform(conic)
points = np.array([cos_, sin_, np.ones(num_points)])
return ((U.dot(points)).T)[:,[0,1]]
'''
Test:
'''
'''
Ellipse with equation whose coefficients are in the list E.
The ellipse has semi-major axes 2 and 1,
it is rotated 60 deg from the horizontal,
and its center is at (1, 4)
'''
E = [ 3.25, -2.59807621, 1.75, -23.40192379, 6.89230485, 39.35769515]
'''
U maps points from unit circle to points on E
'''
U = find_transform(E)
print(U)
'''
the set of points on the ellipse E
'''
p = generate_points_on(E, num_points = 20)
print(p)
'''
check that the points p lie on the ellipse E
'''
print(equation(E, p).round(10))
'''
plot
'''
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(p[:,0], p[:,1], 'ro')
ax.set_aspect('equal')
plt.show()
The code below handles the case of a hyperbola. It largely adapts the code from here
import numpy as np
import matplotlib.pyplot as plt
def equation_to_matrix(eq):
'''
eq[0]*x**2 + eq[1]*x*y + eq[2]*y**2 + eq[3]*x + eq[4]*y + eq[5] = 0
'''
return np.array([[2*eq[0], eq[1], eq[3]],
[ eq[1], 2*eq[2], eq[4]],
[ eq[3], eq[4], 2*eq[5]]]) / 2
def hyp_params_from_general(coeffs):
# get the matrix of the quadratic equation
Aq = equation_to_matrix(coeffs)
# get the matrix of the quadratic form A33
A33 = Aq[:2, :2]
# determinant of A33
detA33 = np.linalg.det(A33)
if detA33 > 0:
raise ValueError('coeffs do not represent a hyperbola: det A33 must be negative!')
# get the center
x0 = -np.linalg.det(np.array([Aq[:2, 2], Aq[:2, 1]]).T) / detA33
y0 = -np.linalg.det(np.array([Aq[:2, 0], Aq[:2, 2]]).T) / detA33
# The semi-major and semi-minor axis lengths (these are not sorted).
# get discriminant of the conic section
delta = np.linalg.det(Aq)
# get the eigenvalues
k1, k2 = np.linalg.eigvals(A33)
k1isk2 = np.isclose(k1/k2, -1)
ap = np.sqrt(abs(delta/k1/detA33))
bp = np.sqrt(abs(delta/k2/detA33))
# Eccentricity.
fac = np.sqrt((Aq[0, 0] - Aq[1, 1])**2 + Aq[0, 1]**2)
if delta < 0:
nu = 1
else:
nu = -1
e = np.sqrt(2*fac/(nu*(Aq[0, 0] - Aq[1, 1]) + fac))
# slope of the asymptotes
if Aq[0, 0] == Aq[1, 1] and k1isk2:
m1 = 0.
m2 = np.nan
else:
m1 = Aq[0, 0]/(-Aq[0, 1] - np.sqrt(-detA33))
m2 = Aq[0, 0]/(-Aq[0, 1] + np.sqrt(-detA33))
# Sort the semi-major and semi-minor axis lengths but keep track of
# the original relative magnitudes of width and height.
width_gt_height = True
if ap < bp and not k1isk2:
width_gt_height = False
ap, bp = bp, ap
# The angle of anticlockwise rotation of the major-axis from x-axis.
if Aq[0, 1] == 0:
phi = 0 if Aq[0, 0] < Aq[1, 1] else np.pi/2
elif Aq[0, 0] == Aq[1, 1]:
phi = np.pi/4 # would divide by zero and arctan(inf) -> pi/4
if m1 > 0 and m2 > 0:
width_gt_height = True
else:# Aq[0, 0] > Aq[1, 1]:
phi = np.arctan(2*Aq[0, 1]/(Aq[0, 0] - Aq[1, 1])) / 2
if not width_gt_height:
# Ensure that phi is the angle to rotate to the semi-major axis.
phi += np.pi/2
phi = phi % np.pi
return x0, y0, ap, bp, phi, e, m1, m2, width_gt_height
def get_hyperbola_pts(params, npts=100, tmin=-1, tmax=1):
x0, y0, ap, bp, phi, m1, m2 = params
# A grid of the parametric variable, t.
t = np.linspace(tmin, tmax, npts)
# points
x = x0 + ap * np.cosh(t) * np.cos(phi) - bp * np.sinh(t) * np.sin(phi)
y = y0 + ap * np.cosh(t) * np.sin(phi) + bp * np.sinh(t) * np.cos(phi)
# asymptotes
ya1 = y0 + m1*(x - x0)
ya2 = y0 + m2*(x - x0)
return x, y, ya1, ya2
if __name__ == '__main__':
coeffs = [1., 6., -2., 3., 0., 0.]
x0, y0, ap, bp, phi, e, m1, m2, width_gt_height = hyp_params_from_general(coeffs)
print('x0, y0, ap, bp, phi, e, m1, m2, width_gt_height = ', x0, y0, ap, bp, phi, e, m1, m2)
x_, y_, ya1, ya2 = get_hyperbola_pts((x0, y0, ap, bp, phi, m1, m2), npts=250, tmin=-2, tmax=3)
fig, ax = plt.subplots(figsize=(16, 9))
ax.plot(x_, y_, marker='.', linewidth=0.5, c='r')
ax.plot(x_, ya1, marker='.', linewidth=0.2, c='b')
ax.plot(x_, ya2, marker='.', linewidth=0.2, c='b')
ax.grid(True, linestyle='--')
I would like my y-axis to be superimposed/shifted as it is in this image:
Here is the graph that I have created using python with the code shown below:
There is only one origin on the graph I produced. I would like there to be at least three so that the functions with the smaller amplitudes are more visible/ easier to read.
What functions can I use to achieve this?
Thank you!
import numpy as np
import matplotlib.pyplot as plt
import math
def initial():
#obtain inital parameters
dt = .04
g = 9.8
l = 9.8
q = 0.5
f_d = 1.2 #driving force
frequency = 0.667 #frequency of driving force
theta_start = 0.2
omega_start = 0
time_stop = 60
return dt, g, l, q, frequency, theta_start, omega_start, time_stop
def rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop):
#create arrays for theta and omega, calculate omega and theta using rk2 method
forces = [0, 0.5, 1.2]
j = 0
while j < 3:
f_d = forces[j]
theta = []
omega = []
time = [np.array([0])]
theta = np.append(theta, theta_start)
omega = np.append(omega, omega_start)
i = 0
while time[i] < time_stop:
#if theta[i] not in range(-3.14,3.14)
theta_prime = theta[i] + 0.5*omega[i]*dt
omega_prime = omega[i] + 0.5*((-g/l)*math.sin(theta[i]) - q*omega[i] + f_d*math.sin(frequency*time[i]))*dt
time_prime = time[i] + 0.5*dt
theta_new = theta[i] + omega_prime*dt
omega_new = omega[i] + ((-g/l)*math.sin(theta_prime) - q*omega[i] + f_d*math.sin(frequency*time_prime))*dt
time_new = time[i] + dt
theta = np.append(theta, theta_new)
omega = np.append(omega, omega_new)
time = np.append(time, time_new)
i = i + 1
plt.plot(time, theta)
j = j+1
plt.plot(time, theta)
plt.xlabel('Time [s]')
plt.ylabel('Angle [rad]')
plt.show()
return theta, omega, time
def main():
dt, g, l, q, frequency, theta_start, omega_start, time_stop = initial()
theta, omega, time = rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop)
#plot(theta, omega, time)
main()
The answer referenced in #tom10's comment can be modified to ensure the tick spacing is consistent across all subplots, even when the height of the subplots is different, by explicitly setting the tick locations (and labels) as well as the limits for each subplot:
import numpy as np
import matplotlib.pyplot as plt
import math
ratios = [5, 5, 7]
lim = [[-0.3, 0.3], [-1, 1], [-12,4]]
labels = [['' if (e != (ratios[j] - 1) / 2) else 0
for e in range(ratios[j]-1)]+[lim[j][1]] for j in range(len(ratios))]
fig, axs = plt.subplots(3, 1, sharex=True, gridspec_kw={'height_ratios': ratios})
def initial():
#obtain inital parameters
dt = .04
g = 9.8
l = 9.8
q = 0.5
f_d = 1.2 #driving force
frequency = 0.667 #frequency of driving force
theta_start = 0.2
omega_start = 0
time_stop = 60
return dt, g, l, q, frequency, theta_start, omega_start, time_stop
def rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop):
forces = [0, 0.5, 1.2]
for j in range(3):
f_d = forces[j]
theta = []
omega = []
time = [np.array([0])]
theta = np.append(theta, theta_start)
omega = np.append(omega, omega_start)
i = 0
while time[i] < time_stop:
theta_prime = theta[i] + 0.5*omega[i]*dt
omega_prime = omega[i] + 0.5*((-g/l)*math.sin(theta[i]) - q*omega[i] +
f_d*math.sin(frequency*time[i]))*dt
time_prime = time[i] + 0.5*dt
theta_new = theta[i] + omega_prime*dt
omega_new = omega[i] + ((-g/l)*math.sin(theta_prime) - q*omega[i] +
f_d*math.sin(frequency*time_prime))*dt
time_new = time[i] + dt
theta = np.append(theta, theta_new)
omega = np.append(omega, omega_new)
time = np.append(time, time_new)
i = i + 1
axs[j].plot(time, theta)
if j != 0: axs[j].spines['top'].set_visible(False)
if j != 2:
axs[j].spines['bottom'].set_visible(False)
axs[j].tick_params(bottom=False)
axs[j].tick_params(axis='y', direction='in')
axs[j].set_ylim(lim[j])
axs[j].set_yticks(np.linspace(lim[j][0], lim[j][1], ratios[j]))
axs[j].set_yticklabels(labels[j])
plt.subplots_adjust(hspace=0)
plt.figtext(0.08, 0.5, 'Angle [rad]', rotation = 90, ha='center', va='center')
plt.xlabel('Time [s]')
plt.show()
return theta, omega, time
def main():
dt, g, l, q, frequency, theta_start, omega_start, time_stop = initial()
theta, omega, time = rk_2(dt, g, l, q, frequency, theta_start, omega_start, time_stop)
main()
I am trying to develop an algorithm (use scipy.integrate.odeint()) that predicts the changing concentration of cells, substrate and product (i.e., π, π, π) over time until the system reaches steady- state (~100 or 200 hours). The initial concentration of cells in the bioreactor is 0.1 π/πΏ and there is no glucose or product in the reactor initially. I want to test the algorithm for a range of different flow rates, π, between 0.01 πΏ/β and 0.25 πΏ/β and analyze the impact of the flow rate on product production (i.e., π β
π in π/β). Eventually, I would like to generate a plot that shows product production rate (y-axis) versus flow rate, π, on the x-axis. My goal is to estimate the flow rate that results in the maximum (or critical) production rate. This is my code so far:
from scipy.integrate import odeint
import numpy as np
# Constants
u_max = 0.65
K_s = 0.14
K_1 = 0.48
V = 2
X_in = 0
S_in = 4
Y_s = 0.38
Y_p = 0.2
# Variables
# Q - Flow Rate (L/h), value between 0.01 and 0.25 that produces best Q * P
# X - Cell Concentration (g/L)
# S - The glucose concentration (g/L)
# P - Product Concentration (g/L)
# Equations
def func_dX_dt(X, t, S):
u = (u_max) / (1 + (K_s / S))
dX_dt = (((Q * S_in) - (Q * S)) / V) + (u * X)
return dX_dt
def func_dS_dt(S, t, X):
u = (u_max) / (1 + (K_s / S))
dS_dt = (((Q * S_in) - (Q * S)) / V) - (u * (X / Y_s))
return dS_dt
def func_dP_dt(P, t, X, S):
u = (u_max) / (1 + (K_s / S))
dP_dt = ((-Q * P) / V) - (u * (X / Y_p))
return dP_dt
t = np.linspace(0, 200, 200)
# Q placeholder
Q = 0.01
# Attempt to solve the Ordinary differential equations
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(S,))
sol_dS_dt = odeint(func_dS_dt, 0.1, t, args=(X,))
sol_dP_dt = odeint(func_dP_dt, 0.1, t, args=(X,S))
In the programs current state there does not seem to be be a way to generate the steady state value for P. I attempted to make this modification to get the value of X.
sol_dX_dt = odeint(func_dX_dt, 0.1, t, args=(odeint(func_dS_dt, 0.1, t, args=(X,)),))
It produces the error:
NameError: name 'X' is not defined
At this point I am not sure how to move forward.
(Edit 1: Added Original Equations)
First Equation
Second Equation and Third Equation
You do not have to apply the functions to each part but return a tuple of the derivatives as I show below:
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
Q = 0.01
V = 2
Ys = 0.38
Sin = 4
Yp = 0.2
Xin = 0
umax = 0.65
Ks = 0.14
K1 = 0.48
def mu(S, umax, Ks, K1):
return umax/((1+Ks/S)*(1+S/K1))
def dxdt(x, t, *args):
X, S, P = x
Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1 = args
m = mu(S, umax, Ks, K1)
dXdt = (Q*Xin - Q*X)/V + m*X
dSdt = (Q*Sin - Q*S)/V - m*X/Ys
dPdt = -Q*P/V - m*X/Yp
return dXdt, dSdt, dPdt
t = np.linspace(0, 200, 200)
X0 = 0.1
S0 = 0.1
P0 = 0.1
x0 = X0, S0, P0
sol = odeint(dxdt, x0, t, args=(Q, V, Xin, Ys, Sin, Yp, umax, Ks, K1))
plt.plot(t, sol[:, 0], 'r', label='X(t)')
plt.plot(t, sol[:, 1], 'g', label='S(t)')
plt.plot(t, sol[:, 2], 'b', label='P(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()
Output:
Hi i'm trying to get a plot of the trajectory of a mass under projectile motion. One with a force acting on the horizontal axis and one without (basically 2 sets of x values plotted against a 1 set of y-values). Here's what i have so far.. I'm new to programming and i can't seem to figure out where this went wrong. Hope you guys can help me. Thank you!
import numpy as np
import matplotlib.pyplot as pl
def position(y0, v0, theta, g, t):
y= y0 + v0*np.sin(theta)*t + (g*t**2)/2
return y
def position2(x0, v0, theta, c, e, alpha, t):
x1 = x0 + v0*(np.cos(theta))*t + c*(t*(e-1)+(2-2*e)/alpha)
return x1
def position3(x0, v0, theta, t):
x2 = x0 + v0*(np.cos(theta))*t
return x2
t = np.linspace(0,10,1000)
#part1
m = 1
theta = 45
y0 = 2
x0 = 0
v0 = 3
k = 1
alpha = 0.5
g = -9.8
c = (-k/m)*(1/alpha**2)
e = -(np.e**(-alpha*t))
x1 = []
x2 = []
y = []
for a in t:
x1_data = position2(x0, v0, theta, c, e, alpha, t)
x1.append(x1_data)
x2_data = position3(x0, v0, theta, t)
x2.append(x2_data)
y_data = position(y0, v0, theta, g, t)
y.append(y_data)
print x1_data
print x2_data
print y_data
pl.title('Constant and Time-Dependent Forces')
pl.xlabel(b'x-position')
pl.ylabel(b'y-position')
x1label = 'projectile 1'
x2label = "'normal' projectile"
plot1 = pl.plot(x1_data, y, 'r')
plot2 = pl.plot(x2_data, y, 'b')
pl.legend()
pl.show()
I went through your code since i am new to matplotlib and wanted to play a bit with it. The only mistake i found is in the for loop where you do for a in t: but end up passing t to the functions instead of a.
import numpy as np
import matplotlib.pyplot as pl
sin = np.sin
cos = np.cos
pi = np.pi
def y_position(y0, v0, phi, g, t):
y_t = y0 + v0 * sin(phi) * t + (g * t**2) / 2
return y_t
def x_position_force(x0, v0, phi, k, m, alpha, t):
term1 = (-k / m) * (1 / alpha ** 2)
term2 = -np.e ** (-alpha * t)
x_t = x0 + v0 * cos(phi) * t + term1 * (t * (term2 - 1) + (2 - 2 * term2) / alpha)
return x_t
def x_position_no_force(x0, v0, phi, t):
x_t = x0 + v0 * cos(phi) * t
return x_t
time = np.linspace(0, 10, 100)
#------------- I N P U T -------------#
x_init = 0
y_init = 2
v_init = 3
theta = 45
gravity = -9.8
m = 1
k = 1
alpha = 0.5
#------------- I N P U T -------------#
x_with_force = []
x_with_no_force = []
y = []
for time_i in time:
x_with_force.append(x_position_force(x_init, v_init, theta, k, m, alpha, time_i))
x_with_no_force.append(x_position_no_force(x_init, v_init, theta, time_i))
y.append(y_position(y_init, v_init, theta, gravity, time_i))
# print(x1_data)
# print(x2_data)
# print(y_data)
pl.subplot(211)
pl.title('Constant and Time-Dependent Forces')
pl.xlabel('time')
plot1 = pl.plot(time, x_with_force, 'r', label='x_coord_dynamicF')
plot2 = pl.plot(time, x_with_no_force, 'g', label='x_coord_staticF')
plot3 = pl.plot(time, y, 'b', label='y_coord')
pl.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.)
pl.subplot(212)
pl.title('Trajectory (x,y)')
pl.xlabel('X')
pl.ylabel('Y')
plot4 = pl.plot(x_with_force, y, 'r^')
plot5 = pl.plot(x_with_no_force, y, 'b*')
pl.show()
I changed a number of things though to make the code inline with PEP8. In my opinion it is the use of bad variable names that lead you to the mistake you did. So i would recommend taking the time to type those few extra characters that ultimately help you and the people reading your code.