从传入数据点生成平滑曲线的算法
Algorithm for generating smooth curves from incoming data points
我正在寻找一种算法,可以在 实时 中平滑地插入点。
例如,假设我从一个包含 10 个 (x,y) 对的数组开始。我目前正在使用 scipy 和高斯 window 来生成平滑曲线。然而,我无法弄清楚的是如何更新平滑曲线以响应在未来某个点生成的第 11 个点(而不完全重做所有 11 个点的平滑)。
我要找的是一种算法,它遵循前面的平滑曲线直到第 10 个 (x,y) 对 和 也 在第 10 对和第 11 对之间平滑地插值(以类似于重做整个算法的方式 - 所以没有尖锐的边缘)。有什么东西可以满足我的需求吗?
我想你可以使用 Cubic Spline。给定 n
个点 (x_1, y_1)..(x_n, y_n)
的列表,该算法在 (x_k, y_k)
和 (x_{k+1}, y_{k+1})
之间找到一个三次多项式 p_k
,具有以下约束:
- 多项式
p_k
和p_{k+1}
通过点(x_{k+1}, y_{k+1})
;
- 多项式
p_k
和 p_{k+1}
在 (x_{k+1}, y_{k+1})
处具有相同的一阶导数;
- 多项式
p_k
和 p_{k+1}
在 (x_{k+1}, y_{k+1})
处具有相同的二阶导数。
此外,还有一些边界条件,为第一个和最后一个多项式定义。我使用了 natural
,它强制二阶导数在曲线末端为零。
您可以应用的步骤是:
- 使用三次样条插值前 10 个点。
- 将
p_10
处的一阶微分值赋给变量d
。
- 运行
p_10
和 p_11
的三次样条,强制 p_10
处的一阶导数为 d
且 [= 处的二阶导数30=] 为零。
从那里,您可以对剩余的点重复相同的步骤。
此代码将为所有点生成插值:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import CubicSpline
height=4
n = 20
x = np.arange(n)
xs = np.arange(-0.1,n+0.1,0.1)
y = np.random.uniform(low=0, high=height, size=n)
plt.plot(x, y, 'o', label='data')
cs = CubicSpline(x, y)
plt.plot(xs, cs(xs), color='orange')
plt.ylim([0, height+1])
现在,此代码将对前 10 个点进行插值,然后在点 10 和 11 之间进行另一个插值:
k = 10
delta = 0.001
plt.plot(x, y, 'o', label='data')
xs = np.arange(x[0], x[k-1]+delta, delta)
cs = CubicSpline(x[0:k], y[0:k])
plt.plot(xs, cs(xs), color='red')
d = cs(x[k-1], 1)
xs2 = np.arange(x[k-1], x[k]+delta, delta)
cs2 = CubicSpline(x[k-1:k+1], y[k-1:k+1], bc_type=((1, d), 'natural'))
plt.plot(xs2, cs2(xs2), color='blue')
plt.ylim([0, height+1])
我正在寻找一种算法,可以在 实时 中平滑地插入点。
例如,假设我从一个包含 10 个 (x,y) 对的数组开始。我目前正在使用 scipy 和高斯 window 来生成平滑曲线。然而,我无法弄清楚的是如何更新平滑曲线以响应在未来某个点生成的第 11 个点(而不完全重做所有 11 个点的平滑)。
我要找的是一种算法,它遵循前面的平滑曲线直到第 10 个 (x,y) 对 和 也 在第 10 对和第 11 对之间平滑地插值(以类似于重做整个算法的方式 - 所以没有尖锐的边缘)。有什么东西可以满足我的需求吗?
我想你可以使用 Cubic Spline。给定 n
个点 (x_1, y_1)..(x_n, y_n)
的列表,该算法在 (x_k, y_k)
和 (x_{k+1}, y_{k+1})
之间找到一个三次多项式 p_k
,具有以下约束:
- 多项式
p_k
和p_{k+1}
通过点(x_{k+1}, y_{k+1})
; - 多项式
p_k
和p_{k+1}
在(x_{k+1}, y_{k+1})
处具有相同的一阶导数; - 多项式
p_k
和p_{k+1}
在(x_{k+1}, y_{k+1})
处具有相同的二阶导数。
此外,还有一些边界条件,为第一个和最后一个多项式定义。我使用了 natural
,它强制二阶导数在曲线末端为零。
您可以应用的步骤是:
- 使用三次样条插值前 10 个点。
- 将
p_10
处的一阶微分值赋给变量d
。 - 运行
p_10
和p_11
的三次样条,强制p_10
处的一阶导数为d
且 [= 处的二阶导数30=] 为零。
从那里,您可以对剩余的点重复相同的步骤。
此代码将为所有点生成插值:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import CubicSpline
height=4
n = 20
x = np.arange(n)
xs = np.arange(-0.1,n+0.1,0.1)
y = np.random.uniform(low=0, high=height, size=n)
plt.plot(x, y, 'o', label='data')
cs = CubicSpline(x, y)
plt.plot(xs, cs(xs), color='orange')
plt.ylim([0, height+1])
现在,此代码将对前 10 个点进行插值,然后在点 10 和 11 之间进行另一个插值:
k = 10
delta = 0.001
plt.plot(x, y, 'o', label='data')
xs = np.arange(x[0], x[k-1]+delta, delta)
cs = CubicSpline(x[0:k], y[0:k])
plt.plot(xs, cs(xs), color='red')
d = cs(x[k-1], 1)
xs2 = np.arange(x[k-1], x[k]+delta, delta)
cs2 = CubicSpline(x[k-1:k+1], y[k-1:k+1], bc_type=((1, d), 'natural'))
plt.plot(xs2, cs2(xs2), color='blue')
plt.ylim([0, height+1])