Я пытаюсь подогнать Brillouin Spectra (с несколькими пиками) с помощью scipy.optimize.curve_fit. У меня есть несколько спектров с несколькими пиками, и я пытаюсь подогнать их с помощью лоренцевых функций (по одному лоренцеву на пик). Я пытаюсь автоматизировать процесс массового анализа (то есть, используя алгоритм поиска пиков scipy, чтобы получить положения пиков, ширину пиков и высоту пиков и использовать их в качестве начальных предположений для подгонки). Сейчас я работаю над одним спектром, чтобы увидеть, работает ли общая идея, затем я расширю его до автоматического c и буду работать со всеми имеющимися у меня спектрами. До сих пор я делал это:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
from scipy.optimize import curve_fit
#import y data from linked google sheet
y_data = np.loadtxt( 'y_peo.tsv' )
#define x data
x_data = np.arange( len( y_data ) )
#find peak properties (peak position, amplitude, full width half maximum ) to use as
#initial guesses for the curve_fit function
pk, properties = find_peaks(y_data, height = 3, width = 3, prominence=0.1 ) #pk returns peaks position, properties returns
#other properties associated with the peaks
I = properties ['peak_heights'] #amplitude
fwhm = (properties['widths']) #full width half maximum
#define sum of lorentzians
def func(x, *params):
y = np.zeros_like(x)
for i in range(0, len(params), 3):
x_0 = params[i]
I = params[i+1]
y_0 = params[i+2]
y = y + (I*y_0**2)/(y_0**2 +(x-x_0)**2)
return y
#initial guess list, to be populated with parameters found above (pk, I, fwhm)
guess = []
for i in range(len(pk)):
guess.append(pk[i])
guess.append(I[i])
guess.append(fwhm[i])
#convert list to array
guess=np.array(guess)
#fit
popt, pcov = curve_fit(func, x_data, y_data, p0=guess, method = 'lm', maxfev=1000000)
print(popt)
fit = func(x_data, *popt)
#plotting
fig= plt.figure(figsize=(10,5))
ax= fig.add_subplot(1,1,1)
ax.plot(pk, y_data[pk], 'o', ms=5)
ax.plot(x_data, y_data, 'ok', ms=1)
ax.plot(x_data, fit , 'r--', lw=0.5)
Где y_peo - зависимая переменная (вот значения в виде файла таблицы Google: https://docs.google.com/spreadsheets/d/1UB2lqs0Jmhthed7B0U9rznqcbpEMRmRX99c-iOBHLeE/edit?usp=sharing) а пиксель - независимая переменная (произвольный массив значений, созданный в коде). Вот что я получаю: Результат подбора спектра . Есть идеи, почему последняя тройка не подходит, как ожидалось? Я проверил, и все пики правильно найдены функцией scipy.signal.find_peaks - следовательно, я думаю, что проблема связана с scipy.optimize.curve_fit, поскольку мне пришлось увеличить количество maxfev, чтобы он «работал». Есть идеи, как решить эту проблему более разумным способом?
Заранее спасибо,
Джузеппе.