ΣΥΝΗΘΕΙΣ ΔΙΑΦΟΡΙΚΕΣ ΕΞΙΣΩΣΕΙΣ ΣΤΗ MATLAB 1. Γενικά περί συνήθων διαφορικών εξισώσεων Μια συνήθης διαφορική εξίσωση (Σ.Δ.Ε.) 1 ης τάξης έχει τη μορφή dy dt f ( t, y( t)) όπου η συνάρτηση f(t, y) είναι γνωστή, και η άγνωστη συνάρτηση που θέλουμε να προσδιορίσουμε είναι η y(t). Η πιο πάνω εξίσωση καλείται διαφορική γιατί μας δίνει πληροφορίες για την παράγωγο μιας συνάρτησης. Καλείται συνήθης γιατί η παράγωγος είναι συνήθης (αντί για μερική), και τέλος, είναι 1 ης τάξης γιατί οι πληροφορίες αφορούν μόνο την 1 η παράγωγο της άγνωστης συνάρτησης. Αν και μπορούμε να μιλήσουμε για Σ.Δ.Ε. 2 ης, 3 ης, 4 ης, τάξης, θα περιοριστούμε μόνο σε αυτές που είναι 1 ης τάξης γιατί οι υπόλοιπες μπορούν να εκφραστούν σαν ένα σύστημα Σ.Δ.Ε. 1 ης τάξης και άρα είναι αρκετό να ξέρουμε πώς να λύνουμε συστήματα Σ.Δ.Ε. 1 ης τάξης στη MATLAB. Σημειώνουμε ότι στη ειδική περίπτωση που η συνάρτηση f εξαρτάται μόνο από το t, τότε έχουμε 1. dy f ( t) y f ( t) dt C dt, όπου C μια αυθαίρετη σταθερά, και έτσι παίρνουμε τη λύση αναλυτικά. (Για την ακρίβεια, παίρνουμε άπειρες λύσεις, μια για κάθε σταθερά C.) Αν εκτός από την διαφορική εξίσωση μας δοθεί και μια αρχική συνθήκη, π.χ. y( t0) y0, με τα t, y γνωστά, τότε η λύση της Σ.Δ.Ε. είναι μοναδική, με την προϋπόθεση ότι η συνάρτηση 0 0 f(t, y) ικανοποιεί κάποιες συνθήκες ομαλότητας. Σε αυτή την περίπτωση έχουμε ένα πρόβλημα αρχικών τιμών (Π.Α.Τ.): y( t) f ( t, y( t)). y( t0) y0 Θα ασχοληθούμε με μεθόδους (αριθμητικής) επίλυσης Π.Α.Τ. χρησιμοποιώντας την MATLAB.
Παράδειγμα. Η μέθοδος του Euler Η πιο παλιά μέθοδος αριθμητικής επίλυσης του Π.Α.Τ. y( t) f ( t, y( t)), y( t0) y0 είναι η λεγόμενη Μέθοδος του Euler, με την οποία βρίσκουμε (διακριτές) προσεγγίσεις y y( t ), i 0,1,2,... για κάποια t, i 0,1, 2,... που μας ενδιαφέρουν. Αν επιλέξουμε κάποιο i i i h > 0 (το λεγόμενο βήμα) και ορίσουμε t 1 t h, i 0,1,2,..., N για κάποιο Ν, τότε μια και τα i i f, t0 και y0 είναι γνωστά, μπορούμε να βρούμε τα y y( t ), i 0,1,2,..., T μέσω της λεγόμενης επανάληψης του Euler: y 1 y hf ( t, y ), i 0,1,2,..., N i i i i Το πιο κάτω m-file υλοποιεί την πιο πάνω διαδικασία, παίρνοντας σαν δεδομένα εισόδου την συνάρτηση f, τις αρχικές τιμές y0, t0, το Τ έτσι ώστε και το βήμα h, και δίνει σαν i i t [ t, T ] δεδομένα εξόδου τα διανύσματα t [ t0, t1,..., tn], y [ y0, y1,..., y ] έτσι ώστε y y( t ), i 0,1,2,..., N. i i function [y,t] = euler(fun,y0,t0,t,h) % [y,t] = euler(fun,y0,t0,t,h) - % This function computes the solution to the IVP % y'(t) = fun(y,t), y(t0)= y0, % for a given function "fun(t,y)" using Euler's method. % The function can be defined via an m-file fun.m, % or as an anonymous function, called fun. % y0 is the initial value, T is the maximum value for t, h % is the stepsize and t0 is initial value for t. % The output is a vector containing the approximate % solution y_euler (and if requested, the vector with the t_i s). % y(1) = y0; t(1) = t0; for i=1:ceil((t-t0)/h) y(i+1) = y(i) + h*feval(fun,t(i),y(i)); t(i+1) = t(i) + h; end; t=t'; y=y'; % End of m-file euler.m 0 N
Παράδειγμα: Ας χρησιμοποιήσουμε το πιο πάνω m-file για το εξής Π.Α.Τ.: y( t) t y, y(1) 4 όπου το t ανήκει στο διάστημα [1, 2], και ας επιλέξουμε αρχικά h = 0.1. >> f = @(t,y) t*sqrt(y); >> [y,t]=euler(f,4,1,2,0.1) y = 4.0000 4.2000 4.4254 4.6779 4.9590 5.2708 5.6152 5.9943 6.4105 6.8663 7.3642 t = 1.0000 1.1000 1.2000 1.3000 1.4000 1.5000 1.6000 1.7000 1.8000 1.9000 2.0000 Παίρνουμε τη γραφική παράσταση της λύσης με τις εξής εντολές:
>> plot(t,y,'o-') >> xlabel('t') >> ylabel('y') >> title('solution to y''(t)=t sqrt(y), t in [1, 2], y(1)=4, via Eulers Method with h=0.1') Solution to y'(t)=t sqrt(y), t in [1, 2], y(1)=4, via Eulers Method with h=0.1 7.5 7 6.5 6 y 5.5 5 4.5 4 1 1.2 1.4 1.6 1.8 2 2.2 2.4 t 1 2 Η ακριβής λύση του πιο πάνω Π.Α.Τ. είναι y ( ) 7 2 ex t t, και το πιο κάτω γράφημα 16 μας δείχνει ότι η λύση που πήραμε με την μέθοδο του Euler δεν είναι παρά μια προσέγγιση. >> yex=@(t) (1/16)*(t.^2+7).^2; >> plot(t,y,'o-',t,yex(t)) >> xlabel('t') >> ylabel('y') >> legend('y_{euler}(t)','y_{exact}(t)')
8 7.5 y Euler (t) y exact (t) 7 6.5 y 6 5.5 5 4.5 4 1 1.2 1.4 1.6 1.8 2 2.2 2.4 t Αν χρησιμοποιήσουμε πιο μικρό βήμα h, τότε η προσέγγιση θα είναι καλύτερη. Αυτό φαίνεται πιο κάτω, όπου χρησιμοποιούμε h = 0.05. >> [y,t]=euler(f,4,1,2,0.05); >> plot(t,y,'o-',t,yex(t)) >> xlabel('t') >> ylabel('y') >> legend('y_{euler}(t)','y_{exact}(t)') 8 7.5 y Euler (t) y exact (t) 7 6.5 y 6 5.5 5 4.5 4 1 1.2 1.4 1.6 1.8 2 2.2 2.4 t Παράδειγμα: Σύγκλιση της μεθόδου του Euler Ας χρησιμοποιήσουμε τη μέθοδο του Euler για το εξής Π.Α.Τ.:
y( x) x y, y(0) 0 for x in [0,1], του οποίου η ακριβής λύση είναι y(x) = e x + x 1. Με x0 = 0, y0 = 0, υπολογίζουμε τις προσεγγίσεις yn, n = 1, 2, 3, χρησιμοποιώντας h = 0.2 και το m-file euler.m. >> f = @(x,y) x - y; >> [y,x] = euler(f,0,0,1,0.2) Y = 0.3277 x = 0 0 0.0400 0.1120 0.2096 0 0.2000 0.4000 0.6000 0.8000 1.0000 Επαναλαμβάνουμε τα πιο πάνω για διάφορα h και δείχνουμε τα αποτελέσματα στους πιο κάτω πίνακες, όπου η τελευταία στήλη αντιστοιχεί στο σφάλμα μεταξύ της ακριβούς και της προσεγγιστικής λύσης σε κάθε σημείο xn, n = 0, 1, 2, h = 0.2: x n Προσέγγιση y n Ακριβής y(x n) Σφάλμα y n y(x n) 0 0 0 0 0.2 0 0.0187 0.0187 0.4 0.0400 0.0703 0.0303 0.6 0.1120 0.1488 0.0368 0.8 0.2096 0.2493 0.0397 1 0.3277 0.3679 0.0402
Το μέγιστο σφάλμα στο [0, 1] είναι 0.0402. h = 0.1: x n Προσέγγιση y n Ακριβής y(x n) Σφάλμα y n y(x n) 0 0 0 0 0.1000 0 0.0048 0.0048 0.2000 0.0100 0.0187 0.0087 0.3000 0.0290 0.0408 0.0118 0.4000 0.0561 0.0703 0.0142 0.5000 0.0905 0.1065 0.0160 0.6000 0.1314 0.1488 0.0174 0.7000 0.1783 0.1966 0.0183 0.8000 0.2305 0.2493 0.0189 0.9000 0.2874 0.3066 0.0191 1.0000 0.3487 0.3679 0.0192 Το μέγιστο σφάλμα στο [0, 1] είναι 0.0192. h = 0.05: x n Προσέγγιση y n Ακριβής y(x n) Σφάλμα y n y(x n) 0 0 0 0 0.0500 0 0.0012 0.0012 0.1000 0.0025 0.0048 0.0023 0.1500 0.0074 0.0107 0.0033 0.2000 0.0145 0.0187 0.0042 0.2500 0.0238 0.0288 0.0050 0.3000 0.0351 0.0408 0.0057 0.3500 0.0483 0.0547 0.0064 0.4000 0.0634 0.0703 0.0069
0.4500 0.0802 0.0876 0.0074 0.5000 0.0987 0.1065 0.0078 0.5500 0.1188 0.1269 0.0081 0.6000 0.1404 0.1488 0.0085 0.6500 0.1633 0.1720 0.0087 0.7000 0.1877 0.1966 0.0089 0.7500 0.2133 0.2224 0.0091 0.8000 0.2401 0.2493 0.0092 0.8500 0.2681 0.2774 0.0093 0.9000 0.2972 0.3066 0.0094 0.9500 0.3274 0.3367 0.0094 1.0000 0.3585 0.3679 0.0094 Το μέγιστο σφάλμα στο [0, 1] είναι 0.0094. Από ότι φαίνεται, όταν το h 0, έχουμε max Error 0. Για να απαντήσουμε στην 0x1 ερώτηση πόσο γρήγορα, θεωρούμε τα εξής: Αν ισχύει E(h) := max 0x1 Error ~ h p, για κάποιο p > 0, τότε lim Eh ( ) 0 και λέμε ότι έχουμε αλγεβρική σύγκλιση τάξης p. (Δηλ. p = 1 h0 δίνει γραμμική σύγκλιση, p = 2 τετραγωνική σύγκλιση, κλπ.) Στόχος μας είναι να βρούμε το p για την Μέθοδο του Euler, χρησιμοποιώντας τους πιο πάνω υπολογισμούς. p p Παρατηρούμε ότι E( h) ~ h E( h) Ch για κάποια σταθερά C (όταν το h είναι επαρκώς μικρό). Παίρνοντας τον λογάριθμο έχουμε p ln( E( h)) ln( Ch ) ln( E( h)) ln( C) pln( h). Αν θέσουμε Y = ln( Eh ( )), X = ln( h ) και B = ln( C ), τότε έχουμε τη γραμμική σχέση Y = px + B, άρα η γραφική παράσταση του X έναντι του Y, θα είναι ευθεία με κλίση p. Στη MATLAB αυτό μπορεί να επιτευχθεί με την εντολή loglog ως εξής: Πρώτα ορίζουμε δύο διανύσματα, το h και το E(h), χρησιμοποιώντας τα προηγούμενα αποτελέσματα (όπως επίσης και κάποια επιπρόσθετα, των οποίων οι λεπτομέρειες παραλείπονται):
>> h=[0.2,0.1,0.05,0.01,0.005] h = 0.2000 0.1000 0.0500 0.0100 0.0050 >> E = [0.0402,0.0192,0.0094,0.0018,9.2162e-004] E = 0.0402 0.0192 0.0094 0.0018 0.0009 >> loglog(h,e,'o-') >> xlabel('h') >> ylabel(' Error ') >> title('convergence of Eulers Method') Η κλίση της ευθείας είναι σχεδόν 1, όπως φαίνεται και πιο κάτω: >> (log(e(end))-log(e(end-1)))/(log(h(end))-log(h(end-1))) ans = 1.0030 Αφού η κλίση (δηλ. το p) είναι 1, έχουμε max 0x1 Error Ch 1 που δίνει ότι η Μέθοδος του Euler συγκλίνει γραμμικά (δηλ. αλγεβρικά με ρυθμό 1) όταν το h τείνει στο 0.
2. Η εντολή ode45 Η MATLAB διαθέτει αρκετές συναρτήσεις/εντολές βιβλιοθήκης για την επίλυση Π.Α.Τ., όπως οι ode23, ode45, ode113, ode15s, ode23s, ode23t, ode23tb κ.α. (Γράψτε, π.χ., doc ode23, κλπ. για περισσότερες πληροφορίες.) Εμείς θα ασχοληθούμε μόνο με την ode45, η οποία λύνει το Π.Α.Τ. και έχει την εξής δομή: y( t) f ( t, y( t)) y( t0) y0 [t_out,y_out] = ode45(odefun, t_span, y0) Τα δεδομένα εισόδου και εξόδου έχουν ως εξής: οdefun: η συνάρτηση t_span: το διάνυσμα f ( t, y) [ t0, T] [0, 1] y0: η αρχική τιμή y0( y( t0)) t_out: το διάνυσμα με τα σημεία t 0, t 1, t 2... (σαν m-file ή σαν ανώνυμη συνάρτηση) όπου ανήκει το t αυτό πρέπει να δοθεί μέσα σε αγκύλες, π.χ. y_out: το διάνυσμα με τις προσεγγιστικές τιμές y0, y1, y 2... της λύσης Όπως βλέπετε, τα δεδομένα εισόδου και εξόδου είναι παρόμοια με αυτά που είχαμε στο m- file που γράψαμε για την μέθοδο του Euler. Η διαφορά έγκειται στο ότι για το m-file που γράψαμε, δίναμε και το βήμα h, ενώ στην ode45 δεν το δίνουμε. Η MATLAB διαλέγει από μόνη της το βήμα με τέτοιο τρόπο ώστε η λύση που παίρνουμε να έχει (απόλυτη) ακρίβεια 10 6. Αυτό σημαίνει ότι το μέγεθος των διανυσμάτων t και y δεν εξαρτάται από εμάς αλλά από την MATLAB, αλλά επίσης και ότι το διάνυσμα t μπορεί να μην είναι ομοιόμορφα κατανεμημένο. Μπορούμε, αν θέλουμε, να αυξομειώσουμε την ακρίβεια στην εντολή ode45 με το να δώσουμε περισσότερα δεδομένα εισόδου για να δείτε πως γράψτε help ode45 στη MATLAB. Παράδειγμα: Θα βρούμε μια προσέγγιση για τη λύση του Π.Α.Τ. y( t) y(2 y), 0 t 1 y(0) 3
χρησιμοποιώντας την εντολή ode45: >> f = @(t,y) y.*(2-y); >> [t,y]=ode45(f,[0,1],3); Βάλαμε ; στο τέλος της εντολής για να μην δούμε τις τιμές που παίρνουμε μια και τα διανύσματα μπορεί να είναι αρκετά μεγάλα: >> length(y) ans = 41 Παίρνουμε τη γραφική παράσταση της λύσης (με κόκκινο) ως εξής: >> plot(t,y,'-rx') >> xlabel('t') >> ylabel('y') >> title('solution to y''(t)=y(2-y), t in [0, 1], y(0)=3') 6 Η ακριβής λύση του πιο πάνω Π.Α.Τ. είναι yex() t, και πιο κάτω δείχνουμε τη 2t 3 γραφική παράσταση του σφάλματος y( t) y ( t) : >> yex=@(t) 6./(3-exp(-2*t)); >> plot(t,abs(y-yex(t)),'*r') >> plot(t,abs(y-yex(t)),'*-r') >> xlabel('t') >> ylabel(' y_{exact}-y ') >> title('absolute Error') ex e
Πράγματι, έχουμε ακρίβεια της τάξης του 10 6. 3. Συστήματα Σ.Δ.Ε. Εκτός από Π.Α.Τ., η εντολή ode45 μπορεί να χρησιμοποιηθεί και για συστήματα Σ.Δ.Ε., όπως για παράδειγμα το πιο κάτω 3 3 σύστημα αρχικών τιμών (Σ.Α.Τ.): x 1( t) f1( t, x1, x2, x3) x2 ( t) f2( t, x1, x2, x3) x ( t) f ( t, x, x, x ) 3 3 1 2 3 x1 ( t0) a1, x2( t0) a2, x3( t0) a3 όπου οι συναρτήσεις fi ( t, x1, x2, x3), i 1,2,3, το σημείο t0 και οι τιμές ai, i = 1, 2, 3 είναι δεδομένα, και θέλουμε να προσδιορίσουμε τις συναρτήσεις x 1 ( t), x 2 ( t), x 3 ( t ). Αν γράψουμε το πιο πάνω σύστημα σε διανυσματική μορφή, τότε έχουμε d x ( t ) [ F ] x ( t ) dt x( t0) [ a1, a2, a3] που μοιάζει με το Π.Α.Τ. που μελετήσαμε προηγουμένως. Ας δούμε ένα συγκεκριμένο παράδειγμα:
8 x1 ( t) x1 ( t) x2( t) x3( t) 3 x ( t) 10 x ( t) 10 x ( t) 2 2 3 3 2 1 2 3 x ( t) x ( t) x ( t) 28 x ( t) x ( t) x1 (0) 20, x2(0) 5, x3(0) 5 το οποίο γράφουμε σε διανυσματική μορφή ως εξής: 8 8 0 x2( t) 0 x2( t) x 1( t) 3 x1( t) 3 d x 2( t) 0 10 10 x2( t) x( t) 0 10 10 x( t) dt x 3( t) x2( t) 28 1 x3( t) x2( t) 28 1 και x(0) [20,5, 5]. [ F ] Τώρα, για να χρησιμοποιήσουμε την εντολή ode45, θα πρέπει να ορίσουμε τον πίνακα [F], που καθορίζει τις συναρτήσεις του δεξιού μέλους του συστήματος, σε ένα m-file (μια και δεν μπορούμε να τον ορίσουμε σαν μια ανώνυμη συνάρτηση). Για το παράδειγμα μας, τον ορίζουμε στο m-file odefun.m, που φαίνεται πιο κάτω: function [xprime] = odefun(t,x) % [xprime] = odefun(t,x) - % This function corresponds to the RHS of the system of ODEs, in % which x=[x(1), x(3), x(3)] represents the (vector) of unknown % functions. xprime = [-8/3,0,x(2);0,-10,10;-x(2),28,-1]*x; % End of m-file odefun.m Η εντολή ode45 χρησιμοποιείται όπως και πριν [t, x] = ode45(@odefun, t_span, a) αλλά, τώρα, τα δεδομένα εισόδου και εξόδου έχουν ως εξής:
οdefun: το όνομα του m-file που ορίζει τον πίνακα [F]. Παρατηρούμε ότι μια και δίνουμε ένα m-file σαν δεδομένο εισόδου, χρειάζεται να βάλουμε το @ πριν από το όνομα του m-file όταν καλούμε την ode45. t_span: το διάνυσμα [ t0, T] a: το διάνυσμα [a1, a2, a3] με τις αρχικές τιμές t: το διάνυσμα με τα σημεία t 0, t 1, t 2... όπου ανήκει το t αυτό πρέπει να δοθεί με αγκύλες x: ένας πίνακας του οποίου η κάθε στήλη αντιστοιχεί στις προσεγγιστικές τιμές των λύσεων [ x, x, x ] 1 2 3 Για το παράδειγμα μας έχουμε t0 = 0, [a1, a2, a3] = [20, 5, 5], και ας υποθέσουμε ότι το t ανήκει στο διάστημα [0, 12]. Γράφουμε >> [t,x] = ode45(@odefun,[0,12],[20,5,-5]); με ; στο τέλος για να μην τυπωθούν οι απαντήσεις στην οθόνη. Για να δούμε τις γραφικές παραστάσεις όλων των λύσεων (στους ίδιους άξονες) γράφουμε: >> plot(t,x) >> xlabel('t') >> ylabel('solution functions') >> legend('x_1(t)','x_2(t)','x_3(t)') Για να πάρουμε τη γραφική παράσταση μιας από τις λύσεις, π.χ. της x2(t), γράφουμε >> plot(t,x(:,2))
Παράδειγμα: Θεωρούμε το εξής Σ.Α.Τ.: x( t) 2 x ( t) 2 x ( t) x ( t) x( t) 2 2 x ( t) x ( t) x t x t x t x t 1 1 1 2 1 1 1 2( ) 1( ) 2( ) 2( ) x 2( t) x2( t) 1 x2( t) x (0) 1, x (0) 3, και με αρχικές συνθήκες 1 2 του δεξιού μέλους έχει ως εξής: t [0,20]. Το m-file που ορίζει τον πίνακα function [xprime] = odefun(t,x) % [xprime] = odefun(t,x) - % This function corresponds to the RHS of the system of ODEs, % in which x=[x(1),x(2)] represents the (vector) of unknown % functions. % The function will be passed as input into the ODE solver. xprime = [2, -2*x(1); x(2), -1]*x; % End of m-file odefun.m Γράφουμε >> [t,x] = ode45(@odefun,[0,12],[1,3]); >> plot(t,x) >> legend('x_1(t)','x_2(t)') >> xlabel('t') >> ylabel('solution functions') και παίρνουμε
Ασκήσεις 1. Θεωρούμε το εξής Π.Α.Τ. y( t) cos( t y), t [0,3] y(0) 0 του οποίου η ακριβής λύση είναι y( t) t 2arctan( t). Χρησιμοποιείστε το m-file euler.m που γράψαμε, με βήμα h = 0.1, για να βρείτε μια προσέγγιση της λύσης. Να κάνετε τη γραφική παράσταση της λύσης που πήρατε μαζί με την ακριβή λύση στους ίδιους άξονες οι οποίοι πρέπει να έχουν ετικέτες, τίτλο και λεζάντα. Επαναλάβετε με βήμα h = 0.05 και 0.01. 2. Για το Π.Α.Τ. της προηγούμενης άσκησης, χρησιμοποιείστε την εντολή βιβλιοθήκης ode45, για να βρείτε μια προσέγγιση της λύσης. Να κάνετε τη γραφική παράσταση της λύσης που πήρατε μαζί με την ακριβή λύση στους ίδιους άξονες οι οποίοι πρέπει να έχουν ετικέτες, τίτλο και λεζάντα. 3. Θεωρούμε το Π.Α.Τ. y( x) x y, y(0) 0, x [0,1], του οποίου η ακριβής λύση είναι y(x) = e x + x 1. Ορίστε το δεξιό μέλος της Σ.Δ.Ε. σαν μια ανώνυμη συνάρτηση f, όπως επίσης και το διάνυσμα με τα εξής βήματα >> h=[0.2,0.1,0.05,0.01,0.005]; και τρέξτε το m-file euler.m που γράψαμε, μέσω του βρόχου >> for i=1:length(h) [y,x] = euler(f,0,0,1,h(i)); yex=exp(-x)+x-1; E(i) = max(abs(yex-y)); end για να υπολογίσετε την προσέγγιση της λύσης (y), την ακριβή λύση (yex) και το μέγιστο σφάλμα (E) μεταξύ της προσέγγισης και της ακριβής λύσης στα σημεία που δίνονται από το διάνυσμα x. Στη συνέχεια, κάντε τη γραφική παράσταση του σφάλματος έναντι του βήματος, σε λογαριθμική κλίμακα: >> loglog(h,e,'o-') Τι είναι η κλίση της ευθείας που παίρνετε και τι αντιπροσωπεύει; 4. Χρησιμοποιήστε την εντολή ode45 για να λύσετε τα πιο κάτω Σ.Α.Τ.:
dx1 3x1 4 x2 ; x1 (0) 1 dt (α) dx2 2x1 3 x2 ; x2(0) 1 dt (β) dx1 dt dx2 dt ( 0.1) x x ; x (0) 10 x 1 2 1 ; x (0) 15 1 2 (γ) dx xz ; x(0) 0 dt dy xz ; y(0) 1 dt dz xy / 2 ; z(0) 1 dt