Python交互式卢瑟福散射模拟中曲线拟合时灵时不灵的问题排查
Python交互式卢瑟福散射模拟中曲线拟合时灵时不灵的问题排查
嗨,我仔细看了你的代码和遇到的问题,曲线拟合时好时坏、大角度突然平线的情况确实挺闹心的,咱们从物理模型和代码细节两个维度来排查解决:
一、核心问题分析
你的拟合不稳定主要来自三个方面:
- 拟合模型冗余:你用了
A / np.sin(theta/2)**4 + B的模型,但卢瑟福散射公式里根本没有常数偏移项B。大角度时sin(theta/2)趋近于1,B很容易被噪声点带偏,直接抵消掉信号导致平线。 - 噪声设计不合理:你当前的噪声计算
total_noise_level = scaled_noise_level + noise_scaling + angle_factor,其中angle_factor是1/sin(theta/2)**4,大角度时这个值会爆炸式增长,导致模拟数据的噪声远大于真实信号,拟合器完全抓不住趋势。 - 初始猜测与边界缺失:虽然你试了多个初始猜测,但没给参数设置物理合理的边界,
curve_fit很容易跑到负数或极端值,直接破坏拟合结果。
二、针对性修改方案
1. 修正拟合模型,去掉冗余的偏移项
把拟合函数改成严格匹配卢瑟福公式的形式,避免引入不必要的自由度:
def fit_curve_function(theta, A): """贴合物理模型的拟合函数,无多余偏移项""" return A / np.sin(theta / 2)**4
2. 优化噪声生成逻辑,贴近真实实验统计特性
把绝对噪声改成相对噪声+泊松统计噪声,大角度的噪声会和信号成正比,不会盖过真实趋势:
def monte_carlo_simulation(analytical, theta, EK_slider_value, Ni_slider_value, noise_level=0.1): """改进的噪声生成,更符合实验统计规律""" # 相对噪声:和信号幅度成正比 relative_noise = np.random.normal(0, noise_level, size=theta.shape) # 泊松噪声:模拟粒子计数的统计涨落(真实实验的核心噪声来源) poisson_noise = np.random.poisson(analytical) - analytical # 组合噪声并确保数据非负 simulated_data = analytical + analytical * relative_noise + poisson_noise simulated_data = np.maximum(simulated_data, 0) return simulated_data
3. 优化拟合逻辑,添加物理合理的参数边界
给拟合参数设置正数边界,同时用中等角度的模拟数据计算初始猜测,让拟合器从更合理的起点开始:
@debounce # Fit the simulated data def fit_simulation(change): global simulated_data, analytical_data if analytical_data is None or simulated_data is None: with output_error: output_error.clear_output() print("Run the simulation first to generate simulated data and analytical curve.") return try: # 使用贴合物理的拟合函数 def fit_curve_function(theta, A): return A / np.sin(theta / 2)**4 # 基于中等角度(比如30度)的模拟数据计算初始猜测,避免极端值干扰 theta_30 = np.radians(30) idx_30 = np.argmin(np.abs(np.degrees(theta_values)-30)) A_init = simulated_data[idx_30] * np.sin(theta_30/2)**4 # 设置参数边界:A必须为正,符合物理意义 popt, pcov = curve_fit(fit_curve_function, theta_values, simulated_data, p0=[A_init], bounds=(0, np.inf)) # 计算拟合曲线 fit_curve = fit_curve_function(theta_values, *popt) # 绘制结果 with output_plot: output_plot.clear_output() plt.figure(figsize=(8, 6)) plt.plot(np.degrees(theta_values), simulated_data, '.', color='green', label="Simulated Data") plt.plot(np.degrees(theta_values), analytical_data, '-', color='blue', label="Analytical Curve") plt.plot(np.degrees(theta_values), fit_curve, '--', color='red', label=f"Fit Curve (A={popt[0]:.2e})") plt.xlabel("Scattering Angle (degrees)") plt.ylabel(r"$N(\theta)$") plt.yscale('log') plt.title("Simulated Data with Analytical and Fit Curves") plt.grid() plt.tight_layout() plt.legend() plt.show() except Exception as e: with output_error: output_error.clear_output() print(f"Fitting failed: {str(e)}")
三、额外优化建议
- 如果大角度的拟合还是不稳定,可以给拟合过程加权重,降低噪声大的点的影响:在
curve_fit里添加sigma=1/np.sqrt(analytical),让信号强的点权重更高。 - 可以在滑块调整时自动重新计算模拟数据(去掉按钮触发),配合防抖函数,提升交互体验。
备注:内容来源于stack exchange,提问作者Keanna
相关产品推荐
相关产品推荐

