昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

y'=-50y+50x^2+2x,y(0)=1/3,0<=x<=1.步长h=0.001,迭代3次。分别用RK4法,Runge-Kutta-Fehlberg法求解。要求显示详细的演绎计算过程

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter


# --- 1. 问题定义 ---
# 定义常微分方程 y' = f(x, y)
def f(x, y):
    """ODE function: y' = -50y + 50x^2 + 2x"""
    return -50 * y + 50 * x ** 2 + 2 * x


# 定义精确解
def y_exact(x):
    """Exact solution: y(x) = (1/3)e^(-50x) + x^2"""
    return (1 / 3) * np.exp(-50 * x) + x ** 2


# --- 2. 数值求解器实现 ---
def rk4_solver(f, x0, y0, h, x_end):
    """四阶龙格-库塔法求解器"""
    x_points = [x0]
    y_points = [y0]

    xi, yi = x0, y0

    while xi < x_end:
        k1 = f(xi, yi)
        k2 = f(xi + 0.5 * h, yi + 0.5 * h * k1)
        k3 = f(xi + 0.5 * h, yi + 0.5 * h * k2)
        k4 = f(xi + h, yi + h * k3)

        yi = yi + (h / 6.0) * (k1 + 2 * k2 + 2 * k3 + k4)
        xi = xi + h

        x_points.append(xi)
        y_points.append(yi)

    return np.array(x_points), np.array(y_points)


def rkf45_solver(f, x0, y0, h, x_end):
    """龙格-库塔-费尔伯格(RKF45)法求解器 (使用四阶公式)"""
    x_points = [x0]
    y_points = [y0]

    xi, yi = x0, y0

    # RKF45 系数
    c = [0, 1 / 4, 3 / 8, 12 / 13, 1, 1 / 2]
    a = [
        [],
        [1 / 4],
        [3 / 32, 9 / 32],
        [1932 / 2197, -7200 / 2197, 7296 / 2197],
        [439 / 216, -8, 3680 / 513, -845 / 4104],
        [-8 / 27, 2, -3544 / 2565, 1859 / 4104, -11 / 40]
    ]
    # 四阶解的系数
    b4 = [25 / 216, 0, 1408 / 2565, 2197 / 4104, -1 / 5, 0]

    while xi < x_end:
        k = np.zeros(6)
        k[0] = f(xi, yi)
        for i in range(1, 6):
            y_temp = yi + h * sum(a[i][j] * k[j] for j in range(i))
            k[i] = f(xi + c[i] * h, y_temp)

        # 使用四阶公式更新 y
        yi = yi + h * sum(b4[i] * k[i] for i in range(6))
        xi = xi + h

        x_points.append(xi)
        y_points.append(yi)

    return np.array(x_points), np.array(y_points)


# --- 3. 计算与可视化 ---
# 初始条件和参数
x0, y0 = 0.0, 1 / 3
h = 0.0001
x_end = 1.0

# 运行求解器
x_rk4, y_rk4 = rk4_solver(f, x0, y0, h, x_end)
x_rkf, y_rkf = rkf45_solver(f, x0, y0, h, x_end)

# 计算用于绘图的精确解
x_true = np.linspace(0, x_end, 500)
y_true = y_exact(x_true)

# 计算每个数值解时间点的误差
y_true_at_steps_rk4 = y_exact(x_rk4)
error_rk4 = np.abs(y_rk4 - y_true_at_steps_rk4)

y_true_at_steps_rkf = y_exact(x_rkf)
error_rkf = np.abs(y_rkf - y_true_at_steps_rkf)

# --- 4. 绘图 ---
# 设置中文字体以正确显示图例
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)

# 图1: 解的对比
ax1.plot(x_true, y_true, 'k-', label='精确解', linewidth=2.5)
ax1.plot(x_rk4, y_rk4, 'r--', label='RK4 解', linewidth=1.5)
ax1.plot(x_rkf, y_rkf, 'b:', label='RKF45 解', linewidth=1.5)
ax1.set_title('数值解与精确解对比', fontsize=16)
ax1.set_ylabel('y(x)', fontsize=12)
ax1.legend(fontsize=12)
ax1.grid(True)

# 放大显示初始阶段的细节
ax_zoom = ax1.inset_axes([0.1, 0.1, 0.4, 0.4])
ax_zoom.plot(x_true, y_true, 'k-')
ax_zoom.plot(x_rk4, y_rk4, 'r--')
ax_zoom.plot(x_rkf, y_rkf, 'b:')
ax_zoom.set_xlim(0, 0.1)
ax_zoom.set_ylim(0, 0.4)
ax_zoom.grid(True)
ax1.indicate_inset_zoom(ax_zoom, edgecolor="black")

# 图2: 误差对比
ax2.plot(x_rk4, error_rk4, 'r-', label='RK4 绝对误差')
ax2.plot(x_rkf, error_rkf, 'b-', label='RKF45 绝对误差')
ax2.set_yscale('log')  # 使用对数坐标轴,因为误差很小
ax2.set_title('绝对误差对比 (对数坐标)', fontsize=16)
ax2.set_xlabel('x', fontsize=12)
ax2.set_ylabel('绝对误差', fontsize=12)
ax2.legend(fontsize=12)
ax2.grid(True, which="both", ls="--")

# 格式化y轴刻度为科学计数法
formatter = ScalarFormatter(useMathText=True)
formatter.set_scientific(True)
formatter.set_powerlimits((-1, 1))
ax2.yaxis.set_major_formatter(formatter)

plt.tight_layout()
plt.show()

posted on 2025-06-24 15:56  Indian_Mysore  阅读(13)  评论(0)    收藏  举报

导航