代码之家  ›  专栏  ›  技术社区  ›  Tom Wenseleers

用与R的B s()函数相同的方法在Matlab中计算B样条基

  •  6
  • Tom Wenseleers  · 技术社区  · 8 年前

    我在Matlab中寻找(一个理想的内置)函数,该函数以与R中相同的方式计算B样条基矩阵,例如,对于具有20个等距节点的3次样条基,我将在R中执行

    require(splines)
    B = bs(x = seq(0,1,length.out=100),
            knots = seq(0, 1, length.out=20), # 20 knots
            degree = 3,
            intercept = FALSE)
    matplot(B,type="l")
    

    enter image description here

    为了在Matlab中得到同样的结果,我想我可以使用

    B = spcol(linspace(0,1,20),3,linspace(0,1,100));
    plot(B);
    

    enter image description here

    但可以看到,当时的边界节点已不复存在。 有没有想过在Matlab中使用什么等效语法来获得与R中相同的结果?

    PS R用于的代码 bs() 有点简单:

    basis <- function(x, degree, i, knots) {
      if(degree == 0){
        B <- ifelse((x >= knots[i]) & (x < knots[i+1]), 1, 0)
      } else {
        if((knots[degree+i] - knots[i]) == 0) {
          alpha1 <- 0
        } else {
          alpha1 <- (x - knots[i])/(knots[degree+i] - knots[i])
        }
        if((knots[i+degree+1] - knots[i+1]) == 0) {
          alpha2 <- 0
        } else {
          alpha2 <- (knots[i+degree+1] - x)/(knots[i+degree+1] - knots[i+1])
        }
        B <- alpha1*basis(x, (degree-1), i, knots) + alpha2*basis(x, (degree-1), (i+1), knots)
      }
      return(B)
    }
    
    bs <- function(x, degree=3, interior.knots=NULL, intercept=FALSE, Boundary.knots = c(0,1)) {
      if(missing(x)) stop("You must provide x")
      if(degree < 1) stop("The spline degree must be at least 1")
      Boundary.knots <- sort(Boundary.knots)
      interior.knots.sorted <- NULL
      if(!is.null(interior.knots)) interior.knots.sorted <- sort(interior.knots)
      knots <- c(rep(Boundary.knots[1], (degree+1)), interior.knots.sorted, rep(Boundary.knots[2], (degree+1)))
      K <- length(interior.knots) + degree + 1
      B.mat <- matrix(0,length(x),K)
      for(j in 1:K) B.mat[,j] <- basis(x, degree, j, knots)
      if(any(x == Boundary.knots[2])) B.mat[x == Boundary.knots[2], K] <- 1
      if(intercept == FALSE) {
        return(B.mat[,-1])
      } else {
        return(B.mat)
      }
    }
    
    1 回复  |  直到 8 年前
        1
  •  9
  •   Wolfie Radu Stefan    8 年前

    你的代码出了两个问题

    1. 我想这里有些混乱 秩序 . 您正确指定了 degree=3 在R代码中,但在MATLAB中,参数传递给 spcol 秩序 样条曲线的一般来说, 有序样条函数 n 是次数的分段多项式 n-1 . [ 1 ]

      因为MATLAB的 spcol公司 接受 秩序 作为输入,您需要指定 order=4 而不是你认为你做了什么 度=3 ! 你在Matlab中生成了一个二次样条,在R中生成了一个三次样条。

    2. 看起来R图中的结束节点具有非奇异多重性,我的意思是它们是重复的使端点具有多重性 degree+1 (在我们的例子中是4)意味着它们的位置与控制多边形重合,这些被称为 夹紧的 结。[ 2 ]

      R documentation for bs 它声明knots数组包含 内部的 断点看起来边界节点被定义为在较长的代码示例中被钳制,因为它们是重复的 学位+1 时间,在这条线上:

      knots <- c(rep(Boundary.knots[1], (degree+1)), interior.knots.sorted, rep(Boundary.knots[2], (degree+1)))
      

      这对于钳制的端点来说是有意义的,并支持关于使用 输入。

      因此,在Matlab中,我们的节点向量(带固定端点)应该是:

      k = [0, 0, 0, linspace(0,1,20), 1, 1, 1]
      

    结论

    让我们用 秩序 4,和一个节点向量,在端点处有固定的节点:

    B = spcol([0, 0, 0, linspace(0,1,20), 1, 1, 1], 4, linspace(0,1,100)); 
    plot(B);
    

    b spline basis MATLAB

    我们现在可以看到边界节点,就像它们在r图中一样,并且在每一端有两个附加的峰值,这是由于3度钳制节点的影响而变小的。


    进一步阅读

    [ ]:维基百科B样条曲线页面

    [ ]:麻省理工学院的有用页面,更深入地描述了夹紧节点和数学。