简体   繁体   中英

Fit a curve with a sum using curve_fit

I am having a problem fitting a curve with scipy. This is the equation I want to fit my data in:

方程

This is the code:

import numpy as np
import os
from mpmath import *
from pandas import read_csv
from scipy.optimize import curve_fit
from matplotlib import pyplot
from sympy import *


M = 0.0129
L = 0.006
PI = np.pi

mp.dps=10


data = np.genfromtxt('Daten.csv',dtype=float,delimiter=',')

x = data[1:,0]
y = data[1:,0]

def objective(x,Mps,B,k,D):

    return (M-Mps)*(1-np.exp(-k*x))+ Mps*(-np.exp(-B*x)*np.power(D/(B*L*L),0.5)*np.power(np.tan((B*L*L)/D),0.5)- (8/(PI*PI))*\

nsum(lambda n: np.exp(-(2*n+1)*(2*n+1)*PI*PI*D*x/(4*L*L))/((2*n+1)*(2*n+1)*(1-(2*n+2)*(2*n+2)*(D*PI*PI/(4*B*L*L)))) ,[0,float('inf')]))


def obtainpar(x,y)
    popt,_ = curve_fit(objective,x,y)

    print '{Mps,B,k,D}=', popt

Then I obtain the following message:

Traceback (most recent call last):
  File "C:/Users/gerardo.salazar/Desktop/hector.py", line 29, in <module>
    popt,_ = curve_fit(objective,x,y)
  File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 763, in curve_fit
    res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 388, in leastsq
    shape, dtype = _check_func('leastsq', 'func', func, x0, args, n)
  File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 26, in _check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
  File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 463, in func_wrapped
    return func(xdata, *params) - ydata
  File "C:/Users/gerardo.salazar/Desktop/hector.py", line 27, in objective
    nsum(lambda n: np.exp(-(2*n+1)*(2*n+1)*PI*PI*D*x/(4*L*L))/((2*n+1)*(2*n+1)*(1-(2*n+2)*(2*n+2)*(D*PI*PI/(4*B*L*L)))) ,[0,float('inf')]))
  File "C:\ProgramData\Anaconda3\lib\site-packages\mpmath\calculus\extrapolation.py", line 1718, in nsum
    return +ctx.adaptive_extrapolation(update, emfun, options)
  File "C:\ProgramData\Anaconda3\lib\site-packages\mpmath\calculus\extrapolation.py", line 1165, in adaptive_extrapolation
    update(partial, xrange(index, index+step))
  File "C:\ProgramData\Anaconda3\lib\site-packages\mpmath\calculus\extrapolation.py", line 1706, in update
    psum = psum + g(ctx.mpf(k))
  File "C:\ProgramData\Anaconda3\lib\site-packages\mpmath\calculus\extrapolation.py", line 1753, in g
    return f(*args)
  File "C:\ProgramData\Anaconda3\lib\site-packages\mpmath\calculus\extrapolation.py", line 1808, in g
    return f(*args)
  File "C:/Users/gerardo.salazar/Desktop/hector.py", line 27, in <lambda>
    nsum(lambda n: np.exp(-(2*n+1)*(2*n+1)*PI*PI*D*x/(4*L*L))/((2*n+1)*(2*n+1)*(1-(2*n+2)*(2*n+2)*(D*PI*PI/(4*B*L*L)))) ,[0,float('inf')]))
TypeError: loop of ufunc does not support argument 0 of type mpf which has no callable exp method

I cannot share the data, but it is just a simply (x,y) points, nothing special. Thank you for the help and suggestion how could I make this happens.

As mentioned by @piterbarg there are several problems with mixing numpy and mpmath . My idea was to stay with mpmath and swap to numpy after the calculation of a value. curve_fit , etc. send numpy arrays though, such that I have to take care of the iterable object. Finally, it turns out that negative D and B are a problem. Instead of putting boundaries, which is an option of course, a use the absolute value inside the function. The result can be, hence, negative...but isn't.

Slightly cleaned up and augmented accordingly the code looks like:

import matplotlib.pyplot as plt
import numpy as np
from mpmath import pi as PI
from mpmath import nsum
from mpmath import exp
from mpmath import sqrt
from mpmath import tan
from scipy.optimize import curve_fit
from matplotlib import pyplot

M = 0.0129
L = 0.006

### might be of interest to:
# ~import mpmath
# ~mpmath.dps=10

def objective( x, Mps, b, k, d ):
    if isinstance( x, ( list, tuple, np.ndarray ) ):
        out = np.fromiter( 
            ( objective( item, Mps, b, k, d ) for item in x ), 
            np.float 
        ) ## always return np.array
    else:
        D = abs( d ) ### fails for neg
        B = abs( b ) ### fails for neg
        dil2 = D / L**2
        out = ( M - Mps ) * ( 1 - exp( -k * x ) )
        out += Mps * ( 
            -exp( -B * x ) * sqrt( dil2 / B ) 
            * sqrt( tan( B / dil2 ) ) 
            -8 / PI**2 
            * nsum( lambda n: 
                exp( -( 2 * n + 1 )**2 * PI**2 * dil2 * x / 4 ) / (
                    ( 2 * n + 1 )**2 * ( 1 - ( 2 * n + 2 )**2
                    * ( dil2 * PI**2 / ( 4 * B ) ) )
                ), [ 0, float( 'inf' ) ]
            )
        )
    return out

############ test
xl = np.linspace( -3, 15, 55 )
yl = objective( xl, 0.5, 1, 0.3, 1.2 )
yl *= np.random.normal( loc=1, scale=0.1, size=len( yl ) )


popt, pcov = curve_fit( objective, xl, yl, p0=[ 1, 1, 1, 1 ] )
print( popt )
print( pcov ) 
### always look at pcov
### shows that fit is basically insenitive to parameter D

xfull = np.linspace( -3, 15, 155 )
yfull = objective( xfull, *popt )

fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )

ax.plot( xl, yl, ls='', marker='o' )
ax.plot( xfull, yfull )

plt.show()

Note, importing everything via * is usually a bad idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM