系列文章目录
文章目录
前言
[3.2.1 相关累加计算](#3.2.1 相关累加计算)
前言
第一章根据短序列的周期性以及延迟相关并长度保持算法进行了判断新数据分组到来的判断。输出的结果就是根据输入给与一个大概位置的有效标志,之后更加精确的判断交给后面的其他模块。因为本实验只使用了一个载波,所以不需要进行载波同步,直接进入符号同步,符号同步会充分利用短序列,燃烧最后价值。消除空闲间隔,输出长序列以及有效数据。
上板环境:
ILA抓取波形:可以看到短序列消失,只输出了长序列和数据域的有效值。3.2us
一、符号同步的目的
符号同步是对细节的打磨,是求得单个OFDM符号开始以及结束的精确时刻。
二、符号同步算法描述
2.1符号同步原理
充分利用已知的前导结构,也就是短序列。对于发射机和接收机来讲,短序列的数值本身就是固定的,即使通过传输也不会发生太大改变。将接受到的实际信号与已知的短序列进行互相关计算,进而进一步定位符号开始和结束的准备时刻。
将接受的数据与本地已知的段训练序列进行互相关计算,可依据公式1,D毋庸置疑就是窗口的长度,也就是短序列的点数,16点。其他的参数跟第一章基本一致。
(1)
当新的数据来到时,最前面的10个段训练符号依次进行互相关计算,结合第一章的计算过程可以想到,由于数值的相关性,理论情况下,在每个段训练符号的结束时刻就是相关数值的峰值,因此10个段训练符号会得到10个峰值。因此我们只需要判断这个峰值大于某个阈值然后进行累加10次,就可以判断出每个符号的结束时刻。
2.2符号同步算法简化
关于寻找峰值的优化,设定一个阈值,超过这个阈值就是出现了峰,即找到了峰值。
短训练序列为16点,每一个都是复数的数据类型,消耗的乘法器资源过多。因此采用持续累加短序列符号的方法降低噪声的影响,并且将接收到的信号量化为{-1,+1},大大节省了硬件资源并提高了运算速度。
简化完的效果也可以实现预想的效果,win。
2.3符号同步偏移的影响
由于多径效应的影响,可能造成符号同步估计的时刻不准,可能正好,可能提前,可能落后。一旦偏了就会对后面数据域的取值造成偏移,进而fft计算结果出现错误。
分析一下危害:正好不多说了,理想状态。提前就是会多一点循环前缀,这个对结果影响不是很大。如果落后了,会包括下一个符号的循环前缀,这样影响比较大。所以取点的时候,一般直接前移一些点。教材给出的经验值是4-6点,这个具体的值还要根据你自己的实际情况进行更改。
2.4符号同步的硬件结构
三步走,量化,匹配滤波,符号输出。
当分组检测模块的输出数据到达符号同步模块时,为了降低运算复杂度及对资源的需求,首先通过量化器把接收到的信号量化为(-1,1)。量化后的接收信号在接下来的匹配滤波器中进行与本地短训练符号的相关计算、相关值累加、幅值计算及峰值的寻找,最后确定短训练符号的结束位置。符号输出模块负责在找到短训练符号的结束点后,按后续处理要求去除循环前缀,输出长训练符号与数据符号:且当接收数据不是symbol长度的整数倍时,在其后补零以满足整数倍条件。由于短训练符号在后续模块均不再使用,故此模块不再输出短训练符号。
三、符号同步算法在FPGA上的实现
3.1量化模块
短序列符号16点,持续累加后,分别将16个最高位缓存下来,正为0,负为1。 先把传过来的实部和虚部缓存下来。
reg [7:0]BufferDataR;
reg [7:0]BufferDataI;
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
BufferEnable <= 0;
BufferDataR <= 0;
BufferDataI <= 0;
end
else
begin
if(inEn)
begin
BufferEnable <= 1;
BufferDataR <= bitInR;
BufferDataI <= bitInI;
end
else
begin
BufferEnable <= 0;
BufferDataR <= 0;
BufferDataI <= 0;
end
end
end
进行扩展累加缓存
reg [191:0] Continual_Accumulation_Real;
reg [191:0] Continual_Accumulation_Imag;
/*持续累加有效信号 *//
reg AddEnable;
//********************************取得量化结果********************************//
always @ (posedge Clk or negedge Rst_n)
begin
if (!Rst_n)
begin
Continual_Accumulation_Real <= 0;
Continual_Accumulation_Imag <= 0;
AddEnable <= 0;
end
else
begin
if(BufferEnable)
begin
/*持续累加移位寄存器左移一个单元*****//
Continual_Accumulation_Real[191:12] <= Continual_Accumulation_Real[179:0];
Continual_Accumulation_Imag[191:12] <= Continual_Accumulation_Imag[179:0];
/*最高一个单元与输入数据的12位扩展相加赋值给最低一个单元****//
Continual_Accumulation_Real[11:0] <= {{4{BufferDataR[7]}},BufferDataR} + Continual_Accumulation_Real[191:180];
Continual_Accumulation_Imag[11:0] <= {{4{BufferDataI[7]}},BufferDataI} + Continual_Accumulation_Imag[191:180];
AddEnable <= 1;
end
else
begin
Continual_Accumulation_Real <= 0;
Continual_Accumulation_Imag <= 0;
AddEnable <= 0;
end
end
end
将最低位12位的最高位缓存到量化数组中
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
Quantization_Result_Real <= 0;
Quantization_Result_Imag <= 0;
QuantizationEnable <= 0;
end
else
begin
if(AddEnable)
begin
QuantizationEnable <= 1;
/*量化结果移位******//
Quantization_Result_Real[14:0] <= Quantization_Result_Real[15:1];
Quantization_Result_Imag[14:0] <= Quantization_Result_Imag[15:1];
/*最高位为0,表正,量化为+1, 在此用0代替,下面语句只是用于判断******//
Quantization_Result_Real[15] <= Continual_Accumulation_Real[11];
/*最高位为1,表负,量化为-1,在此用1表示******//
Quantization_Result_Imag[15] <= Continual_Accumulation_Imag[11];
end
else
begin
Quantization_Result_Real <= 0;
Quantization_Result_Imag <= 0;
QuantizationEnable <= 0;
end
end
end
3.2匹配滤波模块
匹配滤波模块主要负责寻找各个短训练符号的结束点。经过量化处理后,接收信号送入匹配滤波单元,首先与本地16个短训练符号取样进行相关计算,并将相关值累加求和,然后通过寻找其幅值的峰值来确定各个短训练符号的结束点,其实现结构如图所示,可分为相关及累加计算、幅值简化计算和峰值寻找三部分。
3.2.1 相关累加计算
将量化后的数据与本地的短序列共轭进行相关计算。
由于量化的存在,所以共轭乘积就可以简化成了4中加减法运算:
先把传过来的量化数据存下来:
//the enable signal Buffer
reg BufferEnable;
//the input datas buffer
reg [15:0]BufferDataR;
reg [15:0]BufferDataI;
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
BufferEnable <= 0;
BufferDataR <= 0;
BufferDataI <= 0;
end
else
begin
if(QuanEnable)
begin
BufferEnable <= 1;
BufferDataR <= QuanDataR;
BufferDataI <= QuanDataI;
end
else
begin
BufferEnable <= 0;
BufferDataR <= 0;
BufferDataI <= 0;
end
end
end
进行16点的计数,因为STS16点
reg [4:0]Counter;
reg TempEnable;
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
Counter <= 0;
TempEnable <= 0;
end
else
begin
if(BufferEnable)
begin
if(Counter < 15) //when the counter is 16, the enable of correlation is set high, beacuse the lenght of the STS is 16
Counter <= Counter + 1;
else
TempEnable <= 1;
end
else
begin
Counter <= 0;
TempEnable <= 0;
end
end
end
进行计算,调用模块,改变对应的输入即可,4种情况
always @ (posedge Clk or negedge Rst_n)
begin
if (!Rst_n)
begin
output_Real <= 0;
output_Imag <= 0;
OutputEnable <= 0;
end
else if (inEn)
begin
OutputEnable <= 1;
if (multiplier_Real == 0 && multiplier_Imag == 0)
begin
output_Real <= {{1{known_Real[15]}},known_Real} + {{1{known_Imag[15]}},known_Imag};
output_Imag <= {{1{known_Real[15]}},known_Real} - {{1{known_Imag[15]}},known_Imag};
end
else if (multiplier_Real == 0 && multiplier_Imag == 1)
begin
output_Real <= {{1{known_Real[15]}},known_Real} - {{1{known_Imag[15]}},known_Imag};
output_Imag <= - {{1{known_Real[15]}},known_Real} - {{1{known_Imag[15]}},known_Imag};
end
else if (multiplier_Real == 1 && multiplier_Imag == 0)
begin
output_Real <= - {{1{known_Real[15]}},known_Real} + {{1{known_Imag[15]}},known_Imag};
output_Imag <= {{1{known_Real[15]}},known_Real} + {{1{known_Imag[15]}},known_Imag};
end
else //(buffer_multiplier_Real==1 && buffer_multiplier_Imag==1)
begin
output_Real <= - {{1{known_Real[15]}},known_Real} - {{1{known_Imag[15]}},known_Imag};
output_Imag <= - {{1{known_Real[15]}},known_Real} + {{1{known_Imag[15]}},known_Imag};
end
end
else
begin
output_Real <= 0;
output_Imag <= 0;
OutputEnable <= 0;
end
end
都算完了,进行累加
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
CorrelationEnable <= 0;
CorrelationSumR <= 0;
CorrelationSumI <= 0;
end
else
begin
if(TempEnable&CorrelationEn0&CorrelationEn1&CorrelationEn2&CorrelationEn3&CorrelationEn4&CorrelationEn5
&CorrelationEn6&CorrelationEn7&CorrelationEn8&CorrelationEn9&CorrelationEn10&CorrelationEn11
&CorrelationEn12&CorrelationEn13&CorrelationEn14&CorrelationEn15)
begin
/*赋值语句右边的操作数位宽已扩展为21位,跟左边的结果位宽一致,保证带符号位二进制加法运算的正确性*******//
CorrelationSumR <= ((({{4{CorrelationR0[16]}},CorrelationR0} + {{4{CorrelationR1[16]}},CorrelationR1})
+ ({{4{CorrelationR2[16]}},CorrelationR2} + {{4{CorrelationR3[16]}},CorrelationR3}))
+ (({{4{CorrelationR4[16]}},CorrelationR4} + {{4{CorrelationR5[16]}},CorrelationR5})
+ ({{4{CorrelationR6[16]}},CorrelationR6} + {{4{CorrelationR7[16]}},CorrelationR7})))
+ ((({{4{CorrelationR8[16]}},CorrelationR8} + {{4{CorrelationR9[16]}},CorrelationR9})
+ ({{4{CorrelationR10[16]}},CorrelationR10} + {{4{CorrelationR11[16]}},CorrelationR11}))
+ (({{4{CorrelationR12[16]}},CorrelationR12} + {{4{CorrelationR13[16]}},CorrelationR13})
+ ({{4{CorrelationR14[16]}},CorrelationR14} + {{4{CorrelationR15[16]}},CorrelationR15})));
CorrelationSumI <= ((({{4{CorrelationI0[16]}},CorrelationI0} + {{4{CorrelationI1[16]}},CorrelationI1})
+ ({{4{CorrelationI2[16]}},CorrelationI2} + {{4{CorrelationI3[16]}},CorrelationI3}))
+ (({{4{CorrelationI4[16]}},CorrelationI4} + {{4{CorrelationI5[16]}},CorrelationI5})
+ ({{4{CorrelationI6[16]}},CorrelationI6} + {{4{CorrelationI7[16]}},CorrelationI7})))
+ ((({{4{CorrelationI8[16]}},CorrelationI8} + {{4{CorrelationI9[16]}},CorrelationI9})
+ ({{4{CorrelationI10[16]}},CorrelationI10} + {{4{CorrelationI11[16]}},CorrelationI11}))
+ (({{4{CorrelationI12[16]}},CorrelationI12} + {{4{CorrelationI13[16]}},CorrelationI13})
+ ({{4{CorrelationI14[16]}},CorrelationI14} + {{4{CorrelationI15[16]}},CorrelationI15})));
CorrelationEnable <= 1;
end
else
begin
CorrelationEnable <= 0;
CorrelationSumR <= 0;
CorrelationSumI <= 0;
end
end
end
3.2.2幅值简化计算
在得到相关值累加和后,需要计算其幅值,用于峰值判断。显然如果直接计算幅值,不仅需要乘法操作还要开方运算,非常不利于硬件实现。硬件实现上进行式(5-10)简化,即计算输入数据的实部和虚部的绝对值之和,近似其幅值,结构如图所示。首先分别判断实部和虚部是否为正数,若为正数则保持不变,若为负数则其相反数,然后相加。
always @ (posedge Clk or negedge Rst_n) /*输入增加一级缓存,延迟一个时钟周期******//
begin
if (!Rst_n)
begin
BufferEnable <= 0;
BufferDataRe <= 0;
BufferDataIm <= 0;
end
else
begin /*缓存的数据为输入数据的绝对值******//
if(DataEnable)
begin
BufferEnable <= 1;
if(DataInRe[20] == 0) /*符号位为0,表示为正数,绝对值即为输入数******//
begin
BufferDataRe <= DataInRe;
end
else /*符号位为1,表示为负数,绝对值为输入数取反加1******//
begin
BufferDataRe <= ~ DataInRe + 1;
end
if (DataInIm[20] == 0) /*虚部运算同实部******//
begin
BufferDataIm <= DataInIm;
end
else
begin
BufferDataIm <= ~ DataInIm + 1;
end
end
else
begin
BufferEnable <= 0;
BufferDataRe <= 0;
BufferDataIm <= 0;
end
end
end
always @ (posedge Clk or negedge Rst_n)
begin
if (!Rst_n)
begin
Absolute <= 0;
AbsoluteEnable <= 0;
end
else
begin
if(BufferEnable)
begin
/*求取实部与虚部的绝对值之和******//
Absolute <= {BufferDataRe[20],BufferDataRe} + {BufferDataIm[20],BufferDataIm};
AbsoluteEnable <= 1;
end
else
begin
Absolute <= 0;
AbsoluteEnable <= 0;
end
end
end
3.2.3峰值寻找
峰值寻找单元主要负责搜索接收的短训练符号取样与本地短训练符号相关累加和幅值的峰值,即短训练符号的结束点。考虑到硬件实现的复杂度,实现上不采用搜寻最大值的方法。而是采用制定门限值的方法来代替。即当累加值超过了预先设定的门限值时,即认为找到峰值。理论上在每一组短训练符号16个取样的结束点,都将产生一个峰值。但由于分组检测模块输出的第一组短训练符号是不完整的,所以本模块只能连续检测到9个峰值点。当检测到第9个峰值时,意味着短训练符号已经结束。
先缓存下来累加值
reg BufferEnable;
//the input data buffer
reg [21:0]BufferData;
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
BufferEnable <= 0;
BufferData <= 0;
end
else
begin
if(DataEnable)
begin
BufferEnable <= 1;
BufferData <= AbsoluteData;
end
else
begin
BufferEnable <= 0;
BufferData <= 0;
end
end
end
判断,计数峰值,判断的具体值根据实际结果进行修改
reg [3:0] STS_end_counter; /*峰值数目计数器******//
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
STS_end_counter <= 0;
PeakFinded <= 0;
end
else
begin
if(BufferEnable)
begin /*absolute_sum位宽22位(1位符号位 + 7位整数位 + 14位小数位)******//
if(STS_end_counter < 9)
begin
if (BufferData > 22'b0000_0001_10_0000_0000_0000)//1.5
begin
STS_end_counter <= STS_end_counter + 1; /*大于阈值,计数器加1******//
end
PeakFinded <= 0;
end
else
begin
PeakFinded <= 1; /*当找到9个峰值,即短训练序列的结束位置,把信号拉高******//
end
end
else
begin /*帧结束时,把寄存器赋予初始值******//
STS_end_counter <= 0;
PeakFinded <= 0;
end
end
end
3.3符号输出模块
由于数据符号均为16个循环前缀加64个有效数据,在去除循环前缀后数据格式为每64个有效数据之间间隔16个空数据(即这16个时钟没有数据),硬件实现上由一个同步使能信号有效来表示有效数据。而长训练为32个循环前缀加连续两个64样值的格式,为了使长训练符号在去除循环前缀后也保持统一的数据格式,操作上首先输出第一个长训练符号,而第二个长训练符号及后续的数据符号经过深度为16级的移位寄存器输出,如图5-37所示。此外,如果接收数据不为symbol长度的整数倍时,在其后补零以满足整数倍条件。
就是长序列是挨着的,先输出第一个,然后后面的数据统一延时16点
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
begin
Counter1 <= 0;
Counter2 <= 0;
DataOutEnable <= 0;
DataOutRe <= 0;
DataOutIm <= 0;
DataSymbol <= 0;
BufferOutEnable <= 0;
BufferDataSymbol <= 0;
BufferDataOutRe <= 0;
BufferDataOutIm <= 0;
TempSymbol <= 0;
end
else
begin
if(PeakFinded)
begin
if(Counter1 <= 85) //the counter is set by 85, because the processing (quantization,correlation,and so on) delay is 10 clock
begin
Counter2 <= 0;
Counter1 <= Counter1 + 1;
if(Counter1 >= 22 && Counter1 <= 85)//the cyclix prefix of the LTS is 32, and the delay is 10, thus 32-10=22
begin
DataOutEnable <= 1;
DataOutRe <= DataInRe;
DataOutIm <= DataInIm;
end
else
begin
DataOutEnable <= 0;
DataOutRe <= 0;
DataOutIm <= 0;
end
if(Counter1 == 22)
begin
DataSymbol <= DataSymbol + 1;
TempSymbol <= DataSymbol + 1;
end
end
else
begin//when the value of counter2 is between 0 and 63, the input datas are the datas we need
//and when the valus of counter2 is between 64 and 79, the input datas are the cyclic prefix of the next symbol
if(Counter2 == 79)
begin
Counter2 <= 0;
TempSymbol <= TempSymbol + 1;
end
else
begin
Counter2 <= Counter2 + 1;
end
if(Counter2 >= 0 && Counter2 <= 63)
begin
BufferOutEnable[15] <= 1;
BufferDataOutRe[127:120] <= DataInRe;
BufferDataOutIm[127:120] <= DataInIm;
BufferDataSymbol[127:120] <= TempSymbol + 1;
end
else
begin
BufferOutEnable[15] <= 0;
BufferDataOutRe[127:120] <= 0;
BufferDataOutIm[127:120] <= 0;
BufferDataSymbol[127:120] <= 0;
end
BufferOutEnable[14:0] <= BufferOutEnable[15:1];
BufferDataOutRe[119:0] <= BufferDataOutRe[127:8];
BufferDataOutIm[119:0] <= BufferDataOutIm[127:8];
DataOutEnable <= BufferOutEnable[0];
DataOutRe <= BufferDataOutRe[7:0];
DataOutIm <= BufferDataOutIm[7:0];
BufferDataSymbol[119:0] <= BufferDataSymbol[127:8];
DataSymbol <= BufferDataSymbol[7:0];
end
end
else
begin
if(Counter2 == 0) //the length of the input datas is an integral multiple of the length of symbol (64)
begin
BufferOutEnable <= 0;
BufferDataOutRe <= 0;
BufferDataOutIm <= 0;
BufferDataSymbol <= 0;
DataOutEnable <= 0;
DataOutRe <= 0;
DataOutIm <= 0;
DataSymbol <= 0;
end
else //if not, keeping output until it satifies (the values of counter2 is 79)
begin
if(Counter2 == 79)
Counter2 <= 0;
else
Counter2 <= Counter2 + 1;
BufferDataSymbol[127:120] <= TempSymbol+1;
BufferDataSymbol[119:0] <= BufferDataSymbol[127:8];
DataSymbol <= BufferDataSymbol[7:0];
BufferOutEnable[14:0] <= BufferOutEnable[15:1];
BufferDataOutRe[119:0] <= BufferDataOutRe[127:8];
BufferDataOutIm[119:0] <= BufferDataOutIm[127:8];
DataOutEnable <= BufferOutEnable[0];
DataOutRe <= BufferDataOutRe[7:0];
DataOutIm <= BufferDataOutIm[7:0];
BufferOutEnable[15] <= 1;
BufferDataOutRe[127:120] <= DataInRe;
BufferDataOutIm[127:120] <= DataInIm;
end
Counter1 <= 0;
end
end
前面确定短序列的结束位置,这部分一个是要控制延时多少输出,一个是做好计数就可以了
总结
理解教材公式,做好数据控制,验证数据计算。
实际上板需要结合实际更新阈值等数据。
代码参考教材:基于xilinx FPGA的OFDM通信系统基带设计