Bov*_*vaz 6 c# arrays performance bitarray
我有一些代码管理从传感器阵列接收的数据.控制传感器的PIC使用8个SAR-ADC并行读取4096个数据字节.这意味着它读取前8个字节的最高有效位; 然后它读取它们的第二位,依此类推,直到第八位(最低位).
基本上,对于它读取的每8个字节,它创建(并向计算机发送)8个字节,如下所示:
// rxData[0] = MSB[7] MSB[6] MSB[5] MSB[4] MSB[3] MSB[2] MSB[1] MSB[0]
// rxData[1] = B6[7] B6[6] B6[5] B6[4] B6[3] B6[2] B6[1] B6[0]
// rxData[2] = B5[7] B5[6] B5[5] B5[4] B5[3] B5[2] B5[1] B5[0]
// rxData[3] = B4[7] B4[6] B4[5] B4[4] B4[3] B4[2] B4[1] B4[0]
// rxData[4] = B3[7] B3[6] B3[5] B3[4] B3[3] B3[2] B3[1] B3[0]
// rxData[5] = B2[7] B2[6] B2[5] B2[4] B2[3] B2[2] B2[1] B2[0]
// rxData[6] = B1[7] B1[6] B1[5] B1[4] B1[3] B1[2] B1[1] B1[0]
// rxData[7] = LSB[7] LSB[6] LSB[5] LSB[4] LSB[3] LSB[2] LSB[1] LSB[0]
Run Code Online (Sandbox Code Playgroud)
对于系统读取和处理的所有4096个字节重复该模式.
想象一下,每个8字节读取是分开进行的,然后我们可以将它们视为8by8位数组.我需要在从左下角(LSB [7])到右上角(MSB [0])的对角线周围镜像这个数组.完成此操作后,生成的8by8位数组在其行中包含从传感器读取的正确数据字节.我以前在PIC控制器上执行此操作,使用左移等等,但这会大大减慢系统速度.因此,现在使用以下代码在我们处理数据的计算机上执行此操作:
BitArray ba = new BitArray(rxData);
BitArray ba2 = new BitArray(ba.Count);
for (int i = 0; i < ba.Count; i++)
{
ba2[i] = ba[(((int)(i / 64)) + 1) * 64 - 1 - (i % 8) * 8 - (int)(i / 8) + ((int)(i / 64)) * 8];
}
byte[] data = new byte[rxData.Length];
ba2.CopyTo(data, 0);
Run Code Online (Sandbox Code Playgroud)
请注意,此代码有效.
rxData是接收的字节数组.
我用于循环中的ba []索引的公式代码用于上面描述的阵列的镜像.
在别处检查数组的大小,以确保它始终包含正确的字节数(4096).
到目前为止,这是我的问题的背景.
在我的系统的每个处理循环中,我需要执行两次镜像,因为我的数据处理是连续获取的两个阵列之间的差异.速度对我的系统很重要(可能是处理的主要限制因素),镜像占我处理执行时间的10%到30%.
我想知道是否有其他解决方案可以与我的镜像代码进行比较,这可能会让我提高性能.使用BitArrays是我找到的唯一方法来处理接收字节中的不同位.
谢谢
对单独的位进行操作非常慢,并且创建 2 位数组并来回复制数据会产生更多开销
最简单、显而易见的解决方案就是提取这些位并再次组合它们。您可以使用循环来完成此操作,但由于它同时使用左移和右移,因此您需要一个函数来处理负移位量。因此,我在这里展开它以便于理解和提高速度
out[0] = (byte)(((rxData[0] & 0x80) >> 0) | ((rxData[1] & 0x80) >> 1) | ((rxData[2] & 0x80) >> 2) | ((rxData[3] & 0x80) >> 3) |
((rxData[4] & 0x80) >> 4) | ((rxData[5] & 0x80) >> 5) | ((rxData[6] & 0x80) >> 6) | ((rxData[7] & 0x80) >> 7));
out[1] = (byte)(((rxData[0] & 0x40) << 1) | ((rxData[1] & 0x40) >> 0) | ((rxData[2] & 0x40) >> 1) | ((rxData[3] & 0x40) >> 2) |
((rxData[4] & 0x40) >> 3) | ((rxData[5] & 0x40) >> 4) | ((rxData[6] & 0x40) >> 5) | ((rxData[7] & 0x40) >> 6));
out[2] = (byte)(((rxData[0] & 0x20) << 2) | ((rxData[1] & 0x20) << 1) | ((rxData[2] & 0x20) >> 0) | ((rxData[3] & 0x20) >> 1) |
((rxData[4] & 0x20) >> 2) | ((rxData[5] & 0x20) >> 3) | ((rxData[6] & 0x20) >> 4) | ((rxData[7] & 0x20) >> 5));
out[3] = (byte)(((rxData[0] & 0x10) << 3) | ((rxData[1] & 0x10) << 2) | ((rxData[2] & 0x10) << 1) | ((rxData[3] & 0x10) >> 0) |
((rxData[4] & 0x10) >> 1) | ((rxData[5] & 0x10) >> 2) | ((rxData[6] & 0x10) >> 3) | ((rxData[7] & 0x10) >> 4));
out[4] = (byte)(((rxData[0] & 0x08) << 4) | ((rxData[1] & 0x08) << 3) | ((rxData[2] & 0x08) << 2) | ((rxData[3] & 0x08) << 1) |
((rxData[4] & 0x08) >> 0) | ((rxData[5] & 0x08) >> 1) | ((rxData[6] & 0x08) >> 2) | ((rxData[7] & 0x08) >> 3));
out[5] = (byte)(((rxData[0] & 0x04) << 5) | ((rxData[1] & 0x04) << 4) | ((rxData[2] & 0x04) << 3) | ((rxData[3] & 0x04) << 2) |
((rxData[4] & 0x04) << 1) | ((rxData[5] & 0x04) >> 0) | ((rxData[6] & 0x04) >> 1) | ((rxData[7] & 0x04) >> 2));
out[6] = (byte)(((rxData[0] & 0x02) << 6) | ((rxData[1] & 0x02) << 5) | ((rxData[2] & 0x02) << 4) | ((rxData[3] & 0x02) << 3) |
((rxData[4] & 0x02) << 2) | ((rxData[5] & 0x02) << 1) | ((rxData[6] & 0x02) >> 0) | ((rxData[7] & 0x02) >> 1));
out[7] = (byte)(((rxData[0] & 0x01) << 7) | ((rxData[1] & 0x01) << 6) | ((rxData[2] & 0x01) << 5) | ((rxData[3] & 0x01) << 4) |
((rxData[4] & 0x01) << 3) | ((rxData[5] & 0x01) << 2) | ((rxData[6] & 0x01) << 1) | ((rxData[7] & 0x01) >> 0));
Run Code Online (Sandbox Code Playgroud)
显然这仍然很慢,因为它是逐字节操作的。最佳解决方案是同时对多个字节进行操作,例如使用SIMD和/或多线程。特别是当您对大量数据执行此操作时,.NET SIMD 内在函数将非常有用