拆分由扭曲阵列组成的数组

问题描述:

我有一个传感器向我发送一维浮点数组,我必须在4个不同的子数组中分裂。我的数组表示一个Frame,由1024个Ramps组成。每个Ramp都有4个通道的标题和数据(我想要分割的数据)。每个通道有2个浮标,一个用于实体部分,另一个用于复杂部分。为了澄清这一点,我已附加的图像结构为:拆分由扭曲阵列组成的数组

enter image description here

我需要在4个阵列只数据,每一个用于一个单个信道,以解开这个大阵列。这必须快速完成。我的实施需要大约850毫秒,但可惜这不够快。到目前为止,我已经写下了下面的代码:

IntPtr ptr = (IntPtr)frameInfo.ptr; // The pointer to the buffer 

for (int i = 0; i < nChannels; i++) 
{ 
    channelFrames[i].data = new float[nRamps * nPoints * 2]; 
} 

for (int ramp = 0; ramp < nRamps; ramp++) 
{ 
    ptr += (int)rawHeaderSize; // Skip the header 

    for (int point = 0; point < nPoints; point++) 
    { 
      for (int channel = 0; channel < nChannels; channel++) 
      { 
       Marshal.Copy(ptr, channelFrames[channel].data, (int)(point *2 + ramp*nPoints*2), 2); 

       ptr += (sizeof(float) * 2); // Move to the next data       
      } 
    } 
} 

有关如何更快地完成此操作的任何想法?

+1

也许你应该试试[CodeReview](https://codereview.stackexchange.com/) –

+0

你的图表看起来不符合你的描述或代码? “每个频道有2个浮动”,但你的图表显示每个频道有8个浮动?什么是点,什么是nPoints?你为什么一次只复制2个浮点数(根据你的图,这将是re0 + re1,然后是re2 + re3)?由于您为其分配了一个“新的float []”,因此我假设'data'是一个'float''Array'。 – NetMage

+0

@NetMage不,它显示每个通道2个浮动。每个浮点数是4个字节,因此Re0Re1Re2Re3产生一个浮点数并且Im0Im1Im2Im3产生另一个浮点数。 nPoints是4096. Marshal.Copy已将4个字节更改为浮点数。我需要将两个浮点数,实部和虚部复制到通道数组中。 – Ignacio

Marshal.Copy()很可能是性能瓶颈,因为它会调用非托管代码,而且这个调用过于昂贵而无法复制2个浮动内容。以下使用不安全代码(必须在项目属性中启用并且方法必须使用unsafe修饰符修饰)以避免使用Marshal.Copy()并手动复制数据。内循环(遍历通道)被展开,以获得一些额外的性能增益(缺点是代码被硬编码为4个通道)。

我的测量结果显示比原来的方法提高了近10倍的性能。

//Pin arrays with channel data in memory and get pointers of these fixed arrays 
fixed (float* fixed_ch0ptr = channelFrames[0].data) 
fixed (float* fixed_ch1ptr = channelFrames[1].data) 
fixed (float* fixed_ch2ptr = channelFrames[2].data) 
fixed (float* fixed_ch3ptr = channelFrames[3].data) 
{ 
    //fixed arrays pointer cannot be modified, we must create writable copies ot these pointers 
    float* ch0ptr = fixed_ch0ptr; 
    float* ch1ptr = fixed_ch1ptr; 
    float* ch2ptr = fixed_ch2ptr; 
    float* ch3ptr = fixed_ch3ptr; 

    //unsafe pointer to array from sensor 
    float* floatptr = (float*)ptr; 

    for (int ramp = 0; ramp < nRamps; ramp++) 
    { 
     floatptr = (float*)((byte*)(floatptr) + (int)rawHeaderSize); // Skip the header 

     for (int point = 0; point < nPoints; point++) 
     { 
      //Unrolling loop that iterates over channelFrames can give as some additional performance gains 

      //copy channel 0 data 
      *ch0ptr++ = *(floatptr++); 
      *ch0ptr++ = *(floatptr++); 

      //copy channel 1 data 
      *ch1ptr++ = *(floatptr++); 
      *ch1ptr++ = *(floatptr++); 

      //copy channel 2 data 
      *ch2ptr++ = *(floatptr++); 
      *ch2ptr++ = *(floatptr++); 

      //copy channel 3 data 
      *ch3ptr++ = *(floatptr++); 
      *ch3ptr++ = *(floatptr++); 
     } 
    } 
}