Cómo implementar filtro de paso bajo usando java

Estoy tratando de implementar un filtro de paso bajo en Java. Mi requisito es muy simple, tengo que eliminar las señales más allá de una frecuencia particular (dimensión única). Parece que el filtro Butterworth se adaptaría a mi necesidad.

Ahora lo importante es que el tiempo de CPU debe ser lo más bajo posible. Habría cerca de un millón de muestras que el filtro tendría que procesar y a nuestros usuarios no les gustaría esperar demasiado. ¿Hay alguna implementación lista de filtros Butterworth que tenga algoritmos óptimos para el filtrado?

Tengo una página que describe un filtro de paso bajo de CPU muy simple y muy bajo que también puede ser independiente de la frecuencia de cuadros. Lo uso para alisar la entrada del usuario y también para graficar frecuencias de cuadros a menudo.

http://phrogz.net/js/framerate-independent-low-pass-filter.html

En resumen, en su ciclo de actualización:

// If you have a fixed frame rate smoothedValue += (newValue - smoothedValue) / smoothing // If you have a varying frame rate smoothedValue += timeSinceLastUpdate * (newValue - smoothedValue) / smoothing 

Un valor de smoothing de 1 no provoca suavizado, mientras que los valores más altos suavizan cada vez más el resultado.

La página tiene un par de funciones escritas en JavaScript, pero la fórmula es independiente del idioma.

Aquí hay un filtro de paso bajo que usa una transformada de Fourier en la biblioteca matemática de Apache.

  public double[] fourierLowPassFilter(double[] data, double lowPass, double frequency){ //data: input data, must be spaced equally in time. //lowPass: The cutoff frequency at which //frequency: The frequency of the input data. //The apache Fft (Fast Fourier Transform) accepts arrays that are powers of 2. int minPowerOf2 = 1; while(minPowerOf2 < data.length) minPowerOf2 = 2 * minPowerOf2; //pad with zeros double[] padded = new double[minPowerOf2]; for(int i = 0; i < data.length; i++) padded[i] = data[i]; FastFourierTransformer transformer = new FastFourierTransformer(DftNormalization.STANDARD); Complex[] fourierTransform = transformer.transform(padded, TransformType.FORWARD); //build the frequency domain array double[] frequencyDomain = new double[fourierTransform.length]; for(int i = 0; i < frequencyDomain.length; i++) frequencyDomain[i] = frequency * i / (double)fourierTransform.length; //build the classifier array, 2s are kept and 0s do not pass the filter double[] keepPoints = new double[frequencyDomain.length]; keepPoints[0] = 1; for(int i = 1; i < frequencyDomain.length; i++){ if(frequencyDomain[i] < lowPass) keepPoints[i] = 2; else keepPoints[i] = 0; } //filter the fft for(int i = 0; i < fourierTransform.length; i++) fourierTransform[i] = fourierTransform[i].multiply((double)keepPoints[i]); //invert back to time domain Complex[] reverseFourier = transformer.transform(fourierTransform, TransformType.INVERSE); //get the real part of the reverse double[] result = new double[data.length]; for(int i = 0; i< result.length; i++){ result[i] = reverseFourier[i].getReal(); } return result; } 

Recientemente diseñé una función simple de butterworth ( http://baumdevblog.blogspot.com/2010/11/butterworth-lowpass-filter-coefficients.html ). Son fáciles de codificar en Java y deberían ser lo suficientemente rápidos si me preguntas (solo tendrías que cambiar el filtro (muestras dobles *, recuento int) para filtrar (muestras dobles [], recuento int), supongo).

El problema con JNI es que cuesta independencia de la plataforma, puede confundir el comstackdor del punto de acceso y las llamadas al método JNI dentro de su código pueden desacelerar aún más. Así que recomendaría probar Java y ver si es lo suficientemente rápido.

En algunos casos, puede ser beneficioso usar primero una transformada de Fourier rápida y aplicar el filtrado en el dominio de la frecuencia, pero dudo que sea más rápido que aproximadamente 6 multiplicaciones y algunas adiciones por muestra para un filtro de paso bajo simple.

El diseño del filtro es un arte de compensaciones, y para hacerlo bien, debe tener en cuenta algunos detalles.

¿Cuál es la frecuencia máxima que se debe pasar “sin mucha atención” y cuál es el valor máximo de “sin mucho”?

¿Cuál es la frecuencia mínima que debe atenuarse “mucho” y cuál es el valor mínimo de “un lote”?

¿Cuánta ondulación (es decir, variación en la atenuación) es aceptable dentro de las frecuencias que se supone que debe pasar el filtro?

Usted tiene una amplia gama de opciones, que le costará una variedad de cantidades de computación. Un progtwig como Matlab o Scilab puede ayudarlo a comparar las compensaciones . Querrá familiarizarse con conceptos como express frecuencias como una fracción decimal de una frecuencia de muestreo e intercambiar entre medidas de atenuación lineales y logarítmicas (dB).

Por ejemplo, un filtro de paso bajo “perfecto” es rectangular en el dominio de la frecuencia. Expresado en el dominio del tiempo como una respuesta de impulso, esa sería una función sinc (sin x / x) con las colas alcanzando tanto el infinito positivo como el negativo. Obviamente no se puede calcular eso, por lo que la pregunta es si se aproxima la función sinc a una duración finita que se puede calcular, ¿cuánto degrada su filtro?

Alternativamente, si quiere un filtro de respuesta de impulso finito que es muy barato de calcular, puede usar un “box car” o filtro rectangular donde todos los coeficientes son 1. (Esto puede hacerse incluso más barato si lo implementa como un filtro CIC explotando el desbordamiento binario para hacer acumuladores ‘circulares’, ya que de todos modos tomarás la derivada más adelante). Pero un filtro que es rectangular en el tiempo parece una función sinc en frecuencia: tiene un deslizamiento sen x / x en la banda de paso (a menudo elevado a cierta potencia ya que normalmente tendría una versión de múltiples etapas), y un poco de “rebote” en la banda de detención. Aún así, en algunos casos, es útil, ya sea solo o seguido de otro tipo de filtro.

Como dijo Mark Peters en su comentario: un filtro que necesita filtrar mucho debe escribirse en C o C ++. Pero aún puedes hacer uso de Java. Solo eche un vistazo a Java Native Interface (JNI) . Debido a las comstackciones C / C ++ del código máquina nativo, se ejecutará mucho más rápido que ejecutar su bytecode en la Máquina Virtual Java (JVM), que de hecho es un procesador virtual que traduce el bytecode a la máquina local en su código nativo (dependiendo en las instrucciones de la CPU establecidas como x86, x64, ARM , ….)

Adopté esto de http://www.dspguide.com/ Soy bastante nuevo en Java, por lo que no es bonito, pero funciona

 /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package SoundCruncher; import java.util.ArrayList; /** * * @author 2sloth * filter routine from "The scientist and engineer's guide to DSP" Chapter 20 * filterOrder can be any even number between 2 & 20 * cutoffFreq must be smaller than half the samplerate * filterType: 0=lowPass 1=highPass * ripplePercent is amount of ripple in Chebyshev filter (0-29) (0=butterworth) */ public class Filtering { double[] filterSignal(ArrayList signal, double sampleRate ,double cutoffFreq, double filterOrder, int filterType, double ripplePercent) { double[][] recursionCoefficients = new double[22][2]; // Generate double array for ease of coding double[] unfilteredSignal = new double[signal.size()]; for (int i=0; i