概述
(1) 参数初始化程序
仿真程序中需要初始化的参数如下:
采样频率:20MHz
包含数据的子载波数目:52个
包含数据的子载波的位置:[7:32 34:59]
包含用户数据的子载波数目:48个
导频子载波数目:4个
包含用户数据的子载波的位置:[7:11 13:25 27:32 34:39 41:53 55:59]
导频子载波的位置:[12 26 40 54]
生成导频时不同导频子载波需要乘的系数:[1:1:1:-1]
频域表示的短训练符号:
{0,0,1+j,0,0,0,-1-j,0,0,0,1+j,0,0,0,-1-j,0,0,0,-1-j,0,0,0,1+j,0,0,0, 0,0,0,0,-1-j,0,0,0,-1-j,0,0,0,1+j, 0,0,0,1+j,0,0,0,1+j,0,0,0,1+j,0,0}
频域表示的长训练符号:{1,1,-1,-1,1,1,-1,1,-1,1,1,1,1,1,1,-1,-1,1,1,-1,1,-1,1,1,1,1,0,1,-1,-1,1,1,-1,1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,1,-1,1,-1,1,1,1,1}
产生导频的序列:{1,1,1,1,-1,-1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,1,1,-1,1,1,1,1,1,1,-1,1,1,1,-1,1,1,-1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,1,1,1,1,-1,-1,1,1,-1,-1,1,-1,1,-1,1,1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,1,1,1,-1,1,-1,1,-1,1,-1,-1,-1,-1,-1,1,-1,1,1,-1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,1,1,1,-1,-1,-1,-1,-1,-1,-1}
以上参数是在程序设计过程中就已经预先设定好的参数,这部分参数不需要在仿真过程中进行设定或改动。还有一部分参数需要在仿真程序运行前在图形界面GUI中进行手动设定,这些参数包括:需要信号源产生倍号的长度(以8 Bytes为单位,因为6个字节刚好对应OFDM中包含用户数据的子载波的数目)、信号调制方式(BPSK, QPSK,16-QAM, 64-QAM)、产生信道模型中的信噪比SNR。手动设定这些参数的目的是为了使仿真系统更为灵活,更容易满足仿真和测试的需要。
(2) 信号源产生器程序
在发送部分仿真程序中,我们产生发送信号的方法是按照设定好的所需信号的长度,调用随机函数randn ()来产生。产生后的信号一方面发给接下去的模块,另一方面进行保存用于与接收机接收解调后的信号进行比较分析。
具体程序如下:
out = rand(1,baseband_out_length);
baseband_out1 = round(out) ;
baseband_out2 = floor(out*2) ;
baseband_out3 = ceil(out*2)-1 ;
baseband_out4 = randint(1,baseband_out_length);
% 四种生成发送的二进制序列的方法,任取一种产生要发送的二进制序列
if (baseband_out1 == baseband_out2 & baseband_out1 == baseband_out3 )
fprintf(’Transmission Sequence Generated n n’);
baseband_out = baseband_out1 ;
else
fprintf(’Check Code!!!!!!!!!!!!!!!!!!!!! n n’);
end
% 验证四种生成发送的二进制序列的方法
convert_matrix = reshape(baseband_out,bits_per_symbol,length(baseband_out)/bits_per_symbol) ;
for k = 1:(length(baseband_out)/bits_per_symbol)
modulo_baseband(k) = 0 ;
for i = 1:bits_per_symbol
modulo_baseband(k) = modulo_baseband(k) + convert_matrix(i,k)*2^(bits_per_symbol - i) ;
end
end
% 每2个比特转化为整数 0至3
% 采用’left-msb’方式
convert_matrix1 = zeros(length(baseband_out)/bits_per_symbol,bits_per_symbol);
convert_matrix1 = convert_matrix’ ;
Test_convert_matrix1 = bi2de(convert_matrix1,bits_per_symbol,’left-msb’);
Test_convert_matrix2 = bi2de(convert_matrix1,bits_per_symbol,’right-msb’);
if (modulo_baseband == Test_convert_matrix1′)
fprintf(’modulo_baseband = Test_convert_matrix1 nnn’);
else if (modulo_baseband == Test_convert_matrix2′)
fprintf(’modulo_baseband = Test_convert_matrix2 nnn’);
else
fprintf(’modulo_baseband ~= any Test_convert_matrix nnn’);
end
end
carrier_matrix = reshape(modulo_baseband,carrier_count,symbols_per_carrier)’;
% 生成时间-载波矩阵
(3) 信号调制程序
可选的信号调制方式【15】有:BPSK,QPSK,16-QAM,64-QAR,这些调制方式的每个调制后符号所对应比特数目分别为:1, 2, 4, 6。调制后得到的是一个复数信号,实部对应I路信号,虚部对应Q路信号。
% Generate the random binary stream for transmit test
BitsTx = floor(rand(1,NumLoop*NumSubc)*2);
% Modulate (Generates QAM symbols)
% input: BitsTx(1,NumLoop*NumSubc); output: SymQAM(NumLoop,NumSubc/2)
SymQAMtmp = reshape(BitsTx,2,NumLoop*NumSubc/2).’;
SymQAMtmptmp = bi2de(SymQAMtmp,2,’left-msb’);
% 函数说明:
% bin2dec(binarystr) interprets the binary string binarystr and returns the
% equivalent decimal number.
% bi2de是把列向量的每一个元素都由2进制变为10进制
% D = BI2DE(…,MSBFLAG) uses MSBFLAG to determine the input orientation.
% MSBFLAG has two possible values, ‘right-msb’ and ‘left-msb’. Giving a
% ‘right-msb’ MSBFLAG does not change the function’s default behavior.
% Giving a ‘left-msb’ MSBFLAG flips the input orientation such that the
% MSB is on the left.
% % % D = BI2DE(…,P) converts a base P vector to a decimal value.
% % Examples:
% % >> B = [0 0 1 1; 1 0 1 0];
% % >> T = [0 1 1; 2 1 0];
% % >> D = bi2de(B) >> D = bi2de(B,’left-msb’) >> D = bi2de(T,3)
% % D = D = D =
% % 12 3 12
% % 5 10 5
% QAM modulation
% 00->-1-i,01->-1+i,10->1-i,11->1+i
% 利用查表法进行QAM星座映射
QAMTable = [-1-i -1+i 1-i 1+i];
SymQAM = QAMTable(SymQAMtmptmp+1);
(4) IFFT模块程序
由于MATLAB中有现成的IFFT函数可以调用,这给我们的编程带来了极大的方便,从而省去了编写IFFT算法的工作。输入及输出IFFT的数据都按矩阵格式存储,因此应当注意用户数据和导频数据在矩阵中的存放位置,必须按OFDM规定的格式进行存放,否则在接收端将不能正确解调。
% input: SymQAM(NumLoop,NumSubc/2); output: SymIFFT(NumSubc,NumLoop)
SymIFFT = zeros(NumSubc,NumLoop);
SymIFFTtmp = reshape(SymQAM,NumSubc/2,NumLoop);
SymIFFTtmptmp = zeros(NumSubc,NumLoop);
SymIFFTtmptmp(1,:) = real(SymIFFTtmp(1,:)); % 实数
SymIFFTtmptmp(NumSubc/2+1,:) = imag(SymIFFTtmp(1,:)); % 实数
% 这么安排矩阵的目的是为了构造共轭对称矩阵
% 共轭对称矩阵的特点是 在ifft/fft的矢量上 N点的矢量
% 在0,N/2点必须是实数 一般选为0
% 1至N/2点 与 (N/2)+1至N-1点关于N/2共轭对称
SymIFFTtmptmp(2:NumSubc/2,:) = SymIFFTtmp(2:NumSubc/2,:);
SymIFFTtmptmp((NumSubc/2+2):NumSubc,:) = flipdim(conj(SymIFFTtmp(2:NumSubc/2,:)),1);
% % >> a = [1 2 3; 4 5 6; 7 8 9; 10 11 12]
% % a =
% % 1 2 3
% % 4 5 6
% % 7 8 9
% % 10 11 12
% % >> b = flipdim(a,1)
% % b =
% % 10 11 12
% % 7 8 9
% % 4 5 6
% % 1 2 3
SymIFFT = ifft(SymIFFTtmptmp,NumSubc,1);
2.接收部分程序设计说明
接收部分的程序设计流程图如图3.4所示。
图3.4 接收部分程序设计流程图
接收部分仿真程序中需要说明的地方有:
(1) 分组检测程序
分组检测程序用于检测是否已接收到数据分组,该程序采用了Schimdl和Cox的延时和相关算法进行检测,延时D=16,也就是短训练序列的长度。用于判定分组是否到来的判定阐值设定为threshold=0.75。对于算法中的相关运算和功率计算的结果都用了filter()函数进行了滤波,从而使判断更为准确。
(2) 精确时间同步程序
虽然在分组检测程序中,Schimdl和Cox的延时和相关算法已经在一定程度上达到了粗略的时间同步,但这还不能满足正确解调的要求,因此要进行精确的时间同步。精确时间同步程序采用将己知的长训练符号和接收数据进行相关运算的方法,当运算结果大于判定阈值0.75时,判定己达到时间同步,将接收信号输出到下一模块。这里输出的数据是已经去除了前导的数据,即全部都是需要解调的数据。
(3) 频率同步程序
频率同步程序包含两个小模块,一个是频率偏移估计程序,一个频率偏移补偿程序。频率偏移估计程序采用的是时域中的频率偏移估计算法,算法中延时窗长度D=16.频率偏移补偿程序将估计出的频率偏移相位取反后,按时间向量顺序,生成相应的频率补偿向量,与原信号向量相乘达到频率偏移补偿的目的。
(4) FFT模块程序
调用MATLAB中的FFT函数进行运算,并将输出数据中的导频数据和需解调数据分开。导频数据用于相位跟踪,同时还要输出FFT运算后的长训练符号,用于信道估计。典型语句如下:
% input: SymDeCP(NumSubc,NumLoop); output: SymFFT(NumSubc,NumLoop)
SymFFT = fft(SymDeCP,NumSubc,1);
(5) 信道估算程序
进行信道估算的目的是为了载波相位跟踪。方法是通过FFT,后得到的长训练序列和已知的长训练序列进行相关运算得到。
(6) 相位跟踪模块程序
通过信道估算模块得到的信道冲击响应的估计,和FFT模块得到的频域导频信号,进行相位误差估计,得到需要补偿的相位,然后对这个相位误差进行取反后乘回到原信号中。
(7) 解调模块程序
解调应根据发射机所选的不同调制方式进行相应的解调。解调时采用的是硬判决的方式。
% SymFFT(NumSubc,NumLoop); output: SymDec(NumSubc,NumLoop)
SymDec = zeros(NumSubc,NumLoop);
SymEqtmp(1,:) = SymFFT(1,:)+i*SymFFT(NumSubc/2+1,:);
SymEqtmp(2:NumSubc/2,:) = SymFFT(2:NumSubc/2,:);
for m = 1:NumLoop
for n = 1:NumSubc/2
Real = real(SymEqtmp(n,m));
Imag = imag(SymEqtmp(n,m));
if( abs((Real -1)) < abs((Real +1)))
SymDec(2*n-1,m) = 1;
else
SymDec(2*n-1,m) = 0;
end
if( abs((Imag -1)) < abs((Imag +1 )) )
SymDec(2*n,m) = 1;
else
SymDec(2*n,m) = 0;
end
end
end
% ————————————————————————-
% Another way to DeQAM
% QAMTable = [-1-i -1+i 1-i 1+i];
% 00->-1-i,01->-1+i,10->1-i,11->1+i
TestSymDec = zeros(NumSubc,NumLoop);
TestSymEqtmp(1,:) = SymFFT(1,:)+i*SymFFT(NumSubc/2+1,:);
TestSymEqtmp(2:NumSubc/2,:) = SymFFT(2:NumSubc/2,:);
TestSymEqtmp1 = reshape(TestSymEqtmp,1,NumSubc*NumLoop/2);
min_d = zeros(size(TestSymEqtmp1));
min_ddd = zeros(1,NumSubc*NumLoop);
d = zeros(4,1);
min_index = 0;
for ii = 1:1:(NumSubc*NumLoop/2)
for jj = 1:4
d(jj) = abs(TestSymEqtmp(ii) - QAMTable(jj));
end
[min_d(ii),min_index] = min(d);
% % [Y,I] = MIN(X) returns the indices of the minimum values in vector I.
switch min_index
case 1
min_ddd(2*ii-1) = 0 ;
min_ddd(2*ii) = 0 ;
case 2
min_ddd(2*ii-1) = 0 ;
min_ddd(2*ii) = 1 ;
case 3
min_ddd(2*ii-1) = 1 ;
min_ddd(2*ii) = 0 ;
case 4
min_ddd(2*ii-1) = 1 ;
min_ddd(2*ii) = 1 ;
otherwise
fprintf(’Impossible error!!! nn’);
end
end
%————————————————————————–
% 函数说明:
% % C = min(A) returns the smallest elements along different dimensions of an array.
% % If A is a vector, min(A) returns the smallest element in A.
% % If A is a matrix, min(A) treats the columns of A as vectors, returning a row
% % vector containing the minimum element from each column.
% % [C,I] = min(…) finds the indices of the minimum values of A, and returns
% % them in output vector I. If there are several identical minimum values, the
% % index of the first one found is returned.
% Bit Error
BitsRx = zeros(1,NumSubc*NumLoop);
BitsRx = SymDec(:).’;
[Num,Ber] = symerr(BitsTx,BitsRx)
BerSnrTable(snr+1,2) = Num ;
BerSnrTable(snr+1,3) = Ber ;
end
%————————————————————————–
if min_ddd == BitsRx
fprintf(’DeQAM two ways the same results nn’);
else
fprintf(’DeQAM two ways the different results’);
end
% ————————————————————————
figure(1);
subplot(2,1,1);
semilogy(BerSnrTable(:,1),BerSnrTable(:,2),’o-’);
subplot(2,1,2);
semilogy(BerSnrTable(:,1),BerSnrTable(:,3),’o-’);
% ————————————————————————
time_of_sim = toc
最后
以上就是合适日记本为你收集整理的频分复用(OFDM)系统的原理的全部内容,希望文章能够帮你解决频分复用(OFDM)系统的原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复