当前位置: 首页 > news >正文

基于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

在这里插入图片描述

相关文章:

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

基于MATLAB实现的OFDM仿真调制解调&#xff0c;BPSK、QPSK、4QAM、16QAM、32QAM&#xff0c;加性高斯白噪声信道、TDL瑞利衰落信道 相关链接 OFDM中的帧&#xff08;frame&#xff09;、符号&#xff08;symbol&#xff09;、子载波&#xff08;subcarriers&#xff09;、导频…...

Redis核心技术与实战【学习笔记】 - 21.Redis实现分布式锁

概述 在《20.Redis原子操作》我们提到了应对并发问题时&#xff0c;除了原子操作&#xff0c;还可以通过加锁的方式&#xff0c;来控制并发写操作对共享数据的修改&#xff0c;从而保证数据的正确性。 但是&#xff0c;Redis 属于分布式系统&#xff0c;当有多个客户端需要争…...

17.Golang channel的基本定义及使用

目录 概述实践无缓冲 channel代码结果 缓冲 channel代码结果 channel的关闭特点代码结果range代码结果 select channel代码结果 结束 概述 此篇文章介绍 channel 的用法 无缓冲 channel缓冲 channelchannel的关闭特点range channelselect channel 每一种&#xff0c;配上完整…...

Linux - iptables 防火墙

一. 安全技术和防火墙 1.安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全…...

如何在FBX剔除Lit.shader依赖

1&#xff09;如何在FBX剔除Lit.shader依赖 2&#xff09;Unity出AAB包&#xff08;PlayAssetDelivery&#xff09;模式下加载资源过慢问题 3&#xff09;如何在URP中正确打出Shader变体 4&#xff09;XLua打包Lua文件粒度问题 这是第371篇UWA技术知识分享的推送&#xff0c;精…...

cesium-测量高度垂直距离

cesium做垂直测量 完整代码 <template><div id"cesiumContainer" style"height: 100vh;"></div><div id"toolbar" style"position: fixed;top:20px;left:220px;"><el-breadcrumb><el-breadcrumb-i…...

Adobe Illustrator CEP插件开发入门指南

引言 Adobe Creative Cloud&#xff08;创意云&#xff09;中的Illustrator作为一款全球领先的矢量图形设计软件&#xff0c;为设计师提供了丰富的功能和无限的创作可能性。为了进一步增强其功能并满足个性化工作流程需求&#xff0c;Adobe引入了Common Extensibility Platform…...

【Spring】自定义注解 + AOP 记录用户的使用日志

目录 ​编辑 自定义注解 AOP 记录用户的使用日志 使用背景 落地实践 一&#xff1a;自定义注解 二&#xff1a;切面配置 三&#xff1a;Api层使用 使用效果 自定义注解 AOP 记录用户的使用日志 使用背景 &#xff08;1&#xff09;在学校项目中&#xff0c;安防平台…...

linux互斥锁:递归锁,非递归锁用法详解

在实际的项目中经常涉及到共享资源,共享资源被多个线程访问会出现竞争现象;为了解决竞争和保护共享资源常用的机制之一就是互斥锁! 互斥锁又分为递归锁和非递归锁,互斥锁默认是非递归锁,也是我们常用的上锁方式。那么什么是递归锁和非递归锁呢? 非递归锁(Non-recursive …...

MacOS安装dmg提示已文件已损坏的解决方法

MacOS安装dmg提示已文件已损坏的解决方法 导致原因是应用没有上传到苹果的appstroe&#xff0c;系统限制了安装&#xff0c;破碎提示是苹果的误导小手段 方法 一 App 在macOS Catalina&#xff08;比较新的系统&#xff0c;例如m1&#xff0c;m2也适用&#xff09;下提示已损坏…...

前端输入框简单实现检测@成员输入

大体逻辑是 给input框添加一个input监听&#xff0c;并判断输入是否为获取当前光标的位置&#xff0c;你输入的肯定在光标之前&#xff0c;且肯定是最后一个input输入的内容换行可以被认为空格&#xff0c;需要进行全局替换判断成功的逻辑分为两部分&#xff0c;前方一般来说是…...

通过与chatGPT交流实现零样本事件抽取

1、写作动机&#xff1a; 近来的大规模语言模型&#xff08;例如Chat GPT&#xff09;在零样本设置下取得了很好的表现&#xff0c;这启发作者探索基于提示的方法来解决零样本IE任务。 2、主要贡献&#xff1a; 提出了基于chatgpt的多阶段的信息抽取方法&#xff1a;在第一阶…...

使用nodejs和html布局一个简单的视频播放网站,但是使用localhost:端口访问html无法加载视频

js代码&#xff1a; // app.js const express require(express); const path require(path); const app express();// 设置静态文件目录&#xff0c;这里假设你的视频文件在public/videos/目录下 app.use(express.static(path.join(__dirname, )));// 设置主页路由&#xf…...

【AG32VF407】国产MCU+FPGA Verilog双边沿检测输出方波

视频讲解 [AG32VF407]国产MCUFPGA Verilog双边沿检测输出方波 实验过程 本次使用使用AG32VF407开发板中的FPGA&#xff0c;使用双clk的双边沿进行检测&#xff0c;同步输出方波 同时可以根据输出的方波检测clk的频率&#xff0c;以及双clk的相位关系&#xff0c;如下为verilog…...

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--强化学习、模仿学习、机器人

专属领域论文订阅 关注{晓理紫}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起免费为3…...

为什么说TiDB在线扩容对业务几乎没有影响

作者&#xff1a; 数据源的TiDB学习之路 原文来源&#xff1a; https://tidb.net/blog/e82b2c5f 当前的数据库种类繁多&#xff0c;墨天轮当前统计的所有国产数据库已经有 290个 &#xff0c;其中属于关系型数据库的有 166个 。关系型数据库从部署架构上又可以分为集中式…...

STM32--SPI通信协议(2)W25Q64简介

一、W25Q64简介 1、W25Qxx中的xx是不同的数字&#xff0c;表示了这个芯片不同的存储容量&#xff1b; 2、存储器分为易失性与非易失性&#xff0c;主要区别是存储的数据是否是掉电不丢失&#xff1a; 易失性存储器&#xff1a;SRAM、DRAM&#xff1b; 非易失性存储器&#xff…...

svn安装与搭建

1、svn搭建 # yum install subversion -y //安装 # svnserve --version //查看版本 2、创建仓库目录repo # mkdir -p /opt/svn/repo //创建目录 # svnadmin create /opt/svn/repo/ //创建新仓库 # ls !$ …...

什么是缓存击穿、缓存穿透、缓存雪崩?

缓存雪崩 缓存雪崩是指缓存同一时间大面积的失效&#xff0c;所以&#xff0c;后面的请求都会落到数据库上&#xff0c;造成数据库短时间内承受大量请求而崩掉。 解决方案 缓存数据的过期时间设置随机&#xff0c;防止同一时间大量数据过期现象发生。一般并发量不是特别多的时…...

springboot153相亲网站

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...