基于MATLAB实现的OFDM仿真调制解调,BPSK、QPSK、4QAM、16QAM、32QAM,加性高斯白噪声信道、TDL瑞利衰落信道

基于MATLAB实现的OFDM仿真调制解调,BPSK、QPSK、4QAM、16QAM、32QAM,加性高斯白噪声信道、TDL瑞利衰落信道

相关链接

OFDM中的帧(frame)、符号(symbol)、子载波(subcarriers)、导频(Pilot)、保护间隔(guard)的关系图解以及代码详解–MATLAB

【学习笔记】OFDM的原理和技术介绍以及仿真结果分析附代码–MATLAB

1 加性高斯白噪声信道

在本程序中,通过MATLAB仿真了OFDM的发射、信道、接收解调的过程。支持的BPSK、QPSK、多种QAM的解调方式,并计算了不同信噪比下的误比特率。高斯白噪声信道下,不需要信道估计和信道均衡,但是在衰落信道中必须要信道估计或信道均衡,或者两个都使用,才能正确的解调。以下在衰落信道中的解调只实现了信道均衡。

1.1 BPSK和QSPK

%-----------------------仿真OFDM---------------------------%
%% 设置参数
clear;clc;
Nk = 128; % 子载波个数
Nfft = 128; % fft长度
Nframe = 6; % 一帧中有几个OFDM符号M = 2; % 调制符号所含比特(改为1:BPSK,2:QPSK)
SR = 250000; % 符号速率
BR = SR .* M; % 比特率
NGI = 32; % 保护间隔长度
EbN0s = 0:1:12; % 信噪比
Nsym = Nfft + NGI; % 系统长度
bers = zeros(1, length(EbN0s));
fprintf('EbN0 \t \t ber\t\t\t per\t\t\t nloop \t\t \n');
%% 函数主体for kk = 1:length(EbN0s)% rng('default')          % 初始化随机种子EbN0 = EbN0s(kk);nloop = 10000; % 发送多少帧n_biterror = 0; % 错误的数据n_bitdata = 0; % 一共发送了多少数据n_packeterror = 0; % 有多少错误帧n_packetdata = 0; % 发送了多少帧for ii = 1:nloop% 生成一帧数据,串并转换,并QPSK,生成一帧frame_FDserial = randi([0 1], 1, Nk * Nframe * M);% 发送的是bitframe_FDparallel = reshape(frame_FDserial, Nk, Nframe * M); % 串并转换if M==1frame_mod = BPSKMod(frame_FDparallel, Nk, Nframe); % BPSK调制elseif M==2frame_mod = QPSKMod(frame_FDparallel, Nk, Nframe); % QPSK调制end% IFFTpower_FT = sum(abs(frame_mod(:)).^2) / (Nk * Nframe);% 计算下IFFT前的能量,FT表示频域frame_mod_shift = ifftshift(frame_mod); % 频域归零frame_ifft = ifft(frame_mod_shift, Nfft); % ifftpower_TD = sum(sum(abs(frame_ifft).^2)) / Nk / Nframe; % 计算下IFFT前的能量,DT表示时域% 添加保护间隔frame_withGI = AddGI(frame_ifft, Nfft, NGI, Nframe, "CP"); % 添加保护间隔% 并串转换frame_TDserial = reshape(frame_withGI, 1, Nsym * Nframe);x = 1:1:160;% 加性白高斯噪声信道         power_TDserial = sum(abs(frame_TDserial).^2) / length(frame_TDserial); % 计算发送序列的能量EsN0 = EbN0 + 10 * log10(M); % 根据信噪比计算Es/N0(dB)噪声能量,幅值,然后加在信号上N0 = power_TDserial / (10^(EsN0 / 10));noise_msg = sqrt(N0 / 2) .* (randn(size(frame_TDserial)) + 1i * randn(size(frame_TDserial)));frame_recieved = frame_TDserial + noise_msg;% 接收端,串并转换frame_recieved_parallel = reshape(frame_recieved, Nsym, Nframe);% 去GIframe_noGI = RemoveGI(frame_recieved_parallel, Nfft, NGI);% FFTframe_recieved_FD_shift = fft(frame_noGI, Nfft);frame_recieved_FD = fftshift(frame_recieved_FD_shift);if M==1% BPSK解调frame_demod = BPSKDemod(frame_recieved_FD, Nk, Nframe);elseif M==2% QPSK解调frame_demod = QPSKDemod(frame_recieved_FD, Nk, Nframe);end% 并串转换frame_output = reshape(frame_demod, 1, Nk * Nframe * M);% 计算errorn_biterror_tmp = sum(abs(frame_output - frame_FDserial));n_bitdata_tmp = length(frame_FDserial);n_biterror = n_biterror + n_biterror_tmp;n_bitdata = n_bitdata + n_bitdata_tmp;if n_biterror_tmp ~= 0n_packeterror = n_packeterror + 1;endn_packetdata = n_packetdata + 1;end% 计算在当前信噪比下的误码率per = n_packeterror / n_packetdata;ber = n_biterror / n_bitdata;bers(kk) = ber;fprintf('%f\t%e\t%e\t%d\t\n', EbN0, ber, per, nloop);
endsemilogy(EbN0s, bers, '-+');
xlabel('比特信噪比');
ylabel('误码率');
title('不同信噪比下误码率仿真曲线');
if M==1legend('BPSK实验曲线');
elselegend('QPSK实验曲线');
endfunction outs = QPSKMod(input_data,nk,nframe,m)
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*M)
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% m: 调制数
% 输出
% outs: (nk,nframe),输出a+bi
% out_coss:(nk,nframe),输出实部
% out_sins:(nk,nframe),输出虚部if nargin < 4                   % 设置默认值m = 2;
endouts = zeros(nk,nframe);    % 初始化
out_cos = zeros(nk,nframe);
out_sin = zeros(nk,nframe);input_data_pn = 2*input_data - 1;     % 把0,1映射到-1,1
A = 1/sqrt(2);                        % 归一化幅值out_cos((1:nk),(1:nframe)) = input_data_pn((1:nk), (1:2:2*nframe-1)) .* A;    % 每次使用两列
out_sin((1:nk),(1:nframe)) = input_data_pn((1:nk), ((2:2:2*nframe))) .* A;outs = out_cos + out_sin * 1j;
endfunction outputs = QPSKDemod(input_data,nk,nframe)
% 输入
% input_data: (Nk, Nframe), 一个频域的复数,会被拆开解调
% nk: 频域并联
% nframe: 一帧包含符号数
% 输出
% outputs:(Nk, 2*Nframe), 解调后,多出一倍,全是01
outputs = zeros(nk,2*nframe);
A = 1/sqrt(2); 
input_data = input_data ./ A;
outputs((1:nk),(1:2:2*nframe-1)) = real(input_data((1:nk),(1:nframe)))>=0;
outputs((1:nk),(2:2:2*nframe)) = imag(input_data((1:nk),(1:nframe)))>=0;endfunction outs = BPSKMod(input_data,nk,nframe,m)
% BPSK调制函数
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*M)
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% m: 调制数,默认值为1
% 输出
% outs: (nk,nframe),输出复数
A = 1/sqrt(2);    % 归一化幅值
outs = input_data * 2 - 1;  % 将二进制0/1映射为复数-1/1
outs = A * outs;  % 乘以归一化幅值
endfunction outputs = BPSKDemod(input_data,nk,nframe)
% BPSK解调函数
% 输入
% input_data: (Nk, Nframe), 一个频域的复数
% nk: 频域并联
% nframe: 一帧包含符号数
% 输出
% outputs:(Nk, Nframe), 解调后的二进制数据
outputs = real(input_data) >= 0;  % 判断实部是否大于等于0,大于等于0表示1,小于0表示0
endfunction output_TD = AddGI(input_TD, nfft, nGI, nframe, type_GI)
if type_GI=="CP"    % 实现CPoutput_TD = [input_TD(nfft-nGI+1:nfft, :); input_TD(1:nfft, :)];
elseif type_GI=="ZP" % 实现ZPoutput_TD = [zeros(nGI,nframe); input_TD(1:nfft, :)];
end
end
function output_TD = RemoveGI(input_TD,nfft,nGI)
% 输入
% input_TD: (Nsym,Nframe)输入的并联时域数据
% nfft:fft长度
% nGI: GI长度
% 输出
% output_TD: (Nfft,Nframe)去掉GI后的并联时域数据output_TD = input_TD(nGI+1:nfft+nGI,:);
end

在这里插入图片描述

1.2 QAM

M = 16; % 调制符号所含比特(改为4:4QAM,16:16QAM,32:32QAM)

%% 设置参数
clear;clc;
Nk = 128; % 子载波个数
Nfft = 128; % fft长度
Nframe = 6; % 一帧中有几个OFDM符号
M = 16; % 调制符号所含比特(改为4:4QAM,16:16QAM,32:32QAM)
SR = 250000; % 符号速率
BR = SR * log2(M); % 比特率(根据调制方式计算比特率)
NGI = 32; % 保护间隔长度
EbN0s = 0:1:12; % 信噪比
Nsym = Nfft + NGI; % 系统长度
bers = zeros(1, length(EbN0s));
fprintf('EbN0 \t \t ber\t\t\t per\t\t\t nloop \t\t \n');
%% 函数主体for kk = 1:length(EbN0s)% rng('default')          % 初始化随机种子EbN0 = EbN0s(kk);nloop = 10000; % 发送多少帧n_biterror = 0; % 错误的数据n_bitdata = 0; % 一共发送了多少数据n_packeterror = 0; % 有多少错误帧n_packetdata = 0; % 发送了多少帧for ii = 1:nloop% 生成一帧数据,串并转换,并QPSK,生成一帧frame_FDserial = randi([0 1], 1, Nk * Nframe * log2(M));% 发送的是bit(根据M修改生成的比特数)frame_FDparallel = reshape(frame_FDserial, Nk, Nframe * log2(M)); % 串并转换frame_mod = QAMMod(frame_FDparallel, Nk, Nframe, M); %调制(改为QAM调制)% IFFTpower_FT = sum(abs(frame_mod(:)).^2) / (Nk * Nframe);% 计算下IFFT前的能量,FT表示频域frame_mod_shift = ifftshift(frame_mod); % 频域归零frame_ifft = ifft(frame_mod_shift, Nfft); % ifftpower_TD = sum(sum(abs(frame_ifft).^2)) / Nk / Nframe; % 计算下IFFT前的能量,DT表示时域% 添加保护间隔frame_withGI = AddGI(frame_ifft, Nfft, NGI, Nframe, "CP"); % 添加保护间隔% 并串转换frame_TDserial = reshape(frame_withGI, 1, Nsym * Nframe* log2(M));x = 1:1:160;% Channel         power_TDserial = sum(abs(frame_TDserial).^2) / length(frame_TDserial); % 计算发送序列的能量EsN0 = EbN0 + 10 * log10(log2(M)); % 根据信噪比计算Es/N0(dB)噪声能量,幅值,然后加在信号上N0 = power_TDserial / (10^(EsN0 / 10));noise_msg = sqrt(N0 / 2) .* (randn(size(frame_TDserial)) + 1i * randn(size(frame_TDserial)));frame_recieved = frame_TDserial + noise_msg;% 接收端,串并转换frame_recieved_parallel = reshape(frame_recieved, Nsym, Nframe* log2(M));% 去GIframe_noGI = RemoveGI(frame_recieved_parallel, Nfft, NGI);% FFTframe_recieved_FD_shift = fft(frame_noGI, Nfft);frame_recieved_FD = fftshift(frame_recieved_FD_shift);% QPSK解调frame_demod = QAMDemod(frame_recieved_FD, Nk, Nframe, M); %改为QAM解调% 并串转换frame_output = reshape(frame_demod, 1, Nk * Nframe * log2(M)); %修改输出比特数% 计算errorn_biterror_tmp = sum(abs(frame_output - frame_FDserial));n_bitdata_tmp = length(frame_FDserial);n_biterror = n_biterror + n_biterror_tmp;n_bitdata = n_bitdata + n_bitdata_tmp;if n_biterror_tmp ~= 0n_packeterror = n_packeterror + 1;endn_packetdata = n_packetdata + 1;end% 计算在当前信噪比下的误码率per = n_packeterror / n_packetdata;ber = n_biterror / n_bitdata;bers(kk) = ber;fprintf('%f\t%e\t%e\t%d\t\n', EbN0, ber, per, nloop);
endsemilogy(EbN0s, bers, '-+');
xlabel('比特信噪比');
ylabel('误码率');
title('不同信噪比下误码率仿真曲线');
legend(strcat(num2str(M),'QAM实验曲线'));function outs = QAMMod(input_data,nk,nframe,M)
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*log2(M))
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% M: 调制数
% 输出
% outs: (nk,nframe),输出a+bi
% out_coss:(nk,nframe),输出实部
% out_sins:(nk,nframe),输出虚部if nargin < 4                   % 设置默认值M = 4; % 默认为4QAM
end% 将输入二进制数据映射成QAM符号
symbols = qammod(input_data, M);% 将QAM符号按照OFDM格式进行串并转换
outs = reshape(symbols, nk, nframe* log2(M));
endfunction outputs = QAMDemod(input_data,nk,nframe,M)
% 输入
% input_data: (Nk, Nframe), 一个频域的复数,会被拆开解调
% nk: 频域并联
% nframe: 一帧包含符号数
% M: 调制数
% 输出
% outputs:(Nk, Nframe*log2(M)), 解调后的比特流if nargin < 4                   % 设置默认值M = 4; % 默认为4QAM
end% 将输入QAM符号按照OFDM格式进行并串转换
symbols = input_data(:);% 将QAM符号解调为二进制比特流
outputs = qamdemod(symbols, M);
endfunction output_TD = AddGI(input_TD, nfft, nGI, nframe, type_GI)
if type_GI=="CP"    % 实现CPoutput_TD = [input_TD(nfft-nGI+1:nfft, :); input_TD(1:nfft, :)];
elseif type_GI=="ZP" % 实现ZPoutput_TD = [zeros(nGI,nframe); input_TD(1:nfft, :)];
end
endfunction output_TD = RemoveGI(input_TD,nfft,nGI)
% 输入
% input_TD: (Nsym,Nframe)输入的并联时域数据
% nfft:fft长度
% nGI: GI长度
% 输出
% output_TD: (Nfft,Nframe)去掉GI后的并联时域数据output_TD = input_TD(nGI+1:nfft+nGI,:);
end

在这里插入图片描述

2 瑞利衰落信道之TDL信道

时延抽头延迟线(TDL,Tap Delay Line)信道是一种简化的多径模型,用于表示无线通道在特定延迟时间内的衰减特性。该模型通过一系列的时变复数增益,也称为"抽头"来表示信号经不同路径传播后的相位变化和衰减。在给定的TDL模型中,每个抽头都对应着一个特定的时延和相应的平均功率衰减。

信道的数学模型可以表示为:
y ( t ) = ∑ i = 1 N h i ⋅ x ( t − τ i ) + n ( t ) y(t) = \sum_{i=1}^{N} h_i \cdot x(t - \tau_i) + n(t) y(t)=i=1Nhix(tτi)+n(t)

其中,

  • ( y(t) ) 是接收信号,
  • ( x(t) ) 是发送信号,
  • ( h_i ) 是第 ( i ) 个抽头的复数增益,反映了信号在抽头 ( i ) 上的衰减和相位变化 h i h_i hi 取以 $ h_i = \sqrt{\text{PowerTDL}_i} \cdot \text{Rayleigh fading factor}$,并且 ( h ) 数组中的非零位置由TDL抽头的时延决定,则 $\text{Delay}[i]+1) = h_i $
  • $ \tau_i$ 是第 i 个抽头的时间延迟,
  • N是总抽头数,
  • n(t) 是添加到通道输出的高斯白噪声。

在给定的信道模型中,PowerTDL_dB定义了各抽头的平均功率衰减,单位为分贝(dB),Delay数组定义了各抽头相对于首个抽头的时延,单位为符号周期。这两个数组被用来计算PowerTDL,即各抽头的功率,并转换为线性单位。通过这些值,以及Rayleigh衰减模型,可以生成模拟多径效应的复数信道响应。

2.1 BPSK和QPSK

%% 设置参数
clear;clc;
Nk = 128;           % 子载波个数
Nfft = 128;          % fft长度
Nframe = 6;         % 一帧中有几个OFDM符号
M = 1;              % 调制符号所含比特
SR = 250000;        % 符号速率
BR = SR .* M;       % 比特率
NGI = 32;           % 保护间隔长度
EbN0s = 0:2:20;      % 信噪比
Nsym = Nfft+NGI;    % 系统长度
bers = zeros(1,length(EbN0s));  % 误码率储存数组
PowerTDL_dB = [0 -8 -17 -21 -25];   % TDL中信道抽头的功率,dB为单位
Delay = [0 3 5 6 8];                % TDL中信道时延
PowerTDL = 10.^(PowerTDL_dB/10);    % TDL中信道抽头的功率
Nchannel=length(PowerTDL_dB);       % 信道抽头数
Tau_maxTDL = Delay(end)+1;          % 最大时延除以帧长,就是归一化的最大时延
fprintf('EbN0 \t \t ber\t\t\t per\t\t\t nloop \t\t \n');
%% 函数主体for kk = 1:length(EbN0s)% rng('default')          % 初始化随机种子EbN0 = EbN0s(kk);nloop = 10000;          % 发送多少帧n_biterror = 0;         % 错误的数据n_bitdata = 0;          % 一共发送了多少数据n_packeterror = 0;      % 有多少错误帧n_packetdata = 0;       % 发送了多少帧for ii = 1:nloop
%--------------------------发射端-------------------------------%% 生成一帧数据,串并转换,并QPSK,生成一帧frame_FDserial = randi([0 1], 1, Nk * Nframe * M);% 发送的是bitframe_FDparallel = reshape(frame_FDserial,Nk,Nframe*M);% 串并转换if M==1frame_mod = BPSKMod(frame_FDparallel, Nk, Nframe); % BPSK调制elseif M==2frame_mod = QPSKMod(frame_FDparallel, Nk, Nframe); % QPSK调制end% IFFTpower_FT = sum(sum(abs(frame_mod).^2))/Nk/Nframe;  % 计算下IFFT前的能量,FT表示频域frame_mod_shift = ifftshift(frame_mod);         % 频域归零frame_ifft = ifft(frame_mod_shift, Nfft);             % ifft% frame_ifft = ifft(frame_mod, Nfft);power_TD = sum(sum(abs(frame_ifft).^2))/Nk/Nframe; % 计算下IFFT前的能量,DT表示时域% 添加保护间隔frame_withGI = AddGI(frame_ifft, Nfft, NGI, Nframe, "CP");  % 添加保护间隔% 并串转换frame_TDserial = reshape(frame_withGI,1,Nsym*Nframe);
%--------------------------Channel-------------------------------%% 信号先经历衰落channel = Rayleigh_model(Nchannel, PowerTDL);h = zeros(1, Tau_maxTDL);h(Delay+1) = channel;frame_conv = conv(frame_TDserial, h);frame_fading = frame_conv(:,1:length(frame_TDserial));        % 看似是线性卷积,实际上由于CP变成了循环卷积% 添加高斯白噪声power_TDserial = sum(abs(frame_TDserial).^2)/Nk/Nframe;     EsN0 = EbN0 + 10*log10(M);                                  % 根据信噪比计算噪声能量,幅值,然后加在信号上N0 = power_TDserial .* 10.^(-EsN0/10);noise_msg = sqrt(N0 / 2) .* (randn(size(frame_TDserial)) + 1j * randn(size(frame_TDserial)));frame_recieved = frame_fading + noise_msg;
%--------------------------接收端-------------------------------%% 接收端,串并转换frame_recieved_parallel = reshape(frame_recieved,Nsym,Nframe);% 去GIframe_noGI = RemoveGI(frame_recieved_parallel, Nfft, NGI);% FFTframe_recieved_FD_shift = fft(frame_noGI, Nfft);frame_recieved_FD = fftshift(frame_recieved_FD_shift);% 信道均衡H = fftshift(fft([h zeros(1, Nfft-Tau_maxTDL)].', Nfft));frame_equalization = frame_recieved_FD ./ repmat(H, 1, Nframe);if M==1% BPSK解调frame_demod = BPSKDemod(frame_equalization, Nk, Nframe);elseif M==2% QPSK解调frame_demod = QPSKDemod(frame_equalization, Nk, Nframe);end% 并串转换frame_output = reshape(frame_demod, 1, Nk*Nframe*M);% 计算errorn_biterror_tmp = sum(abs(frame_output-frame_FDserial));n_bitdata_tmp = length(frame_FDserial);n_biterror = n_biterror + n_biterror_tmp;n_bitdata = n_bitdata + n_bitdata_tmp;if n_biterror_tmp ~= 0n_packeterror = n_packeterror + 1;endn_packetdata = n_packetdata + 1;end% 计算在当前信噪比下的误码率per = n_packeterror/n_packetdata;ber = n_biterror/n_bitdata;bers(kk)=ber;fprintf('%f\t%e\t%e\t%d\t\n',EbN0,ber,per,nloop);
end
%% 画图
semilogy(EbN0s,bers,'-+');
xlabel('比特信噪比');
ylabel('误码率');
title('不同信噪比下误码率仿真曲线');
% legend('理论曲线','实验曲线');
if M==1legend('BPSK实验曲线');
elselegend('QPSK实验曲线');
endfunction outs = QPSKMod(input_data,nk,nframe,m)
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*M)
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% m: 调制数
% 输出
% outs: (nk,nframe),输出a+bi
% out_coss:(nk,nframe),输出实部
% out_sins:(nk,nframe),输出虚部if nargin < 4                   % 设置默认值m = 2;
endouts = zeros(nk,nframe);    % 初始化
out_cos = zeros(nk,nframe);
out_sin = zeros(nk,nframe);input_data_pn = 2*input_data - 1;     %01映射到-11
A = 1/sqrt(2);                        % 归一化幅值out_cos((1:nk),(1:nframe)) = input_data_pn((1:nk), (1:2:2*nframe-1)) .* A;    % 每次使用两列
out_sin((1:nk),(1:nframe)) = input_data_pn((1:nk), ((2:2:2*nframe))) .* A;outs = out_cos + out_sin * 1j;
endfunction outputs = QPSKDemod(input_data,nk,nframe)
% 输入
% input_data: (Nk, Nframe), 一个频域的复数,会被拆开解调
% nk: 频域并联
% nframe: 一帧包含符号数
% 输出
% outputs:(Nk, 2*Nframe), 解调后,多出一倍,全是01
outputs = zeros(nk,2*nframe);
A = 1/sqrt(2); 
input_data = input_data ./ A;
outputs((1:nk),(1:2:2*nframe-1)) = real(input_data((1:nk),(1:nframe)))>=0;
outputs((1:nk),(2:2:2*nframe)) = imag(input_data((1:nk),(1:nframe)))>=0;endfunction outs = BPSKMod(input_data,nk,nframe,m)
% BPSK调制函数
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*M)
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% m: 调制数,默认值为1
% 输出
% outs: (nk,nframe),输出复数
A = 1/sqrt(2);    % 归一化幅值
outs = input_data * 2 - 1;  % 将二进制0/1映射为复数-1/1
outs = A * outs;  % 乘以归一化幅值
endfunction outputs = BPSKDemod(input_data,nk,nframe)
% BPSK解调函数
% 输入
% input_data: (Nk, Nframe), 一个频域的复数
% nk: 频域并联
% nframe: 一帧包含符号数
% 输出
% outputs:(Nk, Nframe), 解调后的二进制数据
outputs = real(input_data) >= 0;  % 判断实部是否大于等于0,大于等于0表示1,小于0表示0
end
function output_TD = AddGI(input_TD, nfft, nGI, nframe, type_GI)
if type_GI=="CP"    % 实现CPoutput_TD = [input_TD(nfft-nGI+1:nfft, :); input_TD(1:nfft, :)];
elseif type_GI=="ZP" % 实现ZPoutput_TD = [zeros(nGI,nframe); input_TD(1:nfft, :)];
end
endfunction output_TD = RemoveGI(input_TD,nfft,nGI)
% 输入
% input_TD: (Nsym,Nframe)输入的并联时域数据
% nfft:fft长度
% nGI: GI长度
% 输出
% output_TD: (Nfft,Nframe)去掉GI后的并联时域数据output_TD = input_TD(nGI+1:nfft+nGI,:);
end
function H=Rayleigh_model(nchannel, power_channel)
% 瑞利衰落信道
% 输入
% nchannel: 多径信道的个数
% power_channel:(1, nchannel),每一个信道的功率
% 输出
% H:(1, nchannel),一个瑞利信道,符合高斯分布的nchannel个随机数,代表着衰落
H = (randn(1,nchannel)+1j*randn(1,nchannel)).*sqrt(power_channel/2);
% 功率除以二的原因是瑞利分布的E(x^2)=2\sigma^2
end

在这里插入图片描述

2.2 QAM

%% 设置参数
clear;clc;
Nk = 128; % 子载波个数
Nfft = 128; % fft长度
Nframe = 6; % 一帧中有几个OFDM符号
M = 4; % 调制符号所含比特(改为4:4QAM,16:16QAM,32:32:QAM)
SR = 250000; % 符号速率
BR = SR * log2(M); % 比特率(根据调制方式计算比特率)
NGI = 32; % 保护间隔长度
EbN0s = 0:1:12; % 信噪比
Nsym = Nfft + NGI; % 系统长度
bers = zeros(1, length(EbN0s));PowerTDL_dB = [0 -8 -17 -21 -25];   % TDL中信道抽头的功率,dB为单位
Delay = [0 3 5 6 8];                % TDL中信道时延
PowerTDL = 10.^(PowerTDL_dB/10);    % TDL中信道抽头的功率
Nchannel=length(PowerTDL_dB);       % 信道抽头数
Tau_maxTDL = Delay(end)+1;          % 最大时延除以帧长,就是归一化的最大时延
fprintf('EbN0 \t \t ber\t\t\t per\t\t\t nloop \t\t \n');
%% 函数主体for kk = 1:length(EbN0s)% rng('default')          % 初始化随机种子EbN0 = EbN0s(kk);nloop = 10000; % 发送多少帧n_biterror = 0; % 错误的数据n_bitdata = 0; % 一共发送了多少数据n_packeterror = 0; % 有多少错误帧n_packetdata = 0; % 发送了多少帧for ii = 1:nloop% 生成一帧数据,串并转换,并QPSK,生成一帧frame_FDserial = randi([0 1], 1, Nk * Nframe * log2(M));% 发送的是bit(根据M修改生成的比特数)frame_FDparallel = reshape(frame_FDserial, Nk, Nframe * log2(M)); % 串并转换frame_mod = QAMMod(frame_FDparallel, Nk, Nframe, M); %调制(改为QAM调制)% IFFTpower_FT = sum(abs(frame_mod(:)).^2) / (Nk * Nframe);% 计算下IFFT前的能量,FT表示频域frame_mod_shift = ifftshift(frame_mod); % 频域归零frame_ifft = ifft(frame_mod_shift, Nfft); % ifftpower_TD = sum(sum(abs(frame_ifft).^2)) / Nk / Nframe; % 计算下IFFT前的能量,DT表示时域% 添加保护间隔frame_withGI = AddGI(frame_ifft, Nfft, NGI, Nframe, "CP"); % 添加保护间隔% 并串转换frame_TDserial = reshape(frame_withGI, 1, Nsym * Nframe* log2(M));% Channel         channel = Rayleigh_model(Nchannel, PowerTDL);h = zeros(1, Tau_maxTDL);h(Delay+1) = channel;frame_conv = conv(frame_TDserial, h);frame_fading = frame_conv(:,1:length(frame_TDserial));        % 看似是线性卷积,实际上由于CP变成了循环卷积% 添加高斯白噪声power_TDserial = sum(abs(frame_TDserial).^2)/Nk/Nframe;     EsN0 = EbN0 + 10*log10(M);                                  % 根据信噪比计算噪声能量,幅值,然后加在信号上N0 = power_TDserial .* 10.^(-EsN0/10);noise_msg = sqrt(N0 / 2) .* (randn(size(frame_TDserial)) + 1j * randn(size(frame_TDserial)));frame_recieved = frame_fading + noise_msg;% 接收端,串并转换frame_recieved_parallel = reshape(frame_recieved, Nsym, Nframe* log2(M));% 去GIframe_noGI = RemoveGI(frame_recieved_parallel, Nfft, NGI);% FFTframe_recieved_FD_shift = fft(frame_noGI, Nfft);frame_recieved_FD = fftshift(frame_recieved_FD_shift);% 信道均衡H = fftshift(fft([h zeros(1, Nfft-Tau_maxTDL)].', Nfft));frame_equalization = frame_recieved_FD ./ repmat(H, 1, Nframe* log2(M));% QPSK解调frame_demod = QAMDemod(frame_equalization, Nk, Nframe, M); %改为QAM解调% 并串转换frame_output = reshape(frame_demod, 1, Nk * Nframe * log2(M)); %修改输出比特数% 计算errorn_biterror_tmp = sum(abs(frame_output - frame_FDserial));n_bitdata_tmp = length(frame_FDserial);n_biterror = n_biterror + n_biterror_tmp;n_bitdata = n_bitdata + n_bitdata_tmp;if n_biterror_tmp ~= 0n_packeterror = n_packeterror + 1;endn_packetdata = n_packetdata + 1;end% 计算在当前信噪比下的误码率per = n_packeterror / n_packetdata;ber = n_biterror / n_bitdata;bers(kk) = ber;fprintf('%f\t%e\t%e\t%d\t\n', EbN0, ber, per, nloop);
endsemilogy(EbN0s, bers, '-+');
xlabel('比特信噪比');
ylabel('误码率');
title('不同信噪比下误码率仿真曲线');
legend(strcat(num2str(M),'QAM实验曲线'));function outs = QAMMod(input_data,nk,nframe,M)
% 输入
% input_data: 待数字调制的输入数据(Nk,Nframe*log2(M))
% nk: 子载波个数,也就是并联个数
% nframe: 一帧中包含多少OFDM符号
% M: 调制数
% 输出
% outs: (nk,nframe),输出a+bi
% out_coss:(nk,nframe),输出实部
% out_sins:(nk,nframe),输出虚部if nargin < 4                   % 设置默认值M = 4; % 默认为4QAM
end% 将输入二进制数据映射成QAM符号
symbols = qammod(input_data, M);% 将QAM符号按照OFDM格式进行串并转换
outs = reshape(symbols, nk, nframe* log2(M));
endfunction outputs = QAMDemod(input_data,nk,nframe,M)
% 输入
% input_data: (Nk, Nframe), 一个频域的复数,会被拆开解调
% nk: 频域并联
% nframe: 一帧包含符号数
% M: 调制数
% 输出
% outputs:(Nk, Nframe*log2(M)), 解调后的比特流if nargin < 4                   % 设置默认值M = 4; % 默认为4QAM
end% 将输入QAM符号按照OFDM格式进行并串转换
symbols = input_data(:);% 将QAM符号解调为二进制比特流
outputs = qamdemod(symbols, M);
endfunction output_TD = AddGI(input_TD, nfft, nGI, nframe, type_GI)
if type_GI=="CP"    % 实现CPoutput_TD = [input_TD(nfft-nGI+1:nfft, :); input_TD(1:nfft, :)];
elseif type_GI=="ZP" % 实现ZPoutput_TD = [zeros(nGI,nframe); input_TD(1:nfft, :)];
end
end
function output_TD = RemoveGI(input_TD,nfft,nGI)
% 输入
% input_TD: (Nsym,Nframe)输入的并联时域数据
% nfft:fft长度
% nGI: GI长度
% 输出
% output_TD: (Nfft,Nframe)去掉GI后的并联时域数据output_TD = input_TD(nGI+1:nfft+nGI,:);
end
function H=Rayleigh_model(nchannel, power_channel)
% 瑞利衰落信道
% 输入
% nchannel: 多径信道的个数
% power_channel:(1, nchannel),每一个信道的功率
% 输出
% H:(1, nchannel),一个瑞利信道,符合高斯分布的nchannel个随机数,代表着衰落
H = (randn(1,nchannel)+1j*randn(1,nchannel)).*sqrt(power_channel/2);
% 功率除以二的原因是瑞利分布的E(x^2)=2\sigma^2
end

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/669281.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库管理-第144期 深入使用EMCC-01(20240204)

数据库管理144期 2024-02-04 数据库管理-第144期 深入使用EMCC-01&#xff08;20240204&#xff09;1 用户管理2 配置告警动作3 配置意外事件规则总结 数据库管理-第144期 深入使用EMCC-01&#xff08;20240204&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&am…

大创项目推荐 题目:基于深度学习的人脸表情识别 - 卷积神经网络 大创项目推荐 代码

文章目录 0 简介1 项目说明2 数据集介绍&#xff1a;3 思路分析及代码实现3.1 数据可视化3.2 数据分离3.3 数据可视化3.4 在pytorch下创建数据集3.4.1 创建data-label对照表3.4.2 重写Dataset类3.4.3 数据集的使用 4 网络模型搭建4.1 训练模型4.2 模型的保存与加载 5 相关源码6…

vscode1.86无法远程连接waiting the server log

问题 vscode升级到最新的1.86版本后&#xff0c;无法远程连接服务器Remote SSH&#xff0c;在log中提示如下&#xff1a; 观察下面的log提示可得&#xff1a; glibc的版本好像不符合vscode1.86版本的要求。你可以在你的服务器上运行下面的指令查看glibc的版本&#xff1a; …

【计算机网络】物理层概述|通信基础|奈氏准则|香农定理|信道复用技术

目录 一、思维导图 二、 物理层概述 1.物理层概述 2.四大特性&#xff08;巧记"械气功程") 三、通信基础 1.数据通信基础 2.趁热打铁☞习题训练 3.信号の变身&#xff1a;编码与调制 4.极限数据传输率 5.趁热打铁☞习题训练 6.信道复用技术 推荐 前些天发…

服务器端会话技术-Session

一、Session 1.1 概述和快速入门 概述&#xff1a;Session 是服务器端会话技术&#xff0c;在一次会话的多次请求间共享数据&#xff0c;将数据保存在服务器端的对象中 快速入门 获取 HttpSession 对象使用 HttpSession 对象 常用方法 方法作用HttpSession request.getSe…

图像处理常用算法介绍

此篇简单回顾下图像处理领域常用到的一些算法&#xff0c;这边只对每个知识点重要的点做一些记录&#xff0c;便于快速的知其形&#xff0c;会其意。 一. SIFT&#xff08;Scale-Invariant feature transform)特征 重点是了解DOG(Difference of Gaussian)高斯差分图像是如何生…

ubuntu离线安装k8s

目录 一、前期准备 二、安装前配置 三、安装docker 四、安装cri-dockerd 五、部署k8s master节点 六、整合kubectl与cri-dockerd 七、网络等插件安装 八、常见问题及解决方法 一、前期准备 ①ubuntu系统 本地已安装ubuntu系统&#xff0c;lsb_release -a命令查看版本信…

2024网络安全学习路线,最全保姆级教程,学完直接拿捏!

关键词&#xff1a; 网络安全入门、渗透测试学习、零基础学安全、网络安全学习路线 首先咱们聊聊&#xff0c;学习网络安全方向通常会有哪些问题 前排提示&#xff1a;文末有CSDN独家网络安全资料包&#xff01; 1、打基础时间太长 学基础花费很长时间&#xff0c;光语言都…

Windows10安装PCL1.14.0及点云配准

一、下载visual studio2022 下载网址&#xff1a;Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft.com) 安装的时候选择"使用C的桌面开发“&#xff0c;同时可以修改文件路径&#xff0c;可以放在D盘。修改文件路径的时候&#xff0c;共享组件、…

Open CASCADE学习|拉伸

目录 1、沿方向拉伸 2、沿路径拉伸 3、变形拉伸 1、沿方向拉伸 #include <Geom_CylindricalSurface.hxx> #include <gp_Ax3.hxx> #include <GeomAPI_Interpolate.hxx> #include <BRepAdaptor_Curve.hxx> #include <BRepBuilderAPI_MakeEdge.hxx&…

追觅发布多款旗舰新品,双机械臂扫地机器人X40领衔登场

2月2日&#xff0c;追觅科技全球首创仿生“双”机械臂新品发布会在苏州举行。会上&#xff0c;追觅科技中国区总裁郭人杰分享了追觅科技全球化发展的业绩成果。郭人杰称&#xff0c;2019-2023年&#xff0c;追觅科技5年复合年增长率超过100%&#xff0c;增速领跑智能清洁行业&a…

LeetCode、746. 使用最小花费爬楼梯【简单,动态规划 线性DP】

文章目录 前言LeetCode、746. 使用最小花费爬楼梯【简单&#xff0c;动态规划 线性DP】题目与分类思路 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。…

python的进程,线程、协程

python进程的实现 #coding:utf-8 from multiprocessing import Process import timedef run(name):print(%s is running % name)time.sleep(3)print(%s finished his run % name)if __name__ __main__:p Process(targetrun, args(XWenXiang,)) # 创建一个进程对象p.start()…

Redis(十二)Bigkey

文章目录 游标案例生成100万测试数据key生产上限制keys */flushdb/flushall等危险命令不使用keys *&#xff1a;scan Biigkey案例多大算大发现bigkey渐进式删除生产调优示例问题 游标案例 生成100万测试数据key shell: for((i1;i<100*10000;i)); do echo "set k$i v…

Nicn的刷题日常之调整奇数偶数顺序

目录 1.题目描述 2.解题思路 3.解题 1.题目描述 输入一个整数数组&#xff0c;实现一个函数&#xff0c; 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c; 所有偶数位于数组的后半部分。 2.解题思路 1. 给定两个下标left和right&#xff…

手拉手spring-boot-starter-mail实现发送QQ邮箱

技术栈 springbootmybatis-plusmysql 软件 版本 IDEA IntelliJ IDEA 2022.2.1 JDK 17 Spring Boot 3.1 mybatis-plus 3.5 spring-boot-starter-mail Springboot版本 spring boot对mail的封装支持非常好&#xff0c;方便&#xff0c;几行代码就可以把邮件集成进来…

调用Gensim库训练Word2Vec模型

一、前期工作&#xff1a; 1. 安装Gensim库 pip install gensim 2.安装chardet库 pip install chardet 3. 对原始语料分词 选择《人民的名义》的小说原文作为语料&#xff0c;先采用jieba进行分词 import jieba import jieba.analyse import chardet jieba.suggest_freq…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(三)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第六章&#xff1a;决策树 决策树是多功能的机器学习算法&#xff0c;可以执行分类和回归任务&#xff0c;甚至多输出任务。它们…

麻雀搜索算法|Sparrow Search Algorithm(SSA)

在麻雀群体智慧、觅食和反捕食行为的启发下&#xff0c;提出了一种新的群体优化方法&#xff0c;即麻雀搜索算法&#xff08;SSA&#xff09;。 1、简介 在麻雀搜索算法中包含三种类型的麻雀个体&#xff0c;即发现者、跟随者和侦察者&#xff0c;三种类型对应三种行为。发现…

GM8775C——DSI 转双通道 LVDS 发送器

1 产品概述 GM8775C 型 DSI 转双通道 LVDS 发送器产品主要实现将 MIPI DSI 转单 / 双通道 LVDS 功能&#xff0c; MIPI 支持 1/2/3/4 通道可选&#xff0c;每通道最高支持 1Gbps 速率&#xff0c;最大支持 4Gbps 速率。 LVDS 时钟频率高达 154MHz &#xff…