I didn't dive super far into your filter design, but just looking at the source code brings a couple of things up. For example, these lines:
aux1 = ((long)b0*xn) << 1;
aux2 = ((long)a1*y) << 1;
y = ((aux1 + aux2) >> 16);
The first issue I see is the ((long)b0*xn). I have ran across compilers that would compile this incorrectly as ((long)(b0*xn)), which is entirely wrong. Just to be on the safe side, I would write this as (((long)b0)*((long)xn)). To be sure, this is paranoid programming, but...
Next, when you do the "<<1", this is NOT the same as "*2". For most things, it's close, but not for DSP. It has to do with how the MCU/DSP handles overflow conditions and sign extensions, etc. But even if it did work as a *2, you are removing one bit of resolution that you don't need to remove. If you really have to do a *2, then do a *2 and let the compiler figure out if it could substitute a <<1 instead.
The >>16 is also problematic. Off the top of my head, I don't know if it's going to do a logical or arithmetic shift. You want an arithmetic shift. Arithmetic shifts will handle the sign bit correctly where a logical shift will insert zeros for the new bits. Besides, you can save bits of resolution by getting rid of the <<1 and changing the >>16 to >>15. Well, and changing all of these to normal multiplies and divides.
So here's the code I would use:
aux1 = ((long)b0) * ((long)xn);
aux2 = ((long)a1) * ((long)y);
y = (short)((aux1+aux2) / 32768);
Now, I don't claim that this will solve your problem. It may or may not, but it does improve your code.
It sounds like you need to figure out the DSP aspects first, then make an implementation in FPGA.
- Sort out the DSP in C, Matlab, Excel, or anywhere else
- Try and think how you'll transfer what you've learned from that into FPGA-land
- Discover you've made some assumption about the implementation that doesn't work well (like the use of floating point for example)
- Go back and update your offline DSP stuff to take account of this.
- Iterate n times :)
Regarding data types, you can use integers just fine.
here's some sample code to get you going. Note that it's missing a lot of real-world issues (for example reset, overflow management) - but hopefully it's instructive:
library ieee;
use ieee.std_logic_1164.all;
entity simple_fir is
generic (taps : integer_vector);
port (
clk : in std_logic;
sample : in integer;
filtered : out integer := 0);
end entity simple_fir;
----------------------------------------------------------------------------------------------------------------------------------
architecture a1 of simple_fir is
begin -- architecture a1
process (clk) is
variable delay_line : integer_vector(0 to taps'length-1) := (others => 0);
variable sum : integer;
begin -- process
if rising_edge(clk) then -- rising clock edge
delay_line := sample & delay_line(0 to taps'length-2);
sum := 0;
for i in 0 to taps'length-1 loop
sum := sum + delay_line(i)*taps(taps'high-i);
end loop;
filtered <= sum;
end if;
end process;
end architecture a1;
----------------------------------------------------------------------------------------------------------------------------------
-- testbench
----------------------------------------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity tb_simple_fir is
end entity tb_simple_fir;
architecture test of tb_simple_fir is
-- component generics
constant lp_taps : integer_vector := ( 1, 1, 1, 1, 1);
constant hp_taps : integer_vector := (-1, 0, 1);
constant samples : integer_vector := (0,0,0,0,1,1,1,1,1);
signal sample : integer;
signal filtered : integer;
signal Clk : std_logic := '1';
signal finished : std_logic;
begin -- architecture test
DUT: entity work.simple_fir
generic map (taps => lp_taps) -- try other taps in here
port map (
clk => clk,
sample => sample,
filtered => filtered);
-- waveform generation
WaveGen_Proc: process
begin
finished <= '0';
for i in samples'range loop
sample <= samples(i);
wait until rising_edge(clk);
end loop;
-- allow pipeline to empty - input will stay constant
for i in 0 to 5 loop
wait until rising_edge(clk);
end loop;
finished <= '1';
report (time'image(now) & " Finished");
wait;
end process WaveGen_Proc;
-- clock generation
Clk <= not Clk after 10 ns when finished /= '1' else '0';
end architecture test;
Best Answer
It's unlikely to be true. IIR filters use feed-back paths and recirculate a fraction of the output (ever-diminishing hopefully). Hence they have the name Infinite Impulse Response meaning that an impulse on the input would cause an output that continues to decay to infinite.
FIR filter do not have feedback paths and hence the name Finite Impulse Response because the output following an inputted impulse changes and then restores to "normality" after a finite length of time.
The resulting expression may look like an IIR expression but if it contains y[n-i] then it can't be FIR