# Numerical Differentiation There are many ways to evaluate the differentiation of a function numerically, one of which is three-point method. Due to its method which require three point to evaluate an derivative, first and last point required a different form of formula which given below. \begin{equation} f'(x_0) = \dfrac{1}{2h} [-3f(x_0)+4f(x_0+h)-f(x_0+2h)] + \dfrac{h^2}{3}f^{(3)}(\zeta_1) \tag{1} \end{equation} \begin{equation} f'(x_0) = \dfrac{1}{2h} [f(x_0-2h)-4f(x_0-h)+3f(x_0)] + \dfrac{h^2}{3}f^{(3)}(\zeta_2) \tag{2} \end{equation} \begin{equation} f'(x_0) = \dfrac{1}{2h} [f(x_0+h)+-f(x_0-h)] + \dfrac{h^2}{6}f^{(3)}(\zeta_3) \tag{3} \end{equation} By intuition, the information on both end is less than the one in the middle, so you can see from the error function that the error is two times larger at boundary than the one in the middle. Using the error function which is give by the last term from (1) to (3), we can know complete the table which compute the derivative of two different function. ## Example 1 \begin{equation} f(x) = e^{2x} \end{equation} ![](https://i.imgur.com/5c73nwI.png) ## Example 2 \begin{equation} f(x) = xlnx \end{equation} ![](https://i.imgur.com/54Xx2bT.png) ### Code ```fortran= program threepoint !======================================================== ! Purpose: Find derivative ! ! Methods: Three point method ! ! Date Programer Description of change ! ==== ========= ===================== ! 10/30/20 MorrisH Original Code !======================================================== implicit none double precision, external :: f, g double precision :: x(4) = (/ 8.1d0, 8.3d0, 8.5d0, 8.7d0 /) double precision :: x1(4), h=.2d0, err(4), ebd(4) integer :: i ! calculate derivative do i = 1, 4 if (i == 1) then x1(i) = ( -3.d0 * f(x(i)) + 4.d0 * f(x(i+1)) - & f(x(i+2)) ) / (2.d0 * h) else if (i == 4) then x1(i) = ( f(x(i-2)) - 4.d0 * f(x(i-1)) + & 3.d0 * f(x(i)) ) / (2.d0 * h) else x1(i) = (f(x(i+1)) - f(x(i-1))) / (2.d0 * h) end if end do ! calculate error do i = 1, 4 err(i) = abs(x1(i) - g(x(i))) / g(x(i)) end do ! calculate error bound do i = 1, 4 if ((i==1) .or. (i==4)) then ebd(i) = abs(h**2 / 3.d0 * 8.d0 * (-1.d0 / x(i)**2)) else ebd(i) = abs(h**2 / 6.d0 * 8.d0 * (-1.d0 / x(i)**2)) end if end do ! print the table write(6, '(5A15)') 'x', 'f(x)', "f'(x)", 'Error', 'Error Bound' do i = 1, 4 write(6, '(5F15.5)') x(i), f(x(i)), x1(i), err(i), ebd(i) end do end program threepoint function f(x) implicit none double precision :: f, x ! f = dexp(2.d0 * x) f = x * log(x) end function function g(x) implicit none double precision :: g, x ! g = 2.d0 * dexp(2.d0 * x) g = log(x) + 1.d0 end function ``` ## Example 3: Circuit problem A circuit with impressed voltage $\varepsilon(t)$ and inductance $L$, can be express as following equation. \begin{equation} \varepsilon = L\dfrac{di}{dt}+Ri \tag{4} \end{equation} Again, using three-point method to approximate the impressed volage given by (4). With $L=0.98$ and $R=0.142$ the result table is given below. ![](https://i.imgur.com/NuOToQa.png) ### Code ```fortran= program rl !======================================================== ! Purpose: Solve RL circuit ! ! Methods: Three point method ! ! Date Programer Description of change ! ==== ========= ===================== ! 10/30/20 MorrisH Original Code !======================================================== implicit none double precision :: t(5) = (/ 1.d0, 1.01d0, 1.02d0, 1.03d0, 1.04d0 /) double precision :: x(5) = (/ 3.1d0, 3.12d0, 3.14d0, 3.18d0, 3.24d0 /) double precision :: x1(5), v(5), h=.01d0 integer :: i ! calculate derivative do i = 1, 5 if (i == 1) then x1(i) = ( -3.d0 * x(i) + 4.d0 * x(i+1) - & x(i+2) ) / (2.d0 * h) else if (i == 5) then x1(i) = ( x(i-2) - 4.d0 * x(i-1) + & 3.d0 * x(i) ) / (2.d0 * h) else x1(i) = (x(i+1) - x(i-1)) / (2.d0 * h) end if end do ! calculate voltage do i = 1, 5 v(i) = .98d0 * x1(i) + .142d0 * x(i) end do ! print the table write(6, '(4A15)') 't', 'i', "di/dt", 'voltage' do i = 1, 5 write(6, '(4F15.5)') t(i), x(i), x1(i), v(i) end do end program rl ``` ## Example 4: Predator-Prey model Predator-Prey model is govern by following two differential equation where $x_1(x)$ is the number of preys and $x_2(x)$ is the number of predators. \begin{equation} \begin{split} \dfrac{dx_1(t)}{dt} &= k_1x_1-k_2x_1x_2 \\ \dfrac{dx_2(t)}{dt} &= k_3x_1x_2-k_4x_2 \end{split} \end{equation} Solving these equation using RK4 method accompany with initial value value given below gives the following result. \begin{equation*} \begin{split} &x_1(0)=1000 \\ &x_2(0)=500 \\ &k_1=3 \\ &k_2=0.002 \\ &k_3=0.0006 \\ &k_4=0.5 \end{split} \end{equation*} Due to the number of predators initally is outnumber by preys, number of prey raise up. But it didn't last long, soon it follow by the raising of predator which cause the number of prey decrease dracmatically and almost distinguise. And this cycle goes on forever both predator and prey never settle to a single number. ![](https://i.imgur.com/QnBhgNy.png) ![](https://i.imgur.com/NEPs8ak.png) ### Code ```fortran= program sysrk4 !======================================================== ! purpose: solve system of ode ! ! methods: rk4 ! ! date programer description of change ! ==== ========= ===================== ! 10/29/20 morrish original code !======================================================== implicit none double precision, external :: f1, f2 double precision :: k(4), w(4, 2), h, t double precision, dimension(:), allocatable :: x1, x2 integer :: i, n ! coef k = (/ 3.d0, 2.d-3, 6.d-4, .5d0 /) ! time step h = 1.d-3 n = nint(20/h) allocate(x1(n)) allocate(x2(n)) ! inital value x1(1) = 1000.d0 x2(1) = 500.d0 do i = 1, n w(1, 1) = h * f1(x1(i), x2(i), k) w(1, 2) = h * f2(x1(i), x2(i), k) w(2, 1) = h * f1(x1(i)+0.5d0*w(1, 1), & x2(i)+0.5d0*w(1, 2), k) w(2, 2) = h * f2(x1(i)+0.5d0*w(1, 1), & x2(i)+0.5d0*w(1, 2), k) w(3, 1) = h * f1(x1(i)+0.5d0*w(2, 1), & x2(i)+0.5d0*w(2, 2), k) w(3, 2) = h * f2(x1(i)+0.5d0*w(2, 1), & x2(i)+0.5d0*w(2, 2), k) w(4, 1) = h * f1(x1(i)+w(3, 1), x2(i)+w(3, 2), k) w(4, 2) = h * f2(x1(i)+w(3, 1), x2(i)+w(3, 2), k) x1(i+1) = x1(i) + (w(1, 1) + 2.d0 * w(2, 1) + & 2.d0 * w(3, 1) + w(4, 1)) / 6.d0 x2(i+1) = x2(i) + (w(1, 2) + 2.d0 * w(2, 2) + & 2.d0 * w(3, 2) + w(4, 2)) / 6.d0 end do open(66, file='out.dat', status='unknown') do i = 1, n write(66, *) dble(i-1)*h, x1(i), x2(i) end do end program sysrk4 function f1(x1, x2, k) implicit none double precision :: f1, x1, x2 double precision :: k(4) f1 = k(1) * x1 - k(2) * x1 * x2 end function function f2(x1, x2, k) implicit none double precision :: f2, x1, x2 double precision :: k(4) f2 = k(3) * x1 * x2 - k(4) * x2 end function ``` ## Example 5: Projectile motion Consider a baseball was being hit by 2020 World Series MVP, Corey Seager, we can write down the equation of motion of the baseball by \begin{equation} \mathbf{F}=m\mathbf{g}-\dfrac{1}{2}c_w\rho A v^2 \hat{v} \end{equation} where $c_w$ is the dimensionless drag coefficient, $\rho$ is the air density, $v$ is the velocity of the ball, and $A$ is the cross-sectional area of the ball. ### Without air resistance We first ignore resistance, we can see from below figure that the inital speed for it to clear the fence is roughly around 25.5 m/s. ![](https://i.imgur.com/MhPNad3.png) As you can see, this system should always satisfied energy conservation, but it can loose accaracy when preform numerical calculation. So far so good, using RK4 energy were conserved which also can be a indicator to the converges of the parameter that we use in RK4 method(eg. time step). ![](https://i.imgur.com/Ubi6GDU.png) Following is the result of that calculation, it show that the initial speed for the baseball to clear the fence with 35 degrees angle is around 25.432810 m/s. ![](https://i.imgur.com/PumBxoq.png) #### Code ```fortran= program proj !======================================================== ! purpose: solve system of ode ! ! methods: rk4 ! ! date programer description of change ! ==== ========= ===================== ! 10/29/20 morrish original code !======================================================== implicit none double precision, parameter :: pi = 3.1415926535898d0 double precision, external :: f1, f2, f3, f4 double precision :: w(4, 4), h, theta, v0 double precision, dimension(:), allocatable :: x, y, vx, vy double precision, dimension(:), allocatable :: t integer :: i, j, n character(len=15) :: str ! time step h = 1.d-2 n = nint(100/h) allocate(x(n)) allocate(y(n)) allocate(vx(n)) allocate(vy(n)) allocate(t(n)) ! inital value theta = 35.d0 * pi / 180.d0 v0 = 25.0 speed: do t = 0.d0 x = 0.d0 y = 0.d0 vx = 0.d0 vy = 0.d0 y(1) = .7d0 vx(1) = v0 * dcos(theta) vy(1) = v0 * dsin(theta) do i = 1, n w(1, 1) = h * f1(x(i), y(i), vx(i), vy(i)) w(1, 2) = h * f2(x(i), y(i), vx(i), vy(i)) w(1, 3) = h * f3(x(i), y(i), vx(i), vy(i)) w(1, 4) = h * f4(x(i), y(i), vx(i), vy(i)) w(2, 1) = h * f1(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 2) = h * f2(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 3) = h * f3(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 4) = h * f4(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(3, 1) = h * f1(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 2) = h * f2(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 3) = h * f3(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 4) = h * f4(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(4, 1) = h * f1(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 2) = h * f2(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 3) = h * f3(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 4) = h * f4(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) x(i+1) = x(i) + (w(1, 1) + 2.d0 * w(2, 1) + & 2.d0 * w(3, 1) + w(4, 1)) / 6.d0 y(i+1) = y(i) + (w(1, 2) + 2.d0 * w(2, 2) + & 2.d0 * w(3, 2) + w(4, 2)) / 6.d0 vx(i+1) = vx(i) + (w(1, 3) + 2.d0 * w(2, 3) + & 2.d0 * w(3, 3) + w(4, 3)) / 6.d0 vy(i+1) = vy(i) + (w(1, 4) + 2.d0 * w(2, 4) + & 2.d0 * w(3, 4) + w(4, 4)) / 6.d0 t(i+1) = dble(i)*h ! hit the groud if (y(i+1) <= 0.d0) then exit end if end do ! check if it pass the fence do j = 1, i+1 if ((x(j) >= 60.d0).and.(y(j) >= 2.d0)) then exit speed end if end do ! write to a file v0 = v0 + 0.00001d0 ! write(str, '(I6.6)') j ! open(66, file='data/a/'//trim(str)//'.dat', & ! status='unknown') ! do i = 1, n ! write(66, *) t(i), x(i), y(i), vx(i), vy(i) ! if (y(i) <= 0.d0) then ! exit ! end if ! end do ! close(66) end do speed write(6, *) 'With inital angle of 35 degrees, the velocity when & the ball pass the fence.' write(6, '(5A15)') 'v0', 'x(final)', 'y(final)', 'vx(final)', 'vy(final)' write(6, '(5f15.6)') v0, x(j), y(j), vx(j), vy(j) end program proj function f1(x, y, vx, vy) implicit none double precision :: f1, x, y, vx, vy f1 = vx end function function f2(x, y, vx, vy) implicit none double precision :: f2, x, y, vx, vy f2 = vy end function function f3(x, y, vx, vy) implicit none double precision :: f3, x, y, vx, vy f3 = 0.d0 end function function f4(x, y, vx, vy) implicit none double precision :: f4, x, y, vx, vy f4 = -9.8d0 end function \end{minted} ``` ### With air reistance Next we take a step further, considering air resistance by changing differenct initial velocity I found out that in order to clear the fence we need at least 35.57340 m/s. ![](https://i.imgur.com/TaM7keX.png) ![](https://i.imgur.com/l77pU0M.png) With this speed in mind we try to find the best possible angle that can easily clear the fence. We can see from the trajectories, the best angle is roughly around 40 degrees. ![](https://i.imgur.com/BK9DUEg.png) Below figure verified our guess, when the angle is 40.550 we can vertically clear the fence by 1.112 m. ![](https://i.imgur.com/TH8Rkgb.png) ```fortran= program proj !======================================================== ! purpose: solve system of ode ! ! methods: rk4 ! ! date programer description of change ! ==== ========= ===================== ! 10/29/20 morrish original code !======================================================== implicit none double precision, parameter :: pi = 3.1415926535898d0 double precision, external :: f1, f2, f3, f4 double precision :: w(4, 4), h, theta, v0 double precision, dimension(:), allocatable :: x, y, vx, vy double precision, dimension(:), allocatable :: t integer :: i, j, n character(len=15) :: str ! time step h = 1.d-3 n = nint(100/h) allocate(x(n)) allocate(y(n)) allocate(vx(n)) allocate(vy(n)) allocate(t(n)) ! inital value theta = 30.d0 * pi / 180.d0 v0 = 35.573740d0 speed: do t = 0.d0 x = 0.d0 y = 0.d0 vx = 0.d0 vy = 0.d0 y(1) = .7d0 vx(1) = v0 * dcos(theta) vy(1) = v0 * dsin(theta) do i = 1, n w(1, 1) = h * f1(x(i), y(i), vx(i), vy(i)) w(1, 2) = h * f2(x(i), y(i), vx(i), vy(i)) w(1, 3) = h * f3(x(i), y(i), vx(i), vy(i)) w(1, 4) = h * f4(x(i), y(i), vx(i), vy(i)) w(2, 1) = h * f1(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 2) = h * f2(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 3) = h * f3(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(2, 4) = h * f4(x(i)+0.5d0*w(1, 1), & y(i)+0.5d0*w(1, 2), & vx(i)+0.5d0*w(1, 3), & vy(i)+0.5d0*w(1, 4)) w(3, 1) = h * f1(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 2) = h * f2(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 3) = h * f3(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(3, 4) = h * f4(x(i)+0.5d0*w(2, 1), & y(i)+0.5d0*w(2, 2), & vx(i)+0.5d0*w(2, 3), & vy(i)+0.5d0*w(2, 4)) w(4, 1) = h * f1(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 2) = h * f2(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 3) = h * f3(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) w(4, 4) = h * f4(x(i)+w(3, 1), y(i)+w(3, 2), & vx(i)+w(3, 3), vy(i)+w(3, 4)) x(i+1) = x(i) + (w(1, 1) + 2.d0 * w(2, 1) + & 2.d0 * w(3, 1) + w(4, 1)) / 6.d0 y(i+1) = y(i) + (w(1, 2) + 2.d0 * w(2, 2) + & 2.d0 * w(3, 2) + w(4, 2)) / 6.d0 vx(i+1) = vx(i) + (w(1, 3) + 2.d0 * w(2, 3) + & 2.d0 * w(3, 3) + w(4, 3)) / 6.d0 vy(i+1) = vy(i) + (w(1, 4) + 2.d0 * w(2, 4) + & 2.d0 * w(3, 4) + w(4, 4)) / 6.d0 t(i+1) = dble(i)*h ! hit the groud if (y(i+1) <= 0.d0) then exit end if end do ! check if it pass the fence open(66, file='data/angle.dat', status='unknown') do j = 1, i+1 if (x(j) >= 60.d0) then write(66, *) theta / pi * 180.d0, y(j) exit end if end do theta = (theta / pi * 180.d0 + .001d0) * pi / 180.d0 if (theta / pi * 180.d0 >= 50.d0) then exit speed end if ! write to a file ! write(str, '(I6.6)') j ! open(66, file='data/c/'//trim(str)//'.dat', & ! status='unknown') ! do i = 1, n ! write(66, *) t(i), x(i), y(i), vx(i), vy(i) ! if (y(i) <= 0.d0) then ! exit ! end if ! end do ! close(66) end do speed ! write(6, *) 'With inital speed of 35.57374 m/s, the angle when & ! the ball pass the fence.' ! write(6, '(5A15)') 'angle', 'x(final)', 'y(final)', 'vx(final)', 'vy(final)' ! write(6, '(5f15.6)') theta/pi*180.d0, x(j), y(j), vx(j), vy(j) end program proj function f1(x, y, vx, vy) implicit none double precision :: f1, x, y, vx, vy f1 = vx end function function f2(x, y, vx, vy) implicit none double precision :: f2, x, y, vx, vy f2 = vy end function function f3(x, y, vx, vy) implicit none double precision :: f3, x, y, vx, vy f3 = -0.5d0 * .5d0 * 1.335d0 * 7.8539d-3 * vx * & dsqrt(vx**2 + vy**2) / .2d0 end function function f4(x, y, vx, vy) implicit none double precision :: f4, x, y, vx, vy f4 = -9.8d0 - 0.5d0 * .5d0 * 1.335d0 * 7.8539d-3 * vy * & dsqrt(vx**2 + vy**2) / .2d0 end function ```