基于OFDM系统的误码率仿真
正交频分复用技术(OFDM)是多载波调制技术之一,基本原理就是将传输信道分成若干个正交的子信道,将高速数据流转换成并行的低速子数据流,调制到每个子信道上进行传输。它可以利用快速傅里叶反变换(IFFT)和快速傅里叶变换(FFT)来完成数据的调制和解调。由于数据在子信道上传输的速率较低,在经过无线频率选择性衰落信道时,每个子信道都可以看成是平坦性衰落,只要进行适当的频率均衡就能够克服由衰落产生的影响。并且利用IFFT的周期循环特性,在每个传输符号之前相应的插入一定长度的保护间隔,就可以消除多径信道的影响,从而防止码间干扰。
本文决定选用OFDM系统来进行仿真系统的搭建,一是因为数字通信课上对OFDM调制解调原理进行过详细讲解,更容易继续深入学习;二是可以通过对OFDM系统仿真原理进行研究来加深对课程内容的理解。OFDM一般流程如下图所示。
图3-4 系统模块框图
由上图系统模块可知,输入数据流首先经串并转换,实现OFDM时频块的区分,而后经过星座映射和IFFT变换将频域信号转换为时域发射信号,最后增加循环前缀上变频后进行发射。接收机在下变频后进行相反操作,本文首先进行高斯白噪声信道下的仿真,不失一般性,本次仿真条件设置如下
表 仿真参数设置
参数 | 取值 |
系统子载波数 | 512 |
仿真帧数 | 100 |
每帧OFDM符号数 | 6 |
调制进制 | 4,16,64 |
循环前缀 | 16 |
循环后缀 | 16 |
信噪比 | 0-20dB |
FFT长度 | 64 |
在MATLAB设置上表中的仿真条件,利用程序产生随机电文,经系统框图中的串并转换、IFFT和FFT、星座映射和加循环前后缀的流程后,实现OFDM基本通信系统的搭建,本文首先考虑经过加性高斯白噪声信道,下图展示了OFDM发射信号的时域图和频域图,由下图可知,利用IFFT产生的OFDM信号的时域发射波形与多个载波叠加产生的子载波具有同样的效果,展示了理论分析的正确性。
(a) 时域波形 (b)频域波形
图 OFDM时频域图展示
接收机在下变频后,对接收信号进行去循环前缀和FFT变换,而后进行星座的映射,下图展示了接收机星座映射
(a) QPSK (b)16QAM
图 OFDM接收星座图
由上图可知,在接受信噪比为10dB的情况下,QPSK的接收星座图显然比16QAM星座图更加清晰,增加信号的调制阶数将会增大在接收端的误码率,下图展示了不同调制方式的误码率随信噪比变化趋势
图 不同调制方式下的误码率
由上图的变化趋势可知,随着调制方式的增大,误码率也逐渐增大,调制阶数过大时,无法满足通信误码率需求,因此需要对OFDM系统进行一定的改进,目前降低系统误码率的主要方式有:(1)插入导频,进行信道的估计与均衡;(2)增加扩频码,利用频率资源换取误码率的提升;(3)进行信道编码,利用卷积码进行实现一定的纠错功能。下图所示是OFDM系统更为复杂的收发机内部结构框图 :
图3-5 OFDM收发机结构框图
经过改进后的OFDM系统将具有一定的信道估计和均衡能力、纠错能力以及抗噪声干扰能力,下图展示了更新过程
|
(a)增加卷积码 (b)增加扩频码
(c)增加导频
图 OFDM系统更新流程
上图展示了16QAM调制方式下,依次增加卷加码、扩频码和导频后的误码率曲线,显然,随着增加不同方式进行改进,误码率有明显下降。其中,图(a)展示了增加信道编码后的误码率对比图,本文分别增加了(2,1,4)、(2,1,5)、(2,1,7)卷积码,卷积码的基本原理是增加各个符号间的耦合性,为有记忆编码,具备一定的纠错能力,从上图可以看出,增加编码的寄存器越长,性能越好,但相应的结构也就越复杂,下图展示了(2,1,3)卷积码的基本示意图
图 (2,1,3)卷积码示意图
图(b)展示了增加扩频码后的误码率对比图,扩频码的本质即用带宽资源去换取传输可靠性,其在扩频和解扩的过程中,对噪声有良好的抑制作用,本文展示了分别增加3阶和4阶m序列的效果,结果表明,增加扩频码可以进一步降低误码率,m序列阶数越高,抑制噪声的效果越好。不仅在通信领域,在导航领域,其还发挥加密和测距的作用,是目前导航系统的核心要素。
图(c)展示了增加信道估计后的误码率,从图中可以发现,增加导频进行信道估计可以进一步降低误码率,导频的基本原理是通过在数据码中混入导频序列,通过差值拟合的方式,估计信道响应并进行补偿和均衡,降低信道对信号传输的影响,下图展示了几种基本的导频插入方法
图 导频插入
基于OTFS系统的误码率仿真
上述对OFDM系统的性能分析中,信道建模较为简单,未考虑高速移动场景下的多普勒频移影响,但具有频率选择性衰落的信道更符合现实场景的建模与分析,为进一步分析OFDM调制的性能与不足,便于寻找改进方法与策略,本文接下来以高速移动场景为背景,增加如下表所示的仿真参数,利用jakes模型产生单径平坦型Rayleigh衰落信道。
表 仿真参数设置
参数 | 取值 |
相对速度 | 120 km/h |
子载波间隔 | 1.5 kHz |
系统带宽 | 10^3 kHz |
图 Rayleigh衰落信道仿真
第五代(5G)通信系统中使用的调制波形是基于正交频分复用(OFDM)的,在高移动性场景中,通信可靠性和数据速率会发生明显下降。与OFDM相比,正交时频空间(OTFS)调制对信道的多普勒频移具有鲁棒性。R. Hadani提出了一种新的调制方式——正交时频空间 (OTFS) 调制,其基本流程框架如下
图 OTFS基本流程
OTFS调制技术是在延迟多普勒域(Delay Dopler domain)而非传统的时频域(TF)对数据进行调制。依靠DD域的信号表示,它具有针对高动态和复杂环境的强大的多普勒抗性和延迟抗性的优点。通过从TF域到DD域的单元变换,可以实现所需的特性,如信号的可分离性、紧凑性、稳定性,以及可能的稀疏性。这些特性可被用于准确的信道估计和低训练开销以及低复杂度的信号检测。
图OTFS示意图
相较于OFDM系统,OTFS需要在发送和接收处各多加一个OTFS转换,来完成在多普勒-延时域和时频域之间的变换。如上图所示,利用DD域来调制信息,不同信号的区分更清楚,更适合高速运动场景下的通信。然而,核心的思路仍是类似的:在更易进行信号处理的域上装载信息。例如传统的OFDM系统,对于频选多径场景,直接在时域上进行信号处理将非常复杂。然而通过把信息装在在子载波上,由于每个子载波的平坦性,信号处理的难度将大幅降低。相较于OFDM,OTFS则将时变性也考虑在内。
图 OTFS性能对比
上图展示了OFDM和OTFS调制在相同环境参数的误码率对比,由上图可以发现,在高速移动场景下,OFDM误码率明显提高,OFDM难以适应高速移动场景。从上图中还可以看出,OTFS在高速移动场景中展示了比OFDM更好的误码率性能,且在增加编码后误码率有了明显降低,误码性能提升越50%。
总结来看,OTFS调制作为新型调制方式,在提升未来高速移动场景的传输可靠性方面具有可观的潜力,但同时,OTFS调制还有很多问题亟待解决,如信道估计和调制复杂度。目前OFDM系统广泛应用于5G通信,现有的OFDM系统在未来很长一段时间内仍然是主流调制方式。
OFDM MATLAB代码
%% OFDM通信系统演示模型
% Copyright 2023, NUDT
%
% nudt
%
% 说明:
% OFDM通信演示模型
%
% 输入:
% 无
% 输出:
% 无
%
% 原始作者:Tim Liu
% 建立日期:2023年11月20日
%
% 更新历史:
%
clear;
%--------------------------------------------------------------------------
% 定义仿真参数
%--------------------------------------------------------------------------
M = 16; % 调制阵列大小
k = log2(M); % 每个符号的比特数
cpSize = 0.07; % OFDM循环前缀大小
scs = 15e3; % 子载波间距,单位赫兹
Bw = 10e6; % 系统带宽,单位赫兹
ofdmSym = 14; % 每个子帧的OFDM符号数
EbNo = (-3:1:30)'; % 每比特能量与噪声功率之比的范围
velocity = 120; % 移动接收机相对于发送机的速度,单位千米/小时
codeRate = 2/4; % 使用的FEC编码效率
maxIterations = 25; % LDPC解码器的最大迭代次数
totalBits = 1e6; % 模拟的总比特数
repeats = 1; % 仿真重复次数
%--------------------------------------------------------------------------
% 初始化仿真组件
%--------------------------------------------------------------------------
% 初始化OFDM调制/解调变量
numSC = pow2(ceil(log2(Bw/scs))); % 计算最接近的2的幂的OFDM子载波数
cpLen = floor(cpSize * numSC); % 计算循环前缀长度
numDC = (numSC - 12); % 计算数据载波数
% 初始化AWGN信道
awgnChannel = comm.AWGNChannel('NoiseMethod','Variance', 'VarianceSource','Input port');
errorRate = comm.ErrorRate('ResetInputPort',true);
errorRate1 = comm.ErrorRate('ResetInputPort',true);
% 初始化LDPC编码器/解码器
parityCheck_matrix = dvbs2ldpc(codeRate);
ldpcEncoder = comm.LDPCEncoder(parityCheck_matrix);
ldpcDecoder = comm.LDPCDecoder(parityCheck_matrix);
ldpcDecoder.MaximumIterationCount = maxIterations;
noCodedbits = size(parityCheck_matrix,2);
% 创建用于存储误差数据的向量
berOFDM = zeros(length(EbNo),3);
berCOFDM = zeros(length(EbNo),3);
berOTFS = zeros(length(EbNo),3);
berCOTFS = zeros(length(EbNo),3);
errorStats_coded = zeros(1,3);
errorStats_uncoded = zeros(1,3);
for repetition=1:repeats % 使用每次不同信道重复仿真
% 生成和编码数据
[dataIn, dataBits_in, codedData_in, packetSize, numPackets, numCB] = dataGen(k,numDC,ofdmSym,totalBits,codeRate,ldpcEncoder);
% 生成瑞利衰落信道脉冲响应
txSig_size = zeros((numSC+cpLen),ofdmSym);
rayChan = multipathChannel(cpSize, scs, txSig_size, velocity);
% QAM调制
qamTx = qammod(dataIn,M,'InputType','bit','UnitAveragePower',true);
parallelTx = reshape(qamTx,[numDC,ofdmSym*packetSize]);
guardbandTx = [zeros(1,ofdmSym*packetSize); parallelTx];
guardbandTx = [guardbandTx(1:(numDC/2),:); zeros(11,ofdmSym*packetSize); guardbandTx((numDC/2)+1:end,:)];
%--------------------------------------------------------------------------
% OFDM误码率计算
%--------------------------------------------------------------------------
% 计算信噪比
snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC)));
% 多载波调制
frameBuffer = guardbandTx;
txframeBuffer = [];
for w = 1:packetSize
ofdmTx = modOFDM(frameBuffer(:,1:ofdmSym),numSC,cpLen,ofdmSym);
frameBuffer(:, 1:ofdmSym) = [];
txframeBuffer = [txframeBuffer;ofdmTx];
end
% 循环不同的EbNo值
for m = 1:length(EbNo)
% 循环传输的数据包
for j = 1:numPackets
rxframeBuffer = [];
% 逐个传输每个子帧
for u = 1:packetSize
txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) );
% 将信道应用到输入信号
% fadedSig1 = zeros(size(txSig));
% for i = 1:size(txSig,1)
% for j = 1:size(txSig,2)
% fadedSig1(i,j) = txSig(i,j).*rayChan(i,j);
% end
% end
fadedSig=txSig;
% AWGN信道
release(awgnChannel);
powerDB = 10*log10(var(fadedSig));
noiseVar = 10.^(0.1*(powerDB-snr(m)));
rxSig = awgnChannel(fadedSig,noiseVar);
% 均衡
eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym);
% 解调
rxSubframe = demodOFDM(eqSig,cpLen,ofdmSym);
rxframeBuffer = [rxframeBuffer';rxSubframe']';
end
parallelRx = rxframeBuffer;
parallelRx((numDC/2)+1:(numDC/2)+11, :) = [];
parallelRx(1:1, :) = [];
qamRx = reshape(parallelRx,[numel(parallelRx),1]);
dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);
codedData_out = randdeintrlv(dataOut,4831);
codedData_out(numel(codedData_in)+1:end) = [];
errorStats_uncoded = errorRate(codedData_in,codedData_out,0);
powerDB = 10*log10(var(qamRx));
noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC)))));
dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);
codedData_out1 = randdeintrlv(dataOut,4831);
codedData_out1(numel(codedData_in)+1:end) = [];
dataBits_out = [];
dataOut_buffer = codedData_out1;
for q = 1:numCB
dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))];
dataOut_buffer(1:noCodedbits) = [];
end
dataBits_out = double(dataBits_out);
errorStats_coded = errorRate1(dataBits_in,dataBits_out,0);
end
berOFDM(m,:) = errorStats_uncoded;
berCOFDM(m,:) = errorStats_coded;
errorStats_uncoded = errorRate(codedData_in,codedData_out,1);
errorStats_coded = errorRate1(dataBits_in,dataBits_out,1);
end
%--------------------------------------------------------------------------
% OTFS误码率计算
%--------------------------------------------------------------------------
% 计算信噪比
snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC))) + 10*log10(sqrt(ofdmSym));
% 多载波调制
frameBuffer = guardbandTx; % 创建一个“缓冲区”,以便可以单独调制子帧
txframeBuffer = []; % 初始化矩阵
for w = 1:packetSize
otfsTx = ISFFT(frameBuffer(:,1:ofdmSym)); % 对数据的子帧应用OTFS调制
ofdmTx = modOFDM(otfsTx,numSC,cpLen,ofdmSym); % 应用OFDM调制
frameBuffer(:, 1:ofdmSym) = []; % 从frameBuffer中删除调制后的数据
txframeBuffer = [txframeBuffer;ofdmTx]; % 将调制后的子帧添加到传输缓冲区
end
% 循环遍历不同的EbNo值
for m = 1:length(EbNo)
% 循环遍历要传输的数据包
for j = 1:numPackets
rxframeBuffer = []; % 初始化矩阵
% 单独传输每个子帧
for u = 1:packetSize
% 从传输缓冲区中移除下一个子帧
txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) );
% 将信道应用到输入信号
fadedSig = zeros(size(txSig)); % 预先分配向量大小
for i = 1:size(txSig,1) % 执行逐元素...
for j = 1:size(txSig,2) % ...矩阵乘法
fadedSig(i,j) = txSig(i,j).*rayChan(i,j);
end
end
fadedSig = txSig.*rayChan;
% AWGN信道
release(awgnChannel);
powerDB = 10*log10(var(fadedSig)); % 计算发送信号功率
noiseVar = 10.^(0.1*(powerDB-snr(m))); % 计算噪声方差
rxSig = awgnChannel(fadedSig,noiseVar); % 通过有噪声的信道传递信号
% 均衡
eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym);
% 解调
otfsRx = demodOFDM(eqSig,cpLen,ofdmSym); % 应用OFDM解调
rxSubframe = SFFT(otfsRx); % 应用OTFS解调
rxframeBuffer = [rxframeBuffer';rxSubframe']'; % 将解调后的子帧存储在rx缓冲区中
end
% 移除所有空载波
parallelRx = rxframeBuffer;
parallelRx((numDC/2)+1:(numDC/2)+11, :) = []; % 移除中心DC周围的空载波
parallelRx(1:1, :) = []; % 移除索引1处的空载波
qamRx = reshape(parallelRx,[numel(parallelRx),1]); % 转换为串行
% 对整个数据包进行无编码解调
dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);% 应用QAM解调
codedData_out = randdeintrlv(dataOut,4831); % 反交织数据
codedData_out(numel(codedData_in)+1:end) = []; % 移除填充位
errorStats_uncoded = errorRate(codedData_in,codedData_out,0); % 收集误码统计信息
% 对整个数据包进行编码解调
powerDB = 10*log10(var(qamRx)); % 计算接收信号功率
noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC))))); % 计算噪声方差
dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);% 应用QAM解调
codedData_out1 = randdeintrlv(dataOut,4831); % 反交织数据
codedData_out1(numel(codedData_in)+1:end) = []; % 移除填充位
% 解码各个码块
dataBits_out = []; % 初始化矩阵
dataOut_buffer = codedData_out1;
for q = 1:numCB
dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))]; % 解码数据并将其添加到数据位输出矩阵中
dataOut_buffer(1:noCodedbits) = []; % 从缓冲区中删除已解码的数据
end
dataBits_out = double(dataBits_out); % 转换为与errorStats兼容的double类型
errorStats_coded = errorRate1(dataBits_in,dataBits_out,0); % 收集误码统计信息
end
berOTFS(m,:) = errorStats_uncoded; % 保存无编码BER数据
berCOTFS(m,:) = errorStats_coded; % 保存编码BER数据
errorStats_uncoded = errorRate(codedData_in,codedData_out,1); % 重置误码率计算器
errorStats_coded = errorRate1(dataBits_in,dataBits_out,1); % 重置误码率计算器
end
end
%--------------------------------------------------------------------------
% 图表
%--------------------------------------------------------------------------
% 绘制BER / EbNo曲线
plotGraphs(berOFDM, berCOFDM, berOTFS, berCOTFS, M, numSC, EbNo);
OTFS MATLAB主代码
clear;
%--------------------------------------------------------------------------
% 定义仿真参数
%--------------------------------------------------------------------------
M = 16; % 调制阵列大小
k = log2(M); % 每个符号的比特数
cpSize = 0.07; % OFDM循环前缀大小
scs = 15e3; % 子载波间距,单位赫兹
Bw = 10e6; % 系统带宽,单位赫兹
ofdmSym = 14; % 每个子帧的OFDM符号数
EbNo = (-3:1:30)'; % 每比特能量与噪声功率之比的范围
velocity = 120; % 移动接收机相对于发送机的速度,单位千米/小时
codeRate = 2/4; % 使用的FEC编码效率
maxIterations = 25; % LDPC解码器的最大迭代次数
totalBits = 1e6; % 模拟的总比特数
repeats = 1; % 仿真重复次数
%--------------------------------------------------------------------------
% 初始化仿真组件
%--------------------------------------------------------------------------
% 初始化OFDM调制/解调变量
numSC = pow2(ceil(log2(Bw/scs))); % 计算最接近的2的幂的OFDM子载波数
cpLen = floor(cpSize * numSC); % 计算循环前缀长度
numDC = (numSC - 12); % 计算数据载波数
% 初始化AWGN信道
awgnChannel = comm.AWGNChannel('NoiseMethod','Variance', 'VarianceSource','Input port');
errorRate = comm.ErrorRate('ResetInputPort',true);
errorRate1 = comm.ErrorRate('ResetInputPort',true);
% 初始化LDPC编码器/解码器
parityCheck_matrix = dvbs2ldpc(codeRate);
ldpcEncoder = comm.LDPCEncoder(parityCheck_matrix);
ldpcDecoder = comm.LDPCDecoder(parityCheck_matrix);
ldpcDecoder.MaximumIterationCount = maxIterations;
noCodedbits = size(parityCheck_matrix,2);
% 创建用于存储误差数据的向量
berOFDM = zeros(length(EbNo),3);
berCOFDM = zeros(length(EbNo),3);
berOTFS = zeros(length(EbNo),3);
berCOTFS = zeros(length(EbNo),3);
errorStats_coded = zeros(1,3);
errorStats_uncoded = zeros(1,3);
for repetition=1:repeats % 使用每次不同信道重复仿真
% 生成和编码数据
[dataIn, dataBits_in, codedData_in, packetSize, numPackets, numCB] = dataGen(k,numDC,ofdmSym,totalBits,codeRate,ldpcEncoder);
% 生成瑞利衰落信道脉冲响应
txSig_size = zeros((numSC+cpLen),ofdmSym);
rayChan = multipathChannel(cpSize, scs, txSig_size, velocity);
% QAM调制
qamTx = qammod(dataIn,M,'InputType','bit','UnitAveragePower',true);
parallelTx = reshape(qamTx,[numDC,ofdmSym*packetSize]);
guardbandTx = [zeros(1,ofdmSym*packetSize); parallelTx];
guardbandTx = [guardbandTx(1:(numDC/2),:); zeros(11,ofdmSym*packetSize); guardbandTx((numDC/2)+1:end,:)];
%--------------------------------------------------------------------------
% OFDM误码率计算
%--------------------------------------------------------------------------
% 计算信噪比
snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC)));
% 多载波调制
frameBuffer = guardbandTx;
txframeBuffer = [];
for w = 1:packetSize
ofdmTx = modOFDM(frameBuffer(:,1:ofdmSym),numSC,cpLen,ofdmSym);
frameBuffer(:, 1:ofdmSym) = [];
txframeBuffer = [txframeBuffer;ofdmTx];
end
% 循环不同的EbNo值
for m = 1:length(EbNo)
% 循环传输的数据包
for j = 1:numPackets
rxframeBuffer = [];
% 逐个传输每个子帧
for u = 1:packetSize
txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) );
% 将信道应用到输入信号
% fadedSig1 = zeros(size(txSig));
% for i = 1:size(txSig,1)
% for j = 1:size(txSig,2)
% fadedSig1(i,j) = txSig(i,j).*rayChan(i,j);
% end
% end
fadedSig=txSig;
% AWGN信道
release(awgnChannel);
powerDB = 10*log10(var(fadedSig));
noiseVar = 10.^(0.1*(powerDB-snr(m)));
rxSig = awgnChannel(fadedSig,noiseVar);
% 均衡
eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym);
% 解调
rxSubframe = demodOFDM(eqSig,cpLen,ofdmSym);
rxframeBuffer = [rxframeBuffer';rxSubframe']';
end
parallelRx = rxframeBuffer;
parallelRx((numDC/2)+1:(numDC/2)+11, :) = [];
parallelRx(1:1, :) = [];
qamRx = reshape(parallelRx,[numel(parallelRx),1]);
dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);
codedData_out = randdeintrlv(dataOut,4831);
codedData_out(numel(codedData_in)+1:end) = [];
errorStats_uncoded = errorRate(codedData_in,codedData_out,0);
powerDB = 10*log10(var(qamRx));
noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC)))));
dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);
codedData_out1 = randdeintrlv(dataOut,4831);
codedData_out1(numel(codedData_in)+1:end) = [];
dataBits_out = [];
dataOut_buffer = codedData_out1;
for q = 1:numCB
dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))];
dataOut_buffer(1:noCodedbits) = [];
end
dataBits_out = double(dataBits_out);
errorStats_coded = errorRate1(dataBits_in,dataBits_out,0);
end
berOFDM(m,:) = errorStats_uncoded;
berCOFDM(m,:) = errorStats_coded;
errorStats_uncoded = errorRate(codedData_in,codedData_out,1);
errorStats_coded = errorRate1(dataBits_in,dataBits_out,1);
end
%--------------------------------------------------------------------------
% OTFS误码率计算
%--------------------------------------------------------------------------
% 计算信噪比
snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC))) + 10*log10(sqrt(ofdmSym));
% 多载波调制
frameBuffer = guardbandTx; % 创建一个“缓冲区”,以便可以单独调制子帧
txframeBuffer = []; % 初始化矩阵
for w = 1:packetSize
otfsTx = ISFFT(frameBuffer(:,1:ofdmSym)); % 对数据的子帧应用OTFS调制
ofdmTx = modOFDM(otfsTx,numSC,cpLen,ofdmSym); % 应用OFDM调制
frameBuffer(:, 1:ofdmSym) = []; % 从frameBuffer中删除调制后的数据
txframeBuffer = [txframeBuffer;ofdmTx]; % 将调制后的子帧添加到传输缓冲区
end
% 循环遍历不同的EbNo值
for m = 1:length(EbNo)
% 循环遍历要传输的数据包
for j = 1:numPackets
rxframeBuffer = []; % 初始化矩阵
% 单独传输每个子帧
for u = 1:packetSize
% 从传输缓冲区中移除下一个子帧
txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) );
% 将信道应用到输入信号
fadedSig = zeros(size(txSig)); % 预先分配向量大小
for i = 1:size(txSig,1) % 执行逐元素...
for j = 1:size(txSig,2) % ...矩阵乘法
fadedSig(i,j) = txSig(i,j).*rayChan(i,j);
end
end
fadedSig = txSig.*rayChan;
% AWGN信道
release(awgnChannel);
powerDB = 10*log10(var(fadedSig)); % 计算发送信号功率
noiseVar = 10.^(0.1*(powerDB-snr(m))); % 计算噪声方差
rxSig = awgnChannel(fadedSig,noiseVar); % 通过有噪声的信道传递信号
% 均衡
eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym);
% 解调
otfsRx = demodOFDM(eqSig,cpLen,ofdmSym); % 应用OFDM解调
rxSubframe = SFFT(otfsRx); % 应用OTFS解调
rxframeBuffer = [rxframeBuffer';rxSubframe']'; % 将解调后的子帧存储在rx缓冲区中
end
% 移除所有空载波
parallelRx = rxframeBuffer;
parallelRx((numDC/2)+1:(numDC/2)+11, :) = []; % 移除中心DC周围的空载波
parallelRx(1:1, :) = []; % 移除索引1处的空载波
qamRx = reshape(parallelRx,[numel(parallelRx),1]); % 转换为串行
% 对整个数据包进行无编码解调
dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);% 应用QAM解调
codedData_out = randdeintrlv(dataOut,4831); % 反交织数据
codedData_out(numel(codedData_in)+1:end) = []; % 移除填充位
errorStats_uncoded = errorRate(codedData_in,codedData_out,0); % 收集误码统计信息
% 对整个数据包进行编码解调
powerDB = 10*log10(var(qamRx)); % 计算接收信号功率
noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC))))); % 计算噪声方差
dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);% 应用QAM解调
codedData_out1 = randdeintrlv(dataOut,4831); % 反交织数据
codedData_out1(numel(codedData_in)+1:end) = []; % 移除填充位
% 解码各个码块
dataBits_out = []; % 初始化矩阵
dataOut_buffer = codedData_out1;
for q = 1:numCB
dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))]; % 解码数据并将其添加到数据位输出矩阵中
dataOut_buffer(1:noCodedbits) = []; % 从缓冲区中删除已解码的数据
end
dataBits_out = double(dataBits_out); % 转换为与errorStats兼容的double类型
errorStats_coded = errorRate1(dataBits_in,dataBits_out,0); % 收集误码统计信息
end
berOTFS(m,:) = errorStats_uncoded; % 保存无编码BER数据
berCOTFS(m,:) = errorStats_coded; % 保存编码BER数据
errorStats_uncoded = errorRate(codedData_in,codedData_out,1); % 重置误码率计算器
errorStats_coded = errorRate1(dataBits_in,dataBits_out,1); % 重置误码率计算器
end
end
%--------------------------------------------------------------------------
% 图表
%--------------------------------------------------------------------------
% 绘制BER / EbNo曲线
plotGraphs(berOFDM, berCOFDM, berOTFS, berCOTFS, M, numSC, EbNo);