本篇文章的所有代码是MIMO-OFDM系统原理、应用及仿真(李莉)上面的源代码

(本文章不参与任何商业盈利,如果涉及到什么侵权问题请及时联系博主删除文章)

内容:

1.通过对OFDM信号的各个子载波赋共轭对称数据产生一个实OFDM符号。

2.给OFDM符号加循环前缀与循环后缀。

3.给OFDM加窗(升余弦窗).

4.信道采用高斯白噪声信道。

5。去掉循环前缀和后缀,解调。

下面附上代码:

clc;
clear all;
close all;
carrier_count=200; %这个程序中OFDM子载波个数为512,其中400即carrier_count*2为数据符号,其余赋值为0
symbols_per_carrier=20;  %每个子载波上的符号数,在这里即为OFDM符号个数
bits_per_symbol=4;    %OFDM符号的每个子载波上传输的比特数。4bit通常采用16QAM调制
IFFT_bin_length=512;  %FFT长度,也即一个OFDM符号子载波个数
PrefixRatio=1/4;  %循环前缀的比值,即循环前缀与OFDM符号长度的比值,通常在1/6~1/4之间
GI=PrefixRatio*IFFT_bin_length;  %保护间隔的长度,这里为128
beta=1/32;  %升余弦窗的滚降系数
GIP=beta*(IFFT_bin_length+GI);  %循环前缀的长度,这里为20
SNR=30;   %本程序考虑加性高斯白噪声信道,这里信噪比为30dB%------------------OFDM信号的产生------------------------
baseband_out_length=carrier_count*symbols_per_carrier*bits_per_symbol; %计算传输数据总的比特数,200×20×4bit=16000bit。 16000bit的构成
%20个OFDM符号,每个OFDM符号200个子载波,每个子载波传输4bit信息
carriers=(1:carrier_count) + (floor(IFFT_bin_length/4) - floor(carrier_count/2)); %计算OFDM符号子载波的序号,carriers中存放的序号是29-228
conjugate_carriers=IFFT_bin_length - carriers + 2;  %计算OFDM符号子载波的序号,conjugate_carries中存放的序号是282-481,  实际是485-286
rand('twister',0);
baseband_out=round(rand(1,baseband_out_length));  %产生16000bit待传输的二进制比特流。
%这里存放的是发送的二进制信号与后面解调后的二进制信号比较,可以计算误码率。%16QAM调制并绘制星座图
complex_carrier_matrix=qam16(baseband_out);
%调用子程序qam16进行16QAM调制。将baseband_out中的二进制比特流,每4bit转换为一个16QAM信号,即将二进制比特流每4bit转换为-3-3j,-3+3j,3-3j,3+3j,-1-3j
%-1+3j,1-3j,1+3j,-3-j,-3+j,3-j,3+j,-1-j,-1+j,1-j,1+j中的一个。转换后complex_carrier_matrix为1×4000矩阵
complex_carrier_matrix=reshape...(complex_carrier_matrix',carrier_count,symbols_per_carrier)';
%转换complex_carrier_matrix中的数据为carrier_count*symbols_per_carrier矩阵,这里为20×200矩阵
figure(1);
plot(complex_carrier_matrix,'*r');     %绘制16QAM星座图
axis([-4,4,-4,4]);
title('16QAM调制后星座图');
grid on%IFFT,即进行OFDM调制
IFFT_modulation=zeros(symbols_per_carrier,IFFT_bin_length);   %将symbols_per_carrier*IFFT_bin_length矩阵赋0值,这里将20×512矩阵赋0值
%这里512是IFFT的长度,也是OFDM符号的子载波个数
IFFT_modulation(:,carriers)=complex_carrier_matrix; %将20×200的complex_carrier_matrix的数据赋给IFFT_modulation的第29-228列,
%即给512个子载波中的29-229个子载波赋值
IFFT_modulation(:,conjugate_carriers) = conj(complex_carrier_matrix); %将20×200的complex_carrier_matrix的数据赋值给512个子载波中的的282-481个
%子载波这段程序构造了512个子载波的OFDM符号,并且各个子载波上的数据是共轭对称的。这样做的目的是经过IFFT后形成的OFDM符号均为实数。
%另外,在512个子载波中,仅有400个子载波为数据,其余为0值,相当于补0。补零的目的是通常IFFT的长度应该为2的整数次幂
signal_after_IFFT=ifft(IFFT_modulation,IFFT_bin_length,2);     %IFFT实现OFDM调制
time_wave_matrix=signal_after_IFFT;
figure(2);
plot(0:IFFT_bin_length-1,time_wave_matrix(2,:));
%画一个OFDM信号的时域表现
axis([0,512,-0.4,0.4]);
grid on;
ylabel('Amplitude');
xlabel('Time');
title('OFDM Time Signal,One Symbol Period');%添加循环前缀与循环后缀
XX=zeros(symbols_per_carrier,IFFT_bin_length + GI + GIP);
%IFFT_bin_length + GI + GIP为OFDM、循环前缀、循环后缀长度之和
for k=1:symbols_per_carrier;for i=1:IFFT_bin_length;XX(k,i+GI)=signal_after_IFFT(k,i);endfor i=1:GI;XX(k,i)=signal_after_IFFT(k,i+IFFT_bin_length - GI);
%添加循环前缀endfor j=1:GIP;XX(k,IFFT_bin_length + GI + j) = signal_after_IFFT(k,j);%添加循环后缀end
end
time_wave_matrix_cp=XX;  %带循环前缀与循环后缀的OFDM符号
figure(3);
plot(0:length(time_wave_matrix_cp)-1,time_wave_matrix_cp(2,:)); %画带有循环前缀和循环后缀的OFDM信号的时域波形
axis([0,600,-0.3,0.3]);
grid on;
ylabel('Amplitude');
xlabel('Time');
title('OFDM Time Signal with CP, One Symbol Period');%OFDM符号加窗
windowed_time_wave_matrix_cp=zeros(1,IFFT_bin_length + GI + GIP);
for i=1:symbols_per_carrierwindowed_time_wave_matrix_cp(i,:)=real(time_wave_matrix_cp(i,:)).*rcoswindow(beta,IFFT_bin_length + GI)';%调用rcoswindow产生升余弦窗,对带循环前缀与循环后缀的OFDM符号加窗
end
figure(4);
plot(0:IFFT_bin_length - 1 + GI + GIP,windowed_time_wave_matrix_cp(2,:));
%加窗后的OFDM符号
axis([0,700,-0.2,0.2]);
grid on;
ylabel('Amplitude');
xlabel('Time');
title('OFDM Time Signal Apply a window, One Symbol Period');%生成发送信号,并串转换
windowed_Tx_data=zeros(1,symbols_per_carrier*(IFFT_bin_length + GI) + GIP);  %注意这里并串转换后数据长度为
%symbols_per_carrier*(IFFT_bin_length + GI) + GIP,这里考虑了循环前缀与循环后缀的重叠相加
windowed_Tx_data(1:IFFT_bin_length + GI + GIP)=windowed_time_wave_matrix_cp(1,:);   %1:IFFT_bin_length + GI + GIP=1:(IFFT_bin_length + GI + GIP)
%赋给第一个加窗带循环前缀后缀的OFDM符号至windowed_Tx_data,即发送串行数据
for i=1:symbols_per_carrier - 1windowed_Tx_data((IFFT_bin_length + GI)*i + 1:(IFFT_bin_length + GI)*(i+1)+GIP) = windowed_time_wave_matrix_cp(i+1,:);%并串转换,循环前缀与循环后缀重叠相加
end
Tx_data_withoutwindow=reshape(time_wave_matrix_cp',(symbols_per_carrier)*(IFFT_bin_length + GI + GIP),1)';
%不加窗数据并串转换
Tx_data=reshape(windowed_time_wave_matrix_cp',(symbols_per_carrier)*(IFFT_bin_length + GI + GIP),1)';
%加窗数据,但按照循环前缀与循环后缀不重叠相加进行并串转换。此时数据长度为
%(symbols_per_carrier)*(IFFT_bin_length + GI + GIP)
temp_timel=(symbols_per_carrier)*(IFFT_bin_length + GI + GIP);
%加窗,循环前缀与循环后缀不重叠数据长度,即为发送的总数据比特数
figure(5)
subplot(211);
plot(0:temp_timel - 1,Tx_data);    %加了窗的,但不重叠
%画循环前缀与循环后缀不重叠相加OFDM信号的时域波形
grid on
ylabel('Amplitude (volts)')
xlabel('Time (samples)')
title('OFDM Time Signal')
temp_time2 = symbols_per_carrier*(IFFT_bin_length + GI) + GIP;
%加窗,循环前缀与循环后缀重叠相加数据长度
subplot(212);
plot(0:temp_time2-1,windowed_Tx_data);   %加了窗,重叠
%画循环前缀与循环后缀重叠相加OFDM信号的时域波形
grid on
ylabel('Amplitude (volts)')
xlabel('Time (samples)')
title('OFDM Time Signal')%未加窗发送信号频谱
%对发送数据分段,分段计算频谱,去平均作为OFDM信号的频谱
symbols_per_average=ceil(symbols_per_carrier/5);   %4
avg_temp_time=(IFFT_bin_length + GI + GIP)*symbols_per_average;    %分成五段,每段的长度
averages = floor(temp_timel/avg_temp_time);
%将发送数据分5段,每段数据长度为avg_temp_time
average_fft(1:avg_temp_time) = 0;  %存放平均后的OFDM信号的谱,先置零for a=0:(averages - 1)subset_ofdm = Tx_data_withoutwindow(((a*avg_temp_time)+1):((a+1)*avg_temp_time));    %分段subset_ofdm_f = abs(fft(subset_ofdm));   %对分段后的OFDM信号计算频谱average_fft = average_fft + (subset_ofdm_f/averages);  %取平均endaverage_fft_log = 20*log10(average_fft);   %求对数平均谱figure(6);subplot(211);plot((0:(avg_temp_time-1))/avg_temp_time,average_fft_log);%画未加窗OFDM符号对数平均谱hold ongrid onaxis([0 0.5 -20 max(average_fft_log)])ylabel('Magnitude (dB)')xlabel('Normalized Frequency (0.5 = fs/2)')title('OFDM Signal Spectrum')%计算加窗OFDM信号频谱%这段程序与上段程序类似,不同之处在于这段程序是对加窗OFDM信号进行分段计算频谱,再取平均symbols_per_average = ceil(symbols_per_carrier/5);avg_temp_time = (IFFT_bin_length + GI + GIP)*symbols_per_average;averages = floor(temp_timel/avg_temp_time);%将发送数据分5段,每段数据长度为avg_temp_timeaverage_fft(1:avg_temp_time) = 0;   %存放平均后的OFDM信号的谱,先置零for a=0:(averages - 1)subset_ofdm = Tx_data(((a*avg_temp_time)+1):((a+1)*avg_temp_time));    %分段subset_ofdm_f = abs(fft(subset_ofdm));   %对分段后的OFDM信号计算频谱average_fft = average_fft + (subset_ofdm_f/averages);  %取平均endaverage_fft_log = 20*log10(average_fft);   %求对数平均谱subplot(212)plot((0:(avg_temp_time-1))/avg_temp_time,average_fft_log);%画加窗OFDM符号对数平均谱hold ongrid onaxis([0 0.5 -20 max(average_fft_log)])ylabel('Magnitude (dB)')xlabel('Normalized Frequency (0.5 = fs/2)')title('OFDM Signal Spectrum')%====================经过加性高斯白噪声信道========================
Tx_signal_power = var(windowed_Tx_data);   %计算信号功率,var均方差函数 %windowed_Tx_data是并串转换,循环前缀与循环后缀重叠相加的
linear_SNR = 10^(SNR/10);    %转换对数信噪比为线性幅度值
noise_sigma = Tx_signal_power/linear_SNR;   %计算噪声功率,也就是方差
noise_scale_factor = sqrt(noise_sigma);     %计算标准差
noise = randn(1,((symbols_per_carrier)*(IFFT_bin_length + GI)) + GIP)*noise_scale_factor; %产生功率为noise_scale_factor高斯噪声
Rx_data = windowed_Tx_data + noise;
%在发送数据上加噪声,相当于OFDM信号经过加性高斯白噪声信道%==============OFDM信号解调===========================
Rx_data_matrix = zeros(symbols_per_carrier,IFFT_bin_length + GI + GIP);  %存放并行接收数据
for i=1:symbols_per_carrierRx_data_matrix(i,:) = Rx_data(1,(i-1)*(IFFT_bin_length + GI)+1:i*(IFFT_bin_length + GI) + GIP);   %串并转换
end
Rx_data_complex_matrix = Rx_data_matrix(:,GI + 1:GI + IFFT_bin_length);
%去掉循环前缀与循环后缀,取出OFDM符号传输的数据
Y1 = fft(Rx_data_complex_matrix,IFFT_bin_length,2);
%求FFT,即OFDM信号解调
Rx_carriers = Y1(:,carriers);
%取出carriers序号对应的子载波上的发送数据,去掉加入的零及共轭对称部分
Rx_phase = angle(Rx_carriers);  %计算接收信号的相位特性
Rx_mag = abs(Rx_carriers);     %计算接收信号的幅度特性
[M,N] = pol2cart(Rx_phase,Rx_mag);   %转换极坐标数据为直角坐标数据
Rx_complex_carrier_matrix = complex(M,N);   %两个直角坐标的实数据为构成复数据
figure(7);
plot(Rx_complex_carrier_matrix,'*r');    %画接收信号的星座图
axis([-4,4,-4,4]);
title('SNR=30dB接收数据星座图');
grid on%16QAM解调
Rx_serial_complex_symbols = reshape(Rx_complex_carrier_matrix',...size(Rx_complex_carrier_matrix,1)*size(Rx_complex_carrier_matrix,2),1)';
%将矩阵Rx_complex_carrier_matrix转换为1的数组
Rx_decoded_binary_symbols = demoduqam16(Rx_serial_complex_symbols);
%进行16QAM解调
baseband_in = Rx_decoded_binary_symbols;
%将解调恢复的二进制信号存放在baseband_in%误码率计算
bit_errors = find(baseband_in ~= baseband_out);
%解调恢复的二进制信号与发送二进制信号比较,查找误码
bit_error_count = size(bit_errors,2);   %计算误码个数
ber = bit_error_count/baseband_out_length;   %计算误码率

demoduqam16.m

%16QAM信号的解调子程序,子程序名称:demoduqam16.m
%转换16QAM信号为二进制信号
function [demodu_bit_symble] = demoduqam16(Rx_serial_complex_symbols)
%输入参数:Rx_serial_complex_symbols为接收端接收到的复16QAM信号
%输出参数:demodu_bit_symble为二进制数码流
complex_symbols = reshape(Rx_serial_complex_symbols,length(Rx_serial_complex_symbols),1);
d=1;
mapping=[-3*d 3*d;-d 3*d;d 3*d;3*d 3*d;-3*d d;-d d;d d;3*d d;-3*d -d;-d -d;d -d;3*d -d;-3*d -3*d;-d -3*d;d -3*d;3*d -3*d];
complex_mapping=complex(mapping(:,1),mapping(:,2));
%将数据映射表转换为16QAM信号,即3组合为复数
for i=1:length(Rx_serial_complex_symbols);for j=1:16;metrics(j) = abs(complex_symbols(i,1) - complex_mapping(j,1));end[min_metric decode_symble(i)] = min(metrics);%将接收数据与标准16QAM信号比,找到差最小的,将其对应恢复成标准的16QAM信号
end
decode_bit_symble=de2bi((decode_symble-1)','left-msb');
%16QAM转为二进制
demodu_bit_symble=reshape(decode_bit_symble',...1,length(Rx_serial_complex_symbols)*4);    %转换为一行

qam16.m

%16QAM调制子程序,子程序名称:qam16.m
%将二进制数目流转换为16QAM信号
function [complex_qam_data]=qam16(bitdata)
%输入参数:bitdata为二进制数码流
%输出参数:complex_qam_data为16QAM复信号
X1=reshape(bitdata,4,length(bitdata)/4)';    %将二进制数码流以4比特分段
d=1;
%转换4比特二进制码为十进制码1~16,生成mapping映射表中的索引
for i=1:length(bitdata)/4;for j=1:4X1(i,j) = X1(i,j)*(2^(4-j));endsource(i,1)=1+sum(X1(i,:));
end
%16QAM映射表,该表中存放的是16对,每队两个实数,表示星座位置
mapping=[-3*d 3*d;-d 3*d;d 3*d;3*d 3*d;-3*d d;-d d;d d;3*d d;-3*d -d;-d -d;d -d;3*d -d;-3*d -3*d;-d -3*d;d -3*d;3*d -3*d];
for i=1:length(bitdata)/4;qam_data(i,:) = mapping(source(i),:);   %数据映射
end
complex_qam_data=complex(qam_data(:,1),qam_data(:,2));
%组合为复数形式,形成16QAM信号

rcoswindow.m

%窗函数子程序,子程序名称:rcoswindow.m
function [rcosw] = rcoswindow(beta,Ts)
%输入参数:beta为升余弦窗滚降系数,Ts为IFFT长度加循环前缀长度
t=0:(1+beta)*Ts;
rcosw = zeros(1,(1+beta)*Ts);
%计算升余弦窗,共有三部分
for i=1:beta*Ts;rcosw(i)=0.5 + 0.5*cos(pi + t(i)*pi/(beta*Ts));  %计算升余弦窗第一部分
end
rcosw(beta*Ts+1:Ts) = 1;   %计算升余弦窗第二部分
for j=Ts + 1:(1+beta)*Ts + 1;rcosw(j-1) = 0.5*cos((t(j) - Ts) * pi/(beta*Ts));%计算升余弦第三部分
end
rcosw = rcosw';  %转换为列矢量

下面是仿真图:

OFDM信号的产生与解调相关推荐

  1. matlab产生ofdm信号,Matlab 完成简单的OFDM 信号的产生与解调程序.pdf

    Matlab 完成简单的OFDM 信号的产生与解调程序实验研究 OFDM(Orthogonal Frequency Division Multiplexing)即正交频分复用技 术,实际上OFDM是M ...

  2. 光纤非线性效应对光OFDM信号的影响研究

    光正交频分复用(Optical Orthogonal Frequency Di-vision Multiplexing,O-OFDM)技术是近年来出现的一种新型光传输技术,它是将正交频分复用(Orth ...

  3. matlab调频解调,(很实用,很好)用MATLAB实现信号的调制与解调调频调相等

    <(很实用,很好)用MATLAB实现信号的调制与解调调频调相等>由会员分享,可在线阅读,更多相关<(很实用,很好)用MATLAB实现信号的调制与解调调频调相等(7页珍藏版)>请 ...

  4. 2FSK频谱matlab,2FSK信号的频谱分析及解调的实现.doc

    <数字信号处理> 课程设计报告 题 目:2FSK信号的频谱分析及解调的实现 专 业: 信息与计算科学 学 号: 组 长: 指导教师: 成 绩: 2010年1月8日 2FSK信号的频谱分析及 ...

  5. 《通信原理》AM/DSBSC/SSB信号的调制与解调仿真

    一.实验内容 利用matlab实现以下内容: 1.信号的调幅.根据随机产生的整数和已知条件来计算: (1)AM.DSBSC.SSB信号的消息信号和已调信号的频谱: (2)AM.DSBSC.SSB信号的 ...

  6. matlab相干解调,心电信号的调制与解调(AM调制、相干解调)

    陈超 11108125 一. 系统构思: 1).通信原理课程介绍了模拟信号的调制与解调.调制可以实现将低频信号频谱搬移到载频位置,解调相当于 调制的反过程. 2).调制和解调的应用举例:3.4kHZ的 ...

  7. 《通信原理》课程设计-基于matlab的am信号的调制与解调,AM调制解调与解调器抗干扰性能研究系统...

    <AM调制解调与解调器抗干扰性能研究系统>由会员分享,可在线阅读,更多相关<AM调制解调与解调器抗干扰性能研究系统(10页珍藏版)>请在人人文库网上搜索. 1.哈尔滨商业大学课 ...

  8. 上行ofdm 信号生成_在lte-a中用信号发送上行链路控制信息的制作方法

    在lte-a中用信号发送上行链路控制信息的制作方法 [专利说明]在LTE-A中用信号发送上行链路控制信息 [0001] 本申请是申请日为2010年06月18日.申请号为201080035916.0.名 ...

  9. OFDM信号是一种广泛应用的调制技术,其优点在于比传统的单载波调制技术具有更好的频谱利用率和抗干扰性能。然而,OFDM信号的峰均功率比(PAPR)问题一直是制约...

    OFDM信号是一种广泛应用的调制技术,其优点在于比传统的单载波调制技术具有更好的频谱利用率和抗干扰性能.然而,OFDM信号的峰均功率比(PAPR)问题一直是制约其应用的主要障碍之一.在本文中,我们将讨 ...

  10. HackRF-AIS信号的采集与解调

    目录 AIS信号采集与解调 1.硬件设备 2.系统准备 3.软件准备 4.进行实验(需要去有船只经过的江边才能采集到信号,本次实验于重庆长江边进行) 5.AIS信息解译 6.AIS解调后数据源可去以下 ...

最新文章

  1. 【某小学生作文】《我的爸爸是名驾驶员》
  2. 清华大学施路平:发展人工通用智能最好的时机到了!
  3. 新浪api 40022错误
  4. C语言实现上三角蛇形矩阵不用数组,C/C++编程笔记:C++ 嵌套循环,含循环打印及蛇形矩阵实例...
  5. 机器学习——01、机器学习的数学基础1 - 数学分析
  6. LeetCode之Add Two Numbers
  7. c# datetime._C#| DateTime.GetHashCode()方法与示例
  8. RSS、Atom和Feed概念与实现(django)
  9. (转) RabbitMQ学习之发布/订阅(java)
  10. Spring Boot:在Spring Boot中使用定时任务
  11. pptx库ppt演示 python_详解 Python 操作 PPT 的各种骚操作!
  12. c51汇编语言循环指令,汇编语言循环指令loop
  13. 【解决:Failed to execute goal org.apache.tomcat.maven:tomcat7-maven-plugin:2....Could not star】
  14. unity5.x游戏开发指南示例下载
  15. jemalloc疑似内存泄漏分析
  16. 提问的力量四:提问的艺术-体验学习中提问的技巧
  17. Postgresql源码(41)plpgsql函数编译执行流程分析
  18. 转:Beautiful Soup
  19. 博士最惨能惨到什么程度?
  20. Vue全家桶+MongoDB+Koa2全栈开发网站

热门文章

  1. 数据库update多条数据
  2. 算法与数据结构王道天勤_计算机考研专业课 天勤和王道应该如何选择呢 或者说二者的区别是什么?...
  3. Linux命令之du命令
  4. 直角三角公式计算机,直角三角形
  5. 快闪视频快影_快闪的12个步骤!
  6. oracle 如何锁定表,oracle中表的锁定
  7. Netd 服务注册过程(Android 10)
  8. lwj_C#_泛型使用
  9. 1、PCB常用走线宽度
  10. JAVA 大文件压缩极速下载