我试图从wolfram mathematica切换到python。我写了一个计算反射红外光谱的程序。现在我需要确保程序将理论谱调整到实验谱。为此,我决定使用curve_fit。但问题是curve_fit返回初始值,甚至没有尝试将参数拟合到所需的值。
你能帮我解决这个问题吗?
fir.py
import numpy as np
import time
import inspect
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from math import pi
from stack import stack
from tmm.parser import n_parser
from tmm.refindex import n_calc
from tmm.cohtmm import tmm
start_time = time.time()
print(f'===========START PROGRAM=============')
STACK = stack
def fit_func(x_data, x):
frame = inspect.currentframe()
args, _, _, values = inspect.getargvalues(frame)
print(f'Value - {x}')
parse_stack = n_parser(STACK, values)
d = [] # thickness
for layer in parse_stack:
if layer != 1:
d.append(layer['d'])
else:
d.append(np.inf)
r = np.array([])
for w in x_data:
n = np.array([])
for layer in parse_stack:
if layer != 1:
n_value, eps = n_calc(layer.get('n'), w)
n = np.append(n, n_value)
else:
n = np.append(n, 1)
# get reflectance power
l_vac = 10 ** (-2) / w
r_val = tmm('s', n, d, theta, l_vac)
r = np.append(r, r_val)
return r
"""
Input parameters
"""
degree = pi / 180
theta = 13 * degree # incidence angle
pol = 's' # polarisation
exp_file_name = 'result.txt' # experiment filename
# w_min = 350 # from wavelength
# w_max = 4000 # to wavelength
# Load and plot experimental result to np.array
exp_x, exp_y = np.loadtxt(exp_file_name, delimiter=' ', unpack=True)
init_values = [400]
low = [180]
high = [888]
popt, pcov = curve_fit(fit_func, exp_x, exp_y, p0=init_values, bounds=(low, high))
print(f'=========END ({round((time.time() - start_time), 3)} seconds)===========')
plt.figure()
plt.plot(exp_x, exp_y, exp_x, fit_func(exp_x, *popt))
plt.show()
stack.py
from numpy import inf
substrate = {
'd': inf, # thickness
'n': { # values for calculation refractive index
'wLO': ['x', 480.249, 629.181, 909],
'gLO': [2.8, 2.1, 6.5, 19.3],
'wTO': [383.925, 438.887, 567.759, 634.194],
'gTO': [2.7, 3.1, 4.5, 4.9],
'eps_inf': [3.07],
'function': 'general' # eq. for calculation refractive index
}
}
"""
Description of layer composition in sample
Layer numbered from top to bottom.
For vacuum or air - set 1
NOTE: first and last layer must be with infinite thickness
"""
stack = [1, substrate]
更新 cohtmm
import numpy as np
import scipy as sp
from math import pi, exp
def theta_calc(n, theta0):
"""
Calculate theta from Snell law
:param n: np.array of refractive index
:param theta0: angle of incidence
:return: np.array on angles
"""
theta_list = sp.arcsin((n[0]*np.sin(theta0)) / n)
return np.array(theta_list, dtype=complex)
def r_amplitude(n0, theta0, n1, theta1):
"""
Calculate amplitude value of reflectance (Fresnel equations)
:param n0: complex n0 from eq.
:param theta0: complex theta0 from eq.
:param n1: complex n1 from eq.
:param theta1: complex theta1 from eq.
:return: complex amplitude value of reflectance
TODO calc only for s-pol!!!
"""
r = (n0*np.cos(theta0) - n1*np.cos(theta1)) / (n0*np.cos(theta0) + n1*np.cos(theta1))
return np.array(r, dtype=complex)
def t_amplitude(n0, theta0, n1, theta1):
"""
Calculate amplitude value of transmittance (Fresnel equations)
:param n0: complex n0 from eq.
:param theta0: complex theta0 from eq.
:param n1: complex n1 from eq.
:param theta1: complex theta1 from eq.
:return: complex amplitude value of reflectance
TODO calc only for s-pol!!!
"""
t = (2*n0*np.cos(theta0)) / (n0*np.cos(theta0) + n1*np.cos(theta1))
return np.array(t, dtype=complex)
def create_matrix(a, b, c, d):
"""
Fast way to create 2X2 np matrix
:param a: [0 0]
:param b: [0 1]
:param c: [1 0]
:param d: [1 1]
:return: 2X2 matrix
"""
new_array = np.empty((2, 2), dtype=complex)
new_array[0, 0] = a
new_array[0, 1] = b
new_array[1, 0] = c
new_array[1, 1] = d
return new_array
def tmm(pol, n, d, theta0, l_vac):
"""
General function to calculate tmm
:param pol: s or p polarization TODO: realization only for s-pol
:param n: np.array of refractive index for each layer
:param d: np.array of thickness
:param theta0: angle og incidence
:param l_vac: wavelength
:return: refractive index TODO: add different params to return (transm, absorbance etc.)
"""
num_layers = n.size # number of layers in stack
theta = theta_calc(n, theta0) # list on angle theta for each layer
d = np.array(d, dtype=complex) # np.array of thickness
# calculate phase shift (ignore warning about inf multiplication
kz = 2*pi*n*np.cos(theta) / l_vac
olderr = sp.seterr(invalid='ignore')
delta = kz * d
sp.seterr(**olderr)
# print(f"d={d}, n={n}, theta0={theta0}, l_vac={l_vac} delta={delta}")
"""
[num_layers num_layers] matrix for transmittance and reflectance
2D array is overkill but very help to correct writing matrix
"""
t_list = np.zeros((num_layers, num_layers), dtype=complex)
r_list = np.zeros((num_layers, num_layers), dtype=complex)
for i in range(num_layers-1):
t_list[i, i+1] = t_amplitude(n[i], theta[i], n[i+1], theta[i+1])
r_list[i, i+1] = r_amplitude(n[i], theta[i], n[i+1], theta[i+1])
"""
calculate transfer matrix m_tilde
"""
m_list = np.zeros((num_layers, 2, 2), dtype=complex) # list of matrices
for i in range(1, num_layers-1):
m1 = create_matrix(1, r_list[i, i+1], r_list[i, i+1], 1)
m2 = create_matrix(np.exp(-1j*delta[i]), 0, 0, np.exp(1j*delta[i]))
m_list[i] = (1/t_list[i, i+1]) * np.dot(m2, m1)
m_tilde = create_matrix(1, 0, 0, 1)
for i in range(1, num_layers-1):
m_tilde = np.dot(m_tilde, m_list[i])
m_tilde = np.dot((1/(t_list[0, 1])*create_matrix(1, r_list[0, 1], r_list[0, 1], 1)), m_tilde)
# Get complex reflection amplitude TODO add amplitude transmittance
r = m_tilde[1, 0] / m_tilde[0, 0]
# Get reflection power as f proportion of incoming light TODO add transmittance power
R = np.abs(r)**2
return R
parser.py
"""
TODO add script description
"""
def n_parser(stack, values):
"""
TODO add func description
:param stack:
:param values:
:return:
"""
del values['frame']
del values['x_data']
args = values.keys()
for i in args:
for layer in stack:
if layer != 1:
n = layer.get('n')
for key in n.keys():
if key != "function":
n[key] = [values[i] if j == i else j for j in n[key]]
return stack