zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C#,数值计算,解微分方程的龙格-库塔四阶方法与源代码

c#方法计算 源代码 数值 微分方程
2023-09-11 14:15:48 时间

Carl Runge

Martin Wilhelm Kutta

数值分析中,龙格-库塔法(Runge-Kutta)是用于模拟常微分方程的解的重要的一类隐式或显式迭代法。这些技术由数学家卡尔·龙格和马丁·威尔海姆·库塔于1900年左右发明。

对于一阶精度的欧拉公式有:
yi+1=yi+h*K1  K1=f(xi,yi)
当用点xi处的斜率近似值K1与右端点xi+1处的斜率K2的算术平均值作为平均斜率K*的近似值,那么就会得到二阶精度的改进欧拉公式:
yi+1=yi+h*( K1+ K2)/2
K1=f(xi,yi)
K2=f(xi+h,yi+h*K1)
依次类推,如果在区间[xi,xi+1]内多预估几个点上的斜率值K1、K2、……Km,并用他们的加权平均数作为平均斜率K*的近似值,显然能构造出具有很高精度的高阶计算公式。经数学推导、求解,可以得出四阶龙格-库塔公式,也就是在工程中应用广泛的经典龙格-库塔算法:
yi+1=yi+h*( K1+ 2*K2 +2*K3+ K4)/6
K1=f(xi,yi)
K2=f(xi+h/2,yi+h*K1/2)
K3=f(xi+h/2,yi+h*K2/2)
K4=f(xi+h,yi+h*K3)
通常所说的龙格-库塔法是指四阶而言的,我们可以仿二阶、三阶的情形推导出常用的标准四阶龙格-库塔法公式。龙格-库塔法具有精度高,收敛,稳定(在一定条件下),计算过程中可以改变步长,不需要计算高阶导数等优点,但仍需计算 在一些点上的值,如四阶龙格-库塔法每计算一步需要计算四次 的值,这给实际计算带来一定的复杂性,因此,多用来计算“表头” 。
 

源程序

using System;
using System.Collections;
using System.Collections.Generic;

namespace Legalsoft.Truffer.Algorithm
{
    /// <summary>
    /// 给定微分方程的一阶偏导方程
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public delegate double SDE_Equation(double x, double y);

	/// <summary>
    /// 解微分方程的龙格-库塔四阶方法
    /// </summary>
    public static partial class Algorithm_Gallery
    {
        public static SDE_Equation dydx = null;

		/// <summary>
        /// Finds value of y for a given x
        /// using step size h
        /// and initial value y0 at x0.
        /// </summary>
        /// <param name="x0">初值</param>
        /// <param name="y0">初值</param>
        /// <param name="x">求值点</param>
        /// <param name="h">步长</param>
        /// <returns></returns>
        public static double Runge_Kutta_4th_Order(double x0, double y0, double x, double h)
        {
            int n = (int)((x - x0) / h);

            double y = y0;
            for (int i = 1; i <= n; i++)
            {
                double k1 = h * (dydx(x0, y));
                double k2 = h * (dydx(x0 + 0.5 * h, y + 0.5 * k1));
                double k3 = h * (dydx(x0 + 0.5 * h, y + 0.5 * k2));
                double k4 = h * (dydx(x0 + h, y + k3));

                y = y + (1.0 / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4);

                x0 = x0 + h;
            }

            return y;
        }
    }
}