I am trying to solve a system of ODE's related to a coupled mass and spring system using solve_ivp. I am getting a problem stating that "ValueError: setting an array element with a sequence". See below for the code I am trying to use.
from scipy.integrate import solve_ivp
import numpy as np
func(t, w, p):
#unpack the variables and parameters"
x1, y1, x2, y2 = w
m1, m2, k1, k2, L1, L2, b1, b2 = p
# Create the functions
y1 = (-b1 * y1 - k1 * (x1 - L1) + k2 * (x2 - x1 - L2)) / m1,
y2 = (-b2 * y2 - k2 * (x2 - x1 - L2)) / m2
return y1, y2
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.5
# Spring constants
k1 = 8.0
k2 = 40.0
# Natural lengths
L1 = 0.5
L2 = 1.0
# Friction coefficients
b1 = 0.8
b2 = 0.5
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = 0.5
y1 = 0.0
x2 = 2.25
y2 = 0.0
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
w0 = [x1, y1, x2, y2]
t_span = np.linspace(0, 15, 1000)
Sol = solve_ivp(lambda t, w: func(t, w, p), [t_span[0], t_span[-1]], y0=w0, t_eval=t_span)
I am not really sure where I am going wrong because the error doesn't specify which line of code the problem is with. Has anyone experienced this before?
If x is the position and y the velocity, then name z the acceleration and return a vector of the derivatives of the inputs
def func(t, w, p):
#unpack the variables and parameters"
x1, y1, x2, y2 = w
m1, m2, k1, k2, L1, L2, b1, b2 = p
# Create the functions
z1 = (-b1 * y1 - k1 * (x1 - L1) + k2 * (x2 - x1 - L2)) / m1,
z2 = (-b2 * y2 - k2 * (x2 - x1 - L2)) / m2
return y1, z1, y2, z2
Everything else looks like it should work.
Related
I have two 3-d vectors originating from the origin with
v1 = array([ 0.20297736, -0.19208957, -0.63320655])
v2 = array([-0.63721771, 0.17457218, 0.12666251])
These two vectors are orthogonal to the vector axis_vector = array([ 0.21708059, 0.95127211, -0.21899175])
I am trying to determine the angle between v1 and v2 with the condition that I always start from v1. This means that V1 will be the point at which 0-degrees exists. Moving counterclockwise from v1, I want to determine the angle between v1 and v2.
Currently, I have been using the following:
angle=np.arccos(np.dot(vec2,vec1)/(np.linalg.norm(vec1)*np.linalg.norm(vec2))) *180/np.pi
but this particular line of code does not let me dictate which vector takes priority as the starting vector. As a result, it always returns the same angle without regard for which vector I wish to start from.
Any help would be appreciated!
The trick seemed to be to understand that the orthogonal axis vector is also representative of a plane. Once that is understood, you can solve this problem as below:
import numpy as np
import math
v2 = np.array([0.20297736, -0.19208957, -0.63320655])
v1 = np.array([-0.63721771, 0.17457218, 0.12666251])
axis_vector = np.array([ 0.21708059, 0.95127211, -0.21899175])
def find_angle(v1, v2, vn):
x1 = v1[0]
y1 = v1[1]
z1 = v1[2]
x2 = v2[0]
y2 = v2[1]
z2 = v2[2]
xn = vn[0]
yn = vn[1]
zn = vn[2]
dot = x1 * x2 + y1 * y2 + z1 * z2
det = x1 * y2 * zn + x2 * yn * z1 + xn * y1 * z2 - z1 * y2 * xn - z2 * yn * x1 - zn * y1 * x2
angle = math.atan2(det, dot)*180/np.pi
return angle
angle = find_angle(v1, v2, axis_vector)
This answer was based off of: Direct way of computing clockwise angle between 2 vectors
Edit: For sake of completeness, If you have to do this computation multiple times with multiple vectors and planes.
def find_angle(v1, v2, vn):
if v1.shape[0] == 1:
x1 = v1[0]
y1 = v1[1]
z1 = v1[2]
x2 = v2[0]
y2 = v2[1]
z2 = v2[2]
xn = vn[0]
yn = vn[1]
zn = vn[2]
dot = x1 * x2 + y1 * y2 + z1 * z2
det = x1 * y2 * zn + x2 * yn * z1 + xn * y1 * z2 - z1 * y2 * xn - z2 * yn * x1 - zn * y1 * x2
angle = m.atan2(det, dot) * 180 / np.pi
angle = np.array([angle])
else:
elementWiseConcat = np.asarray(list((zip(v1, v2, vn))))
dot = np.einsum('ij, ij->i', v1, v2)
det = np.linalg.det(elementWiseConcat)
angle = np.arctan2(det, dot) * 180 / np.pi
return angle
I am trying to write a program using A Coupled Spring-Mass System . Solve Using ODE's
import numpy as np
import matplotlib.pyplot as plt
kitchen1 = 2.0
kitchen2 = 2.0
money1 = 2.0
money2 = 2.0
walk1 = 5.0
walk2 = 5.0
Lenon1 = 2.0
Lenon2 = 2.0
def f1(x1, v1, x2, v2, t):
return v1
def f2 (x1, v1, x2, v2, t):
return ((-kitchen1/money1)*(x1-Lenon1)) + (kitchen2/money1*(x2-x1-walk1- Lenon2))
def f3(x1, v1, x2, v2, t):
return v2
def f4(x1, v1, x2, v2, t):
return (-kitchen2/money2) * (x2-x1-walk1-Lenon2)
def rk4_gen(x1_arr, v1_arr, x2_arr, v2_arr, t_arr, h):
x1, v1, x2, v2, t = t_arr[0], x1_arr[0], v1_arr[0], x2_arr[0], v2_arr[0]
for i in range(1,len(t)):
t, h = t[i-1], t[i]-t[i-1]
k11 = h*f1(x1, v1, x2, v2, t)
k12 = h*f2(x1, v1, x2, v2, t)
k13 = h*f3(x1, v1, x2, v2, t)
k14 = h*f4(x1, v1, x2, v2, t)
k21 = h*f1(x1+k11/2.0, v1+k12/2.0,x2+k13/2.0,v2+k14/2.0, t+h/2.0)
k22 = h*f2(x1+k11/2.0, v1+k12/2.0,x2+k13/2.0,v2+k14/2.0, t+h/2.0)
k23 = h*f3(x1+k11/2.0, v1+k12/2.0,x2+k13/2.0,v2+k14/2.0, t+h/2.0)
k24 = h*f4(x1+k11/2.0, v1+k12/2.0,x2+k13/2.0,v2+k14/2.0, t+h/2.0)
k31 = h*f1(x1+k21/2.0, v1+k22/2.0,x2+k23/2.0,v2+k24/2.0, t+h/2.0)
k32 = h*f2(x1+k21/2.0, v1+k22/2.0,x2+k23/2.0,v2+k24/2.0, t+h/2.0)
k33 = h*f3(x1+k21/2.0, v1+k22/2.0,x2+k23/2.0,v2+k24/2.0, t+h/2.0)
k34 = h*f4(x1+k21/2.0, v1+k22/2.0,x2+k23/2.0,v2+k24/2.0, t+h/2.0)
k41 = h*f1(x1+k31, v1+k32,x2+k33,v2+k34, t+h)
k42 = h*f2(x1+k31, v1+k32,x2+k33,v2+k34, t+h)
k43 = h*f3(x1+k31, v1+k32,x2+k33,v2+k34, t+h)
k44 = h*f4(x1+k31, v1+k32,x2+k33,v2+k34, t+h)
x1 = x1 + (k11 + 2*k12 + 2*k13 + k14)/6.0
v1 = v1 + (k21 + 2*k22 + 2*k23 + k24)/6.0
x2 = x2 + (k31 + 2*k32 + 2*k33 + k34)/6.0
v2 = v2 + (k41 + 2*k42 + 2*k43 + k44)/6.0
x1_arr[i], v1_arr[i], x2_arr[i], v2_arr[i] = x1, v1, x2, v2
return x1_arr, v1_arr , x2_arr , v2_arr, t_arr
def grafik_ciz(t,y,x_baslik,y_baslik,baslik):
plt.figure(figsize = [12, 9])
plt.plot(t,y)
plt.xlabel(x_baslik)
plt.ylabel(y_baslik)
plt.title(baslik)
plt.grid()
plt.show()
ti = 0
tf = 20
x1 = 2
v1 = 0
x2 = 15
v2 = 0
h = 0.5
t = np.arange(ti,tf+h,h)
x1 = np.zeros(len(t))
v1 = np.zeros(len(t))
x2 = np.zeros(len(t))
v2 = np.zeros(len(t))
x1[0] = x1i
v1[0] = v1i
x2[0] = x2i
v2[0] = v2i
x1 = rk4_gen(x1_arr, v1_arr, x2_arr, v2_arr, t_arr, h
print x1
Using 4th order Runge-Kutta method
I need to plot a graph showing both x and y as a function of time from t = 0 to t=20.
error m.ValueError: too many values to unpack
Here is my code so far but not display anything on the graph.
I think, this error is t = np.arange(ti,tf+h,h).
I need to plot a graph showing both x1 and v1 as a function of time from t = 0 to t=20.
Apart from many errors in implementing the algorithm correctly, using consistent function interfaces, using the correct function names etc.
Your reported problem is that you do not unpack the arrays passed to rk4_gen in the computation of the single RK4 steps.What you can do without too many changes is to rename the parameters like in
def rk4_gen(t_arr, x1_arr, v1_arr, x2_arr, v2_arr, h):
(why do you pass h? In every step you can compute the correct h=t[i]-t[i-1]). Then initialize the running variables
t, x1, v1, x2, v2 = t_arr[0], x1_arr[0], v1_arr[0], x2_arr[0], v2_arr[0]
perform the (corrected) RK4 steps and at the end of each step save the computed value into the array
def rk4_gen(x1_arr, v1_arr, x2_arr, v2_arr, t_arr, h):
t, x1, v1, x2, v2 = t_arr[0], x1_arr[0], v1_arr[0], x2_arr[0], v2_arr[0]
for i in range(1,len(t_arr)):
# Do the RK4 step, it is from i-1 to i
t, h = t_arr[i-1], t_arr[i]-t_arr[i-1]
k11 = h*f1(...)
...
v2 = v_2+(k14+2*k24+2*k34+k44)/6.0
x1_arr[i], v1_arr[i], x2_arr[i], v2_arr[i] = x1, v1, x2, v2
return x1_arr, v1_arr , x2_arr , v2_arr, t_arr
Note also that your finishing computation has the k values in transposed order.
You can solve this problem in a much more compact way using the scipy.integrate methods, like in
from scipy.integrate import solve_ivp
def spring_ode(t,u):
x1,v1,x2,v2 = u
a1 = ((-kitchen1/money1)*(x1-Lenon1)) + (kitchen2/money1*(x2-x1-walk1- Lenon2))
a2 = (-kitchen2/money2) * (x2-x1-walk1-Lenon2)
return [v1,a1,v2,a2]
res = solve_ivp(spring_ode, [ti,tf], [x1i,v1i,x2i,v2i], dense_output=True, rtol=1e-12, atol=1e-14)
h=0.02
t = np.arange(ti,tf+h/2,h)
u = res.sol(t)
x1,v1,x2,v2 = u
plt.figure(figsize = [8, 5])
plt.plot(t,x1,t,x2); plt.legend(["$x_1$","$x_2$"])
plt.grid(); plt.show()
with the resulting plot
I'm trying to define 'hard' limits to the return values of Scipy's odeint function but am unsure if function allows for such. I've modified this example from Scipy Cookbook so that the coupled two bodied system could collide.
Image Link
Graph Collision
Imaginary Stop
Specifically, the spring constant and mass have been changed to be weaker and lighter. You'll also notice the 'if' statement used inside the function trying to limit the travel of 'm1' no further than the initial input of 'x2'. Sorry, I don't have enough reputation points to post the graphs, but you'll clearly see the two masses can occupy the same space during portions of the solution.
# Use ODEINT to solve the differential equations defined by the vector field
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import numpy as np
def vectorfield(w, t, p):
"""
Defines the differential equations for the coupled spring-mass system.
Arguments:
w : vector of the state variables:
w = [x1,y1,x2,y2]
t : time
p : vector of the parameters:
p = [m1,m2,k1,k2,L1,L2,b1,b2]
"""
x1, y1, x2, y2 = w
m1, m2, k1, k2, L1, L2, b1, b2 = p
# Create f = (x1',y1',x2',y2'):
f = [y1,
(-b1 * y1 - k1 * (x1 - L1) + k2 * (x2 - x1 - L2)) / m1,
y2,
(-b2 * y2 - k2 * (x2 - x1 - L2)) / m2]
if y1 > x2:
y1 == x2
else:
y1 == y1
return f
# Parameter values
# Masses:
m1 = 0.5
m2 = 1.5
# Spring constants
k1 = 0.1
k2 = 40.0
# Natural lengths
L1 = 0.5
L2 = 1.0
# Friction coefficients
b1 = 0.8
b2 = 0.5
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = 0.5
y1 = 0.0
x2 = 4.25
y2 = 0.0
# ODE solver parameters
abserr = 1.0e-8
relerr = 1.0e-6
stoptime = 5.0
numpoints = 2500
# Create the time samples for the output of the ODE solver.
# I use a large number of points, only because I want to make
# a plot of the solution that looks nice.
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
w0 = [x1, y1, x2, y2]
# Call the ODE solver.
wsol = odeint(vectorfield, w0, t, args=(p,),
atol=abserr, rtol=relerr)
plt.plot(t, wsol[:, 0], 'b', label='theta(t)')
plt.plot(t, wsol[:, 2], 'g', label='omega(t)')
plt.show()
I'm unsure if my variables are not being set up correctly, or if the odeint function cannot accept these types of 'limits' I'm trying to add. Ideally, it would be nice if an 'upper boundary' could be set, if the displacement of the mass were beyond that value, it could then be set equal to a maximum limit of sorts.
Thank you in advance for the help.
Let us assume I have a set of differential equations to be integrated with scipy odeint. Now my goal is to find the steady-state (I chose initial conditions such that this state exists). At the moment I have implemented something like
cond = True
while cond:
x = integrate(interval = [0,t], steps = 200)
if var(x[-22::]) < maxvar:
cond = False
return mean(x)
else:
t*= 2
Do you have a more efficient approach?
If you are using odeint, then you already have your differential equations written as a function f(x, t) (or possibly f(x, t, *args)). If your system is autonomous (i.e. f does not actually depend on t), you can find an equilibrium by solving f(x, 0) == 0 for x. You can use, for example, scipy.optimize.fsolve to solve for the equilibrium.
The following is an example. It uses the "Coupled Spring Mass System" example from the scipy cookbook. scipy.optimize.fsolve is used to find the equilibrium solution x1 = 0.5, y1 = 0, x2 = 1.5, y2 = 0.
from scipy.optimize import fsolve
def vectorfield(w, t, p):
"""
Defines the differential equations for the coupled spring-mass system.
Arguments:
w : vector of the state variables:
w = [x1, y1, x2, y2]
t : time
p : vector of the parameters:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
"""
x1, y1, x2, y2 = w
m1, m2, k1, k2, L1, L2, b1, b2 = p
# Create f = (x1', y1', x2', y2'):
f = [y1,
(-b1 * y1 - k1 * (x1 - L1) + k2 * (x2 - x1 - L2)) / m1,
y2,
(-b2 * y2 - k2 * (x2 - x1 - L2)) / m2]
return f
if __name__ == "__main__":
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.5
# Spring constants
k1 = 8.0
k2 = 40.0
# Natural lengths
L1 = 0.5
L2 = 1.0
# Friction coefficients
b1 = 0.8
b2 = 0.5
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
# Initial guess to pass to fsolve. The second and fourth components
# are the velocities of the masses, and we know they will be 0 at
# equilibrium. For the positions x1 and x2, we'll try 1 for both.
# A better guess could be obtained by solving the ODEs for some time
# interval, and using the last point of that solution.
w0 = [1.0, 0, 1.0, 0]
# Find the equilibrium
eq = fsolve(vectorfield, w0, args=(0, p))
print "Equilibrium: x1 = {0:.1f} y1 = {1:.1f} x2 = {2:.1f} y2 = {3:.1f}".format(*eq)
The output is:
Equilibrium: x1 = 0.5 y1 = 0.0 x2 = 1.5 y2 = 0.0
Referring to your comments, I don't see any better way:
In this case where you know approximately where the system will settle.
(This is fairly easy to predict in some systems, like a pendulum, or a charging capacitor), and that it will settle, the fastest way I know is to check if
(p[0] * x[i] + p[1] * x[i-1] ... + p[n] * x[i-n] - mean(x[i-0:n]) )< epsilon)
The difficulty is determining the size of epsilon, the parameters p[0:n] to tune this detection.
Clearly you are already using this window method:
epsilon = varmax
p[0:n] = 1
n = 22
and have optimized it by removing the parameters for the filter, and simply using the variance.
For many systems (where settling looks like 1 order differential equations) the filter parameters turn out to look like this:
p[0] = n/2
p[n] = n/2
p[1:n-1] = 0
meaning you can make stuff go faster if you replace the calculation of state variance with this simple test:
if( abs(x[-22] - x[0]) > epsilon)
This will not detect correctly if small disturbances are still present, since we don't know your system, that's difficult to talk about...
I want to find a 3D plane equation given 3 points. I have got the normal calculated after applying the cross product. But the equation of a plane is known to be the normal multiply by another vector which what I am taught to be as P.OP. I substitute my main reference point as OP and i want P to be in (x, y, z) form. So that I can get something like e.g,
OP = (1, 2, 3)
I want to get something like that:
(x-1)
(y-2)
(z-3)
May I know how?
Below is my reference code.(Note: plane_point_1_x(), plane_point_1_y(), plane_point_1_z() are all functions asking for the user input of the respective points)
"""
I used Point P as my reference point so I will make use of it in this section
"""
vector_pop_x = int('x') - int(plane_point_1_x())
vector_pop_y = int('y') - int(plane_point_1_y())
vector_pop_z = int('z') - int(plane_point_1_z())
print vector_pop_x, vector_pop_y, vector_pop_z
All the above is what i did, but for some reason it did not work. I think the problem lies in the x, y , z part.
Say you have three known points, each with (x, y, z). For example:
p1 = (1, 2, 3)
p2 = (4, 6, 9)
p3 = (12, 11, 9)
Make them into symbols that are easier to look at for further processing:
x1, y1, z1 = p1
x2, y2, z2 = p2
x3, y3, z3 = p3
Determine two vectors from the points:
v1 = [x3 - x1, y3 - y1, z3 - z1]
v2 = [x2 - x1, y2 - y1, z2 - z1]
Determine the cross product of the two vectors:
cp = [v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]]
A plane can be described using a simple equation ax + by + cz = d. The three coefficients from the cross product are a, b and c, and d can be solved by substituting a known point, for example the first:
a, b, c = cp
d = a * x1 + b * y1 + c * z1
Now do something useful, like determine the z value at x=4, y=5. Re-arrange the simple equation, and solve for z:
x = 4
y = 5
z = (d - a * x - b * y) / float(c) # z = 6.176470588235294
If I am not mistaken, one good solution here contains mistypes
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * (vector1[0] * vector2[2] - vector1[2] * vector2[0]), vector1[0] * vector2[1] - vector1[1] * vector2[0]]
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = - (cross_product[0] * x1 + cross_product[1] * y1 + cross_product[2] * z1)
Tried previous (author's) version, but had to check it. With couple more minuses in formulas seems correct now.
One good way is:
| x1 y1 z2 1 |
| x2 y2 z2 1 |
| x3 y3 z3 1 | = 0
| x y z 1 |
Where the vertical pipes mean the determinant of the matrix, and (x1 y1 z1), (x2 y2 z2), and (x3 y3 z3) are your given points.
Plane implicit Eqn:
All points P = (x, y, z) satisfying
<n, QP> = 0
where
n is the plane normal vector,
Q is some point on the plane (any will do)
QP is the vector from Q to P
<a, b> is the scalar (dot) product operator.
(Remember that QP can be computed as P - Q)
I wish this answer already existed. Coded from http://www.had2know.com/academics/equation-plane-through-3-points.html
Supposing 3 points p1, p2, p3 - consisting of [x1, y1, z1], etc.
vector1 = [x2 - x1, y2 - y1, z2 - z1]
vector2 = [x3 - x1, y3 - y1, z3 - z1]
cross_product = [vector1[1] * vector2[2] - vector1[2] * vector2[1], -1 * vector1[0] * v2[2] - vector1[2] * vector2[0], vector1[0] * vector2[1] - vector1[1] * vector2[0]]
d = cross_product[0] * x1 - cross_product[1] * y1 + cross_product[2] * z1
a = cross_product[0]
b = cross_product[1]
c = cross_product[2]
d = d