-
Notifications
You must be signed in to change notification settings - Fork 5
Example: Fit single layer reflectance
In this example, we would attempt to fit the reflectance spectrum of a porous silicon thin film, single layer. The light hits the air as the incident medium, with layer 1 as the film of interest supported on a substrate made of crystalline silicon as the emergent medium. See the figure below:

The incident and emergent media are considered as semi-infinite, thus, only the indices of refraction are considered for the modelling aspects. So we are interested in retrieving the thickness and the porosity parameter of layer 1 from its reflectance spectrum.
The complete code can be found here.
using Plots, LaTeXStrings
pyplot()
using ThinFilmsTools
using OptimWe use the PlaneWave structure to build up the light source:
λ = 250:900 # Wavelength range [nm]
θ = [5.] # Angle of incidence [degrees]
pol = 0.5 # Polarisation (1.0 = p, 0.0 = s, between 0.0 and 1.0 = average)
beam = PlaneWave(λ, θ; p=pol)Here we define the system of layers using the LayerTMMO structure and the indices of refraction database RIdb:
incident = RIdb.air(beam.λ)
emergent = RIdb.silicon(beam.λ)
layer1 = ModelFit(:looyenga; N=(ninc=incident, nhost=emergent))
layers = [
LayerTMMO(incident),
layer1,
LayerTMMO(emergent)
]We model the layer 1 with the binary Looyenga-Landau-Lifshitz effective medium approximation using air for the porosity and silicon as a host matrix, indicated with the optional parameter N, with the index of refraction of the inclusions declared in ninc and the host material nhost.
Since we have the information about the raw spectrum and the reference spectrum of reflection, we need to extraxt the absolute reflectance to fit. We proceed as follow:
# Raw measured spectrum stored in Utils
Rexp = SpectraDB.sl1_exp_spectrum(beam.λ)
# Reference measured spectrum stored in Utils
Rref = SpectraDB.sl1_ref_spectrum(beam.λ)
# Theoretical reflectance spectrum for the reference
Rthe = theoretical_spectrum(Reflectance(), beam, incident, emergent)
# Calculate the absolute normalised measured spectra to fit
Rexp_norm = normalize_reflectance(beam.λ, [beam.λ Rexp], [beam.λ Rthe], [beam.λ Rref])The module SpectraDB is exported by ThinFilmsTools.jl and contains a bunch of spectra to load directly.
We proceed now with the optimisation process, setting first the seed as the initial guess for the algorithm, then the options, and finally run the optimisation with the LBFGS() algorithm.
seed = [3300, 0.85]
options = Optim.Options(g_abstol=1e-8, g_reltol=1e-8, iterations=10^5,
store_trace=false, show_trace=false)
solOptim = fit_tmm_optics(
Reflectance(Rexp), [seed], beam, layers;
alg=LBFGS(), options=options,
)To visualize the results we can type the following:
# The objective function value
julia> solOptim.objfunMin
9.525392931417567e-5
# The optimal parameters
julia> solOptim.optParams
1-element Array{Array{Float64,1},1}:
[3318.4038798880383, 0.8551086023617244]The first element of solOptim.optParams is the thickness in nanometers, and the second element is the porosity parameter as determined from the fitting procedure.
Once the process finishes, we plot the results comparing the model reflectance to the data of the experimental one.
plot(FitSpectrum(),
solOptim.beam.λ, solOptim.spectrumExp, solOptim.spectrumFit)
gui() # If you are in Atom editor