OFDM仿真程序

clc
clear allIFFT_bin_length=128; %IFFT点数128个
carrier_count=50;  %子信道(子载波)数目
bits_per_symbol=2; %4进制符号
symbols_per_carrier=200;%每个子信道或者说子载波有200个符号
SNR=0:1:40;
for num=1:41baseband_out_length=carrier_count*symbols_per_carrier*bits_per_symbol; %总bit数
%下面是载波位置,为了满足得到的是实数信号,载波的位置要满足共轭对称
carriers=(1:carrier_count)+(floor(IFFT_bin_length/4)-floor(carrier_count/2)); %floor函数是朝负无穷大四舍五入
conjugate_carriers=IFFT_bin_length-carriers+2;%baseband_out=round(rand(1,baseband_out_length));%20000个0-1信源符号,round函数为四舍五入为最近的小数
baseband_out=randi(2,1,baseband_out_length)-1;   %返回一个介于1和2之间的1*20000的数组
%将一行20000的数据交叉转换为2行10000的数据
convert_matrix=reshape(baseband_out,bits_per_symbol,length(baseband_out)/bits_per_symbol);
%不如写个函数将值映射成0-3,如00-0,01-1,10-2,11-3
for k=1:(length(baseband_out)/bits_per_symbol)modulo_baseband(k)=0;for i=1:bits_per_symbolmodulo_baseband(k)=modulo_baseband(k)+convert_matrix(i,k)*2^(bits_per_symbol-i);end
end%串并转换
%将本次的模4的串行数据流转换为并行数据流,其中,每行整体是一个OFDM符号,每一个OFDM符号由所有载波在该采样点叠加产生,每列代表一个子载波
carrier_matrix=reshape(modulo_baseband,symbols_per_carrier,carrier_count);%采用了差分相移键控调制
carrier_matrix=[zeros(1,carrier_count);carrier_matrix];%补了一行全0,作为编码的参考起点
for i=2:(symbols_per_carrier+1)carrier_matrix(i,:)=rem(carrier_matrix(i,:)+carrier_matrix(i-1,:),2^bits_per_symbol); %rem函数是除后的余数
end%将差分编码转换为相位变化
carrier_matrix=carrier_matrix*((2*pi)/(2^bits_per_symbol));%将相位转换为一个复数
%这句代码保证幅值都是1
[X,Y]=pol2cart(carrier_matrix,ones(size(carrier_matrix,1),size(carrier_matrix,2)));
%构造映射,将相位的值转换为极坐标上的一个复数点0-1,pi/2-j.pi--1,3pi/2--j
complex_carrier_matrix=complex(X,Y);%将每个子载波分配到之前定义好的IFFT输入端,根据IFFT的对称性,这样可以得到实值序列
IFFT_modulation=zeros(symbols_per_carrier+1,IFFT_bin_length);
IFFT_modulation(:,carriers)=complex_carrier_matrix;
IFFT_modulation(:,conjugate_carriers)=conj(complex_carrier_matrix);%画出未经过IFFT的离散幅度谱,总共有50+50个输入端有数据,所以频谱图显示为两个矩形形状
% figure(1)
% stem(0:IFFT_bin_length-1,abs(IFFT_modulation(2,1:IFFT_bin_length)),'b*-')
% grid on;axis([0,IFFT_bin_length -0.5 1.5]);xlabel('IFFT BIN');ylabel('Magnitude');
% title('OFDM Carrier Frequency Magnitude');
%画出未经过IFFT的离散相位谱
% figure(2)
%所有128个点的相位图
% plot(0:IFFT_bin_length-1,(180/pi)*angle(IFFT_modulation(2,1:IFFT_bin_length)),'go');
% hold on;
%带数据的100个点的相位图
% stem(carriers-1,(180/pi)*angle(IFFT_modulation(2,carriers)),'b*-');
% stem(conjugate_carriers-1,(180/pi)*angle(IFFT_modulation(2,conjugate_carriers)),'b*-');
% axis([0 IFFT_bin_length -200 200]);grid on;ylabel('Phase');xlabel('IFFT Bin');
% title('OFDM Carrier Phase');%IFFT变换
time_wave_matrix=ifft(IFFT_modulation,[],2);%对列进行离散傅里叶反变换
%time_wave_matrix=time_wave_matrix;%作图
figure(3)
plot(0:IFFT_bin_length-1,time_wave_matrix(2,:));
grid on;
ylabel('幅度');xlabel('时间');
title('一个OFDM符号时域信号波形图');%colors=['r' 'g' 'b' 'k']
%for f=1:4%temp_bins(1:IFFT_bin_length)=0+0j;%temp_bins(carriers(f))=IFFT_modulation(2,carriers(f));%temp_bins(conjugate_carriers(f))=IFFT_modulation(2,conjugate_carriers(f));%temp_time=ifft(temp_bins');%figure(4)%plot(0:IFFT_bin_length-1,temp_time,colors(f));%hold on;
%end
%grid on;ylabel('幅度');xlabel('时间');title('分离出的时域波形');% 添加一个窗函数,就是滤波器,减弱信号的不连续点
% 每一个时间波形表示所有载波的一个符号周期
% 因为时域矩阵中所有虚部都等于0,所以利用Hamming窗时,只保留实部用于加窗
for i=1:symbols_per_carrier+1windowed_time_wave_matrix(i,:)=real(time_wave_matrix(i,:)).*hamming(IFFT_bin_length)';
%     windowed_time_wave_matrix(i,:)=real(time_wave_matrix(i,:));
end%将调制波形序列化(并串转换)
ofdm_modulation=reshape(time_wave_matrix,1,IFFT_bin_length*(symbols_per_carrier+1));%作图
% temp_time=IFFT_bin_length*(symbols_per_carrier+1);
% figure(5)
% plot(0:temp_time-1,ofdm_modulation);
% grid on;
% ylabel('幅度');xlabel('时间(采样)');title('OFDM时间信号');%频谱图
% symbols_per_average=ceil(symbols_per_carrier/5);
% avg_temp_time=IFFT_bin_length*symbols_per_average;
% averages=floor(temp_time/avg_temp_time);
% average_fft(1:avg_temp_time)=0;
% for a=0:(averages-1)
%     subset_ofdm=ofdm_modulation(((a*avg_temp_time)+1:((a+1)*avg_temp_time)));
%     subset_ofdm_f=abs(fft(subset_ofdm));
%     average_fft=average_fft+(subset_ofdm_f/averages);
% end
% average_fft_log=20*log10(average_fft);
% figure(6)
% plot((0:(avg_temp_time-1))/avg_temp_time,average_fft_log);
% hold on;
% plot(0:1/IFFT_bin_length:1,-35,'rd');grid on;
% axis([0 0.5 -40 max(average_fft_log)]);ylabel('幅度(dB)');xlabel('标准化频率(0.5=fs/2)');
% title('OFDM 信号频谱');
Tx_data=ofdm_modulation;%上变频,不一定用得到%经过信道
Rx_data=awgn(Tx_data,SNR(num));
% Rx_data=Tx_data;%%%%%%%%%%%%%%%%%%接收端%%%%%%%%%%%%%%%%%%%%%%%%%串并转换
Rx_data_matrix=reshape(Rx_data,symbols_per_carrier+1,IFFT_bin_length);%FFT变换
Rx_spectrum=fft(Rx_data_matrix,[],2);%经过FFT的频域相应图
figure(7)
stem(0:IFFT_bin_length-1,abs(Rx_spectrum(1:IFFT_bin_length,2)),'b*-');
grid on;axis([0 IFFT_bin_length -0.5 1.5]);ylabel('幅度');xlabel('FFT Bin');
title('OFDM 接收频谱,幅度');
% figure(8)
% plot(0:IFFT_bin_length-1,(180/pi)*angle(Rx_spectrum(1:IFFT_bin_length)),'go');
% hold on;
% stem(carriers-1,(180/pi)*angle(Rx_spectrum(carriers,2)),'b*-');
% stem(conjugate_carriers-1,(180/pi)*angle(Rx_spectrum(conjugate_carriers,2)),'b*-');
% axis([0 IFFT_bin_length -200 200]);
% grid on;ylabel('相位谱');xlabel('FFT Bin');
% title('OFDM 接受信号相位谱');%将128中真正含有数据的50个载波提取出来
Rx_carriers=Rx_spectrum(:,carriers);%画出每一个接收符号
% figure(9)
% Rx_phase_P=angle(Rx_carriers);
% Rx_mag_P=abs(Rx_carriers);
% polar(Rx_phase_P,Rx_mag_P,'rd');%对每个FFT点,解映射出对应的相位值
Rx_phase=angle(Rx_carriers)*(180/pi);
phase_negative=find(Rx_phase<0);
Rx_phase(phase_negative)=rem(Rx_phase(phase_negative)+360,360);%将负的相位对应为0-2pi内的值%从差分相移编码中,提取相位差值,这里利用diff()函数
Rx_decoded_phase=diff(Rx_phase);
phase_negative=find(Rx_decoded_phase<0);
Rx_decoded_phase(phase_negative)=rem(Rx_decoded_phase(phase_negative)+360,360);%解映射,将不同的相位转换为0-3的信源符号,0的相位范围为-45,45,1的相位范围为45-135,依此类推
base_phase=360/2^bits_per_symbol;
delta_phase=base_phase/2;
Rx_decoded_symbols=zeros(size(Rx_decoded_phase,1),size(Rx_decoded_phase,2));for i=1:(2^bits_per_symbol-1)center_phase=base_phase*i;plus_delta=center_phase+delta_phase;minus_delta=center_phase-delta_phase;decoded=find((Rx_decoded_phase<=plus_delta)&(Rx_decoded_phase>minus_delta));Rx_decoded_symbols(decoded)=i;
end
%Rx_decoded_symbols=Rx_decoded_symbols';
%并串转换
Rx_serial_symbols=reshape(Rx_decoded_symbols,1,size(Rx_decoded_symbols,1)*size(Rx_decoded_symbols,2));%将4进制的符号解码为二进制符号
for i=bits_per_symbol:-1:1if i~=1Rx_binary_matrix(i,:)=rem(Rx_serial_symbols,2);Rx_serial_symbols=floor(Rx_serial_symbols/2);elseRx_binary_matrix(i,:)=Rx_serial_symbols;end
end
baseband_in=reshape(Rx_binary_matrix,1,size(Rx_binary_matrix,1)*size(Rx_binary_matrix,2));%求误码率
bit_errors=find(baseband_in~=baseband_out);
bit_error_count(num)=size(bit_errors,2);
BER(num)=bit_error_count(num)/baseband_out_length;
end
figure(10)
semilogy(SNR,BER,'-ob','MarkerFaceColor','b','MarkerSize',5,'LineWidth',2);hold on;grid on;
title('DPSK-OFDM信噪比与误码率曲线');xlabel('SNR(dB)');ylabel('BER');
plot([0 35],[3.8e-3,3.8e-3],'r','LineWidth',1);hold on;
legend('DPSK-OFDM','FEC(3.8x10^-^3)');

OFDM仿真程序,可直接运行,注释详细(没人注释比我还详细了)相关推荐

  1. 用c++做一个简单的打飞机小游戏(详细说明与注释)

    用c++做一个简单的打飞机小游戏(详细说明与注释) 说明: 代码长度5k多,行数200多行. 不仅没有压行,反而为了条理清晰一点所以很多中间加空换行,把很多可以写在一起的分割成了几个函数. 为了不会忘 ...

  2. 详细聊聊Javadoc注释规范

    Javadoc 注释规范 1. 注释分类 2. Java文档和Javadoc 3. 文档注释的格式  3.1 文档和文档注释的格式化 3.2 文档注释的三部分 4. 使用Javadoc标记  4.1 ...

  3. [GO语言基础] 二.编译运行、语法规范、注释转义及API标准库知识普及

    作为网络安全初学者,会遇到采用Go语言开发的恶意样本.因此从今天开始从零讲解Golang编程语言,一方面是督促自己不断前行且学习新知识:另一方面是分享与读者,希望大家一起进步.前文介绍了什么是GO语言 ...

  4. 使用PyTorch构建GAN生成对抗网络源码(详细步骤讲解+注释版)02 人脸识别 下

    文章目录 1 测试鉴别器 2 建立生成器 3 测试生成器 4 训练生成器 5 使用生成器 6 内存查看 上一节,我们已经建立好了模型所必需的鉴别器类与Dataset类. 使用PyTorch构建GAN生 ...

  5. WebBench压力测试工具(详细源码注释+分析)

    WebBench压力测试工具(详细源码注释+分析) 本文适合人群:对WebBench实现感兴趣的人 WebBench原理: Linux下使用的服务器压力测试工具,利用fork建立多个子进程,每个子进程 ...

  6. 基于stm32、0.96寸OLED实现的贪吃蛇小游戏(详细源码注释)

    简介:本实验基于stm32最小系统.0.96寸OLED(68*128)和摇杆实现一个经典的贪吃蛇小游戏.项目源码地址:点击下载. 硬件设计: 普通摇杆,0.96寸OLED 单色屏幕(SPI协议通讯), ...

  7. 基于stm32、0.96寸OLED实现的俄罗斯方块小游戏(详细源码注释)

    概述:本实验基于stm32最小系统.0.96寸OLED(68*128)和摇杆实现一个经典的俄罗斯方块小游戏.项目源码地址:点击下载. 硬件要求: 普通摇杆,两个电位器和一个开关组成,左右摇动控制一个电 ...

  8. java编译不报错但运行啥都没_java编译时与运行时概念与实例详解

    java编译时与运行时概念与实例详解 发布于 2020-7-29| 复制链接 本篇文章通过实例对 java程序编译时与运行时进行了详解,需要的朋友可以参考下 Java编译时与运行时很重要的概念,但是一 ...

  9. 使用HTML注释标签,超详细的HTML !–…– 注释标签使用实例.pdf

    超详细的HTML 超详细的HTML 注释标签使⽤实例 HTML 注释标签 标签定义及使⽤说明 < !--...--> 注释标签⽤来在源⽂档中插⼊注释.注释不会在浏览器中显⽰. 您可使⽤注释 ...

最新文章

  1. oracle 授权 增删改查权限_linux suid,sgid,sticky-bit三种特殊权限简介
  2. 惊:FastThreadLocal吞吐量居然是ThreadLocal的3倍!!!
  3. 正面管教PHP交流互助会,父母的心态决定孩子的状态/慧育家正面管教家长讲师认证班...
  4. Android向上显示更多内容,如何在Android中为2个父项实现向上导航,指向1个子活动...
  5. 文字链接_新生命道目录及音频、文字链接(20200501更新)
  6. Idea控制台中文乱码解决方案
  7. 微信小程序上传图片到html,微信小程序-上传图片
  8. LINUX设置固定IP上网方法
  9. 方法的反射---反射学习笔记(二)
  10. Intent传递数据时,可以传递哪些类型数据
  11. jlink怎么调试linux程序_STM32开发板JLINK调试步骤
  12. MySQL截取SUBSTRING
  13. 一些关于直播间人货场的打造干货,直播电商新手必须要了解人货场的概念
  14. 主动申请linux内存 脚本,Shell 脚本来自动监控 Linux 系统的内存
  15. 从技术转管理,我做了什么来拯救自己?
  16. 一看就停不下来的中国史
  17. jane street market prediction 冠军方案 奇巧淫技与topline链接整理(3/3)
  18. [2018-03-06] 基于Django的轻量级CMS Mezzanine搭建笔记
  19. 模拟一个“系统登陆“窗体,进行用户名和密码的验证: 1.当用户名和密码都正确时,弹出一个对话框,提示“用户名和密码正确”, 2.用户名错误,弹出一个对话框,提示“用户名错误,请重新输入!”
  20. 宏的录制以及在Visual Basic中显示代码

热门文章

  1. 罚款200元的交通违法行为
  2. 命令终端(CMD)自动补全功能 — Tab Complete 功能
  3. 计算机网络笔记----应用层
  4. python随机抽取人名_python实现艾宾浩斯背单词功能,实现自动提取单词、邮件发送,再也不用担心背单词啦...
  5. 嵌入式C中,全局变量滥用的后果竟如此严重?
  6. 学计算机编程200字感想,计算机学习心得体会
  7. Auto Lisp 标注子样式_CSS 核心样式
  8. Windows下使用net user命令管理账户
  9. 1053 住房空置率(PAT乙级 C++ 坑点分析)
  10. 工业以太网交换机的接口知识详解