Tabla de contenido:

EasyFFT: Transformada rápida de Fourier (FFT) para Arduino: 6 pasos
EasyFFT: Transformada rápida de Fourier (FFT) para Arduino: 6 pasos

Video: EasyFFT: Transformada rápida de Fourier (FFT) para Arduino: 6 pasos

Video: EasyFFT: Transformada rápida de Fourier (FFT) para Arduino: 6 pasos
Video: Implementación por software de la transformada rápida de Fourier (FFT) 2024, Septiembre
Anonim
Image
Image

La medición de la frecuencia de la señal capturada puede ser una tarea difícil, especialmente en Arduino, ya que tiene menor potencia computacional. Hay métodos disponibles para capturar el cruce por cero donde se captura la frecuencia comprobando cuántas veces la señal cruza las líneas cero dentro del tiempo dado. Es posible que este método no funcione cuando la señal es una combinación de varias frecuencias.

De alguna manera, esto es difícil de codificar si no tiene tal experiencia. Pero al ser un modificador este código puede resultar de gran utilidad para diversos proyectos relacionados con la música, el análisis de señales. El motivo de este proyecto fue preparar un código que sea fácil de implementar en Arduino sin pasar a segundo plano.

Este proyecto no explica el funcionamiento de FFT, pero explica la aplicación de la función FFT. El mismo proceso también se explica en el video adjunto.

Si solo está interesado en la aplicación del código y no en una explicación del mismo. Puede saltar directamente al paso 3.

Paso 1: Introducción a la transformación de frecuencia

Introducción a la transformación de frecuencia
Introducción a la transformación de frecuencia
Introducción a la transformación de frecuencia
Introducción a la transformación de frecuencia

Cualquier señal puede estar compuesta por una combinación de varias ondas sinusoidales. Por lo tanto, cualquier señal basada en el tiempo también se puede mostrar como una combinación de varios senos de diferentes amplitudes.

Traté de explicar el funcionamiento de DFT (transformada discreta de Fourier) en uno de los instructables anteriores (https://www.instructables.com/id/Arduino-Frequency…). Estos métodos son extremadamente lentos para cualquier aplicación en tiempo real. lo que lo hace casi inútil.

En la imagen, se muestra una señal que es una combinación de dos frecuencias f2 y f5. Esta señal se multiplica por ondas sinusoidales de prueba de valores f1 af5.

Se puede demostrar matemáticamente que la suma de la multiplicación de dos conjuntos de datos armónicos que tienen una frecuencia diferente tiende a cero (un número mayor de datos puede conducir a un resultado de rebozo). En nuestro caso, si estas dos frecuencias de multiplicación tienen la misma frecuencia (o muy cercana), esa suma de multiplicaciones es el número distinto de cero.

Entonces, si nuestra señal se multiplica por f1, la suma de la multiplicación será cero (cerca de cero para una aplicación real). similar es el caso de f3, f4. Sin embargo, para el valor, la salida de f2 y f5 no será cero, sino significativamente más alta que el resto de los valores.

Aquí una señal se prueba con 5 frecuencias, por lo que la señal debe multiplicarse por cinco frecuencias. Un cálculo tan intenso requiere más tiempo. Matemáticamente se muestra que para N número de muestras se necesitan N * N multiplicaciones complejas.

Paso 2: Transformada rápida de Fourier

Para hacer que el cálculo de DFT sea más rápido, James Cooley y John Tukey desarrollaron el algoritmo FFT. Este algoritmo también se considera como uno de los algoritmos más importantes del siglo XX. Divide una señal en una parte secuenciada par e impar, lo que reduce el número de cálculos necesarios. Al usarlo, la multiplicación compleja total requerida se puede reducir a NlogN. que es una mejora significativa.

Puede consultar las referencias a continuación a las que me referí mientras escribía el código para una comprensión detallada de las matemáticas detrás de FFT:

1.

2.

3.

4.

Paso 3: Explicación del código

1. Seno y coseno rápido:

El cálculo FFT toma el valor de varios senos y cosenos varias veces. La función incorporada de Arduino no es lo suficientemente rápida y requiere una buena cantidad de tiempo para proporcionar el valor requerido. Lo que hace que el código sea significativamente más lento (duplica el tiempo para 64 muestras). Para contrarrestar este problema, el valor de seno de 0 a 90 grados se almacena como múltiplo de 255. Al hacerlo, se eliminará la necesidad de almacenar números como flotante y podemos almacenarlo como un byte que ocupa 1/4 de espacio en Arduino. Sine_data debe pegarse en la parte superior del código para declararlo como una variable global.

Aparte de sine_data, una matriz llamada f_peaks declarada como una variable global. Después de cada ejecución de la función FFT, esta matriz se actualiza. Donde f_peaks [0] es la frecuencia más dominante y los valores adicionales en orden descendente.

byte sine_data [91] = {0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255}; float f_peaks [5];

Como hemos almacenado el valor de seno de 0 a 90 grados, se puede calcular cualquier valor de seno o coseno. A continuación, funciona la primera ronda del número hasta el punto decimal cero y devuelve el valor de los datos almacenados. este método solo necesita una división flotante. Esto se puede reducir aún más almacenando directamente valores de seno (no 255 múltiplos). pero eso consume mucha memoria en Arduino.

El uso del procedimiento anterior reduce la precisión pero mejora la velocidad. Por 64 puntos, da la ventaja de 8ms y por 128 puntos da una ventaja de 20ms.

Paso 4: Explicación del código: Función FFT

La FFT solo se puede realizar para el tamaño de muestra de 2, 4, 8, 16, 32, 64 y así sucesivamente. si el valor no es 2 ^ n, entonces tomará el lado inferior del valor. Por ejemplo, si elegimos el tamaño de muestra de 70, solo considerará las primeras 64 muestras y omitirá el resto.

Siempre se recomienda tener un tamaño de muestra de 2 ^ n. que puede ser:

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, …

Dos flotadores out_r y out_im ocuparán una gran cantidad de memoria. para Arduino nano no funcionará para muestras superiores a 128 (y en algunos casos 128) debido a la falta de memoria disponible.

unsigned int data [13] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

int a, c1, f, o, x; a = N; for (int i = 0; i <12; i ++) // calculando los niveles {if (data <= a) {o = i;}} int in_ps [data [o] = {}; // entrada para secuenciar float out_r [data [o] = {}; // parte real de transform float out_im [data [o] = {}; // parte imaginaria de la transformación

El flujo adicional es el siguiente:

1. El código genera un orden inverso de bits para el tamaño de muestra dado (detalles sobre la inversión de bits en las referencias: paso 2)

2. Datos de entrada ordenados según el orden generado, 3. FFT realizado

4. La amplitud del número complejo calculado, 5. Los picos se detectan y ordenan en orden descendente

6. Se puede acceder a los resultados desde f_peaks.

[para acceder a otros datos (además de la frecuencia pico) se debe modificar el código, de modo que la variable local se pueda copiar a alguna variable global predefinida]

Paso 5: probar el código

Probando el código
Probando el código
Probando el código
Probando el código

Se proporciona una muestra de onda triangular como entrada. para esta frecuencia de muestreo de onda es de 10 Hz y la frecuencia de onda en sí es de 1,25 Hz.

Como se puede mostrar en la salida sin procesar, el valor coincide con la FFT calculada por Scilab. sin embargo, estos valores no son exactamente iguales a los de baja precisión sino a la onda sinusoidal más rápida.

En el arreglo de frecuencia de salida, las frecuencias son 1.25 y 3.75. no es necesario obtener el valor exacto cada vez. normalmente, estos números se denominan intervalos de frecuencia. por lo que el valor de salida puede estar en cualquier lugar dentro de los contenedores especificados.

Velocidad:

para Arduino nano se necesita:

16 puntos: 4ms 32 puntos: 10ms 64 puntos: 26ms 128 puntos: 53ms

Paso 6: Conclusión

Este código FFT se puede utilizar en aplicaciones en tiempo real. Ya que se necesitan alrededor de 30 ms para completar el cálculo. Sin embargo, su resolución está limitada por una serie de muestras. El número de la muestra está limitado por la memoria Arduino. Mediante el uso de Arduino Mega u otra placa de mayor rendimiento se puede mejorar la precisión.

Si tiene alguna consulta, sugerencia o corrección, no dude en comentar.

Actualización (2/5/21)

Actualizaciones: // ----------------------------- Función FFT --------------- ------------------------------- // Float FFT (int en , int N, Float Frequency)

El tipo de datos de N cambió a Integer (Byte existente) para admitir un tamaño de muestra> 255. Si el tamaño de la muestra es <= 128, se debe utilizar el tipo de datos de bytes.

Recomendado: