Main Content

Parallel Computing Toolbox による BER シミュレーション

この例では、BER シミュレーションに関連する通信システムの実行速度を改善する方法を説明します。これらのシステムのパフォーマンスを向上させるために使用できる方法の 1 つとして、シミュレーションの並列化があります。この例では、BER シミュレーションで Parallel Computing Toolbox™ を使用する方法を紹介します。BER シミュレーションの並列化に利用できる 2 つの方法を示しますので、より適した方法を使用することをお勧めします。

ライセンスをチェックして並列プールを開く

この節では、Parallel Computing Toolbox が使用可能かどうかを確認します。使用可能な場合は、ワーカーの並列プールを開き、プール内で使用可能なワーカーの最大数を変数 numWorkers に割り当てます。使用可能でない場合は、numWorkers に 1 を割り当て、その場合、例はシングル コアで実行されます。

[licensePCT,~] = license( 'checkout','Distrib_Computing_Toolbox');
if ( licensePCT && ~isempty(ver('parallel')))
    if isempty(gcp('nocreate'))
        parpool;
    end
    pool = gcp;
    numWorkers = pool.NumWorkers;
else
    numWorkers = 1;
end
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).

初期化

この例では、Parallel Computing Toolbox の使用方法を示すため、空間多重化の例を並列化します。この例のシミュレーションに必要なパラメーターは、次のとおりです。

EbNo = 1:2:11;  % Eb/No in dB
N = 2;          % Number of transmit antennas
M = 2;          % Number of receive antennas
modOrd = 2;     % constellation size = 2^modOrd
numBits = 1e6;  % Number of bits
numErrs =  100; % Number of errors
lenEbNo = length(EbNo);
% Create a local random stream to be used for data generation for
% repeatability. Use the combined multiple recursive generator since it
% supports substreams.
hStr = RandStream('mrg32k3a'); % Setting the random stream
[berZF,berMMSE] = deal(zeros(lenEbNo,3));
[nerrsZF,nbitsZF,nerrsMMSE,nbitsMMSE] = deal(zeros(numWorkers,lenEbNo));

Eb/No 範囲に対する並列化

1 つ目の方法は、Eb/No 範囲に対する並列化で、1 つのワーカーが 1 つの Eb/No 値を処理します。この場合、パフォーマンスは、最も大きい Eb/No 値を処理するために必要な時間によって制限されます。

simIndex = 1;
str = 'Across the Eb/No range';
disp('Performing BER simulations with one worker processing one Eb/No value ...');
Performing BER simulations with one worker processing one Eb/No value ...
tic
parfor idx = 1:lenEbNo
    [BER_ZF,BER_MMSE] = simBERwithPCT(N,M,EbNo,modOrd, ...
        idx,hStr,numBits,numErrs);
    berZF(idx,:) = BER_ZF(idx,:);
    berMMSE(idx,:) = BER_MMSE(idx,:);
end
timeRange = toc;
clockBERwithPCT(simIndex,timeRange,timeRange,str);

並列プール内のワーカー数に対する並列化

2 つ目の方法は、使用可能なワーカー数に対する並列化で、各ワーカーが Eb/No 範囲全体を処理します。ただし、各ワーカーは誤りをカウント (エラー数の合計/numWorkers) してから、次の Eb/No 値の処理に移ります。この方法では、使用可能なすべてのコアが同等かつ効率的に使用されます。

simIndex = simIndex + 1;
str = 'Across the number of available workers';
seed = 0:numWorkers-1;
disp('Performing BER simulations with each worker processing the entire range ...');
Performing BER simulations with each worker processing the entire range ...
tic
parfor n = 1:numWorkers
    hStr = RandStream('mrg32k3a','Seed',seed(n));
    for idx = 1:lenEbNo
        [BER_ZF,BER_MMSE] = simBERwithPCT(N,M,EbNo,modOrd, ...
            idx,hStr,numBits/numWorkers,numErrs/numWorkers);
        nerrsZF(n,idx) = BER_ZF( idx,2);
        nbitsZF(n,idx) = BER_ZF( idx,3);
        nerrsMMSE(n,idx) = BER_MMSE(idx,2);
        nbitsMMSE(n,idx) = BER_MMSE(idx,3);
    end
end
bZF = sum(nerrsZF,1)./sum(nbitsZF,1);
bMMSE = sum(nerrsMMSE,1)./sum(nbitsMMSE,1);
timeWorker = toc;

以下は、64 ビット版 Windows® 7 を実行する 4 コアの Intel® Xeon® CPU W3550 (~3.1GHz、12.288GB RAM) マシンで得られた結果です。この表は、上記の方法のパフォーマンスの比較を示しています。2 つ目の方法の方が 1 つ目の方法よりもパフォーマンス面で優れていることがわかります。これらは 1 回の実行で得られた結果であり、実行状況によって異なる場合があります。

--------------------------------------------------------------------------------------------
Type of Parallelization                             | Elapsed Time (sec)| Speedup Ratio
1. Across the Eb/No range                           |           89.7366 |       1.0000
2. Across the number of available workers           |           28.4443 |       3.1548
--------------------------------------------------------------------------------------------

以下のプロットは、別々の並列化方式を使用してゼロフォーシング (ZF) 受信機と最小平均二乗誤差 (MMSE) 受信機で得られた BER 曲線を示しています。

plotBERwithPCT(EbNo,berZF(:,1),berMMSE(:,1),bZF,bMMSE);

使用しているマシンについてパフォーマンス比較表を生成するには、次のコード行のコメントを解除して、このスクリプト全体を実行してください。

% clockBERwithPCT(simIndex,timeRange,timeWorker,str);

付録

この例では、以下の関数が使用されています。