scipy.optimize curve_fit返回参数

时间:2018-04-10 18:53:22

标签: python scipy curve-fitting

我试图从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

0 个答案:

没有答案