-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspline_interpolation.py
130 lines (112 loc) · 4.31 KB
/
spline_interpolation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
__author__ = 'Tom Gresavage'
import sys
import os
import math
import time
import numpy as np
import numpy.linalg as la
import matplotlib.pyplot as plt
def polynomial(coefficients, name="f"):
# Creates a polynomial whose coefficients of increasing orders of x are given by "coefficients"
def function(x):
y = 0
for i in range(len(coefficients)):
y += coefficients[i]*np.power(x, i)
return y
function.__name__ = name
function.coefficients = coefficients
return function
def polyderiv(polynomial, d=1):
# Calculates the "d"th derivative of "polynomial"
__ = polynomial.coefficients
for j in range(d):
coefficients = []
for i in range(len(__)-1):
coefficients.append(__[i+1]*(i+1))
__ = coefficients
def function(x):
y = 0
for i in range(len(coefficients)):
y += coefficients[i]*np.power(x, i)
return y
function.__name__ = polynomial.__name__ + "p"*d
function.coefficients = coefficients
return function
def make_splines(x, y, units='units'):
'''
Creates a set of natural cubic splines from x and y and calculates the length of the spline
Returns x's and y's which are the coordinates of the splines, length of the spline, spline polynomial functions
Inputs:
x: vector of x's to be used as spline endpoints
y: vector of y's to be used as spline endpoints
units: string denoting units of length, 'units' by default
Outputs:
_x: vector of x points on splines
_y: vector of y points on splines
s_int: length of spline
s: list of polynomial spline functions
'''
n = len(x)-1
S = np.zeros((4*n,4*n))
C = np.array([[1, 1, 1, 1], [1, 1, 1, 1], [0, 1, 2, 3], [0, 0, 1, 3]])
b = np.zeros(4*n)
'''
Create a matrix whose (i,j)th entry is x[i]^j
'''
X = np.array([list(x) for i in range(4)]).transpose()
for i in range(4):
X[:, i] = X[:, i]**i
'''
Create a coefficient and solution matrix for the cubic spline system
Assume naturual spline condition
'''
for i in range(n):
S[4*i:4*i+2, 4*i:4*(i+1)] = C[:2, :]*X[i:i+2, :]
b[4*i:4*i+2] = y[i:i+2]
if i != n-1:
for j in range(2):
S[4*i+2+j, 4*i+1+j:4*(i+1)] = C[2+j, (1+j):]*X[i+1, :-1-j]
S[4*i+2+j, (4*(i+1)+1+j):4*(i+2)] = -C[2+j, (1+j):]*X[i+1, :-1-j]
elif i == n-1:
S[4*i+2, 4*i+1:4*(i+1)] = C[3, 1:]*X[i+1, :-1]
S[4*i+2, 1:4] = -C[2, 1:]*X[i+1, :-1]
S[4*i+3, 4*i+2:4*(i+1)] = C[3, 2:]*X[i+1, :-2]
splines = la.solve(S,b) # Coefficients of cubic splines
print splines
'''
Create polynomials from the splines' coefficients
Plot the results with a unique color for each spline
'''
s = [polynomial(splines[4*i:4*i+4]) for i in range(n)]
t = [np.linspace(x[i], x[i+1]) for i in range(len(x)-1)]
_x = list()
_y = list()
fig = plt.figure(1)
fig.suptitle('The Ant\'s Path')
ax = fig.add_subplot(111)
s_der = [polyderiv(s[i]) for i in range(n)]
quad_x = [0., np.sqrt(5.-2.*np.sqrt(10./7.))/3., -np.sqrt(5.-2.*np.sqrt(10./7.))/3., np.sqrt(5.+2.*np.sqrt(10./7.))/3., -np.sqrt(5.+2.*np.sqrt(10./7.))/3.]
quad_w = [128./225., (322.+13.*np.sqrt(70))/900., (322.+13.*np.sqrt(70))/900., (322.-13.*np.sqrt(70))/900., (322.-13.*np.sqrt(70))/900.]
s_int = 0
for i in range(n):
_x.extend(list(t[i]))
_y.extend(list(s[i](t[i])))
ax.plot(t[i], s[i](t[i]), label='Spline %s' %i)
'''
Create derivatives of each spline
Calculate the curve length using 5-point Gaussian Quadrature
Print the result
'''
ax.text(x[i], y[i], '%s %s' %("{:.2f}".format(s_int), units))
s_int += ((x[i+1]-x[i])/2.)*np.sum([quad_w[j]*np.sqrt(1.+(s_der[i](((x[i+1]-x[i])/2.)*quad_x[j]+((x[i+1]+x[i])/2.)))**2.) for j in range(5)])
ax.text(x[-1], y[-1], '%s %s' %("{:.2f}".format(s_int), units))
ax.scatter(x,y)
ax.legend(loc=4)
ax.set_xlabel('Location (cm)')
ax.set_ylabel('Location (cm)')
plt.show()
print "The length of the curve is %s %s" %('{:.2f}'.format(s_int), units)
return _x, _y, s_int, s
x = np.array([0, 2, 4, 6, 8])
y = np.array([2, -3, -2, 3, 6])
print make_splines(x, y, 'cm')