4.5.1 Trazadores Cúbicos, frontera sujeta con Python

Trazador cúbico frontera sujeta [ Algoritmo ] [ gráfica ] [ función ]
..


1. Algoritmo en Python - Frontera sujeta

Para el ejercicio anterior, haciendo que la primera derivada sea cero en los extremos  y luego de realizar los ajustes al algoritmo, se tiene como resultado:

spline frontera sujeta 04

h: [0.1 0.1 0.1]
A:
[[-0.03333333 -0.01666667  0.          0.        ]
 [ 0.1         0.4         0.1         0.        ]
 [ 0.          0.1         0.4         0.1       ]
 [ 0.          0.          0.01666667  0.03333333]]
B: [ -3.5 -27.   24.   -3. ]
S: [ 178. -146.  136. -158.]
coeficientes[ ,tramo]:
a: [-540.  470. -490.]
b: [ 89. -73.  68.]
c: [-3.99680289e-15  1.60000000e+00  1.10000000e+00]
d: [1.45 1.8  1.7 ]
Trazador cúbico frontera sujeta
Polinomios por tramos: 
x = [ 0.1 , 0.2 ]
expresión: -3.99680288865056e-15*x - 540.0*(x - 0.1)**3 + 89.0000000000001*(x - 0.1)**2 + 1.45
simplifica:
         3          2                
- 540.0⋅x  + 251.0⋅x  - 34.0⋅x + 2.88
x = [ 0.2 , 0.3 ]
expresión: 1.6*x + 470.0*(x - 0.2)**3 - 73.0*(x - 0.2)**2 + 1.48
simplifica:
       3          2                                        
470.0⋅x  - 355.0⋅x  + 87.2000000000001⋅x - 5.20000000000001
x = [ 0.3 , 0.4 ]
expresión: 1.1*x - 490.0*(x - 0.3)**3 + 68.0*(x - 0.3)**2 + 1.37
simplifica:
         3          2                  
- 490.0⋅x  + 509.0⋅x  - 172.0⋅x + 20.72

Instrucciones en Python

# Trazador cubico frontera sujeta
import numpy as np
import sympy as sym

def traza3sujeto(xi,yi,d1y0,dy1n, vertabla=False):
    ''' trazador cubico sujeto, d1y0=y'(x[0]), dyn=y'(x[n-1])
    1ra derivadas en los nodos extremos son conocidas
    '''
    # Vectores como arreglo, numeros reales
    xi = np.array(xi,dtype=float)
    yi = np.array(yi,dtype=float)
    n = len(xi)
    
    h = np.diff(xi,n=1) # h tamano de paso

    # Sistema de ecuaciones
    A = np.zeros(shape=(n,n), dtype=float)
    B = np.zeros(n, dtype=float)
    S = np.zeros(n-1, dtype=float)
    A[0,0] = -h[0]/3
    A[0,1] = -h[0]/6
    B[0] = d1y0 - (yi[1]-yi[0])/h[0]
    for i in range(1,n-1,1):
        A[i,i-1] = h[i-1]
        A[i,i] = 2*(h[i-1]+h[i])
        A[i,i+1] = h[i]
        B[i] = 6*((yi[i+1]-yi[i])/h[i] - (yi[i]-yi[i-1])/h[i-1])
    A[n-1,n-2] = h[n-2]/6
    A[n-1,n-1] = h[n-2]/3
    B[n-1] = d1yn - (yi[n-1]-yi[n-2])/h[n-2]
    
    # Resolver sistema de ecuaciones, S
    S = np.linalg.solve(A,B)

    # Coeficientes
    a = np.zeros(n-1, dtype = float)
    b = np.zeros(n-1, dtype = float)
    c = np.zeros(n-1, dtype = float)
    d = np.zeros(n-1, dtype = float)
    for j in range(0,n-1,1):
        a[j] = (S[j+1]-S[j])/(6*h[j])
        b[j] = S[j]/2
        c[j] = (yi[j+1]-yi[j])/h[j] - (2*h[j]*S[j]+h[j]*S[j+1])/6
        d[j] = yi[j]

    # Polinomio trazador
    x = sym.Symbol('x')
    px_tabla = []
    for j in range(0,n-1,1):
        pxtramo = a[j]*(x-xi[j])**3 + b[j]*(x-xi[j])**2 + c[j]*(x-xi[j])+ d[j]
        px_tabla.append(pxtramo)
    
    if vertabla==True:
        print('h:',h)
        print('A:') ; print(A)
        print('B:',B) ; print('S:',S)
        print('coeficientes[ ,tramo]:')
        print('a:',a) ; print('b:',b)
        print('c:',c) ; print('d:',d)

    return(px_tabla)

# PROGRAMA ---------------
# INGRESO
xi = [0.1 , 0.2, 0.3, 0.4]
fi = [1.45, 1.8, 1.7, 2.0]

titulo = 'Trazador cúbico frontera sujeta'
# sujeto,  1ra derivadas en los nodos extremos son conocidas
d1y0 = 0  # izquierda, xi[0]
d1yn = 0  # derecha, xi[n-1]

# PROCEDIMIENTO
n = len(xi)
# Obtiene los polinomios por tramos
px_tabla = traza3sujeto(xi,fi,d1y0,d1yn,vertabla=True)

# SALIDA
print(titulo)
print('Polinomios por tramos: ')
for i in range(0,n-1,1):
    print('x = [',xi[i],',',xi[i+1],']')
    print('expresión:',px_tabla[i])
    print('simplifica:')
    sym.pprint(px_tabla[i].expand())

Trazador cúbico frontera sujeta [ Algoritmo ] [ gráfica ] [ función ]
..


2. Gráfica en Python

La gráfica se realiza en un bloque con los resultados del algoritmo

# GRAFICA --------------
import matplotlib.pyplot as plt

muestras = 10 # entre cada par de puntos

# Puntos para grafica en cada tramo
xtraza = np.array([],dtype=float)
ytraza = np.array([],dtype=float)
i = 0
while i<n-1: # cada tramo
    xtramo = np.linspace(xi[i],xi[i+1],muestras)
    # evalua polinomio del tramo
    pxk = sym.lambdify('x',px_tabla[i])
    ytramo = pxk(xtramo)
    # vectores de trazador en x,y
    xtraza = np.concatenate((xtraza,xtramo))
    ytraza = np.concatenate((ytraza,ytramo))
    i = i + 1

# Graficar
plt.plot(xtraza,ytraza, label='trazador')
plt.plot(xi,fi,'o', label='puntos')
plt.title(titulo)
plt.xlabel('xi')
plt.ylabel('px(xi)')
plt.legend()
plt.show()
plt.show()

Trazador cúbico frontera sujeta [ Algoritmo ] [ gráfica ] [ función ]
..


3. Trazador cúbico sujeto como función en Scipy.interpolate.CubicSpline

También es posible usar la función de Scipy para generar los trazadores cúbicos en el caso de frontera sujeta. Se hacen los ajustes en el bloque de ingreso, considerando que las primeras derivadas en los nodos extremos son conocidas.

# Trazador cúbico frontera sujeta con Scipy
import numpy as np
import scipy as sp
import sympy as sym

# INGRESO
xi = [0.1 , 0.2, 0.3, 0.4]
fi = [1.45, 1.8, 1.7, 2.0]

titulo = 'Trazador cúbico frontera sujeta'
# sujeto,  1ra derivadas en los nodos extremos son conocidas
d1y0 = 0  # izquierda, xi[0]
d1yn = 0  # derecha, xi[n-1]
cs_tipo = ((1, d1y0), (1, d1yn)) # sujeto

# PROCEDIMIENTO
# Vectores como arreglo, numeros reales
xi = np.array(xi,dtype=float)
fi = np.array(fi,dtype=float)
n = len(xi)

# coeficientes de trazadores cúbicos
traza_c = sp.interpolate.CubicSpline(xi,fi,bc_type=cs_tipo )
traza_coef = traza_c.c # coeficientes
a = traza_coef[0]
b = traza_coef[1]
c = traza_coef[2]
d = traza_coef[3]

# Polinomio trazador
x = sym.Symbol('x')
px_tabla = []
for j in range(0,n-1,1):
    pxtramo = a[j]*(x-xi[j])**3 + b[j]*(x-xi[j])**2 + c[j]*(x-xi[j])+ d[j]
    px_tabla.append(pxtramo)

# SALIDA
print(titulo)
print('coeficientes:')
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)
print('Polinomios por tramos: ')
for i in range(0,n-1,1):
    print('x = [',xi[i],',',xi[i+1],']')
    print('expresión:',px_tabla[i])
    print('simplifica:')
    sym.pprint(px_tabla[i].expand())

La gráfica se puede realizar con el bloque presentado para el algoritmo anterior. El resultado del algoritmo se presenta como

Trazador cúbico frontera sujeta
coeficientes:
a: [-540.  470. -490.]
b: [ 89. -73.  68.]
c: [0.  1.6 1.1]
d: [1.45 1.8  1.7 ]
Polinomios por tramos: 
x = [ 0.1 , 0.2 ]
expresión: -540.0*(x - 0.1)**3 + 89.0*(x - 0.1)**2 + 1.45
simplifica:
         3          2                
- 540.0⋅x  + 251.0⋅x  - 34.0⋅x + 2.88
x = [ 0.2 , 0.3 ]
expresión: 1.6*x + 470.0*(x - 0.2)**3 - 73.0*(x - 0.2)**2 + 1.48
simplifica:
       3          2                           
470.0⋅x  - 355.0⋅x  + 87.2000000000001⋅x - 5.2
x = [ 0.3 , 0.4 ]
expresión: 1.1*x - 490.0*(x - 0.3)**3 + 68.0*(x - 0.3)**2 + 1.37
simplifica:
         3          2                  
- 490.0⋅x  + 509.0⋅x  - 172.0⋅x + 20.72

Trazador cúbico frontera sujeta [ Algoritmo ] [ gráfica ] [ función ]


Unidades