Используя либо lmfit.Model, либо scipy.optimize.curve_fit, я должен оптимизировать функцию, выходные данные которой необходимо свернуть с некоторыми экспериментальными данными, прежде чем они будут соответствовать некоторым другим экспериментальным данным. Подводя итог, рабочий процесс выглядит примерно так:
(1) Функция A определена (например, функция Гаусса). (2) Выход функции A свернут с экспериментальным сигналом, называемым данными B. (3) Параметры функции A оптимизированы для свертки, упомянутой в (2), чтобы полностью соответствовать некоторым другим экспериментальным данным, называемым данными C.
Я сворачиваю вывод функции A с данными B, используя преобразования Фурье, следующим образом:
from scipy.fftpack import fft, ifft
def convolve(data_B, function_A):
convolved = ifft(fft(IRF) * fft(model)).real
return convolved
Как я могу использовать lmfit.Model или scipy.optimize.curve_fit для соответствия «свернутым» данным C?
Обновлено: В ответ на представленный ответ я включил свой шаг свертки в уравнение, используемое для подгонки, следующим образом:
#1 component exponential distribution:
def ExpDecay_1(x, ampl1, tau1, y0, x0, args=(new_y_irf)): # new_y_irf is a list.
h = np.zeros(x.size)
lengthVec = len(new_y_decay)
shift_1 = np.remainder(np.remainder(x-np.floor(x0)-1, lengthVec) + lengthVec, lengthVec)
shift_Incr1 = (1 - x0 + np.floor(x0))*new_y_irf[shift_1.astype(int)]
shift_2 = np.remainder(np.remainder(x-np.ceil(x0)-1, lengthVec) + lengthVec, lengthVec)
shift_Incr2 = (x0 - np.floor(x0))*new_y_irf[shift_2.astype(int)]
irf_shifted = (shift_Incr1 + shift_Incr2)
irf_norm = irf_shifted/sum(irf_shifted)
h = ampl1*np.exp(-(x)/tau1)
conv = ifft(fft(h) * fft(irf_norm)).real # This is the convolution step.
return conv
Однако, когда я пытаюсь это сделать:
gmodel = Model(ExpDecay_1)
Я получаю это:
gmodel = Model(ExpDecay_1) Traceback (последний последний вызов): Файл "", строка 1, в gmodel = Модель (ExpDecay_1) Файл "C:\Users\lopez\Anaconda3\lib\site-packages\lmfit\model.py", строка 273, в инициализации self._parse_params() Файл "C:\Users\lopez\Anaconda3\lib\site-packages\lmfit\model.py", строка 477, в _parse_params если fpar.default == fpar.empty: ValueError: истинное значение массива с более чем одним элементом двусмысленный. Используйте a.any() или a.all()
Обновлено еще раз: мне удалось заставить его работать следующим образом:
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
import numpy as np
from lmfit import Model
from scipy.fftpack import fft, ifft
def Test_fit2(x, arg=new_y_irf, data=new_y_decay, num_decay=1):
IRF = arg
DATA = data
def Exp(x, ampl1=1.0, tau1=3.0): # This generates an exponential model.
res = ampl1*np.exp(-x/tau1)
return res
def Conv(IRF,decay): # This convolves a model with the data (data = Instrument Response Function, IRF).
conv = ifft(fft(decay) * fft(IRF)).real
return conv
if num_decay == 1: # If the user chooses to use a model equation with one exponential term.
def fitting(x, ampl1=1.0, tau1=3.0):
exponential = Exp(x,ampl1,tau1)
convolved = Conv(IRF,exponential)
return convolved
modelling = Model(fitting)
res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
if num_decay == 2: # If the user chooses to use a model equation with two exponential terms.
def fitting(x, ampl1=1.0, tau1=3.0, ampl2=1.0, tau2=1.0):
exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)
convolved = Conv(IRF,exponential)
return convolved
modelling = Model(fitting)
res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
if num_decay == 3: # If the user chooses to use a model equation with three exponential terms.
def fitting(x, ampl1=1.0, tau1=3.0, ampl2=2.0, tau2=1.0, ampl3=3.0, tau3=5.0):
exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)+Exp(x,ampl3,tau3)
convolved = Conv(IRF,exponential)
return convolved
modelling = Model(fitting)
res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
if num_decay == 4: # If the user chooses to use a model equation with four exponential terms.
def fitting(x, ampl1=1.0, tau1=0.1, ampl2=2.0, tau2=1.0, ampl3=3.0, tau3=5.0, ampl4=1.0, tau4=10.0):
exponential = Exp(x,ampl1,tau1)+Exp(x,ampl2,tau2)+Exp(x,ampl3,tau3)+Exp(x,ampl4,tau4)
convolved = Conv(IRF,exponential)
return convolved
modelling = Model(fitting)
res = modelling.fit(DATA,x=new_x_decay,ampl1=1.0,tau1=2.0)
return res
Всегда полезно опубликовать полный, минимальный пример того, что вы пытаетесь сделать. Без полного примера возможны только расплывчатые ответы.
Вы можете просто выполнять свертки в своей функции модели, обернутой lmfit.Model, передавая массив ядра для использования в свертке. Или вы можете создать ядро и функцию свертки и выполнить свертка как часть процесса моделирования, как описано, например, на https://lmfit.github.io/lmfit-py/examples/documentation/model_composite.html
Я бы предположил, что первый подход проще, если ядро на самом деле не предназначено для изменения во время подгонки, но трудно знать это наверняка без дополнительных подробностей.
Не могли бы вы быть так любезны взглянуть на отредактированный вопрос? Если вы не видите ничего плохого в этом, все в порядке. Большое спасибо за Вашу помощь.
Спасибо. Да, теперь я понимаю, что вопрос был очень расплывчатым. Тем не менее, ваш ответ был правильным. Я узнал, что люди сделали это, включив этап свертки в функцию. Теперь у меня проблемы с вводом данных (списка), используемых для свертки, в качестве одного из аргументов функции, потому что, если я добавлю их как параметр, lmfit.Model выдает ошибку, упомянутую в отредактированном вопросе.