OFDM通信连路仿真学习

文章目录

  • 前言
  • 一、前置知识
    • 1、块状导频与梳状导频
      • ①、相似点
      • ②、区别
      • ③、其他
    • 2、其他知识
  • 二、仿真任务及方案
    • 1、仿真任务
    • 2、仿真方案
  • 三、MATLAB仿真
    • 1、MATLAB 源码
    • 2、程序流程
    • 3、仿真结果
      • ①、打印信息
      • ③、8PSK 星座图
      • ②、脉冲成型图
      • ③、ETU300登加AWGN信道下误比特率曲线
  • 四、资源自取


前言

本文继续进行 OFDM 通信连路仿真学习。


一、前置知识

1、块状导频与梳状导频

块状导频也称为训练序列

在这里插入图片描述

①、相似点

  • 导频序列和训练序列的作用都是为了得到准确符号同步频偏纠正
  • 导频序列和训练序列都进行信道估计
  • 二者都传输已知数据;
  • 二者都可称之为基于辅助信息的信道估计方法;

②、区别

  • 添加位置不同:导频序列加在频域上,作用在频域。训练序列是在时域上添加的特定的序列;
  • 表现形式不同:导频序列表现为频谱上的一根线,散布在整个时频单元(在整个帧中是离散的)。训练序列表现为时域上的时间块,一个或多个连续的符号(集中在帧头并且连续)。
  • 要求不同:加在时域的训练序列要求有较强自相关性和弱互相关性。加在频域的导频序列无此要求。

③、其他

  • 同步信道(sync channel)的概念一般只在训练序列中涉及,对于导频来说似乎没有;
  • 导频的频率应当是与载频有关的或者就是载频的频率;
  • 块状导频就相当于训练序列;
  • 导频序列常用于载波同步,训练序列用于帧同步;
  • 二者都可进行信道估计,信道估计的目的是获得信道的一些参数,如频移、时延等。因此信道估计也称为信道参数估计。

2、其他知识

有关其他仿真细节原理知识可以参考我之前的博客:OFDM深入学习及MATLAB仿真

二、仿真任务及方案

1、仿真任务

  • 使用 Matlab 语言,仿真实现 OFDM 基带信号在频率选择性信道条件下的发送与接收。输入为随机比特流,经由 OFDM 调制、仿真信道传输、OFDM 解调后输出比特流,可计算不同信噪比条件下的误码率。其中子载波间隔 15KHz,循环前缀长度及子载波数目可调,各子载波使用 QPSK 调制。
  • 信道:信号经历 3GPP TS36.101 附录 B 中表 B.2.2-1 给出的ETU300 多径信道,随后叠加一个信噪比可调的 AWGN 信道。
    在这里插入图片描述
    在这里插入图片描述
  • 要求:能够查看并解释从输入到输出沿路各点信号的时域波形和频域特性图;能够绘制误码率随信噪比变化的曲线。
  • 设计梳状或块状导频并在接收端完成信道估计与补偿(即均衡)。

2、仿真方案

  • 本方案在满足以上要求的前提下,选用了块状导频;除了循环前缀长度及子载波数目可调外,可以通过改变 M 的值,选用 MPSK,且导频间隔与 OFDM 符号数可任意调整,并具有信道编码,交织,脉冲成型模块。
  • 仿真系统模块依次为:
    • 二进制基带数据生成,卷积码编码,交织,QPSK调制,串并转换,加入虚载波(补零,数目为 fft 点数减去子载波数),插入导频,IFFT,插入循环前缀,并串转换,脉冲成型(先上采样再通过升余弦滚降滤波器),过信道。
    • 解脉冲成型(通过相同的升余弦滚降滤波器,再抽样),串并转换,去循环前缀,FFT,信道估计(取出数据与导频,进行LS信道估计),去除虚载波(去零),并串转换,QPSK解调,解交织,信道译码(维比特译码),得到数据并计算误码率。

三、MATLAB仿真

1、MATLAB 源码

ofdm.m

%%
% 仿真系统构成:信号输入(为随机比特流)、OFDM调制、仿真信道传输、OFDM解调、信号输出
% 仿真分析内容:根据输入、输出比特流计算不同信噪比条件下的误码率,
% 并绘制曲线对调制的要求:
% OFDM调制的子载波间隔为15KHz
% 循环前缀长度,子载波数目,导频间隔及ofdm符号数可调,
% 各子载波使用QPSK调制
% 未使用扩频技术,未乘以载波进行上变频,未测试梳妆导频性能
%%
clc;
clear ;
close ;
tic;
disp("simulation start");
%% 参数设置
sta_num = 5;              %仿真次数
SNR = -4:1:25; 
num_carriers = 100;       %子载波数
cp_length = 15;           %循环前缀长度
M = 8;                    %QPSK时,M=4
is_pilot_k = 1;           %块状导频
q = 8;                    %fs = q*B_jidai;
pilot_interval = 4;       %导频间隔
num_ofdm_symbol = 99;     %ofdm符号数
%% 以上参数为可调部分
f_delta = 15e3;
n = 1;
while(true)
%     if(2^n >= num_carriers / pilot_interval * (pilot_interval +1))
    if(2^n >= num_carriers )
        num_fft = 2^n;
        break;
    end
    n = n+1;
end
num_bit = num_carriers * num_ofdm_symbol * log2(M);%二进制bit数  乘以 log2(M) 是为了考虑调制方式对传输数据的影响
B_jidai = num_carriers * f_delta;                  %基带宽度
fs = q*B_jidai;                                    %数字系统采样率
ts = 1/fs;
fd = 300;                                          %多普勒频偏
pathPower = [-1.0 -1.0 -1.0 0 0 0 -3.0 -5.0 -7.0];
pathDelays = [0 50 120 200 230 500 1600 2300 5000]*1e-9;
% chan = rayleighchan(ts, fd, pathDelays, pathPower);  
rchan = comm.RayleighChannel('SampleRate',fs, ...
    'PathDelays',pathDelays,'AveragePathGains',pathPower, ...
    'MaximumDopplerShift',fd,'FadingTechnique','Sum of sinusoids');

%% 基带数据数据产生
data_sourcebit = randi([0,1],1,num_bit);
%% 信道编码(卷积码、再交织)
L=7;                %卷积码约束长度
tblen=6*L;          %Viterbi译码器回溯深度
trellis = poly2trellis(7,[133 171]);       %(2,1,7)卷积编码
data_conv = convenc(data_sourcebit,trellis);
data_scramble = matintrlv(data_conv, log2(M), length(data_conv) / log2(M));
%% qpsk调制
data_dec = bi2de(reshape(data_scramble,length(data_scramble)/log2(M),log2(M)));
data_moded = pskmod(data_dec,M,pi/M);
scatterplot(data_moded);
%% 串并转换
data_moded = reshape(data_moded,num_carriers,length(data_moded)/num_carriers);
%% 扩频
%%补零
data_buling = [data_moded;...
    zeros(num_fft-size(data_moded,1),size(data_moded,2))];
%% 插入导频    
if (is_pilot_k==1)
    pilot_bit_k = randi([0,1],1,log2(M)*num_fft);
    pilot_seq = pskmod(bi2de...
    (reshape(pilot_bit_k,length(pilot_bit_k)/log2(M),log2(M))),M,pi/M);
    data_pilot_inserted = insert_pilot_f(data_buling,pilot_seq,pilot_interval,is_pilot_k);
end

%% IFFT
data_ifft = ifft(data_pilot_inserted,num_fft)*num_fft;
%data_ifft = ifft(data_pilot_inserted,num_fft)*sqrt(num_fft);
%% 插入保护间隔、循环前缀
data_after_cp = [data_ifft(num_fft-cp_length+1:end,:);data_ifft];
%% 并串转换
data_total = reshape(data_after_cp,[],1);
%% 脉冲成型,
sendfir = rcosdesign(0.4,4,fs/B_jidai,'sqrt');
data_upsam = upsample(data_total,fs/B_jidai);
data_send = conv(data_upsam,sendfir,'same');
%% 画图
signal = data_send;
figure(2);
subplot(311);
plot(real(signal));
subplot(312);
plot(imag(signal));
subplot(313);
fft_y=abs(fft(signal,q*num_fft));
fft_x=fs*((1:(q*num_fft))/(q*num_fft)-1/2);
plot(fft_x,20*log10(fftshift(fft_y./max(fft_y))));
%% DA
%% 上变频
%% 信道(通过多经瑞利信道、AWGN信道)

Ber=zeros(1,length(SNR));
for jj=1:length(SNR) 
    for ii=1:sta_num
        channel_out = step(rchan,data_send);
        rx_channel=awgn(channel_out,SNR(jj),'measured');       
%% 下变频
%% AD
        rx_data1 = conv(rx_channel, sendfir, 'same');
        rx_data2 = rx_data1(1:fs/B_jidai:length(rx_data1));
%% 串并转换
        rx_data3=reshape(rx_data2,num_fft+cp_length,[]);
%% 去掉循环前缀
        rx_data4=rx_data3(cp_length+1:end,:);
%% FFT
        rx_data_fft = (1/num_fft)*fft(rx_data4,num_fft);
%% 信道估计与插值(均衡)
%% 信道校正
        [rx_data_delpilot,H] = get_pilot_f(rx_data_fft,pilot_interval);
        rx_data_estimation = chan_estimation_f...
        (rx_data_delpilot,H,pilot_seq,pilot_interval);
%% 去零,并串转换
        rx_data_quling = rx_data_estimation(1:num_carriers,:);
        rx_data_psk = reshape(rx_data_quling,[],1);
%         scatterplot(rx_data_psk);
%% 解扩
%% QPSK解调
        demodulation_data=pskdemod(rx_data_psk,M,pi/M);    
        De_data1 = reshape(demodulation_data,[],1);
        De_data2 = de2bi(De_data1);
        De_Bit = reshape(De_data2,1,[]);   
%% (解交织)
        rx_data_jiejiaozi = matdeintrlv(De_Bit, log2(M), length(De_Bit) / log2(M));
%% 信道译码(维特比译码)
        rx_data_deco = vitdec(rx_data_jiejiaozi,trellis,tblen,'trunc','hard');   %硬判决
%% 计算误码率
[~, ber] = biterr(rx_data_deco(1:length(data_sourcebit)),data_sourcebit);%译码后的误码率
Ber(jj)=Ber(jj)+ber;
    end
Ber(jj)=Ber(jj)/sta_num;
fprintf("SNR = %d dB, ber = %.5f \n",SNR(jj),Ber(jj));
end
figure(3);
signal = rx_channel;
subplot(311);
plot(real(signal));
subplot(312);
plot(imag(signal));
subplot(313);
fft_y=abs(fft(signal,q*num_fft));
fft_x=fs*((1:(q*num_fft))/(q*num_fft)-1/2);
plot(fft_x,20*log10(fftshift(fft_y./max(fft_y))));
figure(4);
%  semilogy(SNR,Ber2,'b-s');
%  hold on;
semilogy(SNR,Ber,'r-o');
hold on;
xlabel('SNR');
ylabel('BER');
title('ETU300叠加AWGN信道下误比特率曲线');

toc;
  • 第 36 行计算 num_bit 时乘以 log2(M) 是为了考虑调制方式对传输数据的影响。
    • 在 OFDM 系统中,每个子载波上可以传输多个比特,通常使用调制方式将多个比特映射到一个符号上进行传输。调制方式可以是 QPSK、16-QAM、64-QAM等。
    • 在计算 num_bit 时,乘以 log2(M) 可以得到需要传输的总比特数。这是因为在 OFDM 系统中,每个 OFDM 符号的数据部分由多个子载波组成,每个子载波上都传输一定数量的比特,因此需要考虑每个符号上的比特数和调制方式的关系。
  • 第 82 行使用 rcosdesign 函数设计了一个根号升余弦滤波器。该函数的输入参数为滚降系数(0.4)、滤波器的长度(4),以及滤波器的归一化截止频率(fs/B_jidai),其中 fs 为数字系统的采样率,B_jidai 为基带带宽。这个滤波器的作用是在信号传输过程中对信号进行滤波,以限制频带内的能量,并控制信号的带内和带外衰减。
  • 第 83 行使用 upsample 函数对输入的信号 data_total 进行上采样。上采样是将信号的采样率提高,即在信号中插入更多的零值样本,以增加信号的频带范围。上采样的倍数为 fs/B_jidai,其中 fs 为数字系统的采样率,B_jidai 为基带带宽。
  • 第 84 行使用 conv 函数对上采样后的信号 data_upsam 和滤波器的脉冲响应 sendfir 进行卷积运算。卷积运算的结果是将信号通过滤波器,得到经过滤波的信号。'same' 参数表示输出的卷积结果与输入信号的长度相同。
  • 第 94 行计算频域的横坐标,即频率。fs 是采样率,(1:(q*num_fft))/(q*num_fft)-1/2 生成一个从 -0.5 到 0.5 的等间隔序列,并乘以采样率 fs 得到真实的频率值。
  • 第 95 行在当前子图中绘制频谱图。fftshift 函数将频域数据进行移位,使得 0 频率位于图形中心。./max(fft_y)FFT 结果进行归一化处理,使得最大值为 1。20*log10 将幅度转换为以分贝为单位的对数尺度。绘制出的图形将显示信号的频域特性。
  • 第 107-108 行:这两行代码实现了接收端的信号处理。首先,通过卷积运算将接收到的信号与发送端的滤波器的脉冲响应进行反脉冲成型,恢复出发送信号的波形。然后,通过采样操作从反脉冲成型后的信号中提取出每个采样点的样本,以便后续的信号解调和处理。提取后的样本保存在 rx_data2 变量中。
    • 第 107 行使用 conv 函数将接收到的信号 rx_channel 与发送端的滤波器的脉冲响应 sendfir 进行卷积运算。卷积的结果是对接收信号进行反脉冲成型,即恢复出发送信号经过信道传输后的波形。'same' 参数表示输出的卷积结果与输入信号的长度相同。
  • 第 110 行:将接收到的连续信号按照每个子载波的长度(包括循环前缀)进行分组,重新排列为一个矩阵。矩阵的每一列对应于一个子载波的信号样本,行数则表示每个子载波上进行FFT的点数加上循环前缀的长度。这样做的目的是为了后续对每个子载波进行 FFT 处理,以提取频域信息。

2、程序流程

程序流程思维导图文末资源自取。
在这里插入图片描述

3、仿真结果

①、打印信息

simulation start
SNR = -4 dB, ber = 0.45980 
SNR = -3 dB, ber = 0.45087 
SNR = -2 dB, ber = 0.42770 
SNR = -1 dB, ber = 0.41361 
SNR = 0 dB, ber = 0.38854 
SNR = 1 dB, ber = 0.37098 
SNR = 2 dB, ber = 0.34956 
SNR = 3 dB, ber = 0.32510 
SNR = 4 dB, ber = 0.30745 
SNR = 5 dB, ber = 0.28106 
SNR = 6 dB, ber = 0.25711 
SNR = 7 dB, ber = 0.24377 
SNR = 8 dB, ber = 0.22386 
SNR = 9 dB, ber = 0.21781 
SNR = 10 dB, ber = 0.21100 
SNR = 11 dB, ber = 0.20307 
SNR = 12 dB, ber = 0.18618 
SNR = 13 dB, ber = 0.19459 
SNR = 14 dB, ber = 0.16919 
SNR = 15 dB, ber = 0.16418 
SNR = 16 dB, ber = 0.16908 
SNR = 17 dB, ber = 0.15683 
SNR = 18 dB, ber = 0.15314 
SNR = 19 dB, ber = 0.15960 
SNR = 20 dB, ber = 0.14756 
SNR = 21 dB, ber = 0.17572 
SNR = 22 dB, ber = 0.16144 
SNR = 23 dB, ber = 0.14231 
SNR = 24 dB, ber = 0.15244 
SNR = 25 dB, ber = 0.15856 
时间已过 29.591768 秒。

③、8PSK 星座图

请添加图片描述

②、脉冲成型图

在这里插入图片描述
从上到下依次为脉冲成型后待发送的实部图、虚部图和频谱图

③、ETU300登加AWGN信道下误比特率曲线

请添加图片描述

四、资源自取

OFDM通信连路仿真学习

本文参考:
matlab-ofdm通信链路仿真


我的qq:2442391036,欢迎交流!


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

App测试、H5测试及小程序测试

文章目录 前言一、App常见测试要点1.App功能测试1.1.App安装与卸载1.2.App升级测试1.3.App登陆测试1.4.离线测试1.5.触屏及操作测试1.6.App消息推送测试 2.AppUI界面测试3.App兼容性测试-适配/手机适配4.App中断测试5.App网络测试6.App安全测试7.App性能测试8.App测试与web测试…

P29 C++箭头运算符以及它对于结构体与类的指针关系

本期的主要内容是箭头运算符以及它对于结构体与类的指针可以做什么,最后实现我们自己的运算符重载。 01 为什么要使用运算符重载 从开发的角度而言,运算符重载的存在是为了提高开发效率,增加代码的可复用性,很多时候简化了代码。…

Django二转Day03 04

0 cbv执行流程,self问题 path(index/, Myview.as_view()),Myview.as_view() 实例化后返回 变成return Myview.dispatch(request, *args, **kwargs)但是视图函数Myview中没有 dispatch 方法 所以去 父类View中寻找return View.dispatch(request, *args, **kwargs)调用…

Apache Hive3.1.3 遇到DATE_FORMAT转换2021年12月格式的问题

比如:需要将时间2021-12-28 00:00:00转换成2021-12的格式,用date_format会将2021-12转换成2022-12的问题。 解决方法: 方式一:大写的‘Y’换成‘y’ 方式二:字符串截取,substr 本博主推荐方式一&#xf…

从谷歌搜索结果出现 AI 生成的图片谈起:AI的利与弊

随着人工智能(AI)的不断发展,其应用领域也越来越广泛。谷歌搜索是现代人日常生活中的一个常用工具,经常用于获取各种信息。最近,谷歌搜索结果中甚至出现了由AI生成的图片,这引发了人们对AI技术的讨论。 首…

SQL 数据操作技巧:SELECT INTO、INSERT INTO SELECT 和 CASE 语句详解

SQL SELECT INTO 语句 SELECT INTO 语句将数据从一个表复制到一个新表中。 SELECT INTO 语法 将所有列复制到新表中: SELECT * INTO newtable [IN externaldb] FROM oldtable WHERE condition;只复制一些列到新表中: SELECT column1, column2, colu…

如何写好开发信标题?推荐的营销邮件主题?

打开率高的开发信标题有哪些?怎么写吸引人邮件标题? 开发信标题是您的邮件首次与受众接触的部分,因此,它必须引起他们的兴趣,激发他们打开邮件的欲望。蜂邮EDM将讨论如何写好开发信标题,以及一些成功的开发…

mysql:免费的GUI客户端工具推荐并介绍常用的操作

给大家推荐几个常用的 mysql 数据库客户端 sequel-pro sequel-ace 官网下载地址 免费 sequel-ace 可以理解为 Sequel Pro 的升级版,由于Sequel Pro官方不维护了,特别是对 MySQL 8.0 支持不好,所以现在由社区维护了新分支 sequel-ace&#x…

5年经验之谈 —— 接口测试主要测哪些方面?

当今互联网时代,接口测试已经成为软件测试的一个重要组成部分。接口测试是指对系统各个接口进行验证,确保接口的正确性、稳定性和安全性。接口测试是软件开发过程中不可缺少的环节,它旨在确保接口能够正常工作,并且满足所需要的规…

nvm下载node.js以及环境变量配置

文章目录 一.卸载node.js二.安装nvm以及nvm环境配置2.1 安装nvm2.2 nvm环境配置 三.node.js安装以及环境配置3.1 node.js安装3.2 node.js环境配置3.3 node.js的环境配置参考如下文章。 一.卸载node.js 找到自己对应的node.js文件所在路径,通过控制面板卸载node.js&…

阿里云Arthas使用——通过watch命令查看类的返回值 捞数据出来

前言 Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类…

开发中遇到的问题 -- 回调解决应用端和服务端通信问题

前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱 这里写目录标题 一. 问题概述二. 代码展示2.1 公共服务端2.2 应用端 一. 问题概述 项目介绍:今天做项目的时候遇到了点…

C++学习专栏【基础知识2】C++数据类型

1、内置数据类型 基本内置类型 C为程序员提供了丰富的内置数据类型以及用户自定义数据类型。以下表格列出了七种基本的 C 数据类型 - 类型关键字布尔值bool字符char整数int浮点数float双精度浮点数double无值void宽字符wchar_t 基本类型中的几种可以使用一个或多个类型修饰符…

RabbitMQ登录控制台显示--你与此网站的连接不是私密连接

一、RabbitMQ默认账号 Note: The default administrator username and password are guest and guest. 注:默认管理员用户名和密码为guest和guest 二、自己修改过或者注册的情况 由于本人之前用过,注册过账号密码,在登录时,用户名账号有异常出现以下问题 解决方案: 因为我的rab…

使用easyExcel框架报错:服务器缺少字体

后台服务使用easyExcel框架生成表格,但是生成的时候报如下的错误: 这种报错其实就是部署服务的服务器缺少字体,正确的方法是安装字体。需要注意的是,测试环境服务器与生产环境服务器的在配置版本上可能存在差异,因此需…

Node.js+Express+Nodemon+Socket.IO构建Web实时通信

陈拓 2023/11/23-2023/11/27 1. 简介 Websocket WebSocket是一种在单个TCP连接上提供全双工通讯的协议。特别适合需要持续数据交换的服务,例如在线游戏、实时交易系统等。 Websocket与Ajax之间的区别 Ajax代表异步JavaScript和XML。它被用作一组Web开发技术&…

全汉电源SN生产日期解读

新买了一个全汉的电脑电源,SN:WZ3191900030,看了几次没想明白,最后估计SN是2023年19周这样来记录日期的。问了一下京东全汉客服,果然就是这样的。那大家如果在闲鱼上看到全汉电源,就知道它的生产日期了。

YOLOv8改进 | 2023 | 通过RFAConv重塑空间注意力(深度学习的前沿突破)

一、本文介绍 本文给大家带来的改进机制是RFAConv,全称为Receptive-Field Attention Convolution,是一种全新的空间注意力机制。与传统的空间注意力方法相比,RFAConv能够更有效地处理图像中的细节和复杂模式(适用于所有的检测对象都有一定的…

C语言——写一个简单函数,找两个数中最大者

#include <stdio.h>int max( int a, int b ) { return a>b ? a:b; }int main() { int a, b;printf("输入两个数:\n");scanf("%d %d", &a, &b);printf("max %d\n", max(a, b));return 0; }输出结果&#xff1a;

Python---文件

文件--- 内存中存放的数据在计算机关机后就会消失。要长久保存数据&#xff0c;就要使用硬盘、光盘、U 盘等设备。为了便于数据的管理和检索&#xff0c;引入了“文件”的概念。 一篇文章、一段视频、一个可执行程序&#xff0c;都可以被保存为一个文件&#xff0c;并赋予一个…