使用 scipy 从节点和系数创建样条
Create spline from knots and coefficients using scipy
我正在尝试从论文中重现一个函数,该函数仅根据样条结和系数指定。在找到 之后,给定一个 scipy 插值对象,根据它的节点和系数,我可以重新创建 scipy 插值。但是,该方法无法实现本文中指定的功能。要重现 scipy 插值,我可以这样做:
using PyCall, PyPlot, Random
Random.seed!(5)
sp = pyimport("scipy.interpolate")
x = LinRange(0,1,50)
y = (0.9 .+ 0.1rand(length(x))).*sin.(2*pi*(x.-0.5))
t = collect(x[2:2:end-1]) # knots
s1 = sp.LSQUnivariateSpline(x, y, t)
x2 = LinRange(0, 1, 200) # new x-grid
y2 = s1(x2) # evaluate spline on that new grid
figure()
plot(x, y, label="original")
plot(x2, y2, label="interp", color="k")
knots = s1.get_knots()
c = s1.get_coeffs()
newknots(knots, k) = vcat(fill(knots[1],k),knots,fill(knots[end],k)) # func for boundary knots of order k
forscipyknots = newknots(knots, 3)
s2 = sp.BSpline(forscipyknots, c, 3)
y3 = s2(x2)
plot(x2,y3,"--r", label="reconstructed \nfrom knots and coeff")
legend()
它按预期提供了以下内容:
尝试重现具有指定 knots = [.4,.4,.4,.4,.7]
和系数 c = [2,-5,5,2,-3,-1,2]
的函数(下图)应该产生:
使用下面的代码和上面的结和系数:
knots = [.4,.4,.4,.4,.7]
c = [2,-5,5,2,-3,-1,2]
forscipyknots = newknots(knots, 3)
s2 = sp.BSpline(forscipyknots, c, 3)
figure()
plot(x2, s2(x2))
我得到的是以下(下方)。我确定我弄乱了边界结 - 我该如何解决这个问题?
简答:
内结序列t=[0.4,0.4,0.4,0.4,0.7]
和参数c=[2,-5,5,2,-3,-1,2]
不允许构造样条,该示例包含错误(稍后详细介绍)。你能得到的最好的办法是移除一个 0.4
结并构造一个二次(二阶)样条,如下所示
tt = [0.0,0.0,0.0,0.4,0.4,0.4,0.7,1.0,1.0,1.0]
c = [2,-5,5,2,-3,-1,2]
s2 = BSpline(tt,c,2)
这会产生下图
长答案:
示例3中的节点序列只包含内部节点,因此,您需要添加边界节点。由于您想在区间 [0,1]
上评估样条,因此完整的结序列需要覆盖点 0 和 1。最简单的方法是在序列的开头添加 0,在序列的结尾添加 1,并根据需要复制它们根据所需的样条阶数。三次(三次)样条需要四个边界结(即四个零和四个一),二次样条需要三个边界结(三个零和三个一)。
但是有一个问题。三次样条需要 9 个参数,而示例 3 只给你 7 个。因此,你不能由此构造三次样条。使用给定的七个参数,您可以构建二次样条,但是,问题是对于二次样条,每个点在内结序列中最多只能出现三次。 0.4 出现了四次(这表明三次样条)。因此,您所能做的就是移除其中一个 0.4 节并构建二阶样条,如上面的简短答案所示。
现在我来解释一下你做错了什么。在第一个示例中,您使用 knots = s1.get_knots()
从现有样条曲线获得了结序列,这给了您 knots=[0,0.02,0.04,...,0.98,1]
。该序列包含边界节点 0 和 1(尽管只有一次)。因此,为了构建三次样条,您将这三次样条中的每一次都复制了一次以获得 forscipyknots = [0,0,0,0,0.02,0.04,...,0.98,1,1,1,1]
。到目前为止,一切都很好。
然而,在示例3中,结序列不包含边界点。正如您之前所做的那样,您最终将 0.4 和 0.7 节复制了三次,结果是 forscipyknots = [0.4,0.4,0.4,0.4,0.4,0.4,0.4,0.7,0.7,0.7,0.7]
。您不能在此序列上构建样条曲线,无论从中得出什么都不是样条曲线。您需要的是 forscipyknots = [0.0,0.0,0.0,0.0,0.4,0.4,0.4,0.4,0.7,1.0,1.0,1.0,1.0]
(这不会起作用,因为您没有足够的系数;但您可以尝试自己的系数,例如 c = [1,2,-5,5,2,-3,-1,2,1]
)。为此,您需要将 0 添加到数组的开头,将 1 添加到数组的末尾,然后才使用 newknots
函数。
举个例子,三次样条曲线可能看起来像这样
tt = [0.0,0.0,0.0,0.0,0.4,0.4,0.4,0.4,0.7,1.0,1.0,1.0,1.0]
c = [1,2,-5,5,2,-3,-1,2,1]
s2 = BSpline(tt,c,3)
我正在尝试从论文中重现一个函数,该函数仅根据样条结和系数指定。在找到
using PyCall, PyPlot, Random
Random.seed!(5)
sp = pyimport("scipy.interpolate")
x = LinRange(0,1,50)
y = (0.9 .+ 0.1rand(length(x))).*sin.(2*pi*(x.-0.5))
t = collect(x[2:2:end-1]) # knots
s1 = sp.LSQUnivariateSpline(x, y, t)
x2 = LinRange(0, 1, 200) # new x-grid
y2 = s1(x2) # evaluate spline on that new grid
figure()
plot(x, y, label="original")
plot(x2, y2, label="interp", color="k")
knots = s1.get_knots()
c = s1.get_coeffs()
newknots(knots, k) = vcat(fill(knots[1],k),knots,fill(knots[end],k)) # func for boundary knots of order k
forscipyknots = newknots(knots, 3)
s2 = sp.BSpline(forscipyknots, c, 3)
y3 = s2(x2)
plot(x2,y3,"--r", label="reconstructed \nfrom knots and coeff")
legend()
它按预期提供了以下内容:
尝试重现具有指定 knots = [.4,.4,.4,.4,.7]
和系数 c = [2,-5,5,2,-3,-1,2]
的函数(下图)应该产生:
使用下面的代码和上面的结和系数:
knots = [.4,.4,.4,.4,.7]
c = [2,-5,5,2,-3,-1,2]
forscipyknots = newknots(knots, 3)
s2 = sp.BSpline(forscipyknots, c, 3)
figure()
plot(x2, s2(x2))
我得到的是以下(下方)。我确定我弄乱了边界结 - 我该如何解决这个问题?
简答:
内结序列t=[0.4,0.4,0.4,0.4,0.7]
和参数c=[2,-5,5,2,-3,-1,2]
不允许构造样条,该示例包含错误(稍后详细介绍)。你能得到的最好的办法是移除一个 0.4
结并构造一个二次(二阶)样条,如下所示
tt = [0.0,0.0,0.0,0.4,0.4,0.4,0.7,1.0,1.0,1.0]
c = [2,-5,5,2,-3,-1,2]
s2 = BSpline(tt,c,2)
这会产生下图
长答案:
示例3中的节点序列只包含内部节点,因此,您需要添加边界节点。由于您想在区间 [0,1]
上评估样条,因此完整的结序列需要覆盖点 0 和 1。最简单的方法是在序列的开头添加 0,在序列的结尾添加 1,并根据需要复制它们根据所需的样条阶数。三次(三次)样条需要四个边界结(即四个零和四个一),二次样条需要三个边界结(三个零和三个一)。
但是有一个问题。三次样条需要 9 个参数,而示例 3 只给你 7 个。因此,你不能由此构造三次样条。使用给定的七个参数,您可以构建二次样条,但是,问题是对于二次样条,每个点在内结序列中最多只能出现三次。 0.4 出现了四次(这表明三次样条)。因此,您所能做的就是移除其中一个 0.4 节并构建二阶样条,如上面的简短答案所示。
现在我来解释一下你做错了什么。在第一个示例中,您使用 knots = s1.get_knots()
从现有样条曲线获得了结序列,这给了您 knots=[0,0.02,0.04,...,0.98,1]
。该序列包含边界节点 0 和 1(尽管只有一次)。因此,为了构建三次样条,您将这三次样条中的每一次都复制了一次以获得 forscipyknots = [0,0,0,0,0.02,0.04,...,0.98,1,1,1,1]
。到目前为止,一切都很好。
然而,在示例3中,结序列不包含边界点。正如您之前所做的那样,您最终将 0.4 和 0.7 节复制了三次,结果是 forscipyknots = [0.4,0.4,0.4,0.4,0.4,0.4,0.4,0.7,0.7,0.7,0.7]
。您不能在此序列上构建样条曲线,无论从中得出什么都不是样条曲线。您需要的是 forscipyknots = [0.0,0.0,0.0,0.0,0.4,0.4,0.4,0.4,0.7,1.0,1.0,1.0,1.0]
(这不会起作用,因为您没有足够的系数;但您可以尝试自己的系数,例如 c = [1,2,-5,5,2,-3,-1,2,1]
)。为此,您需要将 0 添加到数组的开头,将 1 添加到数组的末尾,然后才使用 newknots
函数。
举个例子,三次样条曲线可能看起来像这样
tt = [0.0,0.0,0.0,0.0,0.4,0.4,0.4,0.4,0.7,1.0,1.0,1.0,1.0]
c = [1,2,-5,5,2,-3,-1,2,1]
s2 = BSpline(tt,c,3)