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

Pri interpolaciji izhajamo iz tabele (različnih) vrednosti xi,yix_i, y_i:

x\mathbf{x}y\mathbf{y}
x0x_0y0y_0
x1x_1y1y_1
…\dots…\dots
xn−1x_{n-1}yn−1y_{n-1}

določiti pa želimo vmesne vrednosti. Če želimo določiti vrednosti zunaj območja xx v tabeli, govorimo o ekstrapolaciji.

V okviru interpolacije (angl. interpolation) točke povežemo tako, da predpostavimo neko funkcijo in dodamo pogoj, da funkcija mora potekati skozi podane točke.

Pri aproksimaciji (angl. approximation ali tudi curve fitting) pa predpostavimo funkcijo, ki se čimbolj (glede na izbrani kriterij) prilega podatkom.

Poglejmo si primer:

x\mathbf{x}y\mathbf{y}
1.00.54030231
2.5-0.80114362
4.0-0.65364362

Pri interpolaciji izhajamo iz tabele vrednosti. Da bomo pozneje lahko enostavno prikazali napako, smo zgornjo tabelo generirali s pomočjo izraza y=cos⁡(x)y = \cos(x)!

Pripravimo numerični zgled; najprej uvozimo pakete:

Nato pripravimo tabelo ter prikaz:

<Figure size 640x480 with 1 Axes>

Interpolacija s polinomom

Interpolacija s polinomom se zdi najbolj primerna, saj je enostavna!

Polinom stopnje n−1n-1:

y=a0 xn−1+a1 xn−2+⋯+an−2 x+an−1.y = a_0\,x^{n-1} +a_1\,x^{n-2} +\cdots + a_{n-2}\,x + a_{n-1}.

je definiran z nn konstantami aia_i. Da določimo nn konstant, potrebujemo nn (različnih) enačb. Za vsak par xi,yix_i, y_i lahko torej zapišemo:

yi=a0 xin−1+a1 xin−2+⋯+an−2 xi+an−1.y_i = a_{0}\,x_i^{n-1} +a_{1}\,x_i^{n-2} +\cdots + a_{n-2}\,x_i + a_{n-1}.

Ker imamo podanih nn parov, lahko določimo nn neznanih konstant aia_i, ki definirajo polinom stopnje n−1n-1. Sistem nn linearnih enačb lahko zapišemo:

[x0n−1x0n−2…x00x1n−1x1n−2…x10⋮xn−1n−1xn−1n−2…xn−10](a0a1⋮an−1)=(y0y1⋮yn−1)\begin{bmatrix} x_{0}^{n-1}&x_{0}^{n-2}&\dots&x_{0}^0\\ x_{1}^{n-1}&x_{1}^{n-2}&\dots&x_{1}^0\\ &&\vdots&&\\ x_{n-1}^{n-1}&x_{n-1}^{n-2}&\dots&x_{n-1}^0\\ \end{bmatrix} \begin{pmatrix} a_{0}\\ a_{1}\\ \vdots\\ a_{n-1} \end{pmatrix}= \begin{pmatrix} y_{0}\\ y_{1}\\ \vdots\\ y_{n-1} \end{pmatrix}

Sistem linearnih enačb zapišemo v obliki:

M a=b.\mathbf{M}\,\mathbf{a}=\mathbf{b}.

Definirajmo matriko koeficientov M\mathbf{M}:

array([[ 1. , 1. , 1. ], [ 6.25, 2.5 , 1. ], [16. , 4. , 1. ]])

Izračunamo koeficiente a0,a1,…a_{0}, a_{1},\dots:

array([ 0.33087687, -2.05236633, 2.26179176])

Pripravimo interpolacijski polinom kot Pythonovo funkcijo:

Izris interpolacijskega polinoma pri bolj gosti mreži točk:

<Figure size 640x480 with 1 Axes>

Slabosti zgornjega postopka so:

  • število numeričnih operacij raste sorazmerno z n3n^3,

  • problem je lahko slabo pogojen (z večanjem stopnje polinoma slaba pogojenost naglo narašča):

71.30227870311077

Navodilo: vrnite se par vrstic nazaj in spremenite število interpolacijskih točk nn na višjo vrednost (npr. 10).

Lagrangeva metoda

Lagrangeva metoda ne zahteva reševanja sistema enačb in je s stališča števila računskih operacij (narašča sorazmerno z n2n^2 (vir)) boljša od predhodno predstavljene polinomske interpolacije (število operacij narašča sorazmerno z n3n^3), kjer smo reševali sistem linearnih enačb. Rešitev pa je seveda popolnoma enaka!

Loading...

Lagrangev interpolacijski polinom stopnje n−1n-1 je definiran kot:

Pn−1(x)=∑i=0n−1yi li(x),P_{n-1}(x)=\sum_{i=0}^{n-1}y_i\,l_i(x),

kjer je lil_i Lagrangev polinom:

li(x)=∏j=0,j≠in−1x−xjxi−xj.l_i(x)=\prod_{j=0, j\ne i}^{n-1} \frac{x-x_j}{x_i-x_j}.

Poglejmo si interpolacijo za zgoraj prikazane xx in yy podatke.

Definirajmo najprej Lagrangeve polinome li(x)=∏j=0,j≠in−1x−xjxi−xjl_i(x)=\prod_{j=0, j\ne i}^{n-1} \frac{x-x_j}{x_i-x_j}:

<Figure size 640x480 with 1 Axes>

Opazimo, da ima ii-ti Lagrangev polinom v xix_i vrednost 1, v ostalih podanih točkah pa nič!

Če torej Lagrangev polinom za i=0i=0 pomnožimo z y0y_0, bomo pri x=x0x=x_0 dobili pravo vrednost, v ostalih interpolacijskih točkah pa nič; implementirajmo torej Lagrangev interpolacijski polinom:

Pn−1(x)=∑i=0n−1yi li(x),P_{n-1}(x)=\sum_{i=0}^{n-1}y_i\,l_i(x),

Pripravimo sliko:

Iz ipywidgets uvozimo interact, ki je močno orodje za avtomatsko generiranje (preprostega) uporabniškega vmesnika znotraj jupyter okolja. Tukaj bomo uporabili relativno preprosto interakcijo s sliko; za pregled vseh zmožnosti pa radovednega bralca naslavljamo na dokumentacijo.

Uvoz funkcije interact

Loading...

Iz slike vidimo, da ima Lagrangev polinom ii samo pri xix_i vrednost 1 v ostalih točkah ≠i\ne i pa ima vrednosti nič; ko Lagrangev polinom li(x)l_i(x) pomnožimo z yiy_i zadostimo ii-ti točki iz tabele. Posledično Lagrangeva interpolacija z vsoto Lagrangevih polinomov interpolira tabelo.

Polinomska interpolacija pri velikem številu točk je lahko slabo pogojena naloga in zato jo odsvetujemo.

Ocena napake

Če je f(x)f(x) funkcija, ki jo interpoliramo in je Pn−1(x)P_{n-1}(x) interpolacijski polinom stopnje n−1n-1, potem se lahko pokaže (glejte npr.: Burden, Faires, Burden: Numerical Analysis), da je napaka interpolacije s polinomom:

e=f(x)−Pn−1(x)=f(n)(ξ)n! (x−x0) (x−x1) ⋯ (x−xn−1),e=f(x)-P_{n-1}(x)=\frac{f^{(n)}(\xi)}{n!}\,(x-x_0)\,(x-x_1)\,\cdots\,(x-x_{n-1}),

kjer je f(n)f^{(n)} odvod funkcije, n−1n-1 stopnja interpolacijskega polinoma in ξ\xi vrednost na interpoliranem intervalu [x0,xn−1][x_0, x_{n-1}].

Zgled

Tukaj si bomo ogledali interpolacijo točk:

Točke prikažimo:

<Figure size 640x480 with 1 Axes>

Linearna interpolacija za vrednost pri x=1.57079633/2:

0.6830127

Kvadratna:

0.6997595236464176

Kubična

0.705889286844634

Zgled ocene napake

Pri interpolaciji ponavadi funkcije f(x)f(x) ne poznamo in napako ocenimo s pomočjo formule:

e=f(n)(ξ)n! (x−x0) (x−x1) ⋯ (x−xn−1).e=\frac{f^{(n)}(\xi)}{n!}\,(x-x_0)\,(x-x_1)\,\cdots\,(x-x_{n-1}).

Pri tem vrednost ξ\xi ni znana; ker je v primeru linearne interpolacije (n=2n=2) drugi odvod sinusne funkcije (f(n)f^{(n)}) med -1 in +1, velja:

∣e∣≤∣−12! (π/4−π/6) (π/4−π/3)∣=12 π12 π12=π2288=0,034|e|\le\left|\frac{-1}{2!}\,(\pi/4-\pi/6)\,(\pi/4-\pi/3)\right|=\frac{1}{2}\,\frac{\pi}{12}\,\frac{\pi}{12}=\frac{\pi^2}{288}=0,034

Poleg Lagrangeve metode bi si tukaj lahko pogledali še Newtonovo metodo interpolacije.

Interpolacija z uporabo scipy

Poglejmo si interpolacijo v okviru modula scipy.interpolate (dokumentacija).

Uporabili bomo funkcijo za interpoliranje tabele z zlepki, scipy.interpolate.interp1d (dokumentacija):

interp1d(x, y, kind='linear', axis=-1, copy=True, bounds_error=None, fill_value=nan, assume_sorted=False)

Podati moramo vsaj dva parametra: seznama interpolacijskih točk x in y. Privzeti parameter kind='linear' pomeni, da interpoliramo z odsekoma linearno funkcijo. interp1d vrne funkcijo f, ki jo kličemo (npr. y = f(x)) za izračun interpolirane vrednosti.

Parameter kind je lahko npr. tudi: 'zero', 'slinear', 'quadratic' in 'cubic'; takrat se uporabi interpolacijski zlepek (ang. spline) reda 0, 1, 2 oz. 3. Zlepke si bomo pogledali v naslednjem poglavju.

Opomba: interp1d je v SciPy označena kot legacy (starejši vmesnik, ki se ne razvija več, a še deluje). Za nove programe SciPy priporoča numpy.interp (odsekoma linearna interpolacija), scipy.interpolate.CubicSpline (dokumentacija) in scipy.interpolate.make_interp_spline (dokumentacija); vse vrnejo objekt, ki ga kličemo enako kot f spodaj.

Definirajmo tabelo podatkov:

8
<Figure size 640x480 with 1 Axes>

Kubični zlepki

Preden gremo v teorijo zlepkov, si poglejmo rezultat, ki ga dobimo s klicanjem funkcije interp1d s parametrom kind='cubic' (rezultat je kubični zlepek).

<Figure size 640x480 with 1 Axes>

Kubični zlepki so pogost način interpolacije.

Zahtevamo, da je: x0<x1<⋯<xnx_0<x_1< \cdots <x_n.

Od točke xix_i do xi+1x_{i+1} naj bo zlepek polinom:

fi,i+1(x)=ai,3 x3+ai,2 x2+ai,1 x+ai,0,f_{i,i+1}(x)= a_{i,3}\,x^3+a_{i,2}\,x^2+a_{i,1}\,x+a_{i,0},

pri čemer so neznane vrednosti konstant ai,ja_{i,j}.

Če imamo na primer n+1n+1 točk, potem je treba določiti nn polinomov.

Celotni zlepek čez n+1n+1 točk je definiran z:

f(x)={f0,1(x);x∈[x0,x1)f1,2(x);x∈[x1,x2)⋮fn−1,n(x);x∈[xn−1,xn]f(x) = \left\{ \begin{array}{rcl} f_{0,1}(x); && x\in[x_0, x_1)\\ f_{1,2}(x); && x\in[x_1, x_2)\\ &\vdots&\\ f_{n-1,n}(x); && x\in[x_{n-1}, x_n] \end{array} \right.

Vsak polinom fi,i+1f_{i,i+1} je definiran s 4 konstantami ai,ja_{i,j}; skupaj torej moramo izračunati 4n4n konstant ai,ja_{i,j}.

Kako določimo konstante ai,ja_{i,j}?

Za določitev 4n4n neznank potrebujemo 4n4n enačb. Poglejmo si, kako jih dobimo:

  • nn enačb dobimo iz interpolacijskega pogoja: yi=fi,i+1(xi),i=0,1,2,…,n−1y_i=f_{i,i+1}(x_i),\quad i=0,1,2,\dots,n-1

  • 1 enačbo iz zadnje točke: yn=fn−1,n(xn)y_n=f_{n-1,n}(x_n)

  • 3(n−1)3(n-1) enačb dobimo iz pogoja C2C^2 zveznosti:

lim⁡x→xi−f(x)=lim⁡x→xi+f(x),\lim_{x\rightarrow x_i^-}f(x)=\lim_{x\rightarrow x_i^+}f(x),
lim⁡x→xi−f′(x)=lim⁡x→xi+f′(x)\lim_{x\rightarrow x_i^-}f'(x)=\lim_{x\rightarrow x_i^+}f'(x)

in

lim⁡x→xi−f′′(x)=lim⁡x→xi+f′′(x).\lim_{x\rightarrow x_i^-}f''(x)=\lim_{x\rightarrow x_i^+}f''(x).

Skupaj imamo definiranih 4n−24n-2 enačbi, manjkata torej še dve!

Različni tipi zlepkov se ločijo po tem, kako ti dve enačbi določimo. V nadaljevanju si bomo pogledali naravne kubične zlepke.

Naravni kubični zlepki

Naravni kubični zlepki temeljijo na ideji Eulerjevega nosilca:

E I d4ydx4=q(x),E\,I\,\frac{\textrm{d}^4y}{\textrm{d}x^4}=q(x),

kjer je EE modul elastičnosti, II drugi moment preseka in q(x)q(x) zunanja porazdeljena sila. Ker zunanje porazdeljene sile ni (q(x)=0q(x)=0), velja:

E I d4ydx4=0.E\,I\,\frac{\textrm{d}^4y}{\textrm{d}x^4}=0.

Sledi, da lahko v vsaki točki tanek nosilec popišemo s polinomom tretje stopnje.

C2C^2 zveznost je zagotovljena v kolikor so vmesne podpore nosilca členki (moment zato nima nezvezne spremembe).

Manjkajoči 2 neznanki pri naravnih kubičnih zlepkih določimo iz pogoja, da je moment na koncih enak nič (členkasto vpetje):

f′′(x0)=0inf′′(xn)=0f''(x_{0})=0\qquad\textrm{in}\qquad f''(x_{n})=0

Izpeljava je natančneje prikazana v knjigi Kiusalaas J: Numerical Methods in Engineering with Python 3, 2013, stran 120 (glejte tudi J. Petrišič: Interpolacija, Fakulteta za strojništvo, 1999); podrobna izpeljava presega namen te knjige.

Tukaj si bomo pogledali samo končni rezultat, ki ga lahko izpeljemo ob zgornjih pogojih. V primeru ekvidistantne delitve h=xi+1−xih=x_{i+1}-x_i tako izpeljemo sistem enačb (i=1,…,n−1i=1,\dots,n-1):

ki−1+4ki+ki+1=6h2(yi−1−2yi+yi+1).k_{i-1} + 4 k_{i} + k_{i+1} = \frac{6}{h^2} \left(y_{i-1} -2 y_{i} +y_{i+1} \right).

kjer je neznanka kik_i drugi odvod odsekovne funkcije ki=fi,i+1′′(xi)k_i = f''_{i,i+1}(x_i).

Rešljiv sistem enačb dobimo, če dodamo še robna pogoja za naravne kubične zlepke:

k0=kn=0.k_0=k_n=0.

Ko določimo neznake kik_i, jih uporabimo v odsekoma definirani funkciji:

fi,i+1(x)=ki+16((x−xi)3h−(x−xi) h)−ki6((x−xi+1)3h−(x−xi+1) h)+yi+1 (x−xi)−yi (x−xi+1)h.f_{i,i+1}(x)=\frac{k_{i+1}}{6}\left(\frac{(x-x_{i})^3}{h}-(x-x_{i})\,h\right) -\frac{k_{i}}{6}\left(\frac{(x-x_{i+1})^3}{h}-(x-x_{i+1})\,h\right) +\frac{y_{i+1}\,(x-x_{i})-y_i\,(x-x_{i+1})}{h}.

Numerična implementacija

Najprej pripravimo funkcijo, katera za podane interpolacijske točke reši sistem linearnih enačb in vrne koeficiente kik_i:

Opomba: pri zgornjem linearnem problemu, lahko izračun zelo pohitrimo, če upoštevamo tridiagonalnost matrike koeficientov! (Glejte odgovor na stackoverflow.com).

Poglejmo si primer izračuna koeficientov:

Matrika koeficientov A lin. sistema:
 [[1. 0. 0. 0. 0.]
 [1. 4. 1. 0. 0.]
 [0. 1. 4. 1. 0.]
 [0. 0. 1. 4. 1.]
 [0. 0. 0. 0. 1.]]
Vektor konstant b lin. sistema:      [  0. -12.  12. -12.   0.]
Koeficienti k so: [ 0.         -4.28571429  5.14285714 -4.28571429  0.        ]

Nato potrebujemo še kubični polinom v določenem intervalu; implementirajmo izraz:

fi,i+1(x)=ki+16((x−xi)3h−(x−xi) h)−ki6((x−xi+1)3h−(x−xi+1) h)+yi+1 (x−xi)−yi (x−xi+1)hf_{i,i+1}(x)=\frac{k_{i+1}}{6}\left(\frac{(x-x_{i})^3}{h}-(x-x_{i})\,h\right) -\frac{k_{i}}{6}\left(\frac{(x-x_{i+1})^3}{h}-(x-x_{i+1})\,h\right) +\frac{y_{i+1}\,(x-x_{i})-y_i\,(x-x_{i+1})}{h}

Izračunamo interpolirane vrednosti:

<Figure size 640x480 with 1 Axes>

Dodatno

Nekaj komentarjev modula scipy.interpolate

SciPy ima implementiranih večje število različnih interpolacij (glejte dokumentacijo). S stališča uporabe se bomo tukaj dotaknili objektne implementacije scipy.interpolate.InterpolatedUnivariateSpline (dokumentacija) (starejši pristop temelji na proceduralnem programiranju, glejte dokumentacijo scipy.interpolate.splrep):

InterpolatedUnivariateSpline(x, y, w=None, bbox=[None, None], k=3, ext=0, check_finite=False)

Pri inicializaciji objekta InterpolatedUnivariateSpline moramo posredovati interpolacijske točke x in y. Argument k s privzeto vrednostjo k=3 definira red interpolacijskega zlepka (1<=k<=5). Pomemben opcijski parameter je tudi w, ki definira uteži posameznim interpolacijskim točkam (uporabimo ga, če želimo določenim področjem dati večji poudarek).

Opomba: InterpolatedUnivariateSpline (in sorodni UnivariateSpline) sta od SciPy 1.15 označena kot legacy; sodobnejša ekvivalenta sta make_interp_spline (interpolacija) in make_smoothing_spline oz. make_splrep (aproksimacija, glejte naslednje predavanje). Objektni vmesnik spodaj še vedno deluje in je zaradi preglednosti primeren za učenje.

<Figure size 640x480 with 1 Axes>

Ker gre za B-zlepke, je rezultat drugačen kot tisti, ki smo ga izpeljali z naravnimi kubičnimi zlepki. V nasprotju z naravnimi kubičnimi zlepki, ki imajo vozle (angl. knots) v interpolacijskih točkah, se vozli B-zlepkov prilagodijo podatkom. V konkretnem primeru so vozli v točkah:

array([1., 3., 5.])

Odvajanje, integriranje ... zlepkov

Zlepke lahko odvajamo in integriramo, saj so polinomi. Objekt InterpolatedUnivariateSpline je tako že pripravljen za odvajanje, integriranje, iskanje korenov (ničel), vozlov ... (glejte dokumentacijo).

Za prvi odvod zlepka v objektu spl na primer uporabimo metodo spl.derivative(1), ki vrne nov objekt zlepka (njen red je sedaj za 1 nižji):

<Figure size 640x480 with 1 Axes>

Vprašanja za vaje


Lagrangeva metoda

Vprašanje 1: Pripravite funkcijo lagrange_interpolacija, ki kot argumente sprejme numerični polji x in y koordinat znanih točk ter numerično polje x_int koordinat, pri katerih nas zanimajo interpolirane vrednosti.

Za vsako izmed znanih točk xix_i naj s pomočjo funkcije lagrange_i izračuna vrednosti polinoma lil_i v točkah x_int ter na koncu izračuna in vrne vrednosti y_int =Pn(= P_n( x_int )), tako, da izračuna vsoto:

Pn(xint)=∑i=0nyili(xint)P_n(x_{\text{int}}) = \sum_{i=0}^{n}y_il_i(x_{\text{int}})

Vprašanje 2: Pripravite nabor petih točk x, enakomerno razporejenih na intervalu x∈[0,2π]x\in[0,2 \pi], ter pripadajočih vrednosti y, definiranih kot:

y=sin⁡(x)y = \sin(x)

Za 100 točk x_int na istem intervalu izračunajte interpolacijsko krivuljo (uporabite ustrezno funkcijo iz scipy).

Na istem grafu prikažite točke (x,y), interpolacijsko krivuljo ter prave vrednosti yy pri točkah x_int.

Kako bi izračunali napako pri interpolaciji v odvisnosti od vrednosti x_int? (Prave vrednosti yy poznamo!)


Kubični zlepki

Primerjava InterpolatedUnivariateSpline in interp1d:

Vprašanje 3: Z uporabo poljubne scipy funkcije pripravite grafični prikaz interpolacije pripravljenih točk (x, y) z linearnimi, kvadratnimi in kubičnimi zlepki.

Vprašanje 4: Za točke x, y primerjajte interpolacijsko krivuljo kubičnih zlepkov scipy.interpolate.InterpolatedUnivariateSpline z rezultatom Lagrangeve interpolacije.

Vprašanje 5: Za krivuljo kubičnih interpolacijskih zlepkov, dobljenih pri prejšnji nalogi z uporabo scipy funkcije poiščite ničle.

Rezultate grafično prikažite.

Vprašanje 6: Grafično prikažite krivuljo zlepkov iz prejšnje naloge in njene odvode.

Vprašanje 7: Podane točke (t, a) predstavljajo izmerjen potek pospeškov avtomobila v smeri vožnje. Z uporabo scipy.interpolate.InterpolatedUnivariateSpline določite interpolacijsko krivuljo z zlepki 2. reda pri časih t_int.

Uporabite obstoječo funkcijo in določite ter grafično prikažite tudi krivulji hitrosti in opravljene poti (namig: help(InterpolatedUnivariateSpline)).