我有一个很好的三次样条代码,但它仅用于插值。我需要对未来进行一点推断。有谁知道这样做的好代码源,而不是库?
这是我在基本(现在是 ASM)中编写的用于插值的代码。
你不需要新的代码。
要外推样条曲线,您可以外推第一个和最后一个样条曲线的参数。
根据您现有的代码/库,如果不修改代码可能无法实现。在这种情况下,只需将另外两个点添加到点列表的开头/结尾即可。您可以通过在第一个/最后两个点之间进行线性插值来获得这两个点。
注意:根据点的原始含义,外推可能完全不合适,尤其是在涉及统计数据时。在这种情况下,您应该考虑使用回归分析。
为简单起见,我将三次贝塞尔曲线表示为 4 个点(A、B、C、D),其中 A 和 D 是曲线的端点,B 和 C 是“控制手柄点”。(实际曲线通常不接触控制手柄点)。
请参阅“Don Lancaster's Guru's Lair Cubic Spline Library” 了解如何将这种三次贝塞尔曲线表示转换为其他流行表示。
插值
给定一条三次贝塞尔曲线(P0、P1、P2、P3),我们使用De Casteljau 算法 将贝塞尔曲线分成左半部分和右半部分。即使在没有“乘法”指令的微控制器上,这也非常容易,因为它只需要计算几个平均值,直到我们得到一个中点:
P0
F0 := average(P0, P1)
P1 S0 := average(F0, F1)
F1 := average(P1, P2) Midpoint := average(S0, S1)
P2 S1 := average(F1, F2)
F2 := average(P2, P3)
P3
整个贝塞尔曲线是 (P0, P1, P2, P3)。
整个贝塞尔曲线的左半部分是贝塞尔曲线(P0、F0、S0、M)。
整个贝塞尔曲线的右半部分是贝塞尔曲线(M、S1、F2、P3)。
许多微控制器继续将每条曲线分成越来越小的小曲线,直到每条曲线小到可以近似为一条直线。
但我们想走另一条路——外推到更大的曲线。
外推
给定左半部分或右半部分,我们可以反向运行以恢复原始曲线。
假设我们忘记了原始点 P1、P2、P3。
给定贝塞尔曲线的左半部分(P0,F0,S0,M),我们可以向右外推:
S1 := M + (M - S0)
F1 := S0 + (S0 - F0)
P1 := F0 + (F0 - P0)
然后使用这些值来计算
F2 := S1 + (S1 - F1)
P2 := F1 + (F1 - P1)
最后
P3 := F2 + (F2 - P2)
外推并恢复外推的 Bazier 曲线(P0、P1、P2、P3)。
细节
外推曲线 (P0, P1, P2, P3) 穿过原始曲线 (P0, F0, S0, M) 中的每个点 - 特别是从 P0 开始并穿过中点 M - 并一直持续到它达到P3。
我们总是可以从任何 4 个点(P0、F0、S0、M)进行推断,无论这 4 个点最初是否计算为某个较大贝塞尔样条的左半部分(或右半部分)。
我相信您已经知道这一点,但只是为了清楚起见:
Midpoint = average(F0, F1)
意思是“找到点 F0 和 F1 之间的中点”,或者换句话说,
Midpoint.x = (F0.x + F1.x)/2
Midpoint.y = (F0.y + F1.y)/2
Midpoint.z = (F0.z + F1.z)/2
表达方式
S1 := M + (M - S0)
意思是“给定一条线段,一端在 S0,中点在 M,从 S0 开始并沿直线经过 M,直到在 S1 到达另一端”,或者换句话说(除非你有一个像样的向量库)3行代码
S1.x := M.x + (M.x - S0.x)
S1.y := M.y + (M.y - S0.y)
S1.z := M.z + (M.z - S0.z)
. (如果你在做 2D,跳过所有“z”的东西——它总是零)。
你真的需要稍微扩展一下这个问题。此外,“三次样条”是一个非常广泛的术语。
如果您对样条线感兴趣,我可以衷心推荐 Carl de Boors 的“样条线实用指南”。然而,它有点数学导向,但包含代码示例(可以从作者的主页下载)。谷歌搜索和维基搜索“三次样条”可以提出一些例子,甚至可能是特定语言 - 另一件事要添加到问题中(如果您正在寻找代码)。
如果您对外推和曲线拟合感兴趣,谷歌搜索可能会有所帮助。Matlab 包有一个非常好的曲线拟合工具箱。维基百科有一些有用参考的链接
真的,这是一个太宽泛的问题,甚至无法开始猜测答案。
另外,你能解释一下你到底想做什么吗?什么样的数据?任何事物 ?
Edit1:在这里,试试这个:你可能会在这里找到有用的东西 -链接
通常对于样条插值,您使用变量 t 在线上进行插值。只要 0 <= t <= 1 你在插值。但是,当 t < 0 或 t > 1 时,您只是在外推样条曲线。
您需要为请求的代码编写更好的要求。样条通常用于通过使用一些固定数据集对一些未知或复杂函数进行插值。如果你想在这个数据集的边界之外估计函数的值,那么你不应该使用样条。
如果您的样条是在您真正想要评估您的值(三次,但不是分段三次)的地方定义的函数,那么您已经可以评估该值。
如果您希望能够在插值范围之外评估样条曲线,但将其保留为在插值范围内具有相同值的分段三次函数,那么您应该通过一些节点扩展样条曲线范围,并在新节点(例如,您希望样条曲线不仅是连续函数,而且还有一些一阶导数也是连续函数)
真的,我建议您使用一些更适合外推的算法,例如使用拉格朗日多项式,如果您真正需要的一切都是离原始数据集点不远的单个值。