Трудности с функцией RK4 VBA. Функция возвращает только #ССЫЛКА! ценность

Н/Д. Уже не вопрос......


person Katherine_5    schedule 19.04.2020    source источник
comment
Чтобы отладить свою функцию, вызовите ее из подпрограммы VBA — тогда вы сможете увидеть, в чем проблема. Также очень полезно, если бы вы могли предоставить примеры аргументов для RK44.   -  person Tim Williams    schedule 19.04.2020
comment
Лол, главная проблема в названии функции! Смотрите мой ответ.   -  person John Alexiou    schedule 19.04.2020


Ответы (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. Кроме того, приведенный выше код может обрабатывать переменные шаги по времени, поскольку количество итераций не является фиксированным.

person John Alexiou    schedule 19.04.2020