Ускорение симуляций 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;

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

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)
Simulation time = 101.0 sec for one worker
Simulation time = 32.8 sec for multiple workers

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