Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

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

Componentes y suministros

Arduino Nano R3
× 1

Aplicaciones y servicios en línea

Arduino IDE

Acerca de este proyecto

La medición de la frecuencia de la señal capturada puede ser una tarea difícil, especialmente en Arduino, ya que tiene una potencia computacional menor. 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 un 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 pasar directamente al paso 3.

Si necesita realizar FFT con alta velocidad (3x) con un pequeño compromiso en la precisión (alrededor del 5%), consulte mi otro artículo sobre ApproxFFT.

https://create.arduino.cc/projecthub/abhilashpatel121/approxfft-fastest-fft-function-for-arduino-fd4917?ref=user&ref_id=1593632&offset=0

Paso 1: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. La DFT típica toma N * N multiplicaciones complejas para obtener resultados, mientras que FFT solo toma N * logN. esto es una ventaja significativa cuando los números de muestra son altos.

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

1. https://flylib.com/books/en/2.729.1/derivation_of _...

2. https://jakevdp.github.io/blog/2013/08/28/understa ...

3. https://cnx.org/contents/[email protected]:zmcmahhR @ 7 / D ...

4. https://en.wikipedia.org/wiki/Fast_Fourier_transfo ...

Paso 2: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 usar números de almacenamiento como flotante y podemos almacenarlo como un byte que ocupa 1/4 de espacio en Arduino. El sine_data [] debe pegarse en la parte superior del código para declararlo como una variable global.

Además 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 al 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 3: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, etc. 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 [i] <=a) {o =i;}} int in_ps [data [o]] ={}; // entrada para secuenciar flotar out_r [data [o]] ={}; // parte real de transformfloat 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. Introduzca los datos ordenados según el orden generado,

3. FFT realizada

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 4:prueba del 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 la onda en sí es de 1,25 Hz.

Como se puede mostrar a partir de la salida sin procesar, el valor coincide con la FFT calculada por Scilab. sin embargo, estos valores no son exactamente iguales a los de la 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:4 ms
  • 32 puntos:10 ms
  • 64 puntos:26 ms
  • 128 puntos:53 ms

Paso 5: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. Al usar 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.

Código

  • EasyFFT
EasyFFT Arduino
Este código realiza FFT y actualiza la matriz F_peasks con las 5 frecuencias más dominantes.
 / * // Datos de ejemplo:int data [64] ={14, 30, 35, 34, 34, 40, 46, 45, 30 , 4, -26, -48, -55, -49, -37, -28, -24, -22, -13, 6, 32, 55, 65, 57, 38, 17, 1, -6, - 11, -19, -34, -51, -61, -56, -35, -7, 18, 32, 35, 34, 35, 41, 46, 43, 26, -2, -31, -50, -55, -47, -35, -27, -24, -21, -10, 11, 37, 58, 64, 55, 34, 13, -1, -7}; * /// ---- -------------------------------------------------- --------------------- // 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, // Pegue esto en la parte superior del programa 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]; // top 5 frecuencias picos en orden descendente // --------------------------------------- ------------------------------------ // configuración vacía () {Serial.begin (250000); } bucle vacío () {/ * // ejemploFFT (datos, 64,100); // para obtener los cinco primeros valores de las frecuencias de X con 64 muestras a 100 Hz de muestreoSerial.println (f_peaks [0]); Serial.println (f_peaks [1]); delay (99999); * // * después de fallar por encima de FFT ( ), frecuencias disponibles en f_peaks [0], f_peaks [1], f_peaks [2], f_peaks [3], f_peaks [4], * /} // --------------- -------------- Función FFT ---------------------------------- ------------ // float FFT (int en [], int N, float Frequency) {/ * Código para realizar FFT en arduino, configuración:pegar sine_data [91] en la parte superior del programa [ variable global], pegue la función FFT al final del programa Término:1. en []:matriz de datos, 2. N:número de muestra (tamaño de muestra recomendado 2,4,8,16,32,64,128 ...) 3. Frecuencia:frecuencia de muestreo requerida como entrada (Hz) Si el tamaño de la muestra no está en potencia de 2, se recortará al lado inferior del número. es decir, para 150 muestras, el código considerará las primeras 128 muestras, la muestra restante se omitirá.Para Arduino nano, no es posible realizar una FFT de más de 128 muestras debido a una limitación importante (se recomiendan 64). problema, Código de ABHILASH Contacto:[email protected] Documentación:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:cambie el tipo de datos de N de float a int para> =256 muestras * / 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 [i] <=a) {o =i;}} int in_ps [data [o]] ={}; // entrada para secuenciar flotar out_r [data [o]] ={}; // parte real de transformfloat out_im [data [o]] ={}; // parte imaginaria de la transformación x =0; for (int b =0; b  a) {out_r [i] =in [in_ps [i] -a];}} int i10, i11, n1; float e, c, s, tr, ti; for (int i =0; i  aquí en adelante out_r contiene amplitud y our_in contiene frecuencia (Hz) para (int i =0; i  out_r [i-1] &&out_r [i]> out_r [i + 1] ) {in_ps [x] =i; // matriz in_ps utilizada para el almacenamiento del número de pico x =x + 1;}} s =0; c =0; for (int i =0; i  360) {j =j-360;} if (j> -1 &&j <91) {out =sine_data [j];} si no (j> 90 &&j <181) {out =sine_data [180-j];} else if (j> 180 &&j <271) {out =-sine_data [j-180];} else if (j> 270 &&j <361) {out =-sine_data [360-j];} return (out / 255);} float coseno (int i) {int j =i; flotar; while (j <0) {j =j + 360;} while (j> 360) {j =j-360;} if (j> -1 &&j <91) {out =sine_data [90-j];} else if (j> 90 &&j <181) {out =-sine_data [j-90];} else if (j> 180 &&j <271) {out =-sine_data [270-j];} else if (j> 270 &&j <361) {out =sine_data [j-270];} return (out / 255);} // ---------------------- -------------------------------------------------- ------------ // 

Esquemas


Proceso de manufactura

  1. ¿Qué es la transformada de Fourier?
  2. Decodificador DTMF usando solo Arduino
  3. Sistema de alarma Arduino:SERENA
  4. Python3 y comunicación Arduino
  5. Monitoreo SMART de temperatura para escuelas
  6. Biblioteca de puertos IO de 8 bits para Arduino
  7. Matriz de teclado de prototipos de 64 teclas para Arduino
  8. TFT Shield para Arduino Nano - Iniciar
  9. Una entrada analógica aislada para Arduino
  10. Robot para navegación interior supercogedora
  11. ¿Cuál es el código HS para bomba hidráulica?