Solving system of ODE's using python and graphing (Chua's circuit) - python

I'm trying to model Chau's Circuit in Python using matplotlib and scipy, which involves solving a system of ordinary differential equations.
This has been done in matlab, and I simply wanted to attempt the problem in python. The matlab code linked is a little confusing; the code on the left doesn't appear to have much relevance to solving the system of ode's that describe Chua's Circuit (page 3, equations (2)(3) and (4)), whilst the code on the right goes beyond that to modelling the circuit component by component.
I'm not familiar with scipy's odeint function so I used some of the examples from the scipy cookbook for guidance.
Can anyone help me troubleshoot my system; why do I get a graph looking like this:
As opposed to one looking like this?
My code is attached below:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def fV_1(V_1, G_a, G_b, V_b):
if V_1 < -V_b:
fV_1 = G_b*V_1+(G_b-G_a)*V_b
elif -V_b <= V_1 and V_1 <=V_b:
fV_1 = G_a*V_1
elif V_1 > V_b:
fV_1 = G_b*V_1+(G_a-G_b)*V_b
else:
print "Error!"
return fV_1
def ChuaDerivatives(state,t):
#unpack the state vector
V_1 = state[0]
V_2 = state[1]
I_3 = state[2]
#definition of constant parameters
L = 0.018 #H, or 18 mH
C_1 = 0.00000001 #F, or 10 nF
C_2 = 0.0000001 #F, or 100 nF
G_a = -0.000757576 #S, or -757.576 uS
G_b = -0.000409091 #S, or -409.091 uS
V_b = 1 #V (E)
G = 0.000550 #S, or 550 uS VARIABLE
#compute state derivatives
dV_1dt = (G/C_1)*(V_2-V_1)-(1/C_1)*fV_1(V_1, G_a, G_b, V_b)
dV_2dt = -(G/C_2)*(V_2-V_1)+(1/C_2)*I_3
dI_3dt = -(1/L)*V_2
#return state derivatives
return dV_1dt, dV_2dt, dI_3dt
#set up time series
state0 = [0.1, 0.1, 0.0001]
t = np.arange(0.0, 53.0, 0.1)
#populate state information
state = odeint(ChuaDerivatives, state0, t)
# do some fancy 3D plotting
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(state[:,0],state[:,1],state[:,2])
ax.set_xlabel('V_1')
ax.set_ylabel('V_2')
ax.set_zlabel('I_3')
plt.show()

So I managed to work it out for myself after some fiddling; I was interpreting the odeint function wrong; more careful reading of the docstring and starting from scratch to stop me following a difficult method solved it. Code below:
import numpy as np
import scipy.integrate as integrate
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#define universal variables
c0 = 15.6
c1 = 1.0
c2 = 28.0
m0 = -1.143
m1 = -0.714
#just a little extra, quite unimportant
def f(x):
f = m1*x+(m0-m1)/2.0*(abs(x+1.0)-abs(x-1.0))
return f
#the actual function calculating
def dH_dt(H, t=0):
return np.array([c0*(H[1]-H[0]-f(H[0])),
c1*(H[0]-H[1]+H[2]),
-c2*H[1]])
#computational time steps
t = np.linspace(0, 30, 1000)
#x, y, and z initial conditions
H0 = [0.7, 0.0, 0.0]
H, infodict = integrate.odeint(dH_dt, H0, t, full_output=True)
print infodict['message']
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot(H[:,0], H[:,1], H[:,2])
plt.show()
Which gives me this:

Related

Runge Kutta constants diverging for Lorenz system?

I'm trying to solve the Lorenz system using the 4th order Runge Kutta method, where
dx/dt=a*(y-x)
dy/dt=x(b-z)-y
dx/dt=x*y-c*z
Since this system doesn't depend explicity on time, it's possibly to ignore that part in the iteration, so I just have
dX=F(x,y,z)
def func(x0):
a=10
b=38.63
c=8/3
fx=a*(x0[1]-x0[0])
fy=x0[0]*(b-x0[2])-x0[1]
fz=x0[0]*x0[1]-c*x0[2]
return np.array([fx,fy,fz])
def kcontants(f,h,x0):
k0=h*f(x0)
k1=h*f(f(x0)+k0/2)
k2=h*f(f(x0)+k1/2)
k3=h*f(f(x0)+k2)
#note returned K is a matrix
return np.array([k0,k1,k2,k3])
x0=np.array([-8,8,27])
h=0.001
t=np.arange(0,50,h)
result=np.zeros([len(t),3])
for time in range(len(t)):
if time==0:
k=kcontants(func,h,x0)
result[time]=func(x0)+(1/6)*(k[0]+2*k[1]+2*k[2]+k[3])
else:
k=kcontants(func,h,result[time-1])
result[time]=result[time-1]+(1/6)*(k[0]+2*k[1]+2*k[2]+k[3])
The result should be the Lorenz atractors, however my code diverges around the fifth iteration, and it's because the contants I create in kconstants do, however I checked and I'm pretty sure the runge kutta impletmentation is not to fault... (at least i think)
edit:
Found a similar post ,yet can't figure what I'm doing wrong
You have an extra call of f(x0) in the calculation of k1, k2 and k3. Change the function kcontants to
def kcontants(f,h,x0):
k0=h*f(x0)
k1=h*f(x0 + k0/2)
k2=h*f(x0 + k1/2)
k3=h*f(x0 + k2)
#note returned K is a matrix
return np.array([k0,k1,k2,k3])
Have you looked at different initial values for your calculation? Do the ones you've chosen make sense? I.e. are they physical? From past experience with rk you can sometimes get very confusing results if you pick silly starting parameters.
Goodnight. This and version I made using the scipy edo integrator, scipy.integrate.odeint.
# Author : Carlos Eduardo da Silva Lima
# Theme : Movement of a Plant around a fixed star
# Language : Python
# date : 11/19/2022
# Environment : Google Colab
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from scipy.optimize import root
from scipy.linalg import eig
from mpl_toolkits.mplot3d import Axes3D
##################################
# Condições inicial e parãmetros #
##################################
t_inicial = 0
t_final = 100
N = 10000
h = 1e-3
x_0 = 1.0
y_0 = 1.0
z_0 = 1.0
#####################
# Equação de Lorenz #
#####################
def Lorenz(r,t,sigma,rho,beta):
x = r[0]; y = r[1]; z = r[2]
edo1 = sigma*(y-x)
edo2 = x*(rho-z)-y
edo3 = x*y-beta*z
return np.array([edo1,edo2,edo3])
t = np.linspace(t_inicial,t_final,N)
r_0 = np.array([x_0,y_0,z_0])
#sol = odeint(Lorenz,r_0,t,rtol=1e-6,args = (10,28,8/3))
sol = odeint(Lorenz, r_0, t, args=(10,28,8/3), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None, rtol=1e-9, atol=1e-9, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0, tfirst=False)
'''x = sol[:,0]
y = sol[:,1]
z = sol[:,2]'''
x, y, z = sol.T
# Plot
plt.style.use('dark_background')
ax = plt.figure(figsize = (10,10)).add_subplot(projection='3d')
ax.plot(x,y,z,'m-',lw=0.5, linewidth = 1.5)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Atrator de Lorenz")
plt.show()
In this second part, I simulate two Lorenz systems to verify the sensitive dependencies of the systems to the initial conditions. In the second system, I add a certain amount of eps = 1e-3 to the initial conditions of x(t0), y(t0) and z(t0).
# Depedência com as condições iniciais
eps = 1e-3
r_0_eps = np.array([x_0+eps,y_0+eps,z_0+eps])
sol_eps = odeint(Lorenz, r_0_eps, t, args=(10,28,8/3), Dfun=None, col_deriv=0, full_output=0, ml=None, mu=None,
rtol=1e-9, atol=1e-9, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0, tfirst=False)
'''x_eps = sol_eps[:,0]
y_eps = sol_eps[:,1]
z_eps = sol_eps[:,2]'''
x_eps, y_eps, z_eps = sol_eps.T
# Plot
plt.style.use('dark_background')
ax = plt.figure(figsize = (10,10)).add_subplot(projection='3d')
ax.plot(x,y,z,'r-',lw=1.5)
ax.plot(x_eps,y_eps,z_eps,'b-.',lw=1.1)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Lorenz Attractor")
plt.show()
Hope I helped, see you :).

Solving an ODE Numerically with SciPy

I'm trying to find a numerical solution and eventually graph, the Gyllenberg-Webb model (cancer cell growth model). This model looks like:
Where β is the reproduction rate of proliferating cells, µp is the death rate of proliferating cells, µq is the death rate of quiescent cells, and r0 and ri are functions (transition rates) of N(t). Also N(t) = P(t)+Q(t).
For my purposes here I defined r_0(N) = bN and r_i(N) = aN to make things more simple.
My problem is when I try and plot my solution with pyplot I get
ValueError: x and y must have same first dimension
which I guess is self-explanatory, but I'm not sure how to go about fixing it without breaking everything else.
My code, which I've done only for the first equation so far, is:
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate
def fun(P,t, params):
beta, mp,b,N,Q = params
return(beta-mp-(b*N))*P+(a*N)*Q
params = (0.5,0.6,0.7,0.8,0.9)
tvec = np.arange(0,6,0.1)
s1 = scipy.integrate.odeint(
fun,
y0 = 1,
t = tvec,
args = (params,))
#print(s1)
plt.plot(fun,tvec)
In the end you will want to solve the coupled system. This is not complicated, just make the state object a vector and return the derivatives in the correct order.
def fun(state,t, params):
P, Q = state
beta, mp, mq, a, b = params
N = P+Q
r0N, riN = b*N, a*N
return [ (beta-mp-r0N)*P + riN*Q, r0N*P - (riN+mq)*Q ]
params = (0.5,0.6,0.7,0.8,0.9)
tsol = np.arange(0,6,0.1)
sol = odeint( fun, y0 = [ 1, 0], t = tsol, args = (params,))
Psol, Qsol = sol.T; plt.plot(tsol, Psol, tsol, Qsol)
You are currently plotting fun vs. tvec. What you actually want is to plot tvec vs s1. You will also have to define the parameter a in fun; I set it to 1 in the code below:
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate
def fun(P, t, params):
beta, mp, b, N, Q = params
return (beta-mp-(b*N))*P + (1.0 * N)*Q
params = (0.5, 0.6, 0.7, 0.8, 0.9)
tvec = np.arange(0, 6, 0.1)
s1 = scipy.integrate.odeint(
fun,
y0=1.,
t=tvec,
args=(params,))
plt.plot(tvec, s1)
plt.show()
This will plot:

How to integrate coupled differential equations?

I've got a system of equations that I've been tryin to get Python to solve and plot but the plot is not coming out right.
This is my code:
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
#function that returns dx/dt and dy/dt
def func(z,t):
for r in range(-10,10):
beta=2
gamma=0.8
c = z[0]
tau = z[1]
dcdt = r*c+c**2-c**3-beta*c*tau**2
dtaudt = -gamma*tau+0.5*beta*c*tau
return [dcdt,dtaudt]
#inital conditions
z0 = [2,0]
#time points
t = np.linspace(0,24,100)
#solve ODE
z = odeint(func,z0,t)
#seperating answers out
c = z[:,0]
tau = z[:,1]
print(z)
#plot results
plt.plot(t,c,'r-')
plt.plot(t,tau,'b--')
plt.legend(['c(t)','tau(t)'])
plt.show()
Let me explain. I am studying doubly diffusive convection. I din't want any assumptions to be made on the value of r, but beta and gamma are positive. So I thougt to assign values to them but not to r.
This is the plot I get and from understanding the problem, that the graph is not right. The tau plot should efinitely not be stuck on 0 and the c plot should be doing more. I am relitively new to Python and am taking courses but really want to understand what I've done wrong, so help in a simple language would be appreciated.
I see 2 problems in your function that you should check.
for r in range(-10,10):
Here you are doing a for loop just reevaluating dcdt and dtaudt. As a result, the output value is the same as just evaluating r=9 (last value in the loop)
dtaudt = -gamma*tau+0.5*beta*c*tau
Here you have dtaudt = tau*(beta*c/2. -gamma). Your choice tau[0]=0 implies that tau will remain 0.
Try this:
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
r = 1
beta=2
gamma=0.8
#function that returns dx/dt and dy/dt
def func(z,t):
c = z[0]
tau = z[1]
dcdt = r*c+c**2-c**3-beta*c*tau**2
dtaudt = -gamma*tau+0.5*beta*c*tau
print(dtaudt)
return [dcdt,dtaudt]
#inital conditions
z0 = [2,0.2] #tau[0] =!0.0
#time points
t = np.linspace(0,24,100)
#solve ODE
z = odeint(func,z0,t)
#seperating answers out
c = z[:,0]
tau = z[:,1]
#plot results
plt.plot(t,c,'r-')
plt.plot(t,tau,'b--')
plt.legend(['c(t)','tau(t)'])
plt.show()

Plotting Sympy Result to Particular Solution of Differential Equation

So far I have managed to find the particular solution to this equation for any given mass and drag coefficient. I have not however found a way to plot the solution or even evaluate the solution for a specific point. I really want to find a way to plot the solution.
from sympy import *
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t:0}),C1)[0]
equation = equation.subs({C1:C1_ic})
For completeness, you may also use Sympy's plot, which is probably more convenient if you want a "quick and dirty" plot.
plot(equation.rhs,(t,0,10))
Import these libraries (seaborn just makes the plots pretty).
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
Then tack this onto the end. This will plot time, t, against velocity, v(t).
# make a numpy-ready function from the sympy results
func = lambdify(t, equation.rhs,'numpy')
xvals = np.arange(0,10,.1)
yvals = func(xvals)
# make figure
fig, ax = plt.subplots(1,1,subplot_kw=dict(aspect='equal'))
ax.plot(xvals, yvals)
ax.set_xlabel('t')
ax.set_ylabel('v(t)')
plt.show()
I get a plot like this for a mass of 2 and a drag coefficient of 2.
If I've understood correctly, you want to represent the right hand side of your solution, here's one of the multiple ways to do it:
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
m = float(raw_input('Mass:\n> '))
g = 9.8
k = float(raw_input('Drag Coefficient:\n> '))
f = Function('f')
f1 = g * m
t = Symbol('t')
v = Function('v')
equation = dsolve(f1 - k * v(t) - m * Derivative(v(t)), 0)
C1 = Symbol('C1')
C1_ic = solve(equation.rhs.subs({t: 0}), C1)[0]
equation = equation.subs({C1: C1_ic})
t1 = np.arange(0.0, 50.0, 0.1)
y1 = [equation.subs({t: tt}).rhs for tt in t1]
plt.figure(1)
plt.plot(t1, y1)
plt.show()

Loop and bifurcation diagram

I'm writing a script which plots the bifurcation diagram of a damped pendulum with a small direct forcing.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
epsi = 0.01
# Declare the model
f_dir = np.arange(0,1.3,0.01)
A_s = np.zeros(len(f_dir))
i = 0
for f in f_dir:
def myModel(y, t):
dy0 = y[1]
dy1 = -epsi*y[1]-np.sin(y[0]) - f*np.cos((1.01)*t)*np.cos(y[0])
return [dy0, dy1]
time = np.arange(0.0, 2000,0.01)
yinit = np.array([np.pi/2, 0])
y = odeint(myModel, yinit, time)
A_s.insert(i,np.abs(np.max(y[-600:-1,0])- np.min(y[-600:-1,0])))
i += 1
plt.plot(f_dir,A_s,'*')
plt.xlabel(r'$f_s$')
plt.ylabel(r'$A_s$')
plt.hold
plt.show()
The problem is that I am not inserting anything into A_s, and I do not know why because the variable i is increased at each step of the loop.
It's a little hard to follow your code, but this is probably closer to what you want. You only need to define your model once, even if f is a variable argument: you can pass such arguments to odeint in the args tuple and they get handed on to the model function.
Also note that NumPy arrays don't have an insert method.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
epsi = 0.01
# Declare the model
f_dir = np.arange(0,1.3,0.01)
A_s = np.zeros(len(f_dir))
def myModel(y, t, f):
dy0 = y[1]
dy1 = -epsi*y[1]-np.sin(y[0]) - f*np.cos((1.01)*t)*np.cos(y[0])
return [dy0, dy1]
i = 0
for f in f_dir:
time = np.arange(0.0, 2000,0.01)
yinit = np.array([np.pi/2, 0])
y = odeint(myModel, yinit, time, args=(f,))
A_s[i] = np.abs(np.max(y[-600:-1,0])- np.min(y[-600:-1,0]))
i += 1
plt.plot(f_dir,A_s,'*')
plt.xlabel(r'$f_s$')
plt.ylabel(r'$A_s$')
plt.hold
plt.show()
You defined the myModel function, but it's not actually being called anywhere - it's just referenced from within the function itself.

Categories