前言:在数字通信系统中插入一种参数可调的滤波器,以校正和补偿系统特性,减少码间干扰的影响,这种起补偿作用的滤波器称为均衡器。
目录
一、自适应均衡器的原理
1、LMS算法
2、LMS算法的原理
3、符号LMS算法
二、自适应均衡器实现
1、matlab仿真
2、产生测试数据
3、定点数在FPGA中的运算
4、自适应均衡器的verilog实现
三、仿真测试结果
一、自适应均衡器的原理
在无线通信系统中,由于通信的信道存在多径效应、信道带宽有限及信道特性本身的不完善等因素,导致数据通过信道时将不可避免地产生码间干扰,从而降低系统的性能,影响通信的质量。自适应均衡器是基于自适应均衡技术的装置,能够基于对信道特性的测量随时调整自身的系数,以适应信道特性的变化,消除码间干扰。
在实现自适应均衡器之前需要了解自适应算法。
1、LMS算法
LMS算法(Least Mean Square)根据均方误差准则设计的一种有效算法,它要求均方估计误差达到最小,即
式中,
2、LMS算法的原理
LMS算法可以用下面一组公式递推来表示:
式中,W(n)为滤波器系数向量,也称权值;X(n)是输入信号组成的一组向量;y(n)是输出信号;d(n)是期望信号;e(n)是误差信号;u是加权向量更新时的步长因子,u越大,算法收敛越快,但同时收敛后的误差信号也越大;u越小,则算法的收敛速度越慢,但同时收敛后的误差信号也相应减小,稳态性能更好。
图1 LMS算法的一般实现结构
如果所有运算均串行执行,则完成一次权值更新需要2N次乘法运算、2N+1次加减法运算和N次移位运算。又因为LMS算法本身是严格的闭环系统,每次权值更新均需要在一个数据周期内完成,因此FPGA的系统时钟频率需要远高于数据速率,这对FPGA的时钟要求很高。
3、符号LMS算法
LMS算法的步骤虽然不能减少,但对滤波器系数更新的运算可以简化。符号LMS算法只给出梯度迭代的方向,而不具体给出数值,即:
在性能上不如LMS算法稳定,且误差相对较大,但运算速度增加、运算量减小并节约了硬件资源。
二、自适应均衡器实现
1、matlab仿真
自适应均衡器的性能仿真主要分为两个方面:相同多径干扰条件下信噪比与系统性能改善情况,以及相同信噪比条件下多径干扰与系统性能改善情况。
Matlab代码如下:
len = 20000;
Tlen = 2000;
step = 1/128;
s = zeros(1,len);
s1 = zeros(1,len);
x = zeros(1,N);
w = ones(1,N);
s = randsrc(1,len);
s1(2:len) = s(1:len-1);
p = 0.1;
SNR = [0:10];
for db = 1:length(SNR)
s2 = sqrt(1-p)*s + sqrt(p)*s1;
s3 = awgn(s2,db,'measured');
for i=N:len
x(1:N) = s3(i:-1:i-N+1);
y(i) = x*w';
e(i) = s(i-3) - y(i);
w = w + 2*step*sign(x)*e(i)';
if y(i)>0
y1(i) = 1;
else
y1(i) = -1;
end
if s3(i)>0
y2(i) = 1;
else
y2(i) = -1;
end
end
errornum1 = sum(y1(Tlen:end)~=s(Tlen-3:end-3));
errornum2 = sum(y2(Tlen:end)~=s(Tlen:end));
ber1(db) = errornum1/(len-Tlen);
ber2(db) = errornum2/(len-Tlen);
end
subplot(121);
semilogy(SNR,ber1,'+-',SNR,ber2,'-');
xlabel('信噪比(SNR)');ylabel('误码率');title('信噪比与误码率的关系(P=0.1)');
legend('有均衡器','无均衡器');
db=10;
p=[0:0.05:1];
for m=1:length(p)
s2=sqrt(1-m*0.05)*s+sqrt(m*0.05)*s1;
s3=awgn(s2,db,'measured');
for i=N:len
x(1:N)=s3(i:-1:i-N+1);
y(i)=x*w';
e(i)=s(i-3)-y(i);
w=w+2*step*sign(x)*e(i)';
if y(i)>0
y1(i)=1;
else
y1(i)=-1;
end
if s3(i)>0
y2(i)=1;
else
y2(i)=-1;
end
end
errornum1=sum(y1(Tlen:end)~=s(Tlen-3:end-3));
errornum2=sum(y2(Tlen:end)~=s(Tlen:end));
ber3(m)=errornum1/(len-Tlen);
ber4(m)=errornum2/(len-Tlen);
end
subplot(122);
semilogy(p,ber3,'+-',p,ber4,'-');
xlabel('多径损耗(P)');ylabel('误码率');title('多径损耗因子与误码率的关系 (SNR=10dB)');
legend('有均衡器 ','无均衡器');
图2 自适应均衡器对系统性能改善关系图
2、产生测试数据
首先用matlab产生测试数据,将数据保存进txt文件中,利用modelsim仿真读取测试数据,再将仿真结果写入外部文件中,最后再matlab中对比FPGA结果和仿真结果。
Matlab代码如下:
len = 2000;
step = 1/128;
N = 7;
B = 16;
p = 0.1;
SNR = 10;
s = randsrc(1,len);
s1 = zeros(1,len);
s1(2:len) = s(1:len-1);
s2 = sqrt(1-p)*s + sqrt(p)*s1;
s3 = awgn(s2,SNR,'measured');
maxs3 = max(abs(s3));
maxs = max(abs(s));
m = max(maxs3,maxs)*1;
s3 = s3/m;
s = s/m;
x = zeros(1,N);
w = ones(1,N);
Mw = 0;Me = 0;
for i=N:len
x(1:N) = s3(i:-1:i-N+1);
y(i) = x*w';
e(i) = s(i-3) - y(i);
w = w + 2*step*sign(e(i)')*x;
if max(abs(w))>Mw
Mw = max(abs(w));
end
if max(abs(e))>Me
Me = max(abs(e));
end
end
fid =fopen('D:matlab\s_in.txt','w');
for k=1:length(s_16)
s_16_Bin = dec2bin(s_16(k) + (s_16(k)<0)*2^B,B);
for q=1:B
if s_16_Bin(q)=='1'
tb = 1;
else
tb = 0;
end
fprintf(fid,'%d',tb);
end
fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);
fid = fopen('D:matlab\s3_in.txt','w');
for k=1:length(s3_16)
s3_16_Bin = dec2bin(s3_16(k) + (s3_16(k)<0)*2^B,B);
for q=1:B
if s3_16_Bin(q) == '1'
tb = 1;
else
tb = 0;
end
fprintf(fid,'%d',tb);
end
fprintf(fid,'\r\n');
end
fprintf(fid,';');
fclose(fid);
fid = fopen('D:matlab\e_out.txt','w');
fprintf(fid,'%8d\r\n',e_16);
fprintf(fid,';');
fclose(fid);
仿真中显示权值最大绝对值介于1、2之间,误差最大绝对值介于1、4之间,输出数据最大绝对值介于1、4之间,这些数据范围为FPGA中定点数小数位置设置了依据。
3、定点数在FPGA中的运算
在此不对定点数的定义做介绍,单介绍其加减法运算。
在verilog中,所有二进制数都当成整数来处理,所以当一个小数想要进行加减运算时需要先对其进行量化,扩展到整数形式,那么这就会产生量化误差问题,这里不对其过多讨论,而是重点讨论如何判断小数点的位置问题。在设计verilog程序时,我们需要有意地设计定点数的小数点位置,例如:两个二进制数00101与00110,逐位相加结果为01011,表示5+6=11;如果小数点均看成在最高位与次高位之间,即0∆0101、0∆0110、0∆1011,则表示0.3125+0.375=0.6875,结果也正确;但如果是0∆0101、00∆101进行加法预算,如果直接逐位相加,若小数点位置与第一个数相同,则表示0.6875,若小数点位置与第二个数相同,则表示1.375,显然结果不正确;从而说明二进制小数的加法与十进制一样,都需要对齐小数点。因为实际上计算的都是00101+00110,也就是量化后的二进制数据,如果不对齐小数点,则计算结果必然出错。
4、自适应均衡器的verilog实现
根据符号LMS算法及自适应均衡器的原理,运算步骤如下:
输入数据和权值均为16bit向量。由于X(n)和d(n)数据范围均在±1之内,故小数点位于15位与14位之间;W(n)的范围在±2之内,故小数点位于14位与13位之间;y(n)及误差e(n)的范围在±4之内,故小数点在13位与12位之间;
Verilog代码如下:
module Equalizer
(
input rst ,
input clk ,
input signed [15:0] Xin ,
input signed [15:0] Rin ,
output signed [15:0] Error,
output signed [15:0] Yout
);
reg [2:0] count;
always@(posedge clk or negedge rst)
if(rst == 1'b0)
count <= 3'd0;
else if(count == 3'd5)
count <= 3'd0;
else
count <= count + 1'b1;
reg signed [15:0] Xin_Reg[6:0];
reg signed [15:0] Rin_Reg[6:0];
reg [2:0] i,j;
always@(posedge clk or negedge rst)
if(rst == 1'b0)
begin
for(i=0;i<7;i=i+1)
begin
Xin_Reg[i] <= 16'd0;
Rin_Reg[i] <= 16'd0;
end
end
else
begin
if(count == 3'd5)
for(j=0;j<6;j=j+1)
begin
Xin_Reg[j+1] <= Xin_Reg[j];
Rin_Reg[j+1] <= Rin_Reg[j];
end
Xin_Reg[0] <= Xin;
Rin_Reg[0] <= Rin;
end
reg signed[15:0] W_Reg[6:0];
reg signed[15:0] DW_Reg[6:0];
reg [2:0] k,q;
always@(posedge clk or negedge rst)
if(rst == 1'b0)
begin
for(k=0;k<7;k=k+1)
begin
W_Reg[k] <= 16'b0010_0000_0000_0000;
end
end
else
begin
if(count == 3'd5)
for(q=0;q<7;q=q+1)
W_Reg[q] <= W_Reg[q] + DW_Reg[q];
end
wire signed[31:0] Y_Reg[6:0];
genvar v;
generate
for(v=0;v<=6;v=v+1)
begin:u
mult u
(
.aclr ( !rst ),
.clock ( clk ),
.dataa ( Xin_Reg[v] ),
.datab ( W_Reg[v] ),
.result ( Y_Reg[v] )
);
end
endgenerate
reg signed[34:0] Y1_out,Y2_out,Y_out;
reg signed[20:0] E_out;
always@(posedge clk or negedge rst)
if(rst == 1'b0)
begin
Y1_out <= 35'd0;
Y2_out <= 35'd0;
E_out <= 21'd0;
Y_out <= 35'd0;
end
else
begin
Y1_out <= {{3{Y_Reg[0][31]}},Y_Reg[0]} + {{3{Y_Reg[1][31]}},Y_Reg[1]} + {{3{Y_Reg[2][31]}},Y_Reg[2]};
Y2_out <= {{3{Y_Reg[3][31]}},Y_Reg[3]} + {{3{Y_Reg[4][31]}},Y_Reg[4]} + {{3{Y_Reg[5][31]}},Y_Reg[5]} + {{3{Y_Reg[6][31]}},Y_Reg[6]};
Y_out <= Y1_out + Y2_out;
if(count == 3'd3)
E_out <= {{5{Rin_Reg[3][15]}},Rin_Reg[3]} - Y1_out[34:14] - Y2_out[34:14];
end
assign Yout = Y_out[31:16];
assign Error = E_out[20:5];
reg [2:0] m,n;
always@(posedge clk or negedge rst)
if(rst == 1'b0)
for(m=0;m<7;m=m+1)
DW_Reg[m] <= 16'd0;
else
begin
for(n=0;n<7;n=n+1)
if(E_out[20])
DW_Reg[n] <= -{{7{Xin_Reg[n][15]}},Xin_Reg[n][15:7]};
else
DW_Reg[n] <= {{7{Xin_Reg[n][15]}},Xin_Reg[n][15:7]};
end
endmodule
其中使用到的乘法器IP核配置如下:
图3 乘法器IP核配置
求取滤波器系数与输入数据乘法操作占2个周期;7个32bit加法运算分为2次并行加法以及1个32bit加法运算,前者占1个周期,后者与求e(n)的减法运算占1个周期,共占2个周期;求取W(n)的1次判断与取反操作占1个周期;最后更新滤波器系数的加法运算占1个周期;整个符号LMS算法占6个周期,故时钟频率应该位抽样频率的6倍。
具体如图所示:
图4 各步骤所需时钟周期
三、仿真测试结果
将FPGA处理数据保存到外部txt文件,用matlab读取文件,完成仿真测试
Matlab代码如下:
fid = fopen('D:Error_out.txt','r');
[Cout,N_n] = fscanf(fid,'%lg',inf);
fclose(fid);
error = Cout/max(abs(Cout));
fid = fopen('D:matlab\e_out.txt','r');
[Cout,N_n] = fscanf(fid,'%lg',inf);
fclose(fid);
e = Cout/max(abs(Cout));
Error = error(1:length(error));
Se = e.^2;
Serror = Error.^2;
N = 1:length(error);
subplot(211);plot(Serror);title('FPGA仿真误差收敛图');xlabel('数据长度');ylabel('归一化误差');
subplot(212);plot(Se);title('matlab仿真误差收敛图');xlabel('数据长度');ylabel('归一化误差');
图5 仿真测试结果
可见,算法收敛后,误差信号在很小的范围内波动。Matlab仿真误差收敛图与FPGA实现后的误差收敛图基本相同,说明FPGA结果接近理论值。
内容仍然有很多未解之处,也有很多地方没有完全写明白,在此先定一个草稿,未完待续…
参考文献:
[1] 杜勇.数字滤波器的MATLAB与FPGA实现——Altera/Verilog版(第二版).北京:电子工业出版社,2019文章来源:https://www.toymoban.com/news/detail-777748.html
[2] 刘威,邵高平. 基于FPGA的高速低功耗自适应滤波器的实现. 数据采集与处理.2006.(B12):150-152文章来源地址https://www.toymoban.com/news/detail-777748.html
到了这里,关于自适应均衡器的原理与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!