Accelerazione delle Simulazioni BER utilizzando Parallel Computing Toolbox
Questo esempio utilizza Parallel Computing Toolbox™ per accelerare una semplice simulazione del tasso di errore bit (BER) QPSK. Il sistema è costituito da un modulatore QPSK, un demodulatore QPSK, un canale AWGN e un contatore del tasso di errore bit.
Impostare i parametri di simulazione.
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
Allocare della memoria agli array utilizzati per memorizzare i dati generati dalla funzione helper_qpsk_sim_with_awgn
.
[numErrors, numBits] = deal(zeros(length(EbNoVec),1));
Eseguire la simulazione e determinare il tempo di esecuzione. Verrà utilizzato un solo processore per determinare la prestazione di riferimento. Di conseguenza, si noti che viene utilizzato il normale for-loop.
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;
Calcolare il BER.
ber1 = numErrors ./ numBits;
Eseguire nuovamente la simulazione per il caso in cui Parallel Computing Toolbox è disponibile. Creare un insieme di lavoratori.
pool = gcp; assert(~isempty(pool), ['Cannot create parallel pool. '... 'Try creating the pool manually using ''parpool'' command.'])
Determinare il numero di lavoratori disponibili dalla proprietà NumWorkers
del pool
. La simulazione esegue l’intervallo di valori su ciascun lavoratore anziché assegnare un singolo punto a ciascun lavoratore, poiché il primo metodo fornisce un maggiore miglioramento della prestazione.
numWorkers = pool.NumWorkers;
Determinare la lunghezza di EbNoVec
da utilizzare nel loop parfor
annidato. Per una corretta classificazione delle variabili, l’intervallo di un for-loop annidato in un parfor
deve essere definito da numeri costanti o variabili.
lenEbNoVec = length(EbNoVec);
Allocare della memoria agli array utilizzati per memorizzare i dati generati dalla funzione helper_qpsk_sim_with_awgn
.
[numErrors,numBits] = deal(zeros(length(EbNoVec),numWorkers));
Eseguire la simulazione e determinare il tempo di esecuzione.
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;
Calcolare il BER. In questo caso, i risultati dei diversi processori devono essere combinati per generare il BER aggregato.
ber2 = sum(numErrors,2) ./ sum(numBits,2);
Confrontare i valori del BER per verificare che si ottengano gli stessi risultati a prescindere dal numero di lavoratori.
semilogy(EbNoVec',ber1,'-*',EbNoVec',ber2,'-^') legend('Single Processor','Multiple Processors','location','best') xlabel('Eb/No (dB)') ylabel('BER') grid
Come si può constatare, le curve del BER sono essenzialmente le stesse con qualsiasi varianza dovuta alla differenziazione dei semi di numeri casuali.
Confrontare i tempi di esecuzione di ogni metodo.
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 = 24.6 sec for one worker Simulation time = 6.1 sec for multiple workers Number of processors for parfor = 6