JACK FIR

Introducción

BruteFIR es excelente para el filtrado digital dada su velocidad. Los ordenadores ARM empiezan a tener una potencia más que respetable con la ventaja de su bajo consumo eléctrico y la no necesidad de procesador. Algunas placas que usan esta arquitectura, incluyen un DSP. Si BruteFIR usase ese DSP, quizá estas placas tendrían potencia suficiente para hacer el filtrado digital.

Aquí recopilo notas sobre un posible fork de BruteFIR que hiciese uso del DSP.

Requerimientos

Realmente dos:

  • Tiene que ser compatible con JACK.
  • Tiene que usar la API del DSP.

Con ello pretendo simplificar BruteFIR:

  • Al eliminar la compatibilidad con ALSA, PULSE, … Se elimina la necesidad de implementer el sistema modular de IO que tiene BruteFIR. La desventaja es que ahora JACK pasa a ser obligatorio.
  • El uso de JACK elimina la necesidad que tiene BruteFIR para conectar unos filtros con otros. Esa funcionalidad ya la proporciona JACK. ¿Por qué reimplementarla? De esta manara, cada cliente de JACK sólo tendría que considerar un único filtro.
  • El uso del DSP tendría que simplificar toda la codificación del proceso de convolución. No es necesario usar ensamblador. Es posible que la programación no sea tan sencilla por las particularidades que pueda tener la programación de un DSP.

Sobre JACK

tutorial

Para compilar:

gcc -o metronome `pkg-config —cflags —libs jack` metro.c

Sobre DSP

El DSP que incorpora la IGEPv2 es el TMS320C64x+.

Tengo la impresión de que la IGEPv2 no es apta para esta aplicación. Quizá sería mejor usar una HawkBoard, que incluye un DSP en coma flotante. La librería para ese DSP es ésta. Tiene funciones para FIR con muchos coeficiones (DSPF_sp_fir_r2).

La placa es más barata 74€ en Farnell.

DSPs

Teoría

http://www.dsptutor.freeuk.com/dfilt1.htm

Hay dos elementos claves para conseguir el rendimiento adecuado cuando se pretenden usar filtros con kernels muy largos:

  • FFT convolution: cuando el kernel tiene más de 60 taps es más económico usar "FFT Convolution" en lugar de la concolución normal en el dominio del tiempo. Para ello se hace el FFT del kernel, obteniendo los valores reales y los imaginarios. Por otro lado, se hace el FFT de la señal obteniendo los valores reales y los imaginarios. En el dominio de la frecuencia, la convolución equivale a la multiplicación, por lo que se hace la multiplicación compleja. Finalmente, se vuelve al dominio del tiempo mediante la IFFT.
  • Partitioned convolution: suele interesar dividir la convolución en trozos más pequeños y combinarlos
  • Convolución eficiente con latencia nula: se explica un procedimiento para realizar la convolución de una forma eficiente sin introducir latencia.

Hardware DSP

Software DSP

FFT Convolution

La convolución en el dominio del tiempo equivale a la multiplicación en el dominio de la frecuencia.

La idea

La secuencia de acontecimientos es:

  • Señal analógica: V=x(t)
  • Señal sampleada: xi = x (ih) = x0, x1, x2, …
  • Se aplica el filtrado obteniendo: y0, y1, y2, …
  • Se vuelve a convertir en analógico.

Aplicar algunos filtrados es inmediato:

  • yi = xi: no hace nada a la señal
  • yi = k*xi : aumenta o disminuye el volumen.
  • yi = xi-1: retrasa la señal un poco (delay)
  • Igualmente podría aplicar algún tipo de derivada: yi = (xi-xi-1)/t

Orden de un filtro

Para un elemento de la salida Yi, es el número de elementos de la entrada de instantes anteriores usados.

Coeficientes del filtro:

yi = ao * xi + a1 * xi-1 + a2 * xi-2 + …

Tipos de filtros

Some people prefer an alternative terminology in which a non-recursive filter is known as an FIR (or Finite Impulse Response) filter, and a recursive filter as an IIR (or Infinite Impulse Response) filter.

No recursivos

Usan la muestra actual y las anteriores en el tiempo (ya han ocurrido).

Recursivos

Pueden usar muestras pasadas y futuras.

Función de transferencia

Riesgos

Además de mis propias limitaciones, hay un par de problemas que pueden caer muy por encima de mis conocimientos informáticos. +++ Multitarea
BruteFIR es multihilo (usa pthreads). Aunque no lo fuese, JACK es multihilo. Eso no es un problema para ARM, pero, potencialmente, sí que lo es para el DSP (no es multitarea).
Texas Instruments tiene algo llamado DSP Link o DSPOS, que parece estar orientado a esta tarea.

Gestión de la memoria

Aunque el DSP sea capaz de realizar muchos cálculos rápidamente, la gestión de la memoria puede ser un problema crítico. No tengo ninguna experiencia en este campo, pero por lo que veo en otros proyectos (por ejemplo, en este intento de optimización de FFT usando NEON -NEON viene a ser la unidad de coma flotante en ARM-).

Alternativas

Una alternativa es pasar del uso del DSP para la realización de los cálculos. En ese sentido, hay varios caminos:

  • Usar NEON: como hemos visto con anterioridad, hay un proyecto que intenta optimizar el cálculo de FFT mediante el uso de estas instrucciones SIMD (Singel Instruction Multiple Data).
  • Usar "fixed point": en lugar de hacer los cálculos en coma flotante, hacerlos mediante enteros. En ese sentido, los procesadores ARM son excelentes (al nivel de los procesadores más potentes de Intel). Ese es el camino seguido por Tremor (un decoder para el formato de audio Vorbis) o Mad (lo mismo para MP3). En este sentido:
    • Hay un proyecto interesante dentro del proyecto de firmware para reproductores de MP3 llamado RockBox. Dentro de este proyecto, existe FasterMDCT, que implementa la Modified Discrete Cosine Transform (de la que no tengo ni idea) pero que se usa en muchos codec de audio. Para ello, tomaron el FFT de FFMPEG (que es más rápido que el FFTW) y lo portaron a aritmética de enteros. Sería interesante tomar esa parte del código para implementar la Partitioned Convolution del BruteFIR o jConv.
    • KissFFT: otro programa que emplea tanto aritmética de coma flotante como de punto fijo. No es especialmente rápido.

Si decido ponerme el mono, podría interesar seguir el siguiente camino:
1. Comprar el hardware más potente. Beagle Board xM. Quizá sea capaz de trabajar con un par de filtros. Permitiría hacer DRC con un sistema pasivo.
2. Si no fuese capaz de dar la potencia suficiente. Hacer un cliente en JACK es sencillo. Quizá fuese relativamente fácil portar jConv para que use el FFT desarrollado por RockBox. Esa placa proporciona ">2000 Dhrystone MIPS" (mi Intel Core 2 produce del orden de 300). Usando enteros, tendría que proporcionar buen rendimiento. Un tema delicado puede ser el tipo de memoria usada. (¿Hay opciones con DDR2 o DDR3?).
3. Dados mis conocimientos, la última alternativa debería ser trabajar con el DSP.

Reducción de riesgos

  • Crear un cliente JACK.
  • Crear un cliente JACK que haga una convolución.
  • Crear un cliente JACK que haga la convolución usando distintas librerías. Opciones:
  • Cuando sea mayor, quizá intentar una implementación en el DSP.

Links

http://www.nicholson.com/rhn/dsp.html
Stream Processors

http://e2e.ti.com/support/embedded/f/356/t/41882.aspx
http://www.lcardaba.com/articles/drc5.htm

  • jack_convolve: podría ser una buena base para implementar esta idea. Se puede descargar de aquí.

¿Se podría envolver el código DSP como un paquete python? En ese caso, podríamos usar: py-jack, simplificando mucho el código.

El rendimiento con enteros de estas placas es brutal. Hay programas que hacen uso únicamente de enteros:

  • mad: decoder MP3 basado en enteros.
  • La decodificación de FLAC sólo requiere cálculos con enteros.
  • libsamplerate: aquí dicen que tiene fixed-point (yo tengo mis dudas).

http://www.ee.iitm.ac.in/~dj/comm_labs/fixed_point/fp_simul.ps
http://www.ee.ed.ac.uk/~pmg/SIGPRO/dsp.chps.html
http://www.isppld.com/corporate/newscenter/newsletters/newsjuly2010/highperformancedspfilterd.cfm

  • jconv: otro convolver que usa jack y partitioned convolution.

http://www.dspguide.com/ch28/6.htm

http://maltanar.blogspot.com/2010_05_01_archive.html
http://beagleboard.org/project/disptec/
http://focus.ti.com/docs/toolsw/folders/print/tmdmfp.html
http://elinux.org/BeagleBoard/DSP_Howto
http://elinux.org/BeagleBoard/GSoC/Ideas
http://elinux.org/BeagleBoard/GSoC/2010_Projects
http://www.mathkb.com/Uwe/Forum.aspx/num-analysis/931/fixed-point-real-FFT-for-embedded
http://www.faqs.org/patents/app/20090172062
http://hax4.blogspot.com/2010/02/arm-fft-in-assembly.html
http://www.dsprelated.com/showmessage/10183/1.php
http://www.lartmaker.nl/projects/fft-arm/

ORC: the Oil Runtime Compiler

Es un lenguaje que permite aprovechar los registros multmedia de los procesadores modernos. Es como escribir en un ensamblador portable. Esa portabilidad es interesante porque permite aprovechar el DSP que existen en algunos procesadores ARM (TI c64x+ DSP) y también los registros NEON (unidad de coma flotante en algunos procesadores ARM).

Sería interesante generar un filtro FIR para gstreamer usando ORC.

Salvo que se diga otra cosa, el contenido de esta obra está bajo la licencia: Creative Commons Reconocimiento NoComercial CompartirIgual 2.5 España.