Неправильный вывод Voigt / свертка с асимметричным вводом x - PullRequest
0 голосов
/ 05 ноября 2018

В настоящее время я подгоняю данные Гаусса или Лоренца к своим данным, но оба не подходят достаточно хорошо, и я хочу переключиться на подгонку Фойгта, свертку их обоих.

Я извлек функцию Voigt из https://www.originlab.com/doc/Origin-Help/Voigt-FitFunc и записал ее в python.

import numpy as np
import matplotlib.pyplot as plt

def lorentz_voigt(x, A, xc, wL):
    return (2*A / np.pi) * (wL / ((4*(x.astype(float) - xc)**2) + wL**2))

def gauss_voigt(x, wG):
    return np.sqrt((4*np.log(2)) / np.pi) * ((np.exp(-(((4*np.log(2)) / (wG**2))*(x.astype(float))**2))) / (wG))

def Voigt(x, xc, A, wG, wL):
    return np.convolve(lorentz_voigt(x, A, xc, wL), gauss_voigt(x, wG), 'same')

symx = np.linspace(-100, 100, 1001)
asymx = np.linspace(0, 100, 1001)
symy = Voigt(symx, 50, 1, 5, 5)
asymy = Voigt(asymx, 50, 1, 5, 5)
plt.clf()
plt.plot(symx, symy)
plt.plot(asymx, asymy)

Как видно на графике ниже, функция Voigt с асимметричным вводом по оси x оранжевого цвета не воспроизводит правильный профиль Voigt, как показано синим цветом. Two outputs of the Voigt function, blue symmetric, orange asymmetric

Мои данные представлены в волновых числах от 600-4000 см -1 , и я хотел бы знать, нужно ли мне добавлять нули к моим данным от -4000 до 600 см -1 потому что это чисто математическое ограничение свертки или есть ошибка в / решении для моего кода?

1 Ответ

0 голосов
/ 06 ноября 2018

Свертка ничего не знает об оси х. Лучше всего вернуть полную свертку, а затем уменьшить ее до исходного диапазона х, например ::1001*

import numpy as np
import matplotlib.pyplot as plt

def lorentz_voigt(x, A, xc, wL):
    return (2*A / np.pi) * (wL / ((4*(x.astype(float) - xc)**2) + wL**2))

def gauss_voigt(x, xc, wG):
    return np.sqrt((4*np.log(2)) / np.pi) * ((np.exp(-(((4*np.log(2)) / (wG**2))*((x-xc).astype(float))**2))) / (wG))

def Voigt(x, xc, A, wG, wL):
    return np.convolve(lorentz_voigt(x, A, xc, wL), gauss_voigt(x, xc, wG), 'full')

symx = np.linspace(-100, 100, 1001)
asymx = np.linspace(0, 200, 1001)
symy = Voigt(symx, 50, 1, 5, 5)[::2]
asymy = Voigt(asymx, 50, 1, 5, 5)[::2]

plt.clf()
plt.plot(symx, symy,'r')
plt.plot(asymx, asymy,'b--')

Также обратите внимание, что ваше определение gauss_voigt не соответствует центральному кординату xc.

resulting graph

Как я уже сказал в комментарии выше, есть другой способ вычисления функции voigt, который не основан на свертке. Свертка является дорогой с точки зрения времени вычислений, что может раздражать при использовании в качестве модели подгонки. Следующий пример кода не нуждается в свертке.

import matplotlib.pyplot as plt
import numpy as np
from scipy.special import wofz

def voigt(x, amp, pos, fwhm, shape):
    tmp = 1/wofz(np.zeros((len(x))) +1j*np.sqrt(np.log(2.0))*shape).real
    return tmp*amp*wofz(2*np.sqrt(np.log(2.0))*(x-pos)/fwhm+1j*np.sqrt(np.log(2.0))*shape).real

x = np.linspace(0, 100, 1001)
y0 = voigt(x, 1, 50, 5, 0)
y1 = voigt(x, 1, 50, 5, 1)
plt.plot(x,y0,'k',label='shape = 0')
plt.plot(x,y1,'b',label='shape = 1')
plt.legend(loc=0)
plt.show()

graph generated using wofz

...