程序阅读_全面详解LTE:MATLAB建模仿真与实现_自学笔记(2)OFDM_程序阅读

本章详细阅读 LTE 标准中的 OFDM 帧结构和实现,讨论 OFDM信号的时-频映射和多种适应信道带宽的资源元素粒度,同时考察迫零(ZF)、最小均方误差(MMSE)、均衡器和重要参考或导频信号。最后,考察到现在为止学习的组件所组成的收发端在 LTE 定义的多种多径衰落和移动条件下的性能

文章目录

  • 程序阅读\_全面详解LTE:MATLAB建模仿真与实现_自学笔记(2)OFDM\_程序阅读
    • commlteSISO.m主函数
      • commlteSISO_params设置参数
      • commlteSISO_initialize通信模型初始化
        • prmsPDSCH程序解读
          • PBCH的时频分布
          • 小区参考信号
          • 主同步信号
          • 辅助同步信号
          • 计算用户数据符号数量
      • zReport_data_rate打印参数
    • OFDM发射端建模_TX
      • commlteSISO_step(TX)发射部分程序注解
      • genPayload函数程序解读
      • CRCgenerator生成CRC校验码
      • lteTbChannelCoding传输块信道编码
        • comm.CRCGenerator_在lteTbChannelCoding出现
        • lteCblkSegParams_在lteTbChannelCoding出现
        • lteIntrlvrIndices_在lteTbChannelCoding出现
        • comm.TurboEncoder_在lteTbChannelCoding出现
      • CSRgenerator程序解读
      • REmapper_1Tx
      • OFDMTx
        • OFDM产生原理(复数IFDT变换原理)
        • 基于复数IFFT的OFDM信号发生过程
    • 信道建模
      • 例程1:ChanModelFading函数解读
        • comm.MIMOChannel系统对象
        • 添加AWGN信道
    • OFDM接收端建模_RX
      • OFDMRX
      • 资源元素反映射
      • 信道估计
        • gridResponse_interpolate典型内插算法
        • 典型的平均算法
      • 均衡器增益计算
    • 信道可视化_结果图

commlteSISO.m主函数

在《全面详解LTE:MATLAB建模仿真与实现》第五章,主要讨论单入单出型OFDM的实现,SISO主要包含了三大部分的内容,分别是发射端建模,传输信道建模,接收端建模。

其中最主要函数是commlteSISO_step.m,通过调用commlteSISO_step.m函数,实现通信模型的建立,因此随后会对commlteSISO_step函数中涉及的发射端,传输信道,接收端模型详细研究。

主函数的主要流程包括几个部分:初始化参数/结构体→在命令窗口打印这些参数数值→commlteSISO_step函数,建立通信模型(会在后文展开)→计算误码率→结果可视化。如图所示:

附commlteSISO程序代码:

clear all
clear functions
disp('Simulating the LTE Mode 1: Single Tx and Rx antrenna');   % 仿真LTE模式1:单发射天线和单接收天线
%% Set simulation parametrs & initialize parameter structures设置仿真参数和初始化参数结构
commlteSISO_params; %设置参数
[prmLTEPDSCH, prmLTEDLSCH, prmMdl] = commlteSISO_initialize( chanBW, contReg,  modType, Eqmode,...cRate,maxIter, fullDecode, chanMdl, corrLvl, chEstOn, maxNumErrs, maxNumBits);
clear chanBW contReg numTx numRx modType Eqmode cRate maxIter fullDecode chanMdl corrLvl chEstOn maxNumErrs maxNumBits;
%%
zReport_data_rate(prmLTEDLSCH, prmLTEPDSCH);    % 功能:在命令窗口打印参数
hPBer = comm.ErrorRate;                         % ErrorRate对象比较来自发射器的输入数据和来自接收器的输入数据% 并将错误率作为运行统计值计算出来。
% snrdB=prmMdl.snrdBs(end);
maxNumErrs=prmMdl.maxNumErrs;
maxNumBits=prmMdl.maxNumBits;
%% Simulation loop 仿真循环
nS = 0; % Slot number, one of [0:2:18] 时隙编号
Measures = zeros(3,1); % initialize BER output
while (( Measures(2)< maxNumErrs) && (Measures(3) < maxNumBits))[dataIn, dataOut, txSig, rxSig, dataRx, yRec, csr] = ...commlteSISO_step(nS, snrdB, prmLTEDLSCH, prmLTEPDSCH, prmMdl);% Calculate  bit errors计算误码率Measures = step(hPBer, dataIn, dataOut);% Visualize constellations and spectrum可视化if visualsOnzVisualize( prmLTEPDSCH, txSig, rxSig, yRec, dataRx, csr, nS);end;% Update subframe number 更新时隙序号nS = nS + 2; if nS > 19, nS = mod(nS, 20); end;
end
disp(Measures);

commlteSISO_params设置参数

  • commlteSISO_params与commlteSISO_initialize参数设置的区别

此函数设置了PDSCH/DLSCH/信道模型/仿真参数等内容,在这里设置的参数,是全局参数,就是在各个嵌套函数中也可以调用的参数。

而一会儿再commlteSISO_initialize里定义的参数,就是定义在结构体中,如果嵌套的函数需要调用,就需要将结构体作为参数,传入函数中。

需要补充的是:

PDSCH的物理层处理流程

eNB以TTI为工作节拍,在每个TTI内,基站通过SCH将传输块(TB)送到物理层。物理层接收到传输块(TB)后,开始物理层的处理过程。每个用户最多可以并发两个处理过程。

​ 1、物理层首先给传输块(TB)加上24bit的CRC冗余校验比特,与PDCCH的16bit CRC并不相同。

​ 2、完成CRC处理后,还会进行数据分块,以适合后续的Turbo编码。Turbo编码要求数据块的大小不超过6144bit,因此CRC处理后的数据块长度如果超过6144bit,就会分块。另外,每个分块还会加上24bit的CRC。

​ 3、数据分块之后,进行Turbo编码,Turbo编码属于前向纠错编码FEC。LTE系统的Turbo编码采用1:3的编码率。

​ 4、Turbo编码后,数据块进行速率适配RM。

% PDSCH PDSCH参数设置
numTx        = 1;    % Number of transmit antennas发射天线数
numRx        = 1;    % Number of receive antennas接收天线数
chanBW       = 4;    % Index to chanel bandwidth used [1,....6]  使用索引方式确定带宽[1,....6]有6种带宽
contReg      = 1;    % No. of OFDM symbols dedictaed to control information [1,...,3] 用1/2/3个OFDM符号来做控制信道
modType      = 2;    % Modulation type [1, 2, 3] for ['QPSK,'16QAM','64QAM']
%% DLSCH (Downlink Shared CHannel) 下行共享信道
cRate        = 1/3;  % Rate matching target coding rate
maxIter      = 6;    % Maximum number of turbo decoding terations  表示允许的迭代最大次数的意思
fullDecode   = 0;    % Whether "full" or "early stopping" turbo decoding is performed 是否加入早期终止机制
% Channel model 信道模型
chanMdl      =  'frequency-selective-high-mobility'; % 频率选择性+高移动速率
corrLvl      = 'Low';   % ?相关程度较低 ?
% Simulation parametrs
Eqmode       = 2;    % Type of equalizer used [1,2] for ['ZF', 'MMSE']均衡器选择'ZF'或 'MMSE'
% MMSE作为一种均衡器,是一种后处理算法,它可以帮助我们找出接收到的数据,使之尽可能地接近原始数据(传输数据)
chEstOn      = 1;    % Whether channel estimation is done or ideal channel model used进行信道估计/使用理想信道模型
maxNumErrs   = 1e7;  % Maximum number of errors found before simulation stops
maxNumBits   = 1e7;  % Maximum number of bits processed before simulation stops
visualsOn    = 0;    % Whether to visualize channel response and constellations是否可视化信道响应和星座
snrdB        = 16;   % Value of SNR used in this experiment信噪比16dB

commlteSISO_initialize通信模型初始化

在该函数中,实现了对PDSCH / DLSCH / 信道参数的初始化,将定义的变量写入结构体中,以便之后调用。

该函数又另外涉及了两个函数,分别是prmsPDSCH和prmsDLSCH,将在后文介绍。附程序注释:

function [prmLTEPDSCH, prmLTEDLSCH, prmMdl] = commlteSISO_initialize(chanBW, contReg, modType, Eqmode,...
cRate,maxIter, fullDecode, chanMdl, corrLvl, chEstOn, maxNumErrs, maxNumBits)
% Create the parameter structures 生成参数结构体
% PDSCH and DLSCH
prmLTEPDSCH = prmsPDSCH(chanBW, contReg, modType); % 计算PDSCH各信号类型的数量
prmLTEPDSCH.Eqmode=Eqmode;      %均衡器的选择
prmLTEPDSCH.modType=modType;    %调制类型
prmLTEDLSCH = prmsDLSCH(cRate,maxIter, fullDecode, prmLTEPDSCH);
% Channel parameters 信道参数
prmMdl.chanMdl = chanMdl;
prmMdl.corrLevel = corrLvl;
prmMdl.chEstOn = chEstOn;
switch modTypecase 1snrdBs=[0:4:8, 9:12];case 2snrdBs=[0:4:12, 13:16];otherwisesnrdBs=0:4:24;
end
prmMdl.snrdBs=snrdBs;
prmMdl.maxNumBits=maxNumBits;
prmMdl.maxNumErrs=maxNumErrs;

prmsPDSCH程序解读

在commlteSISO_initialize程序中,定义了prmsPDSCH函数,函数功能为:定义一个PDSCH参数结构 输出是一个关于P的结构体,包含PDSCH各信号类型的数量

附程序:

function p= prmsPDSCH(chanBW, contReg, modType, varargin)
% LTEPDSCHPRMS Returns parameter structures for LTE PDSCH simulation.
% PDSCH参数结构 输出是一个关于P的结构体,包含PDSCH各信号类型的数量
% Assumes a FDD, normal cyclic prefix, full-bandwidth, single-user
% SISO or SIMO downlink transmission.
%% PDSCH parameters
switch chanBWcase 1      % 1.4 MHzBW = 1.4e6; N = 128; cpLen0 = 10; cpLenR = 9;Nrb = 6; chanSRate = 1.92e6; % cpLen0:第一个OFDM符号的cp时长T_cp=5.2us% cpLenR:其他6个OFDM符号的cp时长T_cp=4.7uscase 2      % 3 MHzBW = 3e6; N = 256; cpLen0 = 20; cpLenR = 18;Nrb = 15; chanSRate = 3.84e6;case 3      % 5 MHzBW = 5e6; N = 512; cpLen0 = 40; cpLenR = 36;Nrb = 25; chanSRate = 7.68e6;case 4      % 10 MHzBW = 10e6; N = 1024; cpLen0 = 80; cpLenR = 72;Nrb = 50; chanSRate = 15.36e6;case 5      % 15 MHzBW = 15e6; N = 1536; cpLen0 = 120; cpLenR = 108;Nrb = 75; chanSRate = 23.04e6;case 6      % 20 MHzBW = 20e6; N = 2048; cpLen0 = 160; cpLenR = 144;Nrb = 100; chanSRate = 30.72e6;
end
p.BW = BW;                  % Channel bandwidth
p.N = N;                    % NFFT
p.cpLen0 = cpLen0;          % Cyclic prefix length for 1st symbol 第一个OFDM符号的cp时长
p.cpLenR = cpLenR;          % Cyclic prefix length for remaining 其他OFDM符号的cp时长
p.Nrb = Nrb;                % Number of resource blocks 资源块数量RB
p.chanSRate = chanSRate;    % Channel sampling rate 采样频率
p.contReg = contReg;        % 用1/2/3个OFDM符号来做控制信道
p.numTx = 1;
p.numRx = 1;
p.numLayers = 1;
p.numCodeWords = 1;% For Normal cyclic prefix, FDD mode
p.deltaF = 15e3;    % subcarrier spacing 子载波间隔
p.Nrb_sc = 12;      % no. of subcarriers per resource block 每个RB中的子载波个数
p.Ndl_symb = 7;     % no. of OFDM symbols in a slot 每个RB中的时隙% Actual PDSCH bits calculation - accounting for PDCCH, PBCH, PSS, SSS
% PDSCH比特计算
numResources = (p.Nrb*p.Nrb_sc)*(p.Ndl_symb*2); %当前参数下是(50*12)*(7*2)资源元素的数量(一个子帧内)
numCSRRE = 2*2*2 * p.Nrb;               % CSR, RE per OFDMsym/slot/subframe per RB
numContRE = (10 + 12*(p.contReg-1))*p.Nrb;
% LTE系统的下行控制信道分布在每个子帧的控制区上,控制区占用了子帧第一个时隙的
% 第一个OFDM符号到第N个OFDM符号,由于第一个OFDM符号内有2个参考信号,因此是10个子载波,第2/3个OFDM符号内是12个
numBCHRE = 60+72+72+72;              % removing the CSR present in 1st symbol(不包含第一个OFDM符号内的CSR)
% PBCH分布在每个无线帧的第0号子帧的第二个时隙上,占用了第一个OFDM符号到第4个OFDM符号,每10ms占用一次
numSSSRE=72;
numPSSRE=72;numDataRE=zeros(3,1); %见后文对计算用户数据符号数量的介绍
% Account for BCH, PSS, SSS and PDCCH for subframe 0
numDataRE(1)=numResources-numCSRRE-numContRE-numSSSRE - numPSSRE-numBCHRE;
% Account for PSS, SSS and PDCCH for subframe 5
numDataRE(2)=numResources-numCSRRE-numContRE-numSSSRE - numPSSRE;
% Account for PDCCH only in all other subframes
numDataRE(3)=numResources-numCSRRE-numContRE;% Maximum data resources - with no extra overheads (only CSR + data)
p.numResources=numResources;
p.numCSRResources =  numCSRRE;
p.numContRE = numContRE;
p.numBCHRE = numBCHRE;
p.numSSSRE=numSSSRE;
p.numPSSRE=numPSSRE;
p.numDataRE=numDataRE;
p.numDataResources = p.numResources - p.numCSRResources;% Modulation types , bits per symbol, number of layers per codeword调制类型
Qm = 2 * modType;
p.Qm = Qm;
p.numLayPerCW = p.numLayers/p.numCodeWords;% Maximum data bits - with no extra overheads (only CSR + data) 最大数据比特数
p.numDataBits = p.numDataResources*Qm*p.numLayPerCW;
numPDSCHBits =numDataRE*Qm*p.numLayPerCW; % 数据块比特数量(有三个维度即:0号子帧/5号子帧/其他子帧)
p.numPDSCHBits = numPDSCHBits;
p.maxG = max(numPDSCHBits);

补充几点:

PBCH的时频分布

从频率上看,PBCH分布在频点带宽中心的72个子载波上,相当于6个RB的带宽。

从时间上看,PBCH分布在每个无线帧的第0号子帧的第二个时隙上,占用了第一个OFDM符号到第4个OFDM符号,每10ms占用一次

由于CSR占了12个,因此:

numBCHRE = 60+72+72+72;          % removing the CSR present in 1st symbol
小区参考信号

从时间分布上看,LTE 的小区参考信号分布在每时隙的第一个 OFDM 符号和倒数第三个OFDM符号上,以0.5 ms为循环周期。

因此,小区参考信号数量:

numCSRRE = 2*2*2 * p.Nrb;               % CSR, RE per OFDMsym/slot/subframe per RB
主同步信号

主同步信号只占用频点中心的6个RB带宽的子载波。6个RB带宽对应72个子载波,不过主同步信号只占用这72个子载波中央的62个子载波,剩下的10个子载波,一边5个,用于频率保护。

辅助同步信号

在FDD双工方式下,基站在每个无线帧的第0号和第5号子帧上,找到第一时隙的倒数第二个OFDM符号,只占用频点中心72个子载波中央的62个子载波,剩下的10个子载波,一边5个,用于频率保护。

因此,在matlab程序中,定义一个0/5号子帧中的同步信号数量是:

numSSSRE=72;
numPSSRE=72;
计算用户数据符号数量

资源网格内数据总量与资源块数量或本质上与带宽有关。资源元素有6 种数据资源类型(用户数据、CSR、DCI、PSS,SSS 和 BCH)。因此,假如单位带宽恒定,则资源网格大小可表示为
Ntotal =Nuser data +NCSR+NDCI+NPSS+NSSS+NBCHN_{\text {total }}=N_{\text {user data }}+N_{\mathrm{CSR}}+N_{\mathrm{DCI}}+N_{\mathrm{PSS}}+N_{\mathrm{SSS}}+N_{\mathrm{BCH}} Ntotal ​=Nuser data ​+NCSR​+NDCI​+NPSS​+NSSS​+NBCH​
对子帧0,可表示所有数据资源∶
Nuser data =Ntotal −(NCSR+NDCI+NPSS+NSSS+NBCH)N_{\text {user data }}=N_{\text {total }}-\left(N_{\mathrm{CSR}}+N_{\mathrm{DCI}}+N_{\mathrm{PSS}}+N_{\mathrm{SSS}}+N_{\mathrm{BCH}}\right) Nuser data ​=Ntotal ​−(NCSR​+NDCI​+NPSS​+NSSS​+NBCH​)
对子帧5,除了用户数据,还可表示CSR、DCI、PSS,和 SSS∶
Nuser data =Ntotal −(NCSR+NDCI+NPSS+NSSS)N_{\text {user data }}=N_{\text {total }}-\left(N_{\mathrm{CSR}}+N_{\mathrm{DCI}}+N_{\mathrm{PSS}}+N_{\mathrm{SSS}}\right) Nuser data ​=Ntotal ​−(NCSR​+NDCI​+NPSS​+NSSS​)
其他帧{1,2,3,4,6,7,8,9},除了用户数据,只可以表示 CSR 和 DCI符号∶
Nuser data =Ntotal −(NCSR+NDCI)N_{\text {user data }}=N_{\text {total }}-\left(N_{\mathrm{CSR}}+N_{\mathrm{DCI}}\right) Nuser data ​=Ntotal ​−(NCSR​+NDCI​)
在matlab中的体现为:

numDataRE=zeros(3,1);
% Account for BCH, PSS, SSS and PDCCH for subframe 0
numDataRE(1)=numResources-numCSRRE-numContRE-numSSSRE - numPSSRE-numBCHRE;
% Account for PSS, SSS and PDCCH for subframe 5
numDataRE(2)=numResources-numCSRRE-numContRE-numSSSRE - numPSSRE;
% Account for PDCCH only in all other subframes{1,2,3,4,6,7,8,9}
numDataRE(3)=numResources-numCSRRE-numContRE;

zReport_data_rate打印参数

功能:在命令窗口打印参数

function y = zReport_data_rate(p1, p2)
y=(1/10.0e-3)*(p1.TBLenVec(1)+p1.TBLenVec(2)+8*p1.TBLenVec(3));
% p1.TBLenVec指数据块比特数量(有三个维度即:0号/5号/其他子帧)
Mod={'QPSK','16QAM','64QAM'};
fprintf(1,'Modulation = %s\n',Mod{p2.modType});
fprintf(1,'Coding rate = %6.4f \n',p1.cRate);
fprintf(1,'Bandwidth = %6.2f MHz\n',p2.Nrb/5);
fprintf(1,'MIMO Antenna  = %1d x %1d \n',p2.numTx, p2.numRx);
fprintf(1,'Data rate = %6.2f Mbps\n\n',y/1e6);
end

+++

OFDM发射端建模_TX

首先给出OFDM在发射端建模时用到的函数及概述。

其中,标红部分为函数,发射端涉及的函数非常多,很多函数中又嵌套很多函数,下文将逐一记录。

commlteSISO_step(TX)发射部分程序注解

在发射端commlteSISO_step,实现流程如下:

生成有效载荷(此处用随机数模拟)→生成CRC校验码数据块TB信道编码对数据块加扰码对数据块进行调制产生小区专用参考信号CSR将PDSCH/CSR(/PDCCH/PSS/SSS/BCH)进行资源网格的配置进行OFDM调制

下图是发射端流程(这是PBCH的流程图,也是数据发射的通用流程)图片来源《LTE教程:结构与实施》

接下来将按照实现流程的顺序,逐一对涉及的函数进行记录。下附commlteSISO_step发射部分的程序及注释:

function [dataIn, dataOut, txSig, rxSig, dataRx, yRec, csr_ref]...= commlteSISO_step(nS, snrdB, prmLTEDLSCH, prmLTEPDSCH, prmMdl)
%% TX
%  Generate payload 生成有效载荷
dataIn = genPayload(nS,  prmLTEDLSCH.TBLenVec);
% Transport block CRC generation 传输块CRC生成
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);
% Generate Cell-Specific Reference (CSR) signals 生成小区专用参考信号
csr = CSRgenerator(nS, prmLTEPDSCH.numTx);    %一共有200个小区参考信号,每个时隙产生两个,为每个子帧生成2个时隙
% 在1个子帧内,终端有4次机会接收到Gold序列(小区参考信号),每次接收到的Gold序列都是不同的
% Resource grid filling 资源网格(RE)填充
E=8*prmLTEPDSCH.Nrb;
csr_ref=reshape(csr(1:E),2*prmLTEPDSCH.Nrb,4);
% reshape:重构数组,使用大小向量(2*prmLTEPDSCH.Nrb,4)重构 csr(1:E)
% 重构之后,相当于列出了在每一个OFDM符号内,所对应的100个小区专用参考信号
txGrid = REmapper_1Tx(modOut, csr_ref, nS, prmLTEPDSCH);
% OFDM transmitter OFDM发送
txSig = OFDMTx(txGrid, prmLTEPDSCH);

注意:本程序不完整,缺少信道传输模块和接收模块,这两部分将在后文介绍

下文将主要对genPayload、lteTbChannelCoding、CSRgenerator、REmapper_1Tx、OFDMTx分别详述。

genPayload函数程序解读

该函数的主要功能:生成有效载荷函数。根据不同子帧,确定每个时隙需要生成的数据码长度,然后随机生成数据码。

由于在第0号和第5号子帧中存在 BCH, PSS, SSS等,因此第0、5号子帧的数据码长度要小于其他子帧,子帧长度已经在参数设置中定义好了。

输入参数

​ nS:时隙编号[0:2:18]

​ prmLTEDLSCH.TBLenVec指数据块(TB)比特数量(有三个维度即:0号/5号/其他子帧)

​ 产生随机数据码

function data = genPayload_HZ(nS,  outLenVec)
% 根据子帧号的不同,生成对应于每一个子帧长度的数据有效载荷
%#codegen
% Extract parameters
outLen = max(outLenVec);switch nS                           % nS:时隙编号[0:2:18]case 0                          % 0号子帧的TB块长度outLen = outLenVec(1);case 10                         % 5号子帧的TB块长度outLen = outLenVec(2);otherwise                       % 其他子帧的TB块长度outLen = outLenVec(3);
enddata = logical(randi( [0 1], outLen, 1));   % 产生随机数据码% [EOF]

CRCgenerator生成CRC校验码

数据内容首先进行CRC处理,CRC长度为24bit。基站在进行CRC处理时,加入循环冗余校验[1 1 0 0 0 0 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 1 0 1 1]。

comm.CRCGenerator('Polynomial', [1 1 0 0 0 0 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 1 0 1 1]);
  1. CRC 算法应用于每个子帧。
  2. 生成的校验和将附加到每个子帧的末尾。

生成方式:

CRC method Generator polynomial
CRC-32 z32+z26+z23+z22+z16+z12+z11+z10+z8+z7+z5+z4+z2+z+1z^{32} + z^{26} + z^{23} + z^{22} + z^{16} + z^{12} + z^{11} + z^{10} + z^{8} + z^{7 }+ z^{5} + z^{4 }+ z^{2} + z + 1z32+z26+z23+z22+z16+z12+z11+z10+z8+z7+z5+z4+z2+z+1
CRC-24 'z^24 + z^23 + z^14 + z^12 + z^8 + 1'
CRC-16 'z^16 + z^15 + z^2 + 1'

CRC 算法的基本思想是将传输的数据[M(X)] 当做一个位数很长的数。将这个数除以另一个数[G(X)] ,得到的余数[R(X)] 作为校验数据附加到原数据后面,组成循环校验码。

M(X) 代表待编码的有效信息
G(X) 代表约定好的多项式
R(X) 代表代表检验位

由于,CRC的结构 = 信息位(N位) + 校验位(K位)

所以,CRC编码 = M(X) + R(X)

在lteTbChannelCoding传输块信道编码中也用到了CRC编码.

lteTbChannelCoding传输块信道编码

函数主要功能:传输数据块的信道编码,即CB(Code Block) segmentation、turbo coding、rate matching、bit selection、CB concatenation

包含以下几个函数/系统对象

comm.CRCGenerator CRC校验码产生模块

lteCblkSegParams 为给定的传输块长度提供代码块分段参数

lteIntrlvrIndices 生成turbo码内部交织器索引 详见第四章程序阅读

comm.TurboEncoder Turbo码编码模块

lteCbRateMatching 码率匹配

输入:

tbCrcOut1:经过添加CRC校验后的数据

nS:时隙序号

prmLTEDLSCH:DLSCH参数结构体

prmLTEPDSCH:PDSCH参数结构体

输出:

out:传输数据快的数据输出

Kplus:每个子码块的长度反映在参数 Kplus

C:一共被分割的块数

附程序解读:

function [out, Kplus, C] = lteTbChannelCoding(in, nS, prmLTEDLSCH, prmLTEPDSCH)
% Transport block channel coding 传输数据块的信道编码
% Reference: [1] "3GPP Technical Specification Group Radio Access Network;
% Evolved Universal Terrestrial Radio Access (E-UTRA); Multiplexing and
% channel coding (Release 10)", 3GPP TS 36.212 v10.0.0 (2010-12).%   Copyright 2012 The MathWorks, Inc.%#codegenpersistent hCBCRCGen hCBTEnc1 hCBTEncAll;
if isempty(hCBCRCGen)% CRC generator - CB level 调用comm工具箱生成CRChCBCRCGen = comm.CRCGenerator('Polynomial', [1 1 zeros(1, 16) 1 1 0 0 0 1 1]);
end
if isempty(hCBTEnc1)% Turbo Encoder - CB level, C==1hCBTEnc1 = comm.TurboEncoder('TrellisStructure', prmLTEDLSCH.trellis, ...'InterleaverIndicesSource',  'Input port');
end
if isempty(hCBTEncAll)% Turbo Encoder - CB level, C>1hCBTEncAll = comm.TurboEncoder('TrellisStructure', prmLTEDLSCH.trellis, ...'InterleaverIndicesSource',  'Input port');
endinLen = size(in, 1);
[C, ~, Kplus] =  lteCblkSegParams(inLen-24); % 不要中间的输出参数,只要C和Kplus两个参数
% C是被分割的块数,Kplus是188种指定长度的一个
intrlvrIndices = lteIntrlvrIndices(Kplus);G = prmLTEPDSCH.maxG; % default 所有子帧中传输数据块最大的数量
switch nScase {0}G = prmLTEPDSCH.numPDSCHBits(1);case {2, 4, 6, 8, 12, 14, 16, 18}G = prmLTEPDSCH.numPDSCHBits(3);case {10}G = prmLTEPDSCH.numPDSCHBits(2);otherwise% Do nothing
end% Bit selection parameters
Nl = prmLTEPDSCH.numLayPerCW; % Number of layers a TB is mapped to (Rel10)每个TB映射到的层数
Qm = prmLTEPDSCH.Qm;          % modulation bits 调制速率
Gprime = G/(Nl*Qm);
gamma = mod(Gprime, C);% Initialize output 初始化输出
out = false(G, 1);% Channel coding the TB     TB数据块信道编码
if (C==1) % single CB, no CB CRC used 如果数据块不是很长,不分块的话,直接加CRC% Turbo encodetEncCbData = step(hCBTEnc1, in, intrlvrIndices);% Rate matching, with bit selection 使用码率匹配rmCbData = lteCbRateMatching(tEncCbData, Kplus, C, G);% unify code pathsout = logical(rmCbData);
else % multiple CBs in TB 在一个TB中有多个CB数据块(数据分块了)startIdx = 0;for cbIdx = 1:C% Code-block segmentationcbData = in((1:(Kplus-24))' + (cbIdx-1)*(Kplus-24));% Append checksum to each CB分别给每个块加上CRCcrcCbData = step(hCBCRCGen, cbData);% Turbo encode each CB 为每个数据块进行Turbo编码tEncCbData = step(hCBTEncAll, crcCbData, intrlvrIndices);% Rate matching with bit selection进行码率匹配if ((cbIdx-1) <= (C-gamma-1))E = Nl*Qm*floor(Gprime/C);elseE = Nl*Qm*ceil(Gprime/C);end        rmCbData = lteCbRateMatching(tEncCbData, Kplus, C, E);% Code-block concatenation 将各个数据块粘合上out((1:E)' + startIdx) = logical(rmCbData);startIdx = startIdx + E;end
end% [EOF]

下文简要介绍以下几个函数:

comm.CRCGenerator CRC校验码产生模块

lteCblkSegParams 为给定的传输块长度提供代码块分段参数

lteIntrlvrIndices 生成turbo码内部交织器索引 详见第四章程序阅读

comm.TurboEncoder Turbo码编码模块

lteCbRateMatching 码率匹配

comm.CRCGenerator_在lteTbChannelCoding出现

crcgenerator 系统对象为每个输入帧生成循环冗余校验(CRC)码位,并将其附加到帧中

差错控制分为发现错误和纠正错误两个步骤,发现错误通常采用循环冗余校验(CRC),纠正错误采用卷积和Turbo编码。

在通信系统中,CRC只用于检错。CRC编码基于循环码,循环码硬件上很容易用带反馈的移位寄存器实现。

相关代码在lteTbChannelCoding里的前几行:

hCBCRCGen = comm.CRCGenerator('Polynomial', [1 1 zeros(1, 16) 1 1 0 0 0 1 1]);

crcgenerator = comm.CRCGenerator(Name,Value)使用一个或多个名称-值对设置属性。 例如,comm.CRCGenerator(‘Polynomial’,‘z^16 + z^14 + z + 1’)配置CRC生成器系统对象附加CRC-16循环冗余校验位到输入帧。 在通信系统中,使用24位CRC校验码。

lteCblkSegParams_在lteTbChannelCoding出现

为给定的传输块长度提供代码块分段参数,该函数之前有过提及,如果传输快长度大于6144,就分块,将传输快按照指定的188种格式,进行分块,详见第四章例程25.

原版书是这么写的:

If the input frame to the turbo encoder exceeds the maximum size, the transport block is usually divided into multiple smaller blocks known as codeblocks. Since the internal interleaver of the turbo encoder is only defined for 188 input block sizes, the sizes of these codeblocks need to match the set of codeblock sizes supported by the turbo coder.

意思是:如果输入帧大于Turbo编码器的最大处理长度,那么就分成若干小块处理。Turbo编码器内部的交织器仅仅只定义了188种长度类型(看程序也可以看得出来,validK是188个长度类型,最小的是40,最长的是6144,因此当长度大于6144时,就要分块处理,如果不大于,就选择合适的Turbo编码器长度)

lteIntrlvrIndices_在lteTbChannelCoding出现

生成turbo码内部交织器索引 详见第四章程序阅读_TbChannelCoding程序解读

使用ltelntrlvrIndices 函数构建使用QPP的 LTE 交织器。
这个函数可查找LTE交织器表中支持的188个输入长度,并查找相应的 fl 和 f 常数,然后计算得到符合标准定义的序列向量。得到交织(打乱)后的排列序号。

comm.TurboEncoder_在lteTbChannelCoding出现

详见第四章 Turbo编码程序 内容

+++

CSRgenerator程序解读

该函数主要功能:小区参考信号的生成,具体地讲,通过生成了不同nS下的小区参考信号,Gold序列上连续的两个码元需要先调制位一个QPSK调制符号,然后这个QPSK调制符号再映射到用于承载小区参考信号的RE上

详见《LTE教程:结构与实施》P43

输入:
nS: 子帧索引,即代表无线帧内时隙的序号
numTx: 发射天线数

输出:
y: 参考信号CSR参考序列

小区参考信号的生成过程:

该函数完成了前两部,即加扰和调制,然后返回主程序参考信号CSR的参考序列。

  • Gold序列的生成方式

附程序:

function y = CSRgenerator(nS, numTx)
%  LTE Cell-Specific Reference signal generation.
%   为每个OFDM符号生成整个集合,为每个时隙生成2个OFDM符号,为每个天线端口(numTx)中的每个子帧生成2个时隙
%   这个函数负责每个天线端口序列的生成,而到资源元素的实际映射是在Resource mapper中完成的。
%#codegen
persistent hSeqGen;
persistent hInt2Bit;
% Assumed parameters
NcellID = 0;        % One of possible 504 values    小区编码
Ncp = 1;            % for normal CP, or 0 for Extended CP   正常CP类型
NmaxDL_RB = 100;    % largest downlink bandwidth configuration, in resource blocks  最大下行链路带宽
y = complex(zeros(NmaxDL_RB*2, 2, 2, numTx));
l = [0; 4];     % OFDM symbol idx in a slot for common first antenna port   Gold序列初始值,0或4
% Buffer for sequence per OFDM symbol  每个OFDM符号的序列缓冲器
seq = zeros(size(y,1)*2, 1); % *2 for complex outputs
if isempty(hSeqGen)hSeqGen = comm.GoldSequence('FirstPolynomial',[1 zeros(1, 27) 1 0 0 1],...'FirstInitialConditions', [zeros(1, 30) 1], ...'SecondPolynomial', [1 zeros(1, 27) 1 1 1 1],...'SecondInitialConditionsSource', 'Input port',... 'Shift', 1600,...'SamplesPerFrame', length(seq));    % 取1600个码元之后的440个码元hInt2Bit = comm.IntegerToBit('BitsPerInteger', 31);
end
% Generate the common first antenna port sequences 生成通用的第一天线端口序列
for i = 1:2 % slot wise for lIdx = 1:2 % symbol wisec_init = (2^10)*(7*((nS+i-1)+1)+l(lIdx)+1)*(2*NcellID+1) + 2*NcellID + Ncp;% Convert to binary vectoriniStates = step(hInt2Bit, c_init); %把c_init转换成了0/1表示的31位% Scrambling sequence - as per Section 7.2, 36.211seq = step(hSeqGen, iniStates); % Store the common first antenna port sequences每两个是一个数,生成200个复数形式的经过加扰的数据流y(:, lIdx, i, 1) = (1/sqrt(2))*complex(1-2.*seq(1:2:end), 1-2.*seq(2:2:end));end
end
% Copy the duplicate set for second antenna port, if exists 复制第二个天线端口的副本设置
if (numTx>1)y(:, :, :, 2) = y(:, :, :, 1);
end
% Also generate the sequence for l=1 index for numTx = 4
if (numTx>2)for i = 1:2 % slot wise% l = 1c_init = (2^10)*(7*((nS+i-1)+1)+1+1)*(2*NcellID+1) + 2*NcellID + Ncp;% Convert to binary vectoriniStates = step(hInt2Bit, c_init);% Scrambling sequence - as per Section 7.2, 36.211seq = step(hSeqGen, iniStates); % Store the third antenna port sequencesy(:, 1, i, 3) = (1/sqrt(2))*complex(1-2.*seq(1:2:end), 1-2.*seq(2:2:end));end% Copy the duplicate set for fourth antenna porty(:, 1, :, 4) = y(:, 1, :, 3);
end

REmapper_1Tx

该函数功能:资源网格按标准制定位置放置资源元素的资源元素映射过程。映射本质上是生成一个资源网格矩阵索引符并将多种信息类型放置入网格的过程。三种不同类型的资源块如图所示。根据使用的子帧不同,我们在围绕资源网格中心 DC子载波的6个资源块的子帧0和子帧5上放置 BCH、PSS,和 SSS。CSR 放置在每个时隙的符号0 和5上,它们在频域间隔六个子载波。

图1:资源元素映射∶子帧1,2,3,4,5,7,8和9+的所有资源块以及子帧0和5的非中心资源块。包括 DCI、CSR,和用户数据

图2 资源元素映射∶子帧5的中心资源块,包括 PSS、SSS、DCI、CSR 和用户数据

图3 资源元素映射∶子帧0的中心资源块,包括 BCH、PSS、SSS、DCI、CSR和用户数据

附张大图,白色表示用户数据,黄色表示CSR,天蓝色是PDCCH,红色是SSS,深蓝色是PSS,绿色是BCH

附程序:

function y = REmapper_1Tx(in, csr, nS, prmLTE, varargin)
% 输入变量是可变的varargin
% 输入:
%   in
%   csr
%   nS
%   prmLTE
%   varargin
% 输出:
%   y
%#codegen
switch nargin %输入可变参数的个数case 4, pdcch=[];pss=[];sss=[];bch=[];case 5, pdcch=varargin{1};pss=[];sss=[];bch=[];case 6, pdcch=varargin{1};pss=varargin{2};sss=[];bch=[];case 7, pdcch=varargin{1};pss=varargin{2};sss=varargin{3};bch=[];case 8, pdcch=varargin{1};pss=varargin{2};sss=varargin{3};bch=varargin{4};otherwiseerror('REMapper has 4 to 8 arguments!');
end
% NcellID = 0;                      % One of possible 504 values
% numTx = 1;                        % prmLTE.numTx;
% Get input params
Nrb = prmLTE.Nrb;                   % either of {6,15,25,50,75,100}当前程序出入为50
Nrb_sc = prmLTE.Nrb_sc;             % 12 for normal mode 每个RB中的子载波个数
Ndl_symb = prmLTE.Ndl_symb;         % 7    for normal mode 每个RB中的时隙
numContSymb    = prmLTE.contReg;    % either {1, 2, 3}  用1/2/3个OFDM符号来做控制信道
% Initialize output buffer
y = complex(zeros(Nrb*Nrb_sc, Ndl_symb*2)); %初始化y矩阵,设置y是一个600*14的复数矩阵
%% Specify resource grid location indices for CSR, PDCCH, PDSCH, PBCH, PSS, SSS
%% 1st: Indices for CSR pilot symbols   参考信号
lenOFDM = Nrb*Nrb_sc;
idx        = 1:lenOFDM;          % 一个OFDM符号上的格子数,即有600个子载波
idx_csr0   = 1:6:lenOFDM;        % More general starting point = 1+mod(NcellID, 6);在第0号OFDM符号的CSR起始位置
idx_csr4   = 4:6:lenOFDM;        % More general starting point = 1+mod(3+NcellID, 6);在第4号OFDM符号的CSR起始位置
idx_csr    =[idx_csr0, 4*lenOFDM+idx_csr4, 7*lenOFDM+idx_csr0, 11*lenOFDM+idx_csr4]; %一个子帧中共有400个CSR
%% 2nd: Indices for PDCCH control data symbols
ContREs=numContSymb*lenOFDM;     % 将第1个OFDM符号作为控制信道,这里是600*1
idx_dci=1:ContREs;               % Downlink Control Information从1:600
idx_pdcch = ExpungeFrom(idx_dci,idx_csr0);  % 排除掉属于参考信号的序号
%% 3rd: Indices for PDSCH and PDSCH data in OFDM symbols whee pilots are present
idx_data0= ExpungeFrom(idx,idx_csr0);   % 去掉参考信号序号后的都是PDSCH(0号OFDM符号上的数据)
idx_data4 = ExpungeFrom(idx,idx_csr4);  % 去掉参考信号序号后的都是PDSCH(4号OFDM符号上的数据)
%% Handle 3 types of subframes differently
switch nS%% 4th: Indices for BCH, PSS, SSS are only found in specific subframes 0 and 5% Thsese symbols share the same 6 center sub-carrier locations (idx_ctr)% and differ in OFDM symbol number.case 0    % Subframe 0  0号子帧% PBCH, PSS, SSS are available + CSR, PDCCH, PDSCHidx_6rbs = (1:72);idx_ctr = 0.5* lenOFDM - 36 + idx_6rbs ;    % 计算PBCH对应的序号idx_SSS  = 5* lenOFDM + idx_ctr;            % 计算辅助同步信号SSS对应的序号idx_PSS  = 6* lenOFDM + idx_ctr;            % 计算主同步信号SSS对应的序号idx_ctr0 = ExpungeFrom(idx_ctr,idx_csr0);   % 排除包含的参考信号 idx_bch=[7*lenOFDM + idx_ctr0, 8*lenOFDM + idx_ctr, 9*lenOFDM + idx_ctr, 10*lenOFDM + idx_ctr];% 第0号子帧的第二个时隙的0号OFDM符号是BCHidx_data5   = ExpungeFrom(idx,idx_ctr);     % 5号OFDM符号上的数据idx_data7 = ExpungeFrom(idx_data0,idx_ctr); % 7号OFDM符号上的数据idx_data   = [ContREs+1:4*lenOFDM,   4*lenOFDM+idx_data4, ...5*lenOFDM+idx_data5, 6*lenOFDM+idx_data5,  7*lenOFDM+idx_data7, 8*lenOFDM+idx_data5, ...9*lenOFDM+idx_data5, 10*lenOFDM+idx_data5, 11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];               % 整个调度块(600*14)上的数据信号对应的序号y(idx_csr)=csr(:);                 % Insert Cell-Specific Reference signal (CSR) = pilotsy(idx_data)=in;                    % Insert Physical Downlink Shared Channel (PDSCH) = user dataif ~isempty(pdcch), y(idx_pdcch)=pdcch;end       % Insert Physical Downlink Control Channel (PDCCH)if ~isempty(pss), y(idx_PSS)=pss;end                   % Insert Primary Synchronization Signal (PSS)if ~isempty(sss), y(idx_SSS)=sss;end                    % Insert Secondary Synchronization Signal (SSS)if ~isempty(bch), y(idx_bch)=bch;end                   % Insert Broadcast Cahnnel data (BCH)case 10  % Subframe 5% PSS, SSS are available + CSR, PDCCH, PDSCH% Primary ans Secondary synchronization signals in OFDM symbols 5 and 6idx_6rbs = (1:72);idx_ctr = 0.5* lenOFDM - 36 + idx_6rbs ;idx_SSS  = 5* lenOFDM + idx_ctr;idx_PSS  = 6* lenOFDM + idx_ctr;idx_data5 = ExpungeFrom(idx,idx_ctr);idx_data   = [ContREs+1:4*lenOFDM, 4*lenOFDM+idx_data4,  5*lenOFDM+idx_data5, 6*lenOFDM+idx_data5, ...7*lenOFDM+idx_data0, 8*lenOFDM+1:11*lenOFDM,  11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];y(idx_csr)=csr(:);                 % Insert Cell-Specific Reference signal (CSR) = pilotsy(idx_data)=in;                    % Insert Physical Downlink Shared Channel (PDSCH) = user dataif ~isempty(pdcch), y(idx_pdcch)=pdcch;end       % Insert Physical Downlink Control Channel (PDCCH)if ~isempty(pss), y(idx_PSS)=pss;end                   % Insert Primary Synchronization Signal (PSS)if ~isempty(sss), y(idx_SSS)=sss;end                    % Insert Secondary Synchronization Signal (SSS)otherwise % other subframes% Only CSR, PDCCH, PDSCHidx_data = [ContREs+1:4*lenOFDM, 4*lenOFDM+idx_data4, ...5*lenOFDM+1:7*lenOFDM, ...7*lenOFDM+idx_data0, ...8*lenOFDM+1:11*lenOFDM, ...11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];y(idx_csr)=csr(:);                 % Insert Cell-Specific Reference signal (CSR) = pilotsy(idx_data)=in;                    % Insert Physical Downlink Shared Channel (PDSCH) = user dataif ~isempty(pdcch), y(idx_pdcch)=pdcch;end       % Insert Physical Downlink Control Channel (PDCCH)
end
end

OFDMTx

OFDM信号生成在资源网格上进行。我们将OFDM符号一个接一个进行IFFT并附加 CP生成OFDM调制信号。

OFDM产生原理(复数IFDT变换原理)

离散余弦变换(非重点,单纯补充,不是该函数使用的方法)

复数IFDT变换

基于复数IFFT的OFDM信号发生过程

回到该函数:函数的输入为资源网格(in)和包含 PDSCH参数的结构(prmLTE)。一个时隙内各个符号的 CP长度各不相同。每个时隙的第一个OFDM符号的 CP长度(cpLenO)略长于其他6个符号的CP值(cpLenR)。更多解释见程序注释:

function y = OFDMTx(in, prmLTE)
%#codegen
persistent hIFFT;
if isempty(hIFFT)hIFFT = dsp.IFFT;
end
[len, numSymb, numLayers] = size(in);
% N assumes 15KHz subcarrier spacing
N = prmLTE.N;
cpLen0 = prmLTE.cpLen0;
cpLenR = prmLTE.cpLenR;
slotLen = (N*7 + cpLen0 + cpLenR*6);    % N=1024代表一个OFDM符号包含1024个采样时长,slotLen表示一个时隙总采样点
subframeLen = slotLen*2;                % 一个时隙的采样点数:共slotLen*2个采样周期Ts
tmp = complex(zeros(N, numSymb, numLayers));
% Pack data, add DC, and reorder 打包数据、添加DC、重新排序     注意:每个
tmp(N/2-len/2+1:N/2, :, :) = in(1:len/2, :, :);         %tmp(213:512,:,:)从213行开始有值了
tmp(N/2+2:N/2+1+len/2, :, :) = in(len/2+1:len, :, :);   %tmp(514:813,:,:)
tmp = [tmp(N/2+1:N, :, :); tmp(1:N/2, :, :)];   % tmp=[tmp(513:1024,:,:),tmp(1:512,:,:)]相当于把本来在中间的tmp(213:813)的值劈成两半放到了tmp的两头,并且颠倒了个
% IFFT processing
x = step(hIFFT, tmp);   % OFDM生成原理
x = x.*(N/sqrt(len));   % 这一步是干啥的,不理解???
% Add cyclic prefix per OFDM symbol per antenna port 加循环前缀的
% and serialize over the subframe (equal to 2 slots)
% For a subframe of data
y = complex(zeros(subframeLen, numLayers));
for j = 1:2 % Over the two slots 注意:这里的y将 x的1024*14的矩阵 变成了一个15360*1的比特流% First OFDM symboly((j-1)*slotLen+(1:cpLen0), :) = x((N-cpLen0+1):N, (j-1)*7+1, :); % y(1:80,:)=x(945:1024,1,:)  在j=1时,y的取值y((j-1)*slotLen+cpLen0+(1:N), :) = x(1:N, (j-1)*7+1, :);    % y(80:1104,:)=x(1:1024,1,:)% 通过简化这些符号,可以看出是如何加cp的了% Next 6 OFDM symbolsfor k = 1:6y((j-1)*slotLen+cpLen0+k*N+(k-1)*cpLenR+(1:cpLenR), :) = x(N-cpLenR+1:N, (j-1)*7+k+1, :);y((j-1)*slotLen+cpLen0+k*N+k*cpLenR+(1:N), :) = x(1:N, (j-1)*7+k+1, :);end
end

到此,发射端函数总结完全。

信道建模

例程1:ChanModelFading函数解读

comm.MIMOChannel系统对象

MIMO系统对通过多输入/多输出(MIMO)多径衰落信道过滤输入信号。该对象模拟了Rayleigh和Rician衰落,并采用Kronecker模型进行建模。

chanObj = comm.MIMOChannel(...'SampleRate', chanSRate, ...'MaximumDopplerShift', Doppler, ...'PathDelays', PathDelays,...'AveragePathGains', PathGains,...'TransmitCorrelationMatrix', eye(numTx),...'ReceiveCorrelationMatrix', eye(numRx),...'PathGainsOutputPort', false,...'NormalizePathGains', true,...'NormalizeChannelOutputs', true);

SampleRate 以赫兹为单位的输入信号样本频率,指定为正值

PathDelays 以秒为单位的离散路径延迟,指定为标量或行向量。

​ 将PathDelays设置为标量时,MIMO通道是频率平坦的。

​ 将PathDelays设置为矢量时,MIMO通道是频率选择性的。

​ PathDelays和averagepathgain属性的长度必须相同。

AveragePathGains 以分贝为单位的平均路径增益。“averagepath增益”和“PathDelays”属性的长度必须相同。

NormalizePathGains 1(ture)对衰落过程进行归一化,使路径增益的总功率(随时间平均)为0 dB。

​ 0 (false)路径增益的总功率没有归一化。averagepath增益属性指定路径增益的平均功率

FadingDistribution 衰落分布用于信道,指定为’瑞利’或’Rician’。

K-factor Rician衰落信道的k因子,指定为正标量或非负值的1 × np向量。

​ NP是由PathDelays属性指定的离散路径延迟数。当KFactor设置为标量或者矢量

DirectPathDopplerShift 直达信号的多普勒频移(多径Rician衰落上的信道),为标量或行向量。

​ 属性的大小必须与KFactor属性相同

​ 当此参数设置为标量时,表示直达信号的多普勒频移。呈现出一个Rician衰退过程

​ 当参数设置为行向量时,对应KFactor向量正值的各自路径(Rician衰落过程)

DirectPathInitialPhase 多径Rician衰落信道的视距分量的初始相位,指定为标量或行向量。单位是弧度。

​ 当参数设置为标量时,该值表示视距信号的初始相位。呈现出一个Rician衰退过程

​ 当参数设置为行向量时,描述了各自视距信号的初始相位(Rician衰落过程)

MaximumDopplerShift 所有信道路径的最大多普勒频移,非负标量。单位是Hz

​ 将此属性设置为0时,通道对于整个输入保持静态。

TransmitCorrelationMatrix 发射机的空间相关性,指定为NT-by-NT矩阵或NT-by-NT- np阵列。NT为发射天线数 属性设置为发射器单位阵I(仅针对该程序)

ReceiveCorrelationMatrix 属性设置为接收机单位阵I

PathGainsOutputPort 输出通道路径增益,指定为逻辑0 (false)或1 (true)。1为启用。

NormalizeChannelOutputs 信道输出归一化:1信道输出按接收天线的数量归一化。0 通道输出未归一化。

添加AWGN信道

根据SNR参数设置,为信号添加白噪声

% Add AWG noise
nVar = 10.^(0.1.*(-snrdB));
rxSig =  AWGNChannel(rxFade, nVar);

OFDM接收端建模_RX

发射端模型是接收端的逆过程,在该程序中,缺省了最开始的信号同步过程,原因是在发射端,省略了PSS、SSS、BCH等信号,由于从发射端到接收端信号开始时间是对齐的,因此该模型没有再进行时间同步。

在接收端,RX包括的模块有:时间同步与去CP,串并转化,FFT,并串转换,资源块重排,信道估计,频域均衡(软判决)、MQAM解调、LTE信道解码、利用CRC判断是否存在无码,并去除CRC得到数据。

OFDMRX

(该部分解读来自《全面详解LTE:MATLAB建模仿真与实现》)

我们将 OFDM 接收端处理视为发射端的反向操作。首先对每个子载波移除CP并进行FFT恢复接受信号和参考信号。根据信道带宽的不同使用不同的FFT 长度。通过合并缩放、重组、移除DC子载波,解包,接收的调制符号按发射端资源网格的顺序放置。

下面的MATLAB函数表现了OFDM接收端一系列操作。函数输入为接收端输入信号(in)和包含 PDSCH参数的结构(prmLTE)。输出为接收端复原的资源网格。

这部分代码首先去CP、再做FFT变换、然后重新排序、删除DC、解压数据。

function y = OFDMRx(in, prmLTE)
%#codegen
persistent hFFT;
if isempty(hFFT)hFFT = dsp.FFT;
end
% For a subframe of data
numDataTones = prmLTE.Nrb*prmLTE.Nrb_sc;        % 数据区每个OFDM符号占50*12个子载波
numSymb = prmLTE.Ndl_symb*2;                    % 一个子帧内共有14个OFDM符号
[~, numLayers] = size(in);
% N assumes 15KHz subcarrier spacing, else N = 4096
N = prmLTE.N;
cpLen0 = prmLTE.cpLen0;
cpLenR = prmLTE.cpLenR;
slotLen = (N*7 + cpLen0 + cpLenR*6);
tmp = complex(zeros(N, numSymb, numLayers));
% Remove CP - unequal lengths over a slot       % 首先是去掉CP 原理见《LTE教程:原理与实现》P135
for j = 1:2 % over two slots% First OFDM symboltmp(:, (j-1)*7+1, :) = in((j-1)*slotLen+cpLen0 + (1:N), :); %tmp(:,1,:)=in(81:1104,:)% Next 6 OFDM symbolsfor k = 1:6tmp(:, (j-1)*7+k+1, :) = in((j-1)*slotLen+cpLen0+k*N+k*cpLenR + (1:N), :);end
end
% FFT processing
x = step(hFFT, tmp);
x =  x./(N/sqrt(numDataTones));
% For a subframe of data
y = complex(zeros(numDataTones, numSymb, numLayers));
% Reorder, remove DC, Unpack data重新排序、删除DC、解压数据
x = [x(N/2+1:N, :, :); x(1:N/2, :, :)];
y(1:(numDataTones/2), :, :) = x(N/2-numDataTones/2+1:N/2, :, :);
y(numDataTones/2+1:numDataTones, :, :) = x(N/2+2:N/2+1+numDataTones/2, :, :);

资源元素反映射

资源元素反映射为资源网格映射的反向操作。下面的MATLAB函数表现了参考信号和数据如何在接收端从复原的资源网格中解压。

函数有三个输入∶

  • 接收资源网格(in)

  • 子帧索引(nS)

  • PDSCH参数设定

函数输出为

  • 用户数据(data)
  • 用户数据索引(idx_data)
  • CSR 信号(csr)
  • 可选的 DCI(pdcch)、PSS和SSS(pss,sss),以及BCH(bch)信号

不同的子帧包含不同的内容,第二个输入子帧索引参数(nS)可以让函数分离正确数据。资源映射函数的算法同样在反映射函数中用于生成索引。

function [data, csr, idx_data, pdcch, pss, sss, bch] = REdemapper_1Tx(in, nS, prmLTE)
%#codegen
% NcellID = 0;                                     % One of possible 504 values
% numTx = 1;                                      % prmLTE.numTx;
% Get input params
Nrb = prmLTE.Nrb;                              % either of {6, }
Nrb_sc = prmLTE.Nrb_sc;                 % 12 for normal mode
numContSymb    = prmLTE.contReg;  % either {1, 2, 3}
%% Specify resource grid location indices for CSR, PDCCH, PDSCH, PBCH, PSS, SSS
%% 1st: Indices for CSR pilot symbols
lenOFDM = Nrb*Nrb_sc;
idx            = 1:lenOFDM;
idx_csr0   = 1:6:lenOFDM;              % More general starting point = 1+mod(NcellID, 6);
idx_csr4   = 4:6:lenOFDM;              % More general starting point = 1+mod(3+NcellID, 6);
idx_csr     =[idx_csr0, 4*lenOFDM+idx_csr4, 7*lenOFDM+idx_csr0, 11*lenOFDM+idx_csr4];
%% 2nd: Indices for PDCCH control data symbols
ContREs=numContSymb*lenOFDM;
idx_dci=1:ContREs;
idx_pdcch = ExpungeFrom(idx_dci,idx_csr0);
%% 3rd: Indices for PDSCH and PDSCH data in OFDM symbols whee pilots are present
idx_data0= ExpungeFrom(idx,idx_csr0);
idx_data4 = ExpungeFrom(idx,idx_csr4);
%% Handle 3 types of subframes differently
pss=complex(zeros(72,1));
sss=complex(zeros(72,1));
bch=complex(zeros(72*4,1));
switch nS%% 4th: Indices for BCH, PSS, SSS are only found in specific subframes 0 and 5% Thsese symbols share the same 6 center sub-carrier locations (idx_ctr)% and differ in OFDM symbol number.case 0    % Subframe 0% PBCH, PSS, SSS are available + CSR, PDCCH, PDSCHidx_6rbs = (1:72);idx_ctr = 0.5* lenOFDM - 36 + idx_6rbs ;idx_SSS  = 5* lenOFDM + idx_ctr;idx_PSS  = 6* lenOFDM + idx_ctr;idx_ctr0 = ExpungeFrom(idx_ctr,idx_csr0);idx_bch=[7*lenOFDM + idx_ctr0, 8*lenOFDM + idx_ctr, 9*lenOFDM + idx_ctr, 10*lenOFDM + idx_ctr];idx_data5   = ExpungeFrom(idx,idx_ctr);idx_data7 = ExpungeFrom(idx_data0,idx_ctr);idx_data   = [ContREs+1:4*lenOFDM,   4*lenOFDM+idx_data4, ...5*lenOFDM+idx_data5, 6*lenOFDM+idx_data5,  7*lenOFDM+idx_data7, 8*lenOFDM+idx_data5, ...9*lenOFDM+idx_data5, 10*lenOFDM+idx_data5, 11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];pss=in(idx_PSS.');    % Primary Synchronization Signal (PSS)sss=in(idx_SSS.');     % Secondary Synchronization Signal (SSS)bch=in(idx_bch.');    % Broadcast Cahnnel data (BCH)case 10  % Subframe 5% PSS, SSS are available + CSR, PDCCH, PDSCH% Primary ans Secondary synchronization signals in OFDM symbols 5 and 6idx_6rbs = (1:72);idx_ctr = 0.5* lenOFDM - 36 + idx_6rbs ;idx_SSS  = 5* lenOFDM + idx_ctr;idx_PSS  = 6* lenOFDM + idx_ctr;idx_data5 = ExpungeFrom(idx,idx_ctr);idx_data   = [ContREs+1:4*lenOFDM, 4*lenOFDM+idx_data4,  5*lenOFDM+idx_data5, 6*lenOFDM+idx_data5, ...7*lenOFDM+idx_data0, 8*lenOFDM+1:11*lenOFDM,  11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];pss=in(idx_PSS.');     % Primary Synchronization Signal (PSS)sss=in(idx_SSS.');      % Secondary Synchronization Signal (SSS)otherwise % other subframes% Only CSR, PDCCH, PDSCHidx_data = [ContREs+1:4*lenOFDM, 4*lenOFDM+idx_data4, ...5*lenOFDM+1:7*lenOFDM, ...7*lenOFDM+idx_data0, ...8*lenOFDM+1:11*lenOFDM, ...11*lenOFDM+idx_data4, ...12*lenOFDM+1:14*lenOFDM];
end
idx_data=idx_data.';
data=in(idx_data);       % Physical Downlink Shared Channel (PDSCH) = user data
csr=in(idx_csr.');            % Cell-Specific Reference signal (CSR) = pilots
pdcch = in(idx_pdcch.');   % Physical Downlink Control Channel (PDCCH)

信道估计

信道估计即测量参考符号,或在OFDM时-频网格中间隙中插入的导频。使用已知参考符号,接收端可以在发送该参考符号的子载波上进行信道估计。参考符号应该在时域和频域有足够高的密度。如此,通过适当的展宽我们可以得到全部时-频网格的估计。

下面的MATLAB函数表现了单天线传输的信道估计。输入为包含PDSCH参数的结构(prmLTE)、接收的资源网格(Rx)、CSR(ref)和频带展宽模式(mode)。在对接收的资源网格进行整形之后,接收信号按CSR内相应的导频信号进行排列。我们随后用接收到的发射参考信号计算信道相应矩阵(hD)的估计。之后通过计算所有按CSR信号排列的资源元素的信道相应矩阵,我们得到全频带展宽的结果。基于资源网格中参考信号的子集,我们可以通过对全部资源网格求信道估计的平均或内插值得到展宽结果;这一过程在每一个子载波和每一个子帧的OFDM符号上进行。

function hD = ChanEstimate_1Tx(prmLTE, Rx, Ref, Mode)
%#codegen
Nrb           = prmLTE.Nrb;     % Number of resource blocks
Nrb_sc      = prmLTE.Nrb_sc;                 % 12 for normal mode
Ndl_symb = prmLTE.Ndl_symb;        % 7    for normal mode
% Assume same number of Tx and Rx antennas = 1
% Initialize output buffer
hD = complex(zeros(Nrb*Nrb_sc, Ndl_symb*2));
% Estimate channel based on CSR - per antenna port基于CSR -估计每个天线端口的信道
csrRx = reshape(Rx, numel(Rx)/4, 4); % Align received pilots with reference pilots将接收到的导频与参考导频对齐
hp      = csrRx./Ref;                % Just divide received pilot by reference pilot只需将接收导频除以参考导频
% to obtain channel response at pilot locations 为了获取在导频处的信道响应
% Now use some form of averaging/interpolation/repeating to
% compute channel response for the whole grid 使用不同方法获取无线环境状态
% Choose one of 3 estimation methods "average" or "interpolate" or "hybrid"
switch Modecase 'average'hD=gridResponse_averageSubframe(hp, Nrb, Nrb_sc, Ndl_symb);case 'interpolate'hD=gridResponse_interpolate(hp, Nrb, Nrb_sc, Ndl_symb);case 'hybrid'hD=gridResponse_averageSlot(hp, Nrb, Nrb_sc, Ndl_symb);otherwiseerror('Choose the right mode for function ChanEstimate.');
end
end

gridResponse_interpolate典型内插算法

典型内插算法针对含有CSR信号(子帧0、5、7和12)OFDM符号频域上的两个子载波。通过计算特定符号的所有子载波信道相应,我们可以内插找到整个网格的信道相应。下面的MATLAB函数(gridResponse_interpolate)进行基于内插的展宽算法。

function hD=gridResponse_interpolate(hp, Nrb, Nrb_sc, Ndl_symb)
% Average over the two same Freq subcarriers, and then interpolate between
% them - get all estimates and then repeat over all columns (symbols).
% The interpolation assmues NCellID = 0.
% Time average two pilots over the slots, then interpolate (F)
% between the 4 averaged values, repeat for all symbols in sframe
hD = complex(zeros(Nrb*Nrb_sc, Ndl_symb*2));
N=size(hp,2);
Separation=6;
Edges=[0,5;3,2;0,5;3,2];
Symbol=[1,5,8,12];
% First: Compute channel response over all resource elements of OFDM symbols 0,4,7,11
for n=1:NEdge=Edges(n,:);y = InterpolateCsr(hp(:,n),  Separation, Edge);hD(:,Symbol(n))=y;
end
% Second: Interpolate between OFDM symbols {0,4} {4,7}, {7, 11}, {11, 13}
for m=[2, 3, 4, 6, 7]alpha=0.25*(m-1);beta=1-alpha;hD(:,m)    = beta*hD(:,1) + alpha*hD(:,  5);hD(:,m+7) =beta*hD(:,8) + alpha*hD(:,12);
end

典型的平均算法

典型的平均算法在含有CSR信号(子帧0、5、7和12)OFDM符号频域上的两个子载波间进行内插。首先我们从开始两个 OFDM符号(子帧0和5)上合并CSR信号。不同于在两个CSR信号间间隔六个子载波,这一过程使两个CSR 间隔三个子载波。随后我们在频轴进行内插。最后我们对时隙或子帧上OFDM 符号用相同的信道响应寻找全体网格的信道响应。下面的MATLAB函数(gridResponse_averageSubframe)展示了这一过程。

function hD=gridResponse_averageSubframe(hp, Nrb, Nrb_sc, Ndl_symb)
% Average over the two same Freq subcarriers, and then interpolate between
% them - get all estimates and then repeat over all columns (symbols).
% The interpolation assmues NCellID = 0.
% Time average two pilots over the slots, then interpolate (F)
% between the 4 averaged values, repeat for all symbols in sframe
h1_a1 = mean([hp(:, 1), hp(:, 3)],2);
h1_a2 = mean([hp(:, 2), hp(:, 4)],2);
h1_a_mat = [h1_a1 h1_a2].';
h1_a = h1_a_mat(:);
h1_all = complex(zeros(length(h1_a)*3,1));
for i = 1:length(h1_a)-1delta = (h1_a(i+1)-h1_a(i))/3;h1_all((i-1)*3+1) = h1_a(i);h1_all((i-1)*3+2) = h1_a(i)+delta;h1_all((i-1)*3+3) = h1_a(i)+2*delta;
end
% fill the last three - use the last delta
h1_all(end-2) = h1_a(end);
h1_all(end-1) = h1_a(end)+delta;
h1_all(end) = h1_a(end)+2*delta;
% Compute the channel response over the whole grid by repeating
hD = h1_all(1:Nrb*Nrb_sc, ones(1, Ndl_symb*2));
end

均衡器增益计算

一个频域均衡器对所有每个子载波接收的资源元素计算增益。频域均衡有不同的算法。最简单的为ZF算法,它通过发射资源元素和每个子载波信道估计的比值得到增益。更加复杂一些的算法为 MMSE 估计,它基于更复杂的信道时/频特性理论计算包含非相关性信道噪声的比值得到增益。当得到均衡器增益之后,通过接收资源元素和均衡器增益的乘积即可得到资源元素的最优估计。下面的MATLAB函数中,用户可通过选择均衡模式参数选择使用ZF或MMSE均衡器。

function [out, Eq]  = Equalizer(in, hD, nVar, EqMode)
%#codegen
switch EqModecase 1,Eq = ( conj(hD))./((conj(hD).*hD));            % Zero forcingcase 2,Eq = ( conj(hD))./((conj(hD).*hD)+nVar);  % MMSEotherwise,error('Two equalization mode vaible: Zero forcing or MMSE');
end
out=in.*Eq;

信道可视化_结果图

通过可视化函数zVisualize可以在matlab直观的展示仿真的实际结果。

(完)

程序阅读_全面详解LTE_MATLAB建模仿真与实现_自学笔记(2)OFDM_程序阅读相关推荐

  1. 频率和波特率_实例详解 | 变频器端子启停与通信设定频率(附程序)

    PLC控制变频器时经常碰到需要频繁修改频率,只能选择用PLC通信来给定频率,在通过数字输出Q点来控制变频器启停正反转,从而实现PLC自动控制.在此我们以CPU ST30和V20变频器为例来讲解.硬件连 ...

  2. 程序阅读_全面详解LTE:MATLAB建模仿真与实现_自学笔记(1)调制与编码_程序阅读

    程序阅读_全面详解LTE:MATLAB建模仿真与实现_自学笔记(1)调制与编码_程序阅读 在粗浅地掌握了LTE知识后,从今天开始对<全面详解LTE:MATLAB建模仿真与实现>一书的学习. ...

  3. python如何制作脚本_用python给自己做一款小说阅读器过程详解

    前言 前一段时间书荒的时候,在喜马拉雅APP发现一个主播播讲的小说-大王饶命.听起来感觉很好笑,挺有意思的,但是只有前200张是免费的,后面就要收费.一章两毛钱,本来是想要买一下,发现说的进度比较慢而 ...

  4. [论文阅读] (06) 万字详解什么是生成对抗网络GAN?经典论文及案例普及

    <娜璋带你读论文>系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢.由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正,非常欢迎大家给我留言评论,学 ...

  5. Android 应用程序之间内容分享详解(二)

    转载请注明出处:http://blog.csdn.net/xiaanming/article/details/9428613 Android 应用程序之间内容分享详解(一) 之前给大家分享了你开发的应 ...

  6. 微信小程序02【配置详解、生命周期-app对象使用、页面跳转详解】

    学习地址:https://www.bilibili.com/video/BV1sx411z77P 笔记01:https://blog.csdn.net/weixin_44949135/article/ ...

  7. 百度提前批-百度智能小程序(面经详解)

    文章目录 百度提前批-百度智能小程序(面经详解) 1.定位 2.z-index .层叠 3.作用域(scope) 4.单例模式 5.原型链 6.继承(借用构造函数,寄生组合继承,缺点是什么) 7.闭包 ...

  8. php小程序onload,微信小程序 loading 组件实例详解

    这篇文章主要介绍了微信小程序 loading 组件实例详解的相关资料,需要的朋友可以参考下 loading通常使用在请求网络数据时的一种方式,通过hidden属性设置显示与否 主要属性: wxml 显 ...

  9. java程序的界面编程详解

    java程序的界面编程详解 在Java中可以为程序自定义程序界面选择Windows.Unix.Java或Macintosh外观.甚至可以在程序运行时让用户自由的选择外观. UIManager和Swin ...

最新文章

  1. PostgreSQL 使用 pgbench 测试 sysbench 相关case
  2. 谷歌二季度净利同比增211%,英特尔降17%,两个公司盘后股价都大涨
  3. android x86一键安装,安卓
  4. Redis常用命令之操作Set(集合)
  5. 解决WebBrowser控件会导致应用程序占用内存居高不下问题
  6. 与Maven 3,Failsafe和Cargo插件的集成测试
  7. Jupyter Notebook的15个技巧和窍门,可简化您的编码体验
  8. 11月25号站立会议
  9. php new static 效率,对比 PHP 中 new static() 与 new self()
  10. java servlet init方法_Java HttpServlet.init方法代码示例
  11. 【[Offer收割]编程练习赛10 C】区间价值
  12. 从 ASCII 到 UTF-8 : 大话编码
  13. free mybatis 不生效_Mybatis非空判断没有生效
  14. 谷歌大脑全新软件能让马赛克样模糊人脸变清晰
  15. [车联网安全自学篇] Android安全之Android中常用权限手册「必备」
  16. [云原生专题-4]:云平台 - 在阿里云平台快速搭建服务器集群
  17. Appium+Python使用-模拟手机按键操作
  18. pdf文件太大怎么压缩?四个步骤完成
  19. yml文件中、<<、 * 是什么意思
  20. [Revit教程]斑马:如何自学Revit#S002

热门文章

  1. 这家国产FPGA换道超车!强攻5G和AI市场!
  2. Android视频编辑器(三)给本地视频加水印和美颜滤镜
  3. 小程序之日历(状态版)
  4. flex 的 三个参数:flex-grow、flex-shrink、flex-basis
  5. “哥伦布”华为,与智能联接新大陆
  6. Java游戏项目之王者荣耀
  7. Unity初级项目实战:官方宇宙飞机大战游戏(一)
  8. 走位神器大全排行榜,你们是什么级别的关羽哥?
  9. [翻译] 在 LaTeX 中对齐公式
  10. matlab tic toc 分段计时,Python模仿matlab的tic/toc计时