Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numerical calculation of curvature

I would like to calculate local curvature i.e at each point. I have a set of data points that a equally spaced in x. Below is the code for generating curvature.

data=np.loadtxt('newsorted.txt') #data with uniform spacing
x=data[:,0]
y=data[:,1]

dx = np.gradient(data[:,0]) # first derivatives
dy = np.gradient(data[:,1])

d2x = np.gradient(dx) #second derivatives
d2y = np.gradient(dy)

cur = np.abs(d2y)/(1 + dy**2))**1.5 #curvature

Below is the image of curvature (magenta) and its comparison with analytical (equation: -0.02*(x-500)**2 + 250)(solid green) curvature

Why does there is so much deviation between the two? How to get exact values that of analytical.

Help appreciated.

like image 294
newstudent Avatar asked May 30 '18 12:05

newstudent


Video Answer


1 Answers

I've been playing a bit with your values and i've found that they aren't smooth enough to compute curvature. In fact, even the first derivative is flawed. Here is why : Few plots of given data and my interpolation

You can see in blue your data looks like a parabola, and it's derivative should look like a straight line but it does not. And it get worse when you take the second derivative. In red this is a smooth parabola computed with 10000 points (tried with 100 points, it works the same : perfect lines and curvature). I made a little script to 'enrich' your data, increasing artificially the number of points but it only get worse, here is my script if you want to try.

import numpy as np
import matplotlib.pyplot as plt

def enrich(x, y):
    x2 = []
    y2 = []
    for i in range(len(x)-1):
        x2 += [x[i], (x[i] + x[i+1]) / 2]
        y2 += [y[i], (y[i] + y[i + 1]) / 2]
    x2 += [x[-1]]
    y2 += [y[-1]]
    assert len(x2) == len(y2)
    return x2, y2

data = np.loadtxt('newsorted.txt')
x = data[:, 0]
y = data[:, 1]

for _ in range(0):
    x, y = enrich(x, y)

dx = np.gradient(x, x)  # first derivatives
dy = np.gradient(y, x)

d2x = np.gradient(dx, x)  # second derivatives
d2y = np.gradient(dy, x)

cur = np.abs(d2y) / (np.sqrt(1 + dy ** 2)) ** 1.5  # curvature


# My interpolation with a lot of points made quickly
x2 = np.linspace(400, 600, num=100)
y2 = -0.0225*(x2 - 500)**2 + 250

dy2 = np.gradient(y2, x2)

d2y2 = np.gradient(dy2, x2)

cur2 = np.abs(d2y2) / (np.sqrt(1 + dy2 ** 2)) ** 1.5  # curvature

plt.figure(1)

plt.subplot(221)
plt.plot(x, y, 'b', x2, y2, 'r')
plt.legend(['new sorted values', 'My interpolation values'])
plt.title('y=f(x)')
plt.subplot(222)
plt.plot(x, cur, 'b', x2, cur2, 'r')
plt.legend(['new sorted values', 'My interpolation values'])
plt.title('curvature')
plt.subplot(223)
plt.plot(x, dy, 'b', x2, dy2, 'r')
plt.legend(['new sorted values', 'My interpolation values'])
plt.title('dy/dx')
plt.subplot(224)
plt.plot(x, d2y, 'b', x2, d2y2, 'r')
plt.legend(['new sorted values', 'My interpolation values'])
plt.title('d2y/dx2')

plt.show()

My recommendation would be to interpolate your data with a parabola and compute as many points on this interpolation to work with.

like image 141
pLOPeGG Avatar answered Oct 24 '22 15:10

pLOPeGG