Logo

A physics toolbox for laser spectroscopy.

Static Badge Static Badge Static Badge

Static Badge Static Badge

© 2025 Patrick Müller. All rights reserved.

Construction and fitting of modular lineshape models

In this tutorial, a basic example is shown how qspec.models can be used to construct lineshape models for data fitting.

First, we import all the required modules and generate our lineshape model. We can print all parameters of the model and set them to new values. Additionally, we can fix certain parameters for fitting by changing the list model.fixes. Here, we define sigma as a Prior, which is basically a known parameter with uncertainty.

import numpy as np
import qspec.models as mod
import matplotlib.pyplot as plt

# Generate the model used in this tutorial
model = mod.Offset(  # Add a y-axis shift (off0e0)

    mod.NPeak(  # Add a single (n_peaks=1)
        # x-axis shift (x0) and an intensity (p0)

        mod.Voigt(), n_peaks=1)) # Add a Voigt lineshape
        # with Lorentzian (Gamma) and Gaussian (sigma) widths

print(f'\nParameter names: {model.names}\n')
# >>> Parameter names: ['Gamma', 'sigma', 'x0', 'p0', 'off0e0']

# Change all parameter values and if they stay fixed during fitting at once
model.set_vals([20., 6., 0., 10., 3.])
model.set_fixes([False, '5(0.7)', False, False, False])

Now, we generate some data for the fit. The data is normally distributed around the model with its current parameters.

# Generate some random data for this tutorial
x = np.linspace(-80., 80., 81)  # x-values
sigma_y = np.full_like(x, 0.5)  # y-uncertainties
y = np.random.normal(model(x, *model.vals), sigma_y)
# Random y-values around the model

We change the initial parameters of the peak position and intensity to later compare the model before and after fitting. During the fit, model.vals is set to the optimized parameters. Therefore, we save our initial values to p_init. We set report=True to get a summary of the fit results.

# Change the initial value of the peak position and intensity
model.set_val(2, 15.)  # Parameter 2 (x0), the peak position
model.set_val(3, 5.)  # Parameter 3 (p0), the peak intensity
p_init = model.vals.copy()  # Copy the initial values for the plot

# Fit the constructed model to the data
popt, pcov, info = mod.fit(
    model, x, y, sigma_y=sigma_y, report=True)
Optimized parameters:
0:   Gamma = 23.07256228925477 +/- 1.6786599666472717
1:   sigma = 4.697853592625128 +/- 0.7099638812366352
2:   x0 = 0.3717374185209716 +/- 0.29514512340842586
3:   p0 = 10.584453120309163 +/- 0.2375261208105466
4:   off0e0 = 2.799096283098853 +/- 0.11049924526028845

Cov. Matrix:
0:    1.00   -0.72   -0.00    0.03   -0.68
1:   -0.72    1.00    0.00   -0.34    0.32
2:   -0.00    0.00    1.00   -0.00    0.00
3:    0.03   -0.34   -0.00    1.00   -0.31
4:   -0.68    0.32    0.00   -0.31    1.00

Red. chi2 = 1.17
Fit successful.

Finally, we plot everything.

# Plot the data, the initial model and the fitted model
plt.errorbar(x, y, yerr=sigma_y, fmt='.k', label='Data')
plt.plot(x, model(x, *p_init), '-C0', label='Initial model')
plt.plot(x, model(x, *popt), '-C1', label='Fitted model')

# Improve the plot
plt.legend()
plt.xlabel('x'), plt.ylabel('y')
plt.subplots_adjust(left=0.08, bottom=0.09, top=0.99, right=0.99)
plt.show()