2

I am trying to linearly interpolate new values from a data set using Apple's Accelerate framework. I've used this piece of documentation for implementing my code, but I am facing issues when I try to interpolate a set of values that are under 1, fractions.

let values: [CGFloat] = [0.0, 0.019124083, 0.035419375, 0.05232375, 0.06873629, 0.08550575, 0.10209821, 0.11870141, 0.1355003, 0.15223834, 0.16881292, 0.18565933, 0.20213126, 0.21881929, 0.2355565, 0.2522735, 0.26899675, 0.28572345, 0.30233976, 0.3187645, 0.33557975, 0.35221455]
let indices: [CGFloat] = [0.0, 0.00438118, 0.017873764, 0.04094696, 0.07394123, 0.11698151, 0.16987896, 0.23201275, 0.30223083, 0.37879562, 0.45942688, 0.54145336, 0.6220541, 0.6985626, 0.7687006, 0.8307409, 0.88353443, 0.9264679, 0.95935345, 0.98232174, 0.9957142, 1.0]

let numberOfElements = vDSP_Length(100)

var result = [Float](repeating: 0,
                count: Int(numberOfElements))

let stride = vDSP_Stride(1)

var base: Float = 0
var end = Float(values.count)
var control = [Float](repeating: 0,
                      count: Int(numberOfElements))

vDSP_vgenp(values, stride,
           indices, stride,
           &result, stride,
           numberOfElements,
           vDSP_Length(values.count))

print(result)

// [0.0, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455, 0.35221455]


Pondorasti
  • 607
  • 6
  • 14
  • 1
    What result do you expect? – Martin R May 26 '20 at 13:33
  • I would expect an array of 100 elements with interpolated elements from "values" array. For example, if values is [1, 3], I would like to interpolate new elements and the result would be [1, 2, 3]. Hope, I've made myself clear. – Pondorasti May 26 '20 at 13:40
  • I am trying to achieve this https://stackoverflow.com/questions/53212548/swift-linear-interpolation-and-upsampling, but with fractions as my input. – Pondorasti May 26 '20 at 13:45

1 Answers1

3

As explained in the referenced document, the fractional parts of the indices define the interpolation between the pair of values in the values array starting at the index defined by the integer part.

The precise algorithm is described as pseudo-code in vDSP_vgenp(_:_:_:_:_:_:_:_:):

for (n = 0; n < N; ++n)
    If n <= B[0],  then C[n] = A[0].
    If B[M-1] < n, then C[n] = A[M-1].
    Otherwise:
        Let m be such that B[m] < n <= B[m+1].
        C[n] = A[m] + (A[m+1]-A[m]) * (n-B[m]) / (B[m+1]-B[m]).

Here A is the values array, B the indices array, and C the result array.

In your case all indices are <= 1, and that is why result[n] = values[21] = 0.35221455 for all n >= 1.

If the intention is to interpolate the values over the interval [0, 100] then the indices should be in that range. So what you probably want is to multiply the indices (in the range 0..1) with the length of the result array:

let numberOfElements = vDSP_Length(100)

let indices: [Float] = [0.0, 0.00438118, ..., 0.9957142, 1.0]
    .map { $0 * Float(numberOfElements) }

The result then is (Screenshot from Quicklook of result.map{ $0 } in a Playground):

enter image description here

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • A bit of an unrelated question, but if I don't have that many data points, the linear interpolation would make the graph look sharp. Is there a way to create a cubic or cosine interpolation to smooth out the rough corners? – Pondorasti May 26 '20 at 14:14
  • 1
    @Pondorasti: There surely is, but I don't know right now if the Accelerate framework has functions for cubic or other nonlinear interpolation methods. – Martin R May 26 '20 at 14:17