如何用lmfit合并7条拟洛伦兹拟合曲线?自定义模型报错求助
解决自定义洛伦兹模型组合拟合的警告与连续曲线合并问题
咱们一步步拆解你的问题来解决:
1. 先修复参数名的低级错误
看你定义组合模型参数的时候,写了p2_ampe=16——这明显是笔误!应该是p2_amp=16才对。这个错误会导致p2_amp参数没有被正确初始化,拟合时系统可能会给它一个默认的0或者NaN,后续计算参数的标准差(stderr)时就会触发invalid value的警告。
2. 解决RuntimeWarning的核心原因
那个警告来自par.stderr/par.value的计算,通常是因为:
- 某个参数的
stderr是NaN(比如参数被过度约束、初始值不合理导致拟合无法收敛) - 参数的
value为0,导致除法出错
针对你的情况,可以这么处理:
(1)固定不需要拟合的参数
如果你不需要拟合e参数(初始值设为0),直接把它固定住,这样lmfit就不会计算它的stderr,自然不会触发警告:
# 固定所有峰的e参数 for peak in ['p1_', 'p2_', 'p3_']: params[f'{peak}e'].vary = False
(2)给参数设置合理的边界
比如amp和sig不能为负数,可以给它们加边界约束:
# 为振幅和半宽设置非负边界 params['p1_amp'].min = 0 params['p1_sig'].min = 0 params['p2_amp'].min = 0 params['p2_sig'].min = 0 params['p3_amp'].min = 0 params['p3_sig'].min = 0
(3)用完整的x数据集拟合
之前你是分段拟合每个峰,现在要合并成连续曲线,应该用覆盖所有峰的完整x范围(比如x = freqs[100:-7780],这个范围要包含8Hz、14Hz、21Hz等所有峰),而不是分x1、x2。这样组合模型可以同时拟合整个曲线,参数的拟合结果会更稳定,stderr计算也更可靠。
3. 完整的正确实现示例
下面是修改后的完整代码,包含自定义模型组合、参数设置、拟合和绘图:
import numpy as np from scipy import signal import matplotlib.pyplot as plt from lmfit import Model # 自定义拟洛伦兹函数 def lorentzian(x, amp, cen, sig, e): return (amp*(1-e)) / ((pow((1.0 * x - cen), 2)) + (pow(sig, 2))) # 准备数据(和你原来的代码一致) dataset = np.asarray(Bxfft) freqs, psd = signal.welch(dataset, fs=266336/300, window='hamming', nperseg=16192, scaling='spectrum') plt.semilogy(freqs[0:-7000], psd[0:-7000]/dataset.size**0, color='r', label='Bx') # 选择覆盖所有峰的完整x范围 x = freqs[100:-7780] y = psd[100:-7780] # 创建带前缀的单个峰模型 peak1 = Model(lorentzian, prefix='p1_') peak2 = Model(lorentzian, prefix='p2_') peak3 = Model(lorentzian, prefix='p3_') # 组合成总模型 model = peak1 + peak2 + peak3 # 初始化参数(修正笔误,添加合理边界) params = model.make_params( p1_amp=6, p1_cen=8, p1_sig=1, p1_e=0, p2_amp=16, p2_cen=14, p2_sig=3, p2_e=0, # 修正了p2_ampe的笔误 p3_amp=16, p3_cen=21, p3_sig=3, p3_e=0 ) # 固定e参数(如果不需要拟合) for peak_prefix in ['p1_', 'p2_', 'p3_']: params[f'{peak_prefix}e'].vary = False # 为振幅和半宽设置非负边界 for param_name in params: if 'amp' in param_name or 'sig' in param_name: params[param_name].min = 0 # 拟合总模型 result = model.fit(y, params, x=x) # 输出拟合报告 print(result.fit_report(min_correl=0.25)) # 绘制拟合后的连续曲线 plt.plot(x, result.best_fit, 'k-', linewidth=2, label='Combined Lorentzian Fit') plt.legend() plt.show()
4. 额外调试技巧
如果还是出现警告,可以打印所有参数的拟合结果,检查是否有异常值:
result.params.pretty_print()
如果某个参数的stderr是NaN,说明这个参数可能不需要拟合(可以固定),或者初始值设置得太不合理,需要调整初始值或边界。
内容的提问来源于stack exchange,提问作者Hiddenguy
相关产品推荐
相关产品推荐

