[6] OFDM链路的误码率和OFDM符号的功率谱密度

2016.04.26 – 05.03
个人理解笔记。(无通信基础且急躁,片面/错误概率大大的。已待纠正)
相应的word版笔记保存地址:[6] OFDM链路的误码率和OFDM符号的功率谱密度。

04.27

1 OFDM链路参数

一个OFDM信号由用PSK或QAM调制的多个子载波组成 [2]
本笔记中的OFDM由16QAM调制的64个子载波(64点IFFT/FFT变换)组成;每次会有3个OFDM信号经过多径Rayleigh衰减信道(最大延迟为15);每个OFDM符号的保护间隔类型为循环前缀(长度为16)。见Beasy_16QAM_64subcarrier_ofdm_link.m中的描述(同[5] OFDM符号 OFDM符号的多径Rayleigh信道链路中的Nframe_ofdm_multi_channel_link.m文件)。

Beasy_16QAM_64subcarrier_ofdm_link.m

% Beasy_16QAM_64subcarrier_ofdm_link.m
% 生成ofdm信号:64个子载波,由16QAM调制;
% 为ofdm添加循环前缀保护间隔,ofdm在多径信道中传输;
% 解析经多径信道后的ofdm信号,得到最初的数据。
clear

% --------OFDM链路参数描述模块---------------------------------------------
% @@@@@@@@ OFDM符号相关参数 @@@@@@@@
Nbps    = 4;            % 对应16QAM调制
M       = 2 ^ Nbps;     % 16QAM调制只能调制16进制数
Nfft    = 64;           % Nfft点ifft/fft变换 - 子载波的个数
Ncp     = Nfft / 4;     % 循环前缀保护间隔长度 (Ncp=0时表示OFDM无保护间隔)
Nsym    = Nfft + Ncp;   % OFDM符号的长度
Ndata   = Nfft;         % OFDM符号中的携带数据部分的长度
Nframe  = 3;            % 每次发送Nframe个OFDM符号

% @@@@@@@@ 多径Rayleigh衰减信道相关参数 @@@@@@@@
PowerdB     = [0 -8 -17 -21 -25];   % 信道抽头功率分布(dB)
Delay       = [0 3 5 6 8];          % 信道延迟样本
Power       = 10.^(PowerdB / 10);   % 信道抽头功率分布(线性
Ntap        = length(PowerdB);      % 信道抽头数
Lch         = Delay(end) + 1;       % 信道长度
channel     = (randn(1, Ntap) + 1i * randn(1, Ntap)).*sqrt(Power / 2);
h           = zeros(1, Lch); 
h(Delay+1)  = channel;              % 信道脉冲响应

% --------OFDM符号生成模块-------------------------------------------------
% @@@@@@@@ 生成Ndata * Nframe个M进制数据 @@@@@@@@
DataSource   =  randi([0, M - 1], 1, Ndata * Nframe);

% @@@@@@@@ 将数据映射为QAM符号(时-->频) @@@@@@@@
MapObj  = modem.qammod(M);
ModSym  = modulate(MapObj, DataSource);

% @@@@@@@@ QAM符号串转并 @@@@@@@@
ModSymSrl2PrlIndx = 1 : Ndata;
ModPrlSym = zeros(Nframe, Ndata);
for i = 1 : Nframe
    ModPrlSym(i, :)     = ModSym(ModSymSrl2PrlIndx);
    ModSymSrl2PrlIndx   = ModSymSrl2PrlIndx + Ndata;
end

% @@@@@@@@ 利用ifft变换生成OFDM符号 @@@@@@@@
OfdmSym = zeros(Nframe, Ndata);
for i = 1 : Nframe
    OfdmSym(i, :)   = ifft(ModPrlSym(i, :));
end

% @@@@@@@@ 为每个OFDM符号添加循环前缀保护间隔 @@@@@@@@
GIOfdmSymIndx   = 1 : Nsym;
OfdmSym_GI      = zeros(Nframe, Nsym);
for i = 1 : Nframe
    OfdmSym_GI(i, :)   = add_cp(Ncp, Ndata, OfdmSym(i,:));
end

% @@@@@@@@ 带循环前缀的OFDM符号并转串 @@@@@@@@
GIOfdmSrlSymIndx    = 1 : Nsym;
OfdmSrlSym_GI       = zeros(1, Nframe * Nsym);
for i = 1 : Nframe
    OfdmSrlSym_GI(GIOfdmSrlSymIndx) =  OfdmSym_GI(i, :);
    GIOfdmSrlSymIndx                = GIOfdmSrlSymIndx + Nsym;
end

% --------OFDM符号经过多径信道模块-----------------------------------------
y           = conv(OfdmSrlSym_GI,h);

% --------OFDM符号解析模块---------------------------------------------
rvOfdmSrlSym_GI = y;
OfdmSymIndx     = 1 : Ndata;
H               = fft([h zeros(1, Nfft - Lch)]); % 信道频域响应
ChFrqRep        = H(OfdmSymIndx);

%  @@@@@@@@ 带循环前缀的OFDM符号串转并 @@@@@@@@
rvOfdmSym_GI = zeros(Nframe, Nsym);
GIOfdmSrlSymIndx = 1 : Nsym;
for i = 1 : Nframe
    rvOfdmSym_GI(i, :)  = rvOfdmSrlSym_GI(GIOfdmSrlSymIndx);
    GIOfdmSrlSymIndx    = GIOfdmSrlSymIndx + Nsym;
end

%  @@@@@@@@ 去掉OFDM符号的循环前缀 @@@@@@@@
rvOfdmSym = zeros(Nframe, Ndata);
for i = 1 : Nframe
    rvOfdmSym(i, :)  = remove_cp(Ncp, Nsym, rvOfdmSym_GI(i, :));
end

%  @@@@@@@@ 用fft变换将OFDM符号变为QAM符号(时-->频),并进行信道补偿 @@@@@@@@
rvModPrlSym = zeros(Nframe, Ndata);
for i = 1 : Nframe
      temp = fft(rvOfdmSym(i, :));
      rvModPrlSym(i, :) = temp./ChFrqRep;
end

%  @@@@@@@@ QAM符号并转串 @@@@@@@@
rvModSym = zeros(1, Nframe * Ndata);
ModSymPrl2SrlIndx = 1 : Ndata;
for i = 1 : Nframe
    rvModSym(ModSymPrl2SrlIndx)     = rvModPrlSym(i, :);
    ModSymPrl2SrlIndx               = ModSymPrl2SrlIndx + Ndata;
end

rvData  = qamdemod(rvModSym, M);

add_cp.m

function y = add_cp(Ngi, Ndata, OfdmSym) % 为OFDM添加保护间隔 - 循环前缀 if Ngi ~= 0 y = [OfdmSym(Ndata - Ngi + 1 : Ndata) OfdmSym(1 : Ndata)];
else
    y   = OfdmSym;
end
end

remove_cp.m

function y = remove_cp(Ngi, Nsym, OfdmSym)
% 去掉OFDM的保护间隔 - 循环前缀
if Ngi ~= 0
    y   = OfdmSym(Ngi + 1 : Nsym); % 丢掉OFDM符号的循环前缀
else
    y   = OfdmSym;
end

end

04.28

2 OFDM链路的误码率

误码率。
这里指的是BER(Bit Error Rate,二进制误码率)。对于OFDM链路来说,是指发送N次Nframe个OFDM符号,有多少个bit错误。

2.1 Beasy_16QAM_64subcarrier_ofdm_link下的误码率

Beasy_16QAM_64subcarrier_ofdm_link.m

% Beasy_16QAM_64subcarrier_ofdm_link.m
% 生成ofdm信号:64个子载波,由16QAM调制;
% 为ofdm添加循环前缀保护间隔,ofdm在多径信道中传输;
% 解析经多径信道后的ofdm信号,得到最初的数据并计算误码率。
clear

% --------OFDM链路参数描述模块---------------------------------------------
% @@@@@@@@ OFDM符号相关参数 @@@@@@@@
…
Nframe  = 3;            % 每次发送Nframe个OFDM符号
Neb     = 0;            % 在OFDM链路中传输数据时,发生位(bit)错误的数量(Neb,Number of error bits)
Ntb     = 0;            % 在OFDM链路中传输的总位(bit)数(Ntb,Number of total bits)
Niter   = 1e5;          % OFDM发送Niter次信息统计一次误码率BER

% @@@@@@@@ 多径Rayleigh衰减信道相关参数 @@@@@@@@for berIndx = 1 : Niter         % 每Niter统计一次OFDM链路的误码率
    % --------OFDM符号生成模块-------------------------------------------------% --------OFDM符号经过多径信道模块-----------------------------------------
    channel     = (randn(1, Ntap) + 1i * randn(1, Ntap)).*sqrt(Power / 2);
    h           = zeros(1, Lch); 
    h(Delay+1)  = channel;              % 信道脉冲响应
    y           = conv(OfdmSrlSym_GI,h);


    % --------OFDM符号解析模块---------------------------------------------
   …

    rvData  = qamdemod(rvModSym, M);

    % -------- 误码 --------------------------------------------------
    Neb     = Neb + sum(sum(de2bi(rvData,Nbps) ~= de2bi(DataSource, Nbps)));
    Ntb     = Ntb + Ndata * Nframe * Nbps;
end

% 误码率
BER     = Neb / Ntb;

运行Beasy_16QAM_64subcarrier_ofdm_link.m几次,BER都为0。

04.29

2.2 添加AWGN后的误码率

在信道模型非常准确的情况下,以上的OFDM链路几乎可以做到0误码。但在实际的OFDM链路下,还存在一些其它干扰。现往OFDM链路中加入AWGN模型,再来看误码率。
Beasy_16QAM_64subcarrier_ofdm_link.m

% Beasy_16QAM_64subcarrier_ofdm_link.m
% 生成ofdm信号:64个子载波,由16QAM调制;
% 为ofdm添加循环前缀保护间隔,ofdm在多径信道中传输;
% 解析经多径信道和AWGN后的ofdm信号,得到最初的数据并计算误码率。
clear

% --------OFDM链路参数描述模块---------------------------------------------
% @@@@@@@@ OFDM符号相关参数 @@@@@@@@
…
Niter       = 1e5;      % OFDM发送Niter次信息统计一次误码率BER
Target_neb  = 500;      % Neb的最大值 

% AWGN相关参数
EbN0    = 0 : 5 : 20;
sigPow  = 0;            % 信号功率

% @@@@@@@@ 多径Rayleigh衰减信道相关参数 @@@@@@@@% 本程序误码率相关文件
ber_file_name   = 'OFDM_BER_Rayleigh_CP_16.dat';
fd             = fopen(ber_file_name, 'w+');

% if awgnIndx == 0, 计算信号功率sigPow
% else 计算误码数Neb
for awgnIndx = 0 : length(EbN0)     % 跟AWGN相关的循环
    % 误码数和码数清0
    Neb = 0; 
    Ntb = 0;
    for berIndx = 1 : Niter         % 每Niter统计一次OFDM链路的误码率
        % --------OFDM符号生成模块-------------------------------------------------
        % @@@@@@@@ 生成Ndata * Nframe个M进制数据 @@@@@@@@
        ….

        % --------OFDM符号经过多径信道模块---------------------------------
        channel     = (randn(1, Ntap) + 1i * randn(1, Ntap)).*sqrt(Power / 2);
        h           = zeros(1, Lch); 
        h(Delay+1)  = channel;              % 信道脉冲响应
        y           = conv(OfdmSrlSym_GI,h);

        % 为添加AWGN噪声测量信号能量
        if awgnIndx == 0
            y1      = y(1 : Nframe * Nsym); 
            sigPow  = sigPow + y1 * y1';
            continue;
        end

        % 添加 AWGN 噪声---------------------------------------------------
        snr         = EbN0(awgnIndx) + 10 * log10(Nbps * (Ndata / Nfft)); % 4.28式
        noise_mag   = sqrt((10.^(-snr / 10)) * sigPow / 2);
        y_AWGN      = y + noise_mag * (randn(size(y)) + 1i * randn(size(y)));

        % --------OFDM符号解析模块-----------------------------------------
        …

        rvData  = qamdemod(rvModSym, M);

        % -------- 误码计算 --------------------------------------------------
        Neb     = Neb + sum(sum(de2bi(rvData,Nbps) ~= de2bi(DataSource, Nbps)));
        Ntb     = Ntb + Ndata * Nframe * Nbps;
        if Neb > Target_neb, break;end  % 误码率迭代到这里已经足够大了
    end
    % 误码率
    BER     = Neb / Ntb;
    if awgnIndx == 0
        sigPow  = sigPow / (Nsym * Nframe * Niter); % 每个OFDM信号的能量 - 平均值
    else
        fprintf(fd, '%d\t%11.3e\n', EbN0(awgnIndx), BER);
        if BER < 1e-6, break; end   % 已经满意当前这个误码率
    end
end
if fd ~= 0, fclose(fd);end
disp('Simulation is finished');

运行Beasy_16QAM_64subcarrier_ofdm_link.m,得到OFDM_BER_Rayleigh_CP_16.dat文件,其内容如下:
[6] OFDM链路的误码率和OFDM符号的功率谱密度_第1张图片
Figure 1. 每发送Niter * Nframe个OFDM符号的误码率

将误码率以曲线的形式绘制出来。
Beasy_16QAM_64subcarrier_ofdm_link.m

if fd ~= 0, fclose(fd);end
plot_ber(ber_file_name);
disp('Simulation is finished');

plot_ber.m

function plot_ber( file_name ) % 绘制OFDM链路的误码率曲线 % file_name中保存的是EbN0和误码率值对 EbN0_BER = load(file_name);
semilogy(EbN0_BER(:,1),EbN0_BER(:,2),'b-o');
grid on
legend('OFDM模拟链路的误码率曲线');
xlabel('EbN0[dB]'), ylabel('BER');
axis([EbN0_BER(1,1) EbN0_BER(end,1) 1e-5 1]);
end

运行Beasy_16QAM_64subcarrier_ofdm_link.m,得到下图
[6] OFDM链路的误码率和OFDM符号的功率谱密度_第2张图片
Figure 2. OFDM链路误码率与EbN0关系曲线图

该部分的matlab代码保存地址为:16QAM_64subcarrier_ofdm_link_BER。

05.03

3 OFDM符号的功率谱密度

完全根据书本附带的代码搬迁/验证过来的,甚至不懂什么是功率谱密度,更别说计算OFDM符号的功率谱密度了。

误码率是在OFDM链路的接收部分计算,而功率谱密度是在OFDM链路的发射部分计算。

在Beasy_16QAM_64subcarrier_ofdm_link.m中计算一次一个OFDM符号的功率谱密度。

Beasy_16QAM_64subcarrier_ofdm_link.m

% Beasy_16QAM_64subcarrier_ofdm_link.m% 在OFDM链路的接收端计算误码率(BER);在OFDM链路的发送端计算一个OFDM符号的功率谱密度(PSD)。
clear

% --------OFDM链路参数描述模块---------------------------------------------% OFDM功率谱密度相关参数
NXpsd       = 2048; 
Frc         = (1 : NXpsd) - NXpsd / 2;  % OFDM符号功率谱密度横坐标个数
NIFFTOvspl  = NXpsd / 2;                % ifft变换的QAM符号长度 
NpsdCp      = 2 * Nfft;                 % 求功率谱密度时循环前缀的长度
Nprxz       = round((NXpsd - NIFFTOvspl - NpsdCp) / 3);    % 在ofdm符号前面补0的个数
Nsuxz       = (NXpsd - NIFFTOvspl - NpsdCp) - Nprxz;        % 在ofdm符号后面补0的个数


% if awgnIndx == 0, 计算信号功率sigPow
% else 计算误码数Neb
for awgnIndx = 0 : length(EbN0)     % 跟AWGN相关的循环
    % 误码数和码数清0
    Neb = 0; 
    Ntb = 0;
    for berIndx = 1 : Niter         % 每Niter统计一次OFDM链路的误码率
        % --------OFDM符号生成模块-------------------------------------------------% ++++++++ 计算一次一个OFDM符号的PSD - 过采样++++++++
        if awgnIndx == 0
            IFFT_Oversample     = [ModPrlSym(i, 1 : end / 2) zeros(1, NIFFTOvspl - Ndata) ModPrlSym(i, end / 2 + 1 : end)];
            PsdOfdmSym          = ifft(IFFT_Oversample);
            PsdOfdmSymCP        = add_cp(NpsdCp, PsdOfdmSym);
            PsdOfdmSymCPAddZros = [zeros(1, Nprxz) PsdOfdmSymCP zeros(1, Nsuxz)];   % 过采样
            OfdmSymComput       = 20 * log10(abs(fft(PsdOfdmSymCPAddZros)));
            OfdmSymPSDy         = fftshift(OfdmSymComput) - max(OfdmSymComput);
        end

        % @@@@@@@@ 利用ifft变换生成OFDM符号 @@@@@@@@end
    % 误码率end
if fd ~= 0, fclose(fd);end

% 绘制OFDM链路接收端的误码率曲线
figure(1); clf
plot_ber(ber_file_name);

% 绘制OFDM链路发射端的PSD曲线
figure(2); clf
plot(Frc,OfdmSymPSDy,'b');grid on
xlabel('frequency[Hz]'); ylabel('PSD[dB]'); axis([Frc([1 end]) -100 0]);
disp('Simulation is finished');

add_cp.m

function y = add_cp(Ngi, OfdmSym)
% 为OFDM添加保护间隔 - 循环前缀
if Ngi ~= 0
    y   = [OfdmSym(end - Ngi + 1 : end) OfdmSym];
else
    y   = OfdmSym;
end
end

remove_cp.m

function y = remove_cp(Ngi, OfdmSym)
% 去掉OFDM的保护间隔 - 循环前缀
if Ngi ~= 0
    y   = OfdmSym(Ngi + 1 : end); % 丢掉OFDM符号的循环前缀
else
    y   = OfdmSym;
end

end

运行Beasy_16QAM_64subcarrier_ofdm_link,得到在发射端的一个OFDM符号的功率谱密度:
[6] OFDM链路的误码率和OFDM符号的功率谱密度_第3张图片
Figure 3. OFDM链路发射端一个OFDM符号的功率谱密度(PSD)图

上图的横坐标值并不代表OFDM符号的频率值,它只是为了绘制纵坐标而出现的 ¬—— 它的个数跟纵坐标值的个数相同。

含OFDM链路接收端误码率(BER)和发送端一个OFDM符号功率谱密度(PSD)的matlab源码笔记地址为:16QAM_64subcarrier_ofdm_link_BER&PSD。

[2016.05.02 - 20:47]

你可能感兴趣的:(psd,OFDM,BER)