文章目录
OFDM其实是一种FDM(多载波)技术,就与之对应的就是单载波技术。单载波技术的信道拥有一个很宽的带宽,而为了保证传输没有ISI(码间干扰),根据奈奎斯特准则要求[1]:

需要保证 H ( f ) H(f) H(f)在 [ − R s 2 , R s 2 ] [-\frac{R_s}{2},\frac{R_s}{2}] [−2Rs,2Rs]中是一个常数( R s R_s Rs表示波特率,表示符号传输的速率,而符号则是一个数据的意思,根据数据的进制而决定长度)。对此我们通常使用的方法是设计一个均衡滤波器抵消信道带来的不平坦频响,用发射和接收滤波器利用滚降升余弦函数去构造一个平坦的信道,实现一个无ISI的传输
在单载波系统中,为了保证高速率传输, R s R_s Rs要尽可能的大。信号带宽增加后,信道带宽如果小于信号带宽就会引起快衰落。我们就需要一个非常复杂的均衡器来抵消这个快衰落,而这个均衡器是难以设计的。
有没有变得办法呢?显然是有的。如同常见的处理非线性问题一样,我们如果使用微元法只看很窄的一段频响,他是不是就接近平坦而很容易实现ISI呢?,这样均衡器设计起来就简单很多了。因此我们把一个宽带信号拆分成多个窄带信号再分别用不同的子载波进行传输,这就是多载波技术。
而什么是OFDM(正交频分复用,正交多载波)呢?我们从时域上来看,当我们使用了多载波技术后,首先把需要发送的信号做一个串并转换,譬如我数据本身1ms发送一个数据,现在我要发送8个数据,使用单载波这需要8ms,我现在将原本的信道变为8个子信道后,这8个子信道只需要在8ms内也发送8个数据就可以。也就是说一个单一信道变为了8ms传输他所分到的那部分数据,8ms后合并就行。这就增大了符号长度,对时延的容忍度大大增加了,ISI就不容易产生。
现在八个子信道就需要8个不同的子载波了。而这8个子载波的频率显然不能完全一致,否则无法区分开需要频分复用,但他们又要离得越近越好,因为这样总带宽的以节省。那么最近是多少呢?最终发现子载波之间的间隔
Δ
f
\Delta f
Δf至少是子信道的波特率,即
Δ
f
=
1
T
s
y
m
\Delta f=\frac{1}{T_{sym}}
Δf=Tsym1(
T
s
y
m
=
N
∗
T
T_{sym}=N*T
Tsym=N∗T),当然后续我们引入了GI和VC之后,这里不是
T
s
y
m
T_{sym}
Tsym而是
T
u
s
e
d
T_{used}
Tused。可以证明
{
e
j
2
π
f
k
t
}
k
=
0
N
−
1
\{e^{j2\pi f_kt}\}_{k=0}^{N-1}
{ej2πfkt}k=0N−1
是正交的,这就是子载波。
而具体OFDM是如何实现的呢?
我们在基带上用滤波器来说明
首先,数据经过串并转换,每个子信道上会走M个数据,这是就可以进行QAM或是PSK,被映射成一个复数
X
k
X_k
Xk=
(
s
k
1
,
s
k
2
)
(s_{k1},s_{k2})
(sk1,sk2)。此时发送的信号
x
(
t
)
x(t)
x(t)就可以写作
x
k
(
t
)
=
s
k
1
c
o
s
2
π
f
k
t
−
s
k
2
s
i
n
2
π
f
k
t
=
R
e
(
X
k
e
j
2
π
f
k
t
)
x_k(t)=s_{k1}cos2\pi f_k t-s_{k2}sin2 \pi f_kt=Re(X_ke^{j2\pi f_kt})
xk(t)=sk1cos2πfkt−sk2sin2πfkt=Re(Xkej2πfkt)
x ( t ) = ∑ k x k ( t ) x(t)=\sum_k{x_k(t)} x(t)=k∑xk(t)
而因为子载波正交,这个解调是很容易的。这就完成了多载波的发射和接收
而之后,人们发现上面的过程可以用IDFT或是IFFT大大简化。[2]



为什么需要保护间隔呢?虽然传输时间增加大大的减少了ISI的干扰,但是时延扩展仍然存在,虽然微弱但这破坏了正交性。为此,我们增加保护间隔避开时延扩展。

所谓保护间隔就是让出时延扩展时间,来避免码间干扰。保护间隔有多种方法,包括ZP,CP,CS。
根据之前所说,此时如果GI时间小于时延扩展,那么不会产生ISI。而如果GI时间大于时延扩展,ISI就被彻底消灭了。然而事实不是这样在实际操作中,会出现符号定时偏差(STO),这导致FFT窗并不是准确的在OFDM符号的起点进行变换,进而造成ISI。[2]中描述:
这也是ZP不被广泛使用的原因,STO的出现不会导致使用CP方法的OFDM出现ICI,而使用ZP的则会

除了ISI和ICI,OFDM还会出现ACI(邻道干扰)问题,这时候我们会引入VC即虚拟子波,即一个符号内两侧的子波不用于传输任何信号,这会导致利用率从 N N N下降到 N u s e d N_{used} Nused
以下代码参考了[2]和[3],但力求读懂每一步
% OFDM实现
clear all;
% 选择CP或ZP
NgType = 2; %对于ZP或CP NgType = 1或2
if NgType == 1
nt = 'CP';
elseif NgType == 2
nt = 'ZP';
end
% 选择信道类型
Ch = 1;
if Ch == 0
chType ='AWGN'; %高斯白噪声信道
Target_neb = 100;
else %多经瑞利信道
chType ='CH';
Target_neb = 500;
end
figure(Ch+1);
clf;
PowerdB = [0 -8 -17 -21 -25]; %信道抽头功率特性'dB'
Delay = [0 3 5 6 8]; %信道时延
Power = 10.^(PowerdB/10); %信道抽头功率特性 '线性'
Ntap = length(PowerdB); %抽头数
Lch = Delay(end)+1; %信道长度,TDL最大抽头数
Nbps = 2; %调制阶数 2/4/6
M = 2^Nbps; %QPSK、16-QAM、64-QAM
Nfft = 64; %FFT大小
% Ng = 3
Ng = Nfft/4; %保护间隔(GI)长度,若没有保护间隔,Ng = 0
Nsym = Nfft + Ng; %符号周期
% 调整Nvc
% VC是不用于传输的子载波,拥有保护带宽,导致传输速率下降到N_used/N
Nvc = Nfft/4; %Nvc若等于0,则没有VC(虚拟子载波)
% Nvc = 0; %Nvc若等于0,则没有VC(虚拟子载波)
Nused = Nfft - Nvc; %Nused为用于传输数据的子载波数
EbN0 = [0:2:20]; %Eb/N0
% EbN0 = 50; %Eb/N0
N_iter = 1e5; %对于每一次EbN0的迭代次数
Nframe = 3; %每一帧的符号数,一个OFDM帧由三个OFDM符号组成
sigPow = 0; %初始信号功率
file_name = ['OFDM_BER_' chType '_' nt '_' 'GL' num2str(Ng) '.dat'];
fid = fopen(file_name,'w+');
norms = [1 sqrt(2) 0 sqrt(10) 0 sqrt(42)]; %BPSK 4-QAM 16-QAM,幅值,用于归一化
for i = 0:length(EbN0)
% 设置伪随机的种子为0,保证每次的计算结果是相同的
randn('state',0);
rand('state',0);
% Ber2=ber(); %初始化BER
Neb = 0; %初始化误比特数
Ntb = 0; %初始化总比特数
for m = 1:N_iter %迭代次数
X = randi([0 M-1],1,Nused*Nframe); % 返回0--M-1之间的一个长度为Nused*Nframe的向量,一帧被拆分为子载波数*符号数个量
Xmod = qammod(X,M,'gray')/norms(Nbps); % 使用格雷码做QAM,变为复数形式
if NgType~=2 % x_GI表示增加了GI的x
x_GI = zeros(1,Nframe*Nsym);
elseif NgType == 2 % Zero Padding,头尾都有零,因此长度要增加
x_GI = zeros(1,Nframe*Nsym+Ng);
end
% kk1 = 1:Nused/2;
% kk2 = Nused/2+1:Nused;
kk1 = [1:Nused/2];
kk2 = [Nused/2+1:Nused];
kk3 = 1:Nfft;
kk4 = 1:Nsym;
for k = 1:Nframe %以下处理针对一个OFDM符号
% 第一步倒置,把x从f/2移到0处,详见我的知乎提问,陈老师专栏
% https://zhuanlan.zhihu.com/p/386509272
if Nvc~= 0
X_shift = [0 Xmod(kk2) zeros(1,Nvc-1) Xmod(kk1)];
else
X_shift = [Xmod(kk2) Xmod(kk1)];
end
% 发送
% 注意此处仍然在基带,发送需要上载波
x = ifft(X_shift);
x_GI(kk4) = guard_interval(Ng,Nfft,NgType,x); %增加CP或ZP,增加后总长度为N_sym
% 向后平移到下一个符号
kk1 = kk1 + Nused;
kk2 = kk2 + Nused;
kk3 = kk3 + Nfft;
kk4 = kk4 + Nsym;
end
% 能量检测
if i == 0 %只测量信号功率
sigPow_temp = x_GI*x_GI';
end
if Ch==0
y = x_GI; % 没有信道,把噪声忽略了?
else %多径衰落信道
% TDL模型,本质上就是考虑了多径的时延和功率
% 生成抽头数个瑞利信道
channel = (randn(1,Ntap)+1j*randn(1,Ntap)).*sqrt(Power/2);
h = zeros(1,Lch);
h(Delay+1) = channel; % 冲激函数采样
y = conv(x_GI,h);
end
if i == 0 %只测量信号功率
y1 = y(1:Nframe*Nsym);
sigPow = sigPow + y1*y1';
continue;
end
%******************** 信道 ***********************%
% SNR这里是EsN0,看陈老湿的解释
% https://zhuanlan.zhihu.com/p/335954327
% 具体来说,SNR是指EsN0,而Es有能量用于发送CP了,倒置后面的一项
snr = EbN0(i) + 10*log10(Nbps*(Nused/Nfft)); %%方便fig标号,(1),原书公式
% snr = EbN0(i) + 10*log10(Nbps);
% snr = EbN0(i) + 10*log10(Nbps*(Nfft/Nsym)); %%方便fig标号,(3)CP消耗能量
noise_msg = sqrt((10.^(-snr/10))*sigPow/2);
% 获得幅度后,噪声是瑞两个高斯噪声
y_GI = y + noise_msg*(randn(size(y)) + 1j*randn(size(y)));
% 接收端
% kk1也是因为头尾都是0
kk1 = (NgType==2)*Ng + [1:Nsym];
kk2 = 1:Nfft;
kk3 = 1:Nused;
kk4 = (Nused/2 + Nvc + 1):Nfft;
kk5 = (Nvc~=0)+[1:Nused/2];
if Ch ==1
H = fft([h zeros(1,Nfft-Lch)]); %信道频率响应,做Nfft点采样,因此要补0
H_shift(kk3) = [H(kk4) H(kk5)]; %得到均衡器
end
for k =1:Nframe
Y(kk2) = fft(remove_GI(Ng,Nsym,NgType,y_GI(kk1)));
Y_shift = [Y(kk4) Y(kk5)];
if Ch ==0
Xmod_r(kk3) = Y_shift;
else
Xmod_r(kk3) = Y_shift./H_shift; %均衡器,去h^-1
end
kk1 = kk1 + Nsym;
kk2 = kk2 + Nfft;
kk3 = kk3 + Nused;
kk4 = kk4 + Nfft;
kk5 = kk5 + Nfft;
end
X_r = qamdemod(Xmod_r*norms(Nbps),M,'gray');
Neb = Neb + sum(sum(de2bi(X_r,Nbps)~=de2bi(X,Nbps))); % 错误的个数
Ntb = Ntb + Nused*Nframe*Nbps;
% if Neb>Target_neb
% break
% end
end
if i == 0
sigPow = sigPow/Nsym/Nframe/N_iter;
fprintf('Signal power= %11.3e\n', sigPow);
fprintf(fid,'%%Signal power= %11.3e\n%%EbN0[dB] BER\n', sigPow);
else
Ber = Neb/Ntb;
fprintf('EbN0=%3d[dB], BER=%4d/%8d=%11.3e\n', EbN0(i), Neb,Ntb,Ber)
fprintf(fid, '%d\t%11.3e\n', EbN0(i), Ber);
if Ber<1e-6
break;
end
end
end %end for i
if(fid~=0)
fclose(fid);
end
disp('sumualtion is finished');
plot_ber(file_name,Nbps);
%%%%选择CP或ZP
if Ch == 1
if NgType == 1
a = load(file_name);
save('ofdm_basic_myself3_cp16_rayleigh','a');
elseif NgType == 2
b = load(file_name);
save('ofdm_basic_myself3_zp16_rayleigh','b');
end
end
[1] 通信原理 第2版 [李晓峰 编著] 2014年版
[2] MIMO-OFDM 无线通信技术及MATLAB 实现
[3] https://zhuanlan.zhihu.com/p/385096476
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型
文章目录认识unity打包目录结构游戏逆向流程Unity游戏攻击面可被攻击原因mono的打包建议方案锁血飞天无限金币攻击力翻倍以上统称内存挂透视自瞄压枪瞬移内购破解Unity游戏防御开发时注意数据安全接入第三方反作弊系统外挂检测思路狠人自爆实战查看目录结构用il2cppdumper例子2-森林whoishe后记认识unity打包目录结构dll一般很大,因为里面是所有的游戏功能编译成的二进制码游戏逆向流程开发人员代码被编译打包到GameAssembly.dll中使用il2ppDumper工具,并借助游戏名_Data\il2cpp_data\Metadata\global-metadata.dat
Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法,Linux…感兴趣就关注我吧!你定不会失望。目录1.ls显示当前目录下的文件内内容2.pwd-显示用户当前所在的目录3.cd-改变工作目录。将当前工作目录改变到指定的目录下1.cd-回到上一次待的工作空间2.cd..返回上一层目录1.相对路径:cd../aurora2.绝对路径:cd/home/aurora/lesson1/aurora3.cd~进入用户家目录4.cd/进入root目录4.mkdir-新建目录5.rmdir/rm-删除1.rmdir删除空文件夹2.rm删除1.rm-f2.rm-i3.rm-r1.ls显示当前目
前言 Slowloris攻击是我在李华峰老师的书——《MetasploitWeb 渗透测试实战》里面看的,感觉既简单又使用,现在这种攻击是很容易被防护的啦。不过我也不敢真刀实战的去试,只是拿个靶机玩玩罢了。 废话还是写在结语里面吧。(划掉)结语可以不看(划掉)Slowloris攻击的原理 Slowloris是一种资源消耗类DoS攻击,它利用部分HTTP请求进行操作。也叫做慢速攻击,这里的慢速并不是说发动攻击慢,而是访问一条链接的速度慢。Slowloris攻击的功能是打开与目标Web服务器的连接,然后尽可能长时间的保持这些连接打开。如果由多台电脑同时发起Slo
目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式 2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置 3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一
例如,我一直看到称为String#split的方法,但从未见过String.split,这似乎更合乎逻辑。或者甚至可能是String::split,因为您可以认为#split位于String的命名空间中。当假定/隐含类(#split)时,我什至单独看到了该方法。我知道这是ri中识别方法的方式。哪个先出现?例如,这是为了区分方法和字段吗?我还听说这有助于区分实例方法和类方法。但这从哪里开始呢? 最佳答案 不同之处在于您如何访问这些方法。类方法使用::分隔符来表示消息可以发送到类/模块对象,而实例方法使用#分隔符表示消息可以发送到实例对
1、为什么压缩的原始数据一般采用YUV格式(1)利用人对图片感觉的生理特性,对于亮度信息比较敏感,对于色度信息不太敏感,所以视频编码是将Y分量和UV分量分开来编码,并且可以减少UV分量.2、视频压缩原理(1)空间冗余:图像相邻像素之间的相关性,比如一帧图片被划分成多个16x16的块之后,相邻的块之间有很多明显的相似性。(2)时间冗余:时间相差较近的两张图片变化较小。(3)视觉冗余:我们的眼睛对某些细节不太敏感,对图像中的高频信息的敏感度小于低频信息,可以去除一些高频信息。(4)编码冗余:一幅图片中不同像素出现的概率是不同的,对于出现次数较多的像素,用少的位数来编码,对于出现次数较少的像素,用多
Python程序运行原理Python是一种脚本语言,编辑完成的程序,也称源代码,可以直接运行。从计算机的角度看,Python程序的运行过程包含两个步骤:解释器将源代码翻译成字节码(即中间码),然后由虚拟机解释执行。Python程序文件的扩展名通常为.py。在执行时,首先由Python解释器将.py文件中的源代码翻译成中间码,这个中间码是一个扩展名为.pyc的文件,再由Python虚拟机(PythonVirtualMachine,PVM)逐条将中间码翻译成机器指令执行。需要说明的是,pyc文件保存在Python安装目录的pycache文件夹下,如果Python无法在用户的计算机上写人字节码,字节
我正在学习Rails数据库连接池概念。在Rails应用程序中,我将池大小定义为5。我对连接池大小的理解如下。当服务器启动时,rails会自动创建n个在database.yml文件中定义的连接。在我的例子中,它将创建5个连接,因为池大小为5。在每个http请求上,如果需要访问数据库,rails将使用连接池中的可用连接来处理请求。但我的问题是,如果我一次达到1000个请求,那么大部分请求将无法访问数据库连接,因为我的连接池大小只有5个。我上面对rails连接池的理解对吗??谢谢, 最佳答案 目的:数据库连接不是线程安全的;所以Activ