OFDM技术的思想是将指配的信道分成许多正交子信道,在每个子信道上进行窄带调制和传输,信号带宽小于信道的相关带宽。OFDM单个用户的信息流被串/并变换为多个低速率码流(100Hz-50kHz),每个码流用一条载波发送。OFDM采用跳频方式选用即便频谱混叠也能保持正交的波形,所以OFDM既有调制技术,也有复用技术。OFDM增强了抗频率选择性衰落和抗窄带干扰的能力。在单载波系统中,单个衰落或干扰会导致整条链路不可用,但在多载波系统中,只会有一小部分载波受影响。纠错码的应用可以恢复一些易错载波上的信息。 OFDM允许各载波间频率互相混叠,采用基于载波频率正交的FFT调制,由于各个载波的中心频点处没有其他载波的频谱分量,所以能够实现各个载波的正交。
流程图如上,这里不做太多介绍。
1.串行数据产生
首先对图像文件进行数据处理, 系统输入数据信号的长度是根据子载波的个数及每帧的符号的个数确定的,通过round()对产生的图像所生成的序列四舍五入取整。
imdata = imread('11.jpg');
BinSer=dec2bin(imdata,8);
BinSer=BinSer';
FileName=[num2str(size(imdata,1)),'_',num2str(size(imdata,2)),'_',num2str(size(imdata,3)),'.txt'];
fid=fopen(FileName,'w');
fprintf(fid,'%c',BinSer(:));
fclose(fid);
FileName='256_256_3.txt'; %文件名为上述生成的文件名
mn1=sscanf(FileName,'%d_%d_%d');
fid=fopen(FileName,'r');
datainput=fscanf(fid,'%c');
fclose(fid);
c=double(datainput);
for i=1:length(datainput)
c(i)=str2num(char(c(i)));
end
%-------------------------发送端-------------------------------------%
for g=1:SNRnum
Signal=round(c);
2.串并\并串转换
OFDM系统是多载波传输的一种特殊方式,而发送端产生的数据为串行的,因此需要进行串并转换。OFDM将高速输入的串行数据比特流转换成并行传输的低速数据流,而且串并转换之后会提高系统的抗干扰能力。串并转换的实现方法很多,在matlab里reshape用来把指定的矩阵改变形状,但是元素个数不变,在本程序中采用reshape函数来实现串并转换。
同样如果对信号进行了串并转换,那么当发送信号和接收信号时,也需对其进行并串转换。在本程序中并串转换也采用了reshape函数来实现。下面是实现串并及并串转换的语句。
SubCarryNdata=reshape(encode,SubCarryN,SymbN*2) %串并转换
ich4=reshape(ich3,1,(fftLen+GuardLen)*SymbN); %并串转换
qch4=reshape(qch3,1,(fftLen+GuardLen)*SymbN);
3.卷积编码与维特比译码
卷积编码作为一种信道编码,具有前向纠错的功能。通过对信号进行卷积编码,对信号增加冗余。当信号在信道传输时,会大大降低误码率。卷积编码的实现方法也很多,在matlab中有卷积编码函数,本程序直接调用了convenc函数。实现卷积编码如下:
trel=poly2trellis(9,[561 753]); %设置网格图
encode=convenc(Signal,trel);
在卷积编码前需要对卷积编码设置网格图,此约束长度为9,此网格图设置可以实现卷积编码后,信号实现一进二岀。产生卷积编码信号如下图。
可以看出原始序列通过卷积编码后,产生一个其长度2倍的序列。
使用卷积编码通常会使用维特比译码来进行译码。使用维特比译码是通常会定义译码深度、量化电平及量化等级,在matlab中维特比译码函数为vitdec。程序具体实现如下:
parti=0:.15:.9;
codebk=0:7;
[x,qcode]=quantiz(ReSig,parti,codebk);
decode= vitdec(qcode',trel,declen,'cont','soft',3);
维特比译码后的信号图如下:
4.QPSK调制与解调
信号的调制方式有多种,可以通过改变发射的射频信号的幅度、相位和频率来调制信号。对于OFDM系统来说,只能采用前两种方法,而不能采用频率的调制方法。因为子载波是频率正交,并且携带独立的信息调制子载波频率会破坏这些子载波的正交特性。QPSK调制方案能等量调制,不会由于星座点的能量不等而为OFDM系统带来PAPR较大的问题。 QPSK调制的方法有两种:一种是数字方法,另一种是相位选择法。本程序中选择的是利用数字的方法来调制信号。
QPSK调制程序如下:
function [iout,qout]=qpskmod(paradata,para,nd,ml)
m2=ml./2;
paradata1=paradata.*2-1;
count2=0;
for k=1:nd
isi = zeros(para,1);
isq = zeros(para,1);
for L = 1 : m2
isi = isi + 2.^ ( m2 - L ) .* paradata1((1:para),L+count2);
isq = isq + 2.^ ( m2 - L ) .* paradata1((1:para),m2+L+count2);
end
iout((1:para),k)=isi;
qout((1:para),k)=isq;
count2=count2+
在进行解调之前信号要完成去掉保护间隔和进行FFT运算的任务。去掉保护间隔也就可以去掉符号间的干扰。解调程序如下:
function [data]=QPSKjietiao(idata,qdata,para,nd,ml)
data=zeros( para,ml*nd );
data((1:para),(1:ml:ml*nd-1))=idata((1:para),(1:nd))>=0;
data((1:para),(2:ml:ml*nd))=qdata((1:para),(1:nd))>=0;
保护间隔
在OFDM系统中,保护间隔是一种循环复制增加了符号的波形长度,在符号的数据部分每一个子载波内有一个整数倍的循环,此种符号的复制产生了一个循环的信号,即将每个OFDM符号的后一段时间的样点复制到OFDM符号的前面,形成前缀。在交接点没有任何的间断。保护间隔的长度的大小是根据给定的系统的设计参数来确定的,为了最大限度的减小由于插入保护比特带来的信噪比损失。在matlab里采用一些特殊运算符号和矩阵的应用就可实现在信号前添加保护间隔。实现程序如下:
ich3=[ich2(fftLen-GuardLen+1:fftLen,:);ich2];
qch3=[qch2(fftLen-GuardLen+1:fftLen,:);qch2];
主要通过比较发送端和接收端的信号是否相同,用errbit来计算错误的个数,在没有接到信号的时候errbit设置为0,是通过发送信号的每一位和接收信号的每一位进行比较,同errbit就加1。用错误的个数errbit和信号的长度SignalLen的比值就是误码率BER。具体实现为:
errbit=sum(abs(ReSig-encode)); %误码个数
encodenum=length(encode); %总共码长
BER(g)=errbit/encodenum %误码率
d(SNR(g))=BER(g);
decode2=decode1(declen+1:end);
Signal2=Signal(1:end-declen);
errbit1=sum(abs(decode2-Signal2));
BER1(g)=errbit1/SignalLen
e(SNR(g))=BER1(g);
未卷积前信号的误码率曲线如图:
卷积后信号的误码率曲线如图:
结果图像输出:
结果可看出,该系统传输出的图像基本没有失真,经卷积编码后误码率明显降低,所以OFDM系统中卷积也是不可确少的。
主程序:
clear all;
close all;
clc;
%---------------------------------------------------------------------%
% OFDM收发信机的设计
% 说明:本程序为主程序,调用了QPSKtiaozhi和QPSKjietiao子函数
%---------------------------------------------------------------------%
%--------------------------参数设置-----------------------------------%
fftLen=512; %设置FFT长度
SymbN=64*3*16; %设置一个帧结构中OFDM信号的个数
SubCarryN=512; %设置并行传输的子载波个数
GuardLen=32; %保护时隙的长度
SNR= 1:1:11; %信噪比
SNRnum=length(SNR); %信噪比数目
SignalLen=SubCarryN*SymbN; %发送信号长度
declen=40; %译码深度
%--------------------------------------------------------------------%
imdata = imread('11.jpg');
BinSer=dec2bin(imdata,8);
BinSer=BinSer';
FileName=[num2str(size(imdata,1)),'_',num2str(size(imdata,2)),'_',num2str(size(imdata,3)),'.txt'];
fid=fopen(FileName,'w');
fprintf(fid,'%c',BinSer(:));
fclose(fid);
FileName='256_256_3.txt'; %文件名为上述生成的文件名
mn1=sscanf(FileName,'%d_%d_%d');
fid=fopen(FileName,'r');
datainput=fscanf(fid,'%c');
fclose(fid);
c=double(datainput);
for i=1:length(datainput)
c(i)=str2num(char(c(i)));
end
%-------------------------发送端-------------------------------------%
for g=1:SNRnum
%Signal=round(rand(1,SubCarryN*SymbN)); %产生随机序列
Signal=round(c);
trel=poly2trellis(9,[561 753]); %设置网格图
encode=convenc(Signal,trel); %卷积编码
SubCarryNdata=reshape(encode,SubCarryN,SymbN*2); %串并转换
[ich,qch]=QPSKtiaozhi(SubCarryNdata,SubCarryN,SymbN,2); %QPSK调制,调用子函数
kmod=1./sqrt(2);
ich1=ich.*kmod;
qch1=qch.*kmod;
qpskx=ich1+qch1.*sqrt(-1); %频域数据变时域
fy=ifft(qpskx); %对信号作IFFT
ich2=real(fy);
qch2=imag(fy);
%-----------------------------------------------------------------%
%---------------------插入保护间隔---------------------------------%
ich3=[ich2(fftLen-GuardLen+1:fftLen,:);ich2];
qch3=[qch2(fftLen-GuardLen+1:fftLen,:);qch2];
ich4=reshape(ich3,1,(fftLen+GuardLen)*SymbN); %并串转换
qch4=reshape(qch3,1,(fftLen+GuardLen)*SymbN);
TrData=ich4+qch4.*sqrt(-1); %形成复数发射数据
%-----------------------------------------------------------------%
%----------------------加入高斯白噪声------------------------------%
ReData=awgn(TrData,SNR(g),'measured');
%------------------------接收端 -----------------------------------%
%----------------------移去保护间隔--------------------------------%
idata=real(ReData);
qdata=imag(ReData);
idata1=reshape(idata,fftLen+GuardLen,SymbN);
qdata1=reshape(qdata,fftLen+GuardLen,SymbN);
idata2=idata1(GuardLen+1:GuardLen+fftLen,:);
qdata2=qdata1(GuardLen+1:GuardLen+fftLen,:);
Rex=idata2+qdata2.*sqrt(-1); % FFT
ry=fft(Rex);
ReIChan=real(ry);
ReQChan=imag(ry);
ReIchan=ReIChan/kmod;
ReQchan=ReQChan/kmod;
ReSubCarryN=QPSKjietiao(ReIchan,ReQchan,SubCarryN,SymbN,2); %QPSK解调 ,调用子函数
ReSig=reshape(ReSubCarryN,1,SubCarryN*SymbN*2); %接收端信号
%-----------------------------------------------------------------%
%---------------------维特比译码-----------------------------------%
parti=0:.15:.9;
codebk=0:7;
[x,qcode]=quantiz(ReSig,parti,codebk);
decode= vitdec(qcode',trel,declen,'cont','soft',3);
decode1=reshape(decode,1,SignalLen);
%----------------------误码率----------------------------------------%
errbit=sum(abs(ReSig-encode)); %误码个数
encodenum=length(encode); %总共码长
BER(g)=errbit/encodenum %误码率
d(SNR(g))=BER(g);
decode2=decode1(declen+1:end);
Signal2=Signal(1:end-declen);
errbit1=sum(abs(decode2-Signal2));
BER1(g)=errbit1/SignalLen
e(SNR(g))=BER1(g);
end
%----------------------------------------------------------------%
%-----------------------输出结果---------------------------------%
%图一输入信号与卷积后信号
figure(1);
subplot(211);stem(Signal(1:40),'b'),grid;
title('输入的信号');
subplot(212),stem(encode(1:80),'b'),grid;
title('卷积编码后的信号');
%图二QPSK星座映射
figure(2);
plot(ReIChan,ReQChan,'o'),grid;
ylabel('正交分量'),xlabel('同相分量');
title('接收端的QPSK星座映射');
%图三接收信号与维特比译码后的信号
figure(3);
subplot(211);stem(Signal(1:40),'b'),grid;
title('接收到的信号');
subplot(212),stem(decode(1:80),'b'),grid;
title('维特比译码后的信号');
%图四误码率分析
figure(4);
semilogy(d,'bo-')
%hold on
%semilogy(e,'ro-')
xlabel('信噪比(dB)');
ylabel('误码率');
title('误码率曲线')
grid on
%卷积完误码率曲线
figure(5);
semilogy(e,'r*-'),grid;
%axis([0,4])
ylabel('误码率'),xlabel('信噪比');
title('卷积后误码率曲线');
%--------------------------------------------------------------%
FileName=[num2str(64),'_',num2str(64),'_',num2str(3),'.txt'];
fid=fopen(FileName,'w');
%BinSer=dec2bin(imdata,8);
%BinSer=BinSer';
dataoutput=num2str(decode1);
datareal=strrep(dataoutput,' ','');
%fprintf(fid,'%c',BinSer(:));
fprintf(fid,'%c',datareal);
fclose(fid);
clear all
FileName='256_256_3.txt'; %文件名为上述生成的文件名
mn=sscanf(FileName,'%d_%d_%d');
M=mn(1);
N=mn(2);
K=mn(3);
fid=fopen(FileName,'r');
data=fscanf(fid,'%c');fclose(fid);
data1=reshape(data,8,length(data)/8);
data2=reshape(bin2dec(data1'),M,N,K);
figure(7);
imshow(uint8(data2));
子函数:
%-----------------------------------------------------------%
% QPSK调制前函数
%-----------------------------------------------------------%
function [iout,qout]=qpskmod(paradata,para,nd,ml)
m2=ml./2;
paradata1=paradata.*2-1;
count2=0;
for k=1:nd
isi = zeros(para,1);
isq = zeros(para,1);
for L = 1 : m2
isi = isi + 2.^ ( m2 - L ) .* paradata1((1:para),L+count2);
isq = isq + 2.^ ( m2 - L ) .* paradata1((1:para),m2+L+count2);
end
iout((1:para),k)=isi;
qout((1:para),k)=isq;
count2=count2+ml;
end
%----------------------------------------------------------------------%
% QPSK解调函数
%----------------------------------------------------------------------%
function [data]=QPSKjietiao(idata,qdata,para,nd,ml)
data=zeros( para,ml*nd );
data((1:para),(1:ml:ml*nd-1))=idata((1:para),(1:nd))>=0;
data((1:para),(2:ml:ml*nd))=qdata((1:para),(1:nd))>=0;