问题描述
我在VHDL中实现了标准形式的FIR滤波器.我的目标是创建一个截止频率为5kHz的低通. ADC大约每20us向我发送一个新样本,因此频率约为50kHz.我的模拟输入信号是200Hz正弦波,另外还有5500Hz正弦波.我对FIR滤波器的期望是过滤掉高频. FIR应该不需要任何软件,而只需数字硬件即可工作.
I implemented a standard form FIR Filter in VHDL. My goal was to create a low pass with a cutoff frequency at 5kHz. The ADC hands me a new sample about every 20us, so with a frequency of about 50kHz. My analog input signal is a 200Hz sine wave with an additional 5500Hz sine wave. What I expect from the FIR filter is to filter out the high frequency. The FIR should work without any software, just digital Hardware.
我从ADC收到一个12位输入. DAC还与12位一起工作以生成模拟信号.对于数学运算,我实现了1.12定点算法. ADC仅给我正值(在0V-3.3V范围内工作).因此,对于1.12固定点,我只需添加一个"0"即可.在每个样本的开头.因此,样本"100010001000"被设置为"1000".变成"0.100010001000".系数由Matlab计算.我也用1.12定点算法表示它们.现在,当我将一个样本与一个系数相乘时,它变成一个2.24定点数.经过所有的乘法和求和运算后,我仍然收到2.24定点数.现在,我的问题是:当我将DAC的2.24截断为12位时,滤波器的值变化被切断了.这就是为什么我的滤波器为我的DAC提供与从ADC接收的输入相同的输出.我希望我能澄清一下,我的问题是什么.有什么办法解决这个问题? DAC必须使用12位.
From the ADC, I receive a 12 Bit Input. The DAC also works with 12 Bit to generate an analog signal.For the mathematecial operations, I implemented a 1.12 fixed point arithmetic. The ADC only gives me positive values (working from 0V - 3.3V). So for the 1.12 fixed point, I just add a "0" at the beginning of every sample. So a sample "100010001000" becomes a "0.100010001000". The coefficients were calculated by Matlab. I also represent them in 1.12 fixed point arithmetic. Now, when I multiply a sample with a coefficient, it becomes a 2.24 fixed point number. After all the multiplication and sum operations, I still receive a 2.24 fixed point number. Now, my problem is: When I truncate the 2.24 to 12 bit for the DAC, the change in the value by the filter is cut off. That's why my filter gives my DAC the same output, as it received as an input from the ADC. I hope I could clarify, what my problem is. Is there any way to solve that issue? The 12 Bit are mandatory for the DAC.
我将添加我的VHDL代码和图片,希望可以进一步解决该问题.
I will add my VHDL Code and a picture, that hopefully clarifies the problem additionally.
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;
图片应说明,截断后,输出与输入相同.
The picture should clarify, that after the truncation, the output is the same as the input.
频率响应
推荐答案
您的FIR过滤器的实现存在错误.如果您橡皮鸭调试以下部分,您将看到错误.
Your implementation of the FIR filter is bugged. If you rubber duck debug the following part you can see the error.
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
- ...
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输入一个常数.
You are multiplying always the same sample for the different coefficients thus is like feeding a constant to the FIR.
要使其正常工作,您必须将该部分更改为以下内容:
To make it work you have to change that part to something like:
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;
这篇关于VHDL截断会导致已实现的FIR滤波器出现故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!