I have an exponential function with two known variables, x, and y. I need to find the value of y when I input an x. However, my code could not go through and solve the problem.
My function and all relevant constants are given below:
import math
import numpy as np
import scipy.optimize as optimize
x1=np.array([0,20])
Vt = 0.026
Io = 23*math.pow(10,-10)
Iph = 2.282
idf = 1
Ns = 60
Nm = 1
Rse = 0.5
Rsh = 1000
x = np.linspace(x1.min(),x1.max(),300)
def equation(x,Iph,Io,Rse,Rsh,Ns,Nm,Vt):
return y - Iph + Io*(np.exp((x+y*Rse)/(Ns*Nm*idf*Vt))-1) + x/Rsh + y*Rse/Rsh
y = optimize.newton(equation(10,Iph,Io,Rse,Rsh,Ns,Nm,Vt), 7)
Present output:
File "<ipython-input-172-93ede88c9b49>", line 16, in ivcurve_equation
return y - Iph + Io*(np.exp((x+y*Rse)/(Ns*Nm*idf*Vt))-1) + v/Rsh + I*Rse/Rsh
TypeError: can't multiply sequence by non-int of type 'float'
Expected output:
y = a real and positive value # >0
Have a quick look at the docs and try to do some 'pattern matching'. The parameters of equation should only be variables and not constants. Here is a working version of your code, that you should tailor to your needs:
import math
import numpy as np
import scipy.optimize as optimize
x1=np.array([0,20])
Vt = 0.026
Io = 23*math.pow(10,-10)
Iph = 2.282
idf = 1
Ns = 60
Nm = 1
Rse = 0.5
Rsh = 1000
x_arr = np.linspace(x1.min(),x1.max(),300)
x = x_arr[0]
def equation(y):
return y - Iph + Io*(np.exp((x+y*Rse)/(Ns*Nm*idf*Vt))-1) + x/Rsh + y*Rse/Rsh
result = optimize.newton(equation, 7)
print(result)
Now if you want the output for an array of x's try this:
def equation(y,x):
return y - Iph + Io*(np.exp((x+y*Rse)/(Ns*Nm*idf*Vt))-1) + x/Rsh + y*Rse/Rsh
result = [optimize.newton(equation, 7, args = (a,)) for a in x_arr]
print(result)
Hope this helps!
Related
Is it possible to solve Cubic equation without using sympy?
Example:
import sympy as sp
xp = 30
num = xp + 4.44
sp.var('x, a, b, c, d')
Sol3 = sp.solve(0.0509 * x ** 3 + 0.0192 * x ** 2 + 3.68 * x - num, x)
The result is:
[6.07118098358257, -3.2241955998463 - 10.0524891203436*I, -3.2241955998463 + 10.0524891203436*I]
But I want to find a way to do it with numpy or without 3 part lib at all
I tried with numpy:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, --4.44]
print(np.roots(coeff))
But the result is :
[ 0.40668245+8.54994773j 0.40668245-8.54994773j -1.19057511+0.j]
In your numpy method you are making two slight mistakes with the final coefficient.
In the SymPy example your last coefficient is - num, this is, according to your code: -num = - (xp + 4.44) = -(30 + 4.44) = -34.44
In your NumPy example yout last coefficient is --4.44, which is 4.44 and does not equal -34.33.
If you edit the NumPy code you will get:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, -34.44]
print(np.roots(coeff))
[-3.2241956 +10.05248912j -3.2241956 -10.05248912j
6.07118098 +0.j ]
The answer are thus the same (note that NumPy uses j to indicate a complex number. SymPy used I)
You could implement the cubic formula
this Youtube video from mathologer could help understand it.
Based on that, the cubic function for ax^3 + bx^2 + cx + d = 0 can be written like this:
def cubic(a,b,c,d):
n = -b**3/27/a**3 + b*c/6/a**2 - d/2/a
s = (n**2 + (c/3/a - b**2/9/a**2)**3)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3) - b/3/a
r1 = (n+s)**(1/3)+(n+s)**(1/3) - b/3/a
r2 = (n-s)**(1/3)+(n-s)**(1/3) - b/3/a
return (r0,r1,r2)
The simplified version of the formula only needs to get c and d as parameters (aka p and q) and can be implemented like this:
def cubic(p,q):
n = -q/2
s = (q*q/4+p**3/27)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3)
r1 = (n+s)**(1/3)+(n+s)**(1/3)
r2 = (n-s)**(1/3)+(n-s)**(1/3)
return (r0,r1,r2)
print(cubic(-15,-126))
(5.999999999999999, 9.999999999999998, 2.0)
I'll let you mix in complex number operations to properly get all 3 roots
I have an optimization formulation where I have multiple decision variables, each decision variable has its own quadratic cost function term. I am planning to use a piecewise linear approximation to simplify the objective function through using the 'Piecewise' function in pyomo. I managed to that in a simple toy problem where I have a single decision variable, the issue arises when I am dealing with many decision variables. Having to write a new line for each decision variable with its own 'Piecewise' function is not viable, so I am trying to automate that with a for loop similar to the way you can do that with constraints.
Here's an example toy problem of what I'm trying to do:
import numpy as np
from pyomo.environ import *
from pyomo.core import *
from pyomo.opt import SolverFactory
def cost_function_0(x):
return x ** 2 + 3 * x + 4
def cost_function_1(x):
return x ** 2 + 6 * x - 2
xdata = np.linspace(-10, 10, 50)
ydata_0 = list(cost_function_0(xdata))
ydata_1 = list(cost_function_1(xdata))
xdata = list(xdata)
model = ConcreteModel()
model.N = range(2)
model.X = Var(model.N, bounds=(-10, 10))
model.Y = Var(model.N)
model.piecewise_0 = Piecewise(model.Y[0],model.X[0],
pw_pts=xdata,
pw_constr_type='EQ',
f_rule=ydata_0,
pw_repn='CC')
model.piecewise_1 = Piecewise(model.Y[1],model.X[1],
pw_pts=xdata,
pw_constr_type='EQ',
f_rule=ydata_1,
pw_repn='CC')
model.obj = Objective(expr=model.Y[0] + model.Y[1], sense=minimize)
opt = SolverFactory('glpk')
obj_val = opt.solve(model)
print('Decision variables: ', model.X[0].value, model.X[1].value)
print('Objective value: ', model.Y[0].value + model.Y[1].value)
So I am trying to replace the process of manually creating the Piecewise objects (model.piecewise_0, model.piecewise_1, ....) with an automated for loop but I got no luck so far.
Thanks in advance!
I hope this answer helps in some way:
import numpy as np
from pyomo.environ import *
from pyomo.core import *
from pyomo.opt import SolverFactory
A = {0:1, 1:1}
B = {0:3, 1:6}
C = {0:4, 1:-2}
lo = {0:-10, 1:-10}
up = {0:10, 1:10}
parts = {0:50, 1:50}
def cost_function(x,a,b,c):
return a * x ** 2 + b * x + c
model = ConcreteModel()
model.N = range(2)
def bounds_rule(model, i):
return (lo[i], up[i])
model.X = Var(model.N, bounds=bounds_rule)
model.Y = Var(model.N)
for idx,n in enumerate(model.N):
xdata = np.linspace(lo[n],up[n],parts[n])
ydata = list(cost_function(xdata,A[n],B[n],C[n]))
xdata = list(xdata)
piecewise = Piecewise(model.Y[n],model.X[n],
pw_pts=xdata,
pw_constr_type='EQ',
f_rule=ydata,
pw_repn='CC')
model.add_component('piecewise_'+ str(idx), piecewise)
def objetive(model):
return sum (model.Y[n] for n in model.N)
model.obj = Objective(rule = objetive, sense=minimize)
opt = SolverFactory('glpk')
obj_val = opt.solve(model)
print('Decision variables: ', model.X[0].value, model.X[1].value)
print('Objective value: ', model.Y[0].value + model.Y[1].value)
I'm trying to solve the following system: d²i/dt² + R'(i)/L di/dt + 1/LC i(t) = 1/L dE/dt as a set of coupled first order differential equations:
di/dt = k
dk/dt = 1/L dE/dt - R'(i)/L k - 1/LC i(t)
Here is the code I'm using:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
#Define model: x = [i , k]
def RLC(x , t):
i = sp.Symbol('i')
t = sp.Symbol('t')
#Data:
E = sp.ln(t + 1)
dE_dt = E.diff(t)
R1 = 1000 #1 kOhm
R2 = 100 #100 Ohm
R = R1 * i + R2 * i**3
dR_di = R.diff(i)
i = x[0]
k = x[1]
L = 10e-3 #10 mHy
C = 1.56e-6 #1.56 uF
#Model
di_dt = k
dk_dt = 1/L * dE_dt - dR_di/L * k - 1/(L*C) * i
dx_dt = np.array([di_dt , dk_dt])
return dx_dt
#init cond:
x0 = np.array([0 , 0])
#time points:
time = np.linspace(0, 30, 1000)
#solve ODE:
x = odeint(RLC, x0, time)
i = x[: , 0]
However, I get the following error: TypeError: Cannot cast array data from dtype('O') to dtype('float64') according to the rule 'safe'
So, I don't know if sympy and odeint don't work well together. Or maybe is it a problem because I defined t as sp.Symbol?
When you differentiate a function, you get a function back. So you need to evaluate it at a point in order to get a number. To evaluate a sympy expression, you could use .subs() but I prefer .replace() which feels more powerful (at least for me).
You must try and make every single variable have its own name in order to avoid confusion. For example, you replace the float input t with a sympy Symbol from the very beginning, thus losing the value of t. The variables x and i are also repeated in the outer scope which is not good practice if they mean different things.
The following should avoid confusion and hopefully produce something that you were expecting:
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# Define model: x = [i , k]
def RLC(x, t):
# define constants first
i = x[0]
k = x[1]
L = 10e-3 # 10 mHy
C = 1.56e-6 # 1.56 uF
R1 = 1000 # 1 kOhm
R2 = 100 # 100 Ohm
# define symbols (used to find derivatives)
i_symbol = sp.Symbol('i')
t_symbol = sp.Symbol('t')
# Data (differentiate and evaluate)
E = sp.ln(t_symbol + 1)
dE_dt = E.diff(t_symbol).replace(t_symbol, t)
R = R1 * i_symbol + R2 * i_symbol ** 3
dR_di = R.diff(i_symbol).replace(i_symbol, i)
# nothing should contain symbols from here onwards
# variables can however contain sympy expressions
# Model (convert sympy expressions to floats)
di_dt = float(k)
dk_dt = float(1 / L * dE_dt - dR_di / L * k - 1 / (L * C) * i)
dx_dt = np.array([di_dt, dk_dt])
return dx_dt
# init cond:
x0 = np.array([0, 0])
# time points:
time = np.linspace(0, 30, 1000)
# solve ODE:
solution = odeint(RLC, x0, time)
result = solution[:, 0]
print(result)
Just something to note: the value i = x[0] seemed to sit very close to 0 throughout each iteration. This means dR_di stayed basically at 1000 the whole time. I'm not familiar with odeint or your specific ODE, but hopefully this phenomenon is expected and isn't a problem.
I have been working with odeint and boundary conditions. Bassically what I am trying to do is to solve the differential equations given in this figure 1
where in my code R=R, ph = Phi, al = alpha, a = a, m = m, l = l and om = omega. The initial conditions that I am trying to implement are R(0)=O(r^l); Phi(0)=O(r^{l-1}) if l/=0 and Phi(0)=O(r) if l=0; a(0) = 1 and a(inf)=1/alpha(inf) (additionally I need that R(inf)=0). I tried to applied the shooting method in order to find initial conditions for alpha that best matches with my boundary conditions. I also need to find the omega that best matches the boundary conditions for R at infinity. The code that I wrote is the following:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import time
start = time.clock()
def system_DE(IC,p,r):
l = p[0]
m = p[1]
om = p[2]
R = IC[0]
ph = IC[1]
a = IC[2]
al = IC[3]
dR_dr = ph
da_dr = a*((2*l+1)*r/2*(om**2*a**2*R**2/al**2+ph**2+l*(l+1)*a**2*R**2/r**2+m**2*a**2*R**2)-(a**2-1)/(2*r))
dal_dr = al*(da_dr/a-l*(l+1)*(2*l+1)*a**2*R**2/r-(2*l+1)*m**2*a**2*r*R**2+(a**2-1)/r)
dph_dr = -2*ph/r-dal_dr*ph/al+da_dr*ph/a-om**2*a**2*R/al**2+l*(l+1)*a**2*R/r**2+m**2*a**2*R
return [dR_dr,da_dr,dal_dr,dph_dr]
def init(u,p,r):
if p==0:
return np.array([1,r,1,u])
else:
return np.array([r**l,l*r**(l-1),1,u])
l = 0
m = 1
ep = 0.3
n_om = 10
omega = np.linspace(m-ep,m+ep,n_om)
r = np.linspace(0.0001, 100, 1000)
niter = 100
u = 0
tol = 0.1
ustep = 0.01
p = np.zeros(3)
p[0] = l
p[1] = m
for j in range(len(omega)):
p[2] = omega[j]
for i in range(niter):
u += ustep
Y = odeint(system_DE(init(u,p[0],r[0]),p,r), init(u,p[0],r[0]), r)
print Y[-1,2]
print Y[-1,3]
if abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
print(i,'times iterations')
print("a'(inf)) = ", Y[len(Y)-1,2])
print('y"(0) =',u)
break
if abs(Y[len(Y)-1,0]) < tol:
print(j,'times iterations in omega')
print("R'(inf)) = ", Y[len(Y)-1,0])
break
However, when I run it I am obtaining: error: The function and its Jacobian must be callable functions.
Could some one help me to understand what my mistake is?
Regards,
Luis Padilla.
To start with, the first argument to odeint is your derivative function system_DE. Just pass its name, no parentheses or arguments. Odeint with call it internally and supply arguments.
I fixed my code and now it is giving me some results. However, when I run it I am obtaining some warnings that I don't know how to solve it. Could some one help me to solve it? Basically my code is this:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import time
def system_DE(IC,r,l,m,om):
R = IC[0]
ph = IC[1]
a = IC[2]
al = IC[3]
dR_dr = ph
da_dr = a*((2*l+1)*r/2*(om**2*a**2*R**2/al**2+ph**2+l*(l+1)*a**2*R**2/r**2+m**2*a**2*R**2)-(a**2-1)/(2*r))
dal_dr = al*(da_dr/a-l*(l+1)*(2*l+1)*a**2*R**2/r-(2*l+1)*m**2*a**2*r*R**2+(a**2-1)/r)
dph_dr = -2*ph/r-dal_dr*ph/al+da_dr*ph/a-om**2*a**2*R/al**2+l*(l+1)*a**2*R/r**2+m**2*a**2*R
return [dR_dr,dph_dr,da_dr,dal_dr]
def init(u,p,r):
if p==0:
return np.array([1.,r,1.,u])
else:
return np.array([r**p,l*r**(p-1),1,u])
l = 0.
m = 1.
ep = 0.2
n_om = 30
omega = np.linspace(m-ep,m+ep,n_om)
r = np.linspace(0.001, 100, 1000)
niter = 1000
tol = 0.01
ustep = 0.01
for j in range(len(omega)):
print('trying with $omega =$',omega[j])
p = (l,m,omega[j])
u = 0.001
for i in range(niter):
u += ustep
ini = init(u,p[0],r[0])
Y = odeint(system_DE, ini,r,p,mxstep=500000)
if abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
break
if abs(Y[len(Y)-1,0]) < tol and abs(Y[len(Y)-1,2]-1/Y[len(Y)-1,3]) < tol:
print(j,'times iterations in omega')
print(i,'times iterations')
print("R'(inf)) = ", Y[len(Y)-1,0])
print("alpha(0)) = ", Y[0,3])
print("\omega",omega[j])
break
plt.subplot(2,1,1)
plt.plot(r,Y[:,0],'r',label = '$R$')
plt.plot(r,Y[:,1],'b',label = '$d R /dr$')
plt.xlim([0,10])
plt.legend()
plt.subplot(2,1,2)
plt.plot(r,Y[:,2],'r',label = 'a')
plt.plot(r,Y[:,3],'b', label = '$alpha$')
plt.xlim([0,10])
plt.legend()
plt.show()
But when I run it I am obtaining this:
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.1243782486482D+01 r2 = 0.8727680448722D-16
How could I fix the problem?
Regards,
Luis Padilla.
I am trying to implement particle filter algorithm in python. I am getting this error:
x_P_update[i] = 0.5*x_P[i] + 25*x_P[i]/(1 + x_P[i]**2) + 8*math.cos(1.2*(t-1)) + math.sqrt(x_N)*np.random.randn()
TypeError: 'float' object has no attribute '__getitem__'
My code:
import math
import numpy as np
import matplotlib.pyplot as plt
x = 0.1 #initial value
x_N = 1 #process noise covariance in state update
x_R = 1 #noise covariance in measurement
T = 75 #number of iterations
N = 10 #number of particles
V = 2
x_P = [None]*(N)
for i in xrange(0, N):
x_P[i] = x + math.sqrt(V)*np.random.randn()
z_out = np.array([x**2 / 20 + math.sqrt(x_R) * np.random.randn()]) #the actual output vector for measurement values.
x_out = np.array([x]) #the actual output vector for measurement values.
x_est = np.array([x]); # time by time output of the particle filters estimate
x_est_out = np.array([x_est]) # the vector of particle filter estimates.
x_P_update = [None]*N
z_update = [None]*N
P_w = [None]*N
for t in xrange(1, T+1):
x = 0.5*x + 25*x/(1 + x**2) + 8*math.cos(1.2*(t-1)) + math.sqrt(x_N)*np.random.randn()
z = x**2/20 + math.sqrt(x_R)*np.random.randn()
for i in xrange(0, N):
#each particle is updated with process eq
x_P_update[i] = 0.5*x_P[i] + 25*x_P[i]/(1 + x_P[i]**2) + 8*math.cos(1.2*(t-1)) + math.sqrt(x_N)*np.random.randn()
#observations are updated for each particle
z_update[i] = x_P_update[i]**2/20
#generate weights
P_w[i] = (1/math.sqrt(2*math.pi*x_R)) * math.exp(-(z - z_update[i])**2/(2*x_R))
P_w[:] = [ k / sum(P_w) for k in P_w]
# print(np.where(np.cumsum(P_w, axis=0) >= np.random.rand()))
# print(index_tuple[0][1])
# P_w_array = np.array(list(P_w))
# indices = [i for i in range(len(P_w)) if np.cumsum(P_w_array) >= np.random.rand()]
for i in xrange(0, N):
index_tuple = np.where(np.random.rand() <= np.cumsum(P_w, axis=0))
m = index_tuple[0][1]
x_P = x_P_update[m]
x_est = np.array([np.mean(x_P)])
x_out = np.array([x_out, x])
z_out = np.array([z_out, z])
x_est_out = np.array([x_est_out, x_est])
I am using matlab code from here to learn how to implement this algorithm in python using scipy. http://studentdavestutorials.weebly.com/particle-filter-with-matlab-code.html
I just started learning python and can't get out of this problem, kindly help.
I'm not going to go through the video tutorial and fix your algorithm, but I can show you why you're getting this error.
In this line:
x_P = x_P_update[m]
You are assigning an array with a float value, which you then attempt to access as an array in the outer loop. Updating it instead will get rid of your error:
x_P[m] = x_P_update[m]