当前位置:首页>java>Python代码:ODMR谱洛伦兹拟合提取NV色心的劈裂频率

Python代码:ODMR谱洛伦兹拟合提取NV色心的劈裂频率

  • 2026-08-24 12:52:30
Python代码:ODMR谱洛伦兹拟合提取NV色心的劈裂频率

注:公众号matlab合集除了matlab代码外,还包含MMA, Python 等各种代码

代码运行效果如下

附上Python代码

import jsonimport numpy as npimport matplotlib.pyplot as pltfrom scipy.optimize import curve_fit# 读取JSON文件#with open('ODMR Spectrum_2025-11-12-14-47-17_FW_4P2K.txt', 'r', encoding='utf-8') as file:with open('ODMR Spectrum_2025-11-12-14-58-52_FW_4P4K.txt', 'r', encoding='utf-8') as file:    data = json.load(file)# 提取实验数据点(带误差)experiment_data = Nonefor series in data['option']['series']:    if series.get('name') == 'PL (a.u.)' and series.get('type') == 'custom':        experiment_data = series        break# 提取频率和强度数据frequencies = np.array([point[0] for point in experiment_data['data']])intensities = np.array([point[1] for point in experiment_data['data']])errors = np.array([point[2] for point in experiment_data['data']])# 定义洛伦兹函数模型(2个峰)def lorentzian_2peaks(x, *params):    """    2个洛伦兹峰叠加的函数    参数顺序: [offset, freq1, fwhm1, contrast1, freq2, fwhm2, contrast2]    """    y = params[0]  # offset    for i in range(2):        freq = params[1 + i * 3]        fwhm = params[2 + i * 3]        contrast = params[3 + i * 3]        y += contrast * (fwhm / 2) ** 2 / ((x - freq) ** 2 + (fwhm / 2) ** 2)    return y# 初始参数猜测(基于数据观察)# 选择两个最明显的峰(2835和2913 MHz附近)initial_guess = [    1.0,  # offset    2835, 6, -0.05,  # 峰1: 频率, 半高宽, 对比度    2913, 6, -0.03  # 峰2]# 参数边界lower_bounds = [0.9] + [2800, 1, -0.1] * 2upper_bounds = [1.1] + [2950, 15, -0.01] * 2# 进行拟合try:    popt, pcov = curve_fit(        lorentzian_2peaks,        frequencies,        intensities,        p0=initial_guess,        sigma=errors,        bounds=(lower_bounds, upper_bounds),        maxfev=5000    )    # 计算拟合优度    fitted_intensities = lorentzian_2peaks(frequencies, *popt)    residuals = intensities - fitted_intensities    chisq = np.sum((residuals / errors) ** 2)    r_squared = 1 - np.var(residuals) / np.var(intensities)    print("双峰拟合成功!")    print(f"R² = {r_squared:.6f}")    print(f"χ² = {chisq:.6f}")except Exception as e:    print(f"双峰拟合失败: {e}")    # 使用简化的参数作为备选    popt = [1.0, 2835, 6, -0.05, 2913, 6, -0.03]    print("使用默认参数")# 生成拟合曲线的高密度点fine_frequencies = np.linspace(frequencies.min(), frequencies.max(), 1000)fitted_curve = lorentzian_2peaks(fine_frequencies, *popt)# 提取拟合参数offset = popt[0]fit_params = []for i in range(2):    freq = popt[1 + i * 3]    fwhm = popt[2 + i * 3]    contrast = popt[3 + i * 3]    fit_params.append((freq, fwhm, contrast))# 设置中文字体plt.rcParams['font.sans-serif'] = ['Noto Sans CJK JP', 'SimHei', 'Arial']plt.rcParams['axes.unicode_minus'] = False# 创建图表plt.figure(figsize=(20, 5))# 绘制实验数据点(带误差棒)plt.errorbar(frequencies, intensities, yerr=errors, fmt='ro',             markersize=4, capsize=3, capthick=1, elinewidth=1,             label='实验数据点', zorder=5)# 用红线连接实验数据点plt.plot(frequencies, intensities, 'r-', linewidth=1, alpha=0.7, zorder=4)# 绘制拟合曲线plt.plot(fine_frequencies, fitted_curve, 'b-', linewidth=1.5, label='双洛伦兹峰拟合')# 添加拟合峰的位置标记colors = ['green', 'orange']for i, (freq, fwhm, contrast) in enumerate(fit_params):    color = colors[i % len(colors)]    label = f'峰{i + 1}: {freq:.1f} MHz (C={contrast:.4f}, FWHM={fwhm:.2f} MHz)'    plt.axvline(x=freq, color=color, linestyle='--',                alpha=0.7, linewidth=1, label=label)# 设置图表属性plt.title('ODMR Spectrum - 双洛伦兹峰拟合', fontsize=16)plt.xlabel('Frequency (MHz)', fontsize=14)plt.ylabel('Normalized PL (a.u.)', fontsize=14)plt.legend(fontsize=9, loc='upper right')plt.grid(True, alpha=0.3)# 添加拟合质量信息文本框fit_info = f'R² = {r_squared:.4f}\nχ² = {chisq:.2f}'plt.annotate(fit_info, xy=(0.02, 0.98), xycoords='axes fraction',             fontsize=10, verticalalignment='top',             bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))# 调整布局并保存图表plt.tight_layout()plot_filename = "odmr_2peak_fit_with_red_line.png"plt.savefig(plot_filename, dpi=300, bbox_inches='tight')plt.show()print(f"双峰拟合的ODMR谱图已保存到 {plot_filename}")# 打印拟合参数详情print("\n双峰拟合参数详情:")print(f"基线 (offset): {offset:.6f}")for i, (freq, fwhm, contrast) in enumerate(fit_params):    print(f"峰{i + 1}:")    print(f"  共振频率: {freq:.2f} MHz")    print(f"  半高全宽: {fwhm:.2f} MHz")    print(f"  对比度: {contrast:.6f}")# 计算两个峰的频率差(可用于估算磁场)if len(fit_params) == 2:    freq_diff = abs(fit_params[1][0] - fit_params[0][0])    print(f"\n两个峰的频率差: {freq_diff:.2f} MHz")    # 对于NV色心,频率差与磁场的关系:Δf = γ * B,其中γ ≈ 2.8 MHz/mT    # 磁场估算:B = Δf / γ    gamma = 2.8  # MHz/mT    magnetic_field = freq_diff / gamma    print(f"估算磁场强度: {magnetic_field:.2f} mT")

最新文章

随机文章