Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Uvod

Vsako elementarno funkcijo lahko analitično odvajamo. Definicija odvoda je:

f′(x)=lim⁡Δx→0f(x+Δx)−f(x)Δx.f'(x)=\lim_{\Delta x \rightarrow 0}\frac{f(x+\Delta x)-f(x)}{\Delta x}.

Neposredna uporaba zgornje enačbe vodi v odštevanje zelo podobnih funkcijskih vrednostih (f(x+Δx)f(x+\Delta x), f(x)f(x)), obremenjenih z zaokrožitveno napako, ki jih delimo z majhno vrednostjo Δx\Delta x; posledično ima odvod bistveno manj signifikantnih števk kakor pa funkcijske vrednosti. Numeričnemu odvajanju se izognemo, če imamo to možnost; je pa v nekaterih primerih (npr. reševanje diferencialnih enačb) nepogrešljivo orodje!

Pri numeričnem odvajanju imamo dva, v principu različna, pristopa:

  1. najprej izvedemo interpolacijo/aproksimacijo, nato pa na podlagi znanih interpolacijskih/aproksimacijskih funkcij izračunamo odvod (o tej temi smo že govorili pri interpolaciji oz. aproksimaciji) in

  2. računanje odvoda neposredno iz vrednosti iz tabele.

V okviru tega poglavja se bomo seznanili s tem, kako numerično izračunamo odvod funkcije f(x)f(x); pri tem so vrednosti funkcije f(x)f(x) podane tabelarično (pari xix_i, yiy_i), kakor je prikazano na sliki: Najprej se bomo osredotočili na ekvidistantno, s korakom hh, razporejene vrednosti xix_i; vrednosti funkcije pa bodo yi=f(xi)y_i=f(x_i).

Glede na zgornjo definicijo odvoda, bi prvi odvod (za mesto ii) lahko zapisali:

yi′=yi+1−yih,y_i'=\frac{y_{i+1}-y_{i}}{h},

kjer je h=xi+1−xih=x_{i+1}-x_{i}. S preoblikovanjem enačbe:

yi′=−yih+yi+1h,y_i'=-\frac{y_{i}}{h}+\frac{y_{i+1}}{h},

lahko tudi rečemo, da za prvi odvod funkcije na mestu ii, utežimo funkcijsko vrednost pri ii z −1/h-1/h in funkcijsko vrednost pri i+1i+1 z +1/h+1/h.

V nadaljevanju si bomo pogledali teoretično ozadje kako določimo ustrezne uteži za različne stopnje odvodov, katere možnosti pri tem imamo in kako to vpliva na red natančnosti.

Aproksimacija prvega odvoda po metodi končnih razlik

Za uvod si oglejmo spodnji video:

Loading...

Odvod f′(x)f'(x) lahko aproksimiramo na podlagi razvoja Taylorjeve vrste. To metodo imenujemo metoda končnih razlik ali tudi diferenčna metoda.

Razvijmo Taylorjevo vrsto naprej (naprej, zaradi člena +h+h):

f(x+h)=∑n=0∞hnn!dndxnf(x)=f(x)+h f′(x)+h22 f′′(x)+⋯⏟O(h2)f{\left (x + h \right )} =\sum_{n=0}^{\infty}\frac{h^n}{n!}\frac{d^n}{dx^n}f(x)= f{\left (x \right )} + h\, f'\left (x \right ) + \underbrace{\frac{h^2}{2}\,f''(x)+\cdots}_{\mathcal{O}\left(h^{2}\right)}

Člen O(h2)\mathcal{O}\left(h^{2}\right) označuje napako drugega reda. Če iz enačbe izrazimo prvi odvod:

f′(x)=1h(f(x+h)−f(x))−h2 f′′(x)+⋯⏟O(h1)f'{\left (x \right )}=\frac{1}{h}\left(f{\left (x + h \right )} - f{\left (x \right )}\right) - \underbrace{\frac{h}{2}\,f''(x)+\cdots}_{\mathcal{O}\left(h^{1}\right)}

Ugotovimo, da lahko ocenimo prvi odvod v točki xix_i (to je: fo′(xi)f_o'(x_i)) na podlagi dveh zaporednih funkcijskih vrednosti:

fo′(xi)=1h(yi+1−yi)f_o'(x_i)=\frac{1}{h}\left(y_{i+1}-y_i\right)

in pri tem naredimo napako metode, ki je prvega reda O(h1)\mathcal{O}\left(h^{1}\right).

Uporabili smo yi=f(xi)y_i=f(x_i) (glejte sliko zgoraj).

Napaka je:

e=−h2 f′′(ξ),e=-\frac{h}{2}\,f''(\xi),

kjer je ξ\xi neznana vrednost na intervalu [xi,xi+1][x_i, x_{i+1}] in smo zanemarili višje člene.

Velja torej izraz:

f′(xi)=fo′(xi)+ef'(x_i)=f_o'(x_i)+e

Sedaj si poglejmo, kako pridemo do istega rezultata s strojno izpeljavo; najprej uvozimo sympy:

Definirajmo simbole:

Nato nadaljujemo z razvojem Taylorjeve vrste naprej (angl. forward Taylor series):

Loading...

Člen O(h2)\mathcal{O}\left(h^{2}\right) vsebuje člene drugega in višjega reda. V zgornji enačbi je uporabljena začasna spremenljivko za odvajanje ξ1\xi_1; izvedmo odvajanje in vstavimo ξ1=x\xi_1=x:

Loading...

Zapišemo enačbo:

Loading...

Rešimo jo za prvi odvod f′(x)f'(x):

Loading...

V kolikor odvoda drugega in višjih redov ne upoštevamo, smo naredili torej napako:

Loading...

Napaka O(h1)\mathcal{O}\left(h^{1}\right) je torej prvega reda in če ta člen zanemarimo, naredimo napako metode in dobimo oceno odvoda:

Loading...

Ugotovimo, da gre za isti izraz, kakor smo ga izpeljali zgoraj, torej je:

yi′=1h(−yi+yi+1).y_i'=\frac{1}{h}\left(-y_i+y_{i+1}\right).

Uteži torej so:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyiy_{i}yi+1y_{i+1}
yi′=1h⋅y_i'=\frac{1}{h}\cdot-11

Centralna diferenčna shema

Odvod f′(x)f'(x)

Najprej si poglejmo razvoj Taylorjeve vrste nazaj (angl. backward Taylor series):

Loading...

Ugotovimo, da se pri razliki vrste naprej in nazaj odštevajo členi sodega reda; definirajmo:

Loading...

Izvedemo sledeče korake:

  1. Taylorjevo vrsto nazaj odštejemo od vrste naprej, sodi odvodi se odštejejo,

  2. rešimo enačbo za prvi odvod,

  3. določimo napako metode,

  4. določimo oceno odvoda.

Izvedimo zgornje korake:

Ocena 1. odvoda torej je:

Loading...

Ali:

yi′=12h(−yi−1+yi+1)y_i'=\frac{1}{2h}\left(-y_{i-1}+y_{i+1}\right)

Uteži torej so:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−1y_{i-1}yiy_{i}yi+1y_{i+1}
yi′=12h⋅y_i'=\frac{1}{2h}\cdot-101

Napaka metode pa je torej drugega reda:

Loading...

Zgled: exp⁡(−x)\exp(-x)

Poglejmo si zgled eksponentne funkcije f(x)=exp⁡(−x)f(x)=\exp(-x) in za točko x=1,0x=1,0 izračunajmo prvi odvod f′(x)=−exp⁡(−x)f'(x)=-\exp(-x) pri koraku h0=1h_0=1 in h1=0,1h_1=0,1.

Najprej pripravimo tabelo numeričnih vrednosti in točen rezultat:

Potem uporabimo shemo naprej:

Loading...

Izračunajmo napako pri x=1,0x=1,0:

Loading...
Loading...

Potrdimo lahko, da je napaka pri koraku h/10h/10 res približno 1/10 tiste pri koraku hh.

Poglejmo sedaj še napako za centralno diferenčno shemo, ki je drugega reda:

Loading...

Analizirajmo napako:

Loading...
Loading...

Potrdimo lahko, da je napaka pri koraku h/10h/10 res približno 1/100 tiste pri koraku hh.

Odvod f′′(x)f''(x)

Če Taylorjevo vrsto naprej in nazaj seštejemo, se odštejejo lihi odvodi:

Loading...

Določimo drugi odvod:

Ocena drugega odvoda je:

Loading...

Ali:

yi′′=1h2(yi−1−2 yi+yi+1)y_i''=\frac{1}{h^2}\left(y_{i-1}-2\,y_{i}+y_{i+1}\right)

Uteži torej so:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−1y_{i-1}yiy_{i}yi+1y_{i+1}
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot1-21

Napaka metode pa je ponovno drugega reda:

Loading...

Odvod f′′′(x)f'''(x)

Če želimo določiti tretji odvod, moramo Taylorjevo vrsto razviti do stopnje 5:

Loading...

Uporaba 1. odvoda, ki smo ga izpeljali zgoraj, nam ne bi koristila, saj je red napake O(h2)\mathcal{O}\left(h^{2}\right), kar pomeni, da bi v zgornji enačbi pri deljenju s h3h^3 dobili O(h−1)\mathcal{O}\left(h^{-1}\right).

Uporabimo trik: ponovimo razvoj, vendar na podlagi dodatnih točk, ki sta od xx oddaljeni za 2h2h in −2h-2h:

Loading...

Sedaj imamo dve enačbi in dve neznanki; sistem bomo rešili po korakih:

  1. enačbo eq_h rešimo za prvi odvod,

  2. enačbo eq_2h rešimo za prvi odvod,

  3. enačimo rezultata prvih dveh korakov in rešimo za tretji odvod,

  4. določimo napako metode,

  5. določimo oceno odvoda.

Izvedimo navedene korake:

Ocena 3. odvoda je:

Loading...

Ali:

yi′′′=1h3(−yi−2/2+yi−1−yi+1+yi+2/2)y_i'''=\frac{1}{h^3}\left(-y_{i-2}/2+y_{i-1}-y_{i+1}+y_{i+2}/2\right)

Uteži torej so:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−2y_{i-2}yi−1y_{i-1}yiy_{i}yi+1y_{i+1}yi+2y_{i+2}
yi′′′=1h3⋅y_i'''=\frac{1}{h^3}\cdot-0.510-10.5

Potrdimo, da je napaka metode drugega reda:

Loading...

Odvod f(4)(x)f^{(4)}(x)

Ponovimo podoben postopek kot za 3. odvod, vendar za 4. odvod seštevamo Taylorjevo vrsto (do stopnje 6) naprej in nazaj:

Loading...

Pripravimo dodatno enačbo na podlagi točk, ki sta od xx oddaljeni za 2h2h in −2h-2h:

Loading...

Iz dveh enačb določimo 4. odvod:

Ocena 4. odvoda je:

Loading...

Ali:

yi(4)=1h4(yi−2−4 yi−1+6 yi−4 yi+1+yi+2)y_i^{(4)}=\frac{1}{h^4}\left(y_{i-2}-4\,y_{i-1}+6\,y_i-4\,y_{i+1}+y_{i+2}\right)

Uteži torej so:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−2y_{i-2}yi−1y_{i-1}yiy_{i}yi+1y_{i+1}yi+2y_{i+2}
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot1-46-41

Potrdimo, da je napaka metode drugega reda:

Loading...

Povzetek centralne diferenčne sheme

Zgoraj smo izpeljali prve štiri odvode z napako metode 2. reda. Bistvo zgornjih izpeljav je, da nam dajo uteži, s katerimi moramo množiti funkcijske vrednosti, da izračunamo približek določenega odvoda. Iz tega razloga bomo tukaj te uteži zbrali. Če ste neučakani, lahko skočite na tabelo spodaj. Z branjem nadaljujte, če pa želite spoznati, kako predhodno izpeljane izraze strojno uredimo.

Najprej zberimo vse ocene odvodov v seznam:

Loading...

Na razpolago imamo 5 funkcijskih vrednosti (pri legah x−2h,x−h,x,x+h,x+2hx-2h, x-h, x, x+h, x+2h), ki jih damo v seznam:

Utež prvega odvoda za funkcijsko vrednosti f(x−h)f(x-h) izračunamo:

Loading...

Sedaj posplošimo in izračunajmo uteži za vse funkcijske vrednosti in za vse ocene odvodov:

Loading...

Zgornje povzetke lahko tudi zapišemo v tabelarični obliki:

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−2y_{i-2}yi−1y_{i-1}yiy_{i}yi+1y_{i+1}yi+2y_{i+2}
yi′=1h⋅y_i'=\frac{1}{h}\cdot0-0.500.50
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot01-210
yi′′′=1h3⋅y_i'''=\frac{1}{h^3}\cdot-0.510-10.5
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot1-46-41

Prikazana centralna diferenčna shema ima napako 2. reda O(h2)\mathcal{O}(h^{2}).

Opomba: v kolikor vas zanima posplošitev diferenčne metode, prosim glejte paket findiff.

Izboljšan približek - Richardsonova ekstrapolacija

Če je točen odvod je izračunan kot:

f′(xi)=fo′(xi)+e,f'(x_i)=f_o'(x_i)+e,

kjer je fo′(xi)f_o'(x_i) numerično izračunan odvod v točki xix_i in ee ocena napake.

Za metodo reda točnosti nn: O(hn)\mathcal{O}(h^{n}) pri koraku hh velja:

f′(xi)=fo′(xi,h)+K hn,f'(x_i)=f_o'(x_i, h)+K\,h^n,

kjer je KK neznana konstanta.

Če korak razpolovimo in predpostavimo, da se KK ne spremeni, velja:

f′(xi)=fo′(xi,h2)+K (h2)n.f'(x_i)=f_o'\left(x_i, \frac{h}{2}\right)+K\,\left(\frac{h}{2}\right)^n.

Iz obeh enačb izločimo konstanto KK in določimo izboljšan približek:

f‾′(xi)=2n fo′(xi,h2)−fo′(xi,h)2n−1\overline{f}'(x_i)=\frac{2^n\,f_o'\left(x_i, \frac{h}{2}\right)-f_o'(x_i, h)}{2^n-1}
Zgled

Poglejmo si zgled f(x)=sin⁡(x)f(x)=\sin(x) (analitični odvod je: f′(x)=cos⁡(x)f'(x)=\cos(x)):

Pri koraku hh imamo funkcijske vrednosti definirane pri:

array([0. , 0.78539816, 1.57079633, 2.35619449, 3.14159265, 3.92699082, 4.71238898, 5.49778714, 6.28318531])

Numerični odvod pri x=πx=\pi:

Loading...

in koraku hh je

Loading...

Izračun pri koraku 2h2h:

Loading...

Izračunajmo izboljšano oceno za x=πx=\pi:

Loading...

Vidimo, da je izboljšana ocena najbližje teoretični vrednosti cos⁡(π)=−1\cos(\pi)=-1.

Necentralna diferenčna shema

Centralna diferenčna shema, ki smo jo spoznali zgoraj, je zelo uporabna in relativno natančna. Ker pa je ne moremo vedno uporabiti (recimo na začetku ali koncu tabele), si moramo pomagati z necentralnimi diferenčnimi shemami za računanje odvodov.

Poznamo:

  • diferenčno shemo naprej, ki odvod točke aproksimira z vrednostmi funkcije v naslednjih točkah in

  • diferenčno shemo nazaj, ki odvod točke aproksimira z vrednostmi v predhodnih točkah.

Izpeljave so podobne, kakor smo prikazali za centralno diferenčno shemo, zato jih tukaj ne bomo obravnavali in bomo prikazali samo končni rezultat.

Diferenčna shema naprej

Diferenčna shema naprej z redom napake O(h1)\mathcal{O}(h^{1}):

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyiy_{i}yi+1y_{i+1}yi+2y_{i+2}yi+3y_{i+3}yi+4y_{i+4}
yi′=1h⋅y_i'=\frac{1}{h}\cdot-11000
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot1-2100
yi′′′=1h3⋅y_i'''=\frac{1}{h^3}\cdot-13-310
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot1-46-41

Diferenčna shema naprej z redom napake O(h2)\mathcal{O}(h^{2}):

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyiy_{i}yi+1y_{i+1}yi+2y_{i+2}yi+3y_{i+3}yi+4y_{i+4}yi+5y_{i+5}
yi′=12h⋅y_i'=\frac{1}{2h}\cdot-34-1000
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot2-54-100
yi′′′=12h3⋅y_i'''=\frac{1}{2h^3}\cdot-518-2414-30
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot3-1426-2411-2

Diferenčna shema nazaj

Diferenčna shema nazaj z redom napake O(h1)\mathcal{O}(h^{1}):

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−4y_{i-4}yi−3y_{i-3}yi−2y_{i-2}yi−1y_{i-1}yiy_{i}
yi′=1h⋅y_i'=\frac{1}{h}\cdot000-11
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot001-21
yi′′′=1h3⋅y_i'''=\frac{1}{h^3}\cdot0-13-31
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot1-46-41

Diferenčna shema nazaj z redom napake O(h2)\mathcal{O}(h^{2}):

Odvod ↓\downarrow \\backslash Vrednosti →\rightarrowyi−5y_{i-5}yi−4y_{i-4}yi−3y_{i-3}yi−2y_{i-2}yi−1y_{i-1}yiy_{i}
yi′=12h⋅y_i'=\frac{1}{2h}\cdot0001-43
yi′′=1h2⋅y_i''=\frac{1}{h^2}\cdot00-14-52
yi′′′=12h3⋅y_i'''=\frac{1}{2h^3}\cdot03-1424-185
yi(4)=1h4⋅y_i^{(4)}=\frac{1}{h^4}\cdot-211-2426-143

Uporaba numpy.gradient

Za izračun numeričnih odvodov (centralna diferenčna shema 2. reda) lahko uporabimo tudi numpy.gradient() (dokumentacija):

gradient(f, *varargs, **kwargs)

kjer f predstavlja tabelo vrednosti (v obliki numeričnega polja) funkcije, katere odvod iščemo. f je lahko ene ali več dimenzij. Pozicijski parametri varargs definirajo razdaljo med vrednostmi argumenta funkcije f; privzeta vrednost je 1. Ta vrednost je lahko skalar, lahko pa tudi seznam vrednosti neodvisne spremenljivke (ali tudi kombinacija obojega). Gradientna metoda na robovih uporabi shemo naprej oziroma nazaj; parameter edge_order definira red sheme, ki se uporabi na robovih (izbiramo lahko med 1 ali 2, privzeta vrednost je 1).

Rezultat funkcije gradient je numerični seznam (ali seznam numeričnih seznamov) z izračunanimi odvodi.

Za podrobnosti glejte dokumentacijo.

Za odvajanje funkcije (in ne tabele vrednosti), glejte: scipy.differentiate.

Zgled

Pogledali si bomo zgled, kako uporabimo uteži, funkcijo gradient in posebnosti na robovih. Najprej pripravimo tabelo podatkov:

Uteži diferenčih shem:

Sedaj izvedemo odvod notranjih točk (prvi način je z izpeljevanjem seznamov, drugi je vektoriziran):

Na robovih uporabimo diferenčno shemo naprej oziroma nazaj:

Sestavimo rezultat:

Prikažemo rezultat skupaj z rezultatom funkcije np.gradient:

<Figure size 640x480 with 1 Axes>

Uporaba numpy.diff

Dajmo tukaj predstaviti še pogosto uporabljeno funkcijo numpy.diff (dokumentacija) izračuna n-to diskretno razliko vzdolž podane osi. Prva razlika je podana kot a[i+1]−a[i]a[i+1] - a[i]. To je osnovna operacija za numerično odvajanje (gre za odvod prve stopnje natančnosti), vendar moramo rezultat deliti s korakom hh.

Pri uporabi np.diff se dolžina polja zmanjša za 1.

<Figure size 640x480 with 1 Axes>

Zaokrožitvena napaka pri numeričnem odvajanju

Zgoraj smo se osredotočili na napako metode. Pri numeričnem odvajanju pa moramo biti zelo pozorni tudi na zaokrožitveno (ali tudi upodobitveno) napako! Poglejmo si prvi odvod (po centralni diferenčni shemi) zapisan z napako metode (k h2k\,h^2) in zaokrožitveno napako ε\varepsilon:

yi′=12h((−yi−1±ε)+(yi+1±ε))+k h2y_i'=\frac{1}{2h}\left((-y_{i-1}\pm\varepsilon)+(y_{i+1}\pm\varepsilon)\right) + k\,h^2

V najslabšem primeru se zaokrožitvena napaka sešteje in je skupna napaka:

n=εh+k h2n=\frac{\varepsilon}{h}+k\,h^2

Ko je hh velik prevladuje napaka metode k h2k\,h^2; ko pa je hh majhen, pa prevladuje zaokrožitvena napaka. Napaka ima minimum, ko velja:

n′=−εh2+2 k h=0.n'=-\frac{\varepsilon}{h^2}+2\,k\,h=0.

Sledi:

h=ε2 k3.h=\sqrt[3]{\frac{\varepsilon}{2\,k}}.

Zgled

Spodaj si bomo pogledali primer, kjer bomo natančnost spreminjali v treh korakih:

  1. float16 - 16-bitni zapis: predznak 1 bit, 5 bitov eksponent, 10 bitov mantisa

  2. float32 - 32-bitni zapis: predznak 1 bit, 8 bitov eksponent, 23 bitov mantisa

  3. float64 - 64-bitni zapis: predznak 1 bit, 11 bitov eksponent, 52 bitov mantisa (to je privzeta natančnost).

Za več o tipih v numpy glejte dokumentacijo

Določimo sedaj osnovno zaokrožitveno napako za posamezni tip:

Osnovna zaokrožitvena napaka za tipe `float16`, `float32` in `float64` je:
[np.float16(0.000977), np.float32(1.1920929e-07), np.float64(2.220446049250313e-16)]

Kot primer si poglejmo seštevanje: k številu 1. prištejemo polovico osnovne zaokrožitvene napake eps16 in pretvorimo v tip float16, ugotovimo, da je nova vrednost še vedno enaka vrednosti 1.:

np.float16(1.0)

Definirajmo najprej funkcijo exp⁡(x)\exp(x), ki bo dala rezultat natančnosti, ki jo definira parameter dtype:

Definirajmo še funkcijo za analitično določljiv odvod (to bomo pozneje potrebovali za določitev relativne napake):

Podobno kakor zgoraj pri seštevanju, lahko tudi pri vrednosti funkcije ugotovimo, da sprememba vrednosti xx, ki je manjša od ϵ\epsilon, vodi v isti rezultat:

np.float16(0.368)
np.float16(0.368)

Uporabimo sedaj centralno diferenčno shemo za prvi odvod. Pri tem naj bodo števila zapisana z natančnostjo dtype, s pomočjo točnega odvoda pa se izračuna še relativna napaka:

Poglejmo primer odvoda pri x=1,0x=1,0 (Python funkcija vrne vrednost in relativno napako):

(np.float16(-0.3662), np.float64(0.004535463210798897))
Loading...

Definirajmo sedaj korak:

array([1.00000000e+00, 2.50000000e-01, 6.25000000e-02, 1.56250000e-02, 3.90625000e-03, 9.76562500e-04, 2.44140625e-04, 6.10351562e-05, 1.52587891e-05, 3.81469727e-06])

Izračunamo oceno odvodov za različne natančnosti zapisa (zaradi deljenja z 0 dobimo opozorilo):

C:\Users\janko\AppData\Local\Temp\ipykernel_16664\1408319698.py:2: RuntimeWarning: invalid value encountered in divide
  f1_ocena = (fun(x+h, dtype=dtype)-fun(x-h,dtype=dtype))/(2*dtype(h))

Izrišemo različne tipe v odvisnosti od velikosti koraka hh. Najprej uvozimo potrebne knjižnice:

Definirajmo sliko:

Prikažimo jo:

<Figure size 640x480 with 1 Axes>

Pri relativno velikem koraku hh prevladuje napaka metode, pri majhnem koraku pa zaokrožitvena napaka; optimalni korak lahko ocenimo glede na:

h=ε2 k3.h=\sqrt[3]{\frac{\varepsilon}{2\,k}}.

V konkretnem primeru velja:

k=−f′′′(x)6=−−e−x6=16 e(x=1)k=-\frac{f'''(x)}{6}=-\frac{-e^{-x}}{6}=\frac{1}{6\,e}\qquad(x=1)

Sledi:

h=3 ε e3.h=\sqrt[3]{3\,\varepsilon\,e}.

Izračunamo primeren korak za 16, 32 in 64-bitni zapis:

Loading...
Loading...
Loading...

Najbolje se izkaže 64-bitni zapis, vendar pa tudi pri tem korak manjši od cca 1e-5 ni priporočen!

Aproksimacija odvoda s kompleksnim korakom

Aproksimacija odvoda s kompleksnim korakom je uporabna takrat, ko imamo definirano katerokoli analitično funkcijo, vendar pa nimamo na voljo analitičnega izraza za prvi odvod, za podrobnosti glejte (vir). Ideja izhaja iz razvoja funkcije f(x)f(x) v Taylorjevo vrsto, vendar se izvede korak v smeri imaginarne osi i hi\,h (i=−1i=\sqrt{-1}):

f(x+i h)=f(x)+i h ddxf(x)−h22d2dx2f(x)+O(h3)f{\left(x + i\,h \right)} = f{\left(x \right)} + i\,h\,\frac{d}{d x} f{\left(x \right)} - \frac{h^{2}}{2} \frac{d^{2}}{d x^{2}} f{\left(x \right)} + O\left(h^{3}\right)

Če sedaj predpostavimo, da funkcija f(x)f(x) realne vrednosti slika na realno os in da sta xx in hh realni vrednosti, potem lahko izpeljemo:

Im(f(x+i h))=h ddxf(x)+O(h3)\mathbf{Im} \left( f{\left(x + i\,h \right)}\right)= h\,\frac{d}{d x} f{\left(x \right)}+ O\left(h^{3}\right)
Re(f(x+i h))=f(x)−h22d2dx2f(x)+O(h3)→Re(f(x+i h))=f(x)+O(h2)\mathbf{Re} \left( f{\left(x + i\,h \right)}\right) = f{\left(x \right)} - \frac{h^{2}}{2} \frac{d^{2}}{d x^{2}} f{\left(x \right)} + O\left(h^{3}\right)\rightarrow \mathbf{Re} \left( f{\left(x + i\,h \right)}\right) = f{\left(x \right)} + O\left(h^{2}\right)

Iz prve enačbe (zgoraj) potem izpeljemo izraz za prvi odvod:

f′(x)=Im(f(x+i h))h+O(h2)f'{\left(x \right)}=\frac{\mathbf{Im} \left( f{\left(x + i\,h \right)}\right)}{h}+ O\left(h^{2}\right)

Rezultat je na nek način zelo presenetljiv. Zgoraj smo z eno koračno shemo naprej uspeli pridobiti natančnost O(h1)O\left(h^{1}\right), tukaj pa O(h2)O\left(h^{2}\right)!

Pomembna prednost metode s kompleksnim korakom je, da nima težav z odštevanjem skoraj enakih števil (ang. cancellation error), ki pesti klasične diferenčne metode pri zelo majhnih korakih hh. Zato lahko izberemo izjemno majhen hh (npr. 10-200) in dobimo praktično točen rezultat (do strojne natančnosti).

Če pogledamo sedaj uporabo metoda na primeru od zgoraj exp⁡(−x)\exp(-x), spomnimo se najprej točnega rezultata pri vrednosti x=1x=1:

Loading...

Pri klicu s korakom h=0.1h=0.1 dobimo točni dve (tri) števki (podobno kakor pri centralni diferenčni shemi), zmanjšanjem koraka na desetino pa bi število točnih števk približno podvojili.

Loading...

Ker nimamo težav z odštevanjem skoraj enakih števil, lahko korak izjemno zmanjšamo in dobimo točen rezulta (do strojne natančnosti):

Loading...
np.complex128(3.0000000004500006e-05j)
np.complex128(0.7780731972380541-1.884520868450896e-05j)

Poglejmo si še primer odvoda funkcije sin(x**2). Iz kode in slike spodaj vidimo bistveno hitrejšo konvergenco metode kompleksnega koraka. Zakaj metoda deluje tako dobro? Če vstavimo x+i hx+i\,h v x2x^2, dobimo: (x+i h)2=x2+2i x h−h2(x+i\,h)^2 = x^2 + 2i\,x\,h - h^2

Ker je hh zelo majhen, je h2h^2 zanemarljiv v realnem delu, imaginarni del 2 x h2\,x\,h pa se linearno prenese skozi sinus. Na tak način dobimo približek teoretičnega odvoda 2 x cos⁡(x2)2\,x\,\cos(x^2). Metoda vidi odvod v imaginarnem delu brez odštevanja, zato ne pride do napake zaokroževanja.

<Figure size 1000x600 with 1 Axes>

Dodatno


Vprašanja za vaje


Vprašanje 1: Podane so izmerjene vrednosti opravljene poti tekača s pri NN točkah v času. Numerično izračunajte potek hitrosti in pospeška (uporabite lahko poljubno metodo).

Opazujte in komentirajte kaj se dogaja, ko povečujete število točk NN.

Vprašanje 2: Simbolno je podana funkcija f(x)f(x) in njen odvod, f′(x)f'(x).

x(t)=e−t(sin⁡(ωt)−0.5cos⁡(2ωt))x(t) = e^{-t} \Big( \sin(\omega t) - 0.5 \cos(2 \omega t) \Big)
ω=2πfinf=4 Hz\omega = 2\pi f \quad \text{in} \quad f=4~\text{Hz}

Potek funkcije in njenega odvoda opazujemo pri 100 točkah časa t∈[0,1]t\in [0, 1].

Pripravi funkciji x_fun, dx_fun za numerično računanje. Izriši pripravljeni funkciji na intervalu t∈[0,1]t\in [0, 1] z uporabo paketa matplotlib.

Vprašanje 3: Razdelite opazovan časovni interval t∈[0,1]t \in [0,1] na 100 ekvidistantnih segmentov.

Pripravite vektor vrednosti x(t)x(t) in odvod x′(t)x'(t) izračunajte še numerično, z uporabo funkcije numpy.gradient(x, h).

Vprašanje 4: Uporabite funkcijo np.gradient še za izračun drugega odvoda x′′(t)x''(t). Opazujte vpliv parametra edge_order na natančnost odvodov na robovih intervala.

Vprašanje 5: Numeričnemu polju x(t)x(t) pri 500 ekvidistantnih točkah na intervalu t∈[0,1]t \in [0, 1] dodajte naključni šum n(t)n(t) amplitude A=0.1A=0.1 z uporabo funkcijo np.random.randn.

xsˇum(t)=x(t)+A⋅n(t)x_{\text{šum}}(t) = x(t) + A\cdot n(t)

Z uporabo funkcije np.gradient numerično določite vrednost prvega in drugega odvoda šumnega signala.


Uteži diferenčnih shem s paketom findiff

Primer 6: Izračunajte vrednosti drugega odvoda x′′(t)x''(t). Uporabite centralno diferenčno shemo drugega odvoda čez 5 točk (red napake 4).

Vprašanje 7: Na podlagi numeričnih podatkov x(t)x(t) pri delitvi intervala t∈[0,1]t \in [0,1] na 100 točk izračunajte vrednost prvega odvoda, x′(t)x'(t) po enačbi centralne diferenčne sheme preko treh točk. Ali lahko na ta način določite vrednost odvoda v točkah t=0t=0 in t=1t=1?

Vprašanje 8: Z uporabo diferenčne sheme naprej oz. nazaj izračunajte prvi odvod x′(t)x'(t) tudi v točkah na robu (t=0t=0, t=1t=1). Primerjajte dobljene vrednosti z rezultatom funkcije np.gradient, kjer nastavite argument edge_order=2.

naprej: ddxf(x)=12h(−3f(x)+4f(x+h)−f(x+2h))nazaj: ddxf(x)=12h(f(x−2h)−4f(x−h)+3f(x))\begin{align} \text{naprej: } & \frac{d}{dx}f(x) = \frac{1}{2h}\Big( -3f(x) + 4f(x+h) -f(x+2h)\Big)\\ \text{nazaj: } & \frac{d}{dx}f(x) = \frac{1}{2h}\Big(f(x-2h) - 4f(x-h) + 3f(x)\Big) \end{align}

(Namig: uporabite lahko funkcijo np.dot)


Izboljšanje približka odvoda z Richardsonovo ekstrapolacijo

Vprašanje 9: Izračunajte izboljšan približek odvoda funkcije:

x(t)=e−t(sin⁡(8πt)−0.5cos⁡(16πt))x(t) = e^{-t} \Big( \sin(8 \pi t) - 0.5 \cos(16 \pi t) \Big)

pri vrednosti ti=0.5t_i = 0.5, tako, da uporabite zgornjo enačbo za dve različni delitvi, h=0.05h=0.05 in h/2=0.025h/2 = 0.025. Uporabite centralno diferenčno shemo za 1. odvod za red napake n=2n=2.


Uporaba np.convolve

Vprašanje 10: Uporabite funkcijo np.convolve in izračunajte vrednosti drugega odvoda x(t)x(t) pri delitvi intervala t∈[0,1]t \in [0, 1] na 100 točk. Uporabite centralno diferenčno shemo drugega odvoda čez 5 točk, uteži izračunajte s pomočjo paketa findiff (funkcija findiff.coefficients).

Rezultat grafično prikažite (pazite na število robnih točk!).