【问题标题】:How to make cubic spline interpolation algorithm faster?如何使三次样条插值算法更快?
【发布时间】:2017-01-13 18:56:53
【问题描述】:

我意识到,当我使用“la_solve”时,由于“la_solve”可以处理的样本数量有限,我得到了 Malloc 错误。

我注意到如果我使用大约 900 个样本,程序运行良好。

因此,我修改了我的代码,如果样本 > 901,则以 901 个样本的顺序块查看整个数据。

但是,我使用了相当幼稚的技术,并且确信这可以变得更加高效和稳健:(1)我需要一个条件,即如果样本

我最需要帮助的是代码末尾的“//调用重采样函数”部分

谢谢!!!

import UIKit
import Accelerate.vecLib.LinearAlgebra

public class Resample {

public class func resample(xi: [Double], xii: [Double], a: [Double]) ->[Double]
{
    // xi - original time stamps (original x)
    // xii - desired time stamps (desired x)
    // a - orignal y values
    // ->[Double] - interpolated y values

    let ni = xii.count // Desired x count

    let n = xi.count // Actual x count

    var h: [Double] = Array(repeating:0, count:n-1)

    for j in 0..<n-1 {
        h[j] = (xi[j+1] - xi[j])
    }

    var A: [Double] = Array(repeating:0, count:(n)*(n))

    A[0] = 1.0

    A[(n*n)-1] = 1.0

    for i in 1..<(n-1) {
        A[(n+1)*i-1] = h[i-1]
        A[(n+1)*i] = 2*(h[i-1] + h[i])
        A[(n+1)*i+1] = h[i]
    }

    var b: [Double] = Array(repeating:0, count:n)

    for i in 1..<n-1 {
        b[i] = (3/h[i])*(a[i+1]-a[i]) - (3/h[i-1])*(a[i]-a[i-1])
    }

    let matA = la_matrix_from_double_buffer(A, la_count_t(n), la_count_t(n), la_count_t(n), la_hint_t(LA_NO_HINT), la_attribute_t(LA_DEFAULT_ATTRIBUTES))

    let vecB = la_matrix_from_double_buffer(b, la_count_t(n), 1, 1, la_hint_t(LA_NO_HINT), la_attribute_t(LA_DEFAULT_ATTRIBUTES))

    let vecCj = la_solve(matA, vecB)

    var cj: [Double] = Array(repeating: 0.0, count: n)

    let status = la_matrix_to_double_buffer(&cj, 1, vecCj)

    if status == la_status_t(LA_SUCCESS) {
        //print(cj.count)
    }
    else {
        print("Failure: \(status)")
    }

    var bj: [Double] = Array(repeating:0, count:n-1)

    for i in 0..<n-1 {
        bj[i] = (1/h[i])*(a[i+1]-a[i]) - (1/3*h[i])*(2*cj[i]+cj[i+1])
    }

    var dj: [Double] = Array(repeating:0, count:n-1)

    for i in 0..<n-1 {
        dj[i] = (1/(3*h[i])) * (cj[i+1]-cj[i])
    }

    var P: [Double] = Array(repeating: 0.0, count: (n-1)*4)

    for i in 0..<n-1 {
        P[(i*4)] = dj[i]
        P[(i*4)+1] = cj[i]
        P[(i*4)+2] = bj[i]
        P[(i*4)+3] = a[i]
    }

    var ai: [Double] = Array(repeating: 0.0, count: ni)


    var jl = Double(1)

    for i in 0..<ni {

        let inter = Double(xii[i])

        while (inter > xi[Int(jl)] && (Int(jl) < n)) {
            jl += 1

        }

        let ind = 4*Int(jl)-4

        var pp = Array(P[ind...ind+3])

        let xx = Double(xii[i]-xi[Int(jl)-1])

        ai[i] = pp[0]*pow(xx, 3) + pp[1]*pow(xx, 2) + pp[2]*xx + pp[3]
    }
    return(ai)
}
}



 // Calling the Re-sampler FUNCTION

let x = Array(stride(from: 0, through: 16649, by: 1.0)) // Orig X (Given, say)

let y = Array(stride(from: 0, through: 16649, by: 1.0)) // Orig Y (Given, say)

let f = 2.0 // Hz (Desired Sampling Freq., say)

let g = Array(stride(from: 0, through: x.count-1, by: 900))
// Helper array for chunking (901 samples each time, say)

var xxx = [Double]() // Results for appended chunks X

var yyy = [Double]() // Results for appended chunks Y

for i in 0..<g.count-1 { // loop through

let xc = Array(x[Int(g[i])...Int(g[i+1])]) // x chunk (count = 901)

let yc = Array(y[Int(g[i])...Int(g[i+1])]) // y chunk (count = 901)

let xci = Array(stride(from: xc[0], through: xc[xc.count-1], by: 1.0/f))
// Desired time stamps for chunk of 901 samples

let yci = Resample.resample(xi: xc, xii: xci, a: yc) // Interpolate chunk

xxx += xci // Append interpolation X

yyy += yci // Append interpolation X

}

if(Int(g[g.count-1])<x.count){
// If helper function last index < original no. of samples

let glb = (Int(g[g.count-1])) // last chunk begin index

let gle = (x.count) // last chunk end index

let xce = Array(x[glb...gle-1]) // last x chunk

let yce = Array(y[glb...gle-1]) // last y chunk

let xcei = Array(stride(from: xce[0], through: xce[xce.count-1], by: 1.0/f))
// Desired time stamps for last chunk of samples

let ycei = Resample.resample(xi: xce, xii: xcei, a: yce) // Interpolate last chunk

xxx += xcei // Append interpolation X for last chunk

yyy += ycei // Append interpolation X for last chunk
}

print(xxx) // would like to identify repeated x values and remove them
print(yyy) // remove y values corresponsding to repated x values (as found above)

// Calling the Re-sampler FUNCTION

【问题讨论】:

    标签: swift algorithm optimization


    【解决方案1】:

    请注意,您正在使用二进制搜索寻找每个 ind,而它的值是单调递增的。因此,您只需检查下一个 x 值是否保持在相同的间隔内或移动到下一个。伪代码:

     jl = 1  //before cycle
    
     //inside cycle
      while (current_x > xi[jl]) and (jl < n)
        jl++
      ind = 4 * jl - 4
    

    la_solve是线性eq.system求解的通用方法吗?如果是,那么您最好对三对角系统使用专用方法(三次复杂度与线性复杂度)。 Classic textPython implementationWiki。这对于长输入数组很重要。

    【讨论】:

    • 感谢 MBo 的反馈!我知道那里的while循环会导致延迟。我不确定我应该使用什么确切的语法来使它更快。是的,la_solve 是求解线性方程组的通用方法。我会按照你的建议搜索并查看三对角系统。
    • 我实现了你的伪代码 MBo。结果是一样的,程序变得更快但仍然很慢。它在 Mac 模拟器上给出了结果,但是当我尝试在我的 iPhone 上安装/运行它时崩溃。我正在寻找一种让它变得非常快的方法。谢谢!!!!
    • 您的数据集有多大,您需要多久构建一次插值?您是否测量/分析了最慢的代码部分?
    • 数据集最初以 250 Hz 采样,典型时长约为 65 秒。也就是说,X 和 Y 向量中大约有 17,000 个样本。我确实运行了分析器,发现 Malloc 变红了——我不完全理解。在 iPhone 上运行,出现以下错误:CUBIC_PROFILE_2(919,0x16df8f000) malloc: *** mach_vm_map(size=2217787392) failed (error code=3) *** error: can't allocate region *** set a breakpoint in malloc_error_break 进行调试
    • 我不了解 Swift 内存分配范式和实践,但通常可以分配一次大数组并在每次函数调用时重用它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多