降低OFDM系统PAPR的各种算法及误码率分析

正交频分复用(OFDM)系统的主要缺点之一是高峰均功率比(PAPR),这会导致功率放大器非线性失真、增加误码率。以下是各种降低PAPR算法的MATLAB实现及性能分析。

一、PAPR问题概述

1.1 PAPR定义

复制代码
PAPR(dB) = 10·log₁₀(max|s(t)|² / E[|s(t)|²])

其中s(t)是OFDM时域信号,E[·]表示期望。

1.2 系统模型

  • 子载波数:N = 64, 128, 256, ...
  • 调制方式:QPSK, 16QAM, 64QAM
  • 过采样因子:L = 4(准确评估PAPR)

二、PAPR降低算法分类

算法类别 代表算法 优点 缺点 BER影响
限幅类 硬限幅、软限幅 实现简单 非线性失真 恶化明显
概率类 SLM、PTS 无失真 计算复杂,需边带信息 无恶化
编码类 块编码、Golay码 无失真 频谱效率低 无恶化
预失真类 ACE、TR 性能好 计算量大 轻微恶化
加扰类 载波预留、压扩 复杂度低 性能受限 轻微恶化

三、MATLAB完整实现

3.1 基础OFDM系统

matlab 复制代码
%% OFDM系统基础模型
classdef OFDMSystem < handle
    % OFDM系统基类
    
    properties
        N = 64;             % 子载波数
        Ncp = 16;           % 循环前缀长度
        M = 4;              % 调制阶数 (QPSK=4, 16QAM=16, 64QAM=64)
        L = 4;              % 过采样因子
        mod_type = 'QPSK';  % 调制类型
        snr_db = 0:2:20;    % 信噪比范围
        num_symbols = 1000; % OFDM符号数
    end
    
    methods
        function obj = OFDMSystem(varargin)
            % 构造函数
            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)
            % 生成随机数据
            bits_per_symbol = log2(obj.M) * obj.N;
            total_bits = bits_per_symbol * obj.num_symbols;
            bits = randi([0, 1], total_bits, 1);
            
            % 调制
            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)
            % OFDM调制
            [N, num_sym] = size(symbols);
            
            % 过采样
            if obj.L > 1
                padded_symbols = zeros(N*obj.L, num_sym);
                center = floor(N/2);
                padded_symbols(1:center, :) = symbols(1:center, :);
                padded_symbols(end-center+1:end, :) = symbols(center+1:end, :);
            else
                padded_symbols = symbols;
            end
            
            % IFFT
            tx_signal = ifft(padded_symbols, N*obj.L, 1);
            
            % 添加循环前缀
            tx_signal = [tx_signal(end-obj.Ncp*obj.L+1:end, :); tx_signal];
        end
        
        function papr_db = calculate_papr(obj, signal)
            % 计算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)
            % 计算CCDF
            papr_values = papr_values(:);
            ccdf = mean(papr_values > threshold_db);
        end
        
        function ber = simulate_ber(obj, varargin)
            % BER仿真框架
            % 子类需重写此方法
            error('必须在子类中实现');
        end
    end
end

3.2 限幅类算法

3.2.1 硬限幅
matlab 复制代码
%% 硬限幅算法
classdef HardClipping < OFDMSystem
    % 硬限幅算法
    
    properties
        clip_ratio = 0.8;  % 限幅比例 (CR)
    end
    
    methods
        function obj = HardClipping(varargin)
            obj = obj@OFDMSystem(varargin{:});
        end
        
        function clipped_signal = apply_clipping(obj, signal)
            % 应用硬限幅
            amplitude = abs(signal);
            phase = angle(signal);
            
            % 计算限幅门限
            threshold = obj.clip_ratio * max(amplitude(:));
            
            % 限幅
            amplitude_clipped = min(amplitude, threshold);
            
            % 重建信号
            clipped_signal = amplitude_clipped .* exp(1j*phase);
        end
        
        function ber = simulate_ber(obj, snr_db)
            % BER仿真
            ber = zeros(size(snr_db));
            
            for snr_idx = 1:length(snr_db)
                total_errors = 0;
                total_bits = 0;
                
                for sym_idx = 1:obj.num_symbols
                    % 生成数据
                    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调制
                    tx_signal = obj.ofdm_modulate(symbols);
                    
                    % 限幅
                    clipped_signal = obj.apply_clipping(tx_signal);
                    
                    % 添加噪声
                    signal_power = mean(abs(clipped_signal).^2);
                    noise_power = signal_power / (10^(snr_db(snr_idx)/10));
                    noise = sqrt(noise_power/2) * (randn(size(clipped_signal)) + 1j*randn(size(clipped_signal)));
                    rx_signal = clipped_signal + noise;
                    
                    % OFDM解调
                    rx_symbols = obj.ofdm_demodulate(rx_signal);
                    
                    % 解调
                    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
                    
                    % 计算误码
                    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)
            % 绘制PAPR性能
            papr_original = [];
            papr_clipped = [];
            
            for i = 1:100
                % 生成数据
                [symbols, ~] = obj.generate_data();
                tx_signal = obj.ofdm_modulate(symbols);
                
                % 计算原始PAPR
                papr_orig = obj.calculate_papr(tx_signal);
                papr_original = [papr_original, papr_orig];
                
                % 应用限幅
                clipped_signal = obj.apply_clipping(tx_signal);
                papr_clip = obj.calculate_papr(clipped_signal);
                papr_clipped = [papr_clipped, papr_clip];
            end
            
            % 计算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
            
            % 绘图
            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('硬限幅PAPR性能');
            legend(['原始 (CR=1.0)', sprintf('限幅 (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('ECDF曲线');
            grid on;
            
            subplot(2,2,3);
            % 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('硬限幅BER性能');
            grid on;
            
            subplot(2,2,4);
            % 星座图
            [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('实部');
            ylabel('虚部');
            title('时域信号星座图');
            legend('原始', '限幅后');
            axis equal;
            grid on;
            
            sgtitle(sprintf('硬限幅算法性能 (N=%d, %s)', obj.N, obj.mod_type));
        end
    end
end
3.2.2 软限幅
matlab 复制代码
%% 软限幅算法
classdef SoftClipping < OFDMSystem
    % 软限幅算法
    
    properties
        clip_ratio = 0.8;      % 限幅比例
        smooth_factor = 0.1;   % 平滑因子
    end
    
    methods
        function clipped_signal = apply_soft_clipping(obj, signal)
            % 应用软限幅
            amplitude = abs(signal);
            phase = angle(signal);
            
            % 计算门限
            threshold = obj.clip_ratio * max(amplitude(:));
            
            % 软限幅函数
            % 分段函数:低于门限保持原样,高于门限平滑过渡
            amplitude_clipped = zeros(size(amplitude));
            
            idx_below = amplitude <= threshold;
            idx_above = amplitude > threshold;
            
            % 低于门限部分保持不变
            amplitude_clipped(idx_below) = amplitude(idx_below);
            
            % 高于门限部分应用软限幅
            excess = amplitude(idx_above) - threshold;
            amplitude_clipped(idx_above) = threshold + ...
                obj.smooth_factor * excess ./ (1 + obj.smooth_factor * excess/threshold);
            
            % 重建信号
            clipped_signal = amplitude_clipped .* exp(1j*phase);
        end
    end
end

3.3 概率类算法

3.3.1 选择性映射(SLM)
matlab 复制代码
%% 选择性映射算法
classdef SLM < OFDMSystem
    % 选择性映射算法
    
    properties
        U = 4;              % 相位序列数量
        phase_sequences;    % 相位序列
        selected_indices;   % 选择的序列索引
    end
    
    methods
        function obj = SLM(varargin)
            obj = obj@OFDMSystem(varargin{:});
            obj.generate_phase_sequences();
        end
        
        function generate_phase_sequences(obj)
            % 生成相位序列
            obj.phase_sequences = exp(1j * 2*pi * rand(obj.N, obj.U));
        end
        
        function [tx_signal, best_idx] = apply_slm(obj, symbols)
            % 应用SLM
            papr_values = zeros(1, obj.U);
            candidate_signals = cell(1, obj.U);
            
            for u = 1:obj.U
                % 应用相位旋转
                rotated_symbols = symbols .* obj.phase_sequences(:, u);
                
                % OFDM调制
                candidate = obj.ofdm_modulate(rotated_symbols);
                candidate_signals{u} = candidate;
                
                % 计算PAPR
                papr_values(u) = mean(obj.calculate_papr(candidate));
            end
            
            % 选择最低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)
            % SLM的BER仿真
            ber = zeros(size(snr_db));
            
            for snr_idx = 1:length(snr_db)
                total_errors = 0;
                total_bits = 0;
                
                for sym_idx = 1:obj.num_symbols
                    % 生成数据
                    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
                    
                    % 应用SLM
                    [tx_signal, best_idx] = obj.apply_slm(symbols);
                    
                    % 传输边带信息(理想情况)
                    side_info = de2bi(best_idx-1, ceil(log2(obj.U)), 'left-msb')';
                    
                    % 添加噪声
                    signal_power = mean(abs(tx_signal).^2);
                    noise_power = signal_power / (10^(snr_db(snr_idx)/10));
                    noise = sqrt(noise_power/2) * (randn(size(tx_signal)) + 1j*randn(size(tx_signal)));
                    rx_signal = tx_signal + noise;
                    
                    % OFDM解调
                    rx_symbols = obj.ofdm_demodulate(rx_signal);
                    
                    % 应用逆相位旋转(假设边带信息正确接收)
                    rx_symbols = rx_symbols .* conj(obj.phase_sequences(:, best_idx));
                    
                    % 解调
                    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
                    
                    % 计算误码
                    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)
            % 绘制SLM性能
            papr_original = [];
            papr_slm = [];
            
            for i = 1:100
                [symbols, ~] = obj.generate_data();
                
                % 原始OFDM
                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
            
            % 计算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
            
            % 绘图
            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('SLM算法PAPR性能 (U=%d)', obj.U));
            legend('原始', 'SLM');
            grid on;
            
            subplot(1,2,2);
            % 不同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('不同U值的SLM性能');
            legend(arrayfun(@(x) sprintf('U=%d', x), U_values, 'UniformOutput', false), '原始');
            grid on;
            
            sgtitle(sprintf('选择性映射(SLM)算法 (N=%d, %s)', obj.N, obj.mod_type));
        end
    end
end
3.3.2 部分传输序列(PTS)
matlab 复制代码
%% 部分传输序列算法
classdef PTS < OFDMSystem
    % 部分传输序列算法
    
    properties
        V = 4;              % 分割数
        W = 4;              % 相位因子数量
        phase_factors;      % 相位因子集合
        partition_method = 'adjacent';  % 分割方法
    end
    
    methods
        function obj = PTS(varargin)
            obj = obj@OFDMSystem(varargin{:});
            obj.generate_phase_factors();
        end
        
        function generate_phase_factors(obj)
            % 生成相位因子
            obj.phase_factors = exp(1j * 2*pi/obj.W * (0:obj.W-1));
        end
        
        function [tx_signal, best_phase] = apply_pts(obj, symbols)
            % 应用PTS
            
            % 分割子载波
            switch obj.partition_method
                case 'adjacent'
                    % 相邻分割
                    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'
                    % 交织分割
                    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'
                    % 伪随机分割
                    partitions = zeros(obj.N, obj.V);
                    for n = 1:obj.N
                        v = randi([1, obj.V]);
                        partitions(n, v) = 1;
                    end
            end
            
            % 生成部分序列
            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
            
            % 搜索最优相位组合
            min_papr = inf;
            best_signal = [];
            best_phase = ones(1, obj.V);
            
            % 遍历所有相位组合
            phase_combinations = obj.generate_all_combinations(obj.V, obj.W);
            
            for combo_idx = 1:size(phase_combinations, 1)
                phase_combo = phase_combinations(combo_idx, :);
                
                % 组合信号
                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
                
                % 计算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)
            % 生成所有相位组合
            indices = 1:W;
            combs = cell(V, 1);
            [combs{:}] = ndgrid(indices);
            combinations = reshape(cat(V+1, combs{:}), [], V);
        end
        
        function plot_pts_performance(obj)
            % 绘制PTS性能
            papr_original = [];
            papr_pts = [];
            
            for i = 1:50
                [symbols, ~] = obj.generate_data();
                
                % 原始OFDM
                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
            
            % 计算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
            
            % 绘图
            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('PTS算法PAPR性能 (V=%d, W=%d)', obj.V, obj.W));
            legend('原始', 'PTS');
            grid on;
            
            subplot(1,3,2);
            % 不同分割方法比较
            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('不同分割方法比较');
            legend(methods{:}, '原始');
            grid on;
            
            subplot(1,3,3);
            % 计算复杂度分析
            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();
                    
                    % 复杂度 = W^V
                    complexity(v_idx, w_idx) = obj.W^obj.V;
                    
                    % 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
            
            % 3D柱状图
            [X, Y] = meshgrid(1:length(W_values), 1:length(V_values));
            bar3(complexity);
            xlabel('W');
            ylabel('V');
            zlabel('计算复杂度');
            title('PTS计算复杂度分析');
            set(gca, 'XTickLabel', W_values);
            set(gca, 'YTickLabel', V_values);
            grid on;
            
            sgtitle(sprintf('部分传输序列(PTS)算法 (N=%d, %s)', obj.N, obj.mod_type));
        end
    end
end

3.4 压扩变换算法

matlab 复制代码
%% μ律压扩算法
classdef MuLawCompanding < OFDMSystem
    % μ律压扩算法
    
    properties
        mu = 255;           % 压扩参数
    end
    
    methods
        function compressed = compress(obj, signal)
            % 压缩
            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)
            % 扩展
            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)
            % 绘制压扩性能
            papr_original = [];
            papr_companded = [];
            
            for i = 1:100
                [symbols, ~] = obj.generate_data();
                tx_original = obj.ofdm_modulate(symbols);
                
                % 压扩
                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
            
            % 计算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
            
            % 绘图
            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('μ律压扩PAPR性能 (μ=%.0f)', obj.mu));
            legend('原始', '压扩后');
            grid on;
            
            subplot(2,2,2);
            % 不同μ值比较
            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('不同μ值性能比较');
            legend(arrayfun(@(x) sprintf('μ=%.0f', x), mu_values, 'UniformOutput', false), '原始');
            grid on;
            
            subplot(2,2,3);
            % 压扩特性曲线
            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('归一化输入');
            ylabel('归一化输出');
            title('μ律压扩特性');
            legend(arrayfun(@(x) sprintf('μ=%.0f', x), mu_values, 'UniformOutput', false), '线性');
            grid on;
            
            subplot(2,2,4);
            % 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
                    % 生成数据
                    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
                    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
                    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);
                    
                    % 解调
                    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('压扩对BER的影响');
            legend('原始', '压扩');
            grid on;
            
            sgtitle('μ律压扩算法性能分析');
        end
    end
end

四、综合性能比较

4.1 算法性能比较

matlab 复制代码
%% 综合性能比较
classdef PAPRComparison
    % PAPR算法综合比较
    
    methods (Static)
        function compare_all_algorithms()
            % 比较所有算法
            
            % 参数设置
            N = 64;
            M = 4;  % QPSK
            num_symbols = 1000;
            L = 4;
            
            % 创建算法实例
            ofdm_base = OFDMSystem('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols);
            
            % 硬限幅
            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 = MuLawCompanding('N', N, 'M', M, 'L', L, 'num_symbols', num_symbols, 'mu', 255);
            
            % 生成数据
            [symbols, bits] = ofdm_base.generate_data();
            
            % 计算各算法PAPR
            papr_results = struct();
            
            % 原始OFDM
            tx_original = ofdm_base.ofdm_modulate(symbols);
            papr_results.original = ofdm_base.calculate_papr(tx_original);
            
            % 硬限幅
            tx_clipped = clipping.apply_clipping(tx_original);
            papr_results.clipping = clipping.calculate_papr(tx_clipped);
            
            % SLM
            [tx_slm, ~] = slm.apply_slm(symbols);
            papr_results.slm = slm.calculate_papr(tx_slm);
            
            % PTS
            [tx_pts, ~] = pts.apply_pts(symbols);
            papr_results.pts = pts.calculate_papr(tx_pts);
            
            % 压扩
            tx_comp = companding.compress(tx_original);
            papr_results.companding = companding.calculate_papr(tx_comp);
            
            % 绘制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('各种算法PAPR性能比较');
            legend(algorithms, 'Location', 'northeast');
            grid on;
            
            subplot(2,2,2);
            % 平均PAPR比较
            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 (dB)');
            title('平均PAPR比较');
            grid on;
            
            subplot(2,2,3);
            % PAPR增益
            papr_gain = avg_papr(1) - avg_papr;
            bar(1:length(algorithms), papr_gain);
            set(gca, 'XTickLabel', algorithms);
            xtickangle(45);
            ylabel('PAPR增益 (dB)');
            title('相对于原始OFDM的PAPR增益');
            grid on;
            
            subplot(2,2,4);
            % 计算复杂度比较
            complexity = [
                1;              % 原始
                N;              % 限幅
                slm.U * N;      % SLM
                pts.W^pts.V;    % PTS
                N               % 压扩
            ];
            
            bar(1:length(algorithms), log10(complexity));
            set(gca, 'XTickLabel', algorithms);
            xtickangle(45);
            ylabel('log10(计算复杂度)');
            title('计算复杂度比较');
            grid on;
            
            sgtitle('OFDM PAPR降低算法综合比较');
            
            % 显示统计表格
            fprintf('\n=== 算法性能统计 ===\n');
            fprintf('%-15s %-10s %-10s %-10s %-10s\n', ...
                '算法', '平均PAPR', '标准差', 'PAPR增益', '复杂度');
            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()
            % BER性能比较
            N = 64;
            M = 4;
            num_symbols = 100;
            snr_db = 0:2:20;
            
            % 创建算法实例
            clipping = HardClipping('N', N, 'M', M, 'num_symbols', num_symbols, 'clip_ratio', 0.8);
            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);
            
            % 仿真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('正在进行BER仿真...\n');
            
            for snr_idx = 1:length(snr_db)
                fprintf('SNR = %d dB\n', snr_db(snr_idx));
                
                % 硬限幅
                ber_c = clipping.simulate_ber(snr_db(snr_idx));
                ber_results.clipping(snr_idx) = ber_c;
                
                % SLM
                ber_s = slm.simulate_ber_with_slm(snr_db(snr_idx));
                ber_results.slm(snr_idx) = ber_s;
                
                % 压扩
                ber_m = 0;
                for i = 1:10
                    [symbols, bits] = companding.generate_data();
                    tx_signal = companding.ofdm_modulate(symbols);
                    tx_comp = companding.compress(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 = companding.expand(rx_signal);
                    rx_symbols = companding.ofdm_demodulate(rx_expanded);
                    
                    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
            
            % 绘制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)
                semilogy(snr_db, ber_results.(algorithms{i}), ...
                    [colors{i}, markers{i}], 'LineWidth', 2, 'MarkerSize', 8);
                hold on;
            end
            
            % 理论QPSK BER
            ber_theory = 0.5 * erfc(sqrt(10.^(snr_db/10)));
            semilogy(snr_db, ber_theory, 'k-', 'LineWidth', 2);
            
            xlabel('SNR (dB)');
            ylabel('BER');
            title('各种PAPR降低算法的BER性能');
            legend([algorithms; '理论QPSK'], 'Location', 'southwest');
            grid on;
            ylim([1e-5, 1]);
            
            % 计算SNR损失
            fprintf('\n=== 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, SNR损失 = %.2f dB\n', ...
                        algorithms{i}, snr_at_target, snr_loss);
                end
            end
        end
    end
end

参考代码 降低正交频分复用系统PAPR的各种算法及误码率 www.youwenfan.com/contentcsu/55026.html

五、实际应用建议

5.1 算法选择指南

应用场景 推荐算法 原因
实时通信 限幅、压扩 计算简单,延迟低
高可靠性 SLM、PTS 无失真,BER性能好
移动设备 压扩、限幅 功耗低,实现简单
广播系统 SLM 可容忍边带信息开销
军事通信 PTS 安全性好,性能优

5.2 参数优化建议

matlab 复制代码
%% 参数优化函数
function optimize_parameters()
    % 参数优化
    
    % 1. SLM的U值优化
    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));
        
        % 评估性能
        papr_data = [];
        for j = 1:50
            [symbols, ~] = slm.generate_data();
            [tx_slm, ~] = slm.apply_slm(symbols);
            papr = slm.calculate_papr(tx_slm);
            papr_data = [papr_data, papr];
        end
        
        % 原始PAPR
        tx_original = slm.ofdm_modulate(symbols);
        papr_orig = slm.calculate_papr(tx_original);
        
        papr_gain(i) = mean(papr_orig) - mean(papr_data);
        complexity(i) = U_values(i) * N;
    end
    
    % 寻找最优U值
    figure;
    yyaxis left;
    plot(U_values, papr_gain, 'b-o', 'LineWidth', 2);
    ylabel('PAPR增益 (dB)');
    
    yyaxis right;
    plot(U_values, complexity, 'r-s', 'LineWidth', 2);
    ylabel('计算复杂度');
    
    xlabel('U值');
    title('SLM参数优化');
    legend('PAPR增益', '计算复杂度');
    grid on;
    
    % 2. 限幅比例优化
    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));
        
        % PAPR评估
        papr_data = [];
        for j = 1:50
            [symbols, ~] = clipping.generate_data();
            tx_signal = clipping.ofdm_modulate(symbols);
            tx_clipped = clipping.apply_clipping(tx_signal);
            papr = clipping.calculate_papr(tx_clipped);
            papr_data = [papr_data, papr];
        end
        papr_clipped(i) = mean(papr_data);
        
        % BER评估
        ber_clipped(i) = clipping.simulate_ber(10);  % SNR=10dB
    end
    
    figure;
    yyaxis left;
    plot(CR_values, papr_clipped, 'b-o', 'LineWidth', 2);
    ylabel('平均PAPR (dB)');
    
    yyaxis right;
    semilogy(CR_values, ber_clipped, 'r-s', 'LineWidth', 2);
    ylabel('BER');
    
    xlabel('限幅比例 (CR)');
    title('限幅算法参数优化');
    legend('PAPR', 'BER');
    grid on;
end

六、总结

6.1 算法性能总结

算法 PAPR增益 BER影响 计算复杂度 边带信息 适用场景
硬限幅 3-5 dB 严重 低成本实时系统
SLM 4-6 dB 中等 广播、固定无线
PTS 5-7 dB 高性能无线
压扩 2-4 dB 轻微 移动通信

6.2 实用MATLAB代码

matlab 复制代码
% 快速使用示例
clear; clc; close all;

% 1. 创建OFDM系统
ofdm = OFDMSystem('N', 64, 'M', 4, 'mod_type', 'QPSK');

% 2. 生成数据
[symbols, bits] = ofdm.generate_data();

% 3. 应用SLM降低PAPR
slm = SLM('N', 64, 'U', 4);
[tx_slm, idx] = slm.apply_slm(symbols);

% 4. 计算PAPR
papr_original = ofdm.calculate_papr(ofdm.ofdm_modulate(symbols));
papr_slm = slm.calculate_papr(tx_slm);

fprintf('原始PAPR: %.2f dB\n', mean(papr_original));
fprintf('SLM后PAPR: %.2f dB\n', mean(papr_slm));
fprintf('PAPR增益: %.2f dB\n', mean(papr_original) - mean(papr_slm));

% 5. 绘制结果
figure;
subplot(1,2,1);
histogram(papr_original, 20, 'FaceColor', 'b');
xlabel('PAPR (dB)'); ylabel('频率');
title('原始OFDM PAPR分布');

subplot(1,2,2);
histogram(papr_slm, 20, 'FaceColor', 'r');
xlabel('PAPR (dB)'); ylabel('频率');
title('SLM后PAPR分布');
相关推荐
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_3:(表单CSS美化实战与盒子模型三大核心属性详解)
前端·javascript·css·html
阿Y加油吧1 小时前
二刷 LeetCode:5. 最长回文子串 & 1143. 最长公共子序列 复盘笔记
笔记·算法·leetcode
张风捷特烈1 小时前
状态管理大乱斗#05 | Riverpod 源码评析 (中) - 上层建筑
android·前端·flutter
土豆12501 小时前
Rust 生命周期开发实战:从"编译不过"到"一次过编"的实用指南
前端·rust
广州灵眸科技有限公司2 小时前
瑞芯微(EASY EAI)RV1126B AI算法开发流程
人工智能·算法·机器学习
Rabitebla2 小时前
【C++】string 类:原理、踩坑与对象语义
linux·c语言·数据结构·c++·算法·github·学习方法
小雅痞3 小时前
[Java][Leetcode middle] 167. 两数之和 II - 输入有序数组
java·算法·leetcode
CN-Dust3 小时前
【C++】输入cin例题专题
java·c++·算法