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 10 to Rev 9
- ↔ Reverse comparison
Rev 10 → Rev 9
/fir_filter/tags/FIR_low_area.vhd
File deleted
/fir_filter/tags/testbench/simulation.do
File deleted
\ No newline at end of file
/fir_filter/tags/testbench/FIR_low_area_tb.vhd
File deleted
/fir_filter/tags/testbench/filtro_fir.m
1,83 → 1,79
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=64e6 |
order=31 |
fc=2e6 |
input_size=8 |
fs = 32e6 |
orden = 31 % = coeficientes -1 |
fc = 10e3 % frec de corte |
|
%%%%%%%%%%%%%%%%%%%% h[n] %%%%%%%%%%%%%%%%%%%%%%%%% |
bits_entrada = 8 |
|
fnyquist=fs/2; |
% 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) |
|
%normalized cut-off frequency |
wn=fc/fnyquist; |
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
%XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
|
h= fir1(order,wn,'low') |
|
figure(1); |
stem(h); |
title('h(n)');grid on; |
wn = 2*fc/fs |
|
h=fir1(orden,wn) % coeficientes del filtro FIR |
|
%%%%%%%%%%%%%%%%%%%% H[z] %%%%%%%%%%%%%%%%%%%%%%%%% |
stem(h); |
title('h(n) = coeficientes filtro FIR');grid on; |
|
figure(2); |
freqz(h); |
|
%%%%%%%%%%%%%%%%%%%% x[n] %%%%%%%%%%%%%%%%%%%%%%%%% |
|
num_cycles=16; |
amplitude=2^input_size-1; |
freq=fc/4; |
figure(2); |
|
num_samples=num_cycles*(fs/freq); |
num_muestras=64; |
magnitud=2^bits_entrada-1; % amplitud de las entradas 0:1:255 (A) |
% entrada impulsional delta[n] |
|
n=0:1/(fs/freq):num_cycles; |
sin=amplitude*sin(2*pi*n); |
x=sin+(amplitude/20)*randn(size(n)); |
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; |
|
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; |
% ventana rectangular u[n] |
|
%%%%%%%%%%%%%%%%%%%% x[z] %%%%%%%%%%%%%%%%%%%%%%%%% |
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; |
|
% NFFT = 2^nextpow2(num_samples); |
% f = (1:NFFT/2+1)*(fs/NFFT); % wn=1 <> fs/2 |
% rampa rampas[n] |
|
% X = fft(x,NFFT); |
% peakpowerX = max(X).*conj(max(X))/NFFT; |
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; |
|
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[n] %%%%%%%%%%%%%%%%%%%%%%%% |
|
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] |
|
% %%%%%%%%%%%%%%%%%%%% y[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=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/filtro_FIR.vhd
0,0 → 1,604
-- SUBSISTEMA ..........: |
-- TARJETA .............: |
|
|
-- AUTOR ...............: DIEGO PARDO |
|
|
|
|
-- TITULO "FILTRO FIR DE COEFICIENTES SIMETRICOS"; |
|
|
------------------------------------------------------------------------------- |
-- DESCRIPCION: |
------------------------------------------------------------------------------- |
-- |
-- Filtro FIR de orden variable (orden min = 1) y totalmente parametrizable. |
-- Dispone de control de saturacion negativa y positiva. (CONSTANT max_coef= 64). |
|
-- La instanciacion y declaracion de este componente estan al final de este |
-- fichero. |
|
-- Para la obtencion de los coeficientes se puede usar el fichero de matlab |
-- "filtros_fir.m". En ese fichero solo es necesario modificar "fs", "orden" |
-- y "fc", y directamente devuelve los coeficientes. Tambien se puede ver unas |
|
-- y rampa ascendente). |
-- Se pueden introducir coef obtenidos por otros metodos, pero siempre deben |
-- ser normalizados a 1 (si no lo estuviesen). |
-- |
-- VELOCIDAD |
------------------ |
-- La velocidad viene marcada por el orden del filtro. El retardo max de salida es |
-- igual al orden del filtro + 1 ciclo. |
-- |
-- AREA |
------------------ |
-- La resolucion, como parametro de entrada, marca la precision de las operaciones |
-- de filtrado (y por tanto el area que ocupa). A menor resolucion menor area. |
-- |
-- ERROR DE SALIDA |
------------------ |
-- El error maximo a la salida del filtro es igual a: |
-- |
-- ------------------------------------------------- |
-- | num_coef * [2^(-bits_resol)] * [(2^bits_in)-1)] | |
-- ------------------------------------------------- |
-- (num_coef = orden+1) |
|
------------------------------------------------------------------------------- |
-- FUNCIONAMIENTO: |
------------------------------------------------------------------------------- |
|
-- x[n] entrada sincrona positiva |
-- h[n] coeficientes |
-- y[n] salida sincrona positiva (procesada en <1 ciclo, sin usar pipeline) |
|
------------------------------------------------------------------------------ |
-- Operaciones de filtrado: |
------------------------------------------------------------------------------ |
|
-- coeficentes normalizados A(0,bits_resol) con resolucion = 2^(-bits_resol) |
-- valores x[n] U(bits_in,0) -> A(bits_in,0) |
-- |
-- y[n] = sum{x[n-k] x h[k]}: |
-- productos A(bits_in,0) x A(0,bits_resol) = A(bits_in+0+1,bits_resol) |
-- num_coef-1 sumas A(bits_in+1,bits_resol) => y[n] : A(bits_in+1+[num_coef]-1,bits_resol) |
-- |
------------------------------------------------------------------------------ |
-- Implementacion: |
------------------------------------------------------------------------------ |
-- |
-- -FIR en forma directa II- |
-- |
-- Se implementan 3 procesos que operan en paralelo de la siguiente forma: |
-- |
-- proceso1(): realiza operaciones de filtrado con la mitad de coef |
-- proceso2(): realiza operaciones de filtrado con la mitad de coef |
-- proceso_reg(): implementa el registro de desplazamiento para x[n-k] |
-- |
-- Los filtros FIR son simetricos, por lo que se aprovecha para que cada uno |
-- de los procesos que realizan operaciones lo hagan de forma simplificada, |
|
-- p.e. para num_coef=5 y coef positivos: |
-- x[n-3]*h(3) + x[n-1]*h[1] = (x[n-3]+x[n-1])*h[3], ya que h[1]=h[3] |
-- |
--------------- |
-- |
-- x: productos realizados por proceso1() -> mitad coef intermedios y coef central |
-- o: productos realizados por proceso2() -> mitad coef intermedios y coef inicial y final (extremos) |
-- |
-- num_coef bi prod proceso1() prod proceso2() |
-- |
-- 2? x x 0 1 bo=b1 |
-- 3 o x o 1 1 bo=b2 |
-- 4 o x x o 1 b1=b2 1 bo=b3 |
-- 5 o x x x o 2 b2=b3 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 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, 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 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 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 4 bo=b14,b1=b13,b2=b12,b3=b11 |
-- ... |
|
------------------------------------------------------------------------------- |
-- Fixed-Point Arithmetic: An Introduction |
-- Randy Yates |
-- March 3, 2001 11:52 |
------------------------------------------------------------------------------- |
|
-- A(a,b): 'a' parte entera sin signo y 'b' parte decimal |
-- |
-- bits = (a+b) + 1 (signo) |
-- resolucion (pasos) = 2^(-b) |
-- max value = 2^a - 2^(-b) |
-- min value = -2^(-a) |
-- |
-- A(x,y) * A(z,n) = A(x+z+1,y+n) con (x+z+1+y+n) +1 bits (signo) |
-- A(x,y) + A(x,y) = A(x+1,y) con (x+1+y) +1 bits (signo) |
-- A(x,y) + A(x,y) + A(x,y)= A(x+2,y) con (x+2+y) +1 bits (signo) |
-- |
|
------------------------------------------------------------------------------ |
-- CONVERSIONES ENTRE TIPOS (CONSTANTES) |
------------------------------------------------------------------------------ |
|
-- |
-- REAL -> INTEGER -> STD_LOGIC_VECTOR -> SIGNED: |
-- |
-- SIGNED(CONV_STD_LOGIC_VECTOR(INTEGER(ROUND(valor_real)))) |
-- |
-- SIGNED -> STD_LOGIC_VECTOR -> INTEGER -> REAL: |
-- |
-- ROUND(REAL(CONV_INTEGER(CONV_STD_LOGIC_VECTOR(valor_signed)))) |
-- |
|
--============================================================================= |
--============================= PACKAGE LOCAL ================================= |
--============================================================================= |
|
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; -- interfaz para introducir los coef en formato real |
|
|
PACKAGE tipos_filtro IS |
|
CONSTANT max_coef: NATURAL:= 64; |
TYPE COEFICIENTES IS ARRAY (max_coef-1 DOWNTO 0) OF REAL; |
FUNCTION real_a_signed (CONSTANT c_real: IN REAL; CONSTANT precision: IN NATURAL) RETURN SIGNED; |
|
END tipos_filtro; |
|
|
PACKAGE body tipos_filtro IS |
|
FUNCTION real_a_signed (CONSTANT c_real: IN REAL; CONSTANT precision: IN NATURAL) RETURN SIGNED IS |
-- SIGNED = REAL / 2^(-precision) = REAL * 2^precision, con redondeo IEEE |
CONSTANT RESOLUCION : REAL := "**"(2,REAL(INTEGER(precision))); |
BEGIN |
RETURN (SIGNED(CONV_STD_LOGIC_VECTOR(INTEGER(ROUND ("*"(c_real,RESOLUCION))),precision+1))); |
END FUNCTION; |
|
END tipos_filtro; |
|
--============================================================================= |
--=========================== ENTITY filtro_FIR =============================== |
--============================================================================= |
|
USE WORK.tipos_filtro.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; -- usada como interfaz para introducir los coef en formato real |
|
--LIBRARY altera; |
--USE altera.altera_syn_attributes.all; |
|
|
ENTITY filtro_FIR IS |
GENERIC |
( |
bits_in : NATURAL := 8; -- = bits de entrada = bits de salida |
num_coef : NATURAL := 32; -- = N (orden) + 1, min 2 coef (N = 1) |
bits_resol : NATURAL := 32; -- = bits parte decimal de los coef => resol = 2^(-bits_resol) |
coeficiente : COEFICIENTES := ( -- coeficientes bi normalizados (bo, ..., bN) |
0.00475562935382438, |
0.00531548289351449, |
0.00697197720225127, |
0.00965735079759454, |
0.0132617084564161, |
0.017637519982969, |
0.0226056603567445, |
0.0279627439350249, |
0.0334894523768257, |
0.038959515246785, |
0.0441489755173365, |
0.0488453605108728, |
0.05285638268919, |
0.0560178139472758, |
0.0582002109141864, |
0.0593142158191887, |
0.0593142158191887, |
0.0582002109141864, |
0.0560178139472758, |
0.05285638268919, |
0.0488453605108728, |
0.0441489755173365, |
0.038959515246785, |
0.0334894523768257, |
0.0279627439350249, |
0.0226056603567445, |
0.017637519982969, |
0.0132617084564161, |
0.00965735079759454, |
0.00697197720225127, |
0.00531548289351449, |
0.00475562935382438, |
OTHERS=>0.0) |
); |
PORT |
( |
reset : IN STD_LOGIC; |
reloj : IN STD_LOGIC; |
enable : IN STD_LOGIC; |
|
yn : OUT STD_LOGIC_VECTOR(bits_in-1 DOWNTO 0) -- Dato de salida con control de sat neg |
-- yn_fraccional : OUT SIGNED (bits_in+1+bits_resol+1+(num_coef-2) DOWNTO 0) -- sin control de sat para depuracion |
); |
END filtro_FIR; |
|
ARCHITECTURE arch_filtro_FIR OF filtro_FIR IS |
type ENTRADA_xn IS ARRAY (num_coef-2 DOWNTO 0) OF SIGNED(bits_in DOWNTO 0); -- A(bits_in,0) : x[n-k] |
type VALORES_h IS ARRAY (num_coef-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 (bits_in+1+bits_resol+1+(num_coef-2) DOWNTO 0); |
SIGNAL yn_aux : SIGNED (bits_in+1+bits_resol+1+(num_coef-2) DOWNTO 0); -- yn_1 + yn_2 |
|
|
BEGIN |
|
-- ======================================================================================= |
-- PROCESO DE LA MITAD DE LAS OPERACIONES DE FILTRADO |
-- (NO INCLUYE COEF INICIAL NI FINAL; INCLUYE COEF INTERMEDIO SI "num_coef" ES IMPAR) |
-- ======================================================================================= |
|
proceso1: |
PROCESS (reloj, reset) |
|
VARIABLE xn_a_pares : SIGNED (bits_in+1 DOWNTO 0); -- para sumas de pares de x[n-k] con coef simetricos |
VARIABLE REGISTRO_h : VALORES_h := (OTHERS => (OTHERS => '0')); -- para guardar los coef (evita el registro) |
VARIABLE producto : SIGNED (bits_in+1+bits_resol+1 DOWNTO 0); -- prod de xn_a_pares por cada coef |
VARIABLE yn_aux : SIGNED (bits_in+1+bits_resol+1+(num_coef-2) DOWNTO 0);-- sumas parciales |
VARIABLE signos_bi : STD_LOGIC_VECTOR (1 DOWNTO 0); -- signos de los coef simetricos |
VARIABLE signos_xn : STD_LOGIC_VECTOR (1 DOWNTO 0); -- Ssignos de los pares de x[n-k] |
|
|
-- estas variables sirven para definir cuantas operaciones el proceso para hacer las |
-- operaciones de filtrado. El proceso comienza en el coef "indice1" y realiza operaciones |
-- con un numero de coeficientes dado por "margen". No se usan ctes porque solo se asignan |
-- si num_coef supera cierto valor (sino darian error por la formula aplicada). |
VARIABLE indice1 : NATURAL; |
VARIABLE margen : NATURAL; |
|
BEGIN |
IF (reset = '1') THEN |
yn_1 <= (OTHERS => '0'); |
|
ELSIF (reloj'event AND reloj='1') THEN |
IF (enable = '1') THEN |
|
-- se usa una variable para evitar el registro de h[n], REGISTRO_h(0) = bN |
FOR ind IN 0 TO (num_coef-1) LOOP |
REGISTRO_h(ind) := real_a_signed (coeficiente(max_coef-num_coef+ind),bits_resol); |
END LOOP; |
|
---------------------------------------------------------------- |
-- operaciones filtrado (num_coef marca el num de prod y sumas) |
---------------------------------------------------------------- |
|
-- en este ciclo aun no se ha aplicado x[n-k] al registro de valores de x[n] |
|
-- como los filtros FIR son simetricos, se aprovecha esto para realizar |
-- la mitad de multiplicaciones (considerando los signos): primero se suman entre |
-- si los x[n-k] que corresponden a operaciones con coeficientes simetricos y |
-- luego se le aplica el signo (se extiende siempre el signo '0' al registro de |
-- x[n-k] porque x[n] es siempre positivo) |
yn_aux := (OTHERS => '0'); |
|
-- operaciones con los coef simetricos (ni con el coef central ni con el inicial o final): |
|
-- (en caso de que el num de coef sea 3 coinciden los coef simetricos intermedios |
-- con el inicial y final, q son caso especial -> debemos evitar confundirlos) |
|
IF (num_coef > 3) THEN |
|
indice1 := (num_coef/2)+(num_coef MOD 2); |
margen := ((num_coef-1)-(num_coef/2))/2 - (num_coef MOD 2); |
|
FOR i IN indice1 TO (indice1 + margen) LOOP |
|
-- signos de los bi simetricos |
signos_bi(1):= REGISTRO_h(i)(bits_resol); |
signos_bi(0):= REGISTRO_h(num_coef-1-i)(bits_resol); |
|
-- signos de los x[n-k] con coef simetricos para extension de signo |
signos_xn(1):= REGISTRO_xn(i)(REGISTRO_xn(i)'left); |
signos_xn(0):= REGISTRO_xn(num_coef-1-i)(REGISTRO_xn(num_coef-1-i)'left); |
|
CASE signos_bi IS |
WHEN "00" => -- FIR tipo I - II |
xn_a_pares:= "+"(signos_xn(1)®ISTRO_xn(i), signos_xn(0)®ISTRO_xn(num_coef-1-i)); |
WHEN "01" => -- FIR tipo III - IV |
xn_a_pares:= "+"(signos_xn(1)®ISTRO_xn(i), -(signos_xn(0)®ISTRO_xn(num_coef-1-i))); |
WHEN "10" => -- FIR tipo III - IV |
xn_a_pares:= "+"(-(signos_xn(1)®ISTRO_xn(i)), signos_xn(0)®ISTRO_xn(num_coef-1-i)); |
WHEN OTHERS => -- FIR tipo I - II |
xn_a_pares:= "+"(-(signos_xn(1)®ISTRO_xn(i)), -(signos_xn(0)®ISTRO_xn(num_coef-1-i))); |
END CASE; |
|
producto:= "*"(xn_a_pares, ABS(REGISTRO_h(i))); |
yn_aux := "+"(yn_aux, producto); |
END LOOP; |
END IF; |
|
--------------------------------------------------------------- |
-- Operacion con el coef central (si num_coef es impar) |
--------------------------------------------------------------- |
|
-- El coef central (si num_coef es impar) no es simetrico con |
-- ningun otro coef |
|
IF (num_coef MOD 2)/=0 THEN |
signos_xn(1):= REGISTRO_xn(num_coef/2)(REGISTRO_xn(num_coef/2)'left); |
producto := "*"(signos_xn(1)®ISTRO_xn(num_coef/2), REGISTRO_h(num_coef/2)); |
yn_aux := "+"(yn_aux, producto); |
END IF; |
|
--------------------------------------------------------------- |
-- SALIDA FRACCIONAL SIN CONTROL DE SATURACION |
--------------------------------------------------------------- |
|
-- yn_1 agrupa los bits de la parte entera y decimal (bits_resol) |
yn_1 <= yn_aux; |
|
|
|
END IF; -- (reloj) |
END IF; -- (reset - enable) |
END PROCESS proceso1; |
|
|
-- ======================================================================================= |
-- PROCESO DE LA OTRA MITAD DE LAS OPERACIONES DE FILTRADO |
-- (INCLUYE COEF INICIAL Y FINAL) |
-- ======================================================================================= |
|
proceso2: |
PROCESS (reloj, reset) |
|
VARIABLE xn_a_pares : SIGNED (bits_in+1 DOWNTO 0); -- para sumas de pares de x[n-k] con coef simetricos |
VARIABLE REGISTRO_h : VALORES_h := (OTHERS => (OTHERS => '0')); -- para guardar los coef (evita el registro) |
VARIABLE producto : SIGNED (bits_in+1+bits_resol+1 DOWNTO 0); -- prod de xn_a_pares por cada coef |
VARIABLE yn_aux : SIGNED (bits_in+1+bits_resol+1+(num_coef-2) DOWNTO 0);-- sumas parciales |
VARIABLE signos_bi : STD_LOGIC_VECTOR (1 DOWNTO 0); -- signos de los coef simetricos |
VARIABLE signos_xn : STD_LOGIC_VECTOR (1 DOWNTO 0); -- Ssignos de los pares de x[n-k] |
|
-- estas variables sirven para definir cuantas operaciones el proceso para hacer las |
-- operaciones de filtrado. El proceso comienza en el coef "indice1" y realiza operaciones |
-- con un numero de coeficientes dado por "margen". No se usan ctes porque solo se asignan |
-- si num_coef supera cierto valor (sino darian error por la formula aplicada). |
VARIABLE indice1 : NATURAL; |
VARIABLE margen : NATURAL; |
|
BEGIN |
IF (reset = '1') THEN |
yn_2 <= (OTHERS => '0'); |
|
ELSIF (reloj'event AND reloj='1') THEN |
IF (enable = '1') THEN |
|
-- se usa una variable para evitar el registro de h[n], REGISTRO_h(0) = bN |
FOR ind IN 0 TO (num_coef-1) LOOP |
REGISTRO_h(ind) := real_a_signed (coeficiente(max_coef-num_coef+ind),bits_resol); |
END LOOP; |
|
---------------------------------------------------------------- |
-- operaciones filtrado (num_coef marca el num de prod y sumas) |
---------------------------------------------------------------- |
|
-- en este ciclo aun no se ha aplicado x[n-k] al registro de valores de x[n] |
|
-- como los filtros FIR son simetricos, se aprovecha esto para realizar |
-- la mitad de multiplicaciones (considerando los signos): primero se suman entre |
-- si los x[n-k] que corresponden a operaciones con coeficientes simetricos y |
-- luego se le aplica el signo (se extiende siempre el signo '0' al registro de |
-- x[n-k] porque x[n] es siempre positivo) |
|
yn_aux := (OTHERS => '0'); |
|
-- operaciones con los coef simetricos (ni con el coef central ni con el inicial o final): |
|
-- (en caso de que el num de coef sea 4 o 5 las operaciones ya habrian sido realizadas |
-- por el proceso anterior) |
|
IF (num_coef > 6) THEN |
|
indice1 := (num_coef/2)+(num_coef MOD 2); |
margen := ((num_coef-1)-(num_coef/2))/2 - (num_coef MOD 2); |
|
FOR i IN (indice1 + margen + 1) TO (num_coef-2) LOOP |
|
-- signos de los bi simetricos |
signos_bi(1):= REGISTRO_h(i)(bits_resol); |
signos_bi(0):= REGISTRO_h(num_coef-1-i)(bits_resol); |
|
-- signos de los x[n-k] con coef simetricos para extension de signo |
signos_xn(1):= REGISTRO_xn(i)(REGISTRO_xn(i)'left); |
signos_xn(0):= REGISTRO_xn(num_coef-1-i)(REGISTRO_xn(num_coef-1-i)'left); |
|
CASE signos_bi IS |
WHEN "00" => -- FIR tipo I - II |
xn_a_pares:= "+"(signos_xn(1)®ISTRO_xn(i), signos_xn(0)®ISTRO_xn(num_coef-1-i)); |
WHEN "01" => -- FIR tipo III - IV |
xn_a_pares:= "+"(signos_xn(1)®ISTRO_xn(i), -(signos_xn(0)®ISTRO_xn(num_coef-1-i))); |
WHEN "10" => -- FIR tipo III - IV |
xn_a_pares:= "+"(-(signos_xn(1)®ISTRO_xn(i)), signos_xn(0)®ISTRO_xn(num_coef-1-i)); |
WHEN OTHERS => -- FIR tipo I - II |
xn_a_pares:= "+"(-(signos_xn(1)®ISTRO_xn(i)), -(signos_xn(0)®ISTRO_xn(num_coef-1-i))); |
END CASE; |
|
producto:= "*"(xn_a_pares, ABS(REGISTRO_h(i))); |
yn_aux := "+"(yn_aux, producto); |
END LOOP; |
END IF; |
|
---------------------------------------------------------------- |
-- operacion con el coef inicial y final (simetricos) |
---------------------------------------------------------------- |
|
-- El coef inicial es el que multiplica a x[n] (que aun no ha |
-- sido registrado) |
|
signos_bi(1):= REGISTRO_h(num_coef-1)(bits_resol); |
signos_bi(0):= REGISTRO_h(0)(bits_resol); |
|
signos_xn(0):= REGISTRO_xn(0)(REGISTRO_xn(0)'left); |
|
CASE signos_bi IS |
WHEN "00" => -- FIR tipo I - II |
xn_a_pares:= "+"("00"&SIGNED(xn), signos_xn(0)®ISTRO_xn(0)); |
WHEN "01" => -- FIR tipo III - IV |
xn_a_pares:= "+"("00"&SIGNED(xn), -(signos_xn(0)®ISTRO_xn(0))); |
WHEN "10" => -- FIR tipo III - IV |
xn_a_pares:= "+"(-SIGNED('0'&xn), signos_xn(0)®ISTRO_xn(0)); |
WHEN OTHERS => -- FIR tipo I - II |
xn_a_pares:= "+"(-SIGNED('0'&xn), -(signos_xn(0)®ISTRO_xn(0))); |
END CASE; |
|
producto:= "*"(xn_a_pares, ABS(REGISTRO_h(num_coef-1))); |
yn_aux := "+"(yn_aux, producto); |
|
|
--------------------------------------------------------------- |
-- SALIDA FRACCIONAL SIN CONTROL DE SATURACION |
--------------------------------------------------------------- |
|
-- yn_2 agrupa los bits de la parte entera y decimal (bits_resol) |
yn_2 <= yn_aux; |
|
|
|
END IF; -- (reloj) |
END IF; -- (reset - enable) |
END PROCESS proceso2; |
|
|
-- ======================================================================================= |
-- PROCESO QUE IMPLEMENTA LOS DESPLAZADORES x[n-k] |
-- ======================================================================================= |
|
proceso_reg: |
PROCESS (reloj, reset) |
|
BEGIN |
|
IF (reset = '1') THEN |
REGISTRO_xn <= (OTHERS => (OTHERS => '0')); |
|
ELSIF (reloj'event AND reloj='1') THEN |
IF (enable = '1')THEN |
|
--------------------------------------------------------------- |
-- x[n-k], no se aplica al instante (agendado) |
--------------------------------------------------------------- |
|
-- el valor actual de x[n] entra al registro de desplazamiento por |
-- la parte alta y el valor mas antiguo de x[n] desaparece |
|
FOR i IN 0 TO (num_coef-3) LOOP -- (ignorado si num_coef=2) |
REGISTRO_xn(i)<= REGISTRO_xn(i+1); |
END LOOP; |
|
REGISTRO_xn(num_coef-2)<= SIGNED('0' & xn); |
|
END IF; |
END IF; |
|
END PROCESS proceso_reg; |
|
|
-- ======================================================================================= |
-- CIRCUITO COMBINACIONAL QUE DETERMINA LA SALIDA |
-- ======================================================================================= |
|
-- se combinan (suman) los resultados de los procesos que operan en paralelo (cada uno |
-- realiza aprox. la mitad de operaciones de filtrado) |
|
-- yn_fraccional <= yn_1 + yn_2; -- salida fraccional sin control de saturacion |
yn_aux <= yn_1 + yn_2; -- para usar en el control de saturacion de yn |
|
--------------------------------------------------------------- |
-- SALIDA NATURAL CON CONTROL DE SATURACION |
--------------------------------------------------------------- |
|
-- yn_aux de tipo A(_,bits_resol): |
-- parte entera: 'LEFT a bits_resol |
-- parte decimal: (bits_resol-1) a 0 |
|
|
yn <= -- saturacion negativa (signo extendido) |
(OTHERS => '0') WHEN yn_aux(yn_aux'left) = '1' ELSE |
-- saturacion positiva |
(OTHERS => '1') WHEN yn_aux(bits_in + bits_resol)= '1' ELSE |
-- redondeo IEEE por arriba (si MSB de parte decimal = '1') |
CONV_STD_LOGIC_VECTOR(yn_aux(yn_aux'LEFT DOWNTO bits_resol),bits_in)+1 WHEN yn_aux(bits_resol-1) = '1' ELSE |
-- valor por defecto (sin alterar) |
CONV_STD_LOGIC_VECTOR(yn_aux(yn_aux'LEFT DOWNTO bits_resol),bits_in); |
|
|
END arch_filtro_FIR; |
-- |
-- |
-- |
-- |
-- |
-- |
-- |
-- |
-- |
-- |
-- |
--============================================================================= |
--============ INSTANCIACION Y DECLARACION COMPONENTE filtro_FIR ============== |
--============================================================================= |
|
--COMPONENT filtro_FIR |
-- GENERIC |
-- ( |
-- bits_in : NATURAL; -- = bits de entrada = bits de salida |
-- num_coef : NATURAL; -- = orden filtro + 1, min 3 coef |
-- bits_resol : NATURAL; -- = bits parte decimal de los coef => resolucion = 2^(-bits_resol) |
-- coeficiente : COEFICIENTES -- coef con matlab: "filtro_fir.m" (modificar fs, orden y fc) |
-- ); |
-- PORT |
-- ( |
-- reset : IN STD_LOGIC; |
-- reloj : IN STD_LOGIC; |
-- enable : IN STD_LOGIC; |
|
-- yn : OUT STD_LOGIC_VECTOR(bits_in-1 DOWNTO 0) -- Dato de salida con control de saturacion |
-- ); |
-- |
--END COMPONENT; |
|
--============================================================================= |
|
--nombre_componente : filtro_FIR |
-- GENERIC MAP( |
-- bits_in : NATURAL => , -- = bits de entrada = bits de salida |
-- num_coef : NATURAL => , -- = orden filtro + 1, min 2 coef |
-- bits_resol : NATURAL => , -- = bits parte decimal de los coef => resolucion = 2^(-bits_resol) |
-- coeficiente : COEFICIENTES => -- coef con matlab: "filtro_fir.m" (modificar fs, orden y fc) |
-- ) |
-- PORT MAP( |
-- reset => , -- 1bit |
-- reloj => , -- 1bit |
-- enable => , -- 1bit |
|
-- yn => -- "bits_in" bit, Dato de salida con control de saturacion |
-- ); |
|
--============================================================================= |