Thanks for your comments, sorry for the delay & sorry I didn't include code earlier on.
I am using a package written by a postdoc for analysis of synchrotron data called xrdfit which you can find here:
xrdfit. Within this it uses a PseudoVoigt model to perform the fitting which, if I understand the code correctly, does apply a background although I can't follow how:
def do_pv_fit(peak_data: np.ndarray, maxima_locations: List[Tuple[float, float]], fit_parameters: lmfit.Parameters = None):
"""
Pseudo-Voigt fit to the lattice plane peak intensity.
Return results of the fit as an lmfit class, which contains the fitted parameters
(amplitude, fwhm, etc.) and the fit line calculated using the fit parameters and
100x two-theta points.
"""
model = None
num_maxima = len(maxima_locations)
for maxima_num in range(num_maxima):
# Add the peak to the model
prefix = f"maximum_{maxima_num + 1}_"
if model:
model += lmfit.models.PseudoVoigtModel(prefix=prefix)
else:
model = lmfit.models.PseudoVoigtModel(prefix=prefix)
model.set_param_hint(f"{prefix}snr", expr=f"{prefix}height/background")
model += lmfit.Model(lambda background: background)
two_theta = peak_data[:, 0]
intensity = peak_data[:, 1]
if not fit_parameters:
fit_parameters = model.make_params()
fit_parameters = guess_params(fit_parameters, two_theta, intensity, maxima_locations)
fit_result = model.fit(intensity, fit_parameters, x=two_theta, iter_cb=iteration_callback)
return fit_result
I consider the second plot a poor fit only for the smallest peak (the dotted red line). As the data is physical data it should have a profile reminiscent to the other fits. The large, smooth profile (red dotted line) with tails that don't flatten indicates to me that this is not a good representation of what I expect the data to show.
You comments have already been helpfull to me. I will see if I can achieve a fit as good as yours Matt using the method you describe.