认识LTE(七):LTE中的两种无反馈模式:发射分集(TM2)和开环空分复用(TM3)
主要注意,在TM3中,不仅仅有码本W,还有CCD,循环延时分集的操作,这是书中没有提到的,具体可以看https://zhuanlan.zhihu.com/p/495045923,把两天线的情况说的比较清晰了。我们可以看到,在TM2中,层映射和预编码是在一步完成的,SFBC自然而然的把输出序列变为了两列,是非常巧妙的!既然是MIMO了,首先我们先来讲一下预编码,理想的预编码是SVD,这是最好的,但很
认识LTE(七):LTE中的两种无反馈模式:发射分集(TM2)和开环空分复用(TM3)
文章目录
零.代码地址
https://github.com/liu-zongxi/LTE_simulation
请大家看完觉得有用别忘了点赞收藏,github项目给star哦
一.LTE中MIMO的一些基本概念
在介绍这两种模式之前,我们要大致说一下MIMO的一些基本概念
- LTE的MIMO包括两个步骤,层映射和预编码,所谓层映射,是指把数据流映射到多个层,MIMO中就可以按层数发送,预编码则是MIMO的手段。分集使用SFBC,二MIMO则是用于减小计算量的SVD
- 层,什么是层呢?
- 层数怎么来确定呢?这涉及到两方面,一个是发射天线和接收天线数,层数和Rank相关,二是要确保要满秩,满秩就要环境足够复杂
- 流:这被称为CodeWord,非常迷惑人的一个称呼,他表示的实际上是有几个数据流
- Rank:这会被再CSI中用RI参数来反馈矩阵的秩的大小
- 层映射,把流映射到层、
二.TM2:发射分集
1. 原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXuaYMzQ-1660205620527)(http://images.lzxixi.ltd/image-20220811143519619.png)]
开局一张图
在之前的博客中,我详细的写过STBC的原理和实现,大家可以去翻看一下
那么SFBC有什么区别呢,答案是没什么区别,只是把其中一个进行了一个符号的变换
有趣的是,在TM2中,四天线和二天线本质上是一致的,哪怕是八天线,其实还是二天线
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使用了码本,开环选用固定的码本,而闭环的会变化,这就是区别
主要注意,在TM3中,不仅仅有码本W,还有CCD,循环延时分集的操作,这是书中没有提到的,具体可以看https://zhuanlan.zhihu.com/p/495045923,把两天线的情况说的比较清晰了
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不是一个酉矩阵,不可以这样解算
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)