认识LTE(七):LTE中的两种无反馈模式:发射分集(TM2)和开环空分复用(TM3)

零.代码地址

https://github.com/liu-zongxi/LTE_simulation

请大家看完觉得有用别忘了点赞收藏,github项目给star哦

一.LTE中MIMO的一些基本概念

在介绍这两种模式之前,我们要大致说一下MIMO的一些基本概念

  1. LTE的MIMO包括两个步骤,层映射和预编码,所谓层映射,是指把数据流映射到多个层,MIMO中就可以按层数发送,预编码则是MIMO的手段。分集使用SFBC,二MIMO则是用于减小计算量的SVD
  2. 层,什么是层呢?

image-20220811142035461

  1. 层数怎么来确定呢?这涉及到两方面,一个是发射天线和接收天线数,层数和Rank相关,二是要确保要满秩,满秩就要环境足够复杂
  2. 流:这被称为CodeWord,非常迷惑人的一个称呼,他表示的实际上是有几个数据流
  3. Rank:这会被再CSI中用RI参数来反馈矩阵的秩的大小
  4. 层映射,把流映射到层、

image-20220811143352890

二.TM2:发射分集

1. 原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXuaYMzQ-1660205620527)(http://images.lzxixi.ltd/image-20220811143519619.png)]

开局一张图

在之前的博客中,我详细的写过STBC的原理和实现,大家可以去翻看一下

那么SFBC有什么区别呢,答案是没什么区别,只是把其中一个进行了一个符号的变换

image-20220811144256689

有趣的是,在TM2中,四天线和二天线本质上是一致的,哪怕是八天线,其实还是二天线

image-20220811144423435

function out = TDEncode(in, numTx)
%   Both SFBC and SFBC with FSTD
persistent hTDEnc;
if isempty(hTDEnc)
    % Use same object for either scheme
    hTDEnc = comm.OSTBCEncoder('NumTransmitAntennas', 2);
end
switch numTx
    case 1
        out=in;
    case 2 % SFBC
        % 为了公用Alamouti的代码,把第二个符号取负共轭
        in((2:2:end).') = -conj(in((2:2:end).'));
        % STBC Alamouti
        y= step(hTDEnc, in);       
        % Scale
        out = y/sqrt(2);
    case 4
        inLen=size(in,1);
        y = complex(zeros(inLen, 4));
        % 同样的操作,STBC到SFBC的转换
        in((2:2:end).') = -conj(in((2:2:end).'));
        % 取出一二两根天线,然后又是使用matlab的特性把他们两交织在一起
        % 这个在之前插值中已经使用过此技巧了
        % idx12的序列是1 2 5 6 9 10...
        % 这最终会被映射到13天线
        idx12 = ([1:4:inLen; 2:4:inLen]); idx12 = idx12(:);
        % 34天线
        % 映射到24天线
        idx34 = ([3:4:inLen; 4:4:inLen]); idx34 = idx34(:);
        % 进行STBC
        y(idx12, [1 3]) = step(hTDEnc, in(idx12));
        y(idx34, [2 4]) = step(hTDEnc, in(idx34));
        out = y/sqrt(2);
end
function y = TDCombine(in, chEst, numTx, numRx)
% LTE transmit diversity combining
%   SFBC and SFBC with FSTD.
persistent hTDDec;
% 为什么只设置2*2的呢,因为即使是4天线也是两个2天线组成的
% 接收具体是如何实现的呢
% function s = Alamouti_Combiner1(u,H)
% %#codegen
% % STBC_DEC STBC Combiner
% % Outputs the recovered symbol vector
% LEN=size(u,1);
% Nr=size(u,2);
% BlkSize=2;
% % 2个为一组
% NoBlks=LEN/BlkSize;
% % Initialize outputs
% h=complex(zeros(1,2));
% s=complex(zeros(LEN,1));
% % Alamouti code for 2 Tx
% indexU=(1:BlkSize);
% for m=1:NoBlks
% t_hat=complex(zeros(BlkSize,1));
% h_norm=0.0;
% % 一个天线一个天线来接受
% for n=1:Nr
% % 一次使用两个时间的即h1和h2
% h(:)=H(2*m-1,:,n);
% % 代表着能量
% h_norm=h_norm+real(h*h');
% r=u(indexU,n);
% r(2)=conj(r(2));
% % 分子
% shat=[conj(h(1)), h(2); conj(h(2)), -h(1)]*r;
% t_hat=t_hat+shat;
% end
% s(indexU)=t_hat/h_norm; % Maximum-likelihood combining
% indexU=indexU+BlkSize;
% end
% end
if isempty(hTDDec)
    % OSTBC combiner - always numTx = 2
    hTDDec = comm.OSTBCCombiner('NumTransmitAntennas', 2, ...
        'NumReceiveAntennas', numRx);
end
inLen = size(in, 1);
Index=(2:2:inLen)';
switch numTx
    case 1
        y=in;
    case 2   % For 2TX - SFBC
        % 恢复本来大小
        in = sqrt(2) * in; % Scale
        y = step(hTDDec, in,chEst);
        % ST to SF transformation.
        % Apply blockwise correction for 2nd symbol combining
        % 恢复成SFBC
        y(Index) = -conj(y(Index));
    case 4   % For 4Tx - SFBC with FSTD
        in = sqrt(2) * in; % Scale
        H = complex(zeros(inLen, 2, numRx));
        idx12 = ([1:4:inLen; 2:4:inLen]); idx12 = idx12(:);
        idx34 = ([3:4:inLen; 4:4:inLen]); idx34 = idx34(:);
        % 找到对应的信道
        H(idx12, :, :) = chEst(idx12, [1 3], :);
        H(idx34, :, :) = chEst(idx34, [2 4], :);
        y = step(hTDDec, in, H);
        % ST to SF transformation.
        % Apply blockwise correction for 2nd symbol combining
        % 恢复成SFBC
        y(Index) = -conj(y(Index));
end

2.全流程

function [dataIn, dataOut, txSig, rxSig, dataRx, yRec, csr_ref]...
    = commlteMIMO_TD_step(nS, snrdB, prmLTEDLSCH, prmLTEPDSCH, prmMdl)
%% TX
%  Generate payload
% 生成数据
dataIn = genPayload(nS,  prmLTEDLSCH.TBLenVec);
% 添加CRC
% Transport block CRC generation
tbCrcOut1 =CRCgenerator(dataIn);
% Channel coding includes - CB segmentation, turbo coding, rate matching,
% bit selection, CB concatenation - per codeword
[data, Kplus1, C1] = lteTbChannelCoding(tbCrcOut1, nS, prmLTEDLSCH, prmLTEPDSCH);
%Scramble codeword
scramOut = lteScramble(data, nS, 0, prmLTEPDSCH.maxG);
% Modulate
modOut = Modulator(scramOut, prmLTEPDSCH.modType);
% TD with SFBC
numTx=prmLTEPDSCH.numTx;
alamouti = TDEncode(modOut(:,1),numTx);
% Generate Cell-Specific Reference (CSR) signals
% CSR的处理
csr = CSRgenerator(nS, numTx);
csr_ref=complex(zeros(2*prmLTEPDSCH.Nrb, 4, numTx));
for m=1:numTx
    csr_pre=csr(1:2*prmLTEPDSCH.Nrb,:,:,m);
    csr_ref(:,:,m)=reshape(csr_pre,2*prmLTEPDSCH.Nrb,4);
end
% Resource grid filling
txGrid = REmapper_mTx(alamouti, csr_ref, nS, prmLTEPDSCH);
% OFDM transmitter
txSig = OFDMTx(txGrid, prmLTEPDSCH);
%% Channel
% MIMO Fading channel
[rxFade, chPathG] = MIMOFadingChan(txSig, prmLTEPDSCH, prmMdl);
% Add AWG noise
nVar = 10.^(0.1.*(-snrdB));
rxSig =  AWGNChannel(rxFade, nVar);
%% RX
% OFDM Rx
rxGrid = OFDMRx(rxSig, prmLTEPDSCH);
% updated for numLayers -> numTx
[dataRx, csrRx, idx_data] = REdemapper_mTx(rxGrid, nS, prmLTEPDSCH);
% MIMO channel estimation
if prmMdl.chEstOn
    chEst = ChanEstimate_mTx(prmLTEPDSCH, csrRx,  csr_ref, prmMdl.chEstOn);
    hD     = ExtChResponse(chEst, idx_data, prmLTEPDSCH);
else
    idealChEst = IdChEst(prmLTEPDSCH, prmMdl, chPathG);
    hD =  ExtChResponse(idealChEst, idx_data, prmLTEPDSCH);
end
% Frequency-domain equalizer
if (numTx==1)
    % Based on Maximum-Combining Ratio (MCR)
    yRec = Equalizer_simo(dataRx, hD, nVar, prmLTEPDSCH.Eqmode);
else
    % Based on Transmit Diversity  with SFBC combiner
    yRec = TDCombine(dataRx, hD, prmLTEPDSCH.numTx, prmLTEPDSCH.numRx);
end
% Demodulate
demodOut = DemodulatorSoft(yRec, prmLTEPDSCH.modType, nVar);
% Descramble received codeword
rxCW =  lteDescramble(demodOut, nS, 0, prmLTEPDSCH.maxG);
% Channel decoding includes - CB segmentation, turbo decoding, rate dematching
[decTbData1, ~,~] = lteTbChannelDecoding(nS, rxCW, Kplus1, C1,  prmLTEDLSCH, prmLTEPDSCH);
% Transport block CRC detection
[dataOut, ~] = CRCdetector(decTbData1);
end

我们可以看到,在TM2中,层映射和预编码是在一步完成的,SFBC自然而然的把输出序列变为了两列,是非常巧妙的!其他的和SISO没有太大的变化

三.TM3:开环空间复用

1.原理

既然是MIMO了,首先我们先来讲一下预编码,理想的预编码是SVD,这是最好的,但很遗憾,这要求反馈信道,这是做不到的

因此LTE使用了码本,开环选用固定的码本,而闭环的会变化,这就是区别

image-20220811151531550

image-20220811151547232

主要注意,在TM3中,不仅仅有码本W,还有CCD,循环延时分集的操作,这是书中没有提到的,具体可以看https://zhuanlan.zhihu.com/p/495045923,把两天线的情况说的比较清晰了

image-20220811152115384

image-20220811152126559

function out = LayerMapper(in1, in2, prmLTEPDSCH)
% LTE Layer mapper for spatial multiplexing.
%
%   Assumes two codeword input for spatial multiplexing.
%   As per TS 36.211 v10.0.0, Section 6.3.3.2.

%   Copyright 2012 The MathWorks, Inc.

%#codegen
% Assumes the incoming codewords are of the same length.
% 参数获取
q = prmLTEPDSCH.numCodeWords;           % Number of codewords
v = prmLTEPDSCH.numLayers;                   % Number of layers
% 两个数据流,TM3总是支持双流的,而现在考虑的是满秩情况
inLen1 = size(in1, 1);
inLen2 = size(in2, 1);
% 根据数据流分类
switch q
    % 如果是单流,那直接根据层数分列就可以了
    case 1  % Single codeword
        % for numLayers = 1,2,3,4
        out = reshape(in1, [], v);
    % 双流的情况
    case 2  % Two codewords
        switch v
            % 两层
            case 2
                % 双流双层,分别对应即可
                out = complex(zeros(inLen1, v));
                out(:,1) = in1(:,1);
                out(:,2) = in2(:,1);
            case 3 % => different length input codewords
                assert(false, '3 layers for 2 codewords is not implemented yet.');
            case 4
                % 双流四层
                % 一个流则对应两个层
                out = complex(zeros(inLen1/2, v));
                out(:,1:2) = reshape(in1, 2, inLen1/2).';
                out(:,3:4) = reshape(in2, 2, inLen2/2).';
            case 5 % => different length input codewords
                assert(false, '5 layers for 2 codewords is not implemented yet.');
            case 6
                % 双流六层
                % 一个流对应三个层
                out = complex(zeros(inLen1/3, v));
                out(:,1:3) = reshape(in1, 3, inLen1/3).';
                out(:,4:6) = reshape(in2, 3, inLen2/3).';
            case 7 % => different length input codewords
                assert(false, '7 layers for 2 codewords is not implemented yet.');
            case 8
                % 双流八层
                out = complex(zeros(inLen1/4, v));
                out(:,1:4) = reshape(in1, 4, inLen1/4).';
                out(:,5:8) = reshape(in2, 4, inLen2/4).';
        end
end

% [EOF]

function [out1, out2] = LayerDemapper(in, prmLTEPDSCH)
% LTE Layer demapper for spatial multiplexing.
%
%   Assumes two codeword input for spatial multiplexing.
%   Based on TS 36.211 v10.0.0, Section 6.3.3.2.

%   Copyright 2012 The MathWorks, Inc.

%#codegen
%   Assumes the incoming codewords are of the same length. Assumes the
%   input signal is oriented similarly as the output of the layer mapper.

q = prmLTEPDSCH.numCodeWords;       % Number of codewords
v = size(in, 2);                    % Number of layers
% 注意,这不是单纯的反过来,还是把数据映射到数据流,但要根据层来
switch q
    case 1  % Single codeword
        out1 = in(:);
        out2 = out1; % dummy
    case 2  % Two codewords
        switch v
            case 2
                out1 = in(:,1);
                out2 = in(:,2);
            case 4
                temp = in(:,1:2).';
                out1 = temp(:);
                temp = in(:,3:4).';
                out2 = temp(:);
            case 6
                temp = in(:,1:3).';
                out1 = temp(:);
                temp = in(:,4:6).';
                out2 = temp(:);
            case 8
                temp = in(:,1:4).';
                out1 = temp(:);
                temp = in(:,5:8).';
                out2 = temp(:);
            otherwise
                out1 = in;
                out2 = in;
        end
    otherwise
        out1 = in;
        out2 = in;
end

function out = SpatialMuxPrecoderOpenLoop(in, prmLTEPDSCH)
% Precoder for PDSCH spatial multiplexing
%#codegen
% Assumes the incoming codewords are of the same length
v = prmLTEPDSCH.numLayers;              % Number of layers
% Initialize the output
out = complex(zeros(size(in)));
inLen = size(in, 1);
% Apply the relevant precoding matrix to the symbol over all layers
for n = 1:inLen
    % Compute the precoding matrix
    % 获得 W D U
    [W, D, U] = PrecoderMatrixOpenLoop(n, v);
    T=W *D*U;
    % 预编码
    temp = T* (in(n, :).');
    out(n, :) = temp.';
end
function [W, D, U] = PrecoderMatrixOpenLoop(n, v)
% 开环MIMO的预编码矩阵
% 实现有问题,参考https://zhuanlan.zhihu.com/p/495045923进行了修改
% LTE Precoder for PDSCH spatial multiplexing.
%#codegen
% i四个就循环了,所以直接mod4
idx=mod(n-1,4);
switch v
    % 层为1,会退化到TM2,不考虑这样的情况
    case 1
        % 涉及到TM3模式的CCD有WUD三个矩阵
        % 单流就是这样,相当于没有进行CCD
        W=complex(1,0);
        U=W;D=W;
    % 层为2
    case 2
        % 是否少了(1/sqrt(2))
        % W= [1 0; 0 1];
        W=(1/sqrt(2)) * [1 0; 0 1];
        U=(1/sqrt(2))*[1 1;1 exp(-1j*pi)];
        D=[1 0;0 exp(-1j*pi*idx)];
    case 4 
        k=1+mod(floor(n/4),4);
        switch k
            case 1, un = [1 -1 -1 1].';
            case 2, un = [1 -1 1 -1].';
            case 3, un = [1 1 -1 -1].';
            case 4, un = [1 1 1 1].';
        end
        W = eye(4) - 2*(un*un')./(un'*un);
        switch k    % order columns
            case 3
                W = W(:, [3 2 1 4]);
            case 2
                W = W(:, [1 3 2 4]);
        end
        a=[0*(0:1:3);2*(0:1:3);4*(0:1:3);6*(0:1:3)];
        U=(1/2)*exp(-1j*pi*a/4);
        b=0:1:3;
        D=diag(exp(-1j*2*pi*idx*b/4));
end

2.全流程

function [dataIn, dataOut, txSig, rxSig, dataRx, yRec, csr_ref]...
    = commlteMIMO_SM_Mode3_step(nS, snrdB, prmLTEDLSCH, prmLTEPDSCH, prmMdl)
%% TX
%  Generate payload
dataIn = genPayload(nS,  prmLTEDLSCH.TBLenVec);
% Transport block CRC generation
tbCrcOut1 =CRCgenerator(dataIn);
% Channel coding includes - CB segmentation, turbo coding, rate matching,
% bit selection, CB concatenation - per codeword
[data, Kplus1, C1] = lteTbChannelCoding(tbCrcOut1, nS, prmLTEDLSCH, prmLTEPDSCH);
%Scramble codeword
scramOut = lteScramble(data, nS, 0, prmLTEPDSCH.maxG);
% Modulate
modOut = Modulator(scramOut, prmLTEPDSCH.modType);
% Map modulated symbols  to layers
% 调制后进行层映射,这里是单流
numTx=prmLTEPDSCH.numTx;
LayerMapOut = LayerMapper(modOut, [], prmLTEPDSCH);
% Precoding
% 预编码
PrecodeOut = SpatialMuxPrecoderOpenLoop(LayerMapOut, prmLTEPDSCH);
% Generate Cell-Specific Reference (CSR) signals
csr = CSRgenerator(nS, numTx);
csr_ref=complex(zeros(2*prmLTEPDSCH.Nrb, 4, numTx));
for m=1:numTx
    csr_pre=csr(1:2*prmLTEPDSCH.Nrb,:,:,m);
    csr_ref(:,:,m)=reshape(csr_pre,2*prmLTEPDSCH.Nrb,4);
end
% Resource grid filling
txGrid = REmapper_mTx(PrecodeOut, csr_ref, nS, prmLTEPDSCH);
% OFDM transmitter
txSig = OFDMTx(txGrid, prmLTEPDSCH);
%% Channel
% MIMO Fading channel
[rxFade, chPathG] = MIMOFadingChan(txSig, prmLTEPDSCH, prmMdl);
% Add AWG noise
sigPow = 10*log10(var(rxFade));
nVar = 10.^(0.1.*(sigPow-snrdB));
rxSig =  AWGNChannel(rxFade, nVar);
%% RX
% OFDM Rx
rxGrid = OFDMRx(rxSig, prmLTEPDSCH);
% updated for numLayers -> numTx
[dataRx, csrRx, idx_data] = REdemapper_mTx(rxGrid, nS, prmLTEPDSCH);
% MIMO channel estimation
if prmMdl.chEstOn
    chEst = ChanEstimate_mTx(prmLTEPDSCH, csrRx,  csr_ref, prmMdl.chEstOn);
    hD     = ExtChResponse(chEst, idx_data, prmLTEPDSCH);
else
    idealChEst = IdChEst(prmLTEPDSCH, prmMdl, chPathG);
    hD =  ExtChResponse(idealChEst, idx_data, prmLTEPDSCH);
end
% Frequency-domain equalizer
if (numTx==1)
    % Based on Maximum-Combining Ratio (MCR)
    yRec = Equalizer_simo(dataRx, hD,mean(nVar), prmLTEPDSCH.Eqmode);
else
    % Based on Spatial Multiplexing
    yRec = MIMOReceiver_OpenLoop(dataRx, hD, prmLTEPDSCH, nVar);
end
% Demap received codeword(s)
[cwOut, ~] = LayerDemapper(yRec, prmLTEPDSCH);    
if prmLTEPDSCH.Eqmode < 3
    % Demodulate
    demodOut = DemodulatorSoft(cwOut, prmLTEPDSCH.modType, mean(nVar));
else
    demodOut = cwOut;
end
% Descramble received codeword
rxCW =  lteDescramble(demodOut, nS, 0, prmLTEPDSCH.maxG);
% Channel decoding includes - CB segmentation, turbo decoding, rate dematching
[decTbData1, ~,~] = lteTbChannelDecoding(nS, rxCW, Kplus1, C1,  prmLTEDLSCH, prmLTEPDSCH);
% Transport block CRC detection
[dataOut, ~] = CRCdetector(decTbData1);
end

可以看到,数据先进行层映射,再进行预编码,在层映射阶段,数据被映射为层数列,而预编码的意义就是再把层数映射到天线数列

这里要重点说一下的是接收机的均衡的解算

function y = MIMOReceiver_MMSE_OpenLoop(in, chEst, nVar, v)
%#codegen
% MIMO Receiver:
%   Based on received channel estimates, process the data elements
%   to equalize the MIMO channel. Uses the MMSE detector.
% noisFac = numLayers*diag(nVar);
noisFac = diag(nVar);
numData = size(in, 1);
y = complex(zeros(size(in)));
%% MMSE receiver
for n = 1:numData
    [W, D, U] = PrecoderMatrixOpenLoop(n, v);
    % iWn = (W *D*U)';             % Orthonormal matrix,W并不一定是酉矩阵吗这是不对的
    iWn = inv(W *D*U);
    h = chEst(n, :, :);               % numTx x numRx
    % 哪有这样的,层不一定等于天线数!
    h = reshape(h(:), v, v).';    % numRx x numTx
    Q = (h'*h + noisFac)\h';
    x = Q * in(n, :).';
    tmp = iWn * x;
    y(n, :) = tmp.';
end

这份代码有一个重大的问题,就是它默认了层=天线数,这是错误的!但由于是2天线的情况,暂时不追究

此外,W不是一个酉矩阵,不可以这样解算

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐