在Matlab

时间:2017-01-19 16:35:10

标签: matlab for-loop optimization

我有一组来自传感器的32位二进制值。我必须形成这些值的所有可能组合,然后将它们转换为十进制值。

如果传入的行数超过80000 - 90000,则代码速度会非常慢。运行需要120分钟。

我想优化这段代码,因为3 For循环和最内层循环中的函数正在减慢我的算法速度。有没有机会我可以消除一些For循环并用矢量化代替它们来加速这个过程。

b1 = [0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b2 = [0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b3 = [0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];
b4 = [0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b5 = [0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];

FullVector = [b1;b2;b3;b4;b5];

for Idx = 1:size(FullVector,1)
k = 1;
MinLength = 4;             
MaxLength = 8; 
StepSize = 2;          

    for StartByte = 1:8
        for StartBit = 1:8
            for SignalLength = MinLength:StepSize:MaxLength
                DecimalVals.s(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
                k = k+1;
            end
        end
    end
end

功能:

function decimal = BitCombinations(ByteArray,Sbyte,Sbit,lengthSignal)
%function extracts the required bits from a byte array and 
%returns the decimal equivalent of the bits.

%Inputs:
%Sbyte  - Starting byte
%Sbit   - Starting bit in the given byte
%length - length of bits to be extracted 

%Output:
%dec    - Returns the dec  

startbit_pos = ((Sbyte-1)*8+Sbit);
endbit_pos = ((Sbyte-1)*8+Sbit+lengthSignal-1);

if endbit_pos <= 64
    extractedbits = ByteArray(startbit_pos:endbit_pos);
    extractedbits = fliplr(extractedbits);
    decimal = bi2de(extractedbits);
else
    decimal = NaN;
end

end

2 个答案:

答案 0 :(得分:1)

您应该使用以下代码示例预先分配结果矩阵DecimalVals

b1 = repmat([0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b2 = repmat([0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b3 = repmat([0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);
b4 = repmat([0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b5 = repmat([0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);

FullVector = [b1;b2;b3;b4;b5];

MinLength = 4;             
MaxLength = 8; 
StepSize = 2;  

% Preallocation of the result struct
noOfValues = (((MaxLength - MinLength) / 2) + 1) * MaxLength * MaxLength;
DecimalVals = zeros(size(FullVector,1),noOfValues);

for Idx = 1:size(FullVector,1)
    k = 1;

    for StartByte = 1:MaxLength
        for StartBit = 1:MaxLength
            for SignalLength = MinLength:StepSize:MaxLength
                DecimalVals(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
                k = k+1;
            end
        end
    end
end

结果(在我的机器上):

没有预先分配的

时间消耗:560秒

时间消耗与预分配:300秒

此外,请使用MATLAB Profiler(使用“运行和时间”启动脚本)来分别识别哪个函数需要花费大部分时间并将函数/行添加到您的问题中。

不幸的是,我无法访问通信系统工具箱的功能,所以我使用了文件交换中的函数bi2de。在这个版本中,有一种错误检查,需要花费很多时间: ~230秒

答案 1 :(得分:0)

除了预先分配数组之外,你可以做的另一件事是不使用fliplr。看一下这段代码

tic
N = 10000;
A = [1:N];
for i = 1:N/2
    b = A(N-i+1:-1:i);
end
toc

b = [];
tic
for i = 1:N/2
    b = fliplr(A(i:N-i+1));
end
toc

经过的时间是0.060007秒。 经过的时间是0.118267秒。

因此,fliplr的使用速度要慢2倍,而不是简单地使用&#34;向后&#34;索引。我非常确定你可以通过自己的bi2de功能获得一些特定于你的问题的东西。

我尝试了这个,虽然没有检查它的效率,但也许你可以将它用于你的目的

function values = myBi2Dec(byte,signalLengths)

persistent indexes
if isempty(indexes)
    % Find the matrix indexes for this 
    indexes = [];
    for iBit = 1:8
        for iSL = signalLengths
            if iBit+iSL-1<=8
                indexes = [indexes;sub2ind([8,8],iBit,iBit+iSL-1)];
            end
        end
    end
end
% Lets get the cumulative value
cumB2D = cumBi2Dec(byte);

% We already calculated their position, so simply return them
values = cumB2D(indexes);

function cumB2D = cumBi2Dec(byte)

persistent B2D
if isempty(B2D)
    B2D = zeros(8,8);
    tmp  = 2.^[0:7];
    for i = 1:8
        B2D(i,i:8) = tmp(1:8-(i-1));
    end
end

cumB2D = cumsum(repmat(fliplr(byte),8,1).*B2D,2);

然后尝试,例如,myBi2Dec([0,0,0,0,1,1,1,1],[4:2:8])