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

scipy.optimize.least_squares迭代5次仍返回初始值问题求助

问题描述

使用scipy.optimize.least_squares拟合数据时,无论设置何种初始猜测值,优化结果始终与初始值完全一致,无任何更新。已确认代价函数和参数配置看似正常,但问题持续存在。

相关代码

def LSMM(initial_guess, ocp_cathode, ocp_anode,soc_values, soc, ocv_entries):

    def ocp_pe(alpha_p, beta_p, ocp_cathode, soc_values):
        ocp_p = {k_soc:v for k_soc, v in zip(np.around(alpha_p*soc_values+beta_p,3), ocp_cathode)}
        return ocp_p

    def ocp_ne(alpha_n, beta_n, ocp_anode, soc_values):
        ocp_n = {k_soc:v for k_soc, v in zip(np.round(alpha_n*soc_values+beta_n,3), ocp_anode)}
        return ocp_n
    
    def ocv_cell(soc, ocv_datapoints):
        ocv = {k_soc:v for k_soc, v in zip(np.round(soc,3), ocv_datapoints)}
        return ocv

    def cost_function(params, ocp_cathode, ocp_anode, soc_values, soc, ocv_datapoints):
        print("here")
        alpha_p, beta_p, alpha_n, beta_n = params
        print(params)
        ocp_p = ocp_pe(alpha_p, beta_p, ocp_cathode, soc_values)
        ocp_n = ocp_ne(alpha_n, beta_n, ocp_anode, soc_values)
        ocv = ocv_cell(soc, ocv_datapoints)
        ocv_cat = []
        ocv_an = []
        for i in ocv.keys():
            ocv_cat.append(ocp_p[i])
            ocv_an.append(ocp_n[i])
        
        ocv_pred = np.array(ocv_cat) - np.array(ocv_an)
        diff = np.sqrt(np.sum((ocv_pred - np.array(list(ocv.values()))) ** 2))
        #return np.sqrt(np.mean((ocv_pred - np.array(list(ocv.values()))) ** 2))
        return diff

    opti = least_squares(cost_function, initial_guess,  args = (ocp_cathode, ocp_anode, soc_values, soc, ocv_entries),method='trf')
    alpha_p, beta_p, alpha_n, beta_n = opti.x
    jac = opti.grad
    #stat = opti.status
    print("alpha p: ", alpha_p)
    print("beta p: ", beta_p)
    print("alpha n: ", alpha_n)
    print("beta n: ", beta_n)
    print(jac)
    o_p = ocp_pe(alpha_p, beta_p, ocp_cathode, soc_values)
    o_n = ocp_ne(alpha_n, beta_n, ocp_anode, soc_values)
    o = ocv_cell(soc, ocv_entries)
    ocv_cat = []
    ocv_an = []
    for j in o.keys():
        ocv_cat.append(o_p[j])
        ocv_an.append(o_n[j])

    ocv_pred = np.array(ocv_cat) - np.array(ocv_an)

    plt.figure(figsize=(10, 6))
    plt.plot(list(o_p.keys()), list(o_p.values()), label="Cathode")
    plt.plot(list(o_n.keys()), list(o_n.values()), label="Anode")
    plt.plot(list(o.keys()), ocv_pred, label="OCV Predicted")
    plt.plot(list(o.keys()), list(o.values()), label ="OCV Measured")
    plt.xlabel("State of Charge (SoC)")
    plt.ylabel("Open Circuit Potential (OCP) [V]")
    plt.title("Open Circuit Potential")
    plt.grid(True)
    plt.legend()
    plt.show()

initial_guess = np.array([1.2,-0.1,1.2,-0.1])
LSMM(initial_guess, ocp_cathode, ocp_anode, soc_values, soc, ocv_entries) 
问题根源与修复方案

1. 代价函数输出不符合要求

scipy.optimize.least_squares要求代价函数返回一维残差数组(每个数据点的预测值与真实值的差值),而非单个标量的误差平方和或均方根。你当前返回的是汇总后的标量,优化器无法通过该标量计算有效梯度,导致参数无法更新,直接返回初始值。

2. 离散字典匹配导致梯度为0

在ocp_pe、ocp_ne中,通过np.around将变换后的SoC离散为三位小数作为字典键,再匹配OCP值。这种离散化会让参数的微小变化无法改变键值,进而无法改变预测的OCP值,残差对参数的梯度为0,优化器无法感知参数变化的影响,停止更新。

修复步骤

步骤1:修改代价函数返回残差数组

将代价函数改为返回每个数据点的残差,替换原有汇总逻辑:

def cost_function(params, ocp_cathode, ocp_anode, soc_values, soc, ocv_datapoints):
    alpha_p, beta_p, alpha_n, beta_n = params
    
    # 用插值替代字典匹配,实现连续OCP计算
    from scipy.interpolate import interp1d
    # 假设soc_values是升序排列的SoC数组,对应ocp_cathode的OCP值
    ocp_p_interp = interp1d(soc_values, ocp_cathode, kind='linear', fill_value="extrapolate")
    ocp_n_interp = interp1d(soc_values, ocp_anode, kind='linear', fill_value="extrapolate")
    
    # 计算每个测量SoC变换后的正极/负极SoC
    transformed_soc_p = alpha_p * soc + beta_p
    transformed_soc_n = alpha_n * soc + beta_n
    
    # 得到预测的电池OCV
    ocv_pred = ocp_p_interp(transformed_soc_p) - ocp_n_interp(transformed_soc_n)
    
    # 返回每个数据点的残差数组
    return ocv_pred - np.array(ocv_datapoints)

步骤2:替换离散匹配为连续插值

使用scipy.interpolate.interp1d将正极/负极的SoC-OCP曲线转换为连续插值函数,参数的微小变化会直接反映在预测OCP上,确保优化器能计算出有效梯度。

步骤3:添加优化日志验证

调用least_squares时添加verbose=2参数,查看优化过程的日志,确认参数是否开始更新:

opti = least_squares(cost_function, initial_guess, 
                     args=(ocp_cathode, ocp_anode, soc_values, soc, ocv_entries),
                     method='trf',
                     verbose=2)

额外建议

  • 确保soc_values是升序排列的数组,插值函数在无序输入时可能出现异常;
  • 可添加参数边界约束,比如bounds=([0.8, -0.2, 0.8, -0.2], [1.5, 0.2, 1.5, 0.2]),避免参数超出物理合理范围。

内容的提问来源于stack exchange,提问作者Mukundh Balabhadra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 15:09:51