+ Post New Thread
Results 1 to 17 of 17

14th March 2017, 17:42 #1
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Manually implementation of a FIR filter in a FPGA.
Hello folks!
I am trying to implement manually a 4 order FIR filter in a FPGA. Therefore I have a VHDL module which is able to generate a sinusoidal signal of whatever frequency with an amplitude which goes from 0 to 65535 (16 bits) designed previously with a script in matlab:
Sinusoidal Matlab script:
Code:N=100; fs=200; f=1; ts=1/fs; t = ts*(0:N1); x=0; x=(((2^16)/2)1)*sin(2*pi*f*tpi/2); x=(((2^16)/2)1)+x; x=round(x); filename = 'SinusSignal.xlsx' xlswrite(filename,x); plot(t,x)
Code:library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.all; use ieee.std_logic_unsigned.all;  Uncomment the following library declaration if using  arithmetic functions with Signed or Unsigned values use IEEE.NUMERIC_STD.ALL;  Uncomment the following library declaration if instantiating  any Xilinx leaf cells in this code. library UNISIM; use UNISIM.VComponents.all; entity WaveGenerator is Generic ( DEBUG : BOOLEAN := false; True for simulations ROM_DEPTH : INTEGER := 100);  Number of items of the ROM Port ( CLK : in STD_LOGIC;  Input Clock RST : in STD_LOGIC;  High level reset WAVE_GEN : out STD_LOGIC_VECTOR (15 downto 0));  Waveform data output end WaveGenerator; architecture Behavioral of WaveGenerator is  Signals to generate the waveform signal dataout : unsigned (15 downto 0); signal table_index : integer range 0 to ROM_DEPTH; signal table_index_down : std_logic;  table_index_down = '1' => walk down the table; ='0' walk up the table ROM for storing the table values generated by MATLAB for the  1/4 of a sinus signal type table_type is array (0 to ROM_DEPTH1) of integer range 0 to 65535; signal table : table_type :=( 0 ,16 ,65 ,145 ,258 ,403 ,580 ,789 ,1029 ,1301 , 1604 ,1937 ,2301 ,2695 ,3119 ,3571 ,4053 ,4563 ,5101 ,5666 , 6258 ,6876 ,7520 ,8188 ,8881 ,9597 ,10336,11098,11881,12684, 13507,14349,15210,16087,16981,17891,18815,19754,20705,21668, 22641,23625,24618,25619,26627,27641,28660,29683,30710,31738, 32767,33796,34824,35851,36874,37893,38907,39915,40916,41909, 42893,43866,44829,45780,46719,47643,48553,49447,50324,51185, 52027,52850,53653,54436,55198,55937,56653,57346,58014,58658, 59276,59868,60433,60971,61481,61963,62415,62839,63233,63597, 63930,64233,64505,64745,64954,65131,65276,65389,65469,65518 ); begin Process to generate the signal process(CLK,RST) begin if RST = '1' then table_index <= 0; table_index_down <= '0'; dataout <= to_unsigned(table(0),dataout'length); elsif rising_edge(CLK) then  walking the table if table_index_down = '0' then  walk up the table if table_index < ROM_DEPTH1 then table_index <= table_index + 1; else table_index_down <= '1'; table_index <= table_index; end if; else  walk down the table if table_index > 0 then table_index <= table_index  1; else table_index_down <= '0'; table_index <= table_index; end if; end if; dataout <= to_unsigned(table(table_index),dataout'length); end if; end process;  Output of the SignalGenerator. WAVE_GEN <= std_logic_vector (dataout); end Behavioral;
I converted the fixed point coefficients into Q7 format
0.15939331054688 @ Q7 = 0x14
0.38282775878906 @ Q7 = 0x31
0.38282775878906 @ Q7 = 0x31
0.15939331054688 @ Q7 = 0x14
This is the code of the 4 order FIR VHDL filter:
Code:library IEEE; use IEEE.STD_LOGIC_1164.ALL;  Uncomment the following library declaration if using  arithmetic functions with UNSIGNED or UnUNSIGNED values use IEEE.NUMERIC_STD.ALL; use ieee.std_logic_unsigned.all; unsigned arithmetics library use ieee.std_logic_signed.all; unsigned arithmetics library  Uncomment the following library declaration if instantiating  any Xilinx leaf cells in this code. library UNISIM; use UNISIM.VComponents.all; entity FIR_FILTER_N2 is Generic ( DEBUG : BOOLEAN := false);  True for simulations Port ( CLK : in STD_LOGIC; RST : in STD_LOGIC; FILTER_IN : in STD_LOGIC_VECTOR (15 downto 0); FILTER_OUT : out STD_LOGIC_VECTOR (15 downto 0)); end FIR_FILTER_N2; architecture Behavioral of FIR_FILTER_N2 is  FIR coefficients. type FIR_COEFF is array (0 to 3) of signed (7 downto 0); signal B : FIR_COEFF;  Multiplication signals type X_ARRAY is array (0 to 3) of signed (15 downto 0); signal X : X_ARRAY; type W_ARRAY is array (0 to 3) of signed (31 downto 0); signal W : W_ARRAY; signal Y : signed (15 downto 0);  FIR signals. type MUL_ARRAY is array (0 to 3) of signed (31 downto 0); signal MUL : MUL_ARRAY; signal TAP_CNT : unsigned (7 downto 0); signal Z1 : signed (31 downto 0); signal Z2 : signed (31 downto 0); signal Z3 : signed (31 downto 0); signal ADD1 : signed (31 downto 0); signal ADD2 : signed (31 downto 0); signal ADD3 : signed (31 downto 0); begin Low pass filter 6kHz > 12kHz 12 dB  Coefficients assigments  B(0) <= "11110111";  B(1) <= "00001001";  B(2) <= "00100110";  B(3) <= "00110011"; B(0) <= x"14"; B(1) <= x"31"; B(2) <= x"31"; B(3) <= x"14"; Multiplication gen_MULT16x16 : for I in 0 to 3 generate X(I) <= resize(B(I), X(I)'length); Y <= signed(FILTER_IN); i_MUL16x16: entity work.MUL16x16 port map ( CLK => CLK, X => X(I), Y => Y, W => W(I) ); MUL(I)<=W(I); end generate gen_MULT16x16; process (RST,CLK) begin if RST = '1' then TAP_CNT <= (others => '0'); elsif rising_edge (CLK) then if TAP_CNT = 0 then Z1 <= MUL(3); TAP_CNT <= TAP_CNT + 1; elsif TAP_CNT = 1 then ADD1 <= Z1 + MUL(2); TAP_CNT <= TAP_CNT + 1; elsif TAP_CNT = 2 then Z2 <= ADD1; TAP_CNT <= TAP_CNT + 1; elsif TAP_CNT = 3 then ADD2 <= Z2 + MUL(1); TAP_CNT <= TAP_CNT + 1; elsif TAP_CNT = 4 then Z3 <= ADD2; TAP_CNT <= TAP_CNT + 1; elsif TAP_CNT = 5 then ADD3 <= Z3 + MUL(0); TAP_CNT <= (others => '0'); end if; end if; end process; FILTER_OUT <= std_logic_vector(resize(ADD3,FILTER_OUT'length)); end Behavioral;
Anyone can tell me why is happening this issue??
Thanks in advance.

14th March 2017, 19:10 #2
 Join Date
 Apr 2014
 Posts
 9,739
 Helped
 2347 / 2347
 Points
 47,675
 Level
 53
Re: Manually implementation of a FIR filter in a FPGA.
Hi,
I didn´t go through your code in detail.
But it looks like some overflow.
This may be caused
* either because of the FIR filter internal sum is too large (you may need some bits headroom)
* or because of the FIR filter characteristic. This may cause some frequencies to be emphasised, which need some additional headroom
* or because of signed/unsigend problems. You say 0...65535 this is unsigned. But the FIR filter may expect signed: 32768 ...0 ...+32767.
I´d say the signed/unsigned problem is most likely.
Check on this.
After that:
Try with reduced input amplitude ( at least 1/4) and see what happens.
Klaus

15th March 2017, 00:21 #3
 Join Date
 Sep 2013
 Location
 USA
 Posts
 6,174
 Helped
 1518 / 1518
 Points
 27,178
 Level
 40
Re: Manually implementation of a FIR filter in a FPGA.
Code:FILTER_OUT <= std_logic_vector(resize(ADD3,FILTER_OUT'length));
I would check the entire 32bit ADD3 output first and see how many of the important bits you dropped.

15th March 2017, 00:21

15th March 2017, 05:49 #4
 Join Date
 Feb 2015
 Posts
 728
 Helped
 217 / 217
 Points
 4,416
 Level
 15
Re: Manually implementation of a FIR filter in a FPGA.
wave generator seems to only use the upper two quadrants, at least from looking at the process.
I'm not sure on mul16x16, what inputs/outputs are signed/unsigned.
The fir filter is also odd because the input seems to be accepted every cycle, but there is a sequential fsm for the accumulation.

15th March 2017, 08:41 #5
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Re: Manually implementation of a FIR filter in a FPGA.
Hello guys!
First of all thank you for the quick answer.
I have been doing some tests more and I would like to do some comments respecting to that...
1) Without touching the original code which I posted before, I run a simulation displaying the ADD3 waveform (See pic1 attached). On pic1 it is possible to see how the ADD3 waveform is a square signal!!!!!!! And definitely this is not normal...The noisy Filter Out signal is also a square signal and noise it is bacause a problem with the "resize" function...Notice that the input freq of the filter = 500KHz....
The code of the Mul16x16 is this:
Code:library IEEE; use IEEE.STD_LOGIC_1164.ALL;  Uncomment the following library declaration if using  arithmetic functions with UNSIGNED or UnUNSIGNED values use IEEE.NUMERIC_STD.ALL; use ieee.std_logic_unsigned.all; unsigned arithmetics library use ieee.std_logic_signed.all; unsigned arithmetics library  Uncomment the following library declaration if instantiating  any Xilinx leaf cells in this code. library UNISIM; use UNISIM.VComponents.all; entity MUL16x16 is Port ( CLK :in STD_LOGIC; X :in SIGNED (15 downto 0); Y :in SIGNED (15 downto 0); W :out SIGNED (31 downto 0) ); end MUL16x16; architecture Behavioral of MUL16x16 is signal W_AUX : SIGNED (31 downto 0); begin W_AUX <= X*Y; process(CLK) begin if rising_edge (CLK) then W <= W_AUX; end if; end process; end Behavioral;
The code of the wavegenerator is this:
Code:library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.all; use ieee.std_logic_unsigned.all;  Uncomment the following library declaration if using  arithmetic functions with Signed or Unsigned values use IEEE.NUMERIC_STD.ALL;  Uncomment the following library declaration if instantiating  any Xilinx leaf cells in this code. library UNISIM; use UNISIM.VComponents.all; entity WaveGenerator is Generic ( DEBUG : BOOLEAN := false; True for simulations ROM_DEPTH : INTEGER := 100);  Number of items of the ROM Port ( CLK : in STD_LOGIC;  Input Clock RST : in STD_LOGIC;  High level reset WAVE_GEN : out STD_LOGIC_VECTOR (15 downto 0));  Waveform data output end WaveGenerator; architecture Behavioral of WaveGenerator is  Signals to generate the waveform signal dataout : signed (15 downto 0); signal table_index : integer range 0 to ROM_DEPTH; signal table_index_down : std_logic;  table_index_down = '1' => walk down the table; ='0' walk up the table ROM for storing the table values generated by MATLAB for the  1/4 of a sinus signal from 0 to 65536 type table_type is array (0 to ROM_DEPTH1) of integer range 32768 to 32767; signal table : table_type :=( 32767,32751,32702,32622,32509,32364,32187,31978,31738,31466, 31163,30830,30466,30072,29648,29196,28714,28204,27666,27101, 26509,25891,25247,24579,23886,23170,22431,21669,20886,20083, 19260,18418,17557,16680,15786,14876,13952,13013,12062,11099, 10126,9142 ,8149 ,7148 ,6140 ,5126 ,4107 ,3084 ,2057 ,1029 , 0 ,1029 ,2057 ,3084 ,4107 ,5126 ,6140 ,7148 ,8149 ,9142 , 10126 ,11099 ,12062 ,13013 ,13952 ,14876 ,15786 ,16680 ,17557 ,18418 , 19260 ,20083 ,20886 ,21669 ,22431 ,23170 ,23886 ,24579 ,25247 ,25891 , 26509 ,27101 ,27666 ,28204 ,28714 ,29196 ,29648 ,30072 ,30466 ,30830 , 31163 ,31466 ,31738 ,31978 ,32187 ,32364 ,32509 ,32622 ,32702 ,32751 ); begin Process to generate the signal process(CLK,RST) begin if RST = '1' then table_index <= 0; table_index_down <= '0'; dataout <= to_signed(table(0),dataout'length)/2; elsif rising_edge(CLK) then  walking the table if table_index_down = '0' then  walk up the table if table_index < ROM_DEPTH1 then table_index <= table_index + 1; else table_index_down <= '1'; table_index <= table_index; end if; else  walk down the table if table_index > 0 then table_index <= table_index  1; else table_index_down <= '0'; table_index <= table_index; end if; end if; dataout <= to_signed(table(table_index),dataout'length)/2; end if; end process;  Output of the SignalGenerator. WAVE_GEN <= std_logic_vector (dataout); end Behavioral;
On this point I have two questions:
1) Any idea why the FIR filter does not attenuate the amplitude of the input signal? Could be an error in the calculation of the FIR coefficients?
2) How to design a FIR filter with only posititive input values?
Greetings,
EP

15th March 2017, 09:32 #6
 Join Date
 Apr 2014
 Posts
 9,739
 Helped
 2347 / 2347
 Points
 47,675
 Level
 53
Re: Manually implementation of a FIR filter in a FPGA.
Hi,
1) Any idea why the FIR filter does not attenuate the amplitude of the input signal? Could be an error in the calculation of the FIR coefficients?
My assumption is:
That you just modified the data_rate for the sine generation and used the same sine table.
If you then used the same (modified) data rate for the FIR filer, then it should be obvious that there is no change in amplitide. The FIR filter then calculates with the same values but faster.
2) How to design a FIR filter with only posititive input values?
Why make handstands?
Why make it "non standard"?
> if you need more resolution than adjust bit width.
The next is:
For a low pass filter this may theoretically work, but for a high pass filter or a band pass filter this simply can´t work, because the output will always go negative.
Klaus

15th March 2017, 10:22 #7
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Re: Manually implementation of a FIR filter in a FPGA.
Hi KlausST
You are right, I am using the same sine table and what I change is the clock frequency to increase or decrease the speed reading of the table...So I increase/decrease the data rate, right. But then if I want to simulate this FIR filter with this wavegenerator.vhd module, i need to create a new script in Matlab in order to estimate new values for the sine signal...
This is the matlab script to generate 100 samples of a sine signal:
Code:N=100; fs=200; f=1; ts=1/fs; t = ts*(0:N1); x=0; x=(((2^16)/2)1)*sin(2*pi*f*tpi/2); x=(((2^16)/2)1)+x; x=round(x); filename = 'SinusSignal.xlsx' xlswrite(filename,x); plot(t,x)
As you can see, the Fs=200 (Hz). Thefore according to the coefficients, the Fc=3MHZ, this sine signal always go trhough the FIR without any attenuation...The question is how to generate 100 samples of a sine signal with Matlab in order to simulate an attenuated sine signal after go through the FIR filter?
Thanks in advance.

15th March 2017, 10:22

15th March 2017, 10:49 #8
 Join Date
 Apr 2014
 Posts
 9,739
 Helped
 2347 / 2347
 Points
 47,675
 Level
 53
Re: Manually implementation of a FIR filter in a FPGA.
Hi,
if the current 100 point sine solution equals a 500kHz signal,
then you should produce a sine table with 15 entries per sine > 3.333MHz
or 6 full waves within 91 entries. > 3.297 MHz
Klaus

15th March 2017, 10:49

15th March 2017, 18:05 #9
 Join Date
 May 2001
 Posts
 136
 Helped
 8 / 8
 Points
 3,558
 Level
 14
Re: Manually implementation of a FIR filter in a FPGA.
Hi,
you can try open cores DDS sinthesyzers to generate the input frequency, in this way you can easily change frequency or sweep it.
Stefano

21st March 2017, 17:36 #10
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Re: Manually implementation of a FIR filter in a FPGA.
@mvmmmboy: That could be a good option. I will try it if I am not able to run my own wavegenerator...
@KlausST: I am not able to attenuate the incomming signal to the filter. Maybe I am doing something wrong. I will describe you the scenario:
1) I generate a sinu signal of 1MHz with the next Matlab code.
Code:N=50; fs=100e6; f=1e6; ts=1/fs; t = ts*(0:N1); x=0; x=(((2^16)/2)1)*sin(2*pi*f*tpi/2); x=round(x); filename = 'SinusSignal_1M.xlsx' xlswrite(filename,x); plot(t,x)
Code:N=4; fs=100e6; f=15.5e6; ts=1/fs; t = ts*(0:N1); x=0; x=(((2^16)/2)1)*sin(2*pi*f*tpi/2); x=round(x); filename = 'SinusSignal_15M5.xlsx' xlswrite(filename,x); plot(t,x)
4) I convert the coefficients into Q7 format:
0.34989364024691172 @ Q7=0x2D
0.12031844969512598 @ Q7=0x0F
0.12031844969512598 @ Q7=0x0F
0.34989364024691172 @ Q7=0x2D
5) I use the FIR filter code showed above in my first post to filter out the sinus signal
6) The results are
6.1) 1MHz sinus signal ==> No attenuation and there is also an amplification!!! (See pic3 attached)
6.2) 15.5MHz sinus signal ==> No attenuation and there is also an amplification!!! (See pic4 attached)
Could it be that there is an error in the filter design with Matlab?? Because I think that the 4 FIR tap VHDL implementation is ok right?
Thanks in advance!!!

21st March 2017, 18:39 #11
 Join Date
 Jan 2008
 Location
 Bochum, Germany
 Posts
 40,388
 Helped
 12337 / 12337
 Points
 233,774
 Level
 100
Re: Manually implementation of a FIR filter in a FPGA.
According to the wave window, the sine frequencies are not 1 MHz and 15 MHz.
Apparently you still don't manage to scale ADD3 into FILTER_OUT, respectively to display the data with correct number format.

21st March 2017, 19:10 #12
 Join Date
 Sep 2013
 Location
 USA
 Posts
 6,174
 Helped
 1518 / 1518
 Points
 27,178
 Level
 40
Re: Manually implementation of a FIR filter in a FPGA.
This means you need to be taking the UPPER bits not the lower bits of ADD3 and assign them to FILTER_OUT, don't use resize, grab the correct bit slice directly, resize won't work correctly it grabs the lower bits.
probably something more like:
Code:FILTER_OUT <= ADD3(ADD3'LEFT downto (ADD3'LEFTFILTER_OUT'LENGTH+1));

21st March 2017, 21:54 #13
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Re: Manually implementation of a FIR filter in a FPGA.
Hi FvM,
I am delivering samples of the sinus signal at 50MHz (input clock of the WaveGenerator.vhd). But i created it with MATLAB with a sample frequency of 100MHz. It means the input clock of the WaveGenerator.vhd should be set to 100MHz to create sinus signal at 1MHz and 15.5MHz right?
Regards,
   Updated   
Hi adssee
I will try it tomorrow. Maybe this is the reason because the amplitude of the output signal looks like a gain....
Thanks!!

22nd March 2017, 04:16 #14
 Join Date
 Feb 2015
 Posts
 728
 Helped
 217 / 217
 Points
 4,416
 Level
 15
Re: Manually implementation of a FIR filter in a FPGA.
resize, for signed in numeric_std, will take the msb and then the N1 lsbs in this case. This is why the waveform looks like a bunch of random positive values then a bunch of random negative values.
In terms of the design, nearly everything is wrong.
the wave generator is listed for "quarter sine" but is actually a half sine.
you do the parallel multiplications, then have a serial accumulator that runs at half rate. you probably want the adder tree.
You select the lsbs for some reason.
You freely have 16x16 multipliers (probably larger) in the FPGA, but you quantize the coefficients to 8 bit.
You should be using a easier test signal  an impulse. you should see the 4 coefficients as the output by definition. You should also try a worst case full scale signal of (fullscale, fullscale, fullscale, fullscale) Basically, values of fullscale for positive coefs and +fullscale for negative. The goal is to ensure the accumulator can't overflow.

22nd March 2017, 04:16

22nd March 2017, 07:21 #15
 Join Date
 Jan 2008
 Location
 Bochum, Germany
 Posts
 40,388
 Helped
 12337 / 12337
 Points
 233,774
 Level
 100
Re: Manually implementation of a FIR filter in a FPGA.
It means the input clock of the WaveGenerator.vhd should be set to 100MHz to create sinus signal at 1MHz and 15.5MHz right?

22nd March 2017, 09:06 #16
 Join Date
 Jan 2014
 Posts
 234
 Helped
 1 / 1
 Points
 1,734
 Level
 9
Re: Manually implementation of a FIR filter in a FPGA.
Ok guys I think that I am already get it....
You were right FvM, I set the frequency of the WaveGenerator.vhd to run the sinus signals at 1MHz and 15.5MHz and see the pics attached to observe what happens.
Pic1 => Sinus signal running at 1MHz ==> No attenuation, everything ok.
Pic2 => Sinus signal running at 15.5MHz ==> The signal is totally degraded and there is a phase shift of 90º!!! Can anybody explain why this is happening??
Thanks at all!

22nd March 2017, 09:36 #17
 Join Date
 Jan 2008
 Location
 Bochum, Germany
 Posts
 40,388
 Helped
 12337 / 12337
 Points
 233,774
 Level
 100
Re: Manually implementation of a FIR filter in a FPGA.
Still have difficulties to match the generator and filter sampling rates seen in the waveform with the design specifications.
Apparently the filter is running at a lower rate as the generator, ratio is 5:16. Having only 5 samples per sine period doesn't look very nice, as expectable.
+ Post New Thread
Please login