睿诚科技协会

MIMO技术MATLAB仿真如何实现?

MIMO技术核心概念回顾

在开始仿真之前,快速回顾一下MIMO的核心思想:

MIMO技术MATLAB仿真如何实现?-图1
(图片来源网络,侵删)
  • 多天线:在发送端和接收端都使用多个天线。
  • 空间分集:通过多个独立的空间路径传输相同的数据,可以显著对抗信道衰落,提高链路的可靠性,常用的方法有 Alamouti 空时编码(2x2 MIMO的特例)和 空频编码
  • 空间复用:在相同的频带上,同时传输多个独立的数据流,从而成倍地提高系统容量,一个 2x2 MIMO 理论上可以将信道容量翻倍,代表算法是 贝尔实验室分层空时架构
  • 波束赋形:通过调整各天线信号的相位和幅度,将信号能量集中指向期望的用户,从而提高信号强度和信噪比。

本示例将重点实现最经典的 2x2 MIMO Alamouti 空时编码系统,因为它结构清晰,能很好地展示MIMO的基本原理。


MIMO系统仿真基本流程

一个完整的MIMO链路仿真通常遵循以下步骤:

  1. 参数配置:设置仿真所需的基本参数,如天线数量、调制方式、信噪比范围、仿真点数等。
  2. 信道建模:生成MIMO信道矩阵,这是仿真的核心,信道可以是瑞利衰落信道莱斯衰落信道,对于空间分集,信道矩阵的元素通常是独立复高斯随机变量。
  3. 信源生成:产生随机的二进制比特流。
  4. 调制:将比特流映射为复杂的调制符号(如QPSK, 16QAM, 64QAM)。
  5. MIMO编码:根据所选的MIMO方案(如Alamouti)对符号进行编码。
  6. 信道传输:将编码后的信号通过MIMO信道进行传输,并叠加高斯白噪声。
  7. MIMO解码:接收端利用信道信息和相应的解码算法(如ZF, MMSE, ML)恢复出发送的符号。
  8. 解调:将恢复出的符号映射回比特流。
  9. 误码率计算:比较原始比特和接收比特,计算误码率。
  10. 结果可视化:绘制BER vs. SNR 的曲线图,评估系统性能。

完整MATLAB仿真示例:2x2 MIMO Alamouti 系统

下面是一个完整的、可运行的MATLAB脚本,用于仿真一个采用Alamouti编码的2x2 MIMO-QPSK系统。

仿真目标

比较以下三种方案的性能:

MIMO技术MATLAB仿真如何实现?-图2
(图片来源网络,侵删)
  1. SISO (Single-Input Single-Output):单天线收发,作为性能基准。
  2. MIMO ( Alamouti + MRC ):2x2 MIMO Alamouti编码,接收端采用最大比合并。
  3. MIMO ( Alamouti + ZF ):2x2 MIMO Alamouti编码,接收端采用迫零均衡。
%% MIMO MATLAB 仿真: 2x2 Alamouti 编码系统
% 作者: AI Assistant
% 日期: 2025-10-27
%% 1. 参数配置
clear; clc; close all;
N = 10^5;           % 每个SNR点的仿真符号数
M = 4;              % 调制阶数 (QPSK)
numBitsPerSym = log2(M); % 每个符号的比特数
numTx = 2;          % 发射天线数
numRx = 2;          % 接收天线数
% 定义SNR范围 (dB)
SNR_dB = 0:2:20;
numSNRs = length(SNR_dB);
% 预存储BER结果
ber_siso = zeros(1, numSNRs);
ber_mrc = zeros(1, numSNRs);
ber_zf = zeros(1, numSNRs);
%% 2. 主仿真循环
for i = 1:numSNRs
    SNR = SNR_dB(i);
    current_siso_errors = 0;
    current_mrc_errors = 0;
    current_zf_errors = 0;
    % 生成随机比特流
    tx_bits = randi([0 1], N * numBitsPerSym, 1);
    % ------------------- SISO 仿真 -------------------
    % 调制
    tx_symbols_siso = bi2de(reshape(tx_bits, numBitsPerSym, [])', 'left-msb');
    tx_symbols_siso = qammod(tx_symbols_siso, M, 'UnitAveragePower', true);
    % 信道 (1x1 瑞利衰落)
    h_siso = (randn(1,1) + 1i*randn(1,1)) / sqrt(2);
    % 加噪声
    noise_var_siso = 1 / (10^(SNR/10)); % 假设信号功率为1
    rx_symbols_siso = h_siso * tx_symbols_siso + sqrt(noise_var_siso/2) * (randn(1,N) + 1i*randn(1,N));
    % 解调 (MRC for SISO is just simple channel inversion)
    rx_symbols_siso = rx_symbols_siso / conj(h_siso);
    % 计算误码
    tx_symbols_siso_demod = qamdemod(rx_symbols_siso, M, 'UnitAveragePower', true);
    tx_bits_siso = de2bi(tx_symbols_siso_demod, numBitsPerSym, 'left-msb')';
    tx_bits_siso = tx_bits_siso(:);
    current_siso_errors = biterr(tx_bits, tx_bits_siso);
    % ------------------- MIMO Alamouti 仿真 -------------------
    % 调制
    tx_symbols_mimo = bi2de(reshape(tx_bits, numBitsPerSym, [])', 'left-msb');
    tx_symbols_mimo = qammod(tx_symbols_mimo, M, 'UnitAveragePower', true);
    % Alamouti 编码 (N个符号 -> 2N个时隙)
    % [s1  -s2*]
    % [s2   s1*]
    tx Alamouti symbols
    tx_alamouti = zeros(2, 2*N);
    for j = 1:N
        s1 = tx_symbols_mimo(j);
        s2 = tx_symbols_mimo(j+N);
        tx_alamouti(1, 2*j-1) = s1;
        tx_alamouti(1, 2*j)   = -conj(s2);
        tx_alamouti(2, 2*j-1) = s2;
        tx_alamouti(2, 2*j)   = conj(s1);
    end
    % 信道 (2x2 瑞利衰落)
    % [h11 h12]
    % [h21 h22]
    h_mimo = (randn(numRx, numTx) + 1i*randn(numRx, numTx)) / sqrt(2);
    % 接收信号 (2个天线 x 2N个时隙)
    noise_var_mimo = 1 / (10^(SNR/10));
    rx_mimo = h_mimo * tx_alamouti + sqrt(noise_var_mimo/2) * (randn(numRx, 2*N) + 1i*randn(numRx, 2*N));
    % Alamouti 解码
    % 接收信号矩阵 Y
    % [y1 y2]
    % [y3 y4]
    % 解码后的信号为 H^H * Y
    decoded_symbols = zeros(2, N);
    for j = 1:N
        % 提取两个时隙的接收信号
        y1 = rx_mimo(1, 2*j-1);
        y2 = rx_mimo(1, 2*j);
        y3 = rx_mimo(2, 2*j-1);
        y4 = rx_mimo(2, 2*j);
        % 构建接收向量
        Y = [y1; y3];
        % Alamouti 解码矩阵 H^H * H
        H_conj = conj(h_mimo);
        H_H_H = H_conj' * h_mimo;
        % 计算解码后的符号
        s_hat = (1 / det(H_H_H)) * H_conj' * Y;
        decoded_symbols(1, j) = s_hat(1);
        decoded_symbols(2, j) = s_hat(2);
    end
    % 合并两个数据流并解调
    rx_symbols_mimo = decoded_symbols(:);
    % MRC 和 ZF 性能比较 (这里Alamouti解码已经隐含了合并过程)
    % 我们直接比较解码后的符号
    % --- MRC (最大比合并) ---
    % 在Alamouti解码中,最优合并已经完成,这里直接计算BER
    rx_symbols_mrc = rx_symbols_mimo;
    tx_symbols_mrc_demod = qamdemod(rx_symbols_mrc, M, 'UnitAveragePower', true);
    tx_bits_mrc = de2bi(tx_symbols_mrc_demod, numBitsPerSym, 'left-msb')';
    tx_bits_mrc = tx_bits_mrc(:);
    current_mrc_errors = biterr(tx_bits, tx_bits_mrc);
    % --- ZF (迫零均衡) ---
    % 如果我们想单独做ZF,可以这样:
    % H_inv = pinv(h_mimo); % 使用伪逆
    % rx_symbols_zf = H_inv * rx_mimo(:);
    % 但在Alamouti结构中,上面的解码方式是等效的且更优的。
    % 为了演示ZF,我们可以在符号层面进行迫零操作
    H_inv = pinv(h_mimo); % 2x2 信道矩阵的伪逆
    rx_symbols_zf_vec = H_inv * rx_mimo(:);
    rx_symbols_zf = reshape(rx_symbols_zf_vec, 2, N);
    tx_symbols_zf_demod = qamdemod(rx_symbols_zf(:), M, 'UnitAveragePower', true);
    tx_bits_zf = de2bi(tx_symbols_zf_demod, numBitsPerSym, 'left-msb')';
    tx_bits_zf = tx_bits_zf(:);
    current_zf_errors = biterr(tx_bits, tx_bits_zf);
    % 计算当前SNR点的BER
    ber_siso(i) = current_siso_errors / (N * numBitsPerSym);
    ber_mrc(i) = current_mrc_errors / (2 * N * numBitsPerSym); % 注意:MIMO传输了2倍的数据
    ber_zf(i) = current_zf_errors / (2 * N * numBitsPerSym);
    fprintf('SNR = %d dB, SISO BER = %e, MIMO Alamouti BER = %e, MIMO ZF BER = %e\n', ...
            SNR_dB(i), ber_siso(i), ber_mrc(i), ber_zf(i));
end
%% 3. 结果可视化
figure;
semilogy(SNR_dB, ber_siso, 'b-o', 'LineWidth', 2, 'DisplayName', 'SISO');
hold on;
semilogy(SNR_dB, ber_mrc, 'r-s', 'LineWidth', 2, 'DisplayName', 'MIMO Alamouti + MRC');
semilogy(SNR_dB, ber_zf, 'g-^', 'LineWidth', 2, 'DisplayName', 'MIMO Alamouti + ZF');
grid on;
axis([min(SNR_dB) max(SNR_dB) 10^-4 1]);
xlabel('SNR (dB)');
ylabel('Bit Error Rate (BER)');'2x2 MIMO Alamouti 系统性能比较');
legend('show', 'Location', 'southwest');

代码关键模块解析

信道建模

h_mimo = (randn(numRx, numTx) + 1i*randn(numRx, numTx)) / sqrt(2);
  • randn 生成标准正态分布(均值为0,方差为1)的随机数。
  • 1i*randn 生成虚部,两者结合形成复高斯随机变量。
  • 除以 sqrt(2):为了保证信道系数的功率(即 E[|h|^2])为1,这是无线信道仿真的标准做法,这使得信噪比的计算更直接。

Alamouti 编码

tx_alamouti = zeros(2, 2*N);
for j = 1:N
    s1 = tx_symbols_mimo(j);
    s2 = tx_symbols_mimo(j+N);
    tx_alamouti(1, 2*j-1) = s1;
    tx_alamouti(1, 2*j)   = -conj(s2);
    tx_alamouti(2, 2*j-1) = s2;
    tx_alamouti(2, 2*j)   = conj(s1);
end
  • 将N个符号对 (s1, s2) 编码成2x2的矩阵。
  • 在第一个时隙,天线1发送 s1,天线2发送 s2
  • 在第二个时隙,天线1发送 -conj(s2),天线2发送 conj(s1)
  • 这种编码结构使得接收端可以非常简单地实现联合解码和合并。

Alamouti 解码

H_conj = conj(h_mimo);
H_H_H = H_conj' * h_mimo;
s_hat = (1 / det(H_H_H)) * H_conj' * Y;
  • H_conj' 是信道矩阵 h_mimo 的共轭转置,也称为Hermitian转置。
  • H_H_HH^H * H,这是一个2x2的矩阵。
  • s_hat = H^H * Y / (H^H * H) 是Alamouti解码的核心公式,它等效于对两个天线接收到的信号进行线性合并,并完美地分离出原始的 s1s2
  • 这种解码方式实现了最大似然检测的性能,并且在计算上非常高效。

误码率计算

ber_mrc(i) = current_mrc_errors / (2 * N * numBitsPerSym);
  • 注意分母:对于2x2 MIMO Alamouti系统,我们实际上在2个时隙内传输了2个符号,总的传输比特数是 2 * N * numBitsPerSym,而SISO系统是 N * numBitsPerSym,这是比较BER时需要注意的地方。
  • 如果你想比较频谱效率,应该确保两者在相同带宽下传输相同数量的比特,但在这个仿真中,我们主要关注MIMO相对于SISO的性能增益。

如何扩展和进阶

这个示例是MIMO仿真的一个绝佳起点,您可以基于此进行扩展:

  1. 空间复用:修改代码,实现一个简单的V-BLAST系统,这需要更复杂的检测算法,如串行干扰消除
  2. 更高级的信道模型:使用MATLAB的 comm.RayleighChannelcomm.TDLChannel 对象来创建具有时延扩展、多普勒频移等更真实特性的信道。
  3. OFDM + MIMO:将MIMO技术与OFDM结合,这是5G等现代通信系统的核心,您需要在每个OFDM子载波上执行上述MIMO处理。
  4. 波束赋形:在发送端,设计一个预编码矩阵(如基于信道状态信息的ZF或MMSE预编码),将信号能量聚焦到接收端。
  5. 其他调制方式:尝试使用16QAM或64QAM,观察不同调制方式下的性能差异。
  6. 使用MATLAB通信工具箱:上述代码是“手动”实现的,有助于理解原理,在实际工程中,可以使用 comm.MIMOEncodercomm.MIMODetector 等内置对象来简化代码,它们经过了高度优化。

希望这个详细的指南能帮助您顺利开始MIMO技术的MATLAB仿真之旅!

MIMO技术MATLAB仿真如何实现?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇