Tabla de contenido:
- Paso 1: instalar la biblioteca
- Paso 2: Transformada de Fourier y conceptos de FFT
- Paso 3: simulación de una señal
- Paso 4: Análisis de una señal simulada: codificación
- Paso 5: Análisis de una señal simulada - Resultados
- Paso 6: Análisis de una señal real: cableado del ADC
- Paso 7: análisis de una señal real: codificación
- Paso 8: Análisis de una señal real - Resultados
- Paso 9: ¿Qué pasa con una señal sinusoidal recortada?
Video: Analizador de espectro FFT de 1024 muestras con un Atmega1284: 9 pasos
2024 Autor: John Day | [email protected]. Última modificación: 2024-01-30 08:41
Este tutorial relativamente fácil (considerando la complejidad de este tema) le mostrará cómo puede hacer un analizador de espectro de 1024 muestras muy simple usando una placa tipo Arduino (1284 Narrow) y el trazador serial. Cualquier tipo de placa compatible con Arduino servirá, pero cuanta más RAM tenga, mejor resolución de frecuencia obtendrá. Necesitará más de 8 KB de RAM para calcular la FFT con 1024 muestras.
El análisis de espectro se utiliza para determinar los principales componentes de frecuencia de una señal. Muchos sonidos (como los producidos por un instrumento musical) se componen de una frecuencia fundamental y algunos armónicos que tienen una frecuencia que es un múltiplo entero de la frecuencia fundamental. El analizador de espectro le mostrará todos estos componentes espectrales.
Es posible que desee utilizar esta configuración como un contador de frecuencia o para verificar cualquier tipo de señal que sospeche que está generando algo de ruido en su circuito electrónico.
Nos centraremos aquí en la parte del software. Si desea hacer un circuito permanente para una aplicación específica, necesitará amplificar y filtrar la señal. Este preacondicionamiento es totalmente dependiente de la señal que se quiera estudiar, dependiendo de su amplitud, impedancia, frecuencia máxima etc… Puede consultar
Paso 1: instalar la biblioteca
Usaremos la biblioteca ArduinoFFT escrita por Enrique Condes. Como queremos ahorrar RAM tanto como sea posible, usaremos la rama de desarrollo de este repositorio que permite usar el tipo de datos flotante (en lugar de doble) para almacenar los datos muestreados y calculados. Entonces tenemos que instalarlo manualmente. No se preocupe, simplemente descargue el archivo y descomprímalo en la carpeta de la biblioteca de Arduino (por ejemplo, en la configuración predeterminada de Windows 10: C: / Users / _your_user_name_ / Documents / Arduino / libraries)
Puede comprobar que la biblioteca está instalada correctamente compilando uno de los ejemplos proporcionados, como "FFT_01.ino".
Paso 2: Transformada de Fourier y conceptos de FFT
Advertencia: si no puede soportar ver ninguna notación matemática, puede pasar al Paso 3. De todos modos, si no lo entiende todo, solo considere la conclusión al final de la sección.
El espectro de frecuencias se obtiene mediante un algoritmo de Transformada Rápida de Fourier. FFT es una implementación digital que se aproxima al concepto matemático de la Transformada de Fourier. Bajo este concepto una vez que se obtiene la evolución de una señal siguiendo un eje de tiempo, se puede conocer su representación en un dominio de frecuencia, compuesto por valores complejos (reales + imaginarios). El concepto es recíproco, por lo que cuando conoce la representación del dominio de frecuencia, puede transformarla de nuevo al dominio del tiempo y recuperar la señal exactamente como antes de la transformación.
Pero, ¿qué vamos a hacer con este conjunto de valores complejos calculados en el dominio del tiempo? Bueno, la mayor parte quedará en manos de los ingenieros. Para nosotros, llamaremos a otro algoritmo que transformará estos valores complejos en datos de densidad espectral: ese es un valor de magnitud (= intensidad) asociado con cada banda de frecuencia. El número de bandas de frecuencia será el mismo que el número de muestras.
Ciertamente está familiarizado con el concepto de ecualizador, como este. Regreso a la década de 1980 con el ecualizador gráfico. Bueno, obtendremos el mismo tipo de resultados pero con 1024 bandas en lugar de 16 y mucha más resolución de intensidad. Cuando el ecualizador ofrece una vista global de la música, el análisis espectral fino permite calcular con precisión la intensidad de cada una de las 1024 bandas.
Un concepto perfecto, pero:
- Dado que la FFT es una versión digitalizada de la transformada de Fourier, se aproxima a la señal digital y pierde algo de información. Entonces, estrictamente hablando, el resultado de la FFT si se vuelve a transformar con un algoritmo de FFT invertido no daría exactamente la señal original.
- También la teoría considera una señal que no es finita, pero que es una señal constante y duradera. Dado que lo digitalizaremos solo durante un cierto período de tiempo (es decir, muestras), se introducirán algunos errores más.
-
Finalmente, la resolución de la conversión de analógico a digital afectará la calidad de los valores calculados.
En la práctica
1) La frecuencia de muestreo (indicada fs)
Tomaremos muestras de una señal, es decir, mediremos su amplitud, cada 1 / fs segundos. fs es la frecuencia de muestreo. Por ejemplo, si tomamos muestras a 8 KHz, el ADC (convertidor analógico a digital) que está integrado en el chip proporcionará una medición cada 1/8000 de segundos.
2) El número de muestras (anotado N o muestras en el código)
Como necesitamos obtener todos los valores antes de ejecutar la FFT, tendremos que almacenarlos y, por lo tanto, limitaremos el número de muestras. El algoritmo FFT necesita un número de muestras que es una potencia de 2. Cuantas más muestras tengamos, mejor, pero requiere mucha memoria, tanto más que también necesitaremos almacenar los datos transformados, que son valores complejos. La biblioteca Arduino FFT ahorra algo de espacio al usar
- Un arreglo llamado "vReal" para almacenar los datos muestreados y luego la parte real de los datos transformados
- Una matriz denominada "vImag" para almacenar la parte imaginaria de los datos transformados.
La cantidad necesaria de RAM equivale a 2 (matrices) * 32 (bits) * N (muestras).
Entonces, en nuestro Atmega1284 que tiene 16 KB de RAM, almacenaremos un máximo de N = 16000 * 8/64 = 2000 valores. Dado que el número de valores debe ser una potencia de 2, almacenaremos un máximo de 1024 valores.
3) La resolución de frecuencia
La FFT calculará valores para tantas bandas de frecuencia como el número de muestras. Estas bandas abarcarán desde 0 HZ hasta la frecuencia de muestreo (fs). Por lo tanto, la resolución de frecuencia es:
Fresolution = fs / N
La resolución es mejor cuando es más baja. Entonces, para una mejor resolución (más baja), queremos:
- más muestras y / o
- una fs más baja
Pero…
4) fs mínimo
Como queremos ver muchas frecuencias, algunas de las cuales son mucho más altas que la "frecuencia fundamental", no podemos establecer fs demasiado bajas. De hecho, existe el teorema de muestreo de Nyquist-Shannon que nos obliga a tener una frecuencia de muestreo muy por encima del doble de la frecuencia máxima que nos gustaría probar.
Por ejemplo, si quisiéramos analizar todo el espectro desde 0 Hz para decir 15 KHz, que es aproximadamente la frecuencia máxima que la mayoría de los humanos pueden escuchar claramente, tenemos que establecer la frecuencia de muestreo en 30 KHz. De hecho, los electrónicos a menudo lo establecen en 2,5 (o incluso 2,52) * la frecuencia máxima. En este ejemplo, sería 2,5 * 15 KHz = 37,5 KHz. Las frecuencias de muestreo habituales en audio profesional son 44,1 KHz (grabación de CD de audio), 48 KHz y más.
Conclusión:
Los puntos 1 a 4 conducen a: queremos utilizar tantas muestras como sea posible. En nuestro caso con un dispositivo de 16 KB de RAM, consideraremos 1024 muestras. Queremos muestrear a la frecuencia de muestreo más baja posible, siempre que sea lo suficientemente alta para analizar la frecuencia más alta que esperamos en nuestra señal (2.5 * esta frecuencia, al menos).
Paso 3: simulación de una señal
Para nuestro primer intento, modificaremos ligeramente el ejemplo de TFT_01.ino dado en la biblioteca, para analizar una señal compuesta de
- La frecuencia fundamental, establecida en 440 Hz (A musical)
- 3er armónico a la mitad de la potencia de la fundamental ("-3 dB")
- 5to armónico a 1/4 de la potencia de la fundamental ("-6 dB)
Puedes ver en la imagen de arriba la señal resultante. De hecho, se parece mucho a una señal real que a veces se puede ver en un osciloscopio (yo lo llamaría "Batman") en una situación en la que hay un recorte de una señal sinusoidal.
Paso 4: Análisis de una señal simulada: codificación
0) Incluir la biblioteca
#include "arduinoFFT.h"
1. Definiciones
En las secciones de declaraciones, tenemos
const byte adcPin = 0; // A0
const uint16_t muestras = 1024; // Este valor SIEMPRE DEBE ser una potencia de 2 const uint16_t samplingFrequency = 8000; // Afectará el valor máximo del temporizador en timer_setup () SYSCLOCK / 8 / samplingFrequency debe ser un número entero
Dado que la señal tiene un quinto armónico (frecuencia de este armónico = 5 * 440 = 2200 Hz), debemos establecer la frecuencia de muestreo por encima de 2,5 * 2200 = 5500 Hz. Aquí elegí 8000 Hz.
También declaramos las matrices donde almacenaremos los datos sin procesar y calculados
flotar vReal [muestras];
flotar vImag [muestras];
2) instanciación
Creamos un objeto ArduinoFFT. La versión dev de ArduinoFFT usa una plantilla para que podamos usar el tipo de datos flotante o doble. Float (32 bits) es suficiente con respecto a la precisión general de nuestro programa.
ArduinoFFT FFT = ArduinoFFT (vReal, vImag, muestras, frecuencia de muestreo);
3) Simular la señal rellenando la matriz vReal, en lugar de rellenarla con valores ADC.
Al comienzo del bucle, llenamos la matriz vReal con:
ciclos de flotación = (((muestras) * frecuencia de señal) / frecuencia de muestreo); // Número de ciclos de señal que leerá el muestreo
for (uint16_t i = 0; i <samples; i ++) {vReal = float ((amplitude * (sin ((i * (TWO_PI * ciclos)) / samples)))); / * Construir datos con valores positivos y valores negativos * / vReal + = float ((amplitud * (sin ((3 * i * (TWO_PI * ciclos)) / samples))) / 2.0); / * Generar datos con valores positivos y negativos * / vReal + = float ((amplitude * (sin ((5 * i * (TWO_PI * ciclos)) / samples))) / 4.0); / * Generar datos con valores positivos y negativos * / vImag = 0.0; // La parte imaginaria debe ponerse a cero en caso de bucle para evitar cálculos incorrectos y desbordamientos}
Añadimos una digitalización de la onda fundamental y los dos armónicos con menor amplitud. Luego inicializamos la matriz imaginaria con ceros. Dado que esta matriz está poblada por el algoritmo FFT, necesitamos borrarla nuevamente antes de cada nuevo cálculo.
4) Computación FFT
Luego calculamos la FFT y la densidad espectral
FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Adelante);
FFT.compute (FFTDirection:: Adelante); / * Calcular FFT * / FFT.complexToMagnitude (); / * Calcular magnitudes * /
La operación FFT.windowing (…) modifica los datos sin procesar porque ejecutamos la FFT en un número limitado de muestras. La primera y la última muestra presentan una discontinuidad (no hay "nada" en uno de sus lados). Ésta es una fuente de error. La operación de "ventana" tiende a reducir este error.
FFT.compute (…) con la dirección "Adelante" calcula la transformación del dominio del tiempo al dominio de la frecuencia.
Luego calculamos los valores de magnitud (es decir, intensidad) para cada una de las bandas de frecuencia. La matriz de vReal ahora está llena de valores de magnitudes.
5) Dibujo de plotter en serie
Imprimamos los valores en el trazador serial llamando a la función printVector (…)
PrintVector (vReal, (muestras >> 1), SCL_FREQUENCY);
Esta es una función genérica que permite imprimir datos con un eje de tiempo o un eje de frecuencia.
También imprimimos la frecuencia de la banda que tiene el valor de magnitud más alto
flotar x = FFT.majorPeak ();
Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");
Paso 5: Análisis de una señal simulada - Resultados
Vemos 3 picos correspondientes a la frecuencia fundamental (f0), los armónicos 3 y 5, con la mitad y 1/4 de la magnitud f0, como se esperaba. Podemos leer en la parte superior de la ventana f0 = 440.430114 Hz. Este valor no es exactamente 440 Hz, por todas las razones explicadas anteriormente, pero está muy cerca del valor real. Realmente no era necesario mostrar tantos decimales insignificantes.
Paso 6: Análisis de una señal real: cableado del ADC
Dado que sabemos cómo proceder en teoría, nos gustaría analizar una señal real.
El cableado es muy sencillo. Conecte las tierras juntas y la línea de señal al pin A0 de su placa a través de una resistencia en serie con un valor de 1 KOhm a 10 KOhm.
Esta resistencia en serie protegerá la entrada analógica y evitará el timbre. Debe ser lo más alto posible para evitar el timbre y lo más bajo posible para proporcionar suficiente corriente para cargar el ADC rápidamente. Consulte la hoja de datos de la MCU para conocer la impedancia esperada de la señal conectada en la entrada ADC.
Para esta demostración utilicé un generador de funciones para alimentar una señal sinusoidal de frecuencia 440 Hz y amplitud alrededor de 5 voltios (es mejor si la amplitud está entre 3 y 5 voltios para que el ADC se use cerca de la escala completa), a través de una resistencia de 1.2 KOhm.
Paso 7: análisis de una señal real: codificación
0) Incluir la biblioteca
#include "arduinoFFT.h"
1) Declaraciones e instanciación
En la sección de declaración definimos la entrada ADC (A0), el número de muestras y la frecuencia de muestreo, como en el ejemplo anterior.
const byte adcPin = 0; // A0
const uint16_t muestras = 1024; // Este valor SIEMPRE DEBE ser una potencia de 2 const uint16_t samplingFrequency = 8000; // Afectará el valor máximo del temporizador en timer_setup () SYSCLOCK / 8 / samplingFrequency debe ser un número entero
Creamos el objeto ArduinoFFT
ArduinoFFT FFT = ArduinoFFT (vReal, vImag, muestras, frecuencia de muestreo);
2) Configuración del temporizador y ADC
Configuramos el temporizador 1 para que funcione en la frecuencia de muestreo (8 KHz) y genere una interrupción en la comparación de salida.
void timer_setup () {
// reiniciar el temporizador 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, preescalador de 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000/8) / frecuencia de muestreo) -1; }
Y configure el ADC para que
- Utiliza A0 como entrada
- Se dispara automáticamente en cada salida del temporizador 1 comparar coincidencias B
- Genera una interrupción cuando se completa la conversión
El reloj ADC se establece en 1 MHz, preescalando el reloj del sistema (16 MHz) en 16. Dado que cada conversión toma aproximadamente 13 relojes a escala completa, las conversiones se pueden lograr a una frecuencia de 1/13 = 0.076 MHz = 76 KHz. La frecuencia de muestreo debe ser significativamente inferior a 76 KHz para que el ADC tenga tiempo de muestrear los datos. (elegimos fs = 8 KHz).
void adc_setup () {
ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // enciende ADC, quiere interrumpir al finalizar ADCSRA | = bit (ADPS2); // Prescaler de 16 ADMUX = bit (REFS0) | (adcPin y 7); // configurando la entrada ADC ADCSRB = bit (ADTS0) | bit (ADTS2); // Temporizador / Contador1 Comparar fuente de disparo Match B ADCSRA | = bit (ADATE); // activa el disparo automático}
Declaramos el controlador de interrupciones que se llamará después de cada conversión de ADC para almacenar los datos convertidos en la matriz vReal y borrar la interrupción.
// ADC completo ISR
ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == samples) {ADCSRA = 0; // apagar ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);
Puede tener una explicación exhaustiva sobre la conversión de ADC en Arduino (analogRead).
3) Configuración
En la función de configuración, borramos la tabla de datos imaginarios y llamamos a las funciones de configuración del temporizador y del ADC
zeroI (); // una función que pone a 0 todos los datos imaginarios - explicado en la sección anterior
timer_setup (); adc_setup ();
3) bucle
FFT.dcRemoval (); // Elimine el componente de CC de esta señal ya que el ADC está referenciado a tierra
FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Adelante); // Pesar datos FFT.compute (FFTDirection:: Forward); // Calcular FFT FFT.complexToMagnitude (); // Calcular magnitudes // imprimir el espectro y la frecuencia fundamental f0 PrintVector (vReal, (samples >> 1), SCL_FREQUENCY); flotar x = FFT.majorPeak (); Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");
Eliminamos el componente de CC porque el ADC está referenciado a tierra y la señal se centra alrededor de 2,5 voltios aproximadamente.
Luego, calculamos los datos como se explica en el ejemplo anterior.
Paso 8: Análisis de una señal real - Resultados
De hecho, solo vemos una frecuencia en esta simple señal. La frecuencia fundamental calculada es 440,118194 Hz. Aquí nuevamente el valor es una aproximación muy cercana a la frecuencia real.
Paso 9: ¿Qué pasa con una señal sinusoidal recortada?
Ahora sobreexcite un poco el ADC aumentando la amplitud de la señal por encima de 5 voltios, para que quede recortada. ¡No presiones demasiado para no destruir la entrada ADC!
Podemos ver aparecer algunos armónicos. El recorte de la señal crea componentes de alta frecuencia.
Ha visto los fundamentos del análisis FFT en una placa Arduino. Ahora puede intentar cambiar la frecuencia de muestreo, el número de muestras y el parámetro de ventana. La biblioteca también agrega algunos parámetros para calcular la FFT más rápido con menos precisión. Notará que si establece la frecuencia de muestreo demasiado baja, las magnitudes calculadas aparecerán totalmente erróneas debido al plegamiento espectral.
Recomendado:
Cómo hacer un analizador de espectro de audio LED: 7 pasos (con imágenes)
Cómo hacer un analizador de espectro de audio LED: el analizador de espectro de audio LED genera el hermoso patrón de iluminación de acuerdo con la intensidad de la música.Hay muchos kits de espectro musical LED DIY disponibles en el mercado, pero aquí vamos a hacer un espectro de audio LED. Analizador con NeoPixe
Cómo hacer un analizador de espectro de música de audio LED de 32 bandas con Arduino Nano en casa #arduinoproject: 8 pasos
Cómo hacer un analizador de espectro de música de audio LED de 32 bandas usando Arduino Nano en casa #arduinoproject: hoy haremos un analizador de espectro de música de audio LED de 32 bandas en casa usando Arduino, puede mostrar el espectro de frecuencia y reproducir música al mismo tiempo. debe estar conectado frente a la resistencia de 100k, de lo contrario el ruido del altavoz
Analizador de espectro acrílico de gran tamaño: 7 pasos (con imágenes)
Analizador de espectro acrílico de gran tamaño: ¿Por qué querrías mirar esas pequeñas pantallas LED o esos LCD pequeños si puedes hacerlo a lo grande? Esta es una descripción paso a paso sobre cómo construir tu propio analizador de espectro de tamaño gigante. tiras de led para construir una habitación que llene la luz
Analizador de espectro de audio DIY FFT: 3 pasos
Analizador de espectro de audio DIY FFT: el analizador de espectro FFT es un equipo de prueba que utiliza análisis de Fourier y técnicas de procesamiento de señales digitales para proporcionar análisis de espectro. Usando el análisis de Fourier es posible que un valor en, por ejemplo, el dominio de tiempo continuo sea conver
Analizador de muestras de rocas: 4 pasos
Analizador de muestras de rocas: el analizador de muestras de rocas se utiliza para identificar y analizar los tipos de muestras de rocas mediante la técnica de vibración de martilleo suave. Es un método novedoso para identificar las muestras de rocas. Si hay un meteorito o cualquier muestra de roca desconocida, se puede estimar