OFDM信号的产生与解调
(1)通过对OFDM信号各个子载波赋共轭对称的数据产生一个实OFDM符号
(2)给OFDM符号加循环前缀与循环后缀
(3)给OFDM符号加窗。在程序中加入的是升余弦窗的滚降系数,观察加入不同升余弦窗对OFDM信号频谱的影响
(4)信道采用加性高斯白噪声信道,可以通过改变信噪比改变信道环境,从而在接收端通过误码率或星座图观察信道对OFDM信号传输的影响
(5)去除循环前缀与循环后缀,对OFDM信号进行解调
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));%floor函数:朝负无穷大方向取整
%(floor(IFFT_bin_length/4)-floor(carrier_count/2)=28
%计算OFDM符号子载波的序号,carriers中存放的序号是29~228
conjugate_carriers=IFFT_bin_length-carriers-2;
%计算OFDM符号子载波的序号,conjugate_carriers中存放的序号是282~481
rand('twister',0);%rand函数(用于产生随机数) twister产生非重复的随机数
baseband_out=round(rand(1,baseband_out_length));%round函数用于舍入到最接近的整数 注:round(2.5) = 3;
%产生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)';% A = reshape(A,m,n)将A 的行列排列成m行n列
%转换complex_carrier_matrix中的数据为carrier_count*symbols_per_carrier矩阵,这里为200*20矩阵
figure(1);
plot(complex_carrier_matrix,'*r');%绘制16QAM星座图
axis([-4,4,-4,4]);
title('16QAM调制后星座图');
grid on;%grid on是matlab中的一种函数,表示在画图的时候添加网格线 。
%IFFT,即进行OFDM调制
IFFT_modulation=zeros(symbols_per_carrier,IFFT_bin_length);%matlab中zeros函数是用于返回一个double类零矩阵
%将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~228子载波赋值
IFFT_modulation(:,conjugate_carriers)=conj(complex_carrier_matrix);%conj函数:用于计算复数的共轭值
%将20*200的complex_carrier_matrix的数据赋给512个子载波中的第282~481个子载波,这段程序构造了512个子载波的OFDM符号,并且各个子载波上的
%数据是共轭对称的。这样做的目的是经过IFFT后形成的OFDM符号均为实数。另外,在512个子载波中,仅有400个子载波为数据,其余为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('幅度');
xlabel('时间');
title('一个周期的OFDM信号时域波形');
%添加循环前缀与循环后缀
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);
end
for i=1:GI
XX(k,i)=signal_after_IFFT(k,i+IFFT_bin_length-GI);
%添加循环前缀
end
for 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('幅度');
xlabel('时间');
title('带循环前缀与循环后缀的一个周期的OFDM信号时域波形');
%OFDM符号加窗
windowed_time_wave_matrix_cp=zeros(1,IFFT_bin_length+GI+GIP);
for i=1:symbols_per_carrier
windowed_time_wave_matrix_cp(i,:)=real(time_wave_matrix_cp(i,:)).*rcoswindow(beta,IFFT_bin_length+GI)';%real函数:求复数的实部
%调用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('幅度');
xlabel('时间');
title('加窗的带循环前缀与循环后缀的一个周期的OFDM信号时域波形');
%生成发送信号,并串转换
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,:);
%赋第一个加窗带循环前缀后缀的OFDM符号至windowed_Tx_data,即发送串行数据
for i=1:symbols_per_carrier-1
windowed_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_time1=(symbols_per_carrier)*(IFFT_bin_length+GI+GIP);
%加窗,循环前缀与循环后缀不重叠数据长度,即为发送的总数据比特数
figure(5);
subplot(2,1,1);
plot(0:temp_time1-1,Tx_data);
%画循环前缀与循环后缀不重叠相加OFDM信号的时域波形
grid on;
ylabel('幅度');
xlabel('时间');
title('循环前缀与循环后缀不重叠相加OFDM符号');
temp_time2=symbols_per_carrier*(IFFT_bin_length+GI)+GIP;
%加窗,循环前缀与循环后缀重叠相加数据长度
subplot(2,1,2);
plot(0:temp_time2-1,windowed_Tx_data);
%画循环前缀与循环后缀重叠相加OFDM信号的时域波形
grid on;
ylabel('幅度');
xlabel('时间');
title('循环前缀与循环后缀重叠相加OFDM符号');
%未加窗发送信号频谱
%对发送数据分段,分段计算频谱,取平均作为OFDM信号的频谱
symbols_per_average=ceil(symbols_per_carrier/5);
avg_temp_time=(IFFT_bin_length+GI+GIP)*symbols_per_average;
average_temp_time=(IFFT_bin_length+GI+GIP)*symbols_per_average;
averages=floor(temp_time1/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);%取平均
end
average_fft_log=20*log10(average_fft);%求对数平均谱
figure(6);
subplot(2,1,1);
plot((0:(avg_temp_time-1))/avg_temp_time,average_fft_log);
%画未加窗OFDM符号对数平均谱
hold on;
grid on;
axis([0 0.5 -20 max(average_fft_log)]);
ylabel('频域幅度(dB)');
xlabel('归一化频率(0.5=fs/2)');
title('OFDM信号的频谱');
%计算加窗OFDM信号的频谱
%这段程序与上段程序类似,不同之处在于这段程序是对加窗OFDM信号进行分段计算频谱,再取平均
symbols_per_average=ceil(symbols_per_carrier/5);
avg_temp_time=(IFFT_bin_length+GI+GIP)*symbols_per_average;
averages=floor(temp_time1/avg_temp_time);
%将发送数据分5段,每段数据长度为avg_temp_time
average_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);%取平均
end
average_fft_log=20*log10(average_fft);%求对数平均谱
subplot(2,1,2);
plot((0:(avg_temp_time-1))/avg_temp_time,average_fft_log);
%画加窗OFDM信号对数平均谱
hold on;
grid on;
axis([0 0.5 -20 max(average_fft_log)]);
ylabel('频域幅度(dB)');
xlabel('归一化频率(0.5=fs/2)');
title('加窗的OFDM信号频谱');
%经过加性高斯白噪声信道
Tx_signal_power=var(windowed_Tx_data);%计算信号功率 var返回为计算方差
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_carrier
Rx_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:IFFT_bin_length+GI);
%去掉循环前缀与循环后缀,取出OFDM符号传输的数据
Y1=fft(Rx_data_complex_matrix,IFFT_bin_length,2);
%求FFT,即OFDM信号解调
Rx_carriers=Y1(:,carriers);
%取出carries序号对应的子载波上的发送数据,去掉加入的零及共轭对称部分
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;%计算误码率
%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:4
X1(i,j)=X1(i,j)*(2^(4-j));
end
source(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
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+0.5*cos((t(j)-Ts)*pi/(beta*Ts));
%计算升余弦窗第三部分
end
rcosw =rcosw';%转换为列矢量
%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
[~, decode_symble(i)]=min(metrics);
%将接收数据与标准16QAM信号比,找到差最小的,将其对应恢复成标准的16QAM信号
end
decode_bit_symble=de2bi((decode_symble-1)','left-msb');%de2bi函数被用于将十进制数字转化为二进制数。且转化后结果矩阵的每一行都与
%原输入矩阵中的元素相对应。
%16QAM转为二进制
demodu_bit_symble=reshape(decode_bit_symble',1,length(Rx_serial_complex_symbols)*4);%转换为一行
第7张图和给的实例不一样,不建议参考。
参考《MIMO-OFDM系统原理、应用及仿真》一书