This is the gist of what I need to do: in python, I have a parametric function f(x(t,omega),y(t,omega)) where omega has five specific values (at non-regular intervals). What I want to do is basically plot this function f on the same plot for each of the five values of omega.
Now, I have a working code for this but I think that it could be more concise (and I'm very interested in knowing HOW it could be more concise, because I want to learn as much as I can about python from this exercise), and also, I can't figure out how to fix the range of x(t,omega) here! This last point is the most problematic.
Here is my "working" code:
x=linspace(0,10,100)
H0=71
omega0=1.01
Rc=0.5*(omega0/(omega0-1))*(1-cos(x))
tc=(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x))
plot(tc,Rc)
omega0=1.1
Rc=0.5*(omega0/(omega0-1))*(1-cos(x))
tc=(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x))
plot(tc,Rc)
omega0=1.5
Rc=0.5*(omega0/(omega0-1))*(1-cos(x))
tc=(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x))
plot(tc,Rc)
omega0=2.0
Rc=0.5*(omega0/(omega0-1))*(1-cos(x))
tc=(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x))
plot(tc,Rc)
omega0=3.0
Rc=0.5*(omega0/(omega0-1))*(1-cos(x))
tc=(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x))
plot(tc,Rc)
show()
as you can see, tc and Rc serve as my x(t,omega) and y(t,omega) and I've used x as my parametric variable, because...well, I already have a t in the form of tc. If you plot this you'll see that it's difficult to get much information out of it even though all the lines are technically there. Any help is much appreciated!
EDIT: I got what I needed. For anyone coming across this thread because they have similar issues, my revised code thanks in large part to the below answer and some further searching is:
import numpy as np
import pylab as pl
from pylab import *
x=linspace(0,50,1000)
H0=71 #units km/s/Mpc
omegas = [1.01,1.1,1.5,2.0,3.0]
Rcs = [0.5*(omega0/(omega0-1))*(1-cos(x)) for omega0 in omegas]
tcs = [(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x)) for omega0 in omegas]
for pair in zip(tcs,Rcs):
pl.plot(pair[0],pair[1])
pl.xlim(0,0.55)
pl.ylim(0,60)
pl.show()
The most apparent way to reduce redundancy in your code is to use a for loop or list comprehension:
x=linspace(0,10,100)
H0 = 71
omegas = [1.01,1.1,1.5,2.0,3.0]
rcs = [0.5*(omega0/(omega0-1))*(1-cos(x)) for omega0 in omegas]
tcs = [(0.5/H0)*(omega0/(omega0-1)**(3/2))*(x-sin(x)) for omega0 in omegas]
for pair in zip(tcs,rcs):
plot(pair[0],pair[1])
show()
Related
I am working in a RK4 orbital propagator, and I have followed the basic structure of:
k1=dt×f(tn,yn)
k2=dt×f(tn+dt/2,yn+k1/2)
k3=dt×f(tn+dt/2,yn+k2/2)
k4=dt×f(tn+dt,yn+k3)
yn+1=yn+1/6(k1+2k2+2k3+k4)
tn+1=tn+dt
I have bassed this procces in a simpler one, created by me for RK1 implementation:
#NOTE: sat is an array with the structure [x,y,z,vx,vy,vz,ax,ay,az]
def pasosimple(sat,dt):
#physics constants
G = 6.6742e-20
m_s = 1.989e30
mu=G*m_s
#Position Change from previous values of velocity and acceleration
dx=sat[3]*dt+sat[6]*(dt**2)/2
dy=sat[4]*dt+sat[7]*(dt**2)/2
dz=sat[5]*dt+sat[8]*(dt**2)/2
#Velocity change due to previous acceleration
dvx=sat[6]*dt
dvy=sat[7]*dt
dvz=sat[8]*dt
#xyz update
x=dx+sat[0]
y=dy+sat[1]
z=dz+sat[2]
#With the xyz update, we calculate new accelerations
ax=(-mu*(x)/(np.sqrt((x)**2+(y)**2+(z)**2)**3))
ay=(-mu*(y)/(np.sqrt((x)**2+(y)**2+(z)**2)**3))
az=(-mu*(z)/(np.sqrt((x)**2+(y)**2+(z)**2)**3))
#Substraction to obtain the difference acceleration
dax=ax-sat[6]
day=ay-sat[7]
daz=az-sat[8]
dsat=np.array([dx,dy,dz,dvx,dvy,dvz,dax,day,daz])
sat=np.array([x,y,z,dvx+sat[3],dvy+sat[4],dvz+sat[5],ax,ay,az])
return dsat,sat
This code works, as far as I know, and I have already tested it.
Now, for imlementing the RK4, I'm doing this:
def rk4(sat,dt):
d1,s1=pasosimple(sat,dt)
d2,s2=pasosimple(sat+d1/2,dt+0.5*dt)
d3,s3=pasosimple(sat+d2/2,dt+0.5*dt)
d4,s4=pasosimple(sat+d3,dt+dt)
sat=sat+(1/6)*(d1+d2*2+d3*2+d4)
return sat
Which does not work.
I was hoping that anyone could give some insight about what i am doing wrong.
Thank you all.
EDIT:
I have tried this alternate configuration for pasosimple, following (or trying to follow) the comments below. The result did not work either. However, using only the new pasosimple code and not nesting it into rk4works nicely, which makes me think the problem is now in rk4.
def pasosimple(sat,dt):
G = 6.6742e-20
m_t=5.972e24
m_s = 1.989e30
m_m=6.39e23
mu=G*m_s
mu_t=G*m_t
mu_m=G*m_m
ax=(-mu*(sat[0])/(np.sqrt((sat[0])**2+(sat[1])**2+(sat[2])**2)**3))
ay=(-mu*(sat[1])/(np.sqrt((sat[0])**2+(sat[1])**2+(sat[2])**2)**3))
az=(-mu*(sat[2])/(np.sqrt((sat[0])**2+(sat[1])**2+(sat[2])**2)**3))
x_punto=np.array([sat[3],sat[4],sat[5],ax,ay,az])
x=np.array([sat[0]+x_punto[0]*dt,sat[1]+x_punto[1]*dt,sat[2]+x_punto[2]*dt,sat[3]+x_punto[3]*dt,sat[4]+x_punto[4]*dt,sat[5]+x_punto[5]*dt])
dsat=np.array([x_punto[0]*dt,x_punto[1]*dt,x_punto[2]*dt,x_punto[3]*dt,x_punto[4]*dt,x_punto[5]*dt,ax-sat[6],ay-sat[7],ay-sat[8]])
sat=np.array([x[0],x[1],x[2],x[3],x[4],x[5],ax,ay,az])
return dsat,sat
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am using a while loop to integrate various quantities from the surface of a star inwards using appropriate boundary conditions and stellar structure equations.
I am using dictionaries to represent physical variables such as pressure and density, where the plan is for the radii to be keys, and the value to be the pressure or density.
I have a key:value pair for the surface, and then I step inwards iteratively using a while loop updating the dictionaries as below:
import constants
import math
import matplotlib.pyplot as plt
mass=3*constants.solar_mass
radius=1.5*constants.solar_radius
#Variables to guess
core_temperature=1.4109*10**7
core_pressure= 2.6851*10**14
luminosity=pow(3,3.5)*constants.solar_luminosity
#Functions we are searching for
temperature={}
#guess
temperature[0]=core_temperature
#From the steffan boltzmann law
temperature[radius]=pow(luminosity/(4*math.pi*pow(radius,2)*constants.stefan_boltzmann_constant),0.25)
pressure={}
#guess
pressure[0]=core_pressure
#Pressure surface boundary condition
pressure[radius]=(2*constants.gravitation_constant*mass)/(3*constants.opacity*pow(radius,2))
mass_enclosed={}
#boundary conditions
mass_enclosed[0]=0
mass_enclosed[radius]=mass
density={}
#density surface boundary condition
density[radius]=(constants.mean_molecular_weight*pressure[radius])/(constants.gas_constant*temperature[radius])
delta_radius=int(radius/100)
#Polytropic constant
K=(pressure[radius]*constants.mean_molecular_weight)/(constants.gas_constant*pow(density[radius],constants.adiabatic_constant))
def integrate_from_surface():
i=0
while radius-i*delta_radius>(0.5*radius):
#temporary radius just for each loop through
r=radius-i*delta_radius
#updating pressure
pressure[r-delta_radius]=pressure[r]+(density[r]*constants.gravitation_constant*mass_enclosed[r]*delta_radius)/pow(r,2)
#updating density
density[r-delta_radius]=pow((pressure[r-delta_radius]*constants.mean_molecular_weight)/(constants.gas_constant*K),1.0/constants.adiabatic_constant)
#updating mass enclosed
mass_enclosed[r-delta_radius]=mass_enclosed[r]-4*math.pi*pow(r,2)*delta_radius*density[r]
i=i+1
integrate_from_surface()
While Loop: Radius and dictionaries are defined above
I am getting a KeyError, as shown below:
Traceback (most recent call last):
File "main.py", line 63, in <module>
integrate_from_surface()
File "main.py", line 51, in integrate_from_surface
pressure[r-delta_radius]=pressure[r]+(density[r]*constants.gravitation_constant*mass_enclosed[r]*delta_radius)/pow(r,2)
KeyError: 1043966868.09
KeyError message
If I print out the variable r in the while group, the process works perfectly until r is 1043966868.09. I do not understand, surely on the previous iteration I made this a key, so there should be no KeyError.
Constants file below:
solar_mass=1.9891*10**30
solar_radius=6.9598*10**8
solar_luminosity=3.8515*10**26
gas_constant=8.3145*10**3
gravitation_constant=6.6726*10**-11
radiation_constant=7.5646*10**-16
speed_of_light=2.9979*10**8
stefan_boltzmann_constant= radiation_constant*speed_of_light * 0.25
opacity=0.034
adiabatic_constant = 5.0/3
mean_molecular_weight = 8.0/13
Thanks in advance for any help.
As I stated in the comments, this behaviour is probably linked to the difficulty of hashing floats. In the end, using floats as dictionary keys is only as precise as your float precision. There are already extensive articles about the consequences and mechanisms at work here, for instance this one.
As an example (credits to the aforementioned article), you can see that hash(10-9.8) == hash(.2) returns False : using such keys in a dictionnary would create two entries.
A workaround (if you want to stick to float keys) would be to first evaluate all possible keys, then reuse those as many time as needed.
There is another good reason for this approch, as you will have to rewrite your "while loop" and replace it with a "for loop" : while loops are slower than for loops (more hints in here).
In your case, you could evaluate your steps this way :
radiuses = [radius-i*delta_radius for i in range(1,50)]
Afterwards, switching the loop iteration is very straightforward (for r in radiuses:). And more to the point, your code won't raise any exception.
Note that you could also store all your datas in a pandas.DataFrame, combining the way of accessing you steps by order (using .iloc) or by radius (using .loc).
That could be used this way (note that I'm storing all intermediate results in lists rather than dictionaries, this is in relation with the pandas.DataFrame constructor ) :
import math
import pandas as pd
SOLAR_MASS = 1.9891*10**30
SOLAR_RADIUS = 6.9598*10**8
SOLAR_LUMINOSITY = 3.8515*10**26
RADIATION_CONSTANT = 7.5646*10**-16
SPEED_OF_LIGHT = 2.9979*10**8
STEFAN_BOLTZMANN = RADIATION_CONSTANT * SPEED_OF_LIGHT * 0.25
OPACITY = 0.034
GRAVITATION_CONSTANT = 6.6726*10**-11
MEAN_MOLECULAR_WEIGHT = 8.0/13
GAS_CONSTANT = 8.3145*10**3
ADIABATIC_CONSTANT = 5.0/3
mass=3*SOLAR_MASS
radius=1.5*SOLAR_RADIUS
luminosity=(3**3.5)*SOLAR_LUMINOSITY
TEMPERATURE_R = (luminosity/(4*math.pi*(radius**2)*STEFAN_BOLTZMANN))**0.25
PRESSURE_R = (2*GRAVITATION_CONSTANT*mass)/(3*OPACITY*(radius**2))
MASS_R = mass
DENSITY_R = (MEAN_MOLECULAR_WEIGHT*PRESSURE_R)/(GAS_CONSTANT*TEMPERATURE_R)
K=(PRESSURE_R*MEAN_MOLECULAR_WEIGHT)/(GAS_CONSTANT*DENSITY_R**ADIABATIC_CONSTANT)
def integrate_from_surface_df():
delta_radius=int(radius/100)
pressure=[PRESSURE_R]
mass_enclosed=[MASS_R]
density=[DENSITY_R]
radiuses = [radius-i*delta_radius for i in range(1,50)]
for r in radiuses:
pressure.append(pressure[-1]+(density[-1]*GRAVITATION_CONSTANT*mass_enclosed[-1]*delta_radius)/r**2)
density.append(((pressure[-2]*MEAN_MOLECULAR_WEIGHT)/(GAS_CONSTANT*K))**(1.0/ADIABATIC_CONSTANT))
mass_enclosed.append(mass_enclosed[-1]-4*math.pi*r**2*delta_radius*density[-2])
df = pd.DataFrame({"pressure":pressure, "density":density, "mass_enclosed":mass_enclosed}, index=[radius]+radiuses)
return df
print(integrate_from_surface_df())
Which would return :
pressure density mass_enclosed
1.043970e+09 7.163524e+03 0.000043 5.967300e+30
1.033530e+09 1.743478e+05 0.000043 5.967300e+30
1.023091e+09 3.449615e+05 0.000292 5.967300e+30
1.012651e+09 1.527176e+06 0.000439 5.967300e+30
1.002211e+09 3.344824e+06 0.001072 5.967300e+30
9.917715e+08 7.876679e+06 0.001716 5.967300e+30
9.813318e+08 1.528565e+07 0.002870 5.967300e+30
9.708921e+08 2.793971e+07 0.004271 5.967299e+30
9.604524e+08 4.718766e+07 0.006134 5.967299e+30
9.500127e+08 7.543907e+07 0.008400 5.967298e+30
9.395730e+08 1.149941e+08 0.011132 5.967297e+30
9.291333e+08 1.685944e+08 0.014335 5.967296e+30
9.186936e+08 2.391984e+08 0.018035 5.967294e+30
9.082539e+08 3.300760e+08 0.022246 5.967292e+30
8.978142e+08 4.447982e+08 0.026988 5.967290e+30
8.873745e+08 5.872670e+08 0.032278 5.967287e+30
8.769348e+08 7.617399e+08 0.038133 5.967284e+30
8.664951e+08 9.728621e+08 0.044575 5.967280e+30
8.560554e+08 1.225701e+09 0.051622 5.967276e+30
8.456157e+08 1.525790e+09 0.059297 5.967271e+30
8.351760e+08 1.879167e+09 0.067624 5.967265e+30
8.247363e+08 2.292433e+09 0.076627 5.967259e+30
8.142966e+08 2.772804e+09 0.086334 5.967253e+30
8.038569e+08 3.328175e+09 0.096773 5.967245e+30
7.934172e+08 3.967188e+09 0.107976 5.967237e+30
7.829775e+08 4.699315e+09 0.119976 5.967229e+30
7.725378e+08 5.534939e+09 0.132808 5.967219e+30
7.620981e+08 6.485454e+09 0.146512 5.967209e+30
7.516584e+08 7.563373e+09 0.161127 5.967198e+30
7.412187e+08 8.782447e+09 0.176699 5.967187e+30
7.307790e+08 1.015780e+10 0.193274 5.967174e+30
7.203393e+08 1.170609e+10 0.210904 5.967161e+30
7.098996e+08 1.344566e+10 0.229642 5.967147e+30
6.994599e+08 1.539674e+10 0.249548 5.967133e+30
6.890202e+08 1.758168e+10 0.270684 5.967117e+30
6.785805e+08 2.002515e+10 0.293117 5.967101e+30
6.681408e+08 2.275445e+10 0.316921 5.967083e+30
6.577011e+08 2.579981e+10 0.342172 5.967066e+30
6.472614e+08 2.919473e+10 0.368956 5.967047e+30
6.368217e+08 3.297638e+10 0.397363 5.967027e+30
6.263820e+08 3.718607e+10 0.427491 5.967007e+30
6.159423e+08 4.186974e+10 0.459445 5.966985e+30
6.055026e+08 4.707856e+10 0.493339 5.966963e+30
5.950629e+08 5.286959e+10 0.529296 5.966940e+30
5.846232e+08 5.930656e+10 0.567451 5.966917e+30
5.741835e+08 6.646075e+10 0.607948 5.966892e+30
5.637438e+08 7.441197e+10 0.650945 5.966867e+30
5.533041e+08 8.324981e+10 0.696611 5.966841e+30
5.428644e+08 9.307487e+10 0.745135 5.966814e+30
5.324247e+08 1.040004e+11 0.796717 5.966786e+30
There is also an other workaround, which you already guessed by yourself : that would be to use integers as keys in your dictionary. I don't think this to be awkward in any way, but I'd rather have keys with a real, direct meaning (that is, your radius) rather than the iteration step... But this is really up to you.
I'm new to python.
I want to make a calculator and I am facing a problem right now.
Here's a simplified code I am trying to make:
from math import *
input = "(2)(3)e(sqrt(49))pi" #This is an example of equation
equation = "(2)*(3)*e*(sqrt(49))*pi" #The output
How can I add " * " between every ")(", ")e", "e(", and others based on the equation so that I can eval (equation) without having to put "*" manually, just like real life math?
I have tried to do it by making a code like this:
from math import *
input = "(2)(3)e(sqrt(49))pi"
input = input.replace(")(", ")*(")
input = input.replace(")e", ")*e")
input = input.replace("e(", "e*(")
input = input.replace(")pi", ")*pi")
#^^^I can loop this using for loop^^^
equation = input
print(eval(equation))
This definitely only works in this equation. I can loop the replacing method but that would be very inefficient. I don't want to have 49 iterations to just check if 7 different symbols need "*" between it or not.
The issue you will encounter here is that "e(" should be transformed to "e*(" but "sqrt(" should stay. As comments have suggested, the best or "cleanest" solution would be to write a proper parser for your equation. You could put "calculator parser" into your favorite search engine for a quick solution, or if you are interested in over-engineering but learning a lot, you could have a look at parser generators such as ANTLr.
If, for some reason, neither of those are an option, a quick-and-dirty solution could be this:
import re
def add_multiplication_symbols(equation: str) -> str:
constants = ['e', 'pi']
constants_re = '|'.join(f'(?:{re.escape(c)})' for c in constants)
equation = re.sub(r'(\))(\(|\w+)', r'\1*\2', equation)
equation = re.sub(f'({constants_re})' + r'(\()', r'\1*\2', equation)
return equation
Then print(add_multiplication_symbols("(2)(3)e(sqrt(49))pi")) results in (2)*(3)*e*(sqrt(49))*pi.
The function makes use of the re module (regular expressions) to group the cases for all constants together. It tries to work around the issue I described above by defining a set of constant variables (e.g. "e" and "pi") by hand.
I am trying to separately compute the elements of a Taylor expansion and did not obtain the results I was supposed to. The function to approximate is x**321, and the first three elements of that Taylor expansion around x=1 should be:
1 + 321(x-1) + 51360(x-1)**2
For some reason, the code associated with the second term is not working.
See my code below.
import sympy as sy
import numpy as np
import math
import matplotlib.pyplot as plt
x = sy.Symbol('x')
f = x**321
x0 = 1
func0 = f.diff(x,0).subs(x,x0)*((x-x0)**0/factorial(0))
print(func0)
func1 = f.diff(x,1).subs(x,x0)*((x-x0)**1/factorial(1))
print(func1)
func2 = f.diff(x,2).subs(x,x0)*((x-x0)**2/factorial(2))
print(func2)
The prints I obtain running this code are
1
321x - 321
51360*(x - 1)**2
I also used .evalf and .lambdify but the results were the same. I can't understand where the error is coming from.
f = x**321
x = sy.Symbol('x')
def fprime(x):
return sy.diff(f,x)
DerivativeOfF = sy.lambdify((x),fprime(x),"numpy")
print(DerivativeOfF(1)*((x-x0)**1/factorial(1)))
321*x - 321
I'm obviously just starting with the language, so thank you for your help.
I found a beginners guide how to Taylor expand in python. Check it out perhaps all your questions are answered there:
http://firsttimeprogrammer.blogspot.com/2015/03/taylor-series-with-python-and-sympy.html
I tested your code and it works fine. like Bazingaa pointed out in the comments it is just an issue how python saves functions internally. One could argument that for a computer it takes less RAM to save 321*x - 321 instead of 321*(x - 1)**1.
In your first output line it also gives you 1 instead of (x - 1)**0
I dont know if this question has been asked before in SO, I will go ahead and post it here, I am attempting to solve a simple system with a PID controller, my system of differential equations are given below. I am basically attempting to code very basic PID algorithm. The structure of my control u depends on both derivative and integral of error term. I dont have any problem with the derivative term, it is the integral term that is creating problem in my code. The problem crops up when I assign s=0 in the beginning
and use it in my function as described in my code below. Is there a way to bypass it? I tried assigning s and told as global variables, but it didnt solve my problem. In a nutshell what I am doing is- I am adding state x1 every time and multiplying by dt(which is denoted by t-told).
Kindly help me iron out this issue, PFA my code attached below.
import numpy as np
from scipy.integrate import ode
import matplotlib.pyplot as plt
plt.style.use('bmh')
t0=0
y0=[0.1,0.2]
kp,kd,ki=2,0.5,0.8
s,told=0,0
def pid(t,Y):
x1,x2=Y[0],Y[1]
e=x1-1
de=x2
s=(x1+s)
integral=s*(t-told)
told=t
#ie=
u=kp*e+kd*de+ki*integral
x1dot=x2
x2dot=u-5*x1-2*x2
return[x1dot,x2dot]
solver=ode(pid).set_integrator('dopri5',rtol=1e-6,method='bdf',nsteps=1e5,max_step=1e-3)
solver.set_initial_value(y0,t0)
t1=10
dt=5e-3
sol = [ [yy] for yy in y0 ]
t=[t0]
while solver.successful() and solver.t<t1:
solver.integrate(solver.t+dt)
for k in range(2): sol[k].append(solver.y[k]);
t.append(solver.t)
print(len(sol[0]))
print(len(t))
x1=np.array(sol[0])
x2=np.array(sol[1])
e=x1-1
de=x2
u=kp*e+kd*de
for k in range(2):
if k==0:
plt.subplot(2,1,k+1)
plt.plot(t,sol[k],label='x1')
plt.plot(t,sol[k+1],label='x2')
plt.legend(loc='lower right')
else:
plt.subplot(2,1,k+1)
plt.plot(t,u)
plt.show()
You are making assumptions on the solver and the time steps that it visits that are not justified. With your hacking of the integral, even if it were mathematically sound (it should look like integral = integral + e*(t-told), which gives an order 1 integration method), you reduce the order of any integration method, probably down to 1, if you are lucky only to order 2.
A mathematically correct method to implement this system is to introduce a third variable x3 for the integral of e, that is, the derivative of x3 is e. That the correct order 1 system has to be of dimension 3 can be read of the fact that (eliminating e) your system has 3 differentiation/integration operations. With that your system becomes
def pid(t,Y):
x1, x2, x3 =Y
e=x1-1
x1dot = x2
edot = x1dot
x3dot = e
u=kp*e+kd*edot+ki*x3
x2dot=u-5*x1-2*x2
return[x1dot, x2dot, x3dot]
Note that there are no global dynamic variables necessary, only the constants (which could also be passed as parameters, whatever seems more efficient or readable).
Now you will also need an initial value for x3, it was not visible from the system what the integration variable would have to be, your code seems to suggest 0.
First of all you need to include "s" Variable into the pid function.
'
def pid(s, t, Y): ...
'
Easiest solution I can see right now is to create a class with s and told as properties of this class:
class PIDSolver:
def __init__(self)
self.t0=0
self.y0=[0.1,0.2]
self.kp,self.kd,self.ki=2,0.5,0.8
self.s,self.told=0,0
def pid(t,Y):
x1,x2=Y[0],Y[1]
e=x1-1
de=x2
self.s=(x1+self.s)
integral=self.s*(t-self.told)
self.told=t
#ie=
u=self.kp*e+self.kd*de+self.ki*integral
x1dot=x2
x2dot=u-5*x1-2*x2
return[x1dot,x2dot]
For the first part of your problem. Use pidsolver = PIDSolver() in the next part of your solution.
I solved this problem myself by using set_f_params() method and passing a list in itz argument. Also I passed a 3rd argument in pid() i.e pid(t,Y,arg). And lastly I assigned s,told=arg[0],arg[1].