實例來自於《CCSDS標准的LDPC編譯碼仿真》中代碼(實際上有點點差別),代碼優化從以下幾個方面進行
稀疏 仿真中的第一個困難在於ccsdscheckmatrix函數在輸入SIZE_M很大的時候,先不說運行時間,直接就爆內存了。(輸入參數4096,2/3) 先分析分析內存的問題,實際上這個函數的最后輸出結果就是一個矩陣,這個矩陣的大小是12288×28672,計算double型的內存占用也就2G左右。但是函數運行過程中產生了很多中間變量沒有清除。當然最后的解決辦法也沒有去管這些東西,由於矩陣H是稀疏矩陣,所以之際采用sparse后,這個運行就沒有任何問題了。 對於矩陣H和H_sparse = spares(H),占用內存如下(當然H要是稀疏的,不然得不償失) Name Size Bytes Class Attributes H 12288x28672 2818572288 double H_sparse 12288x28672 1736712 double sparse 也可以對比稀疏矩陣和原始矩陣的運行時間(和稀疏程度有關) 代碼:tic;H*message';toc; 結果:時間已過 0.288934 秒。 代碼:tic;H_sparse*message';toc; 結果:時間已過 0.001210 秒。 類型轉換 MATLAB中的運算符支持多種類型,譬如矩陣乘法中多用double型變量,但如果一個矩陣是邏輯輸入也沒有關系。但運算速度差異較大,譬如 >> Gc_logic = Gc>0; >> a=randi([0 1],1,16384); >> tic;b = a*Gc;toc 時間已過 0.107618 秒。 >> tic;b = a*Gc_logic;toc 時間已過 0.503132 秒。 觀測結果類型為double,我們可以大膽推測實際上邏輯型變量在運算過程中先轉化為了double型(邏輯怎么乘呢?)另一個實驗結果是 >> tic;Gc_logic=double(Gc_logic);b = a*Gc_logic;toc 時間已過 0.546412 秒。 這一定程度上證明了我們的假設。所以在運算過程中數據類型是重要的,如果上述乘法出現在循環內,那么實現轉化矩陣類型是必要的。即使只運行一次,那么顯式的轉化矩陣類型(特制新建變量)也有好處。譬如 >> tic;Gt=double(Gc_logic);b = a*Gt;toc 時間已過 0.373506 秒。 通過創建新變量,運行速度些許。 向量化 向量化實際上是原代碼修改中獲益最大的方法,這實際上是因為原先的譯碼程序寫了太多的循環。向量化后運行時間變成了原先的1/40 。當然,原先的代碼通用性強,而向量化這個過程實際上是運用了H的一些結構的。譯碼函數太復雜,此處不做舉例。 此處分析差分調制中的例子(實際上對這個程序沒有什么影響) 原來的代碼是這個樣子的(更新值為其本身和前一個值的異或) encodeData_extend = [1 encodeData]; for num = 2:length(encodeData_extend) encodeData_extend(num) = xor(encodeData_extend(num),encodeData_extend(num-1)); end 向量化的結果為(累加模二代替異或) encodeData1 = [1 encodeData]; encodeData1_sum = cumsum(encodeData1); encodeData_2 = mod(encodeData1_sum,2); 運行時間分別為 時間已過 0.023424 秒。 時間已過 0.015003 秒。 雖然后者沒有快很多,但這取決於向量的長度,長度大的話會有較大差距。 其他 MATLAB中提及的都能對代碼運行速度帶來細微的改進,包括
-
將長腳本拆開成小段,調用執行;
-
將大的代碼塊分開為獨立的函數;
-
將過分復雜的函數或是表達式采用簡單的來代替;
-
采用函數,而不是腳本;
上述測試腳本(和以上運行條件有差別)
%% 稀疏矩陣測試
M=4096;
theta=[1 1 2 3 1 1 2 3 1 2 3 0 2 3 0 2 3 0 1 3 0 1 3 0 1 2];
fai=[1787 1077 1753 697 1523 5 2035 331 1920 130 4 85 551 15 1780 1960 3 145 1019 691 132 42 393 502 201 1064
1502 602 749 1662 1371 9 131 1884 1268 1784 19 1839 81 2031 76 336 529 74 68 186 905 1751 1516 1285 1597 1712
1887 521 590 1775 1738 2032 2047 85 1572 78 26 298 1177 1950 1806 128 1855 129 269 1614 1467 1533 925 1886 2046 1167
1291 301 1353 1405 997 2032 11 1995 623 73 1839 2003 2019 1841 167 1087 2032 388 1385 885 707 1272 7 1534 1965 588];
A = zeros(M);
B = eye(M);
L = 0:M-1;
for matrixNum = 1:14
t_k = theta(matrixNum);
f_4i_M = floor(4*L/M);
f_k = fai(f_4i_M+1,matrixNum)';
col_1 = M/4*(mod((t_k+f_4i_M),4)) + ...
mod((f_k+L),M/4);
row_col = col_1+1 + L*M;
C_temp = zeros(M);
C_temp(ind2sub([M,M],row_col)) = 1;
C{matrixNum} = sparse(C_temp)';
end
H = [A A A B B+C{1};B+C{8} B+C{7}+C{6} A A B;A B B+C{5} A C{4}+C{3}+C{2}];
H_23 = [A A;B C{11}+C{10}+C{9};C{14}+C{13}+C{12} B];
H=[H_23 H];
H_full = full(H);
whos H H_full
%% 稀疏矩陣乘法測試
message = randi([0 1],1,28672);
tic;H*message';toc;
tic;H_full*message';toc;
%% 數據類型測試
Gc = randn(16384);
Gc_logic = Gc>0;
a=randi([0 1],1,16384);
tic;b = a*Gc;toc
tic;b = a*Gc_logic;toc %邏輯型運行花費時間
tic;Gc_logic=double(Gc_logic);b = a*Gc_logic;toc %類型轉換
tic;Gt=double(Gc_logic);b = a*Gt;toc %建立新變量
%% 向量化測試
encodeData = randi([0 1],1,1000000);
tic;
encodeData_extend = [1 encodeData];
for num = 2:length(encodeData_extend)
encodeData_extend(num) = xor(encodeData_extend(num),encodeData_extend(num-1));
end
toc;
tic;
encodeData1 = [1 encodeData];
encodeData1_sum = cumsum(encodeData1);
encodeData_2 = mod(encodeData1_sum,2);
toc;
View Code
|