2025年国赛高教社杯数学建模
B题 碳化硅外延层厚度的确定
原题再现
碳化硅作为一种新兴的第三代半导体材料,以其优越的综合性能表现正在受到越来越多的关注。碳化硅外延层的厚度是外延材料的关键参数之一,对器件性能有重要影响。因此,制定一套科学、准确、可靠的碳化硅外延层厚度测试标准显得尤为重要。
红外干涉法是外延层厚度测量的无损伤测量方法,其工作原理是,外延层与衬底因掺杂载流子浓度的不同而有不同的折射率,红外光入射到外延层后,一部分从外延层表面反射出来,另一部分从衬底表面反射回来(图1),这两束光在一定条件下会产生干涉条纹。可根据红外光谱的波长、外延层的折射率和红外光的入射角等参数确定外延层的厚度。
通常外延层的折射率不是常数,它与掺杂载流子的浓度、红外光谱的波长等参数有关。

问题1 如果考虑外延层和衬底界面只有一次反射、透射所产生的干涉条纹的情形(图1), 建立确定外延层厚度的数学模型。
问题2 请根据问题1的数学模型,设计确定外延层厚度的算法。对附件1和附件2提供的碳化硅晶圆片的光谱实测数据,给出计算结果,并分析结果的可靠性。
问题3 光波可以在外延层界面和衬底界面产生多次反射和透射(图2),从而产生多光束干涉。请推导产生多光束干涉的必要条件,以及多光束干涉对外延层厚度计算精度可能产生的影响。
请根据多光束干涉的必要条件,分析附件3和附件4提供的硅晶圆片的测试结果是否出现多光束干涉,给出确定硅外延层厚度计算的数学模型和算法,以及相应的计算结果。 如果你们认为,多光束干涉也会出现在碳化硅晶圆片的测试结果(附件1和附件2)中,从而影响到碳化硅外延层厚度计算的精度,请设法消除其影响,并给出消除影响后的计算结果。

整体求解过程概述(摘要)
本文针对红外干涉法测量半导体外延层厚度这一典型光学计量问题,以多层介质薄膜干涉理论为基础,系统构建了一套从光学机理建模、参数修正到厚度反演与结果验证的完整求解框架,实现了对碳化硅(SiC)与硅(Si)两类典型材料外延层厚度的高精度、高鲁棒性反演,为半导体制造过程中外延层质量的在线检测与工艺优化提供了理论支撑与技术参考。
首先基于 Fresnel 光学基本方程,对红外光在多层介质界面的传播与反射过程进行建模,系统推导了空气 - 外延层、外延层 - 衬底等关键界面的反射系数、透射系数及总反射率的解析表达式,明确了反射光谱中反射率与入射光波数的内在关联机制,建立了厚度反演的基础物理模型。在此基础上,针对半导体材料折射率受载流子浓度与入射光波长的耦合影响,引入 Drude-Lorentz 模型对折射率的色散效应进行修正,精准刻画了载流子散射与晶格振动对光学参数的影响规律,为后续高精度反演奠定了理论基础。
针对具有显著光谱吸收峰特性的 SiC 材料外延层,本文结合其光学特性,对 Drude-Lorentz 模型进行针对性修正,构建了适配 SiC 材料的光学参数模型,并采用全域拟合方法对反射光谱进行全局反演,求解外延层厚度。实验结果表明,在 10° 入射角条件下,SiC 外延层厚度计算结果为 8.468 μm(附件 1.xlsx);在 15° 入射角条件下,厚度为 8.829 μm(附件 2.xlsx)。为验证反演结果的准确性与稳健性,本文进一步采用极值点差分法与线性拟合方法进行交叉验证,以波数为自变量对反射光谱的级数差进行线性拟合,估算得到 10° 入射角下厚度为 8.37 μm(对应折射率 2.42541114)、15° 入射角下厚度为 8.61 μm(对应折射率 2.332541114),与模型计算结果偏差极小,充分证明了本文方法的可靠性。
针对无明显光谱吸收峰的 Si 材料外延层,本文在固定光学参数、仅考虑载流子浓度差异的前提下,采用相同的全局拟合方法进行厚度反演。结果显示,在 10° 入射角条件下,Si 外延层厚度为 3.048 μm(附件 3.xlsx);在 15° 入射角条件下,厚度为 2.813 μm(附件 4.xlsx)。同时,本文通过对多光束干涉产生的三个必要条件进行系统分析,结合 SiC 材料的光学特性与实验光谱特征,验证了在本实验条件下 SiC 材料无显著多光束干涉效应,排除了多光束效应对反演结果的干扰,进一步提升了厚度计算结果的可信度。
模型假设:
1.晶圆衬底厚度远大于红外光的穿透深度,光在衬底内部的多次透射与反射过程可忽略,将衬底视为半无限大介质。
2.外延层与衬底界面为理想平整界面,外延层厚度均匀分布,忽略表面粗糙度、界面起伏引起的光散射效应。
3.实验测得的反射光谱数据噪声水平低,仪器系统误差可忽略不计,数据质量满足建模与反演要求。
4.衬底与外延层的掺杂浓度分别为常数,且在界面处发生突变,仅考虑载流子浓度对折射率的影响,忽略掺杂分布不均匀性带来的误差。
5.在双光束干涉模型中,仅考虑外延层表面与衬底界面的一次反射、透射过程,忽略界面间的多次反射效应,认为仅存在两束相干反射光。
问题分析:
问题一的分析
本问的核心是构建基于双光束干涉机理的半导体外延层厚度物理模型。以红外入射光在空气 - 外延层、外延层 - 衬底界面的反射与折射过程为基础,通过斯涅尔定律刻画光的传播路径,结合菲涅尔公式推导界面反射系数与透射系数,最终建立两束反射光的相位差与外延层厚度的关联方程。建模过程中,考虑到材料折射率的色散特性,引入 Drude-Lorentz 模型,对载流子浓度与入射波长对折射率的耦合影响进行修正,实现了对 SiC 材料折射率的动态、高精度描述,使模型能够适配附件数据所给定的光谱范围,为后续厚度求解提供了可靠的理论基础。模型求解转化为基于反射光谱数据的多参量非线性拟合问题,通过对实测波数、反射率序列的全局寻优,在拟合模型参数的同时,直接反演得到外延层厚度的最优估计值。
问题二的分析
本问的核心任务是基于问题一建立的理论模型,设计一套高精度、高鲁棒性的厚度求解算法,实现从实测反射光谱到外延层厚度的自动反演。算法设计的关键在于对原始数据的预处理与优化求解策略的构建:首先对附件数据进行单位转换,将波数序列转换为对应波长,并完成量纲统一;其次,采用全域拟合策略,以理论反射率模型与实测数据的残差平方和为目标函数,通过迭代优化算法求解模型参数,在保证拟合精度的同时,直接输出外延层厚度的最优估计值。为评估结果的可靠性,采用多角度交叉验证与误差分析相结合的方式,通过不同入射角下厚度计算结果的一致性、标准差等指标,评估反演方法的稳定性;同时,通过与极值点差分法等不同求解思路的结果进行对比,验证模型与算法的准确性,确保厚度估计值的可信度。
问题三的分析
本问的核心是突破双光束模型的简化假设,引入多光束干涉效应的物理机理,建立更具普适性的外延层厚度反演模型。首先,推导了多光束干涉的等效反射率公式,分析了其产生的必要条件,并定义了效应显著性的评判指标,揭示了外延层折射率、吸收系数对干涉效应的影响规律。在此基础上,对 Si 材料和 SiC 材料的附件数据进行分析,判断不同材料在实验条件下的多光束干涉影响程度:对于 Si 材料,基于双光束模型的计算结果与修正模型的结果高度吻合,证明其无显著多光束干涉效应;对于 SiC 材料,通过对数据的对比分析,验证了多光束效应较弱,原始双光束模型计算结果具有较高的可信度。为进一步消除多光束效应可能带来的系统误差,对双光束直接计算法和牛顿迭代反演法进行模型修正,通过等效反射率公式对原始数据进行校正,反演得到修正后的厚度值,与原始结果偏差极小,最终确定了可靠的外延层厚度计算结果。
模型的建立与求解整体论文缩略图

全部论文及程序请见下方" 只会建模 QQ名片" 点击QQ名片即可
部分程序代码(完整论文以及代码请联系博主):
python
# -*- coding: utf-8 -*-
"""
Listing: 问题2 网格-牛顿法拟合碳化硅数据
功能:提供了从CSV文件加载折射率数据,并计算单层薄膜的双光束与多光束反射率的功能。
"""
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import os
import itertools
from pathlib import Path
# ===================== 配置 =====================
sns.set_theme(style="whitegrid", palette="muted")
# ===================== 物理常量 (SI units) =====================
e = 1.602176634e-19 # 电子电荷 (C)
eps0 = 8.8541878128e-12 # 真空介电常数 (F/m)
m_e = 9.1093837015e-31 # 电子质量 (kg)
c0 = 299792458.0 # 光速 (m/s)
# ===================== 单位转换函数 =====================
def _cm1_to_omega(cm1: float) -> float:
"""将波数 [cm^-1] 转换为角频率 [rad/s]"""
return 2 * np.pi * c0 * (cm1 * 100.0)
def _mu_caughey_thomas(N_cm3, mu_min, mu_max, N_c, alpha):
"""Caughey-Thomas 迁移率模型"""
return mu_min + (mu_max - mu_min) / (1.0 + (N_cm3 / N_c) ** alpha)
def _eps_lorentz_drude_omega(omega, eps_inf, wT, wL, g_ph, v_p, g_e):
"""Lorentz-Drude 介电函数模型"""
omega = np.asarray(omega, dtype=complex)
phonon = (wL**2 - wT**2) / (wT**2 - omega**2 - 1j * g_ph * omega)
drude = v_p**2 / (omega * (omega + 1j * g_e))
return eps_inf * (1.0 + phonon) - drude
# ===================== 材料折射率模型 =====================
def n_sic_4H_sigma(sigma_cm, N_cm3, m_eff_rel=0.42):
"""
计算4H-SiC的复折射率 (Lorentz + Drude模型)
参数:
sigma_cm: 波数数组 (cm^-1)
N_cm3: 载流子浓度 (cm^-3)
m_eff_rel: 有效质量相对电子质量
返回:
复折射率数组 n = n + ik
"""
sigma_cm = np.atleast_1d(sigma_cm).astype(float)
# 4H-SiC固定参数
eps_inf = 6.56
sigma_L_cm = 970.1
sigma_T_cm = 793.9
Gamma_ph_cm = 5.501
# Caughey-Thomas迁移率参数
mu_max = 950.0 # cm^2/Vs
mu_min = 40.0 # cm^2/Vs
N_c = 2e17 # cm^-3
alpha = 0.76
# 转换为角频率
w = _cm1_to_omega(sigma_cm)
wT = _cm1_to_omega(sigma_T_cm)
wL = _cm1_to_omega(sigma_L_cm)
g_ph = _cm1_to_omega(Gamma_ph_cm)
# 计算Drude项的v_p和g_e
if N_cm3 > 1e-3:
mu = _mu_caughey_thomas(N_cm3, mu_min, mu_max, N_c, alpha)
mu_SI = mu * 1e-4 # 转换为 m^2/Vs
m_eff = m_eff_rel * m_e
v_p = np.sqrt((N_cm3 * 1e6) * e**2 / (eps0 * m_eff))
g_e = e / (m_eff * mu_SI)
else:
v_p = 0.0
g_e = 0.0
# 计算介电函数和复折射率
eps = _eps_lorentz_drude_omega(w, eps_inf, wT, wL, g_ph, v_p, g_e)
n_complex = np.sqrt(eps + 0j)
return n_complex
# ===================== 反射率计算函数 =====================
def R_two_beam_sigma(sigma_cm, n0, n1_complex, n2_complex, i_deg, pol='avg'):
"""
计算双光束干涉模型的反射率
参数:
sigma_cm: 波数数组
n0: 入射介质折射率
n1_complex: 薄膜复折射率
n2_complex: 衬底复折射率
i_deg: 入射角(度)
pol: 偏振态 ('s', 'p', 'avg')
返回:
反射率数组
"""
# 此处为占位实现,需根据具体公式补充
return np.zeros_like(sigma_cm)
# ===================== 目标函数 =====================
def objective_function(params_scaled, sigma_data, R_exp_data, fixed_params):
"""根据缩放参数计算残差 (R_calc - R_exp)"""
d_scaled, log10_N1, log10_N2 = params_scaled
# 缩放参数还原为物理单位
d = d_scaled * 1e-6 # 微米转米
N1_cm3 = 10 ** log10_N1
N2_cm3 = 10 ** log10_N2
# 获取固定参数
n0 = fixed_params['n0']
i_deg = fixed_params['i_deg']
m_eff_rel = fixed_params['m_eff_rel']
# 计算折射率
nk1_complex = n_sic_4H_sigma(sigma_data, N_cm3=N1_cm3, m_eff_rel=m_eff_rel)
nk2_complex = n_sic_4H_sigma(sigma_data, N_cm3=N2_cm3, m_eff_rel=m_eff_rel)
# 计算理论反射率
R_calc = R_two_beam_sigma(sigma_data, n0, nk1_complex, nk2_complex, i_deg, pol="avg")
# 处理可能出现的NaN或Inf
if np.any(np.isnan(R_calc)) or np.any(np.isinf(R_calc)):
return np.ones_like(R_exp_data) * 1e10
return R_calc - R_exp_data
# ===================== 雅可比矩阵计算 =====================
def calculate_jacobian(params_scaled, func, h_rel=1e-5, **kwargs):
"""使用有限差分法计算函数的Jacobian矩阵"""
num_params = len(params_scaled)
initial_residuals = func(params_scaled, **kwargs)
num_residuals = len(initial_residuals)
J = np.zeros((num_residuals, num_params))
for i in range(num_params):
p_perturb = np.array(params_scaled, dtype=float)
h = h_rel * abs(p_perturb[i])
if h == 0:
h = h_rel
p_perturb[i] += h
perturbed_residuals = func(p_perturb, **kwargs)
J[:, i] = (perturbed_residuals - initial_residuals) / h
return J
# ===================== Newton-Raphson 求解器 =====================
def newton_raphson_fit(initial_params_scaled, sigma_data, R_exp_data, fixed_params,
max_iter=100, tol=1e-6, learning_rate=0.01, verbose=True):
params_current = np.array(initial_params_scaled, dtype=float)
history = [params_current.copy()]
loss_history = []
for iteration in range(max_iter):
residuals = objective_function(params_current, sigma_data, R_exp_data, fixed_params)
loss = np.sum(residuals ** 2)
loss_history.append(loss)
J = calculate_jacobian(params_current, objective_function,
sigma_data=sigma_data, R_exp_data=R_exp_data,
fixed_params=fixed_params)
if np.any(np.isnan(J)) or np.any(np.isinf(J)) or np.any(np.isnan(residuals)) or np.any(np.isinf(residuals)):
if verbose:
print(f"迭代 {iteration}: Jacobian 或残差中出现 NaN 或 Inf。停止。")
break
try:
delta_params = np.linalg.lstsq(J, -residuals, rcond=None)[0]
except np.linalg.LinAlgError:
if verbose:
print(f"迭代 {iteration}: 遇到奇异矩阵。停止。")
break
params_next = params_current + learning_rate * delta_params
# 参数边界约束
params_next[0] = np.maximum(params_next[0], 0.01) # 最小厚度0.01 um
params_next[1] = np.maximum(params_next[1], 15.0) # N1 最小 1e15 cm^-3
params_next[2] = np.maximum(params_next[2], 15.0) # N2 最小 1e15 cm^-3
# 检查收敛性
param_change = np.linalg.norm(params_next - params_current)
if param_change < tol:
if verbose:
print(f"在迭代 {iteration} 收敛。参数变化: {param_change:.2e}")
params_current = params_next
history.append(params_current.copy())
break
params_current = params_next
history.append(params_current.copy())
if verbose:
print(f"迭代 {iteration}, Loss: {loss:.2e}, 参数: {params_current[0]:.2f} um, 10^{params_current[1]:.2f}, 10^{params_current[2]:.2f}")
final_loss = np.sum(objective_function(params_current, sigma_data, R_exp_data, fixed_params)**2)
loss_history.append(final_loss)
if verbose:
print(f"最终 Loss: {final_loss:.2e}")
return params_current, np.array(history), np.array(loss_history)
# ===================== CSV数据加载函数 =====================
def load_refractive_index_csv_two_blocks(path: str):
"""
解析refractiveindex.info导出的CSV文件
文件应包含两段数据:
- 第一段表头 'wl,n' : 后续为 wavelength[µm], n
- 第二段表头 'wl,k' : 后续为 wavelength[µm], k
"""
path = Path(path)
if not path.exists():
raise FileNotFoundError(f"文件不存在: {path}")
data = pd.read_csv(path, header=None, skip_blank_lines=True)
data = data.dropna(how='all')
# 找到两个数据块的索引
idx_n = data[data[0].astype(str).str.contains('wl,n', na=False)].index[0] + 1
idx_k = data[data[0].astype(str).str.contains('wl,k', na=False)].index[0] + 1
# 读取数据
data_n = pd.read_csv(path, skiprows=idx_n, header=None, names=['wl', 'n'], nrows=idx_k - idx_n - 1)
data_k = pd.read_csv(path, skiprows=idx_k, header=None, names=['wl', 'k'])
return data_n, data_k
# ===================== 主程序入口 =====================
if __name__ == "__main__":
output_dir = "plot_data_for_paper"
os.makedirs(output_dir, exist_ok=True)
# 固定参数
n0 = 1.0 # 入射介质(空气)
i_deg = 10.0 # 入射角
m_eff_rel = 0.42 # 有效质量
fixed_params = {
'n0': n0,
'i_deg': i_deg,
'm_eff_rel': m_eff_rel
}
# 加载数据
data = pd.read_excel('附件1.xlsx')
sigma_exp = data['波数 (cm-1)'].astype(float).values
R_real = data['反射率 (%)'].astype(float).values / 100.0
# 参数搜索范围
d_um_start, d_um_end, d_um_steps = 5.0, 12.0, 4
log10_N1_start, log10_N1_end, log10_N1_steps = 16.0, 18.0, 4
log10_N2_start, log10_N2_end, log10_N2_steps = 17.0, 19.0, 4
d_um_grid = np.linspace(d_um_start, d_um_end, d_um_steps)
log10_N1_grid = np.linspace(log10_N1_start, log10_N1_end, log10_N1_steps)
log10_N2_grid = np.linspace(log10_N2_start, log10_N2_end, log10_N2_steps)
best_loss = np.inf
best_params_scaled = None
best_history = None
best_loss_history = None
best_initial_guess = None
total_runs = d_um_steps * log10_N1_steps * log10_N2_steps
print(f"\n开始对 {total_runs} 组初始参数进行网格搜索...")
for d_init, N1_init_log10, N2_init_log10 in itertools.product(d_um_grid, log10_N1_grid, log10_N2_grid):
run_count = 0
run_count += 1
current_initial_params = [d_init, N1_init_log10, N2_init_log10]
print(f"\n--- 运行第 {run_count}/{total_runs} 次拟合, 初始猜测: d={d_init:.2f}um, log10(N1)={N1_init_log10:.2f}, log10(N2)={N2_init_log10:.2f} ---")
final_params_scaled, history, loss_history = newton_raphson_fit(
current_initial_params, sigma_exp, R_real, fixed_params,
max_iter=200, tol=1e-6, learning_rate=0.01, verbose=False
)
current_loss = np.sum(objective_function(final_params_scaled, sigma_exp, R_real, fixed_params)**2)
print(f"第 {run_count}/{total_runs} 次拟合完成。最终 Loss: {current_loss:.2e}")
if current_loss < best_loss:
best_loss = current_loss
best_params_scaled = final_params_scaled
best_history = history
best_loss_history = loss_history
best_initial_guess = current_initial_params
print("--> 发现新的最佳拟合!")
print("\n" + "="*60)
print("网格搜索完成")
print("="*60)
print(f"最佳初始猜测 (d_um, log10_N1, log10_N2): {best_initial_guess}")
print(f"最小总 Loss: {best_loss:.2e}")
if best_params_scaled is None:
print("未找到有效的拟合结果。请检查数据、模型和搜索范围。")
exit()
# 显示最佳拟合结果
final_d_um = best_params_scaled[0]
final_N1_cm3 = 10**best_params_scaled[1]
final_N2_cm3 = 10**best_params_scaled[2]
print("\n--- 最佳拟合参数 ---")
print(f"厚度 d: {final_d_um:.3f} um ({final_d_um*1e-6:.3e} m)")
print(f"薄膜掺杂 N1: {final_N1_cm3:.2e} cm^-3")
print(f"衬底掺杂 N2: {final_N2_cm3:.2e} cm^-3")
# 绘制反射率拟合图
plt.figure(figsize=(10, 6))
final_d_m = final_d_um * 1e-6
final_nk1 = n_sic_4H_sigma(sigma_exp, N_cm3=final_N1_cm3, m_eff_rel=m_eff_rel)
final_nk2 = n_sic_4H_sigma(sigma_exp, N_cm3=final_N2_cm3, m_eff_rel=m_eff_rel)
R_fit = R_two_beam_sigma(sigma_exp, n0, final_nk1, final_nk2, i_deg, pol="avg")
plt.plot(sigma_exp, R_real * 100, 'o', markersize=4, label='实验数据', color="red")
plt.plot(sigma_exp, R_fit * 100, '-', linewidth=2, label='拟合结果', color="blue")
plt.xlabel('波数 ($\\mathrm{cm}^{-1}$)', fontsize=14)
plt.ylabel('反射率 (%)', fontsize=14)
plt.legend(fontsize=12, frameon=True, shadow=True)
plt.grid(True)
plt.tight_layout()
plt.savefig(os.path.join(output_dir, 'reflectance_fit.png'), dpi=300)
plt.show()
# 保存反射率拟合数据
reflectance_data = pd.DataFrame({
'Wavenumber (cm-1)': sigma_exp,
'Experimental Reflectance (%)': R_real * 100,
'Fitted Reflectance (%)': R_fit * 100
})
reflectance_data.to_csv(os.path.join(output_dir, 'reflectance_fit_data.csv'), index=False)
print(f"反射率拟合数据已保存至 {os.path.join(output_dir, 'reflectance_fit_data.csv')}")
# 绘制Loss收敛历史
plt.figure(figsize=(8, 5))
plt.plot(best_loss_history, marker='o', linestyle='-', markersize=4, color="black")
plt.xlabel('迭代次数', fontsize=14)
plt.ylabel('Loss (残差平方和)', fontsize=14)
plt.yscale('log')
plt.grid(True)
plt.tight_layout()
plt.savefig(os.path.join(output_dir, 'loss_convergence.png'), dpi=300)
plt.show()
# 保存参数收敛历史数据
parameter_convergence_df = pd.DataFrame({
'Iteration': np.arange(len(best_history)),
'Thickness (um)': best_history[:, 0],
'log10(N1)': best_history[:, 1],
'log10(N2)': best_history[:, 2]
})
parameter_convergence_df.to_csv(os.path.join(output_dir, 'parameter_convergence_data.csv'), index=False)
print(f"参数收敛数据已保存至 {os.path.join(output_dir, 'parameter_convergence_data.csv')}")