1.目的

实现採样率fs=50MHz,通带为5MHz~15MHz。阻带衰减60dB的IIR带通滤波器

2.方案

採取直接型

3.具体设计

(1)确定滤波器的系数,系数和滤波器输出量化位宽

先依据要求的fs,fc1,fc2以及阻带衰减确定系数,当初假设设置截止频率f1=5MHz,f2 = 15MHz。实际的截止频率差非常多。如图1。因此改动为f1 = 2.6MHz和f2 = 19.3MHz就能满足真正的通带为5MHz~15MHz。如图2满足要求后,再对系数量化。一定要确定好系数和输出数据的位宽,不满足就必须更改位宽,直到达到要求,才干进行下一步。比如:如图3。系数和输出数据的位宽都为8bits,量化后滤波器的响应与理想响应差太远。不能达到滤波要求。但如图4,系数13bits,输出数据位宽为14bit。量化后的幅频特性与理想滤波器的几乎相同,就能满足要求。

(当然,位宽能够尽量量化大点,但相应的也更浪费资源)



(a)



(b)

图1 f1=5MHz,f2 = 15MHz滤波器的幅频特性



(a)



(b)

图2 f1=2.6MHz,f2 = 19.3MHz滤波器的幅频特性



图3 量化位宽不足



图4 量化位宽合适

文件:filter_coe.m

clc;

clear all;

fs = 50e6; %採样频率

f1 = 2.6e6;

f2 = 19.3e6;

N = 5; %5阶

Rp = 60;%阻带衰减

Wn = [2*f1/fs 2*f2/fs];%截止频率

% Qcoe=8; %滤波器系数字长

% Qout=8; %滤波器输出字长

Qcoe=13; %滤波器系数字长

Qout=14; %滤波器输出字长

delta=[1,zeros(1,511)]; %单位冲激信号作为输入信号

[b,a] = cheby2(N,Rp,Wn);

figure(1)

freqz(b,a,1024,fs);

%对滤波器系数进行量化,四舍五入截尾

%量化系数

m = max(max(abs(a)),max(abs(b)));

Qm = floor(log2(m/a(1))); %向下取整

if Qm < log2(m/a(1))

Qm = Qm + 1;

end

Qm = 2^Qm;

Qa = round(a/Qm*(2^(Qcoe-1)-1)) %四舍五入取整

Qb = round(b/Qm*(2^(Qcoe-1)-1)) %四舍五入取整

%求理想幅度响应

y=filter(b,a,delta);

%求量化后的幅度响应。QuantIIRDirectArith为自编的依据系数及输出数据量化位数计算

%IIR滤波器输出的函数

Quant = QuantIIR(Qb,Qa,delta,Qcoe,Qout);

%求滤波器输出幅频响应

Fy=20*log10(abs(fft(y))); Fy=Fy-max(Fy);

FQuant=20*log10(abs(fft(Quant))); FQuant=FQuant-max(FQuant);

%设置幅频响应的横坐标单位为Hz

x_f=[0:(fs/length(delta)):fs-1];

figure(2);

plot(x_f,Fy,’-‘,x_f,FQuant,’.’);

axis([0 fs/2 -100 5]); %仅仅显示正频率部分的幅频响应

xlabel(‘频率(Hz)’);ylabel(‘幅度(dB)’);

legend(‘理想输出’,’量化后输出结果’);

grid on;

(2)产生激励信号用作仿真

这里产生频率分别为:80KHz。10MHz,20MHz的三个正弦波叠加。对它做14bit量化,并以二进制存入txt文件里。在modelsim仿真时,读取txt文件的数据作为设计输入。



图4 激励信号

文件:test_signal_produce.m

clc;

clear all;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%变量声明区

f1 = 80e3; %80KHz

f2 = 12e6; %12MHz

f3 = 20e6; %20MHz

fs = 50e6; %採样频率50MHz

data_num = 10000; %存10000个数据

width = 8; %输入数据量化位宽

len = 2^nextpow2(data_num); %fft长度

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%数据产生区

t = (0:data_num-1)/fs;

x = sin(2*pi*f1*t) + sin(2*pi*f2*t) + sin(2*pi*f3*t);

x = x/max(abs(x)); %归一化

Q_x = round(x*(2^(width-1)-1)); %量化

fft_x = fft(x,len);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%将数据以二进制形式写入txt文件

fid = fopen(‘C:\Users\lidong\Desktop\iir_bpf\Matlab\xin.txt’,’w+’);

for i=1:length(Q_x)

x_bit = dec2bin(Q_x(i)+(Q_x(i)<0)*2^width,width);

for j=1:width

if x_bit(j) == ‘1’

tb = 1;

else

tb = 0;

end

fprintf(fid,’%d’,tb);

end

fprintf(fid,’\n’);

end

fprintf(fid,’;’);

fclose(fid);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%滤波器

fs = 50e6; %採样频率

fc1 = 2.6e6;

fc2 = 19.3e6;

N = 5; %5阶

Rp = 60;%阻带衰减

Wn = [2*fc1/fs 2*fc2/fs];%截止频率

[b,a] = cheby2(N,Rp,Wn);

f = fs*(0:len/2 - 1)/len;

filter_x = filter(b,a,x);

y = fft(filter_x,len);

subplot(2,2,1);

plot(t,x);

title(‘原始信号(时域)’);

grid on;

subplot(2,2,2);

plot(f,abs(fft_x(1:len/2)));

title(‘原始信号(频域)’);

xlabel(‘Hz’);ylabel(‘幅值’);

grid on;

subplot(2,2,3);

plot(filter_x(1:200));

title(‘滤波后(时域)’);

grid on;

subplot(2,2,4);

plot(f,abs(y(1:len/2)));

title(‘滤波后(时域)’);

xlabel(‘Hz’);ylabel(‘幅值’);

grid on;

(3)依据直接型框图编写verilog程序

文件:iir_bpf.v

/*******************************************************************************************************************************************************

模块名:iir_bpf

功能:实现通带为5-15MHz,阻带衰减为60dB的5阶IIR带通滤波器(採样频率为50MHz),採用切比雪夫II型函数设计

參数:clk为模块的时钟,50MHz;rst_n是模块的复位信号,低电平有效,异步复位;xin是模块输入。位宽14bit。yout是滤波后的输出,也是14bit。

滤波器量化后的系数(13bits量化)为:

分子b = [38 -20 -131 27 230 0 -230 -27 131 20 -38]

分母a = [1024 -2337 3127 -3241 3071 -2227 1268 -587 238 -60 9]

时间:2016.3.26

作者:冬瓜

Email:lidong10280528@163.com

*******************************************************************************************************************************************************/

module iir_bpf

(

input wire clk, //FPGA时钟50MHz

input wire rst_n, //复位信号,低电平有效

input wire [ 13:0 ] xin, // 数据输入

output reg [ 13:0 ] yout // 滤波后的数据输出

);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//变量声明区

reg signed[ 13:0 ] xin_r1,xin_r2,xin_r3,xin_r4,xin_r5;

reg signed[ 13:0 ] xin_r6,xin_r7,xin_r8,xin_r9,xin_r10,xin_r11;

reg signed[ 13:0 ] yin_r1,yin_r2,yin_r3,yin_r4,yin_r5;

reg signed[ 13:0 ] yin_r6,yin_r7,yin_r8,yin_r9,yin_r10,yin_r11;

wire signed[ 26:0 ] xmult_w0,xmult_w1,xmult_w2,xmult_w3,xmult_w4;

wire signed[ 26:0 ] xmult_w5,xmult_w6,xmult_w7,xmult_w8,xmult_w9,xmult_w10;

wire signed[ 26:0 ] ymult_w1,ymult_w2,ymult_w3,ymult_w4,ymult_w5;

wire signed[ 26:0 ] ymult_w6,ymult_w7,ymult_w8,ymult_w9,ymult_w10;

wire signed[ 30:0 ] feedforward;

wire signed[ 30:0 ] feedback;

wire signed[ 31:0 ] ysum;

wire signed[ 31:0 ] ydiv;

wire signed[ 13:0 ] yin;

wire signed [12:0 ] coeb[10:0]; //滤波器系数,分子b

wire signed [12:0 ] coea[10:0]; //滤波器系数,分母a

assign coea[0] = 13’d1024;

assign coea[1] = -13’d2337;

assign coea[2] = 13’d3127;

assign coea[3] = -13’d3241;

assign coea[4] = 13’d3071;

assign coea[5] = -13’d2227;

assign coea[6] = 13’d1268;

assign coea[7] = -13’d587;

assign coea[8] = 13’d238;

assign coea[9] = -13’d60;

assign coea[10] = 13’d9;

assign coeb[0] = 13’d38;

assign coeb[1] = -13’d20;

assign coeb[2] = -13’d131;

assign coeb[3] = 13’d27;

assign coeb[4] = 13’d230;

assign coeb[5] = 13’d0;

assign coeb[6] = -13’d230;

assign coeb[7] = -13’d27;

assign coeb[8] = 13’d131;

assign coeb[9] = 13’d20;

assign coeb[10] = -13’d38;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

always @(posedge clk or negedge rst_n)

if (rst_n == 1’b0) //初始化寄存器

begin

xin_r1 <= ‘d0;

xin_r2 <= ‘d0;

xin_r3 <= ‘d0;

xin_r4 <= ‘d0;

xin_r5 <= ‘d0;

xin_r6 <= ‘d0;

xin_r7 <= ‘d0;

xin_r8 <= ‘d0;

xin_r9 <= ‘d0;

xin_r10 <= ‘d0;

xin_r11 <= ‘d0;

end

else

begin

xin_r1 <= xin;

xin_r2 <= xin_r1;

xin_r3 <= xin_r2;

xin_r4 <= xin_r3;

xin_r5 <= xin_r4;

xin_r6 <= xin_r5;

xin_r7 <= xin_r6;

xin_r8 <= xin_r7;

xin_r9 <= xin_r8;

xin_r10 <= xin_r9;

xin_r11 <= xin_r10;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//分子b = [38 -20 -131 27 230 0 -230 -27 131 20 -38]

mult14x13 mult14x13_instb1 (

.dataa ( xin ),

.datab ( coeb[0] ),

.result ( xmult_w0 )

);

mult14x13 mult14x13_instb2 (

.dataa ( xin_r1 ),

.datab ( coeb[1] ),

.result ( xmult_w1 )

);

mult14x13 mult14x13_instb3 (

.dataa ( xin_r2 ),

.datab ( coeb[2] ),

.result ( xmult_w2 )

);

mult14x13 mult14x13_instb4 (

.dataa ( xin_r3 ),

.datab ( coeb[3] ),

.result ( xmult_w3 )

);

mult14x13 mult14x13_instb5 (

.dataa ( xin_r4 ),

.datab ( coeb[4] ),

.result ( xmult_w4 )

);

mult14x13 mult14x13_instb6 (

.dataa ( xin_r5 ),

.datab ( coeb[5] ),

.result ( xmult_w5 )

);

mult14x13 mult14x13_instb7 (

.dataa ( xin_r6 ),

.datab ( coeb[6] ),

.result ( xmult_w6 )

);

mult14x13 mult14x13_instb8 (

.dataa ( xin_r7 ),

.datab ( coeb[7] ),

.result ( xmult_w7 )

);

mult14x13 mult14x13_instb9 (

.dataa ( xin_r8 ),

.datab ( coeb[8] ),

.result ( xmult_w8 )

);

mult14x13 mult14x13_instb10 (

.dataa ( xin_r9 ),

.datab ( coeb[9] ),

.result ( xmult_w9 )

);

mult14x13 mult14x13_instb11 (

.dataa ( xin_r10 ),

.datab ( coeb[10] ),

.result ( xmult_w10 )

);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//计算总的零点系数

always @(posedge clk or negedge rst_n)

if( rst_n == 1’b0)

feedforward <= ‘d0;

else

feedforward <= {{4{xmult_w0[26]}},xmult_w0} + {{4{xmult_w1[26]}},xmult_w1} + {{4{xmult_w2[26]}},xmult_w2} + {{4{xmult_w3[26]}},xmult_w3} +

{{4{xmult_w4[26]}},xmult_w4} + {{4{xmult_w5[26]}},xmult_w5} + {{4{xmult_w6[26]}},xmult_w6} + {{4{xmult_w7[26]}},xmult_w7} +

{{4{xmult_w8[26]}},xmult_w8} + {{4{xmult_w9[26]}},xmult_w9} + {{4{xmult_w10[26]}},xmult_w10};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

always @(posedge clk or negedge rst_n)

if (rst_n == 1’b0 )

begin //初始化寄存器

yin_r1 <= ‘d0;

yin_r2 <= ‘d0;

yin_r3 <= ‘d0;

yin_r4 <= ‘d0;

yin_r5 <= ‘d0;

yin_r6 <= ‘d0;

yin_r7 <= ‘d0;

yin_r8 <= ‘d0;

yin_r9 <= ‘d0;

yin_r10 <= ‘d0;

yin_r11 <= ‘d0;

end

else

begin

yin_r1 <= yin;

yin_r2 <= yin_r1;

yin_r3 <= yin_r2;

yin_r4 <= yin_r3;

yin_r5 <= yin_r4;

yin_r6 <= yin_r5;

yin_r7 <= yin_r6;

yin_r8 <= yin_r7;

yin_r9 <= yin_r8;

yin_r10 <= yin_r9;

yin_r11 <= yin_r10;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////

//分母a = [1024 -2337 3127 -3241 3071 -2227 1268 -587 238 -60 9]

mult14x13 mult14x13_insta1 (

.dataa ( yin_r1 ),

.datab ( coea[1] ),

.result ( ymult_w1 )

);

mult14x13 mult14x13_insta2 (

.dataa ( yin_r2 ),

.datab ( coea[2] ),

.result ( ymult_w2 )

);

mult14x13 mult14x13_insta3 (

.dataa ( yin_r3 ),

.datab ( coea[3] ),

.result ( ymult_w3 )

);

mult14x13 mult14x13_insta4 (

.dataa ( yin_r4 ),

.datab ( coea[4] ),

.result ( ymult_w4 )

);

mult14x13 mult14x13_insta5 (

.dataa ( yin_r5 ),

.datab ( coea[5] ),

.result ( ymult_w5 )

);

mult14x13 mult14x13_insta6 (

.dataa ( yin_r6 ),

.datab ( coea[6] ),

.result ( ymult_w6 )

);

mult14x13 mult14x13_insta7 (

.dataa ( yin_r7 ),

.datab ( coea[7] ),

.result ( ymult_w7 )

);

mult14x13 mult14x13_insta8 (

.dataa ( yin_r8 ),

.datab ( coea[8] ),

.result ( ymult_w8 )

);

mult14x13 mult14x13_insta9 (

.dataa ( yin_r9 ),

.datab ( coea[9] ),

.result ( ymult_w9 )

);

mult14x13 mult14x13_insta10 (

.dataa ( yin_r10 ),

.datab ( coea[10] ),

.result ( ymult_w10 )

);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//计算总的极点系数

assign feedforward = {{4{xmult_w0[26]}},xmult_w0} + {{4{xmult_w1[26]}},xmult_w1} + {{4{xmult_w2[26]}},xmult_w2} + {{4{xmult_w3[26]}},xmult_w3} +

{{4{xmult_w4[26]}},xmult_w4} + {{4{xmult_w5[26]}},xmult_w5} + {{4{xmult_w6[26]}},xmult_w6} + {{4{xmult_w7[26]}},xmult_w7} +

{{4{xmult_w8[26]}},xmult_w8} + {{4{xmult_w9[26]}},xmult_w9} + {{4{xmult_w10[26]}},xmult_w10};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//计算最后的输出

assign ysum = {{{feedforward[30]}},feedforward} - {{feedback[30]},feedback};//31bits

assign ydiv = {{10{ysum[30]}},ysum[30:10]};

assign yin = ydiv[ 13:0 ];

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//最后结果加一级寄存器。提高系统频率

always @(posedge clk)

yout <= ydiv[ 13:0 ];

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

endmodule

(4)Modelsim仿真

编写激励文件iir_bpf_tb.v和脚本文件run.do。并新建project,在命令窗执行run.do文件。如图5,图6输入数据(xin)为多个正弦波叠加。经过滤波器后,输出(yout)为单一的正弦波,执行完后Modelsim会把输出数据存储在txt文件里给Matlab分析。

图5 Modelsim仿真1

图6 Modelsim仿真2

文件:iir_bpf_tb.v

`timescale 1 ns/1 ns

module iir_bpf_tb();

///////////////////////////////////////////////////////////////////////////////////

//变量声明区

parameter clk_period = 20; //50MHz

parameter half_clk_period = clk_period/2;

parameter data_num = 10000;

parameter time_sim = data_num*clk_period;

integer i;

integer fid;

reg clk;

reg rst_n;

reg [7:0 ] xin;

reg [7:0 ] stimulus[1:data_num];

wire clk_write;

wire signed [13:0] yout;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//产生时钟和复位信号

initial

begin

clk = 0;

rst_n = 0;

#400;

rst_n = 1;

#time_sim stop;  
  end  
always #half_clk_period clk = ~clk;  
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
//读取文件数据,作为滤波器输入  
initial  
  beginreadmemb(“xin.txt”,stimulus);

i = 0;

#350;

repeat(data_num)

begin

i = i + 1;

@(posedge clk);

xin = stimulus[i];

end

end

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//将滤波器输出数据存入文件里,给Matlab分析

initial

begin

fid = fopen(“yout.txt”);if(!fid)begindisplay(“Cannot open the file!”);

$finish;

end

end

always @(posedge clk_write)

$fdisplay(fid,”%d”,yout);

assign clk_write = rst_n & clk;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//例化

iir_bpf iir_bpf_inst

(

.clk (clk), //FPGA时钟50MHz

.rst_n (rst_n), //复位信号,低电平有效

.xin (xin), // 数据输入

.yout (yout) // 滤波后的数据输出

);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

endmodule

文件:run.do

quit -sim

.main clear

vlib work

vmap work work

vlog ./iir_bpf_tb.v

vlog ./altera_lib/*.v

vlog ./../quartus_prj/ipcore_dir/mult8x16.v

vlog ./../quartus_prj/ipcore_dir/mult16x16.v

vlog ./../design/*.v

vsim -voptargs=+acc -L work work.iir_bpf_tb

add wave -divider { tb }

add wave iir_bpf_tb/*

add wave -divider { iir_bpf }

add wave iir_bpf_tb/iir_bpf_inst/*

run 50us

(5)Matlab仿真

用Matlab读取Modelsim产生的txt文件里的数据,如图7。滤波器输出数据的频谱为单一的10MHz的正弦波信号。



图7 Matlab仿真

文件:filter_analysis.m

clc;

clear all;

fs = 50e6;

%打开文件,并读取数据

fid_out = fopen(‘C:\Users\lidong\Desktop\iir_bpf\sim\yout.txt’,’r’);

[yout,N_out] = fscanf(fid_out,’%d’,inf);

fclose(fid_out);

%画时域波形

subplot(211);

plot(yout(1:100));

title(‘FPGA仿真滤波后的时域波形’);

grid on;

%归一化处理

NFFT2 = 2^nextpow2(N_out);

yout=yout/max(abs(yout));

Fout=20*log10(abs(fft(yout,NFFT2)));

Fout=Fout-max(Fout);

%画频域波形

subplot(212);

x_f=[0:(fs/length(Fout)):fs/2];

plot(x_f,Fout(1:length(x_f)),’–’);

axis([0 fs/2 -100 3]);

xlabel(‘频率(Hz)’);ylabel(‘幅度(dB)’);title(‘FPGA仿真滤波后的频谱’);

grid on;

4.遇到的问题及解决方式

(1)进行Modelsim仿真时,极点有关的寄存器以及输出均为未知状态x

解决方式:出现未知状态的原因是:開始输入数据的时间控制不正确,必须在复位结束前把数据输入进来。比如复位时间是400ns,假设是在400ns之后数据输入就会导致这种现象



图8 复位时间



图9 数据输入时间



图10 出现仿真问题



图11 改动输入数据開始时间



图12 正常仿真

(2)用Matlab对modelsim的输出仿真时,出现谐波和直流分量

解决方式:出现谐波的原因是:modelsim输出的数据(yout)不为signed型,能够在matlab仿真时,先检查文件里数据的时域波形。再看频域。



图13



图14 Matlab仿真出错

5.系统优化

(1)在计算feedforward时。加入寄存器。对于一个FPGA时序电路来讲。决定整个电路运算速度是单个时钟周期内逻辑运算最多的环节。

在上述程序中。完毕一次完整的IIR滤波,须要10次常系数乘法运算。1次10输入的加减法运算和一次一位运算。显然一个时钟周期的逻辑运算量太大,因此在计算ysum之前,添加一级寄存器,相当于输入数据进行一个时钟周期的延迟。不影响滤波的结果。但在运算速度上,相当于原来1个周期的运算量採用两个时钟周期完毕。

(2)乘法运算后的位宽能够优化1bit,因为位宽分别为N,M的两数据相乘,结果位宽是不超过M+N。并且仅仅有在输入数据的最高位为1,其余位位0时。才会为(M+N)bit宽。因此用(M+N-1)bit表示输出结果时。相当于用-2^M + 1对 -2^M进行近似处理。

(3)能够用移位与加法运算取代乘法运算。比如系数为238时,如图15,但有些可能有多种移位方案,如图16,3071有两种方案,但显然方案2要优于方案1。因为方案2的加法运算级数更少。



图15 乘法优化



图16

技巧:通过移位和累加取代乘法限制了滤波器系数的灵活性,并且编程时比較头疼。总结一下经验(以编写yin_r4*3071为例):

先确定好几个数:assign ymult_w4 = {yin_r4,12’d0} + {yin_r4,12’d0} + {yin_r4,12’d0};

确定好前面的符号是加号还是减号:assign ymult_w4 = {yin_r4,12’d0} - {yin_r4,12’d0} - {yin_r4,12’d0};

确定拼接后面的数:assign ymult_w4 = {yin_r4,12’d0} - {yin_r4,10’d0} - {yin_r4,1’d0};

依据总位宽和输入位宽确定符号位扩展多少:assign ymult_w4 = {yin_r4,12’d0} - {{2{yin_r4[13]}},yin_r4,10’d0} - {{12{yin_r4[13]}},yin_r4};这里ymult_w* 位宽是26bit,而yin_r*是14bit,因此仅仅须要移的位数(yin_r*右边的数)和扩展的符号位数(yin_r*左边的数)之和为26-14 = 12即可,后面计算 ymult_w5, ymult_w6。

。。

都是一样的。

解皮带。绕大树。另外,在优化时也出现了错误,经过对照优化前后仿真图,找到了ymult_w1,ymult_w3移位算错了。从而定位到了a(1)。a(3)移位移错了。

(a)优化前



(b)优化后

图17

(4)加法的优化。

在得到feedback时,须要做9次加法,假设直接用连加。则这些加法器会一级一级的级联,组合逻辑延时太长。比如assign x = a + b + c +d + e + f;能够这样优化

assign x1 = a + b;

assign x2 = c+ d;

assign x3 = e+ f;

assign x4 = x1+ x2;

assign x = x3+ x4;

优化前后分别相应图18,图19。

能够看出优化前数据要经过5个加法器,优化后仅仅过3个加法器。



图18 优化前

图19 优化后

(5)因为本例採用cheby2型的IIR滤波器,分子b具有对称性,因此能够先做加/减法运算,再做乘法运算,能够节约一半乘法。

比如b(1) = -b(10) = 38那么先做减法add1 = (xin_r1 - xin_r10 )。再算乘法38*add1,即可降低一次乘法。

优化前后资源对照,尽管优化后会占用多一点的逻辑资源,但优化前的乘法器用去了91%的乘法器,而优化后是0%。

如图20。如图21,22,优化后功能并没有改变。



(a) 优化前

(b) 优化后

图20 优化前后资源对照



图21



图22

//优化后

/********************************************************************************

模块名:iir_bpf

功能:实现通带为5-15MHz,阻带衰减为60dB的5阶IIR带通滤波器(採样频率为50MHz),採用切比雪夫II型函数设计

时间:2016.3.26

作者:冬瓜

Email:lidong10280528@163.com

********************************************************************************/

module iir_bpf

(

input wire clk, //FPGA时钟50MHz

input wire rst_n, //复位信号,低电平有效

input wire [ 13:0 ] xin, // 数据输入

output reg [ 13:0 ] yout // 滤波后的数据输出

);

//////////////////////////////////////////////////////////////////////////////////////////////

//变量声明区

reg signed[ 30:0 ] feedforward;

reg signed[ 13:0 ] xin_r1,xin_r2,xin_r3,xin_r4,xin_r5;

reg signed[ 13:0 ] xin_r6,xin_r7,xin_r8,xin_r9,xin_r10;

reg signed[ 13:0 ] yin_r1,yin_r2,yin_r3,yin_r4,yin_r5;

reg signed[ 13:0 ] yin_r6,yin_r7,yin_r8,yin_r9,yin_r10;

wire signed[ 14:0 ] xadd0,xadd1,xadd2,xadd3,xadd4;

wire signed[ 25:0 ] xmult_w0,xmult_w1,xmult_w2,xmult_w3,xmult_w4;

wire signed[ 25:0 ] ymult_w1,ymult_w2,ymult_w3,ymult_w4,ymult_w5;

wire signed[ 25:0 ] ymult_w6,ymult_w7,ymult_w8,ymult_w9,ymult_w10;

wire signed[ 25:0 ] ymult_w1_1,ymult_w1_2;

wire signed[ 25:0 ] ymult_w2_1,ymult_w2_2;

wire signed[ 25:0 ] ymult_w3_1,ymult_w3_2;

wire signed[ 25:0 ] ymult_w5_1,ymult_w5_2;

wire signed[ 25:0 ] ymult_w6_1,ymult_w6_2;

wire signed[ 25:0 ] ymult_w7_1,ymult_w7_2;

wire signed[ 30:0 ] feedback;

wire signed[ 30:0 ] feedback1,feedback2,feedback3,feedback4;

wire signed[ 30:0 ] feedback5,feedback6,feedback7,feedback8;

wire signed[ 30:0 ] feedforward1,feedforward2,feedforward3;

wire signed[ 31:0 ] ysum;

wire signed[ 31:0 ] ydiv;

wire signed[ 13:0 ] yin;

//////////////////////////////////////////////////////////////////////////////////////////////

always @(posedge clk or negedge rst_n)

if (rst_n == 1’b0) //初始化寄存器

begin

xin_r1 <= ‘d0;

xin_r2 <= ‘d0;

xin_r3 <= ‘d0;

xin_r4 <= ‘d0;

xin_r5 <= ‘d0;

xin_r6 <= ‘d0;

xin_r7 <= ‘d0;

xin_r8 <= ‘d0;

xin_r9 <= ‘d0;

xin_r10 <= ‘d0;

end

else

begin

xin_r1 <= xin;

xin_r2 <= xin_r1;

xin_r3 <= xin_r2;

xin_r4 <= xin_r3;

xin_r5 <= xin_r4;

xin_r6 <= xin_r5;

xin_r7 <= xin_r6;

xin_r8 <= xin_r7;

xin_r9 <= xin_r8;

xin_r10 <= xin_r9;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//分子b = [38 -20 -131 27 230 0 -230 -27 131 20 -38]

//系数具有对称性。因此先做减法。再做乘法。节约一半乘法器

assign xadd0 = {xin[13],xin} - {xin_r10[13],xin_r10}; //15bits

assign xadd1 = {xin_r1[13],xin_r1} - {xin_r9[13],xin_r9};

assign xadd2 = {xin_r2[13],xin_r2} - {xin_r8[13],xin_r8};

assign xadd3 = {xin_r3[13],xin_r3} - {xin_r7[13],xin_r7};

assign xadd4 = {xin_r4[13],xin_r4} - {xin_r6[13],xin_r6};

//用移位与加法运算取代乘法运算

assign xmult_w0 = {{10{xadd0[14]}},xadd0,1’d0} + {{9{xadd0[14]}},xadd0,2’d0} + {{6{xadd0[14]}},xadd0,5’d0}; //26bit

assign xmult_w1 = -{{9{xadd1[14]}},xadd1,2’d0} - {{7{xadd1[14]}},xadd1,4’d0}; //26bit

assign xmult_w2 = -{{11{xadd2[14]}},xadd2} - {{10{xadd2[14]}},xadd2,1’d0} - {{4{xadd2[14]}},xadd2,7’d0}; //26bit

assign xmult_w3 = {{6{xadd3[14]}},xadd3,5’d0} - {{11{xadd3[14]}},xadd3} - {{9{xadd3[14]}},xadd3,2’d0}; //26bit

assign xmult_w4 = {{3{xadd4[14]}},xadd4,8’d0} - {{10{xadd4[14]}},xadd4,1’d0} - {{8{xadd4[14]}},xadd4,3’d0} - {{7{xadd4[14]}},xadd4,4’d0};//26bit

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//因为加法的级数太长,对其拆分,降低组合逻辑延时,提高系统的Fmax

assign feedforward1 = {{4{xmult_w0[25]}},xmult_w0} + {{4{xmult_w1[25]}},xmult_w1};

assign feedforward2 = {{4{xmult_w2[25]}},xmult_w2} + {{4{xmult_w3[25]}},xmult_w3};

assign feedforward3 = {{4{xmult_w4[25]}},xmult_w4} + feedforward1;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//计算总的零点系数

always @(posedge clk or negedge rst_n)

if( rst_n == 1’b0)

begin

feedforward <= ‘d0;

end

else

begin

feedforward <= feedforward2 + feedforward3;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

always @(posedge clk or negedge rst_n)

if (rst_n == 1’b0 )

begin //初始化寄存器

yin_r1 <= ‘d0;

yin_r2 <= ‘d0;

yin_r3 <= ‘d0;

yin_r4 <= ‘d0;

yin_r5 <= ‘d0;

yin_r6 <= ‘d0;

yin_r7 <= ‘d0;

yin_r8 <= ‘d0;

yin_r9 <= ‘d0;

yin_r10 <= ‘d0;

end

else

begin

yin_r1 <= yin;

yin_r2 <= yin_r1;

yin_r3 <= yin_r2;

yin_r4 <= yin_r3;

yin_r5 <= yin_r4;

yin_r6 <= yin_r5;

yin_r7 <= yin_r6;

yin_r8 <= yin_r7;

yin_r9 <= yin_r8;

yin_r10 <= yin_r9;

end

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//分母a = [1024 -2337 3127 -3241 3071 -2227 1268 -587 238 -60 9]

//用移位与加法运算取代乘法运算

//assign ymult_w1 = -{{12{yin_r1[13]}},yin_r1} - {{7{yin_r1[13]}},yin_r1,5’d0} - {{4{yin_r1[13]}},yin_r1,8’d0} -{{{yin_r1[13]}},yin_r1,11’d0};//26bits

//assign ymult_w2 = {{9{yin_r2[13]}},yin_r2,3’d0} + {{8{yin_r2[13]}},yin_r2,4’d0} + {{7{yin_r2[13]}},yin_r2,5’d0} + {{2{yin_r2[13]}},yin_r2,10’d0} + {{{yin_r2[13]}},yin_r2,11’d0} - {{12{yin_r2[13]}},yin_r2};//26bits

//assign ymult_w3 = -{{12{yin_r3[13]}},yin_r3} - {{9{yin_r3[13]}},yin_r3,3’d0} - {{7{yin_r3[13]}},yin_r3,5’d0} - {{5{yin_r3[13]}},yin_r3,7’d0} - {{2{yin_r3[13]}},yin_r3,10’d0} - {{yin_r3[13]},yin_r3,11’d0};//26bits

//assign ymult_w4 = {yin_r4,12’d0} - {{2{yin_r4[13]}},yin_r4,10’d0} - {{12{yin_r4[13]}},yin_r4}; //26bits

//assign ymult_w5 = -{{12{yin_r5[13]}},yin_r5} - {{11{yin_r5[13]}},yin_r5,1’d0} - {{8{yin_r5[13]}},yin_r5,4’d0} - {{7{yin_r5[13]}},yin_r5,5’d0} - {{5{yin_r5[13]}},yin_r5,7’d0} - {{yin_r5[13]},yin_r5,11’d0};//26bits

//assign ymult_w6 = {{2{yin_r6[13]}},yin_r6,10’d0} + {{4{yin_r6[13]}},yin_r6,8’d0} - {{10{yin_r6[13]}},yin_r6,2’d0} - {{9{yin_r6[13]}},yin_r6,3’d0}; //26bits

//assign ymult_w7 = -{{12{yin_r7[13]}},yin_r7} - {{11{yin_r7[13]}},yin_r7,1’d0} - {{9{yin_r7[13]}},yin_r7,3’d0} - {{6{yin_r7[13]}},yin_r7,6’d0} - {{3{yin_r7[13]}},yin_r7,9’d0};//26bits

//assign ymult_w8 = {{4{yin_r8[13]}},yin_r8,8’d0} - {{11{yin_r8[13]}},yin_r8,1’d0} - {{8{yin_r8[13]}},yin_r8,4’d0}; //26bits

//assign ymult_w9 = {{10{yin_r9[13]}},yin_r9,2’d0} - {{6{yin_r9[13]}},yin_r9,6’d0}; //26bits

//assign ymult_w10 = {{12{yin_r10[13]}},yin_r10} + {{9{yin_r10[13]}},yin_r10,3’d0};

assign ymult_w1_1 = -{{12{yin_r1[13]}},yin_r1} - {{7{yin_r1[13]}},yin_r1,5’d0};//26bits

assign ymult_w1_2 = -{{4{yin_r1[13]}},yin_r1,8’d0} - {{{yin_r1[13]}},yin_r1,11’d0};

assign ymult_w1 = ymult_w1_1 + ymult_w1_2;

assign ymult_w2_1 = {{9{yin_r2[13]}},yin_r2,3’d0} + {{8{yin_r2[13]}},yin_r2,4’d0} + {{7{yin_r2[13]}},yin_r2,5’d0};

assign ymult_w2_2 = {{2{yin_r2[13]}},yin_r2,10’d0} + {{{yin_r2[13]}},yin_r2,11’d0} - {{12{yin_r2[13]}},yin_r2};

assign ymult_w2 = ymult_w2_1 + ymult_w2_2;//26bits

assign ymult_w3_1 = -{{12{yin_r3[13]}},yin_r3} - {{9{yin_r3[13]}},yin_r3,3’d0} - {{7{yin_r3[13]}},yin_r3,5’d0};

assign ymult_w3_2 = -{{5{yin_r3[13]}},yin_r3,7’d0} - {{2{yin_r3[13]}},yin_r3,10’d0} - {{yin_r3[13]},yin_r3,11’d0};

assign ymult_w3 = ymult_w3_1 + ymult_w3_2; //26bits

assign ymult_w4 = {yin_r4,12’d0} - {{2{yin_r4[13]}},yin_r4,10’d0} - {{12{yin_r4[13]}},yin_r4}; //26bits

assign ymult_w5_1 = -{{12{yin_r5[13]}},yin_r5} - {{11{yin_r5[13]}},yin_r5,1’d0} - {{8{yin_r5[13]}},yin_r5,4’d0};

assign ymult_w5_2 = -{{7{yin_r5[13]}},yin_r5,5’d0} - {{5{yin_r5[13]}},yin_r5,7’d0} - {{yin_r5[13]},yin_r5,11’d0};

assign ymult_w5 = ymult_w5_1 + ymult_w5_2; //26bits

assign ymult_w6_1 = {{2{yin_r6[13]}},yin_r6,10’d0} + {{4{yin_r6[13]}},yin_r6,8’d0};

assign ymult_w6_2 = -{{10{yin_r6[13]}},yin_r6,2’d0} - {{9{yin_r6[13]}},yin_r6,3’d0};

assign ymult_w6 = ymult_w6_1 + ymult_w6_2; //26bits

assign ymult_w7_1 = -{{12{yin_r7[13]}},yin_r7} - {{11{yin_r7[13]}},yin_r7,1’d0} - {{9{yin_r7[13]}},yin_r7,3’d0};

assign ymult_w7_2 = -{{6{yin_r7[13]}},yin_r7,6’d0} - {{3{yin_r7[13]}},yin_r7,9’d0};

assign ymult_w7 = ymult_w7_1 + ymult_w7_2; //26bits

assign ymult_w8 = {{4{yin_r8[13]}},yin_r8,8’d0} - {{11{yin_r8[13]}},yin_r8,1’d0} - {{8{yin_r8[13]}},yin_r8,4’d0}; //26bits

assign ymult_w9 = {{10{yin_r9[13]}},yin_r9,2’d0} - {{6{yin_r9[13]}},yin_r9,6’d0}; //26bits

assign ymult_w10 = {{12{yin_r10[13]}},yin_r10} + {{9{yin_r10[13]}},yin_r10,3’d0};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////计算总的极点系数,因为加法的级数太长,对其拆分。降低组合逻辑延时,提高系统的Fmax

assign feedback1 = {{4{ymult_w1[25]}},ymult_w1} + {{4{ymult_w2[25]}},ymult_w2};

assign feedback2 = {{4{ymult_w3[25]}},ymult_w3} + {{4{ymult_w4[25]}},ymult_w4};

assign feedback3 = {{4{ymult_w5[25]}},ymult_w5} + {{4{ymult_w6[25]}},ymult_w6};

assign feedback4 = {{4{ymult_w7[25]}},ymult_w7} + {{4{ymult_w8[25]}},ymult_w8};

assign feedback5 = {{4{ymult_w9[25]}},ymult_w9} + {{4{ymult_w10[25]}},ymult_w10};

assign feedback6 = feedback1 + feedback2;

assign feedback7 = feedback3 + feedback4;

assign feedback8 = feedback6 + feedback7;

assign feedback = feedback5 + feedback8;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//计算最后的输出

assign ysum = {{{feedforward[30]}},feedforward} - {{feedback[30]},feedback};//31bits

assign ydiv = {{10{ysum[30]}},ysum[30:10]};

assign yin = ydiv[ 13:0 ];

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//最后结果加一级寄存器。提高系统频率

always @(posedge clk)

yout <= ydiv[ 13:0 ];

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

endmodule

iir调试记录的更多相关文章

  1. SPI 核软件调试记录

    SPI 核软件调试记录 1.首先说说int SpiFlashWaitForFlashReady(void)这一函数,基本上其它函数在执行的时候,都会事先执行一次此函数.    因为此函数的作用主要是用 ...

  2. Video Timing Controller v6.1软件调试记录

    Video Timing Controller v6.1软件调试记录 GUI配置: . case XVTC_VMODE_PAL: //576i@50 { TimingPtr->Interlace ...

  3. Video Test Pattern Generator(7.0)软件调试记录

    Video Test Pattern Generator(7.0)软件调试记录 . XVidC_VideoMode XVIDC_VM_576_50_I = XVIDC_VM_720x576_50_I ...

  4. MA82G5D16AS16 主频调试记录

    MA82G5D16AS16 主频调试记录 当 SCKS 设置 为 MCKDO / 128 时 MCU 的电流为 0.58mA,100UF 电容可以维持 0.5S,大概可以满足. 但是需要注意外围的线路 ...

  5. Apusic中间件结合MyEclipse进行远程调试记录

    Apusic中间件结合MyEclipse进行远程调试记录. 在金蝶域中正常部署应用. 启动金蝶中间件时使用"startapusic -ds"命令. 在MyEclipse的Run-- ...

  6. http://stblog.baidu-tech.com/?p=1684) coredump调试记录 - PHP篇 原创: 扶墙 贝壳产品技术 今天

    http://stblog.baidu-tech.com/?p=1684) coredump调试记录 - PHP篇 原创: 扶墙 贝壳产品技术 今天

  7. 基于freescale i.Mx6(ARM)的阿里云oss调试记录

    交叉编译阿里OSS调试记录 1.1 开通oss服务 具体参考以下链接: https://help.aliyun.com/document_detail/31884.html?spm=a2c4g.111 ...

  8. [ZJCTF 2019]EasyHeap | house of spirit 调试记录

    BUUCTF 上的题目,由于部分环境没有复现,解法是非期望的 house of spirit 第一次接触伪造堆的利用方式,exp 用的是 Pwnki 师傅的,本文为调试记录及心得体会. 逆向分析的过程 ...

  9. [未完] Linux 4.4 USB —— spiflash模拟usb大容量存储设备 调试记录 Gadget Mass Stroage

    linux 4.4 USB Gadget Mass Stroage 硬件平台: licheepi nano衍生 调试记录 驱动信息 │ This driver is a replacement for ...

随机推荐

  1. js22--链式调用

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  2. php课程 12-41 多态是什么

    php课程 12-41 多态是什么 一.总结 一句话总结:一种请求,多种响应(根据参数类型和数量) 1.function useUsb(Usb $usb){}这句话是什么意思? 判断$usb参数是否实 ...

  3. while 循环的理解

    if 与 while 的主要区别:if 只判断和执行一次,而 while 却代表着一个循环,执行多少次,要视情况而定: 两种情况(A.B)都会让循环体执行: while A or B: 两种情况(A. ...

  4. HDU 4010 Query on The Trees (动态树)(Link-Cut-Tree)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意; 先给你一棵树,有 \(4\) 种操作: 1.如果 \(x\) 和 \(y\) 不在同一 ...

  5. 26.多线程join detach

    #include <iostream> #include <thread> #include <array> #include <Windows.h> ...

  6. Android自定义系统分享面板

    在Android中实现分享有一种比较方便的方式,调用系统的分享面板来分享我们的应用.最基本的实现如下: public Intent getShareIntent(){ Intent intent = ...

  7. mysql集群搭建教程-基础篇

           计算机一级考试系统要用集群,目标是把集群搭建起来,保证一个库dang了,不会影响程序的运行.于是在孟海滨师哥的带领下开始了我的第一次搭建mysql集群,首先看了一些关于集群的资料,然后根 ...

  8. 玩转Bootstrap(基础) -- (6.导航条基础)

    1.导航条样例 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...

  9. poj 1191 棋盘切割 (压缩dp+记忆化搜索)

    一,题意: 中文题 二.分析: 主要利用压缩dp与记忆化搜索思想 三,代码: #include <iostream> #include <stdio.h> #include & ...

  10. 1.6 Python基础知识 - for循环

    在循环语句中,除了while循环外,还有一种循环叫for循环的循环语句,for循环语句用于遍历可迭代(什么是迭代?以及迭代的相关知识,我们到后面再进行阐述,这里只要记住就可以了.)对象集合中的元素,并 ...