【发布时间】:2020-08-01 14:17:20
【问题描述】:
不适用。不再是问题......
【问题讨论】:
-
要调试您的函数,请从 VBA 子程序中调用它 - 然后您可以看到问题出在哪里。如果您可以为 RK44 提供示例参数,也非常有用
-
大声笑,主要问题是函数名!看我的回答。
标签: excel vba differential-equations ref runge-kutta
不适用。不再是问题......
【问题讨论】:
标签: excel vba differential-equations ref runge-kutta
试试这个:
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。此外,上面的代码可以处理可变时间步,因为迭代次数不固定。
【讨论】: