Ускорение симуляций BER Используя Parallel Computing Toolbox

Этот пример использует Parallel Computing Toolbox™, чтобы ускорить простую, симуляцию частоты ошибок по битам (BER) QPSK. Система состоит из модулятора QPSK, демодулятора QPSK, канала AWGN и небольшого счетчика коэффициента ошибок.

Установите параметры симуляции.

EbNoVec = 5:8;     % Eb/No values in dB
totalErrors = 200; % Number of bit errors needed for each Eb/No value
totalBits = 1e7;   % Total number of bits transmitted for each Eb/No value

Выделите память массивам, используемым, чтобы хранить данные, сгенерированные функцией, helper_qpsk_sim_with_awgn.

[numErrors, numBits] = deal(zeros(length(EbNoVec),1));

Запустите симуляцию и определите время выполнения. Только один процессор будет использоваться, чтобы определить базовую эффективность. Соответственно, заметьте, что нормальный цикл for используется.

tic
for idx = 1:length(EbNoVec)
    errorStats = helper_qpsk_sim_with_awgn(EbNoVec,idx, ...
        totalErrors,totalBits);
    numErrors(idx) = errorStats(idx,2);
    numBits(idx) = errorStats(idx,3);
end
simBaselineTime = toc;

Вычислите BER.

ber1 = numErrors ./ numBits;

Повторно выполните симуляцию для случая, в котором Parallel Computing Toolbox доступен. Создайте пул рабочих.

pool = gcp;
assert(~isempty(pool), ['Cannot create parallel pool. '...
  'Try creating the pool manually using ''parpool'' command.'])
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).

Определите количество доступных рабочих от NumWorkers свойство pool. Симуляция запускает область значений$E_{b}/N_{0}$ значений по каждому рабочему вместо того, чтобы присвоить одну$E_{b}/N_{0}$ точку каждому рабочему, когда бывший метод обеспечивает самое большое повышение производительности.

numWorkers = pool.NumWorkers;

Определите длину EbNoVec для использования во вложенном parfor цикл. Для соответствующей переменной классификации область значений цикла for вкладывается в parfor должен быть задан постоянными числами или переменными.

lenEbNoVec = length(EbNoVec);

Выделите память массивам, используемым, чтобы хранить данные, сгенерированные функцией, helper_qpsk_sim_with_awgn.

[numErrors,numBits] = deal(zeros(length(EbNoVec),numWorkers));

Запустите симуляцию и определите время выполнения.

tic
parfor n = 1:numWorkers
    for idx = 1:lenEbNoVec
        errorStats = helper_qpsk_sim_with_awgn(EbNoVec,idx, ...
            totalErrors/numWorkers,totalBits/numWorkers);
        numErrors(idx,n) = errorStats(idx,2);
        numBits(idx,n) = errorStats(idx,3);
    end
end
simParallelTime = toc;

Вычислите BER. В этом случае результаты нескольких процессоров должны быть объединены, чтобы сгенерировать совокупный BER.

ber2 = sum(numErrors,2) ./ sum(numBits,2);

Сравните значения BER, чтобы проверить, что те же результаты получены независимые от количества рабочих.

semilogy(EbNoVec',ber1,'-*',EbNoVec',ber2,'-^')
legend('Single Processor','Multiple Processors','location','best')
xlabel('Eb/No (dB)')
ylabel('BER')
grid

Вы видите, что кривые BER являются по существу тем же самым с любым отклонением, являющимся из-за отличающихся seed случайных чисел.

Сравните времена выполнения для каждого метода.

fprintf(['\nSimulation time = %4.1f sec for one worker\n', ...
    'Simulation time = %4.1f sec for multiple workers\n'], ...
    simBaselineTime,simParallelTime)
fprintf('Number of processors for parfor = %d\n', numWorkers)
Simulation time = 31.6 sec for one worker
Simulation time =  9.6 sec for multiple workers
Number of processors for parfor = 6