Hi!
I have a problem with IIR filter. On the output I have a input sin
signal but the filter doesn't suppress the signal. It behaviour is that
as rewrite
input signal to output. I think that the problem is in the subtraction
operation or types. Fcut=2MHz. Code below:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.NUMERIC_STD.ALL;
entity dsp is
Port ( clk : in STD_LOGIC := '0';
clk_adc : out STD_LOGIC := '0';
clk_dac : out STD_LOGIC := '0';
adc_data : in STD_LOGIC_VECTOR(9 downto 0) := (others =>
'0');
dac_data : out STD_LOGIC_VECTOR(9 downto 0) := (others =>
'0')
);
end dsp;
architecture Behavioral of dsp is
constant coeff_a0: integer := 128; --coefficients
constant coeff_a1: integer := 256;
constant coeff_a2: integer := 128;
constant coeff_b0: integer := -293;
constant coeff_b1: integer := 106;
constant offset: STD_LOGIC_VECTOR(9 downto 0) := "1000000000";
signal adc_buffer: signed(9 downto 0) := (others => '0');
signal dac_buffer: STD_LOGIC_VECTOR(9 downto 0) := (others => '0');
signal mult_a0: signed(19 downto 0):= (others => '0'); --mult registers
signal mult_a1: signed(19 downto 0):= (others => '0');
signal mult_a2: signed(19 downto 0):= (others => '0');
signal mult_b0: signed(19 downto 0):= (others => '0');
signal mult_b1: signed(19 downto 0):= (others => '0');
signal tmult_a0: signed(9 downto 0):= (others => '0'); --truncate
registers
signal tmult_a1: signed(9 downto 0):= (others => '0');
signal tmult_a2: signed(9 downto 0):= (others => '0');
signal tmult_b0: signed(9 downto 0):= (others => '0');
signal tmult_b1: signed(9 downto 0):= (others => '0');
signal add_all: signed(9 downto 0):= (others => '0');
signal pipe_a0: signed(9 downto 0) := (others => '0'); --delay registers
signal pipe_a1: signed(9 downto 0) := (others => '0');
signal pipe_a2: signed(9 downto 0) := (others => '0');
signal pipe_b0: signed(9 downto 0) := (others => '0');
signal pipe_b1: signed(9 downto 0) := (others => '0');
begin
P0: process(clk)
begin
if falling_edge(clk) then
adc_buffer <= signed(adc_data); -- adc give data in U2 code
pipe_a0 <= adc_buffer;
pipe_a1 <= pipe_a0;
pipe_a2 <= pipe_a1;
pipe_b0 <= signed(add_all);
pipe_b1 <= pipe_b0;
dac_data <= dac_buffer(9 downto 0); -- write to dac
end if;
end process;
mult_a0 <= pipe_a0*to_signed(coeff_a0,10); -- multiplication
mult_a1 <= pipe_a1*to_signed(coeff_a1,10);
mult_a2 <= pipe_a2*to_signed(coeff_a2,10);
mult_b0 <= pipe_b0*to_signed(coeff_b0,10);
mult_b1 <= pipe_b1*to_signed(coeff_b1,10);
tmult_a0 <= mult_a0(19 downto 10); -- truncate to 10 bits
tmult_a1 <= mult_a1(19 downto 10);
tmult_a2 <= mult_a2(19 downto 10);
tmult_b0 <= mult_b0(19 downto 10);
tmult_b1 <= mult_b1(19 downto 10);
--sum (add and substract)
add_all <= tmult_a0 + tmult_a1 + tmult_a2 - tmult_b0 - tmult_b1;
dac_buffer <= STD_LOGIC_VECTOR(add_all) + offset; -- to offset binary
convertion
clk_adc <= clk;
clk_dac <= clk;
end Behavioral;
Chris C. wrote: > if falling_edge(clk) then THIS IS NONSENSE. THERE IS NO FALLING CLOCK SENSITIVE FF IN AN FPGA. > clk_adc <= clk; > clk_dac <= clk; THIS IS BAD! CLOCKS CANNOT BE ROUTET OUT. also TRUNCATION IS TO EARLY.
Chris C. wrote: > use IEEE.STD_LOGIC_unsigned.ALL; > use IEEE.NUMERIC_STD.ALL; Use the first one or use the second one. But never ever use both of them together. Best is to use the numeric_std and its conversions and casts. See how simple that is: http://www.lothar-miller.de/s9y/categories/16-Numeric_Std Try Google translator, it's German...
Beside all the other mentioned problems: What is your main clock frequency? I've added a testbench to the see the filter effect. For me it looks like your cutoff frequency is to high. Duke
My clock frequency -> 100MHz
In code below coefficient are for 4MHz cut-off frequency but I dont know
if they are correct. In new code is is easy to change coefficients.
I need coefficients only to test my filter. I would be gratefull if
somebody generate coefficient (10 bit) to low-pass with cut-off beetwenn
1-10MHz.
I dont know what to do with overflow bits. If I have 23-bit ad_all
signal the output amplitude is 4 times lower than when I have 19-bit
ad_all signal.
It probably means that the overflow bits doesn't occur. In my opinion
the sum of 5 signed 19-bit signals should be stored in 23-bit signal.
Secondly is that if I operate on signed values I should be carefull with
math operations signs (+/-). If I add negative values as a constant
signed, in operation of sum of the signals I must use only "+" sign.
I ignored all overflow bits.
It is possible that I have only wrong coefficient. On hardware filter
works but not correct.
My new, some improved code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity dsp is
Port ( clk : in STD_LOGIC := '0';
clk_adc : out STD_LOGIC := '0';
clk_dac : out STD_LOGIC := '0';
adc_data : in STD_LOGIC_VECTOR(9 downto 0) := (others =>
'0');
dac_data : out STD_LOGIC_VECTOR(9 downto 0) := (others =>
'0')
);
end dsp;
architecture Behavioral of dsp is
constant coeff_a0: integer := 133; --coefficients
constant coeff_a1: integer := 262;
constant coeff_a2: integer := 133;
constant coeff_b0: integer := -164;
constant coeff_b1: integer := 70;
constant offset: signed(9 downto 0) := "0111111111"; -- +511 in U2
signal adc_buffer: signed(9 downto 0) := (others => '0');
signal dac_buffer: signed(9 downto 0) := (others => '0');
signal mult_a0: signed(19 downto 0):= (others => '0'); --mult registers
signal mult_a1: signed(19 downto 0):= (others => '0');
signal mult_a2: signed(19 downto 0):= (others => '0');
signal mult_b0: signed(19 downto 0):= (others => '0');
signal mult_b1: signed(19 downto 0):= (others => '0');
signal add_all: signed(19 downto 0):= (others => '0');
signal pipe_a0: signed(9 downto 0) := (others => '0'); --delay registers
signal pipe_a1: signed(9 downto 0) := (others => '0');
signal pipe_a2: signed(9 downto 0) := (others => '0');
signal pipe_b0: signed(9 downto 0) := (others => '0');
signal pipe_b1: signed(9 downto 0) := (others => '0');
begin
P0: process(clk)
begin
if falling_edge(clk) then
adc_buffer <= signed(adc_data); -- adc give data in U2 code
pipe_a0 <= adc_buffer;
pipe_a1 <= pipe_a0;
pipe_a2 <= pipe_a1;
pipe_b0 <= add_all(19 downto 10); --truncated sum
pipe_b1 <= pipe_b0;
dac_data <= STD_LOGIC_VECTOR(dac_buffer(9 downto 0)); -- write to dac
(ignore MSB - offset bin conversion)
mult_a0 <= pipe_a0*to_signed(coeff_a0,10); -- signed * signed return
20 bit signed
mult_a1 <= pipe_a1*to_signed(coeff_a1,10);
mult_a2 <= pipe_a2*to_signed(coeff_a2,10);
mult_b0 <= pipe_b0*to_signed(coeff_b0,10);
mult_b1 <= pipe_b1*to_signed(coeff_b1,10);
--sum of signed results
add_all <= mult_a0 + mult_a1 + mult_a2 + mult_b0 + mult_b1; --signed +
signed + ...
dac_buffer <= add_all(19 downto 10) + offset; -- to offset binary
convertion (add 511) signed + signed
end if;
end process; -- dac buffer is 11 bit long
clk_adc <= clk;
clk_dac <= clk;
end Behavioral;
Chris C. wrote: > In code below coefficient are for 4MHz cut-off frequency but I dont know > if they are correct. Did you have a matlab? There is a toolbox available for calculating filter coeffiecients in fixed data formats. Also do this toolbox a stability analyis of your IIR filter. Best Regards,
Chris C. wrote: > It is possible that I have only wrong coefficient. On hardware filter > works but not correct. Your coefficents are correct but your code doesn't work. If I use your coefficients with the implementation biquad, form 1 as described on this website [1], I got the expected results. Can you describe graphically the structure of your IIR filter? Duke [1] http://www.iowahills.com/4IIRFilterPage.html
The names in code doesn't match with the schematic, but anyway: 1. move the multiplications out of your register stage (if *_edge ... end if) 2. mind the polarity signs on the big 'adder' 3. don't move the adder out of the register stage Another hint (again): Use falling_edge only if you have a good reason. Duke
Duke Scarring wrote: > 1. move the multiplications out of your register stage (if *_edge ... > end if) > 2. .... the big 'adder' This will led to a lot of logic levels in this case - 4 adders - plus 1 multiplier I would expect timing problems with the code posted by Chris. Generally it is difficult to run an IIR-Filter with sampling frequency = clock frequency. Since the feed back loop has only one clock budget but you need at least two operations, add and multiply. Within a second order stage (as shown in the iir.jpg picture) there has to be performed three sequential operations, 2 additions and 1 multiplication. Either you get many logic levels (in terms of DSP blocks) or to many pipeline stages. What is the reason for your IIR-Filter? Tom
Tom, I make this filter as a project on high school. It is very possible that you're right. I spend many hours with trying to resolve problem with this filter. I obtain results which magnitude characteristic was above 10dB upper than expected which I compue in FDA Tool in MATLAB. Interestng is that I implemented FIR filter with the same way and it works very good. I saw the VHDL code where IIR filter was divided to machine state (as you described the number of operations in one clock cycle). Maybe it is a solution of my problem but I need 100MSPS. I think that the problem is in the second part of my filter, it works but 10dB above.
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.






