URL
https://opencores.org/ocsvn/fir_filter/fir_filter/trunk
Subversion Repositories fir_filter
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 9 to Rev 10
- ↔ Reverse comparison
Rev 9 → Rev 10
/fir_filter/tags/filtro_FIR.vhd
File deleted
\ No newline at end of file
/fir_filter/tags/testbench/simulation.do
0,0 → 1,25
quit -sim |
|
vcom -work work -2002 -explicit -check_synthesis -novitalcheck -novital -source -O0 -debug -stats=none F:/Filtro_FIR/src/FIR_low_area.vhd |
vcom -work work -2002 -explicit -check_synthesis -novitalcheck -novital -source -O0 -stats=none F:/Filtro_FIR/testbench/FIR_low_area_tb.vhd |
|
vsim -gui work.fir_low_area_tb |
|
add wave -position insertpoint \ |
/fir_low_area_tb/data_length \ |
/fir_low_area_tb/bits_resol \ |
/fir_low_area_tb/taps \ |
/fir_low_area_tb/hn\ |
/fir_low_area_tb/areset \ |
/fir_low_area_tb/clock_fs \ |
/fir_low_area_tb/freq_xn |
|
add wave -noupdate -format Analog-Interpolated -height 74 -max 2047.0 -min -2048.0 -radix decimal /fir_low_area_tb/duv_fir_signed/xn |
add wave -noupdate -format Analog-Interpolated -height 74 -max 2047.0 -min -2048.0 -radix decimal /fir_low_area_tb/duv_fir_signed/yn |
|
add wave -noupdate -format Analog-Interpolated -height 74 -max 4095.0 -min 0 -radix unsigned /fir_low_area_tb/duv_fir_unsigned/xn |
add wave -noupdate -format Analog-Interpolated -height 74 -max 4095.0 -min 0 -radix unsigned /fir_low_area_tb/duv_fir_unsigned/yn |
|
|
|
run -all |
/fir_filter/tags/testbench/filtro_fir.m
1,79 → 1,83
clear all; |
format long g; |
|
%%%%%%%%%%%%%%%%%%%% h[n] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
figure(1); |
|
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
% OBTENCION DE COEFICIENTES PARA |
% filtro_FIR.vhd |
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
% http://t-filter.appspot.com/fir/index.html |
|
fs = 32e6 |
orden = 31 % = coeficientes -1 |
fc = 10e3 % frec de corte |
fs=64e6 |
order=31 |
fc=2e6 |
input_size=8 |
|
bits_entrada = 8 |
%%%%%%%%%%%%%%%%%%%% h[n] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
% NOTA: las ilustraciones que se muestran tienen los valores |
% redondeados por lo que para verlos correctamente (en la |
% linea de comandos) descomentar el penultimo parrafo al |
% final de este archivo (y_u, y_delta, y_rampas) |
fnyquist=fs/2; |
|
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
%normalized cut-off frequency |
wn=fc/fnyquist; |
|
h= fir1(order,wn,'low') |
|
wn = 2*fc/fs |
figure(1); |
stem(h); |
title('h(n)');grid on; |
|
h=fir1(orden,wn) % coeficientes del filtro FIR |
|
stem(h); |
title('h(n) = coeficientes filtro FIR');grid on; |
%%%%%%%%%%%%%%%%%%%% H[z] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
figure(2); |
freqz(h); |
|
%%%%%%%%%%%%%%%%%%%% x[n] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
figure(2); |
num_cycles=16; |
amplitude=2^input_size-1; |
freq=fc/4; |
|
num_muestras=64; |
magnitud=2^bits_entrada-1; % amplitud de las entradas 0:1:255 (A) |
% entrada impulsional delta[n] |
num_samples=num_cycles*(fs/freq); |
|
delta=[]; |
delta(1:num_muestras)=zeros(1); |
delta(num_muestras/2)=ones(1)*magnitud; |
subplot(2,3,1); axis([0 64 0 max(delta)]); stem(delta); title('x[n]=A delta[n]'); grid on; |
n=0:1/(fs/freq):num_cycles; |
sin=amplitude*sin(2*pi*n); |
x=sin+(amplitude/20)*randn(size(n)); |
|
% ventana rectangular u[n] |
figure(3); |
subplot(2,2,1); |
str=sprintf('x[n]: f=%g Hz max=%g+noise',freq,max(sin)); |
stem(x); title(str); grid on; |
|
u=[]; |
u(1:num_muestras)=zeros(1); |
u(num_muestras/4 :num_muestras/4+7)=ones(1)*magnitud; |
subplot(2,3,2); axis([0 64 0 max(u)]); stem(u); title('x[n]=A u[n]'); grid on; |
%%%%%%%%%%%%%%%%%%%% x[z] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
% rampa rampas[n] |
% NFFT = 2^nextpow2(num_samples); |
% f = (1:NFFT/2+1)*(fs/NFFT); % wn=1 <> fs/2 |
|
rampas=[]; |
rampas(1:num_muestras)=zeros(1); |
for R = 1:(num_muestras/4) |
rampas(R)=magnitud/(num_muestras/4)*R; |
end |
for R = (num_muestras/4+1):num_muestras/2 |
rampas(R)=magnitud/(num_muestras/4)*(R-(num_muestras/4)); |
end |
subplot(2,3,3); axis([0 64 0 max(rampas)]); stem(rampas); title('x[n]=A rampas[n]'); grid on; |
% X = fft(x,NFFT); |
% peakpowerX = max(X).*conj(max(X))/NFFT; |
|
%%%%%%%%%%%%%%%%%%%%% y[n] %%%%%%%%%%%%%%%%%%%%%%%% |
subplot(2,2,2); |
% stem(f,2*abs(X(1:NFFT/2+1))); |
% str=sprintf('x[z] peak power=%g',peakpowerX); |
% title(str); grid on; |
% xlabel('f[Hz]') |
% ylabel('|x[z]|') |
periodogram(x,rectwin(length(x)),length(x),fs); |
|
y_u=filter(h,1,u); % respuesta a: A u[n] |
y_delta=filter(h,1,delta); % respuesta a: A delta[n] |
y_rampas=filter(h,1,rampas);% respuesta a: A rampas[n] |
|
subplot(2,3,4); axis([0 64 0 max(y_delta)]); stem(y_delta); title('y[n]'); grid on; |
subplot(2,3,5); axis([0 64 0 max(y_u)]); stem(y_u); title('y[n]'); grid on; |
subplot(2,3,6); axis([0 64 0 max(y_rampas)]); stem(y_rampas); title('y[n]'); grid on; |
% %%%%%%%%%%%%%%%%%%%% y[n] %%%%%%%%%%%%%%%%%%%%%%% |
|
y=filter(h,1,x); |
subplot(2,2,3); |
str=sprintf('y[n]: fc=%g Hz peak=%g',fc,max(y(length(h):num_samples))); |
stem(y); title(str); grid on; |
|
%%%%%%%%%%%%%%%%%%%% y[z] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
subplot(2,2,4); |
periodogram(y,rectwin(length(y)),length(y),fs); |
|
|
format; |
|
|
/fir_filter/tags/testbench/FIR_low_area_tb.vhd
0,0 → 1,170
|
-- CREATION DATE .......: 08 April 2015 |
-- AUTHOR ..............: DIEGO PARDO (arroxo2@yahoo.es) |
-- REVISION ............: 1.0 |
-- LAST UPDATE .........: 08 April 2015 |
-- UPDATED BY ..........: DIEGO PARDO |
|
-- TITLE "CONFIGURABLE FIR FILTER TESTBENCH"; |
-- |
-- http://t-filter.appspot.com/fir/index.html |
|
--============================================================================= |
--================================ TESTBENCH ================================== |
--============================================================================= |
|
LIBRARY ieee; |
USE ieee.std_logic_1164.all; |
USE ieee.std_logic_arith.all; |
USE ieee.std_logic_signed.all; |
USE ieee.math_real.all; |
|
LIBRARY work; |
USE work.fir_package.all; |
|
|
ENTITY FIR_low_area_tb IS |
END FIR_low_area_tb; |
|
|
ARCHITECTURE FIR_low_area_tb_arch OF FIR_low_area_tb IS |
|
-- TESTCASE SETTINGS |
--............................................................................. |
CONSTANT freq_xn : REAL := 900.0e3; -- input frequency |
CONSTANT data_length : NATURAL := 12; -- input bit size |
|
CONSTANT fs_Hz : REAL := 8.0e6; -- sampling frequency |
CONSTANT taps : NATURAL := 15; -- order+1 |
-- transition band: 800e3 to 1.6e6 |
CONSTANT hn : COEFF_ARRAY := (-0.01259277478717816, |
-0.02704833486706803, |
-0.031157016036431583, |
-0.0033516667471792812, |
0.06651710329324828, |
0.1635643048779222, |
0.249729473226146, |
0.2842779082622769, |
0.249729473226146, |
0.1635643048779222, |
0.06651710329324827, |
-0.0033516667471792812, |
-0.031157016036431583, |
-0.027048334867068043, |
-0.01259277478717816, |
others=>0.0); |
CONSTANT bits_resol : NATURAL := 12; |
--.............................................................................. |
|
SIGNAL areset : STD_LOGIC; |
SIGNAL clock_fs : STD_LOGIC := '1'; |
SIGNAL xn_signed : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
SIGNAL xn_unsigned : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
SIGNAL yn_signed : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
SIGNAL yn_unsigned : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
|
SIGNAL radians : REAL := 0.0; |
SIGNAL radian_step : REAL := 1.0/(fs_Hz/freq_xn); |
|
CONSTANT PI : REAL := 3.1415926535897932; |
CONSTANT num_cycles : NATURAL := 16; |
CONSTANT fs_period : TIME := integer(1.0e12/fs_Hz)* 1 ps; |
CONSTANT num_samples : NATURAL := num_cycles*integer(round(fs_Hz/freq_xn)); |
CONSTANT amplitude : REAL := 2.0**real(data_length-1)-1.0; |
|
BEGIN |
|
duv_fir_signed: ENTITY work.FIR_low_area |
--............................................. |
generic map( |
data_length => data_length, |
data_signed => true, |
improv_t => false, |
bits_resol => bits_resol, |
taps => taps, |
coefficients => hn) |
port map( |
areset => areset, |
sreset => '0', |
clock_fs => clock_fs, |
enable => '1', |
xn => xn_signed, |
yn => yn_signed |
); |
|
duv_fir_unsigned: ENTITY work.FIR_low_area |
--............................................. |
generic map( |
data_length => data_length, |
data_signed => false, |
improv_t => false, |
bits_resol => bits_resol, |
taps => taps, |
coefficients => hn) |
port map( |
areset => areset, |
sreset => '0', |
clock_fs => clock_fs, |
enable => '1', |
xn => xn_unsigned, |
yn => yn_unsigned |
); |
|
sampling_clock: process |
--............................................. |
begin |
clock_fs <= '1'; |
wait for fs_period/2; |
clock_fs <= '0'; |
wait for fs_period/2; |
end process; |
|
xn_sinus: process |
--............................................. |
variable seed1,seed2 : positive; |
variable rand : real; |
variable noise_n : real; |
variable sinus_n : real; |
begin |
UNIFORM(seed1, seed2, rand); -- uniform 0.0 to 1.0 |
noise_n := 2.0*(rand-0.5) * (amplitude/20.0); |
sinus_n := amplitude * sin(2.0*PI*radians) + noise_n; |
|
-- saturation control |
if sinus_n > amplitude then |
sinus_n := amplitude; |
elsif sinus_n < -amplitude then |
sinus_n := -amplitude; |
end if; |
|
xn_signed <= std_logic_vector(conv_signed(integer(round(sinus_n)),data_length)); |
xn_unsigned <= std_logic_vector(conv_unsigned(integer(round(amplitude + sinus_n)),data_length)); |
|
if radians >= 1.0 then |
radians <= 0.0; |
else |
radians <= radians + radian_step; |
end if; |
wait until rising_edge(clock_fs); |
end process; |
|
reset: process |
--............................................. |
begin |
areset <= '1'; |
wait for 10 ns; |
areset <= '0'; |
wait; |
end process; |
|
sim_time: process |
--............................................. |
begin |
wait for num_samples*fs_period; |
assert false report "SIMULATION END" severity failure; |
end process; |
|
|
END FIR_low_area_tb_arch; |
|
|
/fir_filter/tags/FIR_low_area.vhd
0,0 → 1,523
|
-- CREATION DATE .......: 02 Jul 2007 (Filtro_FIR.vhd) |
-- AUTHOR ..............: DIEGO PARDO (arroxo2@yahoo.es) |
-- REVISION ............: 2.0 |
-- LAST UPDATE .........: 08 April 2015 |
-- UPDATED BY ..........: DIEGO PARDO |
|
-- TITLE "CONFIGURABLE FIR FILTER"; |
-- |
-- Generic VHDL (suitable for ALTERA, XILINX, MICROSEMI, etc) |
-- Low resources occupation (fixed-point implementation) |
-- |
|
|
--============================================================================= |
--============================= LOCAL PACKAGE ================================= |
--============================================================================= |
|
LIBRARY ieee; |
USE ieee.std_logic_1164.all; |
USE ieee.std_logic_arith.all; |
USE ieee.std_logic_signed.all; |
USE ieee.math_real.all; |
|
|
PACKAGE fir_package IS |
|
CONSTANT max_coef: NATURAL:= 128; -- (increase if needed) |
TYPE COEFF_ARRAY IS ARRAY (0 to max_coef-1) OF REAL; |
FUNCTION decimal_to_signed (c_real: IN REAL; CONSTANT precision: IN NATURAL) RETURN SIGNED; |
|
END fir_package; |
|
|
PACKAGE body fir_package IS |
|
FUNCTION decimal_to_signed (c_real: IN REAL; CONSTANT precision: IN NATURAL) RETURN SIGNED IS |
-- SIGNED = REAL / 2^(-precision) = REAL * 2^precision, with IEEE rounding |
CONSTANT RESOLUCION : REAL := "**"(2,REAL(INTEGER(precision))); |
BEGIN |
RETURN (SIGNED(CONV_STD_LOGIC_VECTOR(INTEGER(ROUND ("*"(c_real,RESOLUCION))),precision+1))); |
END FUNCTION; |
|
END fir_package; |
|
|
|
--============================================================================= |
--================================== ENTITY =================================== |
--============================================================================= |
|
LIBRARY work; |
USE WORK.fir_package.all; |
|
LIBRARY ieee; |
USE ieee.std_logic_1164.all; |
USE ieee.std_logic_arith.all; |
USE ieee.std_logic_signed.all; |
USE ieee.math_real.all; |
|
--............................................................................. |
-- GAIN 1.0 |
-- SATURATION CONTROL Yes (output) |
-- OUTPUT ROUNDING Yes (IEEE) |
-- IMPLEMENTED BY Fixed-Point (configurable resolution) |
-- 3rd-PARTY IPs No (generic VHDL) |
--............................................................................. |
|
ENTITY FIR_low_area IS |
GENERIC( |
data_length : NATURAL := 8; -- input/output length (number of bits) |
data_signed : BOOLEAN := false; -- input/output type (signed or unsigned) |
improv_t : BOOLEAN := false; -- minimal timing improvement by adding one extra output cycle delay (use only if needed) |
bits_resol : NATURAL := 16; -- number of bits for the internal operations with decimals in fixed point. Recommended: bits_resol > taps. THIS SETTING IS CRITICAL FOR P&R RESULTS (MAX FREQ) |
taps : NATURAL := 5; -- =order+1, 2 coefficients as minimum (order=1) |
coefficients : COEFF_ARRAY :=( -- normalized coefficients bi: (bo,b1, ..., bN). They must be symmetric (but sign) |
-0.11735685282030676, |
0.23471370564061372, |
0.7066280917835991, |
0.23471370564061372, |
-0.11735685282030676, |
OTHERS=>0.0) -- (always end with "others=>0.0") |
); |
PORT( |
areset : IN STD_LOGIC; -- active high |
sreset : IN STD_LOGIC; -- active high |
clock_fs : IN STD_LOGIC; |
enable : IN STD_LOGIC; |
xn : IN STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); -- FILTER INPUT (any fixed-point format, e.g. whole numbers) |
yn : OUT STD_LOGIC_VECTOR(data_length-1 DOWNTO 0) -- FILTER OUTPUT (keeps same fixed-point format of input) |
); |
END FIR_low_area; |
|
|
|
ARCHITECTURE FIR_low_area_arch OF FIR_low_area IS |
|
type ENTRADA_xn IS ARRAY (taps-2 DOWNTO 0) OF SIGNED(data_length DOWNTO 0); -- A(data_length,0) : x[n-k] |
type VALORES_h IS ARRAY (taps-1 DOWNTO 0) OF SIGNED(bits_resol DOWNTO 0); -- A(0,bits_resol) : h[n-k] |
|
SIGNAL REGISTRO_xn : ENTRADA_xn; |
|
SIGNAL yn_1, yn_2 : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); |
SIGNAL yn_aux : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); -- yn_1 + yn_2 |
SIGNAL yn_comb : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); |
SIGNAL yn_sync : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); |
|
SIGNAL yn_unsigned : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
SIGNAL yn_signed : STD_LOGIC_VECTOR(data_length-1 DOWNTO 0); |
|
CONSTANT SIGNED_MAX : INTEGER := 2**(yn'length-1)-1; |
CONSTANT SIGNED_MIN : INTEGER := -1 * 2**(yn'length-1); |
|
|
BEGIN |
|
|
ASSERT (bits_resol >= 4) |
REPORT "PLEASE INCREASE RESOLUTION BITS (result will be poor)" SEVERITY FAILURE; |
|
-- pragma translate_off |
process |
VARIABLE sum_coeff : real; |
begin |
sum_coeff := 0.0; |
FOR ind IN 0 TO (taps-1) LOOP |
sum_coeff := sum_coeff + coefficients(ind); |
END LOOP; |
ASSERT sum_coeff = 1.0 |
REPORT "COEFFICIENTS ARE NOT NORMALIZED" SEVERITY WARNING; |
wait; |
end process; |
-- pragma translate_on |
|
|
-- ======================================================================================= |
-- HALF FILTERING OPERATIONS (1/2) |
-- (DOES NOT INCLUDE INITIAL AND FINAL COEFFICIENTS, INCLUDES CENTRE COEFFICIENT (WHEN "taps" EVEN) |
-- ======================================================================================= |
|
process1: |
PROCESS (clock_fs, areset) |
VARIABLE xn_a_pares : SIGNED (data_length+1 DOWNTO 0); -- to sum x[n-k] with symmetric coefficients |
VARIABLE REGISTRO_h : VALORES_h := (OTHERS => (OTHERS => '0')); -- it stores the coefficients (avoids registers) |
VARIABLE producto : SIGNED (data_length+1+bits_resol+1 DOWNTO 0); -- product of xn_a_pares by symmetric coefficient |
VARIABLE yn_aux : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); -- partial sum |
VARIABLE signos_bi : STD_LOGIC_VECTOR (1 DOWNTO 0); -- signs of the symmetric coefficients |
VARIABLE indice1 : NATURAL; |
VARIABLE margen : NATURAL; |
|
BEGIN |
IF (areset = '1') THEN |
yn_1 <= (OTHERS => '0'); |
|
ELSIF rising_edge(clock_fs) THEN |
IF (sreset = '1') THEN |
yn_1 <= (OTHERS => '0'); |
ELSE |
|
IF (enable = '1') THEN |
|
-- variable avoids h[n] register, REGISTRO_h(0) = bN |
FOR ind IN 0 TO (taps-1) LOOP |
REGISTRO_h(ind) := decimal_to_signed (coefficients(taps-1-ind),bits_resol); |
END LOOP; |
|
yn_aux := (OTHERS => '0'); |
|
-- symmetric coefficients (but first and last ones): |
-- In this cycle x[n-k] has not been applied yet to the shift register of x[n] |
IF (taps > 3) THEN |
|
indice1 := (taps/2)+(taps MOD 2); |
margen := ((taps-1)-(taps/2))/2 - (taps MOD 2); |
|
FOR i IN indice1 TO (indice1 + margen) LOOP |
|
-- symmetric bi signs |
signos_bi(1):= REGISTRO_h(i)(bits_resol); |
signos_bi(0):= REGISTRO_h(taps-1-i)(bits_resol); |
|
CASE signos_bi IS |
WHEN "00" => xn_a_pares:= "+"( CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN "01" => xn_a_pares:= "+"( CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN "10" => xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN OTHERS => xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
END CASE; |
|
producto := "*"(xn_a_pares, ABS(REGISTRO_h(i))); |
yn_aux := "+"(yn_aux, producto); |
END LOOP; |
END IF; |
|
--------------------------------------------------------------- |
-- central coefficient operation (when taps is even) |
--------------------------------------------------------------- |
-- non-symmetric coefficient |
|
IF (taps MOD 2)/=0 THEN |
producto := "*"(CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps/2))),data_length+2), REGISTRO_h(taps/2)); |
yn_aux := "+"(yn_aux, producto); |
END IF; |
|
--------------------------------------------------------------- |
-- output of processo1 |
--------------------------------------------------------------- |
-- yn_1 has decimal part (bits_resol bits) |
|
yn_1 <= yn_aux; |
|
END IF; |
END IF; |
END IF; |
END PROCESS process1; |
|
|
-- ======================================================================================= |
-- HALF FILTERING OPERATIONS (2/2) |
-- (INCLUDINF INITIAL AND FINAL COEFFICIENTS) |
-- ======================================================================================= |
|
process2: |
PROCESS (clock_fs, areset) |
VARIABLE xn_a_pares : SIGNED (data_length+1 DOWNTO 0); -- to sum x[n-k] with symmetric coefficients |
VARIABLE REGISTRO_h : VALORES_h := (OTHERS => (OTHERS => '0')); -- it stores the coefficients (avoids registers) |
VARIABLE producto : SIGNED (data_length+1+bits_resol+1 DOWNTO 0); -- product of xn_a_pares by symmetric coefficient |
VARIABLE yn_aux : SIGNED (data_length+1+bits_resol+1+(taps-2) DOWNTO 0); -- partial sum |
VARIABLE signos_bi : STD_LOGIC_VECTOR (1 DOWNTO 0); -- signs of the symmetric coefficients |
VARIABLE indice1 : NATURAL; |
VARIABLE margen : NATURAL; |
|
BEGIN |
IF (areset = '1') THEN |
yn_2 <= (OTHERS => '0'); |
|
ELSIF rising_edge(clock_fs) THEN |
IF (sreset = '1') THEN |
yn_2 <= (OTHERS => '0'); |
ELSE |
|
IF (enable = '1') THEN |
|
-- variable avoids h[n] register, REGISTRO_h(0) = bN |
FOR ind IN 0 TO (taps-1) LOOP |
REGISTRO_h(ind) := decimal_to_signed (coefficients(taps-1-ind),bits_resol); |
END LOOP; |
|
|
yn_aux := (OTHERS => '0'); |
|
-- symmetric coefficients (but first and last ones). When taps < 7 the operations are resolved by process1: |
-- In this cycle x[n-k] has not been applied yet to the shift register of x[n] |
IF (taps > 6) THEN |
|
indice1 := (taps/2)+(taps MOD 2); |
margen := ((taps-1)-(taps/2))/2 - (taps MOD 2); |
|
FOR i IN (indice1 + margen + 1) TO (taps-2) LOOP |
|
-- symmetric bi signs |
signos_bi(1):= REGISTRO_h(i)(bits_resol); |
signos_bi(0):= REGISTRO_h(taps-1-i)(bits_resol); |
|
CASE signos_bi IS |
WHEN "00" => xn_a_pares:= "+"( CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN "01" => xn_a_pares:= "+"( CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN "10" => xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
WHEN OTHERS => xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(signed(REGISTRO_xn(i))),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(taps-1-i))),data_length+2)); |
END CASE; |
|
producto:= "*"(xn_a_pares, ABS(REGISTRO_h(i))); |
yn_aux := "+"(yn_aux, producto); |
END LOOP; |
END IF; |
|
---------------------------------------------------------------- |
-- first and last coefficients operation (symmetric) |
---------------------------------------------------------------- |
-- The initial coefficient multiplies x[n] (not registered yet) |
|
signos_bi(1):= REGISTRO_h(taps-1)(bits_resol); |
signos_bi(0):= REGISTRO_h(0)(bits_resol); |
|
CASE signos_bi IS |
|
WHEN "00" => if (data_signed = true) then |
xn_a_pares:= "+"( CONV_SIGNED(conv_integer( signed(xn)),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
else |
xn_a_pares:= "+"( CONV_SIGNED(conv_integer(unsigned(xn)),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
end if; |
WHEN "01" => if (data_signed = true) then |
xn_a_pares:= "+"( CONV_SIGNED(conv_integer( signed(xn)),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
else |
xn_a_pares:= "+"( CONV_SIGNED(conv_integer(unsigned(xn)),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
end if; |
WHEN "10" => if (data_signed = true) then |
xn_a_pares:= "+"(-CONV_SIGNED(conv_integer( signed(xn)),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
else |
xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(unsigned(xn)),data_length+2), CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
end if; |
WHEN OTHERS => if (data_signed = true) then |
xn_a_pares:= "+"(-CONV_SIGNED(conv_integer( signed(xn)),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
else |
xn_a_pares:= "+"(-CONV_SIGNED(conv_integer(unsigned(xn)),data_length+2), -CONV_SIGNED(conv_integer(signed(REGISTRO_xn(0))),data_length+2)); |
end if; |
END CASE; |
|
producto := "*"(xn_a_pares, ABS(REGISTRO_h(taps-1))); |
yn_aux := "+"(yn_aux, producto); |
|
--------------------------------------------------------------- |
-- output of processo2 |
--------------------------------------------------------------- |
-- yn_2 has decimal part (bits_resol bits) |
|
yn_2 <= yn_aux; |
|
END IF; |
END IF; |
END IF; |
END PROCESS process2; |
|
|
-- ======================================================================================= |
-- SHIT REGISTER: x[n-k] |
-- ======================================================================================= |
|
process_reg: |
PROCESS (clock_fs, areset) |
BEGIN |
IF (areset = '1') THEN |
REGISTRO_xn <= (OTHERS => (OTHERS => '0')); |
|
ELSIF rising_edge(clock_fs) THEN |
IF (sreset = '1') THEN |
REGISTRO_xn <= (OTHERS => (OTHERS => '0')); |
ELSE |
|
IF (enable = '1')THEN |
|
--------------------------------------------------------------- |
-- x[n-k], it is not applied instantaneously (scheduled) |
--------------------------------------------------------------- |
-- right-shift |
|
FOR i IN 0 TO (taps-3) LOOP -- (ignored when taps=2) |
REGISTRO_xn(i)<= REGISTRO_xn(i+1); |
END LOOP; |
|
if (data_signed = true) then |
REGISTRO_xn(taps-2) <= CONV_SIGNED(conv_integer( signed(xn)),data_length+1); |
else |
REGISTRO_xn(taps-2) <= CONV_SIGNED(conv_integer(unsigned(xn)),data_length+1); |
end if; |
|
END IF; |
END IF; |
END IF; |
|
END PROCESS process_reg; |
|
|
-- ======================================================================================= |
-- OUTPUT (neither saturation control nor IEEE rounding) |
-- ======================================================================================= |
-- SUM of process1 and process2 outputs |
|
yn_comb <= yn_1 + yn_2; |
yn_sync <= yn_1 + yn_2 when rising_edge(clock_fs); |
|
yn_aux <= yn_sync when (improv_t = true) else yn_comb; |
|
|
--------------------------------------------------------------- |
-- OUTPUT (with saturation control and IEEE rounding) |
--------------------------------------------------------------- |
|
-- yn_aux of type A(_,bits_resol): |
-- whole part: 'LEFT downto bits_resol |
-- decimal part: (bits_resol-1) downto 0 |
-- |
-- |<------------------------------------------ yn_aux ------------------------------------------->| |
-- [yn_aux'left] ..... [bits_resol+data_length-1] ..... [bits_resol] [bits_resol-1] .........[0] |
-- |<------------ yn_signed/unsigned ------------>|<----- (decimal part) ----->| |
|
|
-- unsigned output: |
yn_unsigned <= |
(OTHERS => '0') WHEN yn_aux(bits_resol+data_length+1) = '1' ELSE -- negative overflow |
(OTHERS => '1') WHEN yn_aux(bits_resol+data_length) = '1' ELSE -- positive overflow |
STD_LOGIC_VECTOR(yn_aux(bits_resol+data_length-1 DOWNTO bits_resol))+1 WHEN yn_aux(bits_resol-1) = '1' and STD_LOGIC_VECTOR(yn_aux(bits_resol+data_length-1 downto bits_resol)) /= (yn'range => '1') ELSE -- positive IEEE rounding (avoids positive overflow) |
STD_LOGIC_VECTOR(yn_aux(bits_resol+data_length-1 DOWNTO bits_resol)); -- truncated |
|
-- signed output: |
yn_signed <= |
STD_LOGIC_VECTOR(CONV_SIGNED(SIGNED_MIN,data_length)) WHEN yn_aux(bits_resol+data_length) = '1' and yn_aux(bits_resol+data_length-1) = '0' ELSE -- negative overflow |
STD_LOGIC_VECTOR(CONV_SIGNED(SIGNED_MAX,data_length)) WHEN yn_aux(bits_resol+data_length) = '0' and yn_aux(bits_resol+data_length-1) = '1' ELSE -- positive overflow |
STD_LOGIC_VECTOR(yn_aux(bits_resol+data_length-1 DOWNTO bits_resol))+1 WHEN yn_aux(bits_resol-1) = '1' and -- positive or negative IEEE rounding (avoids positive overflow) |
(yn_aux(bits_resol+data_length-1) = '1' or STD_LOGIC_VECTOR(yn_aux(bits_resol+data_length-2 downto bits_resol)) /= (yn_aux(bits_resol+data_length-2 downto bits_resol)'range => '1')) ELSE |
STD_LOGIC_VECTOR(signed(yn_aux(bits_resol+data_length-1 DOWNTO bits_resol))); -- truncated |
|
-- FINAL OUTPUT |
yn <= yn_signed when (data_signed = true) else yn_unsigned; |
|
|
END FIR_low_area_arch; |
|
|
|
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
--@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
|
|
------------------------------------------------------------------------------- |
-- DESCRIPTION |
------------------------------------------------------------------------------- |
-- |
------------------ |
-- DELAY |
------------------ |
-- clock_fs period x taps |
-- |
------------------ |
-- AREA |
------------------ |
-- bits_resol stablishes the precision of the filtering operations (resources) |
-- |
------------------ |
-- OUTPUT ERROR |
------------------ |
-- maximum output error: |
-- |
-- ------------------------------------------------------ |
-- | taps * [2^(-bits_resol)] * [(2^data_length)-1)] | |
-- ------------------------------------------------------ |
-- (taps = order+1) |
-- |
------------------------------------------------------------------------------ |
-- Operations: |
------------------------------------------------------------------------------ |
-- |
-- h[n] = A(0,bits_resol) with resolution = 2^(-bits_resol) |
-- x[n] = A(data_length,0) |
-- |
-- y[n] = sum{x[n-k] x h[k]} |
-- x[n-i] x h[i] = A(data_length,0) x A(0,bits_resol) = A(data_length+0+1,bits_resol) |
-- y[n] = A(data_length+1+[taps]-1,bits_resol) |
-- |
------------------------------------------------------------------------------ |
-- Implementation: |
------------------------------------------------------------------------------ |
-- |
-- -FIR direct form II- |
-- |
-- 3 process() in parallel: |
-- |
-- process1(): 1/2 part of the filtering operations |
-- process2(): 2/2 part of the filtering operations |
-- process_reg(): x[n-k] |
-- |
-- FIR filters have symmetric coefficients (but sign): |
-- |
-- e.g. taps=5 and positive h[n] coefficients: |
-- x[n-3]*h(3) + x[n-1]*h[1] = (x[n-3]+x[n-1])*h[3], because h[1]=h[3] |
-- |
--------------- |
-- |
-- x: products by means of process1() and centre coefficient |
-- o: products by means of process2() and first-last coefficients |
-- |
-- |
-- taps bi prod process1() prod process2() |
-- |
-- 2 x x 0 1 bo=b1 |
-- 3 o x o 1 b1 1 bo=b2 |
-- 4 o x x o 1 b1=b2 1 bo=b3 |
-- 5 o x x x o 2 b1=b3, b2 1 bo=b4 |
-- 6 o x x x x o 2 b1=b4, b2=b3 1 bo=b5 |
-- 7 o o x x x o o 2 b2=b4, b3 2 bo=b6, b1=b5 |
-- 8 o o x x x x o o 2 b2=b5, b3=b4 2 bo=b7, b1=b6 |
-- 9 o o x x x x x o o 3 b2=b6, b3=b5, b4 2 bo=b8, b1=b7 |
-- 10 o o x x x x x x o o 3 b2=b7, b3=b6, b4=b5 2 bo=b9, b1=b8 |
-- 11 o o o x x x x x o o o 3 b3=b7, b4=b6, b5 3 bo=b10, b1=b9, b2=b8 |
-- 12 o o o x x x x x x o o o 3 b3=b8, b4=b7, b5=b6 3 bo=b11, b1=b10, b2=b9 |
-- 13 o o o x x x x x x x o o o 4 b3=b9, b4=b8, b5=b7, b6 3 bo=b12, b1=b11, b2=b10 |
-- 14 o o o o x x x x x x o o o o 4 b4=b9, b5=b8, b6=b7 4 bo=b13, b1=b12, b2=b11, b3=b10 |
-- 15 o o o o x x x x x x x o o o o 4 b4=b10,b5=b9, b6=b8, b7 4 bo=b14, b1=b13, b2=b12, b3=b11 |
-- (etc)... |
|
------------------------------------------------------------------------------- |
-- Fixed-Point Arithmetic: An Introduction |
-- Randy Yates |
-- March 3, 2001 11:52 |
------------------------------------------------------------------------------- |
-- |
-- A(a,b): a = whole part, b = decimal part |
-- |
-- length = (a+b) +1 bits (sign) |
-- resolution (steps) = 2^(-b) |
-- maximum value = 2^a - 2^(-b) |
-- minimum value = -2^(-a) |
-- |
-- Operations: |
-- |
-- A(x,y) * A(z,n) = A(x+z+1,y+n), length = (x+z+1+y+n) +1 bits (sign) |
-- A(x,y) + A(x,y) = A(x+1,y) , length = (x+1+y) +1 bits (sign) |
-- A(x,y) + A(x,y) + A(x,y)= A(x+2,y) , length = (x+2+y) +1 bits (sign) |
-- |
|
------------------------------------------------------------------------------ |
-- TYPES CONVERSION (OF CONSTANT VALUES) |
------------------------------------------------------------------------------ |
-- |
-- REAL -> INTEGER -> STD_LOGIC_VECTOR -> SIGNED: |
-- |
-- SIGNED(CONV_STD_LOGIC_VECTOR(INTEGER(ROUND(<real_value>)))) |
-- |
-- SIGNED -> STD_LOGIC_VECTOR -> INTEGER -> REAL: |
-- |
-- ROUND(REAL(CONV_INTEGER(CONV_STD_LOGIC_VECTOR(<signed_value>)))) |
-- |