LSQUnivariateSpline.get_coeffs() - what coefficients do I get? - python

Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import LSQUnivariateSpline
x = np.linspace(-3,3,7)
y = np.sin(x)
t = [-1,1]
LSQ_USpline = LSQUnivariateSpline(x, y, t, k = 3)
print(LSQ_USpline.get_coeffs())
As far I understand I am getting 3 polynomials pieced back together. The output of LSQ_USpline.get_coeffs() is
[-0.14112001 -0.90624802 -1.47578155 1.47578155 0.90624802 0.14112001]
I thought that first two coefficients are related to the first polynomial, in particular a_0 -> -0.14112001 and a_1 -> -0.90624802, where a_0 is the coefficient of x^3. After plotting it I realized that it is not true.
Could somebody help me to understand what how to read output of LSQ_USpline.get_coeffs()?
Update: Overall what do coefficients of spline mean? I thought they are coefficients of polynomials of the spline.
Update: After differentiating and checking values at zero get_coeffs() is definitely not coefficients of polynomials or there is a bug in this function.

Related

How to extract coefficients of Jacobi polynomial using SymPy

I'd like to consecutively plot the zeros of several Jacobi polynomials. The parameters and degree of the Jacobi polynomials depend on a certain size variable n. I want to compute the roots of each polynomial by first extracting the coefficients of the polynomial into an array. However, this cannot be done with the coeffs() command since the Jacobi polynomial is of class sympy.core.add.Add, which does not have coeffs() as an attribute. Any suggestions on how to overcome this problem?
import matplotlib.pyplot as plt
init_printing()
x = Symbol("x")
def show_roots(n,a,b,c):
for k in range (1,n+1):
p = jacobi(a*k,-(a+b)*k,(b+c)*k,x)
coeff = p.coeffs(x)
roots = numpy.roots(coeff)
plt.plot(roots)
plt.show()
plt.pause(3)
The error I am shown when I try out show_roots with specific values:
AttributeError: 'Add' object has no attribute 'coeffs'
You need to convert Add to Poly first then call coeffs() on the result.
import matplotlib.pyplot as plt
import sympy
import numpy
x = sympy.symbols('x')
def show_roots(n,a,b,c):
for k in range (1,n+1):
p = sympy.jacobi(a*k,-(a+b)*k,(b+c)*k,x)
coeff = sympy.poly(p).coeffs()
roots = numpy.roots(coeff)
print(roots)
show_roots(3,1,2,3)
gives
[2.]
[2.+0.65465367j 2.-0.65465367j]
[2.24801968+0.j 1.87599016+0.92968658j 1.87599016-0.92968658j]
You can now do the plotting stuff.

Discontinuity in numerical derivative of an interpolating cubic spline

I am trying to to calculate and plot the numerical derivative (dy/dx) from two lists x and y. I am using the scipy.interpolate.UnivariateSpline and scipy.interpolate.UnivariateSpline.derivative to compute the slope. The plot of y vs x seems to be C1 continuous and I was expecting the slope dy/dx to be smooth as well when plotted against x. But then what is causing the little bump in the plot here? Also any suggestion on how I can massage the code to make it C1 continuous?
import numpy as np
from matplotlib import pyplot as plt
from scipy.interpolate import UnivariateSpline
x=[20.14141131550861, 20.29161104293003, 20.458574567775457, 20.653802880772922, 20.910446090013004, 21.404599384233677, 21.427939384233678, 21.451279384233676, 21.474619384233677, 21.497959384233678, 21.52129938423368, 21.52130038423368, 21.54463938423368, 21.56797938423368, 21.59131938423368, 21.61465938423368, 21.63799938423368, 22.132152678454354, 22.388795887694435, 22.5840242006919]
y=[-1.6629252348586834, -1.7625046339166028, -1.875358801338162, -2.01040013818419, -2.193327440415778, -2.5538174545988306, -2.571799827167608, -2.5896274995868005, -2.607298426787476, -2.624811539182082, -2.642165776735291, -2.642165776735291, -2.659360089028171, -2.6763934353217587, -2.693264784620056, -2.7099731157324367, -2.7265165368570314, -3.0965791078676754, -3.290845721407758, -3.440799238587583]
spl1 = UnivariateSpline(x,y,s=0)
dydx = spl1.derivative(n=1)
T = dydx(x)
plt.plot(x,y,'-x')
plt.plot(x,T,'-')
plt.show()
The given data points look like they define a nice C1-smooth curve, but they do not. Plotting the slopes (difference of y over difference of x) shows this:
plt.plot(np.diff(y)/np.diff(x))
There are some duplicate values of y in the array, which look like they don't belong, also some near-duplicate (but not duplicate) values of x.
The easiest way to fix the spline is to allow a tiny bit of smoothing:
spl1 = UnivariateSpline(x, y, s=1e-5)
makes the derivative what you expected:
Removing the "bad apple" also helps, though not as much.
spl1 = UnivariateSpline(x[:10] + x[11:], y[:10] + y[11:], s=0)

Python: odeint to solve ODEs with variable coefficients (QHO)

I'm trying to solve the equation y'' + (epsilon-x^2)y = 0 numerically using odeint. I know the solutions (the wavefunctions of a QHO), but the output from odeint has no apparent relation to it. I can solve ODEs with constant coefficients just fine, but as soon as I move to variable ones, I can't solve any of the ones I tried. Here's my code:
#!/usr/bin/python2
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as spi
x = np.linspace(-5,5,1e4)
n = 0
epsilon = 2*n+1
def D(Y,x):
return np.array([Y[1], (epsilon-x**2)*Y[0]])
Y0 = [0,1]
Y = spi.odeint(D,Y0,x)
# Y is an array with the first column being y(x) and the second y'(x) for all x
plt.plot(x,Y[:,0],label='num')
#plt.plot(x,Y[:,1],label='numderiv')
plt.legend()
plt.show()
And the plot:
[not enough rep:] https://drive.google.com/file/d/0B6840LH2NhNpdUVucUxzUGFpZUk/edit?usp=sharing
Look here for plots of solution: http://hyperphysics.phy-astr.gsu.edu/hbase/quantum/hosc5.html
It looks like your equation is not correctly interpreted. You have a differential equation y'' + (epsilon-x^2)y = 0, but you forget a minus sign in your vector form. In particular it should be
y[0]' = y[1]
y[1]' = -(epsilon-x^2)y[0]
So (adding the minus sign in front of the epsilon term
def D(Y,x):
return np.array([Y[1], -(epsilon-x**2)*Y[0]])
In fact the plot you have is consistent with the DE y'' + (epsilon-x^2)y = 0. Check it out: Wolphram Alpha

Having trouble while using scipy.integrate.odeint with python

I was trying to use odeint to solve a problem. My code is as below:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
eta=1.24e-9/2
def fun(x):
f=1.05e-8*eta*x**(1.5)*np.exp(13.6/x)
return (np.sqrt(1.+4*f)-1)/2./f
x=np.arange(0,1,0.001)
y=odeint(fun,x,0)[0]
plt.plot(x,y)
plt.plot(x,x)
plt.show()
It the two curves are the same, which is obviously wrong. If I plot the function, it will looks like a step function, which is very very small before about 0.3 and exponentially goes to 1. Can you help me figure out what's wrong with it? Thank you!
There are several problems with your code, most of which you might be able to solve yourself if you read the docstring for odeint more carefully.
To get you started, the following is a simple example of solving a scalar differential equation with odeint. Instead of trying to understand (and possibly debug) your function, I'll use a very simple equation. I'll solve the equation dy/dt = a * y, with initial condition y(0) = 100. Once you have this example working, you can modify fun to solve your problem.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def fun(y, t, a):
"""Define the right-hand side of equation dy/dt = a*y"""
f = a * y
return f
# Initial condition
y0 = 100.0
# Times at which the solution is to be computed.
t = np.linspace(0, 1, 51)
# Parameter value to use in `fun`.
a = -2.5
# Solve the equation.
y = odeint(fun, y0, t, args=(a,))
# Plot the solution. `odeint` is generally used to solve a system
# of equations, so it returns an array with shape (len(t), len(y0)).
# In this case, len(y0) is 1, so y[:,0] gives us the solution.
plt.plot(t, y[:,0])
plt.xlabel('t')
plt.ylabel('y')
plt.show()
Here's the plot:
More complicated examples of the use of odeint can be found in the SciPy Cookbook (scroll down to the bullet labeled "Ordinary differential equations").

Spline representation with scipy.interpolate: Poor interpolation for low-amplitude, rapidly oscillating functions

I need to (numerically) calculate the first and second derivative of a function for which I've attempted to use both splrep and UnivariateSpline to create splines for the purpose of interpolation the function to take the derivatives.
However, it seems that there's an inherent problem in the spline representation itself for functions who's magnitude is order 10^-1 or lower and are (rapidly) oscillating.
As an example, consider the following code to create a spline representation of the sine function over the interval (0,6*pi) (so the function oscillates three times only):
import scipy
from scipy import interpolate
import numpy
from numpy import linspace
import math
from math import sin
k = linspace(0, 6.*pi, num=10000) #interval (0,6*pi) in 10'000 steps
y=[]
A = 1.e0 # Amplitude of sine function
for i in range(len(k)):
y.append(A*sin(k[i]))
tck =interpolate.UnivariateSpline(x, y, w=None, bbox=[None, None], k=5, s=2)
M=tck(k)
Below are the results for M for A = 1.e0 and A = 1.e-2
http://i.imgur.com/uEIxq.png Amplitude = 1
http://i.imgur.com/zFfK0.png Amplitude = 1/100
Clearly the interpolated function created by the splines is totally incorrect! The 2nd graph does not even oscillate the correct frequency.
Does anyone have any insight into this problem? Or know of another way to create splines within numpy/scipy?
Cheers,
Rory
I'm guessing that your problem is due to aliasing.
What is x in your example?
If the x values that you're interpolating at are less closely spaced than your original points, you'll inherently lose frequency information. This is completely independent from any type of interpolation. It's inherent in downsampling.
Nevermind the above bit about aliasing. It doesn't apply in this case (though I still have no idea what x is in your example...
I just realized that you're evaluating your points at the original input points when you're using a non-zero smoothing factor (s).
By definition, smoothing won't fit the data exactly. Try putting s=0 in instead.
As a quick example:
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
x = np.linspace(0, 6.*np.pi, num=100) #interval (0,6*pi) in 10'000 steps
A = 1.e-4 # Amplitude of sine function
y = A*np.sin(x)
fig, axes = plt.subplots(nrows=2)
for ax, s, title in zip(axes, [2, 0], ['With', 'Without']):
yinterp = interpolate.UnivariateSpline(x, y, s=s)(x)
ax.plot(x, yinterp, label='Interpolated')
ax.plot(x, y, 'bo',label='Original')
ax.legend()
ax.set_title(title + ' Smoothing')
plt.show()
The reason that you're only clearly seeing the effects of smoothing with a low amplitude is due to the way the smoothing factor is defined. See the documentation for scipy.interpolate.UnivariateSpline for more details.
Even with a higher amplitude, the interpolated data won't match the original data if you use smoothing.
For example, if we just change the amplitude (A) to 1.0 in the code example above, we'll still see the effects of smoothing...
The problem is in choosing suitable values for the s parameter. Its values depend on the scaling of the data.
Reading the documentation carefully, one can deduce that the parameter should be chosen around s = len(y) * np.var(y), i.e. # of data points * variance. Taking for example s = 0.05 * len(y) * np.var(y) gives a smoothing spline that does not depend on the scaling of the data or the number of data points.
EDIT: sensible values for s depend of course also on the noise level in the data. The docs seem to recommend choosing s in the range (m - sqrt(2*m)) * std**2 <= s <= (m + sqrt(2*m)) * std**2 where std is the standard deviation associated with the "noise" you want to smooth over.

Categories