EDA实验:FIR滤波器的设计(VHDL)
基于VHDL的FIR滤波器设计
目录
一:FIR基本介绍
“FIR(Finite Impulse Response)滤波器:有限长单位冲激响应滤波器,又称为非递归型滤波器,是数字信号处理系统中最基本的元件,它可以在保证任意幅频特性的同时具有严格的线性相频特性,同时其单位抽样响应是有限长的,因而滤波器是稳定的系统。因此,FIR滤波器在通信、图像处理、模式识别等领域都有着广泛的应用。”
二、实验要求
根据转置FIR 滤波器的原理,设计并调试一个滤波器长度为4的 DaubechiesDB4转置FIR滤波器,该滤波器的系数为G(Z)=0.48301+0.8365Z-1 +0.2241Z-2-0.1294Z-3。若将系数变换成8位(加上符号位)精度模式,则G(Z)=124/256+214Z-1/256+57Z-2/256-33Z-3/256
因此Y(n)=124 X(n)/256+214X(n-1)/256+57X(n-2)/256-33X(n-3)/256。并用GW48系列或其他EDA实验开发系统(事先应选定拟采用的实验芯片的型号)进行硬件验证。
图2.1 顶层电路图
整体思路分析:
首先是疑问:便是信号由什么产生? 如何传输让 FIR滤波器进行运算?当滤波器运算结果通过什么模块能够在数码管上显示?
那么来根据疑问来设计模块:为了能够控制整个程序是否运行,加入了按键控制模块。
为了驱动整个程序运行需要时钟的输入,可以由外部时钟或者内部时钟,这里我选择的外部时钟,要能够让人能够看见变化,需要对外部时钟进行分频,于是加入了分配器模块
为了能够测量多个数据,需要加入输入控制模块
为了能够将滤波器多次运算的结果分批次显示到数码管上需要添加输出控制模块
要在数码管上显示其中动态显示和动态扫描是缺少不了的,可以想象这个程序就是一个工厂的流水线工程流水线是源源不断的通过传输带传输产品,然后通过一系列加工然后输出,发货到全国各地
三、VHDL主要源程序
由整体电路图可以看出需要按键控制(KG)模块、分频器(CLKGEN)模块。动态扫描(CTRLS)模块、动态显示(DISPLAY)模块、FIR滤波器模块、输入控制(KZSR)模块、输出控制(XSKZQ)模块共七个模块。常用模块可以移植
3.1输入控制模块
--前端控制
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
--USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY KZSR IS
PORT(CLK:IN STD_LOGIC;
XOUT:OUT STD_LOGIC_VECTOR(8 DOWNTO 0);
LOAD:OUT STD_LOGIC;
COUT:OUT STD_LOGIC_VECTOR(8 DOWNTO 0));
END ENTITY KZSR;
ARCHITECTURE ART OF KZSR IS
SIGNAL SEL:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL A:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
PROCESS(SEL,CLK)
BEGIN
IF CLK'EVENT AND CLK='0' THEN
SEL<=SEL+'1';
ELSE
NULL;
END IF;
IF CLK'EVENT AND CLK='0' THEN
A<=A+'1';
ELSE NULL;
END IF;
CASE A IS
WHEN "0000"=>LOAD<='0';
WHEN "0001"=>LOAD<='0';
WHEN "0010"=>LOAD<='0';
WHEN "0011"=>LOAD<='0';
WHEN OTHERS=>LOAD<='1';
END CASE;
CASE SEL IS
WHEN "0000"=>COUT<="001111100";XOUT<="000000000";
WHEN "0001"=>COUT<="011010110";XOUT<="000000000";
WHEN "0010"=>COUT<="000111001";XOUT<="000000000";
WHEN "0011"=>COUT<="111011111";XOUT<="000000000";
WHEN "0100"=>XOUT<="001100100";COUT<="000000000";
WHEN "0101"=>XOUT<="010010110";COUT<="000000000";
WHEN "0110"=>XOUT<="011001000";COUT<="000000000";
WHEN "0111"=>XOUT<="011111010";COUT<="000000000";
WHEN OTHERS=>XOUT<="000000000";COUT<="000000000";
END CASE;
END PROCESS;
END ARCHITECTURE ART;
3.2输出控制模块
--后端控制
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY XSKZQ IS
PORT (ABCD:IN STD_LOGIC_VECTOR(10 DOWNTO 0); --是FIR运算的位宽
G,S,B,Q:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); --分离出四位的每一位数字 ,可以理解为拆分器
END ENTITY XSKZQ;
ARCHITECTURE ART OF XSKZQ IS
SIGNAL TEMP1,TEMP2,TEMP3,TEMP4:INTEGER RANGE 0 TO 9; --相对于最大四位数,每个位数的数值
SIGNAL T0,T1,T2,T3:INTEGER RANGE 0 TO 10#9999#; --这个四个数据的结果
BEGIN
PROCESS (ABCD) IS
BEGIN
T0<=CONV_INTEGER(ABCD);T1<=T0-T0/1000*1000;T2<=T1-T1/100*100;T3<=T2-T2/10*10;--CONV是转换函数
TEMP1<=T3; --这个才是提出每一个数据
TEMP2<=(T2-T3)/10;
TEMP3<=(T1-T2)/100;
TEMP4<=(T0-T1)/1000;
CASE TEMP1 IS
WHEN 0 =>G<="0000";
WHEN 1 =>G<="0001";
WHEN 2 =>G<="0010"; --后面代码对于DISPLAY里面的数字
WHEN 3 =>G<="0011";
WHEN 4 =>G<="0100";
WHEN 5 =>G<="0101";
WHEN 6 =>G<="0110";
WHEN 7 =>G<="0111";
WHEN 8 =>G<="1000";
WHEN 9 =>G<="1001";
WHEN OTHERS=>G<="0000";
END CASE;
CASE TEMP2 IS
WHEN 0 =>S<="0000";
WHEN 1 =>S<="0001";
WHEN 2 =>S<="0010";
WHEN 3 =>S<="0011";
WHEN 4 =>S<="0100";
WHEN 5 =>S<="0101";
WHEN 6 =>S<="0110";
WHEN 7 =>S<="0111";
WHEN 8 =>S<="1000";
WHEN 9 =>S<="1001";
WHEN OTHERS=>S<="0000";
END CASE;
CASE TEMP3 IS
WHEN 0 =>B<="0000" ;
WHEN 1 =>B<="0001";
WHEN 2 =>B<="0010";
WHEN 3 =>B<="0011";
WHEN 4 =>B<="0100";
WHEN 5 =>B<="0101";
WHEN 6 =>B<="0110";
WHEN 7 =>B<="0111";
WHEN 8 =>B<="1000";
WHEN 9 =>B<="1001";
WHEN OTHERS=>B<="0000";
END CASE;
CASE TEMP4 IS
WHEN 0 =>Q<="0000" ;
WHEN 1 =>Q<="0001";
WHEN 2 =>Q<="0010";
WHEN 3 =>Q<="0011";
WHEN 4 =>Q<="0100";
WHEN 5 =>Q<="0101";
WHEN 6 =>Q<="0110";
WHEN 7 =>Q<="0111";
WHEN 8 =>Q<="1000";
WHEN 9 =>Q<="1001";
WHEN OTHERS=>Q<="0000";
END CASE;
END PROCESS;
END ARCHITECTURE ART;
3.3 FIR滤波器模块
--FIR.VHD 8号口动态扫描 ,6号口为外部时钟3M
LIBRARY LPM;
USE LPM.LPM_COMPONENTS.ALL;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY FIR IS
GENERIC(W1:INTEGER:=9;
W2:INTEGER:=18;
W3:INTEGER:=19;
W4:INTEGER:=11;
L:INTEGER:=4;
MPIPE:INTEGER:=3);
PORT(CLK:IN STD_LOGIC;
LOAD_X:IN STD_LOGIC;
X_IN:IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
C_IN:IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
Y_OUT:OUT STD_LOGIC_VECTOR(W4-1 DOWNTO 0));
END ENTITY FIR;
ARCHITECTURE ART OF FIR IS
SUBTYPE N1BIT IS STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
SUBTYPE N2BIT IS STD_LOGIC_VECTOR(W2-1 DOWNTO 0);
SUBTYPE N3BIT IS STD_LOGIC_VECTOR(W3-1 DOWNTO 0);
TYPE ARRAY_N1BIT IS ARRAY(0 TO L-1) OF N1BIT;
TYPE ARRAY_N2BIT IS ARRAY(0 TO L-1) OF N2BIT;
TYPE ARRAY_N3BIT IS ARRAY(0 TO L-1) OF N3BIT;
SIGNAL X:N1BIT;
SIGNAL Y:N3BIT;
SIGNAL C:ARRAY_N1BIT;
SIGNAL P:ARRAY_N2BIT;
SIGNAL A:ARRAY_N3BIT;
BEGIN
LOAD:PROCESS IS
BEGIN
WAIT UNTIL CLK='1';
IF (LOAD_X='0')THEN
C(L-1)<=C_IN;
FOR I IN L-2 DOWNTO 0 LOOP
C(I)<=C(I+1);
END LOOP;
ELSE
X<=X_IN; --获得一个采样运算
END IF;
END PROCESS LOAD;
SOP:PROCESS(CLK)IS --乘加运算
BEGIN
IF CLK'EVENT AND(CLK='1')THEN
FOR I IN 0 TO L-2 LOOP --计算加法
A(I)<=(P(I)(W2-1)&P(I))+A(I+1);
END LOOP;
A(L-1)<=P(L-1)(W2-1)&P(L-1);
END IF;
Y<=A(0);
END PROCESS SOP;
MULGEN:FOR I IN 0 TO L-1 GENERATE
MULS:LPM_MULT --乘法运算
GENERIC MAP(LPM_WIDTHA=>W1,LPM_WIDTHB=>W1,
LPM_PIPELINE=>MPIPE,
LPM_REPRESENTATION=>"SIGNED",
LPM_WIDTHP=>W2,
LPM_WIDTHS=>W2)
PORT MAP(CLOCK=>CLK,DATAA=>X,
DATAB=>C(I),RESULT=>P(I));
END GENERATE;
Y_OUT<=Y(W3-1 DOWNTO W3-W4);
END ARCHITECTURE ART;
四:硬件实验现象
五:源代码分析
5.1 输入端代码分析
CLK是通过分配器获得的1hz的时钟,COUT是FIR滤波器系数,XOUT是输入数字。LOAD是控制FIR滤波器是否工作。当下降沿到来的时候,A和SEL进行加1操作,A决定LOAD的数值,LOAD决定FIR滤波器是否工作,SEL控制传输的数据,当LOAD=0的时候FIR滤波器开始工作。
首先需要将FIR滤波器的系数输入,COUT<=001111100化为二进制就是滤波器的第一个系数:124
后面依次类推即可,把FIR滤波器的4位系数(FIR滤波器的系数是固定死的)输入完成后便输入运算的数值。如果要调整运算的数字的个数,可以通过只改变波形中X—IN的值即可。
当LOAD为低电平时,将滤波器的系数输入,当LOAD为高电平时,将需要计算的数值输入进去,例如输入的X(1)为100则X(n)为100,X(n-1),X(n-2),,X(n-3)都为0,待人方程可得48,同理将第二个数字输入进去,则前俩个数字为有效数字,后俩位为0、
可以看到输入4个数字之后输入便是数字0,所以输入到第七个时,只有X(n-3)有数字,其他均为0,当第八个输入时,四个输入均为0,则输出为0。
(只改变仿真波形的输入值,硬件并不会出现任何改变,需要改动代码,硬件才会变化)
5.2输出模块代码分析
XSKZQ为输出代码控制,由于要分多次在数码管上显示,而又因为输入的数据是多位的
(类比于流水线,只需要把核心的程序设置好了,后面不管来多少产品都可以进行处理)
先将FIR滤波器运算的四位数STD_LOGIC类型的数据通过CONV_INTEGER类型转换成实数,并且将4位数的实数提出每个位数,例如 0150 分离出 0、1、5、0 每个位数通过传输到DISPLAY端来驱动数码管是否显示数据。
六:引脚锁定、
图6.1 硬件锁定图
由于要显示到数码管所以要配置引脚,其中选择产生时钟的由外部时钟产生,配置为六号口为时钟空,与3M频率的接口相连,通过分频器产生1S的时钟周期信号,CLK2为动态扫描端口,配置为8号端口。配置按键为8号按键。
要注意一点RTL图和原理图含义是不一样的。
图6.2 整体RTL图
大家还会遇到一些其他问题可以在底下提出,大家互相交流学习。
(如果需要源代码,后面我会进行开源)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)