如何包装最后/第一个元素进行建筑插值?

时间:2016-02-15 09:02:39

标签: algorithm pseudocode linear-interpolation

我有这个代码迭代一些样本并在点之间建立一个简单的线性插值:

foreach sample:
   base = floor(index_pointer)
   frac = index_pointer - base
   out = in[base] * (1 - frac) + in[base + 1] * frac
   index_pointer += speed

   // restart
   if(index_pointer >= sample_length) 
   {
      index_pointer = 0
   }

使用等于1的“速度”,游戏完成。但是如果index_pointer不同于1(即得到小数部分),我需要包装last / first元素以保持翻译的一致性。

你会怎么做?双重索引?

这是我拥有的价值观的一个例子。让in数组包含4个值:[8,12,16,20]。

它将是:

1.0*in[0] + 0.0*in[1]=8
0.28*in[0] + 0.72*in[1]=10.88
0.56*in[1] + 0.44*in[2]=13.76
0.84*in[2] + 0.14*in[3]=16.64
0.12*in[2] + 0.88*in[3]=19.52
0.4*in[3] + 0.6*in[4]=8 // wrong; here I need to wrapper

最后一点是错误的。 [4]将为0,因为我没有[4],但第一部分需要注意0.4和第一个样本的重量(我认为?)。

2 个答案:

答案 0 :(得分:1)

只需环绕索引:

out = in[base] * (1 - frac) + in[(base + 1) % N] * frac

,其中%是模运算符,N是输入样本的数量。

此过程为您的样本数据生成以下行(虚线是插值的采样点,圆圈是输入值):

Endianess

答案 1 :(得分:1)

我想我现在明白了这个问题(答案只适用于我真的......):

您以标称速度sn采样值。但实际上你的采样器以真实的速度进行采样,其中s!= sn。现在,您想要创建一个函数,该函数对以速度s采样的系列进行重新采样,因此它产生一个系列,就像通过2个相邻样本之间的线性插值以速度sn采样一样。或者,您的采样器抖动(实际采样时的时间差异为sn + Noise(sn))。

这是我的方法 - 一个名为“重新样本”的函数。它采用样本数据和所需的重新采样点列表。 对于将在原始数据之外索引的任何重新采样点,它将返回相应的边界值。

let resample (data : float array) times =
    let N = Array.length data
    let maxIndex = N-1
    let weight (t : float) =
        t - (floor t)
    let interpolate x1 x2 w = x1 * (1.0 - w) + x2 * w
    let interp t1 t2 w =
        //printfn "t1 = %d t2 = %d w = %f" t1 t2 w
        interpolate (data.[t1]) (data.[t2]) w
    let inter t =
        let t1 = int (floor t)
        match t1 with
        | x when x >= 0 && x < maxIndex -> 
            let t2 = t1 + 1
            interp t1 t2 (weight t)
        | x when x >= maxIndex -> data.[maxIndex]
        | _ -> data.[0]

    times 
    |> List.map (fun t -> t, inter t)
    |> Array.ofList

let raw_data = [8; 12; 16; 20] |> List.map float |> Array.ofList
let resampled = resample raw_data [0.0..0.2..4.0]

收益率:

  

val resample:data:float array - &gt; times:浮动列表 - &gt; (float * float)[]

     

val raw_data:float [] = [| 8.0; 12.0; 16.0; 20.0 |]

     

val resampled:(float * float)[] =

     

[|(0.0,8.0); (0.2,8.8); (0.4,9.6); (0.6,10.4); (0.8,11.2); (1.0,12.0);

     

(1.2,12.8); (1.4,13.6); (1.6,14.4); (1.8,15.2); (2.0,16.0);

     

(2.2,16.8); (2.4,17.6); (2.6,18.4); (2.8,19.2); (3.0,20.0);

     

(3.2,20.0); (3.4,20.0); (3.6,20.0); (3.8,20.0); (4.0,20.0)|]

现在,我仍然无法理解你问题的“环绕”部分。最后,插值 - 与外推相反,仅针对[0..N-1]中的值定义。因此,您需要决定该函数是否应该产生运行时错误,或者只是使用边值(或0)来表示原始数据数组之外的时间值。

<强> 修改

事实证明,它也是关于如何使用循环(环)缓冲区的。

这里是resample函数的一个版本,使用循环缓冲区。以及一些操作。

  • update将新的样本值添加到环形缓冲区
  • read读取内容一个环形缓冲区元素,就好像它是一个普通数组,索引为[0..N-1]。
  • initXXX以各种形式创建环形缓冲区的函数。
  • length,返回环形缓冲区的长度或容量。

将环形缓冲区逻辑纳入模块中以使其全部清洁。

module Cyclic =
    let wrap n x = x % n // % is modulo operator, just like in C/C++

    type Series = { A : float array; WritePosition : int  }

    let init (n : int) = 
            { A = Array.init n (fun i -> 0.);
            WritePosition = 0 
            }

    let initFromArray a =
        let n = Array.length a
        { A = Array.copy a;
        WritePosition = 0
        }

    let initUseArray a =
        let n = Array.length a
        { A = a;
        WritePosition = 0
        }


    let update (sample : float ) (series : Series)  =
        let wrapper = wrap (Array.length series.A)
        series.A.[series.WritePosition] <- sample
        { series with 
                WritePosition = wrapper (series.WritePosition + 1) }

    let read i series = 
        let n = Array.length series.A
        let wrapper = wrap (Array.length series.A)
        series.A.[wrapper (series.WritePosition + i)] 

    let length (series : Series) = Array.length (series.A)
let resampleSeries (data : Cyclic.Series) times =
    let N = Cyclic.length data
    let maxIndex = N-1
    let weight (t : float) =
        t - (floor t)
    let interpolate x1 x2 w = x1 * (1.0 - w) + x2 * w
    let interp t1 t2 w =
        interpolate (Cyclic.read t1 data) (Cyclic.read t2 data) w
    let inter t =
        let t1 = int (floor t)
        match t1 with
        | x when x >= 0 && x < maxIndex -> 
            let t2 = t1 + 1
            interp t1 t2 (weight t)
        | x when x >= maxIndex -> Cyclic.read maxIndex data
        | _ -> Cyclic.read 0 data

    times 
    |> List.map (fun t -> t, inter t)
    |> Array.ofList    


let input = raw_data
let rawSeries0 = Cyclic.initFromArray input
(resampleSeries rawSeries0 [0.0..0.2..4.0]) = resampled