首页 > 解决方案 > 在迭代调用的函数中存储和加载参数的有效方法

问题描述

我一直在研究需要模拟系统的问题。我已经剥离了我写的相关代码,只写了对这个问题很重要的部分。

def oscillatorParams():
    K1,K2,K3 = 1e5,1e6,1e2
    B1,B2,B3 = 100,100,100
    a1,a2,a3 = 1,1,1
    b1,b2,b3 = 1,1,1
    I1,I2,I3 = 1000,10000,20000
    return K1,K2,K3,B1,B2,B3,a1,a2,a3,b1,b2,b3,I1,I2,I3

def ode_3DOF_oscillator(state,t, u):
    K1, K2, K3, B1, B2, B3, a1, a2, a3, b1, b2, b3, I1, I2, I3 = oscillatorParams()
    ..equations for the odesolver..
    return [omega[0],omega[1],omega[2],dw1dt,dw2dt,dw3dt]

def runSim(u,dt,T):
    t=np.arange(0,T,dt) ; N=len(t)
    for i in range(0, N ):
        if i==N-1 or i==N:
            tt = [t[i], t[i]]  # [t1 t2]
        else:
            tt = [t[i], t[i+1]]  # [t1 t2]
        x=odeint(ode_3DOF_oscillator,x0,tt,args=(M[i,:],))
    return t,y1,y2,y3

我没有很强的编程背景,我对如何以最佳方式实现参数感到困惑。我更愿意将参数存储在某处以使其易于编辑,因为我可能会在多个其他文件中使用这些函数,但我假设此函数将继续为每个 ode_3DOF_oscillator(state,t,u) 调用分配参数。有没有更好的方法来解决这个问题?

标签: pythonpython-3.xmemory-management

解决方案


只是为了解释您现有的代码,ODE 求解器 Python 的每次迭代都必须:

  1. ode_3DOF_oscillator立即调用的调用oscillatorParams
  2. 局部变量被设置为您的参数变量
  3. 局部变量变成元组并且函数返回
  4. 返回的元组被解包到一组局部变量中以供以后使用
  5. 其余代码运行,直到它返回结果

假设你很高兴在源代码中硬编码参数值,我会做类似的事情:

def make_3DOF_oscillator():
    K1,K2,K3 = 1e5,1e6,1e2
    B1,B2,B3 = 100,100,100
    a1,a2,a3 = 1,1,1
    b1,b2,b3 = 1,1,1
    I1,I2,I3 = 1000,10000,20000

    def fn(state, t, u):
        # ..equations for the odesolver..
        return [omega[0],omega[1],omega[2],dw1dt,dw2dt,dw3dt]

    return fn

def runSim(u,dt,T):
    myfn = make_3DOF_oscillator()
    t=np.arange(0,T,dt) ; N=len(t)
    for i in range(0, N ):
        if i==N-1 or i==N:
            tt = [t[i], t[i]]  # [t1 t2]
        else:
            tt = [t[i], t[i+1]]  # [t1 t2]
        x=odeint(myfn, x0,tt,args=(M[i,:],))
    return t,y1,y2,y3

这会带来良好的性能,因为参数可以作为局部变量直接在函数中使用fn(与稍微慢一些的全局变量相反)。参数也只设置一次,而不是每一步。

否则,假设性能不是问题并且您不介意输入更多内容,则可以使用类:

class Oscillator3DOF:
    def __init__(self):
        self.K1, self.K2, self.K3 = 1e5,1e6,1e2
        self.B1, self.B2, self.B3 = 100,100,100
        self.a1, self.a2, self.a3 = 1,1,1
        self.b1, self.b2, self.b3 = 1,1,1
        self.I1, self.I2, self.I3 = 1000,10000,20000

    def deriv(self, y, t, u):
        # ..equations for the odesolver..
        return [omega[0],omega[1],omega[2],dw1dt,dw2dt,dw3dt]

def runSim(u,dt,T):
    system = Oscillator3DOF()
    t=np.arange(0,T,dt) ; N=len(t)
    for i in range(0, N ):
        if i==N-1 or i==N:
            tt = [t[i], t[i]]  # [t1 t2]
        else:
            tt = [t[i], t[i+1]]  # [t1 t2]
        x=odeint(system.deriv, x0,tt,args=(M[i,:],))
    return t,y1,y2,y3

请注意,deriv将访问参数self.K1等。

另一种选择是使用类似namedtuples 的东西来存储你的参数一次。这将更容易将参数值保存在源代码之外,这可能是一个理想的属性

不太确定您的Mu参数的用途,但我很想以相同的方式设置它们。例如,将它们传递给make_3DOF_oscillator(M[i,:])使其在 中可用fn,或将其保存为 的构造函数中的成员变量Oscillator3DOF。在这些情况下,您希望在for i循环中创建对象,以便它可以访问正确的东西


推荐阅读