You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

lmfit中SineModel+ConstantModel拟合不准及参数不确定性问题

问题描述

我尝试用lmfit把简单正弦函数拟合到实验数据里,发现SineModel结合ConstantModel的拟合精度很差。我最关心峰值频率,虽然能用scipy.find_peaks()拿到,但还是想展示拟合曲线。

第一个拟合函数(效果不佳)

我使用的Sine函数代码如下:

def Sine(self, x_axis, y_axis):
    sine = SineModel()
    const = ConstantModel()

    x_fit = np.linspace(min(x_axis), max(x_axis), x_axis.size)
    guess_sine = sine.guess(y_axis, x=x_fit)

    pars = sine.guess(y_axis, x=x_fit)
    sine_offset = SineModel() + ConstantModel()

    pars.add('c', value=1, vary=True)

    result = sine_offset.fit(y_axis, pars, x=x_fit)

    return result

该函数的拟合结果(图表及报告)显示效果不理想。

自定义拟合函数(效果好但无参数不确定性)

后来我自行定义拟合函数,并提供基于FFT的合理初始猜测值,拟合效果更贴近数据,但报告提示“Uncertainties could not be estimated”,无法计算参数不确定性:

def Sine_User2(self, x_axis, y_axis):
    def sine_func(x, amplitude, freq, shift, c):
        return amplitude * np.sin(freq * x + shift) + c

    sinemodel = Model(sine_func)

    # 对数据做FFT以提供曲线拟合的初始猜测值
    x = np.array(x_axis)
    y = np.array(y_axis)
    ff = np.fft.fftfreq(len(x), (x[1] - x[0]))   # 假设均匀间隔
    Fyy = abs(np.fft.fft(y))
    guess_freq = abs(ff[np.argmax(Fyy[1:]) + 1]) * 2. * np.pi
    guess_amp = np.std(y) * 2.**0.5
    guess_offset = np.mean(y)

    x_fit = np.linspace(min(x_axis), max(x_axis), x_axis.size)

    params = sinemodel.make_params(amplitude = guess_amp, freq = guess_freq, shift = 0, c = guess_offset )
    result = sinemodel.fit(y_axis, params, x = x_fit)

    return result

我曾尝试为参数添加最值限制,将sinmodel.make_params替换为以下代码,但拟合效果又回到第一个模型的糟糕状态,说明问题出在初始值设置上:

params = Parameters()
params.add('amplitude', value=guess_amp, min = 0)
params.add('freq', value=guess_freq, min=0)
params.add('shift', value=0, min=-2*np.pi, max=2*np.pi)
params.add('c', value=guess_offset)

核心问题

  1. 如何改进第一个Sine函数的拟合效果?
  2. 第二个Sine_User2函数无法计算参数不确定性的原因是什么?

实验数据(CSV)

Wavelength (nm),Power (dBm),,,,,
1549.9,-13.76008731,,,,,
1549.905,-13.69423162,,,,,
1549.91,-12.59004339,,,,,
1549.915,-11.31061848,,,,,
1549.92,-10.58731809,,,,,
1549.925,-10.19024329,,,,,
1549.93,-10.07301418,,,,,
1549.935,-10.19513172,,,,,
1549.94,-10.45582159,,,,,
1549.945,-11.15984161,,,,,
1549.95,-12.15876596,,,,,
1549.955,-13.44674933,,,,,
1549.96,-13.56388277,,,,,
1549.965,-12.2513065,,,,,
1549.97,-11.08699015,,,,,
1549.975,-10.43829185,,,,,
1549.98,-10.12861158,,,,,
1549.985,-10.0962929,,,,,
1549.99,-10.1852173,,,,,
1549.995,-10.55438183,,,,,
1550,-11.19555345,,,,,
1550.005,-12.28715299,,,,,
1550.01,-13.5153863,,,,,
1550.015,-13.47019261,,,,,
1550.02,-12.12394732,,,,,
1550.025,-11.01946751,,,,,
1550.03,-10.42138778,,,,,
1550.035,-10.14438079,,,,,
1550.04,-10.05681218,,,,,
1550.045,-10.17148605,,,,,
1550.05,-10.56046759,,,,,
1550.055,-11.11621478,,,,,
1550.06,-12.19930263,,,,,
1550.065,-13.48428349,,,,,
1550.07,-13.43424913,,,,,
1550.075,-12.08019952,,,,,
1550.08,-11.08731704,,,,,
1550.085,-10.45730899,,,,,
1550.09,-10.11278169,,,,,
1550.095,-10.00651194,,,,,
,,,,,,

问题解答

一、改进第一个Sine函数的拟合效果

第一个函数效果差的核心原因是初始猜测值严重偏离数据特征:你用sine.guess()生成的默认参数,再手动添加c=1的常数项,完全没贴合你的实验数据。

改进方案是复用自定义函数里的FFT初始猜测逻辑,给SineModel+ConstantModel设置贴合数据的初始参数:

def Sine(self, x_axis, y_axis):
    x = np.array(x_axis)
    y = np.array(y_axis)
    # 用FFT计算贴合数据的初始猜测值
    ff = np.fft.fftfreq(len(x), (x[1] - x[0]))
    Fyy = abs(np.fft.fft(y))
    guess_freq = abs(ff[np.argmax(Fyy[1:]) + 1]) * 2. * np.pi
    guess_amp = np.std(y) * 2.**0.5
    guess_offset = np.mean(y)

    # 组合模型
    sine_offset = SineModel() + ConstantModel()
    # 生成参数并设置初始值(注意SineModel的参数名是amplitude、frequency、phase)
    pars = sine_offset.make_params(
        amplitude=guess_amp,
        frequency=guess_freq,
        phase=0,
        c=guess_offset
    )

    x_fit = np.linspace(min(x_axis), max(x_axis), x_axis.size)
    result = sine_offset.fit(y_axis, pars, x=x_fit)

    return result

关键注意点:

  • SineModel的内置参数名是amplitude(振幅)、frequency(频率)、phase(相位),和自定义函数的参数名不要混淆
  • 放弃使用sine.guess()的默认初始值,用FFT得到的贴合数据的猜测值,这是拟合收敛到最优解的核心

二、Sine_User2无法计算参数不确定性的原因

提示“Uncertainties could not be estimated”通常是因为拟合的协方差矩阵无法求解,常见原因有两个:

  1. 参数强相关性:自定义函数中freq(频率)和shift(相位)存在极强的冗余相关性——微调相位可以抵消频率变化带来的拟合差异,导致协方差矩阵奇异,无法计算不确定度。
  2. 未收敛到全局最优:虽然拟合曲线看起来贴合数据,但可能只是陷入了局部极小值,而非全局最优解,此时协方差矩阵的计算也会失败。

解决办法:

  • 限制相位范围:给shift参数设置min=-np.pi, max=np.pi(正弦函数周期为2π,该范围已覆盖所有相位情况,可大幅降低和频率的相关性)
  • 检查收敛状态:打印result.fit_report()查看message字段,确认拟合是否真的收敛。若为局部极小值,可尝试微调shift的初始值(比如设为np.pi/2)或频率初始值后重新拟合。
  • 改用SineModel组合方式:SineModel内部已经优化了参数相关性问题,只要初始值合理,通常能正常计算参数不确定度。

内容的提问来源于stack exchange,提问作者Euan Tough

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 13:50:47