【问题标题】:Linear resampling datapoints captured at fluctuating time intervals, to flxed time intervals, in swift以波动的时间间隔捕获的线性重采样数据点,到固定的时间间隔,迅速
【发布时间】:2015-12-24 09:36:49
【问题描述】:

我想将一些在波动时捕获的指标线性插值到固定的时间间隔。

let original_times:[Double] = [0.0,1.3,2.2,3.4,4.2,5.5,6.6,7.2,8.4,9.5,10.0]
let metric_1:[Double] = [4,3,6,7,4,5,7,4,2,7,2]

let wanted_times:[Double] = [0,1,2,3,4,5,6,7,8,9,10]

//linearly resample metric_1 (with corresponding sampling times 'original_times') to fixed time interval times 'wanted_times'

Accelerate 提供vDSP_vlint,但我正在努力弄清楚如何为我的应用程序实现它。

func vDSP_vlint(_ __A: UnsafePointer<Float>, _ __B: UnsafePointer<Float>, _ __IB: vDSP_Stride, _ __C: UnsafeMutablePointer<Float>, _ __IC: vDSP_Stride, _ __N: vDSP_Length, _ __M: vDSP_Length)

【问题讨论】:

    标签: swift accelerate-framework vdsp


    【解决方案1】:

    我不明白你想 100% 做的数学运算,但我明白如何使用 Accelerate。我创建了一个函数,它可以更轻松地调用这个 Accelerate 函数并向您展示它是如何工作的。

    /**
     Vector linear interpolation between neighboring elements
    
     - Parameter a: Input vector.
     - Parameter b: Input vector: integer parts are indices into a and fractional parts are interpolation constants.
    
     Performs the following operation:
    
     ```C
     for (n = 0; n < N; ++n) {
        double b = B[n];
        double index = trunc([b]); //int part of B value
        double alpha = b - index; //frac part of B value
    
        double a0 = A[(int)index];     //indexed A value
        double a1 = A[(int)index + 1]; //next A value
    
        C[n] = a0 + (alpha * (a1 -a0)); //interpolated value
     }
     ```
     Generates vector C by interpolating between neighboring values of vector A as controlled by vector B. The integer portion of each element in B is the zero-based index of the first element of a pair of adjacent values in vector A.
    
     The value of the corresponding element of C is derived from these two values by linear interpolation, using the fractional part of the value in B.
    */
    func interpolate(inout a: [Double], inout b: [Double]) -> [Double] {
        var c = [Double](count: b.count, repeatedValue: 0)
        vDSP_vlintD(&a, &b, 1, &c, 1, UInt(b.count), UInt(a.count))
        return c
    }
    

    编辑:好的,我已经解决了你的问题,我现在明白你想要做什么了。做起来很有趣,我想出了这个:

    import Accelerate
    
    func calculateB(sampleTimes: [Double], outputTimes: [Double]) -> [Double] {
        var i = 0
        return outputTimes.map { (time: Double) -> Double in
            defer {
                if time > sampleTimes[i] { i++ }
            }
            return Double(i) + (time - sampleTimes[i]) / (sampleTimes[i+1] - sampleTimes[i])
        }
    }
    
    func interpolate(inout b: [Double], inout data: [Double]) -> [Double] {
        var c = [Double](count: b.count, repeatedValue: 0)
        vDSP_vlintD(&data, &b, 1, &c, 1, UInt(b.count), UInt(data.count))
        return c
    }
    
    
    let sampleTimes : [Double] = [0.0, 1.3, 2.2, 3.4, 4.2, 5.5, 6.6, 7.2, 8.4, 9.5, 10.0]
    let outputTimes : [Double] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    var metric_1 : [Double] = [4, 3, 6, 7, 4, 5, 7, 4, 2, 7, 2]
    var metric_2 : [Double] = [5, 4, 7, 5, 6, 6, 1, 3, 1, 6, 7]
    var metric_3 : [Double] = [9, 8, 5, 7, 4, 8, 5, 6, 8, 9, 5]
    
    var b = calculateB(sampleTimes, outputTimes: outputTimes)
    
    interpolate(&b, data: &metric_1)   // [4, 3.230769, 5.333333, 6.666667, 4.75, 4.615385, 5.909091, 5, 2.666667, 4.727273, 2]
    interpolate(&b, data: &metric_2)   // [5, 4.230769, 6.333333, 5.666667, 5.75, 6, 3.727273, 2.333333, 1.666667, 3.727273, 7]
    interpolate(&b, data: &metric_3)   // [9, 8.230769, 5.666667, 6.333333, 4.75, 6.461538, 6.636364, 5.666667, 7.333333, 8.545455, 5]
    

    变量是 Accelerate 所必需的。我不知道如何使用 Accelerate 完成 calculateB,我的意思是我认为有可能,但是搜索正确的 vDSP 函数很痛苦......

    【讨论】:

    • 感谢您的提示。很好的简化。我想要做的是将数据从不同的时间间隔采样重新采样到固定的时间间隔采样。我会尝试清理问题以帮助解释
    • @Ian 我再次把头绕过去,我编辑了我的答案
    • 太棒了!!这是一个完美的解决方案..非常感谢您的帮助!现在就去实施
    • 我正在调试一些代码并看到这种行为: vDSP_lint([-149.3, -149.5], [ 0.0, 0.5, 1.0], 1, output, 1, output.count, 2)正在将输出设置为 [ -149.3, -149.4, NaN]。为什么最后一个值不是 -149.5 而不是 NaN?
    【解决方案2】:

    这是另一个不使用任何 Accelerate 东西的解决方案

    public class Resampler {
    
    
    ///
    /// ### Class method to resample some data
    ///
    /// ### Inputs
    /// - Actual time data that may not be regularly sampled
    /// - Desired times you want the metric found at
    /// - Metric data corresponding with actual time data
    ///
    public class func resample( acualTimes atimes: [Double], desiredTimes dtimes: [Double], metric: [Double] ) ->[Double]
    {
        //
        // Initialize the desired metrics array
        //
        var desiredMetrics: [Double] = [Double](count: dtimes.count, repeatedValue: 0);
    
        // Initialize a counter to keep track of which metric value we are on
        var counter: Int = 0;
    
        // Loop through the desired times
        for dtime in dtimes {
    
            // Find the bounding indices, based on actual time data, for the desired time
            // using a binary search
            let (li, ri) = binarySearch(0,highBound: atimes.count-1, desiredTime: dtime, timeData: atimes);
    
            // Find the desired metric using an interpolation
            desiredMetrics[counter] = linearInterpolate(lowTime: atimes[li],
                                                        highTime: atimes[ri],
                                                        lowMetric: metric[li],
                                                        highMetric: metric[ri],
                                                        desiredTime: dtime);
            // Increment the counter
            counter++;
        }
    
        // Return the desired metrics
        return desiredMetrics;
    }
    
    
    ///
    /// ### Binary search code to find the bounding time value indices
    ///
    private class func binarySearch(  lowBound: Int,
                                highBound: Int,
                                desiredTime: Double,
                                timeData: [Double]) -> (leftIndex: Int, rightIndex: Int)
    {
        if( highBound-lowBound == 1 ){
            return (lowBound, highBound);
        }else{
            let center: Int = (lowBound + highBound)/2;
            if( desiredTime <= timeData[center]){
                return binarySearch(lowBound, highBound: center, desiredTime: desiredTime, timeData: timeData);
            }else{
                return binarySearch(center, highBound: highBound, desiredTime: desiredTime, timeData: timeData);
            }
        }
    }
    
    
    ///
    /// ### Linear interpolation method
    ///
    private class func linearInterpolate(   lowTime lt: Double,
                                            highTime ht: Double,
                                            lowMetric lm: Double,
                                            highMetric hm: Double,
                                            desiredTime dt: Double ) -> Double
    {
        return lm + (dt-lt)*(hm-lm)/(ht-lt);
    }
    
    }
    

    然后您只需执行以下操作即可运行它:

        let times: [Double] = [0.0,1.3,2.2,3.4,4.2,5.5,6.6,7.2,8.4,9.5,10.0];
        let desiredTimes: [Double] = [0,1,2,3,4,5,6,7,8,9,10];
        let metricData: [Double] = [4,3,6,7,4,5,7,4,2,7,2];
    
        let desiredMetrics = Resampler.resample(acualTimes: times, desiredTimes: desiredTimes, metric: metricData);
        print(desiredMetrics)
    

    上面这个例子会输出:

    [4.0, 3.23076923076923, 5.33333333333333, 6.66666666666667, 4.75, 4.61538461538461, 5.90909090909091, 5.0, 2.66666666666667, 4.72727272727273, 2.0]
    

    【讨论】:

      【解决方案3】:

      问题的另一种解决方案,100% 加速:

      import Accelerate
      
      let metric_1: [Double] = [4.0, 3.0, 6.0, 7.0, 4.0, 5.0, 7.0, 4.0, 2.0, 7.0, 2.0]
      let original_times: [Double] = [0.0, 1.3, 2.2, 3.4, 4.2, 5.5, 6.6, 7.2, 8.4, 9.5, 10.0]
      let wanted_times: [Double] = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
      
      let count = metric_1.count
      let length = vDSP_Length(count)
      var output = [Double](repeating: 0, count: count)
      var interpolationConstant = 2.0
      
      // calculate interpolated times
      vDSP_vintbD(original_times, 1, wanted_times, 1, &interpolationConstant, &output, 1, length)
      
      // calculate interpolated values
      vDSP_vlintD(metric_1, &output, 1, &output, 1, length, length)
      
      output: [4.0,
               3.2999999999999998,
               5.3999999999999995,
               6.5999999999999996,
               4.6000000000000005,
               4.5,
               5.8000000000000007,
               4.6000000000000005,
               2.8000000000000007,
               4.5,
               2.0]
      

      【讨论】:

        猜你喜欢
        • 2020-08-15
        • 1970-01-01
        • 2014-02-15
        • 2021-11-03
        • 2020-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-24
        相关资源
        最近更新 更多