Python 求两条三次曲线之间的公共切线

Python 求两条三次曲线之间的公共切线,python,numpy,scipy,sympy,equation-solving,Python,Numpy,Scipy,Sympy,Equation Solving,给定两个函数,我想整理两条曲线的公共切线: 公共切线的斜率可通过以下方式获得: slope of common tangent = (f(x1) - g(x2)) / (x1 - x2) = f'(x1) = g'(x2) 61.6634100000000 -941.2375622594436 62.3429030000000 -941.2377748739724 62.9226515000000 -941.2378903605746 63.0043440000000 -941.237898

给定两个函数,我想整理两条曲线的公共切线:

公共切线的斜率可通过以下方式获得:

slope of common tangent = (f(x1) - g(x2)) / (x1 - x2) = f'(x1) = g'(x2)
61.6634100000000 -941.2375622594436
62.3429030000000 -941.2377748739724
62.9226515000000 -941.2378903605746
63.0043440000000 -941.2378981684135
63.7160150000000 -941.2378864590100
64.4085050000000 -941.2377753645115
65.1046835000000 -941.2375332100225
65.8049585000000 -941.2372030376584
66.5093925000000 -941.2367456992965
67.2180970000000 -941.2361992239395
67.9311515000000 -941.2355493856510
54.6569312500000 -941.2300821583739
55.3555152500000 -941.2312112888004
56.1392347500000 -941.2326135552780
56.9291575000000 -941.2338291772218
57.6992532500000 -941.2348135408652
58.4711572500000 -941.2356230099117
59.2666985000000 -941.2362715934311
60.0547935000000 -941.2367074271724
60.8626545000000 -941.2370273047416
最后我们得到了一个由两个方程组成的系统,其中有两个未知数:

f'(x1) = g'(x2) # Eq. 1
(f(x1) - g(x2)) / (x1 - x2) = f'(x1) # Eq. 2
出于某种原因,我不明白,python没有找到解决方案:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import sys
from sympy import *
import sympy as sym


# Intial candidates for fit 
E0_init = -941.510817926696
V0_init = 63.54960592453
B0_init = 76.3746233515232
B0_prime_init = 4.05340727164527

# Data 1 (Red triangles): 
V_C_I, E_C_I = np.loadtxt('./1.dat', skiprows = 1).T

# Data 14 (Empty grey triangles):
V_14, E_14 = np.loadtxt('./2.dat', skiprows = 1).T

def BM(x, a, b, c, d):
        return  (2.293710449E+17)*(1E-21)* (a + b*x + c*x**2 + d*x**3 )

def P(x, b, c, d):
    return -b - 2*c*x - 3 *d*x**2

init_vals = [E0_init, V0_init, B0_init, B0_prime_init]
popt_C_I, pcov_C_I = curve_fit(BM, V_C_I, E_C_I, p0=init_vals)
popt_14, pcov_14 = curve_fit(BM, V_14, E_14, p0=init_vals)

x1 = var('x1')
x2 = var('x2')

E1 = P(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) - P(x2, popt_14[1], popt_14[2], popt_14[3])
print 'E1 = ', E1

E2 = ((BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - BM(x2, popt_14[0], popt_14[1], popt_14[2], popt_14[3])) / (x1 - x2)) - P(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])

sols = solve([E1, E2], [x1, x2])

print 'sols = ', sols

# Linspace for plotting the fitting curves:
V_C_I_lin = np.linspace(V_C_I[0], V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0], V_14[-1], 10000)

plt.figure()
# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black', label='Cubic fit data 1' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b', label='Cubic fit data 2')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='Data 1', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='Data 2', s=100)

plt.ticklabel_format(useOffset=False)
plt.show()

1.dat
如下所示:

slope of common tangent = (f(x1) - g(x2)) / (x1 - x2) = f'(x1) = g'(x2)
61.6634100000000 -941.2375622594436
62.3429030000000 -941.2377748739724
62.9226515000000 -941.2378903605746
63.0043440000000 -941.2378981684135
63.7160150000000 -941.2378864590100
64.4085050000000 -941.2377753645115
65.1046835000000 -941.2375332100225
65.8049585000000 -941.2372030376584
66.5093925000000 -941.2367456992965
67.2180970000000 -941.2361992239395
67.9311515000000 -941.2355493856510
54.6569312500000 -941.2300821583739
55.3555152500000 -941.2312112888004
56.1392347500000 -941.2326135552780
56.9291575000000 -941.2338291772218
57.6992532500000 -941.2348135408652
58.4711572500000 -941.2356230099117
59.2666985000000 -941.2362715934311
60.0547935000000 -941.2367074271724
60.8626545000000 -941.2370273047416
2.dat
如下所示:

slope of common tangent = (f(x1) - g(x2)) / (x1 - x2) = f'(x1) = g'(x2)
61.6634100000000 -941.2375622594436
62.3429030000000 -941.2377748739724
62.9226515000000 -941.2378903605746
63.0043440000000 -941.2378981684135
63.7160150000000 -941.2378864590100
64.4085050000000 -941.2377753645115
65.1046835000000 -941.2375332100225
65.8049585000000 -941.2372030376584
66.5093925000000 -941.2367456992965
67.2180970000000 -941.2361992239395
67.9311515000000 -941.2355493856510
54.6569312500000 -941.2300821583739
55.3555152500000 -941.2312112888004
56.1392347500000 -941.2326135552780
56.9291575000000 -941.2338291772218
57.6992532500000 -941.2348135408652
58.4711572500000 -941.2356230099117
59.2666985000000 -941.2362715934311
60.0547935000000 -941.2367074271724
60.8626545000000 -941.2370273047416
更新:使用@if。。。。方法:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

# Intial candidates for fit, per FU: - thus, the E vs V input data has to be per FU
E0_init = -941.510817926696   
V0_init = 63.54960592453  
B0_init = 76.3746233515232  
B0_prime_init = 4.05340727164527 

def BM(x, a, b, c, d):
         return  a + b*x + c*x**2 + d*x**3 

def devBM(x, b, c, d):
         return  b + 2*c*x + 3*d*x**2 

# Data 1 (Red triangles): 
V_C_I, E_C_I = np.loadtxt('./1.dat', skiprows = 1).T

# Data 14 (Empty grey triangles):
V_14, E_14 = np.loadtxt('./2.dat', skiprows = 1).T

init_vals = [E0_init, V0_init, B0_init, B0_prime_init]
popt_C_I, pcov_C_I = curve_fit(BM, V_C_I, E_C_I, p0=init_vals)
popt_14, pcov_14 = curve_fit(BM, V_14, E_14, p0=init_vals)

from scipy.optimize import fsolve
def equations(p):
    x1, x2 = p
    E1 = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) - devBM(x2, popt_14[1], popt_14[2], popt_14[3])
    E2 = ((BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - BM(x2, popt_14[0], popt_14[1], popt_14[2], popt_14[3])) / (x1 - x2)) - devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
    return (E1, E2)

x1, x2 =  fsolve(equations, (50, 60))
print 'x1 = ', x1
print 'x2 = ', x2

slope_common_tangent = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
print 'slope_common_tangent = ', slope_common_tangent

def comm_tangent(x, x1, slope_common_tangent):
   return BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - slope_common_tangent * x1 + slope_common_tangent * x

# Linspace for plotting the fitting curves:
V_C_I_lin = np.linspace(V_C_I[0], V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0], V_14[-1], 10000)

plt.figure()

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black', label='Cubic fit Calcite I' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b', label='Cubic fit Calcite II')

xp = np.linspace(54, 68, 100)
pcomm_tangent, = plt.plot(xp, comm_tangent(xp, x1, slope_common_tangent), 'green', label='Common tangent')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='Calcite I', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='Calcite II', s=100)

fontP = FontProperties()
fontP.set_size('13')

plt.legend((p1, p2, p5, p6, pcomm_tangent), ("1", "Cubic fit 1", "2", 'Cubic fit 2', 'Common tangent'), prop=fontP)

print 'devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) = ', devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])

plt.ylim(-941.240, -941.225) 
plt.ticklabel_format(useOffset=False)

plt.show()
我能够找到公共切线,如下所示:

但是,此公共切线对应于数据范围之外区域中的公共切线,即使用

V_C_I_lin = np.linspace(V_C_I[0]-30, V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0]-20, V_14[-1]+2, 10000)
xp = np.linspace(40, 70, 100)
plt.ylim(-941.25, -941.18)
可以看到以下内容:

slope of common tangent = (f(x1) - g(x2)) / (x1 - x2) = f'(x1) = g'(x2)
61.6634100000000 -941.2375622594436
62.3429030000000 -941.2377748739724
62.9226515000000 -941.2378903605746
63.0043440000000 -941.2378981684135
63.7160150000000 -941.2378864590100
64.4085050000000 -941.2377753645115
65.1046835000000 -941.2375332100225
65.8049585000000 -941.2372030376584
66.5093925000000 -941.2367456992965
67.2180970000000 -941.2361992239395
67.9311515000000 -941.2355493856510
54.6569312500000 -941.2300821583739
55.3555152500000 -941.2312112888004
56.1392347500000 -941.2326135552780
56.9291575000000 -941.2338291772218
57.6992532500000 -941.2348135408652
58.4711572500000 -941.2356230099117
59.2666985000000 -941.2362715934311
60.0547935000000 -941.2367074271724
60.8626545000000 -941.2370273047416

是否可以将解算器约束到有数据的范围,以找到所需的公切线

更新2.1:使用@if。。。。范围限制方法,以下代码生成
x1=61.2569899
x2=59.7677843
。如果我们绘制它:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import sys
from sympy import *
import sympy as sym
import os

# Intial candidates for fit, per FU: - thus, the E vs V input data has to be per FU
E0_init = -941.510817926696  # -1882.50963222/2.0 
V0_init = 63.54960592453 #125.8532/2.0 
B0_init = 76.3746233515232 #74.49 
B0_prime_init = 4.05340727164527 #4.15

def BM(x, a, b, c, d):
         return  a + b*x + c*x**2 + d*x**3

def devBM(x, b, c, d):
         return  b + 2*c*x + 3*d*x**2

# Data 1 (Red triangles): 
V_C_I, E_C_I = np.loadtxt('./1.dat', skiprows = 1).T

# Data 14 (Empty grey triangles):
V_14, E_14 = np.loadtxt('./2.dat', skiprows = 1).T

init_vals = [E0_init, V0_init, B0_init, B0_prime_init]
popt_C_I, pcov_C_I = curve_fit(BM, V_C_I, E_C_I, p0=init_vals)
popt_14, pcov_14 = curve_fit(BM, V_14, E_14, p0=init_vals)

def equations(p):
    x1, x2 = p
    E1 = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) - devBM(x2, popt_14[1], popt_14[2], popt_14[3])
    E2 = ((BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - BM(x2, popt_14[0], popt_14[1], popt_14[2], popt_14[3])) / (x1 - x2)) - devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
    return (E1, E2)

from scipy.optimize import least_squares
lb = (61.0, 59.0)   # lower bounds on x1, x2
ub = (62.0, 60.0)    # upper bounds
result = least_squares(equations, [61, 59], bounds=(lb, ub))
print 'result = ', result

# The result obtained is:
# x1 = 61.2569899
# x2 = 59.7677843

slope_common_tangent = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
print 'slope_common_tangent = ', slope_common_tangent


def comm_tangent(x, x1, slope_common_tangent):
   return BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - slope_common_tangent * x1 + slope_common_tangent * x

# Linspace for plotting the fitting curves:
V_C_I_lin = np.linspace(V_C_I[0]-2, V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0], V_14[-1]+2, 10000)


fig_handle = plt.figure()

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b' )

xp = np.linspace(54, 68, 100)
pcomm_tangent, = plt.plot(xp, comm_tangent(xp, x1, slope_common_tangent), 'green', label='Common tangent')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='1', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='2', s=100)

fontP = FontProperties()
fontP.set_size('13')

plt.legend((p1, p2, p5, p6, pcomm_tangent), ("1", "Cubic fit 1", "2", 'Cubic fit 2', 'Common tangent'), prop=fontP)


plt.ticklabel_format(useOffset=False)

plt.show()
我们发现,我们没有获得公共切线:

符号根查找 你的方程组由一个二次方程和一个三次方程组成。这种系统没有封闭形式的符号解。事实上,如果有,人们可以将其应用于一般的五次方程
x**5+a*x**4+…=0
通过引入
y=x**2
(二次型)并将原始方程改写为
x*y**2+a*y**2+…=0(立方)。我们知道这一点。所以SymPy解决不了这个问题也就不足为奇了。您需要一个数值解算器(另一个原因是Symphy并不是真正设计用来解满是浮点常量的方程的,它们对于符号操作来说很麻烦)

数值根查找 这是我想到的第一件事。你可以这样做:

def F(x):
    x1, x2 = x[0], x[1]
    E1 = P(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) - P(x2, popt_14[1], popt_14[2], popt_14[3])
    E2 = ((BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - BM(x2, popt_14[0], popt_14[1], popt_14[2], popt_14[3])) / (x1 - x2)) - P(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
    return [E1, E2] 

print fsolve(F, [50, 60])    # some reasonable initial point
顺便说一下,我将(x1-x2)从E2中的分母移开,将E2重写为

(...) - (x1 - x2) * P(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
所以系统是多项式的。这可能会使
fsolve
的生活变得更轻松

范围限制:最小化
fsolve
及其相关项(如
root
)都不支持在变量上设置边界。但是您可以使用
最小二乘法
,它将查找表达式E1、E2的平方和的最小值。它支持上限和下限,如果幸运的话,最小值(“成本”)将在机器精度范围内为0,表示您找到了根。一个抽象的例子(因为我没有你的数据):

输出:

 active_mask: array([0, 0])
        cost: 2.524354896707238e-29
         fun: array([7.10542736e-15, 0.00000000e+00])
        grad: array([1.93525199e-13, 1.34611132e-13])
         jac: array([[27.23625045, 18.94483256],
       [66.10672633, -0.        ]])
     message: '`gtol` termination condition is satisfied.'
        nfev: 8
        njev: 8
  optimality: 2.4802477446153134e-13
      status: 1
     success: True
           x: array([ 2.26968753, -0.15747203])

成本非常小,所以我们有一个解决方案,它是x。通常,将
最小二乘法的输出分配给某个变量
res
,并从那里访问
res.x

多亏了所有@if。。。。帮助,通过运行此答案末尾发布的以下代码,讨论了3条路径的结果:

1)
最小平方
带默认公差: 成本为零,找到的公切线非常接近,但不理想:

2)
最小平方
公差更紧: 我原以为成本会更高,但由于某种原因我不明白,成本甚至更低。找到的公共切线更接近:

3)使用
fsolve
但限制区域 我们在帖子中看到,当使用
x1,x2=fsolve(等式,(50,60))
时,找到的公共切线不是正确的(第二张和第三张图片)。然而,如果我们使用
x1,x2=fsolve(方程式,(61.5,62))

我们发现,发现的斜率与
最小二乘法非常相似,公差更紧。因此,找到的公共切线也非常接近:

此表总结了结果:

产生以下三种途径的代码:

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import sys
from sympy import *
import sympy as sym
import os
import pickle as pl


# Intial candidates for fit, per FU: - thus, the E vs V input data has to be per FU
E0_init = -941.510817926696  # -1882.50963222/2.0 
V0_init = 63.54960592453 #125.8532/2.0 
B0_init = 76.3746233515232 #74.49 
B0_prime_init = 4.05340727164527 #4.15

def BM(x, a, b, c, d):
         return  a + b*x + c*x**2 + d*x**3 

def devBM(x, b, c, d):
         return  b + 2*c*x + 3*d*x**2 

# Data 1 (Red triangles): 
V_C_I, E_C_I = np.loadtxt('./1.dat', skiprows = 1).T

# Data 14 (Empty grey triangles):
V_14, E_14 = np.loadtxt('./2.dat', skiprows = 1).T

init_vals = [E0_init, V0_init, B0_init, B0_prime_init]
popt_C_I, pcov_C_I = curve_fit(BM, V_C_I, E_C_I, p0=init_vals)
popt_14, pcov_14 = curve_fit(BM, V_14, E_14, p0=init_vals)


def equations(p):
    x1, x2 = p
    E1 = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3]) - devBM(x2, popt_14[1], popt_14[2], popt_14[3])
    E2 = ((BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - BM(x2, popt_14[0], popt_14[1], popt_14[2], popt_14[3])) / (x1 - x2)) - devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
    return (E1, E2)

from scipy.optimize import least_squares
lb = (61.0, 59.0)   # lower bounds on x1, x2
ub = (62.0, 60.0)   # upper bounds
result = least_squares(equations, [61, 59], bounds=(lb, ub))
result_tight_tols = least_squares(equations, [61, 59], ftol=1e-12, xtol=1e-12, gtol=1e-12, bounds=(lb, ub))

print """
####  ftol=1e-08, xtol=1e-08, gtol=1e-08  #####
"""
print 'result = ', result
print 'result.x = ', result.x
print """

"""
x1 = result.x[0]
x2 = result.x[1]

slope_common_tangent = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
print 'slope_common_tangent = ', slope_common_tangent

def comm_tangent(x, x1, slope_common_tangent):
   return BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - slope_common_tangent * x1 + slope_common_tangent * x

# Linspace for plotting the fitting curves:
V_C_I_lin = np.linspace(V_C_I[0]-2, V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0], V_14[-1]+2, 10000)


plt.figure()

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b' )

xp = np.linspace(54, 68, 100)
pcomm_tangent, = plt.plot(xp, comm_tangent(xp, x1, slope_common_tangent), 'green', label='Common tangent')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='1', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='2', s=100)

fontP = FontProperties()
fontP.set_size('13')

plt.legend((p1, p2, p5, p6, pcomm_tangent), ("1", "Cubic fit 1", "2", 'Cubic fit 2', 'Common tangent'), prop=fontP)
plt.title('Least squares. Default tolerances: ftol=1e-08, xtol=1e-08, gtol=1e-08')

plt.ticklabel_format(useOffset=False)

### Tighter tolerances:
print """
####  ftol=1e-12, xtol=1e-12, gtol=1e-12  #####
"""
print 'result_tight_tols = ', result_tight_tols
print 'result_tight_tols.x = ', result_tight_tols.x
print """

"""
x1 = result_tight_tols.x[0]
x2 = result_tight_tols.x[1]

slope_common_tangent = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
print 'slope_common_tangent = ', slope_common_tangent

def comm_tangent(x, x1, slope_common_tangent):
   return BM(x1, popt_C_I[0], popt_C_I[1], popt_C_I[2], popt_C_I[3]) - slope_common_tangent * x1 + slope_common_tangent * x

# Linspace for plotting the fitting curves:
V_C_I_lin = np.linspace(V_C_I[0]-2, V_C_I[-1], 10000)
V_14_lin = np.linspace(V_14[0], V_14[-1]+2, 10000)


plt.figure()

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b' )

xp = np.linspace(54, 68, 100)
pcomm_tangent, = plt.plot(xp, comm_tangent(xp, x1, slope_common_tangent), 'green', label='Common tangent')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='1', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='2', s=100)

fontP = FontProperties()
fontP.set_size('13')

plt.legend((p1, p2, p5, p6, pcomm_tangent), ("1", "Cubic fit 1", "2", 'Cubic fit 2', 'Common tangent'), prop=fontP)
plt.title('ftol=1e-08, xtol=1e-08, gtol=1e-08')

plt.ticklabel_format(useOffset=False)

plt.title('Lest Squares. Tightening tolerances: ftol=1e-12, xtol=1e-12, gtol=1e-12')

print """
#### Using `fsolve`, but restricting the region:  ####

"""

from scipy.optimize import fsolve
x1, x2 =  fsolve(equations, (61.5, 62))

print 'x1 = ', x1
print 'x2 = ', x2

slope_common_tangent = devBM(x1, popt_C_I[1], popt_C_I[2], popt_C_I[3])
print 'slope_common_tangent = ', slope_common_tangent

plt.figure()

# Plotting the fitting curves:
p2, = plt.plot(V_C_I_lin, BM(V_C_I_lin, *popt_C_I), color='black' )
p6, = plt.plot(V_14_lin, BM(V_14_lin, *popt_14), 'b' )

xp = np.linspace(54, 68, 100)
pcomm_tangent, = plt.plot(xp, comm_tangent(xp, x1, slope_common_tangent), 'green', label='Common tangent')

# Plotting the scattered points: 
p1 = plt.scatter(V_C_I, E_C_I, color='red', marker="^", label='1', s=100)
p5 = plt.scatter(V_14, E_14, color='grey', marker="^", facecolors='none', label='2', s=100)

fontP = FontProperties()
fontP.set_size('13')

plt.legend((p1, p2, p5, p6, pcomm_tangent), ("1", "Cubic fit 1", "2", 'Cubic fit 2', 'Common tangent'), prop=fontP)
plt.ticklabel_format(useOffset=False)

plt.title('Using `fsolve`, but restricting the region')



plt.show()

一个最简单的例子是从立方参数开始,如果你的问题是你认为的,我们不需要拟合过程。非常感谢你的回答。我已经实现了你的方法,但不幸的是,这并没有得到正确的等式。请参阅更新的帖子。方程式E1和E2基于P是BM的导数的假设。在您的代码中,P不是BM的导数。因此,您需要BM的导数。错误消息准确地说明了问题所在:初始点不可行(意思是:不满足约束)。第一个坐标的下限是61,但初始值是60,很接近。导数在这两点上看起来差不多,切线在另一点上也非常接近切线。似乎最小的决定它足够好,并停止。您应该阅读它的输出,看看什么终止条件是导致停止的原因,并通过减少相应的参数来收紧它。默认停止参数为ftol=1e-08、xtol=1e-08、gtol=1e-08;请参阅读取最小二乘法的完整输出也很有用,因为它包含成本,成本应该非常接近于0。如果不是,则您知道即使不绘制解决方案,该解决方案也不会很好。您没有在
fsolve
中限制区域,因此没有此类选项。您提供的元组
(61.5,62)
,用作起点x0(请参阅)。如果起点更接近您想要的解决方案,
fsolve
更有可能找到它,而不是离开某个地方,最终收敛到另一个不想要的解决方案。