Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

VHDL and Transposed Fir

Altera_Forum
Honored Contributor II
2,911 Views

Hello guys , 

 

I'm implementing a transposed fir filter in vhdl in which only the sum are pipelined. 

 

The code I wrote up (using this (http://www.google.it/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0cdaqfjac&url=http%3a%2f%2fwww4.hcmut.edu.vn%2f~hoangtrang%2flecture%2520note%2fdsp%2520on%2520fpga%2fdsp_fpga_ch%252010%2520-%2520fir%2520filter%2520design.pdf&ei=a76eu6uummnp4qt88yggba&usg=afqjcnhr62rzy5-5rvzgccd0nxqz9xaoow&bvm=bv.68911936,d.bge)) until now is the one below: 

LIBRARY lpm; USE lpm.lpm_components.ALL; LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.all; ENTITY transposed_fir_test IS GENERIC (W1 : INTEGER := 16; -- Input bit width W2 : INTEGER := 32; -- Multiplier bit width W3 : INTEGER := 35; -- Adder width W4 : INTEGER := 16; -- Output bit width L : INTEGER := 15; -- Filter length Mpipe : INTEGER := 0-- Pipeline steps of multiplier ); PORT ( clk : IN STD_LOGIC; Load_x : IN STD_LOGIC; x_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0); c_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0); y_out : OUT STD_LOGIC_VECTOR(W4-1 DOWNTO 0)); END transposed_fir_test; ARCHITECTURE fpga OF transposed_fir_test IS SUBTYPE N1BIT IS STD_LOGIC_VECTOR(W1-1 DOWNTO 0); SUBTYPE N2BIT IS STD_LOGIC_VECTOR(W2-1 DOWNTO 0); SUBTYPE N3BIT IS STD_LOGIC_VECTOR(W3-1 DOWNTO 0); TYPE ARRAY_N1BIT IS ARRAY (0 TO L-1) OF N1BIT; TYPE ARRAY_N2BIT IS ARRAY (0 TO L-1) OF N2BIT; TYPE ARRAY_N3BIT IS ARRAY (0 TO L-1) OF N3BIT; SIGNAL x : N1BIT; SIGNAL y : N3BIT; SIGNAL c : ARRAY_N1BIT; -- Coefficient array SIGNAL p : ARRAY_N2BIT; -- Product array SIGNAL a : ARRAY_N3BIT; -- Adder array BEGIN Load: PROCESS ------> Load data or coefficient BEGIN WAIT UNTIL clk = '1'; IF (Load_x = '0') THEN c(L-1) <= c_in; -- Store coefficient in register FOR I IN L-2 DOWNTO 0 LOOP -- Coefficients shift one c(I) <= c(I+1); END LOOP; ELSE x <= x_in; -- Get one data sample at a time END IF; END PROCESS Load; SOP: PROCESS (clk) ------> Compute sum-of-products BEGIN IF rising_edge(clk) THEN FOR I IN 0 TO L-2 LOOP -- Compute the transposed a(I) <= std_logic_vector(signed(p(I)) + signed(a(I+1))); -- filter adds END LOOP; a(L-1) <=std_logic_vector(resize(signed(p(L-1)),W3)); -- First TAP has END IF; -- only a register y <= a(0); END PROCESS SOP; -- Instantiate L pipelined multiplier MulGen: FOR I IN 0 TO L-1 GENERATE Muls: lpm_mult -- Multiply p(i) = c(i) * x; GENERIC MAP ( LPM_WIDTHA => W1, LPM_WIDTHB => W1, LPM_PIPELINE => Mpipe, LPM_REPRESENTATION => "SIGNED", LPM_WIDTHP => W2, LPM_WIDTHS => W2) PORT MAP ( dataa => x, datab => c(I), result => p(I)); END GENERATE; y_out <=y(W3-1 DOWNTO W3-W4); END fpga;  

 

By the way using a delta-stimulus of 32767 and this set of coeff: [32437,31463,29888,27779,25230,22351,19269,16118,13036,10157,7608,5500,3924,2950,2621] I get the following output: 

[X,X,X,X,X,1576,1396,1204,1007,814,634,475,343,245,184,163,0] 

 

So it seems I miss the first ouptut samples of the filter and a scaled output.. 

 

Any suggestions ?? 

 

ty !
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
1,847 Views

to get initial values correctly you need to set accumulators to zero start. 

 

you are scaling by discarding 19 bits. Is that what you wanted?
0 Kudos
Altera_Forum
Honored Contributor II
1,847 Views

 

--- Quote Start ---  

to get initial values correctly you need to set accumulators to zero start. 

 

you are scaling by discarding 19 bits. Is that what you wanted? 

--- Quote End ---  

 

 

Yep, those X's are related to the initial values of the C matrix. 

 

As long as I need only 16 bit I have to take only the MSbs at the output. The magnitude is ok. I was a little confused because the very first values at the output of the filter where not shown due to the lack of initialization of the C matrix. 

 

One curiosity, now the filter coefficient are uploaded at the same clock of the input signal. By the way I want to control the coefficient uploading with a different clock (I want to set the coefficient via NIOS PIOs).  

I've thought to use a first pio to load the coefficient into c_in and a secondo pio to get the c_in loaded (so it acts like the clock of the previus code). I ended up with this code: 

 

-- This is a generic FIR filter generator -- It uses W1 bit data/coefficients bits LIBRARY lpm; -- Using predefined packages USE lpm.lpm_components.ALL; LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.all; ENTITY transposed_fir_test IS ------> Interface GENERIC (W1 : INTEGER := 16; -- Input bit width W2 : INTEGER := 32; -- Multiplier bit width 2*W1 W3 : INTEGER := 35; -- Adder width = W2+log2(L)-1 W4 : INTEGER := 16; -- Output bit width L : INTEGER := 15; -- Filter length Mpipe : INTEGER := 0-- Pipeline steps of multiplier ); PORT ( clk : IN STD_LOGIC; rst : IN STD_LOGIC; Load_x : IN STD_LOGIC; x_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0); c_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0); wr_clk : IN STD_LOGIC; y_out : OUT STD_LOGIC_VECTOR(W4-1 DOWNTO 0)); END transposed_fir_test; ARCHITECTURE fpga OF transposed_fir_test IS SUBTYPE N1BIT IS STD_LOGIC_VECTOR(W1-1 DOWNTO 0); SUBTYPE N2BIT IS STD_LOGIC_VECTOR(W2-1 DOWNTO 0); SUBTYPE N3BIT IS STD_LOGIC_VECTOR(W3-1 DOWNTO 0); TYPE ARRAY_N1BIT IS ARRAY (0 TO L-1) OF N1BIT; TYPE ARRAY_N2BIT IS ARRAY (0 TO L-1) OF N2BIT; TYPE ARRAY_N3BIT IS ARRAY (0 TO L-1) OF N3BIT; SIGNAL x : N1BIT; SIGNAL y : N3BIT; SIGNAL c : ARRAY_N1BIT; -- Coefficient array SIGNAL p : ARRAY_N2BIT; -- Product array SIGNAL a : ARRAY_N3BIT; -- Adder array BEGIN x <= x_in; Load: PROCESS(wr_clk,Load_x) ------> Load data or coefficient BEGIN if(rising_edge(wr_clk)) then IF (Load_x = '0') THEN c(L-1) <= c_in; -- Store coefficient in register FOR I IN L-2 DOWNTO 0 LOOP -- Coefficients shift one c(I) <= c(I+1); END LOOP; ELSE ; END IF; end if; END PROCESS Load; SOP: PROCESS (clk) ------> Compute sum-of-products BEGIN IF rising_edge(clk) THEN FOR I IN 0 TO L-2 LOOP -- Compute the transposed a(I) <= std_logic_vector(signed(p(I)) + signed(a(I+1))); -- filter adds END LOOP; a(L-1) <=std_logic_vector(resize(signed(p(L-1)),W3)); -- First TAP has END IF; -- only a register y <= a(0); END PROCESS SOP; -- Instantiate L pipelined multiplier MulGen: FOR I IN 0 TO L-1 GENERATE Muls: lpm_mult -- Multiply p(i) = c(i) * x; GENERIC MAP ( LPM_WIDTHA => W1, LPM_WIDTHB => W1, LPM_PIPELINE => Mpipe, LPM_REPRESENTATION => "SIGNED", LPM_WIDTHP => W2, LPM_WIDTHS => W2) PORT MAP ( dataa => x, datab => c(I), result => p(I)); END GENERATE; y_out <=y(W3-1 DOWNTO W3-W4); END fpga; 

 

Any suggestions ? 

 

What can I do if I want to intialize to 0's the C matrix while resetting ? 

 

ty !
0 Kudos
Altera_Forum
Honored Contributor II
1,847 Views

to initilaise use := (others => (others => '0')); 

 

your dividing by 2^19 may not be right for unity gain. Your output will be scaled somewhere above or below unity
0 Kudos
Altera_Forum
Honored Contributor II
1,847 Views

Thank you kaz ! 

 

I have never understand if that type initialization is true also during the power up .. could you confirm it ?
0 Kudos
Altera_Forum
Honored Contributor II
1,847 Views

 

--- Quote Start ---  

Thank you kaz ! 

 

I have never understand if that type initialization is true also during the power up .. could you confirm it ? 

--- Quote End ---  

 

 

yes it is supported as initial values on registers at powerup
0 Kudos
Reply