如何将字典作为参数传递给Scipy的solve_ivp求解常微分方程组
错误根源
你遇到的报错来自两个低级错误,以及对solve_ivp参数规则的不熟悉:
- 你直接传入
args=morris_lecar2_defaults,这里传的是函数本身,没有加括号调用,所以solve_ivp拿到的是函数对象,不是你预期的参数字典。 solve_ivp的args参数要求传入可迭代对象,迭代得到的元素会按顺序作为额外位置参数传递给微分方程函数。哪怕你只需要传1个参数,也要把它包装成单元素元组,否则直接传字典会被拆分为多个键值参数,导致函数入参不匹配。- 额外注意:你的微分函数定义名为
morris_lecar2,调用solve_ivp时写的是Morris_Lecar2,大小写不匹配,也会触发调用错误。 - 你传入的初始状态
(-20, 1, 0.001)是3个值,但你的微分方程只解V、N两个变量,维度不匹配也会后续报错。
直接修正写法
按照规则调整调用代码即可正常运行:
import numpy as np from scipy.integrate import solve_ivp # 你的参数生成函数和微分函数不变 def morris_lecar2_defaults(): return { "C_M" : 20, "g_K" : 8, "g_L" : 2, "V_Ca" : 120, "V_K" : -80, "V_L" : -60, "V_1" : -1.2, "V_2" : 18, "g_Ca" : 4.0, "phi" : 1/15, "V_3" : 12, "V_4" : 17.4, "I_ext" : 30, } def morris_lecar2(t, u, p): (V, N) = u M_inf = 0.5*(1 + np.tanh((V - p["V_1"])/p["V_2"])) N_inf = 0.5*(1 + np.tanh((V - p["V_3"])/p["V_4"])) tau_N = 1/(p["phi"]*np.cosh((V - p["V_3"])/(2*p["V_4"]))) dVdt = (-p["g_L"]*(V - p["V_L"]) - p["g_Ca"]*M_inf*(V - p["V_Ca"]) - p["g_K"]*N*(V - p["V_K"]) + p["I_ext"])/p["C_M"] dNdt = (N_inf - N)/tau_N return np.array((dVdt, dNdt)) # 调整调用代码 p = morris_lecar2_defaults() # 按需修改参数,比如p["I_ext"] = 40,不需要动其他参数 sol_2 = solve_ivp( morris_lecar2, t_span=(0, 1000), y0=(-20, 0.01), # 修正为2维初始状态 args=(p,) # 参数字典包为单元素元组 )
更规范的大参数管理方案
如果参数数量多,担心写错字典键名,可以用dataclass定义参数类,IDE能自动补全属性,还能做参数校验,比纯字典更易用:
from dataclasses import dataclass import numpy as np from scipy.integrate import solve_ivp @dataclass class MorrisLecarParams: # 所有参数自带默认值,修改时只需指定要改的参数即可 C_M: float = 20 g_K: float = 8 g_L: float = 2 V_Ca: float = 120 V_K: float = -80 V_L: float = -60 V_1: float = -1.2 V_2: float = 18 g_Ca: float = 4.0 phi: float = 1/15 V_3: float = 12 V_4: float = 17.4 I_ext: float = 30 def morris_lecar2(t, u, p: MorrisLecarParams): (V, N) = u M_inf = 0.5*(1 + np.tanh((V - p.V_1)/p.V_2)) N_inf = 0.5*(1 + np.tanh((V - p.V_3)/p.V_4)) tau_N = 1/(p.phi * np.cosh((V - p.V_3)/(2*p.V_4))) dVdt = (-p.g_L*(V - p.V_L) - p.g_Ca*M_inf*(V - p.V_Ca) - p.g_K*N*(V - p.V_K) + p.I_ext)/p.C_M dNdt = (N_inf - N)/tau_N return np.array((dVdt, dNdt)) # 调用示例:只修改刺激电流,其他参数用默认值 p = MorrisLecarParams(I_ext=50) sol_2 = solve_ivp(morris_lecar2, (0, 1000), (-20, 0.01), args=(p,))
内容的提问来源于stack exchange,提问作者ConsistentC
相关产品推荐
相关产品推荐

