当前位置:首页 > 技术 > 正文内容

基于MATLAB的2发1收空时分组码MIMO系统实现

访客 技术 2026年6月23日 1

本文介绍双发射天线单接收天线配置下的空时分组码MIMO系统实现,采用Alamouti编码方案。系统包含调制、编码、信道传输和解码全流程。

系统架构

系统核心参数配置:

  • 发射端:2个天线
  • 接收端:1个天线
  • 编码方案:Alamouti空时编码
  • 可配置调制方式:BPSK/QPSK/16QAM/64QAM
% 2Tx1Rx STBC-MIMO系统仿真
clear; clc;

%% 系统参数
txNum = 2;               % 发射天线数
rxNum = 1;               % 接收天线数
modType = 'QPSK';        % 调制类型
bitLength = 1e4;         % 传输比特数
snrRange = 0:2:20;       % 信噪比范围(dB)
frameCount = 100;        % 每SNR仿真帧数

% 调制参数配置
switch modType
    case 'BPSK'
        bitsPerSym = 1;
        symSet = [0, 1];
    case 'QPSK'
        bitsPerSym = 2;
        symSet = 0:3;
    case '16QAM'
        bitsPerSym = 4;
        symSet = 0:15;
    case '64QAM'
        bitsPerSym = 6;
        symSet = 0:63;
end

% 比特数对齐
bitLength = ceil(bitLength/bitsPerSym) * bitsPerSym;

%% 主循环
errorRate = zeros(size(snrRange));
for idx = 1:length(snrRange)
    errSum = 0; bitSum = 0;
    
    for frm = 1:frameCount
        % 生成随机比特
        txBits = randi([0 1], bitLength, 1);
        
        % 调制
        modSyms = modulate(txBits, modType);
        
        % Alamouti编码
        encSyms = stbcEncode(modSyms);
        
        % 瑞利信道
        H = (randn(rxNum, txNum, length(encSyms)) + ...
             1i*randn(rxNum, txNum, length(encSyms))) / sqrt(2);
        
        % 加噪传输
        rxSyms = transmit(encSyms, H, snrRange(idx));
        
        % Alamouti解码
        decSyms = stbcDecode(rxSyms, H);
        
        % 解调
        rxBits = demodulate(decSyms, modType);
        
        % 误码统计
        errSum = errSum + sum(txBits ~= rxBits);
        bitSum = bitSum + bitLength;
    end
    
    errorRate(idx) = errSum / bitSum;
end

%% 结果可视化
figure;
semilogy(snrRange, errorRate, 'bo-', 'LineWidth', 1.5);
grid on;
xlabel('信噪比(dB)'); 
ylabel('误码率');
title([num2str(txNum) '发' num2str(rxNum) '收STBC-MIMO性能 (' modType ')']);

%% 调制函数
function out = modulate(bits, scheme)
    switch scheme
        case 'BPSK'
            out = 1 - 2*double(bits);
        case 'QPSK'
            rebits = reshape(bits, 2, [])';
            symIdx = bi2de(rebits, 'left-msb');
            out = exp(1i*(pi/2*symIdx + pi/4));
        case '16QAM'
            rebits = reshape(bits, 4, [])';
            symIdx = bi2de(rebits, 'left-msb');
            out = qammod(symIdx, 16, 'UnitAveragePower', true);
        case '64QAM'
            rebits = reshape(bits, 6, [])';
            symIdx = bi2de(rebits, 'left-msb');
            out = qammod(symIdx, 64, 'UnitAveragePower', true);
    end
end

%% 解调函数
function out = demodulate(syms, scheme)
    switch scheme
        case 'BPSK'
            out = real(syms) < 0;
        case 'QPSK'
            phase = angle(syms);
            symIdx = mod(round((phase - pi/4)/(pi/2)), 4);
            out = de2bi(symIdx, 2, 'left-msb')';
            out = out(:);
        case '16QAM'
            symIdx = qamdemod(syms, 16, 'UnitAveragePower', true);
            out = de2bi(symIdx, 4, 'left-msb')';
            out = out(:);
        case '64QAM'
            symIdx = qamdemod(syms, 64, 'UnitAveragePower', true);
            out = de2bi(symIdx, 6, 'left-msb')';
            out = out(:);
    end
end

%% STBC编码器
function out = stbcEncode(syms)
    out = zeros(2, length(syms));
    for k = 1:2:length(syms)-1
        s1 = syms(k); 
        s2 = syms(k+1);
        out(1,k) = s1;       % 时隙1: 天线1
        out(2,k) = s2;       % 时隙1: 天线2
        out(1,k+1) = -conj(s2); % 时隙2: 天线1
        out(2,k+1) = conj(s1);  % 时隙2: 天线2
    end
end

%% 信道传输
function out = transmit(txSyms, H, snr)
    [~, symCount] = size(txSyms);
    out = zeros(size(H,1), symCount);
    noiseVar = 10^(-snr/10);
    
    for t = 1:symCount
        chOut = H(:,:,t) * txSyms(:,t);
        noise = sqrt(noiseVar/2)*(randn(size(chOut)) + 1i*randn(size(chOut)));
        out(:,t) = chOut + noise;
    end
end

%% STBC解码器
function out = stbcDecode(rxSyms, H)
    symCount = size(rxSyms, 2);
    out = zeros(1, symCount);
    
    for k = 1:2:symCount-1
        y1 = rxSyms(:,k); 
        y2 = rxSyms(:,k+1);
        h1 = H(:,1,k); 
        h2 = H(:,2,k);
        
        % Alamouti组合
        s1_hat = conj(h1).*y1 + h2.*conj(y2);
        s2_hat = conj(h2).*y1 - h1.*conj(y2);
        
        % 信道增益归一化
        chGain = abs(h1).^2 + abs(h2).^2;
        out(k) = s1_hat ./ chGain;
        out(k+1) = s2_hat ./ chGain;
    end
end

信道估计增强实现

%% 带信道估计的STBC-MIMO
function ber = stbcMIMO_CE()
    % 系统参数
    txNum = 2; rxNum = 1;
    modType = 'QPSK';
    bitLen = 1e4;
    snrVec = 0:2:20;
    frameNum = 100;
    
    % 导频配置
    pilotSym = [1; -1j];  % QPSK导频
    pilotInterval = 10;
    
    % 调制参数
    switch modType
        case 'BPSK', symBits = 1;
        case 'QPSK', symBits = 2;
        case '16QAM', symBits = 4;
        case '64QAM', symBits = 6;
    end
    
    % 主循环
    ber = zeros(size(snrVec));
    for snrIdx = 1:length(snrVec)
        errCnt = 0; bitCnt = 0;
        
        for frm = 1:frameNum
            % 生成数据
            dataBits = randi([0 1], bitLen, 1);
            dataSyms = modulate(dataBits, modType);
            
            % 插入导频
            txSyms = [];
            pilotPos = [];
            for p = 1:pilotInterval:length(dataSyms)
                txSyms = [txSyms; pilotSym];
                pilotPos = [pilotPos, length(txSyms)-1, length(txSyms)];
                endIdx = min(p+pilotInterval-1, length(dataSyms));
                txSyms = [txSyms; dataSyms(p:endIdx)];
            end
            
            % STBC编码
            encSyms = stbcEncode(txSyms);
            
            % 信道传输
            H_true = (randn(rxNum, txNum, size(encSyms,2)) + ...
                     1i*randn(rxNum, txNum, size(encSyms,2)))/sqrt(2);
            rxSyms = transmit(encSyms, H_true, snrVec(snrIdx));
            
            % 信道估计
            H_est = zeros(size(H_true));
            for p = 1:2:length(pilotPos)-1
                pos = pilotPos(p);
                y1 = rxSyms(:,pos); y2 = rxSyms(:,pos+1);
                h1 = (conj(pilotSym(1))*y1 + pilotSym(2)*conj(y2))/2;
                h2 = (conj(pilotSym(2))*y1 - pilotSym(1)*conj(y2))/2;
                H_est(:,:,pos:pos+1) = cat(3, h1, h2);
            end
            
            % 线性插值
            for ant = 1:txNum
                for rx = 1:rxNum
                    H_est(rx,ant,:) = interp1(pilotPos, ...
                        squeeze(H_est(rx,ant,pilotPos)), ...
                        1:size(H_est,3), 'linear');
                end
            end
            
            % STBC解码
            decSyms = stbcDecode(rxSyms, H_est);
            decSyms(pilotPos) = [];  % 移除导频
            
            % 误码统计
            rxBits = demodulate(decSyms, modType);
            errCnt = errCnt + sum(dataBits ~= rxBits);
            bitCnt = bitCnt + bitLen;
        end
        
        ber(snrIdx) = errCnt / bitCnt;
    end
    
    % 结果展示
    figure;
    semilogy(snrVec, ber, 'ms-', 'LineWidth', 1.5);
    grid on;
    xlabel('信噪比(dB)'); ylabel('误码率');
    title('带信道估计的STBC-MIMO性能');
end

系统性能对比

%% STBC-MIMO与SISO性能对比
function compareSystems()
    modType = '16QAM';
    bitLen = 1e4;
    snrVec = 0:2:20;
    frameNum = 50;
    
    berMIMO = zeros(size(snrVec));
    berSISO = zeros(size(snrVec));
    
    for snrIdx = 1:length(snrVec)
        errMIMO = 0; errSISO = 0; bitTotal = 0;
        
        for frm = 1:frameNum
            % 公共数据源
            data = randi([0 1], bitLen, 1);
            modSyms = modulate(data, modType);
            
            %% MIMO分支
            encSyms = stbcEncode(modSyms);
            H_mimo = (randn(1,2,size(encSyms,2)) + ...
                      1i*randn(1,2,size(encSyms,2)))/sqrt(2);
            rxMIMO = transmit(encSyms, H_mimo, snrVec(snrIdx));
            decSyms = stbcDecode(rxMIMO, H_mimo);
            rxBitsMIMO = demodulate(decSyms, modType);
            errMIMO = errMIMO + sum(data ~= rxBitsMIMO);
            
            %% SISO分支
            H_siso = (randn(1,1,length(modSyms)) + ...
                      1i*randn(1,1,length(modSyms)))/sqrt(2);
            rxSISO = zeros(size(modSyms));
            for k = 1:length(modSyms)
                rxSISO(k) = H_siso(:,:,k)*modSyms(k);
            end
            noise = sqrt(10^(-snrVec(snrIdx)/10)/2) * ...
                    (randn(size(rxSISO)) + 1i*randn(size(rxSISO)));
            rxSISO = rxSISO + noise;
            eqSyms = rxSISO ./ squeeze(H_siso);
            rxBitsSISO = demodulate(eqSyms, modType);
            errSISO = errSISO + sum(data ~= rxBitsSISO);
            
            bitTotal = bitTotal + bitLen;
        end
        
        berMIMO(snrIdx) = errMIMO / bitTotal;
        berSISO(snrIdx) = errSISO / bitTotal;
    end
    
    % 可视化对比
    figure;
    semilogy(snrVec, berMIMO, 'bd-', 'LineWidth', 1.5, 'DisplayName', 'STBC-MIMO');
    hold on;
    semilogy(snrVec, berSISO, 'r^--', 'LineWidth', 1.5, 'DisplayName', 'SISO');
    grid on;
    xlabel('信噪比(dB)'); ylabel('误码率');
    title(['系统性能对比 (' modType ')']);
    legend('Location', 'best');
end

实现说明:

  1. 支持不同调制方式配置
  2. 包含基础实现和信道估计扩展
  3. 提供与SISO系统的性能对比
  4. 采用准静态平坦瑞利衰落信道模型

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。