OFDM技术是HPA联盟(HomePlug Powerline Alliance)工业规范的基础,它采用一种不连续的多音调技术,将被称为载波的不同频率中的大量信号合并成单一的信号,从而完成信号传送。由于这种技术具有在杂波干扰下传送信号的能力,因此常常会被利用在容易受外界干扰或者抵抗外界干扰能力较差的传输介质中。
百度百科:OFDM
参考书籍:MIMO-OFDM Wireless Communications with MATLAB
书上代码都有了……
2015年带几个本科生做的课程设计就是这个。
任务(2015年10月10日10:57:49)
我猜其实你们是不愿意做什么课程设计的,所以我特意选了个简单的。(见下面红字)
参考书籍:《MIMO-OFDM Wireless Communications with MATLAB》第4-6章
第4章OFDM简介
第5章 OFDM同步
第6章 OFDM信道估计
自学4-6章。
OFDM系统框图如下。
对于Matlab编程的说明。
(1)最低要求。第4章,明白为什么要用OFDM。编出一个最简单的OFDM系统,画出发射、接收的星座图。计算误码率。
调制格式为QPSK。信源发出数据,星座图映射,S/P,IFFT,加CP。传输。加信道(AWGN或瑞利)。加噪声(AWGN)。接收。恢复。
(2)稍高层次的要求。自己设置定时误差、频率偏移。并恢复。
(3)更高层次的要求。加信道均衡。
各个流程的代码几!乎!都!有!了!
大家都争取自己写一写,每人写一点点,拼一个较完整的OFDM的Matlab仿真程序。
最后做PPT的话,看你们代码完成程度。
仿真Eb/N0从x dB到y dB时,QPSK-OFDM系统的误比特率性能。
伪代码如下。
开始。
0. 对于一个给定的信噪比Eb/N0
1. 产生二进制序列(信源)
2. QPSK星座点格雷映射
3. 串行数据转并行数据
4. IFFT
5. 加入循环前缀CP
6. 并行数据转串行数据,形成OFDM信号
7. 计算OFDM信号的功率
8. 根据0.中的信噪比和由7.得出的OFDM信号功率,计算噪声功率
9. 产生AWGN,均值为0,方差为8.中计算得到的噪声功率
10. 向6.中的OFDM信号加入AWGN
11. 去掉5.加入的循环前缀
12. 串行数据转并行数据
13. FFT,即4.的逆变换
14. 并行数据转串行数据
15. 根据QPSK星座点格雷映射,由接收到的符号判决输出二进制序列,即2.的逆操作
16. 与1.中的原始二进制序列对比,统计错误的比特数,计算误码率
17. 改变0.中的Eb/N0,重复1-16
结束。
仿真Eb/N0从x dB到y dB时,QPSK-OFDM系统的误比特率性能。
伪代码如下。
开始。
0. 对于一个给定的信噪比Eb/N0
1. 产生二进制序列(信源)
2. QPSK星座点格雷映射
3. 串行数据转并行数据
4. IFFT
5. 加入循环前缀CP
6. 并行数据转串行数据,形成OFDM信号
7. 计算OFDM信号的功率
8. 根据0.中的信噪比和由7.得出的OFDM信号功率,计算噪声功率
9. 产生AWGN,均值为0,方差为8.中计算得到的噪声功率
10. 向6.中的OFDM信号加入AWGN
11. 去掉5.加入的循环前缀
12. 串行数据转并行数据
13. FFT,即4.的逆变换
14. 并行数据转串行数据
15. 根据QPSK星座点格雷映射,由接收到的符号判决输出二进制序列,即2.的逆操作
16. 与1.中的原始二进制序列对比,统计错误的比特数,计算误码率
17. 改变0.中的Eb/N0,重复1-16
结束。
注。有人始终纠结,这到底是频域符号还是时域信号。
这个无所谓啊!傅里叶变换前后本来就是同一个东西-_-!!
有人非要说,ifft之前是频域的。我也是⊙﹏⊙b汗。
那我问你,如果x是时域,X = fft(x),那X是频域了吧。那继续fft呢?Y = fft(X)。呵呵…
啥啥啥时域对偶,等距同构……数学学好了再说话。数学这么烂,搞什么自然科学?
尽管网上代码一抓就是一大把,我还是再贴一个版本上来。
Main函数
%% 基本QPSK-OFDM
% 不用VC,加CP。
% QPSK使用gray码
% 书上p.115
% AWGN信道,循环前缀,QPSK
% 开始时间:2015年10月13日12:44:48
% 版本编号:v1.1
% 整体思路:
% 1、算信号功率 (自己循环N_iter次)
% 2、根据1的结果算噪声幅度
% 3、再产生信号+噪声
% 4、判决,计算错误比特数
% (3和4循环N_iter次)
clear;
close all;
clc
EbN0_dB = 0:1:25;
N_iter = 1e3; % 重复N_iter次试验 1e3基本就可以了。
% 1e5相当准确了。但是等待的时间很漫长。matlab解释执行,慢。
Nbps = 2;
N_LEVEL = 2^Nbps; % QPSK 调制阶数
Nfft = 64;
Nvc = 0;
Nused = Nfft - Nvc; % 不用虚拟载波
Ng = Nfft/4;
Nsym = Nfft + Ng;
Nframe = 3; %每一帧的符号数?? 还是仿真的帧数??
symbol_total = Nfft * Nframe; % 一次仿真信源输出的所有码元总数
x_GI = complex(zeros(Nsym * Nframe,1),0);
Y = complex(zeros(symbol_total,1),0);
% gray_r = zeros(symbol_total,1); % 收到的格雷码
symbol_output = zeros(symbol_total,1);
bers = zeros(size(EbN0_dB));
%% 1、计算信号功率(只需计算一次)
% 思路:用很长一段信号的能量 除以 采样点的个数 可以得 时间平均的功率
sigEng = 0; %信号能量
for m = 1:N_iter
symbol = randi(N_LEVEL,symbol_total,1) - 1; % 信源发出的码元总数,不是二进制的个数
graycode = symbol;
% 将码元编为gray码 (对于QPSK,就是把3和2换一下位置)
index_3 = find(symbol==3);
index_2 = find(symbol==2);
graycode(index_3) = 2;
graycode(index_2) = 3;
data_QPSK = exp(1j * graycode* pi/2 + 1j * pi/4); % 映射为QPSK信号星座点 scatterplot(data_QPSK);
for k = 1:Nframe %处理每一帧的数据 S/P Nframe个串行的转成1帧
kk1 = (k-1) * Nfft + (1:Nfft);
kk2 = (k-1) * Nsym + (1:Nsym);
X = data_QPSK(kk1);
x = ifft(X);
x_GI(kk2) = guard_interval(Ng,Nfft,x);
end
sigEng = sigEng + x_GI' * x_GI; %共轭转置
end
% 信号功率
sigPow = sigEng/Nsym/Nframe/N_iter;
%% 2、计算噪声幅度
snrs = EbN0_dB + 10 * log10(Nbps*(Nused/Nfft)); % 时域信噪比 SNRt
noise_mags = sqrt((10.^(-snrs/10))*sigPow/2); % dB换算为线性刻度
%% 3、再产生信号,并加入噪声
for k_EbN0 = 1:length(EbN0_dB)
ber_count = 0; % 初始化 误bit数
for m = 1:N_iter
% Info Source & Mod
symbol = randi(N_LEVEL,symbol_total,1) - 1; % 信源
graycode = symbol;
% 将码元编为gray码 (对于QPSK,就是把3和2换一下位置)
index_3 = find(symbol==3);
index_2 = find(symbol==2);
graycode(index_3) = 2;
graycode(index_2) = 3;
data_QPSK = exp(1j * graycode* pi/2 + 1j * pi/4); % 映射为QPSK信号星座点 scatterplot(data_QPSK);
% scatterplot(data_QPSK); 【注意】千万不要在整个for循环里面画图!卡爆!要单步运行,看一看即可。
% title('QPSK X 频域信号');
% grid on;
% Tx
for k = 1:Nframe %处理每一帧的数据 S/P Nframe个串行的转成1帧
kk1 = (k-1) * Nfft + (1:Nfft);
kk2 = (k-1) * Nsym + (1:Nsym);
X = data_QPSK(kk1); % 每次循环,X的值在变
x = ifft(X);
x_GI(kk2) = guard_interval(Ng,Nfft,x);
end
% Channel
y = x_GI;
% AWGN 【注意】实部和虚部是独立的!所以要randn两次
noise_mag = noise_mags(k_EbN0);
complex_noise = noise_mag * (randn(size(y))+1j*randn(size(y))); % y(t) + noise(t)
y_GI = y + complex_noise;
% Rx
for k = 1:Nframe % 这应该是Nframe帧吧!就是一共发了这么多帧。并行以后还有Nframe个
kk2 = (k-1) * Nsym + (1:Nsym);
kk1 = (k-1) * Nfft + (1:Nfft);
Y(kk1) = fft(remove_GI(Ng,Nsym,y_GI(kk2)));
end
% % 在这里可以看收到信号的星座图 %scatterplot(Y);
% 【注意】千万不要在整个for循环里面画图!会卡爆的!要单步运行,看一看即可。
% if m == 1
% scatterplot(Y);
% grid on;
% plot_title = ['E_b/N_0 = ' num2str(EbN0_dB(k_EbN0)) ' dB'];
% title(plot_title);
% end
% DeMod
% 解调(其实就是去映射,因为没有放到高频上去) 判决
y_real = real(Y); % 向量操作!节省时间!
y_imag = imag(Y); % 向量操作!
% scatterplot(Y);
% 判决
% 判决:直接将格雷码判决为自然数
for n = 1:symbol_total
r_value = y_real(n);
i_value = y_imag(n);
if r_value > 0 && i_value >0
symbol_output(n) = 0;
elseif r_value < 0 && i_value < 0
symbol_output(n) = 3;
elseif r_value < 0 && i_value > 0
symbol_output(n) = 1;
else
symbol_output(n) = 2;
end
end
% ber_count = ber_count + sum(nnz(data_output~=symbol));
% 计算BER
% 1.找出 收到的格雷码 和 原始的 格雷码 不同的index
% 2.对于每一个不同的 格雷码符号,看错成了哪个,再累计错了几位
error_index = find(symbol_output~=symbol);
for error_k = 1:length(error_index)
k_temp = error_index(error_k);
error_v = symbol_output(k_temp);
origin_v = symbol(k_temp);
% 0 --> 1 或 0 --> 2 错了1位
% 0 --> 3 错了2位
if origin_v == 0
if error_v == 1 || error_v == 2
ber_count = ber_count + 1;
else
ber_count = ber_count + 2;
end
% 1 --> 0 或 1 --> 3 错了1位
% 1 --> 2 错了2位
elseif origin_v == 1
if error_v == 0 || error_v == 3
ber_count = ber_count + 1;
else
ber_count = ber_count + 2;
end
% 2 --> 0 或 2 --> 3 错了1位
% 2 --> 1 错了2位
elseif origin_v == 2
if error_v == 0 || error_v == 3
ber_count = ber_count + 1;
else
ber_count = ber_count + 2;
end
% 3 --> 1 或 3 --> 2 错了1位
% 3 --> 0 错了2位
else
if error_v == 1 || error_v == 2
ber_count = ber_count + 1;
else
ber_count = ber_count + 2;
end
end
end
end
% 总的比特数是多少?!!!! QPSK!!! 每个符号2个比特!!
ber = ber_count/symbol_total/N_iter/2; %ber (平均值)!!
bers(k_EbN0) = ber;
end
%% 4、绘图
% bers
% 理论分析的 AWGN信道 QPSK的BER线
M = N_LEVEL;
Pe_AWGN = ber_QAM(0:EbN0_dB(end),M,'AWGN');
semilogy(0:EbN0_dB(end),Pe_AWGN,'r-');hold on;grid on;
semilogy(EbN0_dB,bers,'b*'),
legend('AWGN analytic', 'Simulation');
xlabel('E_b/N_0 [dB]'), ylabel('BER'); axis([0 10 1e-6 1])
function x_GI = guard_interval( Ng,N_FFT,x )
% 作用:加入CP
% 说明:输入N_FFT个点,输出N_SYM个点
% 版本号:v1.0
% 开始时间:2015年10月12日21:55:21
x_GI = [ x(N_FFT-Ng+1:N_FFT); x];
end
function y=remove_GI(Ng,Nsym,ofdmSym)
%MIMO-OFDM Wireless Communications with MATLAB㈢ Yong Soo Cho, Jaekwon Kim, Won Young Yang and Chung G. Kang
%?2010 John Wiley & Sons (Asia) Pte Ltd
y=ofdmSym(Ng+1:Nsym);
end
function y=Q(x)
% co-error function: 1/sqrt(2*pi) * int_x^inf exp(-t^2/2) dt.
y=erfc(x/sqrt(2))/2;
function ber=ber_QAM(EbN0dB,M,AWGN_or_Rayleigh)
% Find ananlytical BER of Mary QAM in AWGN or Rayleigh channel
% EbN0dB=EbN0dB: Energy per bit-to-noise power[dB] for AWGN channel
% =rdB: Average SNR(2*sigma Eb/N0)[dB] for Rayleigh channel
% M = Modulation order (Constellation size)
%MIMO-OFDM Wireless Communications with MATLAB㈢ Yong Soo Cho, Jaekwon Kim, Won Young Yang and Chung G. Kang
%?2010 John Wiley & Sons (Asia) Pte Ltd
N= length(EbN0dB); sqM= sqrt(M);
a= 2*(1-power(sqM,-1))/log2(sqM); b= 6*log2(sqM)/(M-1);
if nargin<3, AWGN_or_Rayleigh='AWGN'; end
if lower(AWGN_or_Rayleigh(1))=='a', ber = a*Q(sqrt(b*10.^(EbN0dB/10)));
else rn= b*10.^(EbN0dB/10)/2; ber = 0.5*a*(1-sqrt(rn./(rn+1)));
end