【matlab】 16-QAM 调制的 OFDM 数字基带系统仿真

% OFDM 数字基带系统


clc; clear; close all;

%% 参数设置
M = 16;                % 16-QAM
N = 64;                % IFFT 点数
CP = 16;               % 循环前缀长度(25%)
num_frames = 100;      % 帧数
bits_per_frame = 96;   % 每帧原始比特数
total_bits = bits_per_frame * num_frames;



%% 1. 随机数据 + 卷积编码
data = randi([0 1], total_bits, 1);  % 9600 比特

trellis = poly2trellis(7, [171 133]);
coded = convenc(data, trellis);      % 编码后变长

%% 2. 交织
% 交织行列尺寸:25x24,可扩展为更大尺寸提高抗突发干扰能力


reshaped=reshape(coded, [], 600);
reshaped=reshaped';
interleaved = matintrlv(reshaped, 25, 24);
interleaved = interleaved';
interleaved = interleaved(:);


%% 3. 16-QAM 调制
symbols = qammod(bi2de(reshape(interleaved, 4, [])', 'left-msb'), M);

%% 4. 分帧插入导频(每帧48个数据子载波 + 4个导频 → 64点)
num_symbols = length(symbols); 
symbols_per_frame = 48;
num_ofdm_frames = num_symbols / symbols_per_frame;

pilot = 3 + 3j;
ofdm_symbols = zeros(N, num_ofdm_frames); % 64行,100列(每帧)

k = 1;
for i = 1:num_ofdm_frames
    temp = zeros(1, 64);
    % 插入导频(固定位置)
    temp([8, 22, 44, 58]) = pilot;
    
    % 插入数据
    data_idx = setdiff(1:64, [8, 22, 44, 58]);
    temp(data_idx(1:48)) = symbols(k:k+47);
    k = k + 48;
    
    ofdm_symbols(:, i) = temp.';  % 存储成列向量(方便后面 IFFT)
end

%% 5. IFFT + 加循环前缀
ifft_out = ifft(ofdm_symbols, N, 1);
ifft_cp = [ifft_out(end-CP+1:end, :); ifft_out];  % 80×100

%% 6. 加 AWGN + 接收处理
snr_range = 0:2:64;
MaxIter = 100 ;    %设置迭代次数,如果运行时间过长,可以减少数值
total_bit_errors_zf=0;
total_bit_errors_mmse=0;
total_bits_all = length(data) * MaxIter;  % 每次发送相同 data,迭代 MaxIter 次
BER_zf = zeros(1, length(snr_range));
BER_mmse = zeros(1, length(snr_range));



for snr_idx = 1:length(snr_range)
    snr = snr_range(snr_idx);
    
    % 初始化每个SNR下的误码计数
    bit_errors=0;
    bit_errors_zf = 0;
    bit_errors_mmse = 0;

    for iter = 1:MaxIter
        %% 发射端
        tx_signal = ifft_cp(:);  % 原始OFDM时域信号
        rx = awgn(tx_signal, snr, 'measured');  % 加AWGN

        %% 接收端:处理为帧结构
        rx = reshape(rx, N + CP, []);       % 每帧80点
        rx_no_cp = rx(CP+1:end, :);         % 去循环前缀
        fft_out = fft(rx_no_cp, N, 1);      % FFT 变换
        
        % 初始化当前帧的解调数据
        rx_data = [];
        rx_data_zf = [];
        rx_data_mmse = [];

        for i = 1:num_ofdm_frames
            frame = fft_out(:, i);
            pilot_idx = [8, 22, 44, 58];
            data_idx = setdiff(1:64, pilot_idx);
            
          
            %不做估计和均衡
            rx_data = [rx_data; frame(data_idx(1:48))];

            % LS 信道估计
            received_pilots = frame(pilot_idx);
            h_est_pilot = received_pilots ./ pilot;
            h_est_full = interp1(pilot_idx, h_est_pilot, 1:64, 'linear', 'extrap')';

            % ZF均衡
            equalized_frame_zf = frame ./ h_est_full;
            rx_data_zf = [rx_data_zf; equalized_frame_zf(data_idx(1:48))];

            % MMSE均衡
            snr_linear = 10^(snr / 10);
            mmse_weights = conj(h_est_full) ./ (abs(h_est_full).^2 + 1/snr_linear);
            equalized_frame_mmse = frame .* mmse_weights;
            
            rx_data_mmse = [rx_data_mmse; equalized_frame_mmse(data_idx(1:48))];
        end
        %% 未做估计和均衡
        demod = qamdemod(rx_data, M);
        bin = de2bi(demod, 4, 'left-msb')';
        bin = bin(:);
    
        deintlvd = matdeintrlv(reshape(bin, [], 600)', 25, 24)';
        deintlvd = deintlvd(:);
    
        decoded = vitdec(deintlvd, trellis, 35, 'trunc', 'hard');
        [num_err, ~] = biterr(data, decoded);
        bit_errors = bit_errors + num_err;

        %% ZF 解调链路
        demod_zf = qamdemod(rx_data_zf, M);
        bin_zf = de2bi(demod_zf, 4, 'left-msb')';
        bin_zf = bin_zf(:);
        deintlvd_zf = matdeintrlv(reshape(bin_zf, [], 600)', 25, 24)';
        deintlvd_zf = deintlvd_zf(:);
        decoded_zf = vitdec(deintlvd_zf, trellis, 35, 'trunc', 'hard');
        [num_err_zf, ~] = biterr(data, decoded_zf);
        bit_errors_zf = bit_errors_zf + num_err_zf;

        %% MMSE 解调链路
        demod_mmse = qamdemod(rx_data_mmse, M);
        bin_mmse = de2bi(demod_mmse, 4, 'left-msb')';
        bin_mmse = bin_mmse(:);
        deintlvd_mmse = matdeintrlv(reshape(bin_mmse, [], 600)', 25, 24)';
        deintlvd_mmse = deintlvd_mmse(:);
        decoded_mmse = vitdec(deintlvd_mmse, trellis, 35, 'trunc', 'hard');
        [num_err_mmse, ~] = biterr(data, decoded_mmse);
        bit_errors_mmse = bit_errors_mmse + num_err_mmse;
    end

    % BER 计算(每个 SNR 单独计数)
    BER(snr_idx) = bit_errors / (length(data) * MaxIter);
    BER_zf(snr_idx) = bit_errors_zf / (length(data) * MaxIter);
    BER_mmse(snr_idx) = bit_errors_mmse / (length(data) * MaxIter);
end
    

%% 绘图(同时显示 ZF 和 MMSE)
figure;
semilogy(snr_range, BER, 'b-o', 'LineWidth', 1.5); hold on;
semilogy(snr_range, BER_zf, 'g-o', 'LineWidth', 1.5); hold on;
semilogy(snr_range, BER_mmse, 'r-s', 'LineWidth', 1.5);
xlabel('SNR (dB)');
ylabel('BER');
title('性能对比');
legend('不做估计均衡','ZF', 'MMSE', 'Location', 'best');
grid on;
hold off;

发送端处理流程:
随机比特生成:生成原始二进制数据;
卷积编码:采用约束长度为7的卷积编码提高可靠性;
交织:防止突发错误影响译码性能;
16-QAM 调制:将编码后的比特映射为复数符号;
导频插入 + OFDM帧结构构建:每帧包含48个数据子载波 + 4个导频子载波;
IFFT + 加循环前缀:实现OFDM调制的核心过程;
串化发送。

信道建模:
使用 awgn模拟加性高斯白噪声信道。

接收端处理:
去除循环前缀并进行FFT;
提取导频并基于 LS(最小二乘)方法进行信道估计;
分别使用 ZF 与 MMSE 均衡器进行等化;
QAM 解调、反交织、Viterbi 解码,恢复原始数据;
统计各均衡方式下的误码率(BER)。

性能评估与绘图:
对比不同 SNR 下“无均衡”、“ZF均衡”、“MMSE均衡”的误码率;

仿真结果:

运行结果
可以看到仿真结果是脱离预计的,理论上的结果应该是MMSE >ZF>不做均衡,是结果正好相反,以下是本人的一些猜想:
1.因为本次仿真仅仅用到AWGN信道进行模拟,在信道过于简单的情况下进行估计和插值反而得到了反效果,从而导致进行估计和均衡后的效果不如不做估计和均衡
2.理论上MMSE均衡在低信噪比的情况下效果不如ZF均衡,可能情况是MMSE公式中1/SNR 项在低信噪比情况下变大,导致 MMSE 把权重压得太小,为抑噪削弱了信号,ZF 反而保留信号更多。但是上面也提到信道太过于简单,信噪比加到12以后,误码率为0,体现不出MMSE的优势
3.如果加入时变瑞利信道或真实水声信道,可能会看到更明显的性能反转

该代码仿真为本人一次小小的尝试,若有不足欢迎指出

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值