日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

常微分方程数值求解【python】

發(fā)布時(shí)間:2025/4/16 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常微分方程数值求解【python】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡述

這里只考慮最為簡單的一種常微分方程

dydx=f(x,y)\frac{dy}{dx} = f(x,y)dxdy?=f(x,y)

然后這里的實(shí)例都是以下面這個方程來做展示的。

dydx=y?(1?y2)\frac{dy}{dx} = y*(1-y^2)dxdy?=y?(1?y2)
初值給定

y(0)=2y(0) = 2y(0)=2

這個方程的精確解結(jié)果是下面這個方程

y(x)=4?e2x4?e2x?3y(x) = \sqrt{\frac{4*e^{2x}}{4*e^{2x}-3}}y(x)=4?e2x?34?e2x??

文章目錄

    • 簡述
    • 歐拉公式求解
      • 簡單的理論推理
      • 代碼實(shí)現(xiàn)
        • 實(shí)現(xiàn)后的效果
        • 代碼
        • 誤差畫圖
        • 誤差畫圖代碼
    • 改進(jìn)版歐拉公式
      • 理解這個公式
      • 改進(jìn)版本的畫圖
      • 歐拉算法和改進(jìn)版歐拉算法的比較
          • 加上絕對值再來看
    • 累積誤差和分步的誤差
      • 圖像
      • 代碼

歐拉公式求解

歐拉公式非常簡潔。(歐拉果然大佬!!!)

yn+1=yn+h?f(xn,yn)xn=x0+n?hy_{n+1} = y_n + h*f(x_n, y_n)\\ x_n=x_0+n*hyn+1?=yn?+h?f(xn?,yn?)xn?=x0?+n?h

  • h是步長

簡單的理論推理

其實(shí)非常直觀,將上面的第一個式子變形一下,有

dydx=f(x,y)=yn+1?ynh\frac{dy}{dx} = f(x,y)=\frac{y_{n+1}- y_n}{h}dxdy?=f(x,y)=hyn+1??yn??

是不是非常熟悉,

  • 微商的推導(dǎo)公式右邊的加上一個取極限(h→0h\to0h0
  • 之前的第一個式子,就是一階泰勒展開。
  • 代碼實(shí)現(xiàn)

    實(shí)現(xiàn)后的效果

    x取值精確值數(shù)值逼近值誤差
    02.020.0
    0.11.60965717050902921.40.20965717050902932
    0.21.41810455587022391.26560.15250455587022382
    0.31.3036676496455711.18944336035840.11422428928717099
    0.41.22812384194336131.14010816301480270.08801567892855866
    0.51.1751778561206881.10592240471880590.06925545140188216
    0.61.13658062519152031.08125321679537210.05532740839614814
    0.71.10766202709141861.06296830379809150.0446937232933271
    0.81.0855609572859361.04916017387519340.03640078341074249
    0.91.06841885384474741.03859124164073150.029827612204015974
    11.05497292194519551.03042046080156640.02455246114362919

    代碼

    import numpy as np# dy/dx = f(x,y) # Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1 while x <= 1:loss = F(x) - yprint(x, '|', F(x), '|', y, '|', loss)y = y + h * f(y)x += 0.1

    誤差畫圖

    誤差畫圖代碼

    import numpy as np import matplotlib.pyplot as plt# dy/dx = f(x,y) # Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1 losses = [] while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(loss)y = y + h * f(y)x += 0.1plt.plot(np.arange(0, 1.1, 0.1), losses) plt.plot(np.arange(0, 1.1, 0.1), losses, 'r*') plt.show()

    改進(jìn)版歐拉公式

    之前提到的歐拉公式簡單,容易實(shí)現(xiàn),但是效率卻有點(diǎn)低。
    所以有歐拉公式的改進(jìn)版本。

    yˉn+1=yn+h?f(xn,yn)yn+1=yn+h2?(f(xn,yn)+f(xn+1,yˉn+1))\bar y_{n+1} = y_n + h * f(x_n, y_n)\\ y_{n+1} = y_n + \frac{h}{2} * (f(x_n, y_n) + f(x_{n+1}, \bar y_{n+1}))yˉ?n+1?=yn?+h?f(xn?,yn?)yn+1?=yn?+2h??(f(xn?,yn?)+f(xn+1?,yˉ?n+1?))

    x的話,任然是按照步長移動的,所以,這里就不作贅述了。

    理解這個公式

    書上的話,是用定積分的方式推理出來的。
    但是這個具體含義,也沒有給出什么東西來。
    但是實(shí)際上,這個公式的邏輯含義是非常漂亮的!

    將上面的兩個公式聯(lián)立起來。
    yn+1?ynh=12?(yˉn+1?ynh+f(xn+1,yˉn+1))\frac{y_{n+1}-y_n}{h} = \frac{1}{2}* (\frac{\bar y_{n+1} -y_n}{h} + f(x_{n+1}, \bar y_{n+1}))hyn+1??yn??=21??(hyˉ?n+1??yn??+f(xn+1?,yˉ?n+1?))

    之前的歐拉方法是用這里的 yˉn+1?ynh\frac{\bar y_{n+1} - y_n}{h}hyˉ?n+1??yn??來近似dydx\frac{dy}{dx}dxdy?
    而現(xiàn)在我們逼近的其實(shí)是,用歐拉公式得到的導(dǎo)數(shù),和實(shí)際上的在該點(diǎn)的導(dǎo)數(shù)值的均值。
    從這個角度上來看,其實(shí)會是更貼近于正確的結(jié)果。

    • 注意到: 我們這里用了yn+1y_{n+1}yn+1?或者說是yny_nyn?是正確解。
    • 用這個其實(shí)是合理的,因?yàn)?#xff0c;這里的算法是基于之前的歐拉算法的,而歐拉算法本來就是會近似逼近正確的結(jié)果。所以,yny_nyn?本身就是會逐漸接近于正確的結(jié)果。所以之前的假設(shè)是合理的。
    • 而且,留心到,這是在原來的基礎(chǔ)上,做了新的加速的過程。

    歐拉公式的預(yù)估值,和代入其的校正值的平均值,就是改進(jìn)歐拉方法的計(jì)算結(jié)果

    改進(jìn)版本的畫圖

    import numpy as np import matplotlib.pyplot as plt# dy/dx = f(x,y) # Advanced Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1 losses = [] while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(loss)y1 = y + h * f(y)y2 = y + h * f(y1)y = (y1+y2)/2x += 0.1plt.plot(np.arange(0, 1.1, 0.1), losses) plt.plot(np.arange(0, 1.1, 0.1), losses, 'r*') plt.show()

    歐拉算法和改進(jìn)版歐拉算法的比較

    import numpy as np import matplotlib.pyplot as plt# dy/dx = f(x,y) # Advanced Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1def AdvancedEular():x = 0y = 2h = 0.1losses = []while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(loss)y1 = y + h * f(y)y2 = y + h * f(y1)y = (y1 + y2) / 2x += 0.1return lossesdef Eular():x = 0y = 2h = 0.1losses = []while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(loss)y = y + h * f(y)x += 0.1return lossesadEl = AdvancedEular() El = Eular() plt.plot(np.arange(0, 1.1, 0.1), adEl, label='Advance Eular') plt.plot(np.arange(0, 1.1, 0.1), adEl, 'r*')plt.plot(np.arange(0, 1.1, 0.1), El, label='Eular') plt.plot(np.arange(0, 1.1, 0.1), El, 'b*') plt.legend() plt.show()
    加上絕對值再來看

    import numpy as np import matplotlib.pyplot as plt# dy/dx = f(x,y) # Advanced Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1def AdvancedEular():x = 0y = 2h = 0.1losses = []while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(abs(loss))y1 = y + h * f(y)y2 = y + h * f(y1)y = (y1 + y2) / 2x += 0.1return lossesdef Eular():x = 0y = 2h = 0.1losses = []while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(abs(loss))y = y + h * f(y)x += 0.1return lossesadEl = AdvancedEular() El = Eular() plt.plot(np.arange(0, 1.1, 0.1), adEl, label='Advance Eular') plt.plot(np.arange(0, 1.1, 0.1), adEl, 'r*')plt.plot(np.arange(0, 1.1, 0.1), El, label='Eular') plt.plot(np.arange(0, 1.1, 0.1), El, 'b*') plt.legend() plt.show()

    累積誤差和分步的誤差

    前面的話,我們是用一個不那么正確的結(jié)果來放到公式中來推導(dǎo)出正確的結(jié)果。下面我們嘗試每一步都用正確的結(jié)果來推導(dǎo)出對應(yīng)y值。

    x取值精確值數(shù)值逼近值(每步使用對應(yīng)的精確值推出)誤差
    02.020.0
    0.11.60965717050902921.40.20965717050902932
    0.21.41810455587022391.353561325293040.06454323057718381
    0.300000000000000041.3036676496455711.2747312737074090.028936375938162007
    0.41.22812384194336131.21246966516119840.015654176782162965
    0.51.1751778561206881.16569975978668520.009478096334002872
    0.61.13658062519152031.13039852729964490.006182097891875404
    0.71.10766202709141861.1034134388525420.004248588238876527
    0.79999999999999991.0855609572859361.0825274957876550.003033461498280987
    0.89999999999999991.06841885384474741.06618992618851040.0022289276562370564
    0.99999999999999991.05497292194519551.05329871338702130.0016742085581742394

    圖像

    代碼

    import numpy as np import matplotlib.pyplot as plt# dy/dx = f(x,y) # Euler formula f = lambda x: x * (1 - x ** 2) F = lambda x: ((4 * np.exp(2 * x) / (4 * np.exp(2 * x) - 3))) ** 0.5 x = 0 y = 2 h = 0.1def stepEular():x = 0y = 2h = 0.1losses = []while x <= 1:ty = F(x)loss = ty - yprint(x, '|', ty, '|', y, '|', loss)losses.append(abs(loss))y = ty + h * f(ty)x += 0.1return lossesdef Eular():x = 0y = 2h = 0.1losses = []while x <= 1:loss = F(x) - y# print(x, '|', F(x), '|', y, '|', loss)losses.append(abs(loss))y = y + h * f(y)x += 0.1return lossesadEl = stepEular() El = Eular() plt.plot(np.arange(0, 1.1, 0.1), adEl, label='Step Eular') plt.plot(np.arange(0, 1.1, 0.1), adEl, 'r*')plt.plot(np.arange(0, 1.1, 0.1), El, label='Eular') plt.plot(np.arange(0, 1.1, 0.1), El, 'b*') plt.legend() plt.show()

    總結(jié)

    以上是生活随笔為你收集整理的常微分方程数值求解【python】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。