【问题标题】:Storing overlap add values in an array在数组中存储重叠添加值
【发布时间】:2014-01-31 05:12:54
【问题描述】:

我有一个相当简单的问题,但我找不到简单的解决方案。 事情是这样的,我有一个信号让我们说 x 的长度是 32.x[32]。这个数组在每一步都得到了实时信号的值。在第一步我得到 [0:31] 值,第二步 [1:32],第三步 [2:33] 等等。为了获得我想要重叠的最终信号,添加这些值并将它们存储到一个数组中。我尝试这样做的方法是声明一个特定长度的数组,比如说 150。xfinal[150]。 然后,为了填充 xfinal,我这样做了。

Step 1. xfinal[0:31] = x[0:31].
Step 2. xfinal[1:31] = xfinal[1:31] + x[0:30].
    xfinal[32] = x[31];
Step 3. xfinal[2:32] = xfinal[2:32] + x[0:30].
    xfinal[33] = x[31];

等等。这样,在 33 个信号之后,x_final 中的每个值都将是 32 的总和。

我用 C 编写的代码是(它有点复杂,因为 x 是一个帧,所以我必须逐个像素地复制。

void Overlapadd ( float **final_X, float **all_frames_X, int add_index,int w, int h)
{
    for (int i=0; i< frame_size ; i++) {  // for every pixel

        for( int j=add_index; j<add_index+32; j++){
            final_X[j][i] += all_frames_S[j-add_index][i];
        }

    }

    add_index++;
}

这段代码的问题是,当我长时间运行它时,final_X 数组将填满,final_X[add_index+32] 将耗尽内存。这就是为什么我想以循环方式存储它。所以当我到达终点时,我回到 0。问题是当我到达final_X 中的一个点时,假设 add_index=60。所以final_X[add_index] 将是 32 帧的总和,但final_X[add_index+1] 将是仅 31 帧中的一些,final_X[add_index+2] 将是仅 30 帧中的一些,依此类推。这些值对我很重要,因为它们通过添加新 x 帮助我获得新值。

我不知道我是否说清楚了,可能没有,但我希望能得到一些帮助。所以问题是我如何重叠添加信号并将它们长期存储在向量中。

【问题讨论】:

  • 从您的问题中我发现有两件事难以理解:1)虽然您的解释和草图将 final_X 视为一维数组,但您的代码将其用作二维数组。 2)目前尚不清楚您如何确定“内存不足”的情况。能否包括分配步骤?
  • 我将 final_X 视为一维数组,以便于理解。 x 本身是一个数组,所以 final_x 将是一个数组的数组,但原理是一样的。内存不足的意思是我为 final_X 分配了 150 帧,在某些时候我会调用 final_X[151]。

标签: c arrays add store


【解决方案1】:

您可以为此使用模运算,代价是最内层循环中的一个额外变量用作计数器,而另一个将用作位置索引。

#define FINAL_X_LEN 150

void Overlapadd(float **final_X, float **all_frames_X, int add_index)
{
    for (int i = 0; i < frame_size; i++)
        for(int j = add_index, int k = 0; k < 32; j = (j+1)%FINAL_X_LEN)
            final_X[j][i] += all_frames_S[k][i];

}

这里,k 用于计算迭代次数,j 是您要索引的实际位置。

注意Overlapadd 末尾的add_index++;,这很可能不会按您预期的方式工作。值是通过副本传递的,所以add_index++ 只是增加了add_index 的本地副本,调用者将看不到此更改。如果要模拟传递引用,则必须将 add_index 作为指针传递。

另外,请注意,您组织代码的方式对缓存不是很友好。 final_X[j][i] += ... 不好,因为 j 在最内层循环的每次迭代中都会更改,这会破坏空间局部性并增加缓存未命中率。如果您访问阵列中附近的位置,则可以增加缓存命中时间和整体程序性能。我建议为j 的每个位置复制每一帧,而不是为j 的每个位置一次复制一帧(这就是你现在正在做的事情)。在这种情况下,这就像交换循环的顺序一样简单:

void Overlapadd(float **final_X, float **all_frames_X, int add_index)
{
    for(int j = add_index, int k = 0; k < 32; j = (j+1)%FINAL_X_LEN)
        for (int i = 0; i < frame_size; i++)
            final_X[j][i] += all_frames_S[k][i];

}

【讨论】:

  • 我不确定我是否完全理解它的工作原理,但我会尝试一下:D。我担心的一件事是它会不断添加和添加,我只对始终拥有 32 帧感兴趣。我的意思是它第一次会通过向量,但是当它再次出现时,它会添加到先前的值。因此,例如第 33 位的第一次迭代我将有 32 帧,第二次我将有 64 帧(因为它保留了前 32 个值)等等..
  • 感谢循环建议,我实际上想知道哪种方式会更快:逐帧或每帧像素。
  • @CRS 那么当它环绕时会发生什么?您想重新开始,即,您想在添加之前在该位置将final_X 设置为 0?如果只是这样,if 就是您所需要的。
【解决方案2】:

我不完全理解你的目标是什么,但是对于循环添加,你必须只有一个使用模数的连续索引变量:

int x[32];
int xfinal[32];

for (int i=0; i<32; i++) // initialize xfinal with 0
    xfinal[i] = 0;

int iter = 100; // doing additions e.g. 100 times

for (int i=0; i<iter; i++)
    for (int j=0; j<32; j++)
        xfinal[(j+i)%32] += x[j]; // index of xfinal remains inside 0-31

另请注意,Overlapaddd() 中的 add_index++ 没有剩余效果!

编辑:

这就是我的解决方案的作用:

外圈是xfinal,内圈是x。内圈顺时针旋转,i 运行到iter,外圈运行+= 底层单元。在第一次迭代中,内圈相对于完全 0 初始化的外圈未旋转,因此外圈变为 = 内圈(= 你的第 1 步)。等等……

【讨论】:

  • 在这种情况下,它不会只添加相同的 x 100 次吗?或者对我来说,每次迭代 X 都是不同的。我同意,我在 add_index 上犯了一个错误,我将它声明为一个指针。
  • 我现在可以看到了。感谢您的解释,但仍然对我没有太大帮助,因为我还需要存储 100 x_final 的值。
【解决方案3】:

好吧,我想到的就是这个。

到目前为止,从每次迭代的第 33 帧开始,我都为 x_final 获得了一个不错的值。所以我在为 x_final 获得足够的值后考虑复制该位置之后的帧并将它们放在向量的开头。 因此,假设 x_final 的长度为 170。 x_final[170]

int curr_pos;

// if I reached frame 132 it means that values from 32-131 already have a 32 frame sum in them

if(add_index == 132) // I have 100 good values of x_final already - x_final[32:131]
{
    for( int j=add_index; j<add_index+32; j++){
        for (int i=0; i< (w*h) ; i++) {
            x_final[add_index-132][i] = x_final[j][i]; //copy the rest at the beginning of the vector
        }
    }
    curr_pos = 0;
}
else
    curr_pos = add_index;



  //Overlap add the new 32 frames 
  for( int j=curr_pos; j<curr_pos+32; j++){
        for (int i=0; i< (w*h) ; i++) {
        x_final[j][i] += all_frames_S[j-curr_pos][i];
    }
}

   // prepare vector for next iteration
   for (int i=0; i< (w*h) ; i++) {
        x_final[curr_pos+32][i] = 0;
    }

这种方法有什么缺陷吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    相关资源
    最近更新 更多