5.7 Diferenciación numérica

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]

Referencia: Chapra 23.1 p668, Rodríguez 8.2 p324

La diferenciación numérica aproxima la derivada f'(x) utilizando muestras xi alrededor del punto de interés que se encuentran a distancia h.

Diferenciacion numérica con varias h

Se pueden generar fórmulas por diferencias divididas de alta exactitud
tomando términos adicionales en la expansión de la serie de Taylor. Como referencia, el polinomio de Taylor muestra una aproximación de una función f(x) em el punto x0:

P_{n}(x) = f(x_0)+\frac{f'(x_0)}{1!} (x-x_0) + + \frac{f''(x_0)}{2!}(x-x_0)^2 + ...

de donde se obtiene la aproximación de las derivadas, al seleccionar la cantidad de términos y despejar, como se mostrará a continuación.

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]

..


1. Primera Derivada con Diferencias divididas hacia adelante

Una aproximación a primera derivada, usa los primeros dos términos del polinomio de Taylor alrededor de xi en para un punto a la derecha xi+1 a una distancia h = xi+1-xi

Diferenciacion Adelante 01

f(x_{i+1}) = f(x_i)+\frac{f'(x_i)}{1!} (h) + \frac{f''(x_i)}{2!}(h)^2 + ...

se puede simplificar en un polinomio de grado uno y un término de error:

f_{i+1} = f_i + (h)f'_i + O(h^2) ...

Despejando la expresión para f'i


f'_i = \frac{f_{i+1}-f_i}{h} = \frac{\Delta f_i}{h}

La expresión también es la primera diferencia finita dividida con un error del orden O(h). (tema usado en interpolación).

Revise que el término de la expresión queda O(h2)/h con lo que se disminuye el exponente en uno.

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]

..


2. Primera derivada con diferencias divididas centradas

Se realiza el mismo procedimiento que el anterior, usando un punto xi+1 y xi-1 alrededor de xi. En el término xi-1 el valor de h es negativo al invertir el orden de la resta.

Diferenciacion Centrada 01

f_{i+1} = f_i+\frac{f'_i}{1!}(h) + \frac{f''_i}{2!}(h)^2 + O(h^3) ... f_{i-1} = f_i-\frac{f'_i}{1!}(h) + \frac{f''_i}{2!}(h)^2

restando la ecuaciones se tiene que

f_{i+1} - f_{i-1} = (h)f'_i +(h)f'_i f_{i+1} - f_{i-1} = 2h f'_i

La expresión de primera derivada usando un punto antes y otro después del punto central queda como:

f'_i = \frac{f_{i+1} - f_{i-1}}{2h}

con un error del orden O(h2)

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]
..


3. Algoritmo en Python

Compara las diferencias divididas hacia adelante, centro y atrás.

El punto xk para la derivada se encuentra en la posición i , de dónde se toman para el cálculo los puntos xi  hacia la izquierda o derecha .

Se requieren al menos 2 tramos para usar las fórmulas, para disponer de un valor de h dentro del intervalo.

Para observar el error en la gráfica, se incorpora f'(x) obtenida de forma analítica como referencia en el ejercicio.

El resultado del algoritmo es:

diferenciación numérica:
en xk: 1.5 	, h: 0.5
   tramos: 4
[  dfx/dx,  valor,  error]
['df_analítica', 0.4938606479864909, 0]
['df_atras', 0.7604117685484817, 0.2665511205619908]
['df_centro', 0.4444697684399397, -0.04939087954655119]
['df_adelante', 0.12852776833139767, -0.3653328796550932]

Instrucciones en Python

# Diferenciación Numérica - 1ra Derivada
# Compara con diferenciación numérica
import numpy as np

# INGRESO
fx = lambda x: np.sqrt(x)*np.sin(x)
dfx = lambda x: np.sin(x)/(2*np.sqrt(x))+ np.sqrt(x)*np.cos(x)
xk = 1.5 # punto derivada

a = 1  # intervalo de observación
b = 3
tramos = 64 # >=2, al menos 2 tramos 

# PROCEDIMIENTO
# revisa valores, Tarea: incluir en algoritmo
cond1 = a<b
cond2 = a<xk and xk<b
cond3 = tramos>=2
if not(cond1):
    print('a>b, no es ascendente')
if not(cond2):
    print('ak fuera de intervalo [a,b]')
if not(cond3):
    print('tramos deben ser al menos 2')
    
# tramo menor hacia atras y adelante
dx_atras = abs(xk-a) # xk hacia atras intervalo
dx_adelante = abs(xk-b) # xk hacia frente intervalo
dx_min = min(dx_atras,dx_adelante)

h_tramo = (b-a)/tramos
h = min(h_tramo,dx_min)

xi_atras = np.sort(np.arange(xk,a-h/2,-h))
xi_adelante = np.arange(xk,b+h/2,h)
xi = np.concatenate((xi_atras,xi_adelante[1:]),axis=0)

i = len(xi_atras)-1
# puntos de muestras
fi = fx(xi)
tabla = [] # tangentes a xi[i]

# derivada analítica, como referencia
dfi = dfx(xi[i])
px = lambda x: fi[i] + dfi*(x-xi[i])
pxi = px(xi)
tabla.append(['df_analítica',dfi,0,pxi,px])

# hacia Atras, diferencias divididas
df1_atras = (fi[i]-fi[i-1])/h
px = lambda x: fi[i] + df1_atras*(x-xi[i])
pxi = px(xi)
errado = df1_atras - dfi
tabla.append(['df_atras',df1_atras,errado,pxi,px])

# Centro, diferencias divididas
df1_centro = (fi[i+1]-fi[i-1])/(2*h)
px = lambda x: fi[i] + df1_centro*(x-xi[i])
pxi = px(xi)
errado = df1_centro - dfi
tabla.append(['df_centro',df1_centro,errado,pxi,px])

# hacia Adelante, diferencias divididas
df1_adelante = (fi[i+1]-fi[i])/h
px = lambda x: fi[i] + df1_adelante*(x-xi[i])
pxi = px(xi)
errado = df1_adelante - dfi
tabla.append(['df_adelante',df1_adelante,errado,pxi,px])

# SALIDA
print('diferenciación numérica:')
print('en xk:',xk,'\t, h:',h,)
print('   tramos:', tramos)
print('[  dfx/dx,  valor,  error]')
for unadifdiv in tabla:
    print(unadifdiv[0:3])

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]

..


3.1Gráficas en Python

diferencias divididas para 4 tramosSe complementa el algoritmo anterior con las siguientes instrucciones.

# GRAFICA  --------------
import matplotlib.pyplot as plt
txt = 'Diferenciación Numérica'
txt = txt + ', xi:'+str(xk)
txt = txt + ', tramos:'+str(tramos)
titulo = txt + ', h:'+str(h)

# fx suave aumentando muestras
muestrasfxSuave = tramos*10 + 1
xk = np.linspace(a,b,muestrasfxSuave)
fk = fx(xk)

# Graficar f(x), puntos
plt.ylim(min(fk),max(fk)*1.5)
plt.plot(xk,fk, label ='f(x)',linestyle='dotted')
if tramos<64:
    plt.plot(xi,fi, 'o') # muestras

for unadifdiv in tabla: # tangentes a xi[i]
    linea = 'dashed'
    if unadifdiv[0]=='df_analítica':
        linea = 'solid'
    plt.plot(xi,unadifdiv[3],label=unadifdiv[0],
             linestyle=linea)

plt.plot(xi[i],fi[i],'ro') # punto i observado

plt.xlabel('xi')
plt.ylabel('f(xi)')
plt.title(titulo)
plt.legend()
plt.tight_layout()
plt.show()

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]


Segundas derivadas

Al continuar con el procedimiento mostrado se pueden obtener las fórmulas para segundas derivadas, las que se resumen en las tablas de Fórmulas de diferenciación por diferencias divididas.

Diferencias Divididas [ hacia adelante ] [ centradas ] || [ algoritmo ] [ gráfica ]