ODE (Ordinära DifferentialEkvationer)
Syftet med denna laboration är att Du skall
bekanta Dig med några enkla metoder för att lösa
ODE-problem. Du kommer också att lära Dig att skriva
om ett ODE-problem som ett system av första ordningens ekvationer.
Matlabs ode45
-rutin
används för att beräkna en approximativ
lösningen
till problemet.
Först en kort
repetition från envariabelkursen.
I denna första del kommer Du att beräkna approximativa
lösningar till ett begynnelsevärdesproblem:
y' = f(t, y), y(t0) = y0
Problemet kan
lösas för hand så att Du enkelt skall kunna
beräkna skillnaden mellan approximation och exakt lösning.
Detta gör att Du kan jämföra effektiviteten hos
några olika metoder. Metoderna, som Du kommer att testa, är:
I samtliga fall itererar vi när k = 0, 1, 2, ...,
n-1 och vi använder fixt tidssteg h. Så tk = t0
+ k h.
Begynnelsevärde y0, starttid t0 samt
tidssteg h ges nedan. Slut-tiden ges indirekt via h och n. Vi sa under
föreläsningen att Eulers metod är alldeles för
ineffektiv för att användas i praktiken. Det gäller nu
även de andra två metoderna, men de är bättre
än Eulers metod, eftersom felet blir mindre (för samma h).
I denna lab står "felet" för det globala felet dvs.
skillnaden mellan exakt- och approximativt värde. Det finns teori
(som vi ej tagit upp) som säger att man kan
förvänta sig att felet i Eulers metod är av
storleksordningen h, en första ordningens metod. Metod 2 och 3
är andra ordningens metoder och man förväntar sig att
felet är av storleksordningen h2. Jag använder
ordet "förväntar" eftersom de feluppskattningar som finns
är mycket svaga. I denna lab kommer Du att se om
förväntningarna infrias. Den metod, ode45, som Du kommer att
använda i nästa lab är en kombination av två
metoder, en av fjärde- och en av femte ordningen.
Att Heuns metod ger mindre fel, är inte så
konstigt. Metoden kräver ju två funktionsberäkningar
(beräkningar av funktionen f) i varje iteration. Mer information
borde ge en bättre metod. Man
programmerar inte Heuns metod som den är skriven ovan. Det finns
ju ingen anledning att räkna ut f(tk,
yk) två gånger. Heuns metod är en sk enstegsmetod, den utnyttjar bara
information som kan räknas fram i det aktuella steget.
Adamsmetoden är en flerstegsmetod, den utnyttjar
information från föregående steg (som man ser till att
spara). Metoden kräver, liksom Eulers metod, bara en funktionsberäkning i varje
steg, men Adamsmetoden ger ett mindre fel. I tillämpningar har man
normalt system av ODE, vilket gör att beräkningen av f tar
mest datortid. Detta gör att Adamsmetoden blir mycket snabbare
än Eulers metod. Man kan skapa Adamsmetoder (liksom andra metoder)
av ännu högre ordning, och dessa metoder blir då
ännu snabbare.
Ett litet problem med flerstegsmetoder är att de
kräver speciell behandling i början av iterationen. När
k = 0 har vi ju inget föregående steg (dvs. f(t-1,
y-1) saknas). För att lösa det i denna lab, kan Du
stega Adamsmetoden för k = 1, 2, ... (dvs. börja med k = 1
och inte k = 0) och utnyttja (t1,
y1) från Heuns metod ((t0,
y0) känner Du ju).
![]() |
Använd de tre metoderna på problemet y' = -y + t /
10, t0 = 0, y0 = 1, n = 51, h = 0.1. Beräkna
den exakta lösningen och plotta absolutbeloppet av felet, | y(tk)
- yk |, k = 1, ..., n med kommandot semilogy. Felen (för de
tre metoderna) skall plottas i samma
diagram, så att man enkelt kan jämföra. Dra slutsatser!
Verkar resonemanget kring metodens ordning och felet i lösningen
hålla? |
Nu till ett system av
ekvationer.
Ett exempel på hur man använder ode45 hittar Du i
föreläsningsanteckningarna.
Bakgrund: På en plan yta har vi, på olika
ställen, "klistrat
fast" en uppsättning laddade partiklar. Vi har dessutom en fri
laddad
partikel som kan röra sig på planet, och uppgiften går
ut
på att bestämma den fria partikelns väg (bana). Alla
partiklarna
har lika stor laddning (och samma tecken).
Lår r(t) vara den fria partikelns position vid tiden t. r(t) är en vektor med två komponenter (en x- och en y-komponent). Vi känner begynnelsepositionen r(0) samt initialhastigheten, r'(0).
Låt p1, ..., pn vara positionerna för de n fixa partiklarna. Under lämpliga villkor (ingen friktion osv) kan rörelse-ekvationen för den fria partikeln skrivas som (jag skriver inte längre ut tiden t):
r'' = c [ (r - p1) / | r - p1 |3 + (r - p2) / | r - p2 |3 + ... + (r - pn) / | r - pn |3 ]
| | betecknar det vanliga avståndet. c är en konstant som
har
att göra med partikelns massa och kraften mellan partiklarna,
använd
c = 1e-5
. Några fysikaliska
detaljer.
Observera att detta är ett andra ordningens system, r
är inte en skalär storhet.
![]() |
Skriv om ovanstående problem som ett system av första ordningens ekvationer på formen y' = f(t, y), y(0) = y(0). Din omskrivning skall klara ett godtyckligt värde på n. |
Vi vill nu implementera ovanstående omskriving i form av en
Matlabfunktion,
låt oss kalla den f
. Funktionen kommer att anropas
(av
ode45
) med aktuell tidpunkt, tk, och
approximation,
y(k), och funktionen skall returnera vektorn av
derivator,
så en lämplig början är något i stil med (tk
svarar alltså mot tkoch yk mot y(k)):
function yprim = f(tk, yk)
yprim = [...
tk och yk är ju vanliga
variabelnamn, så man kan givetvis skriva sin funktion på
följande sätt i stället:
function yprim = f(t, y)
yprim = [...
Matlabfunktionen, f
, svarar direkt mot f
i uttrycket
y' = f(t, y).
Ode-lösaren, ode45,
anropar Din funktion för varje tidssteg. Lösaren
tillhandahåller (via parametrarna,
tk, yk
eller t,
y
) aktuell tid och approximation av lösningen vid denna
tidpunkt. Din funktion får använda dessa värden
för att beräkna och returnera derivatorna (yprim). Tiden, t, ingår
inte explicit
i
differentialekvationen (däremot beror ju y av t), men
Matlab
kräver ändå att man har med tiden eftersom ode45
är en allmän rutin där formen på funktionen
är
bestämd av den som som skrev ode45
. Mer
om detta.
Använd kolonnvektorer överallt! Det är (som
vanligt)
ett bekymmer med att skicka extra variabler till funktionen
(hjälp med detta). Du kan välja
på
att anropa ode45
med extra variabler (help ode45
),
utnyttja global
eller att definiera samma variabel
på
flera ställen.
Tips lagra p1, ..., pn som
kolonner i
matrisen P. Du kan lätt bestämma n, givet P (t.ex. genom n
= size(P, 2);
).
ode45
anropas på följande sätt
(förutsatt
att funktionen heter f
och är lagrad på filen
f.m
).
[t, y] = ode45(@f, [t0:delta_t:t_slut], y0);
t0
, delta_t
, t_slut
samt
y0
(kolonnvektorn av begynnelsevärden) måste ha
tilldelats värden innan anropet. ode45
returnerar en
vektor,
t
, av tidpunkter, där vi efterfrågat
lösningen, samt en matris y
. Varje rad i matrisen
svarar
mot en tidpunkt och kolonnerna svarar mot de olika
lösningskomponenterna
i systemet.
t0
är begynnelsetiden (noll i detta exempel) och t_slut
är den sista tidpunkten. Eftersom vi senare skall animera
rörelseförloppet vill ha utmatning vid bestämda
tidpunkter
(vi vill inte ha olika tät utmatning, metoden är ju adaptiv,
eftersom
det kommer att ge felaktiga fartvariationer). Vi styr detta med
variabeln
delta_t
Observera att detta inte är det
tidssteg
som metoden använder, utan endast steget i utmatningen.
![]() |
Gör ovanstående och testa på fallen nedan.
Plotta partikelns bana, inte hastigheten (välj rätt
kolonner från y -matrisen med andra ord, y(:,
j) är kolonn j . help colon ).
Använd även mitt lilla animeringsprogram, anim , för att animera
rörelseförloppet (hämta denna m-fil och skriv sedan help
anim i Matlab). Redovisa koden och rita partikelns färd i
x-y-planet. Animeringen går ju inte att lämna in. |
Detta är ett lite roligare fall, en potentialgrop. Den fria partikeln är inringad av partiklar som ligger som staketstolpar i ett osynligt stängsel. Stängslet utgörs av den växelverkan vi har mellan den fria partikeln och de fixa partiklarna. Den fria partikeln kan komma ur gropen om ger ger den tillräckligt stor begynnelsehastighet. Generera 16 fixa partiklar som ligger på jämna mellanrum på enhetscirkeln, t.ex. genom:
e = exp(sqrt(-1) * [0:pi/8:15*pi/8]);
P = [real(e); imag(e)]; % blir en 2 x 16-matris
Låt r(0) = (0.7, 0), r'(0)
= (0, 0.004)
Testa gärna några andra begynnelsehastigheter, t.ex. (0, 0.0122) respektive (0, 0.009), eller några andra initialplaceringar.
Lämpliga tidsvärden är t0 = 0
, delta_t
= 10
, t_slut = 2000.
Om Du har en snabb dator
får
Du minska delta_t
så att partikeln inte rör
sig så
snabbt vid animationen.
Med mera Matlabprogrammering skulle man givetvis kunna göra ett litet GUI så att man kunde klicka ut positionerna.