How to take a derivative of Function, then evaluate using real numbers? - python

I have a massive, ugly expression. I need to take its derivative, then plug in some numbers and evaluate it.
This is to calculate the total error in the output of an electrical circuit.
The actual formula looks like this:
Almost all those variables on the right are temperature dependent, and I am concerned with the overall temperature sensitivity, dReff/dT.
But let's make things simpler for the sake of explanation. Let's say I have a much simpler formula:
R(T) = 2*R_0(T)
I would like to get the derivative in terms of the variables:
dR/dT = 2*dR_0/dT
And then, knowing dR_0/dT from a datasheet, I would like to be able to plug it in:
dR_0/dT = 2ohms/°C
dR/dT = 2*2ohms/°C = 4ohms/°C
Now, I've used python and sympy to get me pretty far but now I'm stuck. It looks like this:
from sympy import *
T = Symbol('T')
R_0 = Function('R_0')(T)
R = 2*R_0
diffR = Symbol('diffR')
diffR = R.diff(T)
At this point if you print diffR, you get the following
2*Derivative(R_0(T),T)
How to I get the rest of the way? Is there a way to plug in values for the derivative term?

One solution is to make another symbol for the derivative:
dR0 = Function('R_0')(T).diff(T)
Then, you can substitute in for this in your larger derivative expression.
expr.subs(dR0, value)
This works in the few examples I've tried. Their might be an easier way to do this, but I only deal with sympy when strictly needed.

Related

How to solve equations in python

I try to write a script that simulates a resistor. It takes 2 arguments for example P and R and it should calculate all missing values of this resistor.
The problem is that I don't want to write every single possible equation for every value. This means I want to write something like (U=RxI, R=U/R, I=U/R , P=UxI) and the script should then complete all equation with the given values for every equation.
For example, something like this:
in R=10
in I=5
out U=R*I
out P=I**2 * R
You can use https://pypi.org/project/Equation/ Packages.
Example
>>> from Equation import Expression
>>> fn = Expression("sin(x+y^2)",["y","x"])
>>> fn
sin((x + (y ^ (2+0j))))
>>> print fn
\sin\left(\left(x + y^{(2+0j)}\right)\right)
>>> fn(3,4)
(0.42016703682664092+0j)
Sympy
Second: https://github.com/sympy/sympy/wiki
Arbitrary precision integers, rationals and floats, as well as symbolic expressions
Simplification (e.g. ( abb + 2bab ) → (3ab^2)), expansion (e.g. ((a+b)^2) → (a^2 + 2ab + b^2)), and other methods of rewriting expressions
Functions (exp, log, sin, ...)
Complex numbers (like exp(Ix).expand(complex=True) → cos(x)+Isin(x))
Taylor (Laurent) series and limits
Differentiation and integration
In vanilla python, there is no solution as general as the one you are looking for.
The typical solution would be to write an algorithm for every option (only given U, only given R) and then logically select which option to execute.
You may also want to consider using a module like SymPy, which has a solver module that may be more up your alley.

How to return a finite (float) value with nonlinsolve in SymPy?

I am very new to programming, and had to use sympy for a school project.
I think I get that using nonlinsolve to return an angle gives an ImageSet with the angle + 2n*pi. However I want it to return only the value of the angle (in the interval [0,pi/2]), and as one value and not an interval.
from sympy import nonlinsolve, symbols,cos
x=symbols('x')
print(nonlinsolve([cos(x)-1],[x]).args[0][0])
I want the result to be 0 and not 2*n*pi.
Clarification : I know that the result is correct, but I only want one value, that I can use algebraically, and I don't know how Sympy works (how to manipulate ImageSets)
So I might be wrong because i dont use sympy, but the solution that solvers return seems to be corect to me.
ImageSet(Lambda(_n, 2*_n*pi), Integers)
From what I understand solver returned lambda function. Cosinus is a cyclic function which means it reapeats it's value every 2PI. So the solver says first solution (_n = 0) is 0, second (_n = 1) is 2pi and so on.
look at the function plot and it will hopefully make sense:
Wolfram Alpha - (cos(x) - 1)
EDIT: I think you need to use intersect method of imageset like this( note that intersect returns all the intersections, here i selected just the first one):
from sympy import nonlinsolve, symbols,cos, Interval
import math
x = symbols('x')
f = nonlinsolve([cos(x)-1], [x]).args[0][0]
sol = f.intersect(Interval(0, math.pi/2)).args[0]
print(sol)

get sympy result as trig function rather than complex log

I'm doing some manipulation of trig equations and would like the results back in trig form.
What I'm doing is this:
from sympy import *
B,D,a=symbols(r'B,D,alpha',real=True,positive=True)
eq1=Eq(D,B*((sin(a)*sin(a))/(sin(a+a))))
solve(eq1,a)
I expect the result to be atan(2*D/B) but I'm getting:
[-I*log(-sqrt((B + 2*I*D)/(B - 2*I*D))), -I*log((B + 2*I*D)/(B - 2*I*D))/2]
I know sympy is expanding the trig functions into exponential form, but I can't seem to convince it to convert the results back.
I've tried:
[n.rewrite(atan) for n in solve(eq1,a)]
but I get the same result back...
If you simplify before solving, the result looks better.
>>> solve(eq1.simplify(), a)
[atan(2*D/B)]
Also, the more mathematically rigorous solveset (a modern alternative to solve) returns a more mathematically correct answer without the need for simplification:
>>> solveset(eq1, a)
ConditionSet(alpha, Eq(tan(alpha)/2 - D/B, 0), Reals)
The point being that there are infinitely many solutions, so they cannot be given as a list: so, solveset presents them as the set of all alpha such that tan(alpha) is 2*D/B.

solve cubic equations ,sympy

I have a project that one step of the process of it is to solve R(k,d,a),
where k means kth step.
My friend suggest me to do this in sympy ,but I don't know how to do it.
from sympy import *
k= symbols('k')
d= symbols('d')
a= symbols('a')
R= function('R')(k,d,a)
print R`
In fact I don't know how to define a function in sympy with class method...
and this expression is failure.
def R(k,d,a):
k:# of nth process
d:parameter in order to initializing
R(0,d,a) should be given
if k==0:
return 100*d
r=d*(1-(1-(d/R(k-1,d,a))**2)**0.5)**0.5
B=-3/2*d
D=(R(k-1,d,a))**3*(3*a*d/R(k-1,d,a)-2)+r**2*(r-3/2*d)
here I define R(k,d,a) with R(k-1,d,a),is it appropriate?
x^3+Bx^2+Cx+D=0 ,where c=0
x represent R(k,d,a) here.
x=symbols('x')
y=solve (x**3+x**2*B+D,x)
return max(y)
Here I want a list of y,and asking y in real number.
Later return the biggest one.
But I don't know how to realize it.
Finally,for each k ,I will need the other function to give a value that R(k,d,a) will be a parameter in it.I think I can do it by my self with for loop,it is not hard for me.
What is the hardest is how to get R(k,d,a).
I don't need complex root .But if I want ,how can I get them ?
Thank you for watching!
What you have looks basically OK. Three suggestions, however:
make sure your function always returns a SymPy value, e.g. don't return 100*d since d might be an int; return S(100)*d;
wherever you have division make sure that it is not suffering from Python trunction wherein 1/2 -> 0. e.g. write B = -S(3)/2*d instead of what you have (and use that B in your expression for D, writing (r+B) at the end of it;
max will not be able to sort the roots if complex roots are present so it would be better to select the real ones by hand: y=[i for i in solve (x**3+x**2*B+D,x) if i.is_real].

Avoiding hard coding a lot of coupled ODEs in python

First of, I'm sorry if the title is not entirely fitting, I had a hard time finding an appropriate one (which might have also effect my searching efficiency for already asked questions like this :/ ).
The problem is the following. While it is comparably easy to solve coupled ODE's in python with Scipy, I still have to write down my ODE in the form explicitly. For example for a coupled ODE of the form
d/dt(c_0)=a(c_0)+b(c_1) and d/dt(c_1)=c(c_0)
I would set up sth like:
import numpy as np
from scipy.integrate import ode
a=1
b=2
c=3
val=[]
def dC_dt(t, C):
return [a*C[0]+b*C[1],
c*C[0]]
c0, t0 = [1.0,0.0], 0
r = ode(dC_dt).set_integrator('zvode', method='bdf',with_jacobian=False)
r.set_initial_value(c0, t0)
t1 = 0.001
dt = 0.000005
while r.successful() and r.t < t1:
r.integrate(r.t+dt)
val.append(r.y)
However, now I have coupled ODE's of the rough form
d/dt(c_{m,n})=a(c_{m,n})+b(c_{m+1,n-1})+k(c_{m-1,n+1})
with c_{0,0}=1 and I have to include orders with m^2+n^2-mn smaller than a max value.
For a small max, what I did, is using a dictionary to use a notation with two indices and map it on a 1D list
dict_in={'0,0':0,'-1,0':2,...}
and then I entered the ODE for each order
def dC_dt(t,C):
return[a*C[dict_in['0,0']]+b*C[dict_in['1,-1']]...
Now I basically have to do that for some 100 coupled equations, which I ofc do not want to hard code, so I was trying to figure out a way, to realize the ODE's with a loop or sth. However I couldn't yet find a way around the fact of having two indices in my coefficients together with the condition of only including orders with m^2+n^2-mn smaller than a max value.
As I am running in some deadlines, I figured it is time to ask smarter people for help.
Thanks for reading my question!
I had a similar problem. If you fill you dictionary you can just redeclare the function more times inside the loop. This is a silly example of how it works:
dict_in={'0,0':0,'-1,0':2}
for elem in dict_in:
def dC_dt(t,C):
#return[a*C[dict_in['0,0']]+b*C[dict_in['1,-1']]
return dict_in[elem]
t, C = 0, 0
print(dC_dt(t,C))
#r = ode(dC_dt).set_integrator('zvode', method='bdf',with_jacobian=False)
If you need to use more functions together you can use anonymous functions and store them in memory. Another example:
functions_list = list()
for i in range(4):
f = lambda n = i: n
functions_list.append(f)
for j in range(4):
print(functions_list[j]())
You can use a list or a generator too. For example you can write down the value on a txt file and read that with the readline function each time.
As pointed in the comments below, if you use lamda functions you should pay attention to references. See also https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result

Categories