Note
Click here to download the full example code
Mueller matrix
Mueller matrix fit to a SiO2 on Si measurement.
import elli
from elli.fitting import ParamsHist, fit_mueller_matrix
Read data
We load the data from an ascii file containing each of the mueller matrix elements. The wavelength range is cut to be in between 210 nm and 820 nm, to stay in the range of the provided literature values for Si. The data is expected to be in a pandas dataframe containing the columns Mxy, where x and y refer to the matrix element inside the mueller matrix. The data is scaled by the M11 element, such that \(M_{11} = 1\) for all wavelengths. To show the structure we print the MM dataframe. If you load your data from another source make sure it adheres to this form.
M11 M12 M13 M14 ... M41 M42 M43 M44
Wavelength ...
210.30366 1.0 -0.09147 -0.01241 -0.00614 ... 0.00986 0.00048 -0.95574 0.25821
210.76102 1.0 -0.10879 -0.01151 -0.00901 ... 0.00917 0.01319 -0.96899 0.24432
211.21834 1.0 -0.10639 -0.00694 -0.00475 ... 0.00712 0.00891 -0.96191 0.24986
211.67561 1.0 -0.11544 -0.02094 -0.00348 ... 0.01877 0.01726 -0.95951 0.25408
212.13284 1.0 -0.12199 0.02182 0.00480 ... -0.01790 -0.01957 -0.95493 0.28308
... ... ... ... ... ... ... ... ... ...
818.08934 1.0 -0.44285 -0.00048 -0.00288 ... 0.00292 -0.00276 -0.87949 0.15713
818.50589 1.0 -0.44301 0.00376 0.00118 ... -0.00159 -0.01090 -0.87876 0.16422
818.92240 1.0 -0.44245 0.00887 0.00626 ... -0.00585 -0.01388 -0.87960 0.16743
819.33886 1.0 -0.44406 -0.00646 -0.00610 ... 0.00882 0.00424 -0.87907 0.15105
819.75528 1.0 -0.44381 0.01170 0.00550 ... -0.00692 -0.01260 -0.87849 0.16637
[1396 rows x 16 columns]
Setting start parameters
Here we set the start parameters for the SiO2 cauchy dispersion and thickness of the layer.
params = ParamsHist()
params.add("SiO2_n0", value=1.452, min=-100, max=100, vary=True)
params.add("SiO2_n1", value=36.0, min=-40000, max=40000, vary=True)
params.add("SiO2_n2", value=0, min=-40000, max=40000, vary=True)
params.add("SiO2_k0", value=0, min=-100, max=100, vary=True)
params.add("SiO2_k1", value=0, min=-40000, max=40000, vary=True)
params.add("SiO2_k2", value=0, min=-40000, max=40000, vary=True)
params.add("SiO2_d", value=120, min=0, max=40000, vary=True)
Building the model
Here the model is build and the experimental structure is returned. For details on this process please refer to the Basic usage example. When executed in an jupyter notebook this displays an interactive graph with which you can select the start parameters before fitting the data.
@fit_mueller_matrix(MM, params, display_single=False, sharex=True, full_scale=False)
def model(lbda, params):
sr = elli.TableSpectraRay("./")
Si = elli.IsotropicMaterial(sr.load_dispersion_table("Si_Aspnes.mat"))
SiO2 = elli.Cauchy(
params["SiO2_n0"],
params["SiO2_n1"],
params["SiO2_n2"],
params["SiO2_k0"],
params["SiO2_k1"],
params["SiO2_k2"],
).get_mat()
Layer = [elli.Layer(SiO2, params["SiO2_d"])]
return elli.Structure(elli.AIR, Layer, Si).evaluate(
lbda, 70, solver=elli.Solver4x4, propagator=elli.PropagatorExpm()
)
Plot & Fit the model
Here we plot the model at the initial parameter set vs. the experimental data.
model.plot()
We can also plot the residual between measurement and model.
model.plot_residual()
Now we execute a fit and plot the model afterwards.
fit_stats = model.fit()
model.plot(full_scale=False)
For comparison we plot the residual again to have a figure of merit for the fit quality
model.plot_residual()
We may also print the fit statistics.
fit_stats
References
Here you can find the latest jupyter notebook and data files of this example.
Total running time of the script: ( 0 minutes 17.315 seconds)