[英]Using vectorization instead of a 'for Loop' in Matlab
我有一組來自傳感器的 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
您應該使用以下代碼示例預先分配結果矩陣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 探查器(通過使用“運行和時間”啟動腳本)來確定瓶頸,分別是哪個函數花費最多時間並將函數/行添加到您的問題中。
不幸的是,我無法訪問通信系統工具箱的功能,所以我使用了文件交換中的功能bi2de
。 在這個版本中,有一種錯誤檢查,需要很多時間: ~230秒
除了預先分配數組之外,您還可以做的另一件事是不使用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 倍左右,而不是簡單地使用“向后”索引。 我很確定您也可以通過制作自己的特定於您的問題的 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])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.