Introduction
This advanced tutorial explores the optimization algorithms used for thickness extraction,
focusing on when and how to use each method effectively. We'll cover parameter selection,
convergence diagnostics, and troubleshooting common issues.
The Optimization Problem
Objective Function
All thickness extraction methods minimize the difference between measured and modeled reflectance:
χ²(d) = Σᵢ [Rmeas(λᵢ) - Rmodel(λᵢ, d)]²
Where:
- d: Film thickness (parameter to optimize)
- λᵢ: Wavelength measurement points
- Rmeas: Measured reflectance spectrum
- Rmodel: Theoretical reflectance from transfer matrix
Why Optimization is Needed
Unlike FFT which gives a direct estimate, finding the exact thickness requires solving a
nonlinear inverse problem. The reflectance R(λ, d) has a complex functional form involving:
- Trigonometric functions (cosine from interference)
- Wavelength-dependent refractive indices (dispersion)
- Multiple Fresnel reflections
No closed-form solution exists → iterative optimization required.
Algorithm 1: Levenberg-Marquardt (L-M)
Mathematical Foundation
L-M is a damped least-squares method that interpolates between gradient descent and
Gauss-Newton approaches:
dk+1 = dk - [JTJ + λI]-1 JTr
Where:
- J: Jacobian matrix (∂R/∂d at each wavelength)
- r: Residual vector (Rmeas - Rmodel)
- λ: Damping parameter (adjusted each iteration)
- I: Identity matrix
How It Works
- Start: Initial guess d₀ (typically from FFT)
- Compute: Calculate Rmodel(λ, dk) and residuals
- Gradient: Numerical Jacobian: J ≈ [R(d+h) - R(d-h)] / 2h
- Update: Solve linear system for step direction
- Accept/Reject: If χ² decreases, accept step and reduce λ. Else, increase λ and retry
- Converge: Stop when |dk+1 - dk| < tolerance
Parameter Selection
| Parameter | Recommended Value | Description |
| Initial λ | 0.001-0.01 | Smaller for good initial guess |
| λ increase | ×10 | When step rejected |
| λ decrease | ÷10 | When step accepted |
| Max iterations | 50-100 | Typical convergence: 10-20 iterations |
| Tolerance | 0.01 nm | Stop criterion for parameter change |
When to Use
✓ Advantages:
- Very fast convergence (0.1 seconds typical)
- High precision (±0.5 nm)
- Provides uncertainty estimate from Jacobian
- Standard method in commercial tools
✗ Limitations:
- Requires good initial guess (within ~20% of true value)
- Can converge to local minima
- Sensitive to measurement noise at edges
Best Practice
Always use FFT estimate as initial guess for L-M. This hybrid approach
combines FFT's robustness with L-M's precision.
Algorithm 2: Differential Evolution (DE)
Population-Based Global Search
DE is a stochastic evolutionary algorithm that maintains a population of candidate solutions
and evolves them toward the global optimum.
Algorithm Steps
- Initialize: Create population of NP random thickness values within bounds
- Mutation: For each individual xᵢ, create mutant:
vᵢ = xr1 + F(xr2 - xr3)
where r1, r2, r3 are random distinct indices
- Crossover: Mix parent and mutant with probability CR:
uᵢⱼ = vᵢⱼ if rand() < CR, else uᵢⱼ = xᵢⱼ
- Selection: Keep offspring if χ²(offspring) < χ²(parent)
- Iterate: Repeat for G generations until convergence
Hyperparameters
| Parameter | Typical Value | Effect |
| Population size (NP) | 10-20 | Larger = better global search, slower |
| Mutation factor (F) | 0.5-1.0 | Step size in parameter space |
| Crossover rate (CR) | 0.7-0.9 | Probability of using mutant |
| Max generations | 100-300 | Budget for convergence |
When to Use
✓ Advantages:
- No initial guess needed
- Finds global minimum (avoids local minima)
- Robust to noisy data
- Simple to implement
✗ Limitations:
- Slower (1-2 seconds typical)
- More function evaluations (300-500 vs 10-20 for L-M)
- Stochastic (slightly different result each run)
- No uncertainty estimate from algorithm itself
When DE is Essential
Unknown samples: If you don't know approximate thickness (no FFT possible
due to too few fringes), DE can search the entire physically reasonable range.
Multi-modal problems: Some configurations have multiple local minima. DE
explores globally and avoids getting trapped.
Algorithm Comparison
Levenberg-Marquardt
Type: Local gradient-based
Speed: ⚡⚡⚡ Fast (0.1s)
Accuracy: ★★★ Excellent (±0.5 nm)
Robustness: ★★☆ Needs good guess
Best for: Production QC, high-throughput
Differential Evolution
Type: Global stochastic
Speed: ⚡☆☆ Slow (1.5s)
Accuracy: ★★★ Excellent (±0.5 nm)
Robustness: ★★★ Very robust
Best for: Unknown samples, R&D
Decision Tree
Do you have FFT estimate? ─┐
│
┌───────┴───────┐
│ │
YES NO
│ │
Use L-M with Use DE with
FFT as guess wide bounds
(fast & accurate) (slower but robust)
│ │
└───────┬───────┘
│
Does it converge?
│
┌───────┴───────┐
YES NO
│ │
Done! Try DE or
adjust bounds
Setting Parameter Bounds
Why Bounds Matter
Proper bounds prevent unphysical solutions and improve convergence:
- Physical constraints: Thickness cannot be negative or unreasonably large
- Search space reduction: Smaller range = faster convergence
- Regularization: Prevents optimizer from wandering into bad regions
Recommended Bounds
| Situation | Lower Bound | Upper Bound |
| With FFT estimate dFFT |
0.7 × dFFT |
1.3 × dFFT |
| Process spec (e.g., 250±25 nm) |
225 nm |
275 nm |
| Unknown, visible fringes |
50 nm |
1000 nm |
| Unknown, few/no fringes |
10 nm |
100 nm |
Bounds Too Tight
If true thickness falls outside bounds, optimizer will converge to boundary value.
Check residuals - large systematic errors indicate this problem.
Adaptive Bounds Strategy
- Run FFT → get dFFT
- Set bounds: [0.7 × dFFT, 1.3 × dFFT]
- Run L-M fitting
- If converged thickness is near boundary (within 5%), expand bounds and refit
Convergence Diagnostics
How to Know if Fitting Succeeded
1. Chi-Squared Value
χ² < 10⁻⁴ : Excellent fit
χ² < 10⁻³ : Good fit
χ² < 10⁻² : Acceptable
χ² > 10⁻² : Poor fit (check data/model)
2. Residual Analysis
Plot residuals: Rmeas(λ) - Rmodel(λ)
- Good: Random scatter around zero, no patterns
- Bad: Systematic oscillations → wrong model or multi-layer
- Bad: Linear trend → baseline drift in data
3. Convergence History
Plot χ² vs iteration number:
- Good: Smooth monotonic decrease to plateau
- Bad: Oscillations without decrease → diverging
- Bad: Flat from start → stuck at initial guess
4. Parameter Uncertainty
From L-M covariance matrix: σd < 2 nm typically
- Large uncertainty (>5 nm) indicates poor sensitivity or noisy data
- Check SNR of spectral data
- Verify sufficient number of fringes (≥3)
Troubleshooting Common Issues
Issue 1: Non-Convergence
Symptoms: Maximum iterations reached, χ² still large
Causes & Solutions:
- Bad initial guess: Switch to DE or try different guess
- Wrong material index: Verify refractive index value
- Multi-layer film: Single-layer model invalid
- Poor data quality: Check for measurement artifacts
Issue 2: Boundary Convergence
Symptoms: Fitted thickness exactly at lower or upper bound
Solutions:
- Expand bounds (e.g., double the range)
- Check if thickness truly outside initial guess range
- Verify FFT estimate is reasonable
Issue 3: Multiple Solutions
Symptoms: Different initial guesses converge to different values
Cause: Thick films can have ambiguous fringe counting
Solutions:
- Use process knowledge to eliminate unphysical solutions
- Run DE to search globally
- Measure at different wavelength range to resolve ambiguity
Issue 4: Slow Convergence
Symptoms: Takes >100 iterations for L-M
Solutions:
- Improve initial guess (use FFT)
- Reduce damping parameter λ
- Check for numerical precision issues
Advanced Techniques
1. Hybrid Two-Stage Fitting
Stage 1: Global Search
- Run DE with wide bounds [50, 1000] nm
- Find approximate global minimum: d_DE ≈ 245 nm
- Time: 1.5 seconds
Stage 2: Local Refinement
- Run L-M with initial guess d_DE
- Narrow bounds: [0.9×d_DE, 1.1×d_DE]
- Precise result: d = 250.15 ± 0.82 nm
- Time: 0.1 seconds
Total: 1.6 seconds for guaranteed global optimum
2. Multi-Start L-M
Run L-M from 5-10 different random initial guesses, keep best result:
guesses = [100, 200, 300, 400, 500] # nm
results = []
for guess in guesses:
d_fit, chi2 = run_LM(guess)
results.append((d_fit, chi2))
best_d = min(results, key=lambda x: x[1])[0]
# Best result has lowest χ²
3. Uncertainty Quantification via Bootstrap
Estimate uncertainty by resampling data with noise:
n_bootstrap = 100
thicknesses = []
for i in range(n_bootstrap):
# Add random noise to measured spectrum
R_perturbed = R_measured + noise_level * randn()
d_fit = run_fitting(R_perturbed)
thicknesses.append(d_fit)
d_mean = mean(thicknesses)
d_std = std(thicknesses)
# Report: d = d_mean ± d_std nm