I am trying to plot the phase potrait for the equation as defined in my sh2 function in the code below. I know the expected phase plot should be [[expected phase plot][1]][1] [1]: https://i.stack.imgur.com/y1T9Y.png.
However this is my result: [[result][1]: https://i.stack.imgur.com/EuSOm.png.
I am using integrate.odeint can anyone suggest what I could change in the could below or if there would be best to use another algorithm that would give me a closer result to th expected.
Please find my code :
import matplotlib.pyplot as plt
import numpy as np
from numpy import sin
import scipy.integrate as integrate
from math import *
g = 9.81
l = 1.6
l_big = 2.0
l_small = 1.6
m = 0.01
alpha = l_big-l_small
k = 10*(10**40)
def sh2(r1,t):
theta1,omega1 = r1
sh2_theta1 = omega1
sh2_omega1 = -g*(l + ((1/2)*alpha*(1-np.tanh(theta1*omega1*k))))*sin(theta1)
return np.array([sh2_theta1, sh2_omega1],float)
init_state = np.radians([30.0,0])
dt = 1/10.0
time = np.arange(0,10.0,dt)
timexo = np.arange(0,10.0,dt)
state2 = integrate.odeint(sh2,init_state,time)
print(len(state2),len(timexo))
state2_plot = np.transpose(state2[0:2500])
plt.plot(timexo[0:2500],state2_plot[1], '--m', label = r'$\theta = \frac{\pi}{6}$')
plt.xlabel('Time t (s) ')
plt.ylabel('Angular Velocity' ' ' r'$\dot{\theta}$')
plt.show()
#code for phase plot
# initial values
x_0 = 0.0 # intial angular position
v_0 = 1.0 # initial angular momentum
t_0 = 0 # initial time
# initial y-vector from initial position and momentum
y0 = np.array([x_0,v_0])
# max value of time and points in time to integrate to
t_max = 10
N_spacing_in_t = 10000
# create vector of time points you want to evaluate
t = np.linspace(t_0,t_max,N_spacing_in_t)
# create vector of positions for those times
y_result = integrate.odeint(sh2, init_state, t)
# get angle and angular momentum
angle = y_result[:,0]
angular_velocity = y_result[:,1]
# plot result
fig = plt.figure()
plt.plot(angle, angular_velocity,'--k',lw=1)
plt.xlabel('Angle' ' ' r'$\theta$')
plt.ylabel(r'Angular Velocity' r' $\dot{\theta}$')
plt.gcf().savefig('pumping.png',dpi=300)
plt.show()
Thank you for tour time
Related
I would like to use GEKKO to incrementally solve a dynamic model. I need to insert some parameters at different points in the simulation that are determined stochastically using an external model.
As a simple proof of concept, I tried adjusting the PID control example from the tutorial website to solve in 10 minute increments.
m = GEKKO()
tf = 40
timesteps = np.linspace(0,tf,2*tf+1)
step = np.zeros(2*tf+1)
step[3:40] = 2.0
step[40:] = 5.0
# Controller model
Kc = 15.0 # controller gain
tauI = 2.0 # controller reset time
tauD = 1.0 # derivative constant
OP_0 = m.Const(value=0.0) # OP bias
OP = m.Var(value=0.0) # controller output
PV = m.Var(value=0.0) # process variable
SP = m.Param(value=step) # set point
Intgl = m.Var(value=0.0) # integral of the error
err = m.Intermediate(SP-PV) # set point error
m.Equation(Intgl.dt()==err) # integral of the error
m.Equation(OP == OP_0 + Kc*err + (Kc/tauI)*Intgl - PV.dt())
# Process model
Kp = 0.5 # process gain
tauP = 10.0 # process time constant
m.Equation(tauP*PV.dt() + PV == Kp*OP)
setpoint_final = []
pv_final = []
output_final = []
for i in range(8):
SP.value = step[10*i:10*(i+1)]
m.time = timesteps[10*i:10*(i+1)]
m.options.IMODE=7
m.solve(disp=False)
setpoint_final.append(SP.value)
pv_final.append(PV.value)
output_final.append(OP.value)
plt.figure()
plt.subplot(2,1,1)
plt.plot(timesteps[:-1],np.concatenate(output_final),'b:',label='OP')
plt.ylabel('Output')
plt.legend()
plt.subplot(2,1,2)
plt.plot(timesteps[:-1],np.concatenate(setpoint_final),'k-',label='SP')
plt.plot(timesteps[:-1],np.concatenate(pv_final),'r--',label='PV')
plt.xlabel('Time (sec)')
plt.ylabel('Process')
plt.legend()
plt.show()
I should get something like this:
Instead it seems to reset at each interval:
Is there something I am missing or is this type of simulation not possible in GEKKO?
Try using m.options.TIME_SHIFT=10, m.options.IMODE=4, and change the way the values are stored.
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
m = GEKKO(remote=False)
tf = 40
timesteps = np.linspace(0,tf,2*tf+1)
step = np.zeros(2*tf+1)
step[3:40] = 2.0
step[40:] = 5.0
# Controller model
Kc = 15.0 # controller gain
tauI = 2.0 # controller reset time
tauD = 1.0 # derivative constant
OP_0 = m.Const(value=0.0) # OP bias
OP = m.Var(value=0.0) # controller output
PV = m.Var(value=0.0) # process variable
SP = m.Param(value=step) # set point
Intgl = m.Var(value=0.0) # integral of the error
err = m.Intermediate(SP-PV) # set point error
m.Equation(Intgl.dt()==err) # integral of the error
m.Equation(OP == OP_0 + Kc*err + (Kc/tauI)*Intgl - PV.dt())
# Process model
Kp = 0.5 # process gain
tauP = 10.0 # process time constant
m.Equation(tauP*PV.dt() + PV == Kp*OP)
setpoint_final = []
pv_final = []
output_final = []
m.options.TIME_SHIFT=10
m.time = timesteps[0:10]
for i in range(8):
SP.value = step[10*i:10*(i+1)]
m.options.IMODE=4
m.solve(disp=False)
setpoint_final = np.concatenate((setpoint_final,SP.value))
pv_final = np.concatenate((pv_final,PV.value))
output_final = np.concatenate((output_final,OP.value))
plt.figure()
plt.subplot(2,1,1)
plt.plot(timesteps[:-1],output_final,'b:',label='OP')
plt.ylabel('Output')
plt.legend()
plt.subplot(2,1,2)
plt.plot(timesteps[:-1],setpoint_final,'k-',label='SP')
plt.plot(timesteps[:-1],pv_final,'r--',label='PV')
plt.xlabel('Time (sec)')
plt.ylabel('Process')
plt.legend()
plt.show()
I'm trying to resolve a nonlinear PDE Schrödinger equation with the split-step Fourier pseudo-spectral method. The fonction "solver" is supposed to solve the time and space dependant equation with the split-step method but it gives values oscillating between 0.49 and 0.51 instead of the good answer which is between 0 and 1.657 (see here).
What should I change to get the good result?
import numpy as np
from matplotlib import pyplot as plt
i = np.complex(0,1)
K = 1
dt = 0.01 #temps
t = np.arange(0,20,dt)
N = 1024#espace
x = np.linspace(-20,20,N) #domaine truncated
L = 40
dx = L/N
k =np.linspace(-N/2,N/2-1,N)
def solver(x,t):
F = []
psi = 0.5 +0.01*np.cos(2*np.pi*x/40)
for l in range(len(t)):
g = np.exp(-i*K*(np.abs(psi))*dt)*psi
fg = np.fft.fftshift((np.fft.fft(g)))
fpsi = np.exp(-i/2*(2*np.pi*k/L)**2*dt)*fg
psi = np.fft.ifft(fpsi)
F.append(psi)
return F
M = np.abs(solver(x,t))
print(M)
#plt.plot(x,M)
#plt.show()
fig = plt.figure(figsize=(10,10))
ax1 = fig.add_subplot()
m1 = ax1.matshow(M)
plt.title("")
fig.colorbar(m1)
ax1.set_xlabel('espace')
ax1.set_ylabel('temps')
enter image description here
I am trying to plot the relationship between period and amplitude for an undamped and undriven pendulum for when small angle approximation breaks down, however, my code did not do what I expected...
I think I should be expecting a strictly increasing graph as shown in this video: https://www.youtube.com/watch?v=34zcw_nNFGU
Here is my code, I used zero crossing method to calculate period:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
from itertools import chain
# Second order differential equation to be solved:
# d^2 theta/dt^2 = - (g/l)*sin(theta) - q* (d theta/dt) + F*sin(omega*t)
# set g = l and omega = 2/3 rad per second
# Let y[0] = theta, y[1] = d(theta)/dt
def derivatives(t,y,q,F):
return [y[1], -np.sin(y[0])-q*y[1]+F*np.sin((2/3)*t)]
t = np.linspace(0.0, 100, 10000)
#initial conditions:theta0, omega0
theta0 = np.linspace(0.0,np.pi,100)
q = 0.0 #alpha / (mass*g), resistive term
F = 0.0 #G*np.sin(2*t/3)
value = []
amp = []
period = []
for i in range (len(theta0)):
sol = solve_ivp(derivatives, (0.0,100.0), (theta0[i], 0.0), method = 'RK45', t_eval = t,args = (q,F))
velocity = sol.y[1]
time = sol.t
zero_cross = 0
for k in range (len(velocity)-1):
if (velocity[k+1]*velocity[k]) < 0:
zero_cross += 1
value.append(k)
else:
zero_cross += 0
if zero_cross != 0:
amp.append(theta0[i])
# period calculated using the time evolved between the first and last zero-crossing detected
period.append((2*(time[value[zero_cross - 1]] - time[value[0]])) / (zero_cross -1))
plt.plot(amp,period)
plt.title('Period of oscillation of an undamped, undriven pendulum \nwith varying initial angular displacemnet')
plt.xlabel('Initial Displacement')
plt.ylabel('Period/s')
plt.show()
enter image description here
You can use the event mechanism of solve_ivp for such tasks, it is designed for such "simple" situations
def halfperiod(t,y): return y[1]
halfperiod.terminal=True # stop when root found
halfperiod.direction=1 # find sign changes from negative to positive
for i in range (1,len(theta0)): # amp==0 gives no useful result
sol = solve_ivp(derivatives, (0.0,100.0), (theta0[i], 0.0), method = 'RK45', events =(halfperiod,) )
if sol.success and len(sol.t_events[-1])>0:
period.append(2*sol.t_events[-1][0]) # the full period is twice the event time
amp.append(theta0[i])
This results in the plot
I'm going through Strogatz's Nonlinear Dynamics and Chaos and I've hit a snag in chapter 2 Exercise 2.8.1. (Educator flag: I've graduated so this isn't for a class, I'm just trying to get back into the numerical solving of differential equations) It's a pretty simple differential equation and I can plot individual solution curves given different initial conditions but I'm trying to use quiver or streamplot to superimpose individual solutions on top of the vector field.
My problem is in understanding how to translate the vector field plots for similar problems in the dy/dx form found here over to the dx/dt form that's primarily tackled in Strogatz's book.
Given that the x vector that's defined in the logistic function is only one dimensional I'm having a hard time reasoning out how express the u and v flows in quiver or streamplot since the problem only seems to have a u flow. It's probably super easy and is being over-thought but any guidance or assistance would be much appreciated!
So far I have the following:
# 2.8.1
# Plot the vector field and some trajectories for xdot = x(1-x) given
# some different initial conditions for the logistic equation with carrying
# capacity K = 1
# dx/dt = x(1-x)
# Imports:
from __future__ import division
from scipy import *
import numpy as np
import pylab
import matplotlib as mp
from matplotlib import pyplot as plt
import sys
import math as mt
def logistic(x,t):
return np.array([x[0]*(1-x[0])])
def RK4(t0 = 0, x0 = np.array([1]), t1 = 5 , dt = 0.01, ng = None):
tsp = np.arange(t0, t1, dt)
Nsize = np.size(tsp)
X = np.empty((Nsize, np.size(x0)))
X[0] = x0
for i in range(1, Nsize):
k1 = ng(X[i-1],tsp[i-1])
k2 = ng(X[i-1] + dt/2*k1, tsp[i-1] + dt/2)
k3 = ng(X[i-1] + dt/2*k2, tsp[i-1] + dt/2)
k4 = ng(X[i-1] + dt*k3, tsp[i-1] + dt)
X[i] = X[i-1] + dt/6*(k1 + 2*k2 + 2*k3 + k4)
return X
def tplot():
t0 = 0
t1 = 10
dt = 0.02
tsp = np.arange(t0,t1,dt)
X = RK4(x0 = np.array([2]), t1 = 10,dt = 0.02, ng = logistic)
Y = RK4(x0 = np.array([0.01]), t1 = 10,dt = 0.02, ng = logistic)
Z = RK4(x0 = np.array([0.5]), t1 = 10,dt = 0.02, ng = logistic)
P = RK4(x0 = np.array([3]), t1 = 10,dt = 0.02, ng = logistic)
Q = RK4(x0 = np.array([0.1]), t1 = 10,dt = 0.02, ng = logistic)
R = RK4(x0 = np.array([1.5]), t1 = 10,dt = 0.02, ng = logistic)
O = RK4(x0 = np.array([1]), t1 = 10,dt = 0.02, ng = logistic)
pylab.figure()
pylab.plot(tsp,X)
pylab.plot(tsp,Y)
pylab.plot(tsp,Z)
pylab.plot(tsp,P)
pylab.plot(tsp,Q)
pylab.plot(tsp,R)
pylab.plot(tsp,O)
pylab.title('Logistic Equation - K=1')
pylab.xlabel('Time')
pylab.ylabel('Xdot')
pylab.show()
print tplot()
image here
To graph a slope from a derivative (like, dx/dt), you can first find dx/dt, and then use a fixed dt to calculate dx. Then, at each (t, x) of interest, plot the little line segment from (t,x) to (t+dt, x+dx).
Here's an example for your equation dx/dt = x(1-x). (The Strogatz picture doesn't have arrowheads so I removed them too.)
import numpy as np
import matplotlib.pyplot as plt
times = np.linspace(0, 10, 20)
x = np.linspace(0 ,2, 20)
T, X = np.meshgrid(times, x) # make a grid that roughly matches the Strogatz grid
dxdt = X*(1-X) # the equation of interest
dt = .5*np.ones(X.shape) # a constant value (.5 is just so segments don't run into each other -- given spacing of times array
dx = dxdt * dt # given dt, now calc dx for the line segment
plt.quiver(T, X, dt, dx, headwidth=0., angles='xy', scale=15.)
plt.show()
wonkybadonk: For the difference in slope of the plotted trajectories and the plotted vector field seem to be due to the fact that your vector field are not steep enough. Make sure that
dx = dxdt*dt; (point by point multiplication, not a dot product)
and that you added "angles='xy'" as a quiver argument. (see tom10 post).
I am attempting to model a 1D wave created by a Gaussian point source using the finite difference approximation method. Below is my code.
import matplotlib.pyplot as plt
import numpy as np
########Pre-Defining Values########
# spacial extent
lox = -1000
upx = 1000
# space sampling interval (km)
dx = 2.0
dx2inv = 1/(dx*dx)
# temporal extent
lot = 0
upt = 60
# time sampling interval (s)
dt = 0.5
dt2 = dt*dt
x = np.arange(lox,upx,dx)
t = np.arange(lot,upt,dt)
# pressure source location
psx = 0
# velocity (km/s)
v = 2.0
v2 = v*v
# density change location
pcl = 500
# density
p1 = 1
p1inv = 1/p1
p2 = 0.2
p2inv = 1/p2
pinv = np.zeros_like(x)
p = np.zeros_like(x)
for i in range(0,(int)((upx+pcl)/dx),1):
pinv[i] = p1inv
p[i] = p1
for i in range((int)((upx+pcl)/dx),len(pinv),1):
pinv[i] = p2inv
p[i] = p2
# waveform
f = np.zeros((len(t),len(x)))
# source
amp = 20
mu = 0
sig = 10/dx
s = np.zeros_like(f)
s[0] = 1/(sig*np.sqrt(2*np.pi)) * np.exp(-(x-mu)*(x-mu)/2/sig/sig)
maxinv = 1/np.amax(s[0])
for i in range(1,len(s[0])):
s[0][i] *= amp*maxinv
########Calculating Waveform########
h = np.zeros_like(f)
n1 = len(f)
n2 = len(f[0])
def fdx(i1):
for i2 in range(1,n2-1):
gi = f[i1][i2 ]
gi -= f[i1][i2-1]
gi *= pinv[i2]
h[i1][i2-1] -= gi
h[i1][i2 ] = gi
#f[0] = s[0]
fdx(0)
for i2 in range(0,n2):
f[1][i2] = 2*f[0][i2] + (s[0][i2] - h[0][i2] * dx2inv) * p[i2] * v2 * dt2
for i1 in range(1,n1-1):
fdx(i1)
for i2 in range(0,n2):
f[i1+1][i2] = 2*f[i1][i2] - f[i1-1][i2] + (s[i1][i2] - h[i1][i2] * dx2inv) * p[i2] * v2 * dt2
########Plotting########
plt.plot(x,f[50])
maxf = 1.5*amp
minf = -1.5*amp
plt.axis([lox,upx,minf,maxf])
plt.xlabel('x')
plt.ylabel('f(x,t)')
# vertical colored bars representing density
plt.axvspan(lox, pcl, facecolor='g', alpha=0.1)
plt.axvspan(pcl, upx, facecolor='g', alpha=0.2)
# text with density values
plt.text(pcl-0.2*upx,0.8*maxf,r'$\rho = $%s'%(p1),fontsize=15)
plt.text(pcl+0.05*upx,0.8*maxf,r'$\rho = $%s'%(p2),fontsize=15)
plt.show()
Unfortunately this code does not produce the correct result (two Gaussian pulses traveling left and right away from x=0). It instead produces one Gaussian pulse that grows with time. Does anyone know what error I am making?
Thank you very much.
It has been some time since you posted this, but if it is of any help, here is a code to generate Gaussian pulses. I am not good at programming so i am sorry if this code is obfuscating. I have used 1D FDTD wave propagation equation for an EM wave (unitless) :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#defining dimensions
xdim=720
time_tot = 500
xsource = xdim/2
#stability factor
S=1
#Speed of light
c=1
epsilon0=1
mu0=1
delta =1
deltat = S*delta/c
Ez = np.zeros(xdim)
Hy = np.zeros(xdim)
epsilon = epsilon0*np.ones(xdim)
mu = mu0*np.ones(xdim)
fig , axis = plt.subplots(1,1)
axis.set_xlim(len(Ez))
axis.set_ylim(-3,3)
axis.set_title("E Field")
line, = axis.plot([],[])
def init():
line.set_data([],[])
return line,
def animate(n, *args, **kwargs):
Hy[0:xdim-1] = Hy[0:xdim-1]+(delta/(delta*mu[0:xdim-1]))*(Ez[1:xdim]-Ez[0:xdim-1])
Ez[1:xdim]= Ez[1:xdim]+(delta/(delta*epsilon[1:xdim]))*(Hy[1:xdim]-Hy[0:xdim-1])
Ez[xsource] = Ez[xsource] + 30.0*(1/np.sqrt(2*np.pi))*np.exp(-(n-80.0)**2/(100))
ylims = axis.get_ylim()
if (abs(np.amax(Ez))>ylims[1]):
axis.set_ylim(-(np.amax(Ez)+2),np.amax(Ez)+2)
line.set_data(np.arange(len(Ez)),Ez)
return line,
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=(time_tot), interval=10, blit=False, repeat =False)
fig.show()
I hope it helps. :)