[8] OFDM的发送和接收 —— 按照框图模块化

Posted 资质平庸的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[8] OFDM的发送和接收 —— 按照框图模块化相关的知识,希望对你有一定的参考价值。

2016.05.12 - 05.24
个人理解笔记。(无通信基础且急躁,片面/错误概率大大的。已待纠正)

05.12
到了这一步,可以在某书本上找一个OFDM的链路框图,在matlab下将每个模块实现下,完整是指基本实现OFDM链路框图的每一个模块,粗糙是指每个模块中有些细节可能还未涉及。至于像“ [7] OFDM过采样和参数选择”提到的OFDM链路参数,再留留(实际的OFDM链路参数与仿真代码还对应不过来)。

1 OFDM框图

摘《MIMO-OFDM Wireless Communications with Matlab》的《OFDM Basics》一章中的OFDM框图(如下)。

Figure 1. OFDM系统的发送和接收框图

在后续对OFDM模拟中,暂不包括“FEC coding”、“Bit interleaver/deinterleaver”、“ADC/DAC”、“RF Tx/Rx”、“Timing/frequency synchronization and channel estimation”以及“Channel equalizer”模块。其余模块将会被包含在OFDM系统中,以模块化(m文件)方式编写。

2 OFDM模块化

05.12

2.1 生成随机数据流(Bit stream)

OFDM_Bbasics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
%Nfft    = 64;   % 进行ifft/fft变换时的点数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
sdBitStream     = generate_bit_stream(Nbit, N); % 生成发射端数据

% ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
% ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
rvBitStream   = sdBitStream;    % 获取发送端发送的数据
% ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed


% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

generate_bit_stream.m

function BitStream = generate_bit_stream( Nbit, N )
% @功能:生成N个Nbit位的随机正整数
% @返回:sdBitStream为生成的随机正整数序列

M               = (2 ^Nbit) - 1;        % Nbit位所能表示的最大整数
BitStream     = randi([0, M], 1, N);    % 生成1 x N的0到M的随机整数
end

05.13

2.2 生成/解调调制符号(QAM/PSK modulated symbol)

OFDM_Basics.m

% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
%Nfft    = 64;   % 进行ifft/fft变换时的点数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
sdBitStream     = generate_bit_stream(Nbit, N); % 生成发射端数据

rLen    = Ncr;
ModType = 'psk';
ParModSym = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号
% ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
% ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
rvBitStream   = demodulate_symbol( ModType, Nbit, ParModSym,  Nframe);    % 解调QAM/PSK符号
% ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed


% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

generate_modulated_symbol.m

function ParModSym = generate_modulated_symbol( ModType, Nbit, BitStream, Nframe, rLen )
% @功能:根据ModType选择调制BitStream的方式
% @返回:ParModSym为调制(的并行)PSK/QAM符号
% @参数:Modtype —— 调制类型,其值可为'psk'或'qam'
%       Nbit —— 数据流BitStream中元素的位数
%       BitStream —— 数据流
%       将调制符号分为Nframe x rLen

mType       = lower(ModType);
M           = 2 ^Nbit;
ParModSym   = zeros(Nframe, rLen);

if strcmp(mType, 'psk')
    ModObj  = modem.pskmod(M);
elseif strcmp(mType, 'qam')
    ModObj  = modem.qammod(M);
else
    fprintf('generate_modulated_symbol m-fun: error %s parameter\\n', ModType);
    return ;
end     % 调制对象

ModSym  = modulate(ModObj, BitStream);  % 生成调制符号

ser2parIndex    = 1 : rLen;
for i = 1 : Nframe
    ParModSym(i, :)     = ModSym(ser2parIndex);
    ser2parIndex        = ser2parIndex + rLen;
end     % 调制符号串转并
end

demodulate_symbol.m

function DemodSym = demodulate_symbol( ModType, Nbit,ParModSym,  Nframe)
% @功能:将PSK/QAM符号解调
% @返回:DemodSym为解调数据
% @参数:Nbit —— 调制符号对应的数的位数
%       ModType —— 调制类型,其值可谓'psk'或'qam'
%       ParModSym —— PSK/QAM调制符号(Nframe行)

rLen        = length(ParModSym(1,:));
SerModSym   = zeros(1, Nframe * rLen);
par2serIndex = 1 : rLen;
for i = 1 : Nframe
    SerModSym(par2serIndex) = ParModSym(i, :);
    par2serIndex            = par2serIndex + rLen;
end

M       = 2 ^Nbit;
mType   = lower(ModType);
if strcmp(mType, 'psk')
    DemodSym  = pskdemod(SerModSym, M);
elseif strcmp(mType, 'qam')
    DemodSym  = qamdemod(SerModSym, M);
else
    fprintf('generate_modulated_symbol m-fun: error %s parameter\\n', ModType);
    DemodSym = zeros(1, Nframe * rLen);
    return ;
end     % 调制对象
end

05.16

2.3 生成OFDM符号

OFDM_Basics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
sdBitStream     = generate_bit_stream(Nbit, N); % 生成发射端数据

rLen    = Ncr;
ModType = 'psk';
ParModSym = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号
Nifftop = 1024;
SerOverOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop);
% ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
% ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
NofdmSym = Ncr;
Rlen    = Nframe;
rvParModSym = get_modulate_symbol( SerOverOfdmSym, Nifftop, NofdmSym, Rlen );
rvBitStream   = demodulate_symbol( ModType, Nbit, rvParModSym,  Nframe );    % 解调QAM/PSK符号

% ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed


% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

generate_ofdm_symbol.m

function SerOverOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop )
% @功能:利用ifft变换生成OFDM符号
% @返回:返回串行的OFDM符号到SerOfdmSym
% @参数:ParModSym —— 并行的调制符号
%       Nifftosp —— ifft过采样变换的长度

[rLen, cLen]    = size(ParModSym);
ParOverOfdmSym  = zeros(rLen, Nifftop);
for i = 1 : rLen
    IFFT_oversample = [ParModSym(i, 1 : cLen / 2), zeros(1, Nifftop - cLen),...
                    ParModSym(i, cLen / 2 + 1 : end)];
    ParOverOfdmSym(i, :) = ifft(IFFT_oversample);           
end     % 生成ofdm符号

SerOverOfdmSym      = zeros(1, rLen * cLen);
par2serIndex    = 1 : Nifftop;
for i = 1 : rLen
    SerOverOfdmSym(par2serIndex)    =  ParOverOfdmSym(i, :);
    par2serIndex = par2serIndex + Nifftop;
end

end

get_modulate_symbol.m

function ParModSym = get_modulate_symbol( SerOfdmSym, Nifftop, NofdmSym, Rlen )
% @功能:根据串行的OFDM符号恢复PSK/QAM符号
% @返回:ParModSym值为并行的PSK/QAM符号
% @参数:SerOfdmSym —— 带过采样的串行OFDM符号
%   Nifftop —— 进行ifft变换时的长度
%   NofdmSym —— 一个OFDM符号的长度
%   Rlen —— SerOfmSym中所包含的OFDM符号的个数

OverModSym = zeros(Rlen, Nifftop);
ser2parIndx = 1 : Nifftop;
for i = 1 : Rlen
    OverModSym(i, :)    = fft(SerOfdmSym(ser2parIndx));
    ser2parIndx         = ser2parIndx + Nifftop;
end % 含过采样的并行调制符号

ParModSym = zeros(Rlen, NofdmSym);
for i = 1 : Rlen
    ParModSym(i, 1 : NofdmSym / 2) = OverModSym(i, 1 : NofdmSym / 2);
    ParModSym(i, NofdmSym / 2 + 1 : end) = OverModSym(i, Nifftop - NofdmSym + NofdmSym / 2 + 1 : end);
end % 还原调制符号

end

05.17

2.4 保护间隔

OFDM_Basics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
sdBitStream     = generate_bit_stream( Nbit, N ); % 生成发射端数据

rLen    = Ncr;
ModType = 'psk';
ParModSym = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号
Nifftop = 1024;
GiType  = 'CP';
Ngi     = Ncr / 4;
SerOverGIOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop, GiType, Ngi );
% ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
% ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
NofdmSym    = Ncr;
Rlen        = Nframe;
GiType      = 'CP';
Ngi         = Ncr / 4;
rvParModSym = get_modulate_symbol( SerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi );
rvBitStream = demodulate_symbol( ModType, Nbit, rvParModSym,  Nframe );    % 解调QAM/PSK符号

% ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed


% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

generate_ofdm_symbol.m

function SerOverGIOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop, GiType, Ngi )
% @功能:利用ifft变换生成OFDM符号
% @返回:返回串行的OFDM符号到SerOfdmSym
% @参数:ParModSym —— 并行的调制符号
%       Nifftosp —— ifft过采样变换的长度
%       GiType —— 添加保护间隔的类型
%       Ngi —— OFDM保护间隔长度

[rLen, cLen]    = size(ParModSym);
ParOverOfdmSym  = zeros(rLen, Nifftop);
for i = 1 : rLen
    IFFT_oversample = [ParModSym(i, 1 : cLen / 2), zeros(1, Nifftop - cLen),...
                    ParModSym(i, cLen / 2 + 1 : end)];
    ParOverOfdmSym(i, :) = ifft(IFFT_oversample);           
end     % 生成ofdm符号

ParOverGIOfdmSym    = add_gi( ParOverOfdmSym, GiType, Ngi ); % 为每个OFDM添加保护间隔
[rLen, cLen]        = size(ParOverGIOfdmSym);
SerOverGIOfdmSym    = zeros(1, rLen * cLen);
par2serIndex        = 1 : Nifftop + Ngi;
for i = 1 : rLen
    SerOverGIOfdmSym(par2serIndex)    =  ParOverGIOfdmSym(i, :);
    par2serIndex = par2serIndex + Nifftop + Ngi;
end % 带过采样和保护间隔的OFDM符号并转串

end

get_modulate_symbol.m

function ParModSym = get_modulate_symbol( SerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi )
% @功能:根据串行的OFDM符号恢复PSK/QAM符号
% @返回:ParModSym值为并行的PSK/QAM符号
% @参数:SerOfdmSym —— 带过采样的串行OFDM符号
%   Nifftop —— 进行ifft变换时的长度
%   NofdmSym —— 一个OFDM符号的长度
%   Rlen —— SerOfmSym中所包含的OFDM符号的个数
%   GiType —— OFDM符号的保护间隔类型('CP', 'ZP')
%   Ngi —— OFDM保护间隔长度

OverOfdmSym = zeros(Rlen, Nifftop);

ser2parIndx = 1 : Nifftop + Ngi;
for i = 1 : Rlen
    OverOfdmSym(i, :)   = remove_gi( SerOverGIOfdmSym(ser2parIndx), GiType, Ngi );
    ser2parIndx         = ser2parIndx + Nifftop + Ngi;
end % 去掉OFDM符号的保护间隔并得到并行的带过采样的OFDM符号

OverModSym  = zeros(Rlen, Nifftop);
for i = 1 : Rlen
    OverModSym(i, :)    = fft(OverOfdmSym(i, :)); 
end % 含过采样的并行调制符号

ParModSym = zeros(Rlen, NofdmSym);
for i = 1 : Rlen
    ParModSym(i, 1 : NofdmSym / 2) = OverModSym(i, 1 : NofdmSym / 2);
    ParModSym(i, NofdmSym / 2 + 1 : end) = OverModSym(i, Nifftop - NofdmSym + NofdmSym / 2 + 1 : end);
end % 还原调制符号

end

add_gi.m

function ParOverGIOfdmSym = add_gi( ParOverOfdmSym, GiType, Ngi )
% @功能:为每个OFDM符号添加保护间隔
% @返回:ParOverGIOfdmSym为带保护间隔的并行的OFDM符号
% @参数:ParOverOfdmSym —— (含过采样)的多个OFDM符号,
%       GiType —— 保护间隔类型('CP', 'ZP')
%       Ngi —— 保护间隔的长度

if Ngi <= 0
    ParOverGIOfdmSym = ParOverOfdmSym;
    return ;
end % 不添加保护间隔

LgiType             = lower(GiType);
[rLen, cLen]        = size(ParOverOfdmSym);
ParOverGIOfdmSym    = zeros(rLen, cLen + Ngi);
if strcmp('cp', LgiType) % 循环前缀 —— CP
    for i = 1 : rLen
        ParOverGIOfdmSym(i, :) = add_cp(Ngi, ParOverOfdmSym(i, :));
    end
elseif strcmp('zp',LgiType)
    ParOverGIOfdmSym = ParOverOfdmSym; % ZP情况以后再补充
else
    ParOverGIOfdmSym = ParOverOfdmSym;
end

end

remove_gi.m

function OverOfdmSym = remove_gi( OverGIOfdmSym, GiType, Ngi )
% @功能:去掉OFDM符号中的保护间隔
% @返回:返回去掉保护间隔后的OFDM符号
% @参数:OverGIOfdmSym —— 带保护间隔的OFDM符号
%       GiType —— 保护间隔类型
%       Ngi —— 保护间隔长度

if Ngi <= 0
    OverOfdmSym     = OverGIOfdmSym;
end

LgiType     = lower(GiType);
if strcmp('cp', LgiType)
    OverOfdmSym = remove_cp(Ngi, OverGIOfdmSym);
elseif strcmp('zp', LgiType)
     OverOfdmSym     = OverGIOfdmSym;   % 留以后补充
end

end

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

05.17

2.5 无线信道

OFDM_Basics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
sdBitStream     = generate_bit_stream( Nbit, N ); % 生成发射端数据

rLen    = Ncr;
ModType = 'psk';
ParModSym = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号
Nifftop = 1024;
GiType  = 'CP';
Ngi     = Ncr / 4;
SerOverGIOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop, GiType, Ngi );
% ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


% st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
% @@@@@@@@ 多径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;       % 信道长度

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


% st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
rvSerOverGIOfdmSym = y;
OfdmSymIndx     = 1 : Nifftop;
H               = fft([h zeros(1, Nifftop - Lch)]); % 信道频域响应
ChFrqRep        = H(OfdmSymIndx);

NofdmSym    = Ncr;
Rlen        = Nframe;
GiType      = 'CP';
Ngi         = Ncr / 4;
rvParModSym = get_modulate_symbol( rvSerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi, ChFrqRep );
rvBitStream = demodulate_symbol( ModType, Nbit, rvParModSym,  Nframe );    % 解调QAM/PSK符号
% ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed


% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

get_modulate_symbol.m

function ParModSym = get_modulate_symbol( SerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi, ChFrqRep )
% @功能:根据串行的OFDM符号恢复PSK/QAM符号
% @返回:ParModSym值为并行的PSK/QAM符号
% @参数:SerOfdmSym —— 带过采样的串行OFDM符号
%   Nifftop —— 进行ifft变换时的长度
%   NofdmSym —— 一个OFDM符号的长度
%   Rlen —— SerOfmSym中所包含的OFDM符号的个数
%   GiType —— OFDM符号的保护间隔类型('CP', 'ZP')
%   Ngi —— OFDM保护间隔长度

OverOfdmSym = zeros(Rlen, Nifftop);

ser2parIndx = 1 : Nifftop + Ngi;
for i = 1 : Rlen
    OverOfdmSym(i, :)   = remove_gi( SerOverGIOfdmSym(ser2parIndx), GiType, Ngi );
    ser2parIndx         = ser2parIndx + Nifftop + Ngi;
end % 去掉OFDM符号的保护间隔并得到并行的带过采样的OFDM符号

OverModSym  = zeros(Rlen, Nifftop);
for i = 1 : Rlen
    temp    = fft(OverOfdmSym(i, :)); 
    OverModSym(i, :)    = temp ./ ChFrqRep;
end % 含过采样的并行调制符号加信道补偿

ParModSym = zeros(Rlen, NofdmSym);
for i = 1 : Rlen
    ParModSym(i, 1 : NofdmSym / 2) = OverModSym(i, 1 : NofdmSym / 2);
    ParModSym(i, NofdmSym / 2 + 1 : end) = OverModSym(i, Nifftop - NofdmSym + NofdmSym / 2 + 1 : end);
end % 还原调制符号

end

05.19

2.6 AWGN

OFDM_Basics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

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

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N               = Ncr * Nframe;
% if awgnIndx == 0, 计算信号功率sigPow
% else 计算误码数Neb
for awgnIndx = 0 : length(EbN0)
    sdBitStream     = generate_bit_stream( Nbit, N ); % 生成发射端数据

    rLen    = Ncr;
    ModType = 'psk';
    ParModSym = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号
    Nifftop = 1024;
    GiType  = 'CP';
    Ngi     = Ncr / 4;
    SerOverGIOfdmSym = generate_ofdm_symbol( ParModSym, Nifftop, GiType, Ngi );
    % ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


    % st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
    Nifftop     = 1024;
    [y, ChFrqRep]   = multi_rayleigh( SerOverGIOfdmSym, Nifftop );


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

    % 添加 AWGN 噪声
    snr         = EbN0(awgnIndx) + 10 * log10(Nbit * (Ncr / Nifftop)); % 4.28式
    noise_mag   = sqrt((10.^(-snr / 10)) * sigPow / 2);
    y_AWGN      = y + noise_mag * (randn(size(y)) + 1i * randn(size(y)));
    % ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


    % st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
    rvSerOverGIOfdmSym = y_AWGN;

    NofdmSym    = Ncr;
    Rlen        = Nframe;
    GiType      = 'CP';
    Ngi         = Ncr / 4;
    rvParModSym = get_modulate_symbol( rvSerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi, ChFrqRep );
    rvBitStream = demodulate_symbol( ModType, Nbit, rvParModSym,  Nframe );    % 解调QAM/PSK符号
    % ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed
end

% @@@@@@@@ 绘制误码率(BER) @@@@@@@@

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@

multi_rayleigh.m

function [y, ChFrqRep] = multi_rayleigh( SerOverGIOfdmSym, Nifftop )
% @功能:描述多径rayleigh信道
% @返回:经多径ralyeigh信道后的信号
% @参数:SerOverGIOfdmSym —— 带过采样、保护间隔的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;       % 信道长度

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

%信道频率响应
OfdmSymIndx     = 1 : Nifftop;
H               = fft([h zeros(1, Nifftop - Lch)]); % 信道频域响应
ChFrqRep        = H(OfdmSymIndx);
end

05.20

2.7 误码率(BER)

OFDM_Basics.m

% OFDM_Basics.m
% @功能:仿真OFDM系统(链路)的发射端,无线信道模块以及接收端;
%       以一般书中的OFDM框图为最小模块组织该OFDM系统。
% @结果:绘制在OFDM链路接收端的误码率(BER);
%       绘制OFDM链路发射端OFDM符号的功率谱密度(PSD)。
clear
% ######## OFDM相关参数值 ########
Nbit    = 6;    % 表示数的位数
Ncr     = 48;   % 子载波个数
Nframe  = 7;    % 经过无线信道时的OFDM符号个数

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

% 误码率相关参数
Neb         = 0;        % 在OFDM链路中传输数据时,发生位(bit)错误的数量(Neb,Number of error bits)
Ntb         = 0;        % 在OFDM链路中传输的总位(bit)数(Ntb,Number of total bits)
NBerIter    = 1e5;      % OFDM发送Niter次信息统计一次误码率BER
Target_neb  = 500;      % Neb的最大值

% 本程序误码率相关文件
ber_file_name   = 'OFDM_Rayleigh_BER.dat';
fd              = fopen(ber_file_name, 'w+');

% st_st_st_st_st_st_st_st OFDM发射端 st_st_st_st_st_st_st_st
N   = Ncr * Nframe;
% if awgnIndx == 0, 计算信号功率sigPow
% else 计算误码数Neb
for awgnIndx = 0 : length(EbN0)
    % 误码数和码数清0
    Neb = 0; 
    Ntb = 0; 
    for berIndx = 1 : NBerIter % 每 NBerIter 统计一次OFDM链路的误码率
        sdBitStream     = generate_bit_stream( Nbit, N ); % 生成发射端数据

        rLen        = Ncr;
        ModType     = 'psk';
        ParModSym   = generate_modulated_symbol( ModType, Nbit, sdBitStream, Nframe, rLen );  % 生成QAM/PSK符号

        Ngi                 = Ncr / 4;
        GiType              = 'CP';
        Nifftop             = 1024;        
        SerOverGIOfdmSym    = generate_ofdm_symbol( ParModSym, Nifftop, GiType, Ngi ); % 生成OFDM符号 
        % ed_ed_ed_ed_ed_ed_ed_ed OFDM发射端 ed_ed_ed_ed_ed_ed_ed_ed


        % st_st_st_st_st_st_st_st 无线信道 st_st_st_st_st_st_st_st
        Nifftop         = 1024;
        [y, ChFrqRep]   = multi_rayleigh( SerOverGIOfdmSym, Nifftop );

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

        % @@@@@@@@ 添加 AWGN 噪声 @@@@@@@@
        snr         = EbN0(awgnIndx) + 10 * log10(Nbit * (Ncr / Nifftop)); % 4.28式
        noise_mag   = sqrt((10.^(-snr / 10)) * sigPow / 2);
        y_AWGN      = y + noise_mag * (randn(size(y)) + 1i * randn(size(y)));
        % ed_ed_ed_ed_ed_ed_ed_ed 无线信道 ed_ed_ed_ed_ed_ed_ed_ed


        % st_st_st_st_st_st_st_st OFDM接收端 st_st_st_st_st_st_st_st
        rvSerOverGIOfdmSym = y_AWGN;

        Ngi         = Ncr / 4;
        Rlen        = Nframe;
        GiType      = 'CP';
        NofdmSym    = Ncr;
        rvParModSym = get_modulate_symbol( rvSerOverGIOfdmSym, Nifftop, NofdmSym, Rlen, GiType, Ngi, ChFrqRep );    % 由串行的OFDM符号得到QAM/PSK符号 
        rvBitStream = demodulate_symbol( ModType, Nbit, rvParModSym,  Nframe );    % 解调QAM/PSK符号

        % @@@@@@@@ 误码统计 @@@@@@@@
        Neb     = Neb + sum(sum(de2bi(rvBitStream, Nbit) ~= de2bi(sdBitStream, Nbit)));
        Ntb     = Ntb + Ncr * Nframe * Nbit;
        if Neb > Target_neb, break;end  % 误码率迭代到这里已经足够大了
        % ed_ed_ed_ed_ed_ed_ed_ed OFDM接收端 ed_ed_ed_ed_ed_ed_ed_ed
    end

    % @@@@@@@@ 误码率计算 @@@@@@@@
     BER     = Neb / Ntb;
     if awgnIndx == 0
        sigPow  = sigPow / ((Ncr + Nifftop) * Nframe * NBerIter); % 每个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
% @@@@@@@@ 绘制误码率(BER) @@@@@@@@
figure(1); clf
plot_ber(ber_file_name); % 绘制OFDM链路接收端的误码率曲线

% @@@@@@@@ 绘制OFDM功率谱密度(PSD) @@@@@@@@
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

在matlab的命令行中运行OFDM_Basics.m文件,得到BER曲线图如下:

05.24

2.8 OFDM的功率谱密度(PSD)

OFDM_Basics.m以上是关于[8] OFDM的发送和接收 —— 按照框图模块化的主要内容,如果未能解决你的问题,请参考以下文章

PythonPython 仿真OFDM发射机信道和接收机-实现多种调制方式

OFDM图像传输系统matlab仿真,以图片作为数据源进行发送,接收端还原图片,对比MPSK,MQAM等调制方式

OFDM技术原理及系统MATLAB仿真

FPGA 串口通信

OFDM基本原理

OFDM基本原理