Um dos desafios inerentes aos sistemas de Transmissão por Divisão de Frequência Ortogonal (OFDM) é o elevado Pico de Relação Média de Potência (PAPR). Um PAPR alto pode conduzir a distorções não lineares nos amplificadores de potência e, consequentemente, aumentar a taxa de erro de bit (BER). Este artigo explora diversas técnicas para mitigar o PAPR em sistemas OFDM, apresentando implementações em MATLAB e análises de desempenho.
- O Problema do PAPR
1.1 Definição de PAPR
A Relação Pico-Média de Potência (PAPR) de um sinal s(t) é definida como:
PAPR(dB) = 10·log₁₀(max|s(t)|² / E[|s(t)|²])
Onde s(t) representa o sinal OFDM no domínio do tempo e E[·] denota o valor esperado.
1.2 Modelo de Sistema Adotado
- Número de subportadoras (N): 64, 128, 256, etc.
- Modulação: QPSK, 16QAM, 64QAM.
- Fator de sobreamostragem (L): 4, para uma avaliação precisa do PAPR.
- Classificação de Algoritmos de Redução de PAPR
Os algoritmos para redução de PAPR podem ser categorizados da seguinte forma:
| Categoria do Algoritmo | Algoritmo Representativo | Vantagens | Desvantagens | Impacto na BER |
|---|---|---|---|---|
| Clipping (Limitação) | Clipping Duro, Clipping Suave | Implementação simples | Distorção não lineear | Degradação notável |
| Probabilístico | SLM (Selective Mapping), PTS (Partial Transmit Sequences) | Sem distorção adicional | Complexidade computacional, requer informação de banda lateral | Sem degradação |
| Codificação | Codificação em Bloco, Código de Golay | Sem distorção | Baixa eficiência espectral | Sem degradação |
| Pré-distorção | ACE (Average Coder Extension), TR (Tone Reservation) | Bom desempenho | Alta carga computacional | Degradação leve |
| Entrelaçamento | Reservas de Portadora, Expansão/Compressão | Baixa complexidade | Desempenho limitado | Degradação leve |
- Implementação Completa em MATLAB
3.1 Modelo Básico de Sistema OFDM
A classe OFDMSystem define a estrutura fundamental para simulações OFDM.
%% Modelo Básico de Sistema OFDM
classdef OFDMSystem < handle
% Classe base para sistemas OFDM
properties
N = 64; % Número de subportadoras
Ncp = 16; % Comprimento do prefixo cíclico
M = 4; % Ordem de modulação (QPSK=4, 16QAM=16, 64QAM=64)
L = 4; % Fator de sobreamostragem
mod_type = 'QPSK'; % Tipo de modulação
snr_db = 0:2:20; % Faixa de SNR
num_symbols = 1000; % Número de símbolos OFDM
end
methods
function obj = OFDMSystem(varargin)
% Construtor
for i = 1:2:length(varargin)
if isprop(obj, varargin{i})
obj.(varargin{i}) = varargin{i+1};
end
end
end
function [symbols, bits] = generate_data(obj)
% Geração de dados aleatórios
bits_per_symbol = log2(obj.M) * obj.N;
total_bits = bits_per_symbol * obj.num_symbols;
bits = randi([0, 1], total_bits, 1);
% Modulação
if strcmp(obj.mod_type, 'QPSK')
symbols = pskmod(reshape(bits, 2, [])', 4, pi/4, 'gray');
elseif strcmp(obj.mod_type, '16QAM')
symbols = qammod(reshape(bits, 4, [])', 16, 'gray', 'InputType', 'bit');
else
symbols = qammod(reshape(bits, 6, [])', 64, 'gray', 'InputType', 'bit');
end
symbols = reshape(symbols, obj.N, obj.num_symbols);
end
function tx_signal = ofdm_modulate(obj, symbols)
% Modulação OFDM
[N_subcarriers, num_sym] = size(symbols);
% Sobreamostragem
if obj.L > 1
padded_symbols = zeros(N_subcarriers*obj.L, num_sym);
center_idx = floor(N_subcarriers/2);
padded_symbols(1:center_idx, :) = symbols(1:center_idx, :);
padded_symbols(end-center_idx+1:end, :) = symbols(center_idx+1:end, :);
else
padded_symbols = symbols;
end
% IFFT
tx_signal = ifft(padded_symbols, N_subcarriers*obj.L, 1);
% Adição de Prefixo Cíclico
tx_signal = [tx_signal(end-obj.Ncp*obj.L+1:end, :); tx_signal];
end
function papr_db = calculate_papr(obj, signal)
% Cálculo do PAPR
signal_power = abs(signal).^2;
peak_power = max(signal_power, [], 1);
avg_power = mean(signal_power, 1);
papr_linear = peak_power ./ avg_power;
papr_db = 10*log10(papr_linear);
end
function ccdf = calculate_ccdf(obj, papr_values, threshold_db)
% Cálculo da CCDF (Complementary Cumulative Distribution Function)
papr_values = papr_values(:);
ccdf = mean(papr_values > threshold_db);
end
function ber = simulate_ber(obj, snr_db_values)
% Estrutura para simulação de BER
% Subclasses devem sobrescrever este método
error('O método simulate_ber deve ser implementado na subclasse.');
end
end
end
3.2 Algoritmos de Clipping
3.2.1 Clipping Duro
O método de clipping duro limita diretamente o envelope do sinal a um valor máximo predefinido.
%% Algoritmo de Clipping Duro
classdef HardClipping < OFDMSystem
% Implementação do algoritmo de Clipping Duro
properties
clip_ratio = 0.8; % Razão de limitação (CR)
end
methods
function obj = HardClipping(varargin)
obj = obj@OFDMSystem(varargin{:});
end
function clipped_signal = apply_clipping(obj, signal)
% Aplica o clipping duro ao sinal
amplitude = abs(signal);
phase = angle(signal);
% Define o limiar de clipping
threshold = obj.clip_ratio * max(amplitude(:));
% Aplica a limitação
amplitude_clipped = min(amplitude, threshold);
% Reconstrói o sinal
clipped_signal = amplitude_clipped .* exp(1j*phase);
end
function ber = simulate_ber(obj, snr_db_values)
% Simulação de BER com Clipping Duro
ber = zeros(size(snr_db_values));
for snr_idx = 1:length(snr_db_values)
total_errors = 0;
total_bits = 0;
for sym_idx = 1:obj.num_symbols
% Geração de dados
bits_per_symbol = log2(obj.M) * obj.N;
bits = randi([0, 1], bits_per_symbol, 1);
% Modulação
if strcmp(obj.mod_type, 'QPSK')
symbols = pskmod(reshape(bits, 2, [])', 4, pi/4, 'gray');
else
symbols = qammod(reshape(bits, 4, [])', 16, 'gray', 'InputType', 'bit');
end
% Modulação OFDM
tx_signal = obj.ofdm_modulate(symbols);
% Aplica Clipping
clipped_signal = obj.apply_clipping(tx_signal);
% Adição de Ruído
signal_power = mean(abs(clipped_signal).^2);
noise_power = signal_power / (10^(snr_db_values(snr_idx)/10));
noise = sqrt(noise_power/2) * (randn(size(clipped_signal)) + 1j*randn(size(clipped_signal)));
rx_signal = clipped_signal + noise;
% Demodulação OFDM
rx_symbols = obj.ofdm_demodulate(rx_signal); % Método assume-se existente na superclasse
% Demodulação
if strcmp(obj.mod_type, 'QPSK')
rx_bits = pskdemod(rx_symbols, 4, pi/4, 'gray');
else
rx_bits = qamdemod(rx_symbols, 16, 'gray', 'OutputType', 'bit');
end
% Cálculo de erros
errors = sum(bits(:) ~= rx_bits(:));
total_errors = total_errors + errors;
total_bits = total_bits + length(bits);
end
ber(snr_idx) = total_errors / total_bits;
end
end
function plot_papr_performance(obj)
% Geração de gráficos de desempenho de PAPR
papr_original = [];
papr_clipped = [];
for i = 1:100
% Geração de dados
[symbols, ~] = obj.generate_data();
tx_signal = obj.ofdm_modulate(symbols);
% Cálculo de PAPR original
papr_orig = obj.calculate_papr(tx_signal);
papr_original = [papr_original, papr_orig];
% Aplica clipping
clipped_signal = obj.apply_clipping(tx_signal);
papr_clip = obj.calculate_papr(clipped_signal);
papr_clipped = [papr_clipped, papr_clip];
end
% Cálculo de CCDF
threshold_db = 0:0.1:12;
ccdf_original = zeros(size(threshold_db));
ccdf_clipped = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_original(i) = mean(papr_original > threshold_db(i));
ccdf_clipped(i) = mean(papr_clipped > threshold_db(i));
end
% Plotagem
figure('Position', [100, 100, 800, 600]);
subplot(2,2,1);
plot(threshold_db, ccdf_original, 'b-', 'LineWidth', 2);
hold on;
plot(threshold_db, ccdf_clipped, 'r--', 'LineWidth', 2);
xlabel('PAPR_0 (dB)');
ylabel('CCDF = Pr(PAPR > PAPR_0)');
title('Desempenho PAPR com Clipping Duro');
legend(['Original (CR=1.0)', sprintf('Clipping (CR=%.1f)', obj.clip_ratio)]);
grid on;
subplot(2,2,2);
[f_orig, x_orig] = ecdf(papr_original);
[f_clip, x_clip] = ecdf(papr_clipped);
plot(x_orig, 1-f_orig, 'b-', 'LineWidth', 2);
hold on;
plot(x_clip, 1-f_clip, 'r--', 'LineWidth', 2);
xlabel('PAPR (dB)');
ylabel('CCDF');
title('Curvas ECDF');
grid on;
subplot(2,2,3);
% Desempenho de BER
snr_db = obj.snr_db;
ber = obj.simulate_ber(snr_db);
semilogy(snr_db, ber, 'b-o', 'LineWidth', 2);
xlabel('SNR (dB)');
ylabel('BER');
title('Desempenho de BER com Clipping Duro');
grid on;
subplot(2,2,4);
% Diagrama de constelação
[symbols, ~] = obj.generate_data();
tx_signal = obj.ofdm_modulate(symbols(:,1));
clipped_signal = obj.apply_clipping(tx_signal);
scatter(real(tx_signal(1:1000)), imag(tx_signal(1:1000)), 10, 'b.');
hold on;
scatter(real(clipped_signal(1:1000)), imag(clipped_signal(1:1000)), 10, 'r.');
xlabel('Parte Real');
ylabel('Parte Imaginária');
title('Constelação no Domínio do Tempo');
legend('Original', 'Após Clipping');
axis equal;
grid on;
sgtitle(sprintf('Algoritmo de Clipping Duro (N=%d, %s)', obj.N, obj.mod_type));
end
end
end
3.2.2 Clipping Suave
O clipping suave aplica uma transição gradual em vez de uma limitação abrupta, visando reduzir a distorção gerada.
%% Algoritmo de Clipping Suave
classdef SoftClipping < OFDMSystem
% Implementação do algoritmo de Clipping Suave
properties
clip_ratio = 0.8; % Razão de limitação
smooth_factor = 0.1; % Fator de suavização
end
methods
function clipped_signal = apply_soft_clipping(obj, signal)
% Aplica o clipping suave ao sinal
amplitude = abs(signal);
phase = angle(signal);
% Define o limiar
threshold = obj.clip_ratio * max(amplitude(:));
% Função de clipping suave
amplitude_clipped = zeros(size(amplitude));
idx_below = amplitude <= threshold;
idx_above = amplitude > threshold;
% Parte abaixo do limiar permanece inalterada
amplitude_clipped(idx_below) = amplitude(idx_below);
% Parte acima do limiar aplica o clipping suave
excess = amplitude(idx_above) - threshold;
amplitude_clipped(idx_above) = threshold + ...
obj.smooth_factor * excess ./ (1 + obj.smooth_factor * excess/threshold);
% Reconstrói o sinal
clipped_signal = amplitude_clipped .* exp(1j*phase);
end
end
end
3.3 Algoritmos Probabilísticos
3.3.1 Selective Mapping (SLM)
O SLM gera múltiplos sinais OFDM a partir dos mesmos dados de entrada, rotacionando as fases das subportadoras. O sinal com o menor PAPR é selecionado para transmissão, exigindo o envio de informação de controle para a reconstrução.
%% Algoritmo Selective Mapping (SLM)
classdef SLM < OFDMSystem
% Implementação do algoritmo SLM
properties
U = 4; % Número de sequências de fase
phase_sequences; % Sequências de fase geradas
selected_indices; % Índices das sequências selecionadas
end
methods
function obj = SLM(varargin)
obj = obj@OFDMSystem(varargin{:});
obj.generate_phase_sequences();
end
function generate_phase_sequences(obj)
% Geração de sequências de fase aleatórias
obj.phase_sequences = exp(1j * 2*pi * rand(obj.N, obj.U));
end
function [tx_signal, best_idx] = apply_slm(obj, symbols)
% Aplica o algoritmo SLM
papr_values = zeros(1, obj.U);
candidate_signals = cell(1, obj.U);
for u = 1:obj.U
% Aplica rotação de fase
rotated_symbols = symbols .* obj.phase_sequences(:, u);
% Modulação OFDM
candidate = obj.ofdm_modulate(rotated_symbols);
candidate_signals{u} = candidate;
% Cálculo de PAPR
papr_values(u) = mean(obj.calculate_papr(candidate));
end
% Seleciona o sinal com menor PAPR
[~, best_idx] = min(papr_values);
tx_signal = candidate_signals{best_idx};
obj.selected_indices = best_idx;
end
function ber = simulate_ber_with_slm(obj, snr_db_values)
% Simulação de BER para SLM
ber = zeros(size(snr_db_values));
for snr_idx = 1:length(snr_db_values)
total_errors = 0;
total_bits = 0;
for sym_idx = 1:obj.num_symbols
% Geração de dados
bits_per_symbol = log2(obj.M) * obj.N;
bits = randi([0, 1], bits_per_symbol, 1);
% Modulação
if strcmp(obj.mod_type, 'QPSK')
symbols = pskmod(reshape(bits, 2, [])', 4, pi/4, 'gray');
else
symbols = qammod(reshape(bits, 4, [])', 16, 'gray', 'InputType', 'bit');
end
% Aplica SLM
[tx_signal, best_idx] = obj.apply_slm(symbols);
% Transmissão de informação de banda lateral (ideal)
side_info = de2bi(best_idx-1, ceil(log2(obj.U)), 'left-msb')';
% Adição de Ruído
signal_power = mean(abs(tx_signal).^2);
noise_power = signal_power / (10^(snr_db_values(snr_idx)/10));
noise = sqrt(noise_power/2) * (randn(size(tx_signal)) + 1j*randn(size(tx_signal)));
rx_signal = tx_signal + noise;
% Demodulação OFDM
rx_symbols_pre = obj.ofdm_demodulate(rx_signal); % Método assume-se existente na superclasse
% Aplica rotação inversa de fase (assumindo informação de banda lateral correta)
rx_symbols = rx_symbols_pre .* conj(obj.phase_sequences(:, best_idx));
% Demodulação
if strcmp(obj.mod_type, 'QPSK')
rx_bits = pskdemod(rx_symbols, 4, pi/4, 'gray');
else
rx_bits = qamdemod(rx_symbols, 16, 'gray', 'OutputType', 'bit');
end
% Cálculo de erros
errors = sum(bits(:) ~= rx_bits(:));
total_errors = total_errors + errors;
total_bits = total_bits + length(bits);
end
ber(snr_idx) = total_errors / total_bits;
end
end
function plot_slm_performance(obj)
% Geração de gráficos de desempenho SLM
papr_original = [];
papr_slm = [];
for i = 1:100
[symbols, ~] = obj.generate_data();
% OFDM Original
tx_original = obj.ofdm_modulate(symbols);
papr_orig = obj.calculate_papr(tx_original);
papr_original = [papr_original, papr_orig];
% SLM
[tx_slm, ~] = obj.apply_slm(symbols);
papr_s = obj.calculate_papr(tx_slm);
papr_slm = [papr_slm, papr_s];
end
% Cálculo de CCDF
threshold_db = 0:0.1:12;
ccdf_original = zeros(size(threshold_db));
ccdf_slm = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_original(i) = mean(papr_original > threshold_db(i));
ccdf_slm(i) = mean(papr_slm > threshold_db(i));
end
% Plotagem
figure('Position', [100, 100, 1000, 400]);
subplot(1,2,1);
plot(threshold_db, ccdf_original, 'b-', 'LineWidth', 2);
hold on;
plot(threshold_db, ccdf_slm, 'r--', 'LineWidth', 2);
xlabel('PAPR_0 (dB)');
ylabel('CCDF = Pr(PAPR > PAPR_0)');
title(sprintf('Desempenho PAPR com SLM (U=%d)', obj.U));
legend('Original', 'SLM');
grid on;
subplot(1,2,2);
% Comparação com diferentes valores de U
U_values = [2, 4, 8, 16];
colors = {'b-', 'r--', 'g-.', 'm:'};
for u_idx = 1:length(U_values)
obj.U = U_values(u_idx);
obj.generate_phase_sequences();
papr_slm_u = [];
for i = 1:50
[symbols, ~] = obj.generate_data();
[tx_slm, ~] = obj.apply_slm(symbols);
papr_s = obj.calculate_papr(tx_slm);
papr_slm_u = [papr_slm_u, papr_s];
end
ccdf_slm_u = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_slm_u(i) = mean(papr_slm_u > threshold_db(i));
end
plot(threshold_db, ccdf_slm_u, colors{u_idx}, 'LineWidth', 2);
hold on;
end
plot(threshold_db, ccdf_original, 'k-', 'LineWidth', 3);
xlabel('PAPR_0 (dB)');
ylabel('CCDF');
title('Desempenho SLM com diferentes U');
legend(arrayfun(@(x) sprintf('U=%d', x), U_values, 'UniformOutput', false), 'Original');
grid on;
sgtitle(sprintf('Algoritmo Selective Mapping (SLM) (N=%d, %s)', obj.N, obj.mod_type));
end
end
end
3.3.2 Partial Transmit Sequences (PTS)
O PTS divide o sinal OFDM em subconjuntos, aplica rotações de fase a cada subconjunto e recombina-os para minimizar o PAPR. Asim como o SLM, requer informação de banda lateral.
%% Algoritmo Partial Transmit Sequences (PTS)
classdef PTS < OFDMSystem
% Implementação do algoritmo PTS
properties
V = 4; % Número de partições
W = 4; % Número de fatores de fase
phase_factors; % Conjunto de fatores de fase
partition_method = 'adjacent'; % Método de particionamento
end
methods
function obj = PTS(varargin)
obj = obj@OFDMSystem(varargin{:});
obj.generate_phase_factors();
end
function generate_phase_factors(obj)
% Geração de fatores de fase
obj.phase_factors = exp(1j * 2*pi/obj.W * (0:obj.W-1));
end
function [tx_signal, best_phase] = apply_pts(obj, symbols)
% Aplica o algoritmo PTS
% Particionamento das subportadoras
switch obj.partition_method
case 'adjacent'
% Particionamento adjacente
subcarriers_per_part = floor(obj.N / obj.V);
partitions = zeros(obj.N, obj.V);
for v = 1:obj.V
start_idx = (v-1)*subcarriers_per_part + 1;
end_idx = min(v*subcarriers_per_part, obj.N);
partitions(start_idx:end_idx, v) = 1;
end
case 'interleaved'
% Particionamento entrelaçado
partitions = zeros(obj.N, obj.V);
for n = 1:obj.N
v = mod(n-1, obj.V) + 1;
partitions(n, v) = 1;
end
case 'pseudo'
% Particionamento pseudo-aleatório
partitions = zeros(obj.N, obj.V);
for n = 1:obj.N
v = randi([1, obj.V]);
partitions(n, v) = 1;
end
end
% Geração de sequências parciais
part_sequences = cell(1, obj.V);
for v = 1:obj.V
part_symbols = symbols .* partitions(:, v);
part_sequences{v} = obj.ofdm_modulate(part_symbols);
end
% Busca pela combinação ótima de fases
min_papr = inf;
best_signal = [];
best_phase = ones(1, obj.V);
% Itera sobre todas as combinações de fases
phase_combinations = obj.generate_all_combinations(obj.V, obj.W);
for combo_idx = 1:size(phase_combinations, 1)
phase_combo = phase_combinations(combo_idx, :);
% Combina os sinais
combined_signal = zeros(size(part_sequences{1}));
for v = 1:obj.V
phase_factor = obj.phase_factors(phase_combo(v));
combined_signal = combined_signal + phase_factor * part_sequences{v};
end
% Cálculo de PAPR
papr = mean(obj.calculate_papr(combined_signal));
if papr < min_papr
min_papr = papr;
best_signal = combined_signal;
best_phase = phase_combo;
end
end
tx_signal = best_signal;
end
function combinations = generate_all_combinations(obj, V, W)
% Geração de todas as combinações de fases
indices = 1:W;
combs = cell(V, 1);
[combs{:}] = ndgrid(indices);
combinations = reshape(cat(V+1, combs{:}), [], V);
end
function plot_pts_performance(obj)
% Geração de gráficos de desempenho PTS
papr_original = [];
papr_pts = [];
for i = 1:50
[symbols, ~] = obj.generate_data();
% OFDM Original
tx_original = obj.ofdm_modulate(symbols);
papr_orig = obj.calculate_papr(tx_original);
papr_original = [papr_original, papr_orig];
% PTS
[tx_pts, ~] = obj.apply_pts(symbols);
papr_p = obj.calculate_papr(tx_pts);
papr_pts = [papr_pts, papr_p];
end
% Cálculo de CCDF
threshold_db = 0:0.1:12;
ccdf_original = zeros(size(threshold_db));
ccdf_pts = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_original(i) = mean(papr_original > threshold_db(i));
ccdf_pts(i) = mean(papr_pts > threshold_db(i));
end
% Plotagem
figure('Position', [100, 100, 1200, 400]);
subplot(1,3,1);
plot(threshold_db, ccdf_original, 'b-', 'LineWidth', 2);
hold on;
plot(threshold_db, ccdf_pts, 'r--', 'LineWidth', 2);
xlabel('PAPR_0 (dB)');
ylabel('CCDF');
title(sprintf('Desempenho PAPR com PTS (V=%d, W=%d)', obj.V, obj.W));
legend('Original', 'PTS');
grid on;
subplot(1,3,2);
% Comparação com diferentes métodos de particionamento
methods = {'adjacent', 'interleaved', 'pseudo'};
colors = {'b-', 'r--', 'g-.'};
for m_idx = 1:length(methods)
obj.partition_method = methods{m_idx};
papr_pts_m = [];
for i = 1:30
[symbols, ~] = obj.generate_data();
[tx_pts, ~] = obj.apply_pts(symbols);
papr_p = obj.calculate_papr(tx_pts);
papr_pts_m = [papr_pts_m, papr_p];
end
ccdf_pts_m = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_pts_m(i) = mean(papr_pts_m > threshold_db(i));
end
plot(threshold_db, ccdf_pts_m, colors{m_idx}, 'LineWidth', 2);
hold on;
end
plot(threshold_db, ccdf_original, 'k-', 'LineWidth', 3);
xlabel('PAPR_0 (dB)');
ylabel('CCDF');
title('Comparação de Métodos de Particionamento');
legend(methods{:}, 'Original');
grid on;
subplot(1,3,3);
% Análise de complexidade computacional
V_values = [2, 4, 8];
W_values = [2, 4];
complexity = zeros(length(V_values), length(W_values));
papr_gain = zeros(length(V_values), length(W_values));
for v_idx = 1:length(V_values)
for w_idx = 1:length(W_values)
obj.V = V_values(v_idx);
obj.W = W_values(w_idx);
obj.generate_phase_factors();
% Complexidade = W^V
complexity(v_idx, w_idx) = obj.W^obj.V;
% Ganho de PAPR
papr_pts_test = [];
for i = 1:20
[symbols, ~] = obj.generate_data();
[tx_pts, ~] = obj.apply_pts(symbols);
papr_p = obj.calculate_papr(tx_pts);
papr_pts_test = [papr_pts_test, papr_p];
end
papr_gain(v_idx, w_idx) = mean(papr_original(1:20)) - mean(papr_pts_test);
end
end
% Gráfico de barras 3D
[X, Y] = meshgrid(1:length(W_values), 1:length(V_values));
bar3(complexity);
xlabel('W');
ylabel('V');
zlabel('Complexidade Computacional');
title('Análise de Complexidade Computacional PTS');
set(gca, 'XTickLabel', W_values);
set(gca, 'YTickLabel', V_values);
grid on;
sgtitle(sprintf('Algoritmo Partial Transmit Sequences (PTS) (N=%d, %s)', obj.N, obj.mod_type));
end
end
end
3.4 Algoritmo de Expansão/Compressão (Companding)
O Companding (μ-law) comprime a faixa dinâmica do sinal antes da transmissão e o expande na recepção, o que pode reduzir o PAPR.
%% Algoritmo de Companding μ-law
classdef MuLawCompanding < OFDMSystem
% Implementação do algoritmo de Companding μ-law
properties
mu = 255; % Parâmetro de companding
end
methods
function compressed = compress(obj, signal)
% Compressão do sinal
max_amplitude = max(abs(signal(:)));
normalized = signal / max_amplitude;
compressed = (log(1 + obj.mu * abs(normalized)) / log(1 + obj.mu)) .* ...
exp(1j * angle(normalized)) * max_amplitude;
end
function expanded = expand(obj, signal)
% Expansão do sinal
max_amplitude = max(abs(signal(:)));
normalized = signal / max_amplitude;
expanded = ((1/obj.mu) * ((1 + obj.mu).^abs(normalized) - 1)) .* ...
exp(1j * angle(normalized)) * max_amplitude;
end
function plot_companding_performance(obj)
% Geração de gráficos de desempenho do Companding
papr_original = [];
papr_companded = [];
for i = 1:100
[symbols, ~] = obj.generate_data();
tx_original = obj.ofdm_modulate(symbols);
% Companding
tx_companded = obj.compress(tx_original);
papr_orig = obj.calculate_papr(tx_original);
papr_comp = obj.calculate_papr(tx_companded);
papr_original = [papr_original, papr_orig];
papr_companded = [papr_companded, papr_comp];
end
% Cálculo de CCDF
threshold_db = 0:0.1:12;
ccdf_original = zeros(size(threshold_db));
ccdf_companded = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_original(i) = mean(papr_original > threshold_db(i));
ccdf_companded(i) = mean(papr_companded > threshold_db(i));
end
% Plotagem
figure('Position', [100, 100, 800, 600]);
subplot(2,2,1);
plot(threshold_db, ccdf_original, 'b-', 'LineWidth', 2);
hold on;
plot(threshold_db, ccdf_companded, 'r--', 'LineWidth', 2);
xlabel('PAPR_0 (dB)');
ylabel('CCDF');
title(sprintf('Desempenho PAPR Companding μ-law (μ=%.0f)', obj.mu));
legend('Original', 'Após Companding');
grid on;
subplot(2,2,2);
% Comparação com diferentes valores de μ
mu_values = [1, 10, 100, 255];
colors = {'b-', 'r--', 'g-.', 'm:'};
for mu_idx = 1:length(mu_values)
obj.mu = mu_values(mu_idx);
papr_mu = [];
for i = 1:50
[symbols, ~] = obj.generate_data();
tx_signal = obj.ofdm_modulate(symbols);
tx_comp = obj.compress(tx_signal);
papr_c = obj.calculate_papr(tx_comp);
papr_mu = [papr_mu, papr_c];
end
ccdf_mu = zeros(size(threshold_db));
for i = 1:length(threshold_db)
ccdf_mu(i) = mean(papr_mu > threshold_db(i));
end
plot(threshold_db, ccdf_mu, colors{mu_idx}, 'LineWidth', 2);
hold on;
end
plot(threshold_db, ccdf_original, 'k-', 'LineWidth', 3);
xlabel('PAPR_0 (dB)');
ylabel('CCDF');
title('Comparação de Desempenho com Diferentes μ');
legend(arrayfun(@(x) sprintf('μ=%.0f', x), mu_values, 'UniformOutput', false), 'Original');
grid on;
subplot(2,2,3);
% Curva característica do Companding
x = linspace(0, 1, 1000);
for mu_idx = 1:length(mu_values)
mu = mu_values(mu_idx);
y = log(1 + mu * x) / log(1 + mu);
plot(x, y, colors{mu_idx}, 'LineWidth', 2);
hold on;
end
plot(x, x, 'k--', 'LineWidth', 1);
xlabel('Entrada Normalizada');
ylabel('Saída Normalizada');
title('Característica do Companding μ-law');
legend(arrayfun(@(x) sprintf('μ=%.0f', x), mu_values, 'UniformOutput', false), 'Linear');
grid on;
subplot(2,2,4);
% Desempenho de BER
snr_db = 0:2:20;
ber_original = zeros(size(snr_db));
ber_companded = zeros(size(snr_db));
for snr_idx = 1:length(snr_db)
ber_o = 0;
ber_c = 0;
total_bits = 0;
for sym_idx = 1:10
% Geração de dados
bits_per_symbol = log2(obj.M) * obj.N;
bits = randi([0, 1], bits_per_symbol, 1);
if strcmp(obj.mod_type, 'QPSK')
symbols = pskmod(reshape(bits, 2, [])', 4, pi/4, 'gray');
else
symbols = qammod(reshape(bits, 4, [])', 16, 'gray', 'InputType', 'bit');
end
% OFDM Original
tx_original = obj.ofdm_modulate(symbols);
signal_power = mean(abs(tx_original).^2);
noise_power = signal_power / (10^(snr_db(snr_idx)/10));
noise = sqrt(noise_power/2) * (randn(size(tx_original)) + 1j*randn(size(tx_original)));
rx_original = tx_original + noise;
rx_symbols_o = obj.ofdm_demodulate(rx_original);
% OFDM com Companding
tx_comp = obj.compress(tx_original);
signal_power_c = mean(abs(tx_comp).^2);
noise_power_c = signal_power_c / (10^(snr_db(snr_idx)/10));
noise_c = sqrt(noise_power_c/2) * (randn(size(tx_comp)) + 1j*randn(size(tx_comp)));
rx_comp = tx_comp + noise_c;
rx_expanded = obj.expand(rx_comp);
rx_symbols_c = obj.ofdm_demodulate(rx_expanded);
% Demodulação
if strcmp(obj.mod_type, 'QPSK')
rx_bits_o = pskdemod(rx_symbols_o, 4, pi/4, 'gray');
rx_bits_c = pskdemod(rx_symbols_c, 4, pi/4, 'gray');
else
rx_bits_o = qamdemod(rx_symbols_o, 16, 'gray', 'OutputType', 'bit');
rx_bits_c = qamdemod(rx_symbols_c, 16, 'gray', 'OutputType', 'bit');
end
errors_o = sum(bits ~= rx_bits_o);
errors_c = sum(bits ~= rx_bits_c);
ber_o = ber_o + errors_o;
ber_c = ber_c + errors_c;
total_bits = total_bits + length(bits);
end
ber_original(snr_idx) = ber_o / total_bits;
ber_companded(snr_idx) = ber_c / total_bits;
end
semilogy(snr_db, ber_original, 'b-o', 'LineWidth', 2);
hold on;
semilogy(snr_db, ber_companded, 'r-s', 'LineWidth', 2);
xlabel('SNR (dB)');
ylabel('BER');
title('Impacto do Companding no BER');
legend('Original', 'Companding');
grid on;
sgtitle('Análise de Desempenho do Companding μ-law');
end
end
end
- Comparação Abrangente de Desempenho
4.1 Comparação de Desempenho de Algoritmos
Esta seção compara o desempenho de PAPR, complexidade e outras métricas de vários algoritmos.
%% Comparação Abrangente de Algoritmos
classdef PAPRComparison
% Comparação abrangente de algoritmos de redução de PAPR
methods (Static)
function compare_all_algorithms()
% Compara todos os algoritmos
% Configuração dos parâmetros
N = 64;
M = 4; % QPSK
num_symbols = 1000;
L = 4;
% Criação de instâncias dos algoritmos
ofdm_base = OFDMSystem('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols);
% Clipping Duro
clipping = HardClipping('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols, 'clip_ratio', 0.8);
% SLM
slm = SLM('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols, 'U', 4);
% PTS
pts = PTS('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols, 'V', 4, 'W', 4);
% Companding
companding = MuLawCompanding('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols, 'mu', 255);
% Geração de dados
[symbols, bits] = ofdm_base.generate_data();
% Cálculo de PAPR para cada algoritmo
papr_results = struct();
% OFDM Original
tx_original = ofdm_modulate(ofdm_base, symbols);
papr_results.original = calculate_papr(ofdm_base, tx_original);
% Clipping Duro
tx_clipped = apply_clipping(clipping, tx_original);
papr_results.clipping = calculate_papr(clipping, tx_clipped);
% SLM
[tx_slm, ~] = apply_slm(slm, symbols);
papr_results.slm = calculate_papr(slm, tx_slm);
% PTS
[tx_pts, ~] = apply_pts(pts, symbols);
papr_results.pts = calculate_papr(pts, tx_pts);
% Companding
tx_comp = compress(companding, tx_original);
papr_results.companding = calculate_papr(companding, tx_comp);
% Plotagem da comparação de CCDF
figure('Position', [100, 100, 1000, 800]);
subplot(2,2,1);
threshold_db = 0:0.1:12;
algorithms = fieldnames(papr_results);
colors = {'k-', 'b-', 'r--', 'g-.', 'm:', 'c-'};
for i = 1:length(algorithms)
papr_data = papr_results.(algorithms{i});
ccdf = zeros(size(threshold_db));
for t = 1:length(threshold_db)
ccdf(t) = mean(papr_data > threshold_db(t));
end
plot(threshold_db, ccdf, colors{i}, 'LineWidth', 2);
hold on;
end
xlabel('PAPR_0 (dB)');
ylabel('CCDF = Pr(PAPR > PAPR_0)');
title('Comparação de Desempenho PAPR dos Algoritmos');
legend(algorithms, 'Location', 'northeast');
grid on;
subplot(2,2,2);
% Comparação de PAPR médio
avg_papr = zeros(length(algorithms), 1);
std_papr = zeros(length(algorithms), 1);
for i = 1:length(algorithms)
avg_papr(i) = mean(papr_results.(algorithms{i}));
std_papr(i) = std(papr_results.(algorithms{i}));
end
bar(1:length(algorithms), avg_papr);
hold on;
errorbar(1:length(algorithms), avg_papr, std_papr, 'k.', 'LineWidth', 2);
set(gca, 'XTickLabel', algorithms);
xtickangle(45);
ylabel('PAPR Médio (dB)');
title('Comparação de PAPR Médio');
grid on;
subplot(2,2,3);
% Ganho de PAPR
papr_gain = avg_papr(1) - avg_papr;
bar(1:length(algorithms), papr_gain);
set(gca, 'XTickLabel', algorithms);
xtickangle(45);
ylabel('Ganho de PAPR (dB)');
title('Ganho de PAPR em Relação ao OFDM Original');
grid on;
subplot(2,2,4);
% Comparação de complexidade computacional
complexity = [
1; % Original
N; % Clipping
slm.U * N; % SLM
pts.W^pts.V; % PTS
N % Companding
];
bar(1:length(algorithms), log10(complexity));
set(gca, 'XTickLabel', algorithms);
xtickangle(45);
ylabel('log10(Complexidade Computacional)');
title('Comparação de Complexidade Computacional');
grid on;
sgtitle('Comparação Abrangente dos Algoritmos de Redução de PAPR OFDM');
% Exibe a tabela estatística
fprintf('\n=== Estatísticas de Desempenho dos Algoritmos ===\n');
fprintf('%-15s %-10s %-10s %-10s %-10s\n', ...
'Algoritmo', 'PAPR Médio', 'Desvio Padrão', 'Ganho PAPR', 'Complexidade');
fprintf('%s\n', repmat('-', 60, 1));
for i = 1:length(algorithms)
fprintf('%-15s %-10.2f %-10.2f %-10.2f %-10.0f\n', ...
algorithms{i}, avg_papr(i), std_papr(i), ...
papr_gain(i), complexity(i));
end
end
function ber_comparison()
% Comparação de desempenho de BER
N = 64;
M = 4;
num_symbols = 100;
snr_db = 0:2:20;
% Criação de instâncias dos algoritmos
clipping = HardClipping('N', N, 'M', M, 'num_symbols', num_symbols);
slm = SLM('N', N, 'M', M, 'num_symbols', num_symbols, 'U', 4);
pts = PTS('N', N, 'M', M, 'num_symbols', num_symbols, 'V', 4, 'W', 4);
companding = MuLawCompanding('N', N, 'M', M, 'num_symbols', num_symbols, 'mu', 255);
% Simulação de BER
ber_results = struct();
ber_results.clipping = zeros(size(snr_db));
ber_results.slm = zeros(size(snr_db));
ber_results.pts = zeros(size(snr_db));
ber_results.companding = zeros(size(snr_db));
fprintf('Iniciando simulação de BER...\n');
for snr_idx = 1:length(snr_db)
fprintf('SNR = %d dB\n', snr_db(snr_idx));
% Clipping Duro
ber_results.clipping(snr_idx) = simulate_ber(clipping, snr_db(snr_idx));
% SLM
ber_results.slm(snr_idx) = simulate_ber_with_slm(slm, snr_db(snr_idx));
% Companding
ber_m = 0;
for i = 1:10
[symbols, bits] = generate_data(companding);
tx_signal = ofdm_modulate(companding, symbols);
tx_comp = compress(companding, tx_signal);
signal_power = mean(abs(tx_comp).^2);
noise_power = signal_power / (10^(snr_db(snr_idx)/10));
noise = sqrt(noise_power/2) * (randn(size(tx_comp)) + 1j*randn(size(tx_comp)));
rx_signal = tx_comp + noise;
rx_expanded = expand(companding, rx_signal);
rx_symbols = ofdm_demodulate(companding, rx_expanded); % Método assume-se existente na superclasse
if strcmp(companding.mod_type, 'QPSK')
rx_bits = pskdemod(rx_symbols, 4, pi/4, 'gray');
else
rx_bits = qamdemod(rx_symbols, 16, 'gray', 'OutputType', 'bit');
end
errors = sum(bits ~= rx_bits);
ber_m = ber_m + errors / length(bits);
end
ber_results.companding(snr_idx) = ber_m / 10;
end
% Plotagem das curvas de BER
figure('Position', [100, 100, 800, 600]);
algorithms = fieldnames(ber_results);
colors = {'b-', 'r--', 'g-.', 'm:'};
markers = {'o', 's', '^', 'd'};
for i = 1:length(algorithms)
plot(snr_db, ber_results.(algorithms{i}), ...
[colors{i}, markers{i}], 'LineWidth', 2, 'MarkerSize', 8);
hold on;
end
% BER Teórica QPSK
ber_theory = 0.5 * erfc(sqrt(10.^(snr_db/10)));
plot(snr_db, ber_theory, 'k-', 'LineWidth', 2);
xlabel('SNR (dB)');
ylabel('BER');
title('Desempenho de BER de Vários Algoritmos de Redução de PAPR');
legend([algorithms; 'QPSK Teórico'], 'Location', 'southwest');
grid on;
ylim([1e-5, 1]);
% Análise de perda de SNR
fprintf('\n=== Análise de Perda de SNR (BER=10^{-3}) ===\n');
target_ber = 1e-3;
for i = 1:length(algorithms)
ber_data = ber_results.(algorithms{i});
idx = find(ber_data <= target_ber, 1);
if ~isempty(idx)
snr_at_target = snr_db(idx);
snr_theory = interp1(log10(ber_theory), snr_db, log10(target_ber));
snr_loss = snr_at_target - snr_theory;
fprintf('%-10s: SNR@BER=1e-3 = %.2f dB, Perda de SNR = %.2f dB\n', ...
algorithms{i}, snr_at_target, snr_loss);
end
end
end
end
end
Referência do Código Original: www.youwenfan.com/contentcsu/55026.html
- Recomendações de Aplicação Prática
5.1 Guia de Seleção de Algoritmo
| Cenário de Aplicação | Algoritmo Recomendado | Justificativa |
|---|---|---|
| Comunicação em Tempo Real | Clipping, Companding | Baixa complexidade, baixa latência |
| Alta Confiabilidade | SLM, PTS | Sem distorção, bom desempenho de BER |
| Dispositivos Móveis | Companding, Clipping | Baixo consumo de energia, implementação simples |
| Sistemas de Transmissão | SLM | Tolerância ao overhead de informação de banda lateral |
| Comunicações Militares | PTS | Boa segurança, desempenho superior |
5.2 Sugestões de Otimização de Parâmetros
%% Função de Otimização de Parâmetros
function optimize_parameters()
% Otimização de parâmetros
% 1. Otimização do valor U para SLM
N = 64;
U_values = [2, 4, 8, 16, 32];
papr_gain = zeros(size(U_values));
complexity = zeros(size(U_values));
for i = 1:length(U_values)
slm = SLM('N', N, 'U', U_values(i));
% Avaliação de desempenho
papr_data = [];
for j = 1:50
[symbols, ~] = generate_data(slm);
[tx_slm, ~] = apply_slm(slm, symbols);
papr = calculate_papr(slm, tx_slm);
papr_data = [papr_data, papr];
end
% PAPR Original
tx_original = ofdm_modulate(slm, symbols);
papr_orig = calculate_papr(slm, tx_original);
papr_gain(i) = mean(papr_orig) - mean(papr_data);
complexity(i) = U_values(i) * N;
end
% Busca pelo valor ótimo de U
figure;
yyaxis left;
plot(U_values, papr_gain, 'b-o', 'LineWidth', 2);
ylabel('Ganho de PAPR (dB)');
yyaxis right;
plot(U_values, complexity, 'r-s', 'LineWidth', 2);
ylabel('Complexidade Computacional');
xlabel('Valor de U');
title('Otimização de Parâmetros SLM');
legend('Ganho de PAPR', 'Complexidade Computacional');
grid on;
% 2. Otimização da Razão de Clipping
CR_values = 0.5:0.1:1.0;
papr_clipped = zeros(size(CR_values));
ber_clipped = zeros(size(CR_values));
for i = 1:length(CR_values)
clipping = HardClipping('clip_ratio', CR_values(i));
% Avaliação de PAPR
papr_data = [];
for j = 1:50
[symbols, ~] = generate_data(clipping);
tx_signal = ofdm_modulate(clipping, symbols);
tx_clipped = apply_clipping(clipping, tx_signal);
papr = calculate_papr(clipping, tx_clipped);
papr_data = [papr_data, papr];
end
papr_clipped(i) = mean(papr_data);
% Avaliação de BER
ber_clipped(i) = simulate_ber(clipping, 10); % SNR=10dB
end
figure;
yyaxis left;
plot(CR_values, papr_clipped, 'b-o', 'LineWidth', 2);
ylabel('PAPR Médio (dB)');
yyaxis right;
semilogy(CR_values, ber_clipped, 'r-s', 'LineWidth', 2);
ylabel('BER');
xlabel('Razão de Clipping (CR)');
title('Otimização de Parâmetros de Clipping');
legend('PAPR', 'BER');
grid on;
end
- Conclusão
6.1 Resumo do Desempenho dos Algoritmos
| Algoritmo | Ganho PAPR | Impacto na BER | Complexidade Computacional | Informação de Banda Lateral | Cenário de Aplicação |
|---|---|---|---|---|---|
| Clipping Duro | 3-5 dB | Severo | Baixa | Não | Sistemas de tempo real de baixo custo |
| SLM | 4-6 dB | Nenhum | Média | Sim | Transmissão, rádio fixo |
| PTS | 5-7 dB | Nenhum | Alta | Sim | Rádio de alto desempenho |
| Companding | 2-4 dB | Leve | Baixa | Não | Comunicações móveis |
6.2 Código MATLAB de Uso Prático
% Exemplo de uso rápido
clear; clc; close all;
% 1. Criação do sistema OFDM
ofdm = OFDMSystem('N', 64, 'M', 4, 'mod_type', 'QPSK');
% 2. Geração de dados
[symbols, bits] = generate_data(ofdm);
% 3. Aplicação de SLM para reduzir PAPR
slm = SLM('N', 64, 'U', 4);
[tx_slm, idx] = apply_slm(slm, symbols);
% 4. Cálculo de PAPR
papr_original = calculate_papr(ofdm, ofdm_modulate(ofdm, symbols));
papr_slm = calculate_papr(slm, tx_slm);
fprintf('PAPR Original: %.2f dB\n', mean(papr_original));
fprintf('PAPR após SLM: %.2f dB\n', mean(papr_slm));
fprintf('Ganho de PAPR: %.2f dB\n', mean(papr_original) - mean(papr_slm));
% 5. Plotagem dos resultados
figure;
subplot(1,2,1);
histogram(papr_original, 20, 'FaceColor', 'b');
xlabel('PAPR (dB)'); ylabel('Frequência');
title('Distribuição PAPR OFDM Original');
subplot(1,2,2);
histogram(papr_slm, 20, 'FaceColor', 'r');
xlabel('PAPR (dB)'); ylabel('Frequência');
title('Distribuição PAPR após SLM');