I'm trying to do a multi-gaussian deconstruction of a spectral measurement I took, but I'm getting ValueError: 'x0' is infeasible. I'm using curve_fit and I'm trying to break down my measurement into 3 Gaussians. Here's my code:
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
directory=r"C:\Users\jh\data"
filename = "test(0,1).txt"
filepath = os.path.join(directory, filename)
data = pd.read_csv(filepath, delimiter = "\t")
x = data['Wavelength (nm)']
y = data['Absorbance']
#Gaussian 1
amp1 = 100
cen1 = 450
sig1 = 15
#Gaussian 2
amp2 = 50
cen2 = 550
sig2 = 10
#Gaussian 3
amp3 = 20
cen3 = 760
sig3 = 5
p0 = [amp1, cen1, sig1, amp2, cen2, sig2, amp3, cen3, sig3]
def gaussian(x, amp, cen, sig):
gau = amp*(1/(sig*(np.sqrt(2*np.pi))))*(np.exp((-1/2)*(((x-cen)/sig)**2)))
return gau
def three_gaussian(x, amp1, cen1, sig1, amp2, cen2, sig2, amp3, cen3, sig3): #Amp: Amplitude, Cen: Center, Sig: Sigma
gau1 = amp1*(1/(sig1*(np.sqrt(2*np.pi))))*(np.exp((-1/2)*(((x-cen1)/sig1)**2)))
gau2 = amp2*(1/(sig2*(np.sqrt(2*np.pi))))*(np.exp((-1/2)*(((x-cen2)/sig2)**2)))
gau3 = amp3*(1/(sig3*(np.sqrt(2*np.pi))))*(np.exp((-1/2)*(((x-cen3)/sig3)**2)))
return gau1 + gau2 + gau3
popt, pcov = curve_fit(three_gaussian, x, y, p0, bounds = ((400, -np.inf, -np.inf, 500, -np.inf, -np.inf, 650, -np.inf, -np.inf), (470, np.inf, np.inf, 600, np.inf, np.inf, 900, np.inf, np.inf)))
RRa_pars = popt[0:3]
RRe_pars = popt[3:6]
Pol_pars = popt[6:9]
RRa = gaussian(x, *RRa_pars)
RRe = gaussian(x, *RRe_pars)
Pol = gaussian(x, *Pol_pars)
I'm positive that the problem is this line from the curve_fit call:
popt = curve_fit(three_gaussian, x, y, p0, bounds = ((400, -np.inf, -np.inf, 500, -np.inf, -np.inf, 650, -np.inf, -np.inf), (470, np.inf, np.inf, 600, np.inf, np.inf, 900, np.inf, np.inf)))
I previously tried this code without the bounds and it was working, but the model was inaccurate to what I was expecting. So I introduced the bounds to try and constrain the center to where I was expecting. That's what introduced the ValueError: 'x0' is infeasible. This is what the fit looks like without the bounds:

The fit is good, but the two Gaussians should be closer in amplitude and they should be more shifted left. (I'm neglecting the last Gaussian in this image because it's not the one with a problem).
I'm not really sure how to fix this problem.
When you provide bounds and an initial guess, the initial guess must satisfy the bounds, otherwise the initial guess is considered "infeasible" (that's just another way of saying it doesn't satisfy the constraints). Consider this modified version of the
scipy.optimize.curve_fitexample from the documentation.If we call the curve fit like so:
There aren't any issues because the initial guess satisfies the constrains.
But if we call it like this:
We get
ValueError: 'x0' is infeasiblesince theainitial guess is not within the bounds.