【问题标题】:Difficulties with RK4 VBA Function. Function only returns #REF! valueRK4 VBA 函数的难点。函数只返回#REF!价值
【发布时间】:2020-08-01 14:17:20
【问题描述】:

不适用。不再是问题......

【问题讨论】:

  • 要调试您的函数,请从 VBA 子程序中调用它 - 然后您可以看到问题出在哪里。如果您可以为 RK44 提供示例参数,也非常有用
  • 大声笑,主要问题是函数名!看我的回答。

标签: excel vba differential-equations ref runge-kutta


【解决方案1】:

试试这个:

Function dCdt(y As Variant) As Variant
    dCdt = ((0.02) - (0.1) * (y))
End Function

Function SIMRK44(ByVal x0 As Double, ByVal y0 As Double, ByVal n As Integer, ByVal xtarg As Double) As Double

    Dim k1 As Double, k2 As Double, k3 As Double, k4 As Double
    Dim ym As Double, ym2 As Double, ye As Double
    Dim Slope As Double, yi As Double, xi As Double, h As Double

    h = (xtarg - x0) / n
    xi = x0
    yi = y0

    For i = 1 To n
        'apply Euler Method to get y at the end of the interval
        k1 = dCdt(yi)
        ym = yi + k1 * h / 2#

        k2 = dCdt(ym)
        ym2 = yi + k2 * h / 2#

        k3 = dCdt(ym2)
        ye = yi + k3 * h

        k4 = dCdt(ye)

        Slope = (1 / 6#) * (k1 + 2# * k2 + 2# * k3 + k4)

        yi = yi + Slope * h
        xi = xi + h
    Next i

    SIMRK44 = yi
End Function

主要问题是名称 RK44 指的是一个单元格,因此 Excel 会感到困惑。将函数重命名为SIMRK44,问题就消失了。

我将代码调整为真正的模拟,其中每一步的结果都取决于上一步。您的代码中有一些混淆 yold 是不需要的。

另外,为了提高可读性,每个应该是实系数而不是整数的值,我使用了文字。所以2# 而不是2。无论如何,编译器在内部都会进行更改,更清楚的是1/6# 不是整数除法。

此外,VBA 默认传递函数参数ByRef,这可能会导致副作用。您必须将ByVal 放在每个参数之前,以向 Excel 显示该函数不会修改参数。只有这样它才能用作 UDF。


如果我被要求编写一个RK4 积分器,那么我会坚持使用教科书中给出的标准伪代码。更简单、更容易理解意图是什么。

Function f(ByVal x As Double, ByVal y As Double) As Double
    f = 0.02 - 0.1 * y
End Function

Function SIMRK4(ByVal x0 As Double, ByVal y0 As Double, ByVal n As Long, ByVal xtarg As Double) As Double
    Dim xi As Double, yi As Double, h As Double
    Dim k1 As Double, k2 As Double, k3 As Double, k4 As Double
    h = (xtarg - x0) / n

    xi = x0
    yi = y0

    Do
        'Ensure we don't overstep
        If xi + h > xtarg Then
            h = xtarg - xi
        End If
        k1 = f(xi, yi)
        k2 = f(xi + h / 2#, yi + h / 2# * k1)
        k3 = f(xi + h / 2#, yi + h / 2# * k2)
        k4 = f(xi + h, yi + h * k3)

        xi = xi + h
        yi = yi + (h / 6#) * (k1 + 2# * k2 + 2# * k3 + k4)
    Loop Until xi = xtarg
    SIMRK4 = yi
End Function

PS。此外,上面的代码可以处理可变时间步,因为迭代次数不固定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多