%{ Solving 1st-order ODE Method: RKF45 with step-size control Alex G. March 2022 %} clear; clc; close; dx = @f; fa = @(t) atan(100*t); % analytic solution for function f (if availble) KeyA = 0; % 1 - if comparing with analytic solution, 0 - if not tolerance = 1.e-6; StepsMax = 1000; % 1: initial condition % ti = 0.00; % xi = 1.00; ti = -1.0; xi = atan(-100); % 2: "time" step and max time dt = 0.5; tmax = 1.0; % 3: prepare to plot an analytic solution (if available) if KeyA == 1 a = ti; b = tmax+dt; Nplot = 100; h = (b-a)/Nplot; for k = 1:Nplot+1 xa(k) = a+ (k-1)*h; ya(k) = fa(xa(k)); end end % 4: getting ready for the main loop i = 1; step = 1; t(i) = ti; x(i) = xi; % 5: the MAIN part while (ti < tmax) tf = ti + dt; [xf,er5] = RKF51(dx,ti,xi,tf); er5 = abs(er5); if (er5 <= tolerance) i = i + 1; x(i) = xf; t(i) = tf; ti = tf; xi = xf; dt = min(0.9*dt*(abs(tolerance/er5)).^(1/5),2.0*dt); else dt = max(0.9*dt*(abs(tolerance/er5)).^(1/5),0.2*dt); end step = step + 1; if step > StepsMax fprintf(' Max number of steps exceeded at tf = %8.4f \n',tf) break end end % figure (1) figure('DefaultAxesFontSize',14) if KeyA == 0 plot(t,x,'b-o','LineWidth',1.0) legend('RKF45') elseif KeyA == 1 plot(t,x,'bo',xa,ya,'r','LineWidth',1.0) legend('RKF45','analytic solution') end xlabel('t') ylabel('x(t)') grid function f=f(t,x) %======== % function for dx/dt = f(t,x) %======== %f = 0.0-x+0*t; %f = x+exp(-t); %f = 0.5*sin(2*x) - x*cos(t); f = 100/(1+10000.*t.^2); end function [xf,er5] = RKF51(dx,ti,xi,tf) %================================================== % Solution of a single 1st order ODE dx/dt=f(x,t) % Method: Runge-Kutta-Fehlberg RKF45 % Alex G. March 2022 %-------------------------------------------------- % input ... % dx(t,x)- function dx/dt (supplied by a user) % ti - initial time % xi - initial position % tf - time for a solution % output ... % xf - solution at point tf % er511 - error estimate %================================================== h = tf-ti; k1 = h*dx(ti,xi); k2 = h*dx(ti+h/4.0, xi+k1/4.0); k3 = h*dx(ti+3*h/8, xi+3*k1/32+9*k2/32); k4 = h*dx(ti+12*h/13,xi+1932*k1/2197-7200*k2/2197+7296*k3/2197); k5 = h*dx(ti+h, xi+439*k1/216-8*k2+3680*k3/513-845*k4/4104); k6 = h*dx(ti+h/2, xi-8*k1/27+2*k2-3544*k3/2565+1859*k4/4104-11*k5/40); xf = xi + 16*k1/135+6656*k3/12825+28561*k4/56430-9*k5/50+2*k6/55; er5 = k1/360-128*k3/4275-2197*k4/75240+k5/50+2*k6/55; end