filter - VHDL 截断导致实现的 FIR 滤波器出现故障
问题描述
我用 VHDL 实现了标准形式的 FIR 滤波器。我的目标是创建一个截止频率为 5kHz 的低通。ADC 大约每 20us 给我一个新样本,因此频率约为 50kHz。我的模拟输入信号是一个 200Hz 正弦波和一个额外的 5500Hz 正弦波。我对 FIR 滤波器的期望是滤除高频。FIR 无需任何软件即可工作,只需数字硬件即可。
从 ADC,我收到一个 12 位输入。DAC 还与 12 位一起工作以生成模拟信号。对于数学运算,我实现了 1.12 定点算法。ADC 只给我正值(从 0V - 3.3V 工作)。所以对于 1.12 的固定点,我只是在每个样本的开头添加一个“0”。所以样本“100010001000”变成了“0.100010001000”。系数由 Matlab 计算。我还用 1.12 定点算术表示它们。现在,当我将一个样本与一个系数相乘时,它变成了一个 2.24 的定点数。在所有的乘法和求和运算之后,我仍然收到一个 2.24 的定点数。现在,我的问题是:当我将 DAC 的 2.24 位截断为 12 位时,滤波器的值变化被截断。这就是为什么我的滤波器给我的 DAC 相同的输出,因为它作为来自 ADC 的输入接收。我希望我能澄清一下,我的问题是什么。有没有办法解决这个问题?DAC 必须使用 12 位。
我将添加我的 VHDL 代码和图片,希望能进一步澄清问题。
VHDL代码:
--
--Implementierung der Direktform eines FIR - Tiefpasses
--Kennwerte: Abtastrate: 50 kHz
--f_Durchlass = 0,8kHz
--f_stopp: 5kHz bei delta_s = 20dB Absenkung
--passband Ripple = 0,1db
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
use IEEE.math_real.all;
entity FIR_Test is
generic(N : integer := 20); --(Anzahl der Koeffizienten - 1)
port
(
x_in : in std_logic_vector(11 downto 0); --Input 12 Bit vom AD Wandler
clk : in std_logic; --Input Clk mit hoher Frequenz
rst : in std_logic; --Reset Active Low
enable_data : in std_logic; --next Sample von ADC
data_acknowledged : in std_logic; --DA hat Daten erhalten
filter_rdy : out std_logic; --Signalisiere dem DA ready.
y : out std_logic_vector(11 downto 0) --Output 12 Bit an den DA - Wandler
);
end FIR_Test;
architecture FIR_Test_arch of FIR_Test is
type tap_line is array(0 to N) of std_logic_vector(12 downto 0); --Typenerklärung: Array zum Verschieben
-- =(Zeitverzögern) des Inputs
type table is array(0 to N) of signed(12 downto 0); --Typenerklärung: Array aus Filterkoeffizienten,
--States
type states is (
waitForADC,
readData,
filter,
shiftToDA
);
signal x : tap_line;
constant coeff : table:= (
"1" & X"fcd",
"1" & X"ffd",
"0" & X"015",
"0" & X"03f",
"0" & X"07b",
"0" & X"0c4",
"0" & X"114",
"0" & X"161",
"0" & X"1a2",
"0" & X"1cc",
"0" & X"1db",
"0" & X"1cc",
"0" & X"1a2",
"0" & X"161",
"0" & X"114",
"0" & X"0c4",
"0" & X"07b",
"0" & X"03f",
"0" & X"015",
"1" & X"ffd",
"1" & X"fcd"
); --Koeffiziententabelle, von a_20 bis a_0
-- --Darstellung: signed 1.12 Bit Zahl
signal current_state : states := waitForADC; --Enthält den aktuellen Status, initialisiert mit "waitForADC"
signal filter_rdy_intern : std_logic := '0'; --Internes Signal für die fertige Filteroperation
signal data_read_ready : std_logic := '0'; --Daten einlesen fertig
signal test_sop : std_logic_vector (25 downto 0) := (others => '0');
begin
--Schreiben der Statemachine
write_statemachine : process(clk, rst)
begin
--Reset aktiv low
if (rst = '0') then
current_state <= waitForADC;
--Signaländerung bei steigender Flanke des 125MHz Clocks
elsif (rising_edge(clk)) then
if (enable_data = '1' and data_read_ready = '0' ) then --Nur 1x lesen
current_state <= readData;
elsif (data_read_ready = '1' and filter_rdy_intern = '0') then
current_state <= filter;
elsif (filter_rdy_intern = '1' and data_acknowledged = '0') then
current_state <= shiftToDA;
elsif (data_acknowledged = '1') then
current_state <= waitForADC;
else
NULL;
end if;
end if;
end process write_statemachine;
--Durchführen der Operationen abhängig vom State
statemachine : process(clk)
variable sop : signed(25 downto 0); --Variable für Zwischenergebnis der Multiplikation, Darstellung 2.24
variable counter_filter : integer range 0 to (N + 2);
begin
if (rising_edge(clk)) then
case (current_state) is
when waitForADC =>
filter_rdy_intern <= '0';
data_read_ready <= '0';
sop := (others => '0');
counter_filter := 0;
when readData =>
x(0) <= "0" & x_in; --Neues Datum einlesen und auf Position 0 des Arrays abspeichern. 0 vorne Anhängen für Darstellung
data_read_ready <= '1';
when filter =>
counter_filter := counter_filter + 1;
if (counter_filter <= N) then --Abbruchbedingung für Zeitverschiebung
x(counter_filter) <= x(counter_filter - 1); --Zeitverschiebung
else
NULL;
end if;
if (counter_filter <= (N+1)) then --Abbruchbedingung für Rechenoperation
sop := sop + coeff(counter_filter - 1) * signed(x(counter_filter - 1)); --Durchführung einer Multiplikation und einer Addition
test_sop <= std_logic_vector (sop);
else
filter_rdy_intern <= '1';
end if;
when shiftToDA =>
y <= std_logic_vector(sop(23 downto 12)); --Ergebnis in 11 Bit Form für AD, 13 Bit nach rechts geshiftet
filter_rdy <= '1';
end case;
else
NULL;
end if;
end process statemachine;
end FIR_Test_arch;
解决方案
您的 FIR 滤波器的实现有问题。如果你用橡皮鸭调试以下部分,你可以看到错误。
when filter =>
counter_filter := counter_filter + 1;
if (counter_filter <= N) then --Abbruchbedingung für Zeitverschiebung
x(counter_filter) <= x(counter_filter - 1); --Zeitverschiebung
else
NULL;
end if;
if (counter_filter <= (N+1)) then --Abbruchbedingung für Rechenoperation
sop := sop + coeff(counter_filter - 1) * signed(x(counter_filter - 1)); --Durchführung einer Multiplikation und einer Addition
test_sop <= std_logic_vector (sop);
else
filter_rdy_intern <= '1';
end if;
通过filter
状态的迭代:
counter_filter = 1
,x(1) = x(0) = x_in
,sop = sop + coeff(0)*x(0) = sop + coeff(0)*x_in
counter_filter = 2
,x(2) = x(1) = x_in
,sop = sop + coeff(1)*x(1) = sop + coeff(1)*x_in
counter_filter = 3
,x(3) = x(2) = x_in
,sop = sop + coeff(2)*x(2) = sop + coeff(2)*x_in
- ...
您总是为不同的系数乘以相同的样本,因此就像向 FIR 提供一个常数。
要使其工作,您必须将该部分更改为:
when filter =>
if (counter_filter < N) then --Abbruchbedingung für Zeitverschiebung
x(N-counter_filter) <= x(N-counter_filter - 1); --Zeitverschiebung
else
NULL;
end if;
if (counter_filter < (N+1)) then --Abbruchbedingung für Rechenoperation
sop := sop + coeff(N-counter_filter) * signed(x(N-counter_filter)); --Durchführung einer Multiplikation und einer Addition
test_sop <= std_logic_vector (sop);
else
filter_rdy_intern <= '1';
end if;
counter_filter := counter_filter + 1;
推荐阅读
- sql - 如何对两个 SQL 查询使用 IF 或 CASE JOINED 遍历每条记录
- javascript - 如何在 NodeJS 中运行函数并向客户端发送响应?
- c++ - windows.h 的 C++ 问题,在 vs17 中非法声明匿名“结构”
- php - Laravel 新错误显示包(Ignition)导致共享主机出错
- c# - 有没有办法用openxml制作一个只读段落?
- dask - 能够锁定 dask 工作人员,直到某些后期任务/步骤完成
- hadoop - Hadoop:在 hadoop 命令中使用 wikipediaminer jar 文件时出错
- python - Python:单词搜索
- python - 如何让 Selenium 登录 Costco.com 网站
- javascript - 将一种类型的嵌套对象数组映射到另一种类型的对象嵌套数组的通用方法