最近有個朋友讓我幫忙做個計算,工具不限。考慮到方便快捷,於是選擇了python。
其核心要求是做一個函數擬合,但是被擬合函數是個積分表達式。最簡單的方法是利用scipy庫中的函數來做,下面是源代碼。
# -*- coding: utf-8 -*-
from scipy import integrate
from scipy import optimize
from matplotlib import pyplot
import numpy
import pandas
import time
I = complex(0, 1)
def tmp(E, params):
global I
Z = params[1]
delta = params[2]
Gamma = params[3]
complex_num = 0.5 + numpy.sqrt(pow(E+I*Gamma, 2)-delta*delta)/(2*(E+I*Gamma))
alpha = complex_num.real
eta = complex_num.imag
beta = 1 - alpha
gamma = numpy.sqrt( numpy.power(alpha+Z*Z*(alpha-beta), 2)
+ numpy.power(eta*(2*Z*Z+1), 2) )
return alpha, beta, gamma, eta
def factor(E, params):
P = params[0]
Z = params[1]
alpha, beta, gamma, eta = tmp(E, params)
numerator1 = numpy.sqrt((alpha*alpha+eta*eta)*(beta*beta+eta*eta))
denominator1 = gamma*gamma
AE = numerator1/denominator1
numerator2 = Z*Z*( numpy.power((alpha-beta)*Z-2*eta, 2)
+ numpy.power(2*eta*Z+(alpha-beta), 2) )
denominator2 = gamma*gamma
BE = numerator2/denominator2
return 1+(1-P)*AE-BE
def dfdV_mod(E, V):
variable = E - V
if (variable >= 0):
exp = numpy.exp(-variable)
else:
exp = numpy.exp(variable)
numerator = -exp
denominator = numpy.power(exp+1, 2)
return numerator/denominator
# 被積函數
def integrand(E, V, params):
return dfdV_mod(E, V)*factor(E, params)
# 積分
def integral(V, params):
result = integrate.quad(integrand, -numpy.inf, numpy.inf, args=(V, params))
return result[0]
# 畫圖時計算積分
def integral_all(V, params):
result = numpy.zeros(V.size)
for i in range(0, V.size):
res = integrate.quad(integrand, -numpy.inf, numpy.inf, args=(V[i], params))
result[i] = res[0]
return result
# 實驗測量值與理論值的偏差
def residual(params, g, V):
res = numpy.zeros(g.size)
for i in range(0, g.size):
res[i] = g[i] - integral(V[i], params)
return res
# 將實驗數據讀入,需在實驗數據中添加表頭
def ReadData(path):
dataframe = pandas.read_excel(path, sheet_name=0)
x = numpy.array(dataframe.iloc[:, 0])
y = numpy.array(dataframe.iloc[:, 1])
return y, x
if __name__ == '__main__':
start = time.time()
# 賦初值
P = 0.5
Z = 1
delta = 0
Gamma = 0
# 讀入數據
g, V = ReadData("data.xlsx")
# 最小二乘法擬合
params0 = numpy.array([P, Z, delta, Gamma])
result = optimize.least_squares(residual, params0, bounds=([-1, -5, -1, -1], [1, 5, 1, 1]), args=(g, V))
print("result: " + str(result))
# 畫出結果
params = result.x
V_test = numpy.linspace(V.min(), V.max(), 100)
g_test = integral_all(V_test, params)
pyplot.plot(V, g, 'o', markersize=1, label='data')
pyplot.plot(V_test, g_test, label='fitted curve')
pyplot.xlabel('V')
pyplot.ylabel('g')
pyplot.show()
end = time.time()
print("time elapsed: " + str(end-start) + "s")
從代碼來看還是很清晰的,主要用到兩個函數,一個是integrate.quad,用來算積分,另一個是optimize.least_squares,利用最小二乘法給出函數參數值。