Escrito por Guillermo Acevedo
Diseño
En esta practica desarrollaremos un filtro FIR en hardware, para este caso en especifico, realizaremos un filtro rechaza-banda para ventana Hamming entre 3000Hz y 13000Hz de orden 20 con una frecuencia de muestreo de 44100Hz, para lograr esto, utilizaremos el siguiente diseño:
Como observamos en la imagen, lo primero que tenemos que hacer es buscar el NCO en los open cores, y conectarlo a una ROM hecha en la FPGA para tomar diferentes valores de frecuencia, este tiene como salida una señal que simula una señal seno con la frecuencia deseada, utilizaremos un modulo llamado waveform_gen, este esta escrito en VHDL, asi que realizamos la instanciación en verilog y lo instanciamos en nuestro modulo principal. Simulamos el modulo waveform_gen y el resultado de el es:
Ver una señal análoga Modelsim parece difícil cuando se ve, pero en realidad se puede realizar fácilmente de la siguiente manera:
Para lograr esto, damos click derecho sobre la señal que queremos ver, escogemos la opcion de format y pinchamos en analog (automatic), para que automáticamente de el tamaño de la señal y no salga de los margenes que se nos da para dibujar la señal.
Creamos luego el modulo div_freq y colocamos en su entrada 31'd566, el cual hace referencia a una frecuencia de 44100Hz.
El siguiente es la ROM para las frecuencias que vamos a pasar para el NCO, para eso utilizamos el principio de la multiplexión de señales y las controlaremos por medio de los SW que tenemos en la tarjeta, para esto utilizamos la formula dada por el creador del modulo waveform_gen para generar las frecuencias.
Dependiendo de la señan de los sw sale una valor que es enviado al NCO para producir las señales senoidales
Procedemos ahora a crear nuestro modulo FIR, para el cual, debemos obtener primero los coeficientes del filtro en Matlab, para ello utilizaremos el código de FIR SW Design, este nos da unos coeficientes entre 0 y 1, nosotros tenemos que escalarlos para ingresarlos facilmente en la FPGA y no trabajar con decimales, utilizaremos para este caso un escalonaje de 8 bits, es decir, multiplicaremos los valores dados anteriormente por 256, es decir 2^8. El filtro hecho con Matlab queda como:
Con coeficientes de
-0,00148636112047322 0,000610781534272632 -0,00669201059088164 -0,00275624156299243 0,0303606416472069 0,0219128277898686 0,00449108715728677 0,132599993943691 0,179821495619680 -0,165922289863956 0,543677517903215 -0,172948355895413 0,195655602021611 0,151061333326642 0,00538349072957317 0,0278386935227264 0,0412726372637053 -0,00404892024397716 -0,0105945089674328 0,000972578512282662 -0,00186606153195758
respectivamente
al escalonar estas variables, el resultado es:
Como podemos observar en la imagen, se desplaza el filtro en su magnitud en dB, sus coeficientes quedan:
0 0 1 0 -3 -6 2 15 13 -9 233 -9 13 15 2 -6 -3 0 1 0 0
respectivamente
Ya que hay números negativos, tenemos que pasar todo a complemento a 2 y a hexadecimal, haciendo esto, nos quedan los valores:
0000 0000 0001 0000 FFFD FFFA 0002 000F 000D FFF7 00E9 FFF7 000D 000F 0002 FFFA FFFD 0000 0001 0000 0000
respectivamente
Guardamos esto en un archivo llamado coef.txt, el cual utilizaremos mas adelante.
Creamos nuestro modulo fir, con sus respectivas señales de entrada y salida:
Necesitamos un clk, una entrada de audio, que es por donde entra nuestra señal senoidal, audio_out es nuestra salida, los coef, que son para ingresar coeficientes desde el NIOS II, pero aqui no se hablara de eso, y una entrada para los SW.
Se crean registros para la entrada de los valores senoidales, ya que son 21 coeficientes, solo pueden haber 21 valores en los registros de entrada, se crean 2 cables para realizar en ellos las operaciones correspondientes.
Debemos llegar a este diseño, que es como funciona este tipo de filtros:
Donde z^-1 significa un retardo, es decir, el dato anterior de la entrada, y en los amplificadores se colocan los valores de los coeficientes hallados anteriormente, luego de esto, se realiza la suma de todos los valores hasta llegar a un valor final, como el filtro es de orden 20 tenemos 21 coeficientes, es decir, tendremos 21 retardos, 21 amplificadores y 20 sumas.
Seguido a esto, inicializamos los coeficientes, para eso utilizaremos initial $readmemh para leer un archivo, entonces colocamos:
Luego de eso, inicializamos los valores de la dirección [0] de los registros y de los cables, es decir, vamos a tomar los valores en la entrada del NCO cada pulso de reloj, también tomaremos los de coef. En el caso de multi[0] va a ser igual al valor de la entrada en la posicion [0] por el valor del coef en la direccion [0], y sum[0] sera multi de la posición [20] +multi de la posición [19], el valor de la suma [19] que sera la ultima, sera la salida del sistema escalada 8 bits, es decir, la salida no tomara los 8 bits menos significativos que serian los 256 que multiplicamos al escalar en Matlab.
Ahora utilizamos los generate para realizar las asignaciones, donde vamos a realizar las sumas, de la suma anterior con la siguiente multiplicación en el primer generate y en el segundo se pasa el valor del registro al siguiente registro y borra el ultimo valor, para los valores de la seniodal y para los coeficientes.
Luego instanciamos en verilog nuestro modulo y lo pegamos en nuestro modulo principal
Se crean algunos cables, como el de clk_44100 que es el que lleva la señal de la salida del div_freq al FIR, el cable seno transporta transporta la señal de salida del NCO, audio_out_fir, es la salida del FIR y se conecta al multiplexor, el cual dependiendo del estado del KEY[0] deja pasar la señal de salida del FIR o la del NCO.
Para finalizar debemos instanciar el modulo del dac, y conectar los cables de entrada del multiplexor y su salida seria la frecuencia analogica.
Por ultimo, tenemos la simulación del filtro, en Modelsim, en la cual tenemos un modulo con la generación de la señal seno, la selección de la frecuencia, para alguna de las guardadas en la ROM, y tenemos el filtro, el cual, como podemos observar en la siguiente figura, tenemos una onda seno con diferentes frecuencias, podemos observar que sus amplitudes son las mismas, cuando observamos la señal filtrada, nos damos cuenta de que los valores de las frecuencias son iguales, pero dependiendo de la frecuencia utilizada la señal se atenúa, cuando tenemos un 110 en la señal del SW, obtenemos la máxima atenuación, cabe resaltar que se puede llegar a mejores resultados si se utiliza otro tipo de ventana, si aumentamos la precisión o si aumentamos el numero de bits en el escalamiento.
En el siguiente link podrán encontrar los diferentes archivos utilizados en esta practica, el programa completo con los módulos en un .qar de quartus, el archivo de los coeficientes en un .txt y el archivo de Matlab con el cual se tomaron los coeficientes, y el código utilizado para la simulación del filtro. https://github.com/Adrizcorp/ece10243upb2016/tree/master/Estudiantes/guillermo/archivos_FIR
Referencias