Índice:
- Etapa 1: Instalando a Biblioteca
- Etapa 2: Transformada de Fourier e conceitos FFT
- Etapa 3: Simulando um sinal
- Etapa 4: Análise de um sinal simulado - codificação
- Etapa 5: Análise de um sinal simulado - Resultados
- Etapa 6: Análise de um Sinal Real - Fiação do ADC
- Etapa 7: Análise de um Sinal Real - Codificação
- Etapa 8: Análise de um Sinal Real - Resultados
- Etapa 9: o que dizer de um sinal sinusoidal cortado?
2024 Autor: John Day | [email protected]. Última modificação: 2024-01-30 11:36
Este tutorial relativamente fácil (considerando a complexidade deste assunto) mostrará como você pode fazer um analisador de espectro de 1024 amostras muito simples usando uma placa do tipo Arduino (1284 Narrow) e o plotter serial. Qualquer tipo de placa compatível com Arduino serve, mas quanto mais RAM ela tiver, melhor resolução de frequência você terá. Será necessário mais de 8 KB de RAM para calcular o FFT com 1024 amostras.
A análise de espectro é usada para determinar os principais componentes de frequência de um sinal. Muitos sons (como aqueles produzidos por um instrumento musical) são compostos por uma frequência fundamental e alguns harmônicos que possuem uma frequência que é um múltiplo inteiro da frequência fundamental. O analisador de espectro mostrará todos esses componentes espectrais.
Você pode querer usar esta configuração como um contador de frequência ou para verificar qualquer tipo de sinal que você suspeita que esteja trazendo algum ruído em seu circuito eletrônico.
Vamos nos concentrar aqui na parte do software. Se quiser fazer um circuito permanente para uma aplicação específica, você precisará amplificar e filtrar o sinal. Este pré-condicionamento é totalmente dependente do sinal que você deseja estudar, dependendo de sua amplitude, impedância, frequência máxima etc … Você pode verificar
Etapa 1: Instalando a Biblioteca
Estaremos usando a biblioteca ArduinoFFT escrita por Enrique Condes. Como queremos poupar RAM o máximo possível, usaremos o branch de desenvolvimento deste repositório que permite usar o tipo de dados float (em vez de double) para armazenar os dados amostrados e calculados. Portanto, temos que instalá-lo manualmente. Não se preocupe, basta fazer o download do arquivo e descompactá-lo na pasta da biblioteca do Arduino (por exemplo, na configuração padrão do Windows 10: C: / Users / _your_user_name_ / Documents / Arduino / libraries)
Você pode verificar se a biblioteca está instalada corretamente compilando um dos exemplos fornecidos, como "FFT_01.ino".
Etapa 2: Transformada de Fourier e conceitos FFT
Aviso: se você não aguenta ver nenhuma notação matemática, pode pular para a Etapa 3. De qualquer forma, se você não entender tudo, considere a conclusão no final da seção.
O espectro de frequência é obtido por meio de um algoritmo de Transformada Rápida de Fourier. FFT é uma implementação digital que se aproxima do conceito matemático da Transformada de Fourier. Sob este conceito, uma vez que você obtenha a evolução de um sinal seguindo um eixo do tempo, você pode saber sua representação em um domínio de frequência, composto de valores complexos (reais + imaginários). O conceito é recíproco, portanto, quando você conhece a representação no domínio da frequência, pode transformá-la de volta no domínio do tempo e obter o sinal de volta exatamente como antes da transformação.
Mas o que vamos fazer com esse conjunto de valores complexos computados no domínio do tempo? Bem, a maior parte será deixada para os engenheiros. Para nós, chamaremos outro algoritmo que transformará esses valores complexos em dados de densidade espectral: ou seja, um valor de magnitude (= intensidade) associado a cada banda de frequência. O número da banda de frequência será igual ao número de amostras.
Você certamente está familiarizado com o conceito de equalizador, como este Back to the 1980s With the Graphic EQ. Bem, obteremos o mesmo tipo de resultados, mas com 1024 bandas em vez de 16 e muito mais resolução de intensidade. Quando o equalizador dá uma visão global da música, a análise espectral fina permite calcular com precisão a intensidade de cada uma das 1024 bandas.
Um conceito perfeito, mas:
- Como a FFT é uma versão digitalizada da transformada de Fourier, ela se aproxima do sinal digital e perde algumas informações. Então, estritamente falando, o resultado da FFT se transformado de volta com um algoritmo FFT invertido não daria exatamente o sinal original.
- Além disso, a teoria considera um sinal que não é finito, mas que é um sinal constante e duradouro. Uma vez que iremos digitalizá-lo apenas por um determinado período de tempo (ou seja, amostras), mais alguns erros serão introduzidos.
-
Finalmente, a resolução da conversão analógica para digital terá impacto na qualidade dos valores calculados.
Na prática
1) A frequência de amostragem (notado fs)
Vamos amostrar um sinal, ou seja, medir sua amplitude, a cada 1 / fs segundos. fs é a frequência de amostragem. Por exemplo, se amostrarmos a 8 KHz, o ADC (conversor analógico para digital) que está integrado no chip fornecerá uma medição a cada 1/8000 de segundos.
2) O número de amostras (observado N ou amostras no código)
Como precisamos obter todos os valores antes de executar a FFT, teremos que armazená-los e, portanto, limitaremos o número de amostras. O algoritmo FFT precisa de um número de amostras que é uma potência de 2. Quanto mais amostras tivermos, melhor, mas é preciso muita memória, tanto mais que também precisaremos armazenar os dados transformados, que são valores complexos. A biblioteca Arduino FFT economiza algum espaço usando
- Uma matriz chamada "vReal" para armazenar os dados de amostra e, em seguida, a parte real dos dados transformados
- Uma matriz chamada "vImag" para armazenar a parte imaginária dos dados transformados
A quantidade necessária de RAM é igual a 2 (matrizes) * 32 (bits) * N (amostras).
Portanto, em nosso Atmega1284 que tem ótimos 16 KB de RAM, armazenaremos no máximo N = 16000 * 8/64 = 2.000 valores. Como o número de valores deve ser uma potência de 2, armazenaremos no máximo 1024 valores.
3) A resolução de frequência
O FFT calculará os valores para tantas bandas de frequência quanto o número de amostras. Essas bandas vão de 0 HZ à frequência de amostragem (fs). Portanto, a resolução de frequência é:
Fresolution = fs / N
A resolução é melhor quando menor. Portanto, para uma melhor resolução (menor), queremos:
- mais amostras e / ou
- um fs mais baixo
Mas…
4) Fs mínimo
Como queremos ver muitas frequências, algumas delas muito mais altas do que a "frequência fundamental", não podemos definir fs muito baixo. Na verdade, existe o teorema de amostragem de Nyquist-Shannon que nos força a ter uma frequência de amostragem bem acima de duas vezes a frequência máxima que gostaríamos de testar.
Por exemplo, se quisermos analisar todo o espectro de 0 Hz a, digamos, 15 KHz, que é aproximadamente a frequência máxima que a maioria dos humanos pode ouvir distintamente, temos que definir a frequência de amostragem em 30 KHz. Na verdade, os eletrônicos costumam definir em 2,5 (ou mesmo 2,52) * a frequência máxima. Neste exemplo, seria 2,5 * 15 KHz = 37,5 KHz. As frequências de amostragem usuais em áudio profissional são 44,1 KHz (gravação de CD de áudio), 48 KHz e mais.
Conclusão:
Os pontos 1 a 4 levam a: queremos usar o máximo de amostras possível. Em nosso caso, com um dispositivo de 16 KB de RAM, consideraremos 1.024 amostras. Queremos amostrar com a frequência de amostragem mais baixa possível, contanto que seja alta o suficiente para analisar a frequência mais alta que esperamos em nosso sinal (2,5 * esta frequência, pelo menos).
Etapa 3: Simulando um sinal
Para a nossa primeira tentativa, iremos modificar ligeiramente o exemplo TFT_01.ino dado na biblioteca, para analisar um sinal composto por
- A frequência fundamental, definida para 440 Hz (musical A)
- 3º harmônico na metade da potência do fundamental ("-3 dB")
- 5º harmônico a 1/4 da potência do fundamental ("-6 dB)
Você pode ver na imagem acima o sinal resultante. Na verdade, ele se parece muito com um sinal real que às vezes pode ser visto em um osciloscópio (eu o chamaria de "Batman") em uma situação em que há um corte de um sinal senoidal.
Etapa 4: Análise de um sinal simulado - codificação
0) Incluir a biblioteca
#include "arduinoFFT.h"
1. Definições
Nas seções de declarações, temos
const byte adcPin = 0; // A0
amostras const uint16_t = 1024; // Este valor SEMPRE DEVE ser uma potência de 2 const uint16_t samplingFrequency = 8000; // Afetará o valor máximo do temporizador em timer_setup () SYSCLOCK / 8 / samplingFrequency deve ser um inteiro
Uma vez que o sinal tem um 5º harmônico (frequência deste harmônico = 5 * 440 = 2200 Hz), precisamos definir a frequência de amostragem acima de 2,5 * 2200 = 5500 Hz. Aqui eu escolhi 8000 Hz.
Também declaramos as matrizes onde armazenaremos os dados brutos e computados
float vReal [amostras];
float vImag [amostras];
2) Instanciação
Criamos um objeto ArduinoFFT. A versão dev do ArduinoFFT usa um modelo para que possamos usar o tipo de dados float ou double. Float (32 bits) é suficiente no que diz respeito à precisão geral do nosso programa.
ArduinoFFT FFT = ArduinoFFT (vReal, vImag, samples, samplingFrequency);
3) Simular o sinal preenchendo o array vReal, em vez de preenchê-lo com valores ADC.
No início do Loop, preenchemos o array vReal com:
ciclos flutuantes = (((amostras) * signalFrequency) / samplingFrequency); // Número de ciclos de sinal que a amostragem irá ler
for (uint16_t i = 0; i <amostras; i ++) {vReal = float ((amplitude * (sin ((i * (TWO_PI * ciclos))) / amostras)))); / * Construir dados com positivo e valores negativos * / vReal + = float ((amplitude * (sin ((3 * i * (TWO_PI * ciclos)) / amostras))) / 2.0); / * Construir dados com valores positivos e negativos * / vReal + = float ((amplitude * (sin ((5 * i * (TWO_PI * ciclos)) / amostras))) / 4,0); / * Construir dados com valores positivos e negativos * / vImag = 0,0; // A parte imaginária deve ser zerada em caso de loop para evitar cálculos errados e estouros}
Adicionamos uma digitalização da onda fundamental e os dois harmônicos com menos amplitude. Em seguida, inicializamos a matriz imaginária com zeros. Uma vez que esta matriz é preenchida pelo algoritmo FFT, precisamos limpá-la novamente antes de cada novo cálculo.
4) Computação FFT
Em seguida, calculamos a FFT e a densidade espectral
FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward);
FFT.compute (FFTDirection:: Forward); / * Compute FFT * / FFT.complexToMagnitude (); / * Calcular magnitudes * /
A operação FFT.windowing (…) modifica os dados brutos porque executamos a FFT em um número limitado de amostras. A primeira e a última amostra apresentam uma descontinuidade (não há "nada" de um lado). Esta é uma fonte de erro. A operação de "janelamento" tende a reduzir esse erro.
FFT.compute (…) com a direção "Forward" calcula a transformação do domínio do tempo para o domínio da frequência.
Em seguida, calculamos os valores de magnitude (ou seja, intensidade) para cada uma das bandas de frequência. O array vReal agora é preenchido com valores de magnitudes.
5) Desenho de plotter serial
Vamos imprimir os valores na plotadora serial chamando a função printVector (…)
PrintVector (vReal, (amostras >> 1), SCL_FREQUENCY);
Esta é uma função genérica que permite imprimir dados com um eixo de tempo ou um eixo de frequência.
Também imprimimos a frequência da banda que tem o maior valor de magnitude
float x = FFT.majorPeak ();
Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");
Etapa 5: Análise de um sinal simulado - Resultados
Vemos 3 picos correspondentes à frequência fundamental (f0), o 3º e o 5º harmônicos, com metade e 1/4 da magnitude de f0, como esperado. Podemos ler no topo da janela f0 = 440,430114 Hz. Este valor não é exatamente 440 Hz, por todas as razões explicadas acima, mas está muito próximo do valor real. Não era realmente necessário mostrar tantos decimais insignificantes.
Etapa 6: Análise de um Sinal Real - Fiação do ADC
Como sabemos como proceder na teoria, gostaríamos de analisar um sinal real.
A fiação é muito simples. Conecte os aterramentos e a linha de sinal ao pino A0 de sua placa por meio de um resistor em série com um valor de 1 KOhm a 10 KOhm.
Este resistor em série protegerá a entrada analógica e evitará o toque. Deve ser o mais alto possível para evitar toques e o mais baixo possível para fornecer corrente suficiente para carregar o ADC rapidamente. Consulte a folha de dados MCU para saber a impedância esperada do sinal conectado na entrada ADC.
Para esta demonstração eu usei um gerador de função para alimentar um sinal senoidal de frequência 440 Hz e amplitude em torno de 5 volts (é melhor se a amplitude estiver entre 3 e 5 volts para que o ADC seja usado quase em escala total), através de um resistor de 1,2 KOhm.
Etapa 7: Análise de um Sinal Real - Codificação
0) Incluir a biblioteca
#include "arduinoFFT.h"
1) Declarações e instanciação
Na seção de declaração definimos a entrada ADC (A0), o número de amostras e a frequência de amostragem, como no exemplo anterior.
const byte adcPin = 0; // A0
amostras const uint16_t = 1024; // Este valor SEMPRE DEVE ser uma potência de 2 const uint16_t samplingFrequency = 8000; // Afetará o valor máximo do temporizador em timer_setup () SYSCLOCK / 8 / samplingFrequency deve ser um inteiro
Criamos o objeto ArduinoFFT
ArduinoFFT FFT = ArduinoFFT (vReal, vImag, samples, samplingFrequency);
2) Configuração do temporizador e ADC
Ajustamos o temporizador 1 para que ele faça um ciclo na frequência de amostragem (8 KHz) e aumente uma interrupção na comparação de saída.
void timer_setup () {
// redefine o Timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, prescaler de 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000/8) / samplingFrequency) -1; }
E definir o ADC para que
- Usa A0 como entrada
- Aciona automaticamente em cada saída do temporizador 1, compara correspondência B
- Gera uma interrupção quando a conversão é concluída
O relógio ADC é ajustado para 1 MHz, pré-escalando o relógio do sistema (16 MHz) em 16. Como cada conversão leva aproximadamente 13 relógios em escala completa, as conversões podem ser obtidas a uma frequência de 1/13 = 0,076 MHz = 76 KHz. A frequência de amostragem deve ser significativamente inferior a 76 KHz para permitir que o ADC tenha tempo para amostrar os dados. (escolhemos fs = 8 KHz).
void adc_setup () {
ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // liga o ADC, deseja interrupção na conclusão ADCSRA | = bit (ADPS2); // Prescaler de 16 ADMUX = bit (REFS0) | (adcPin & 7); // configurando a entrada ADC ADCSRB = bit (ADTS0) | bit (ADTS2); // Timer / Contador1 Compare a origem do acionador da Correspondência B ADCSRA | = bit (ADATE); // liga o acionamento automático}
Declaramos o manipulador de interrupção que será chamado após cada conversão ADC para armazenar os dados convertidos no array vReal e limpar a interrupção
// ADC completo ISR
ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == samples) {ADCSRA = 0; // desliga ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);
Você pode ter uma explicação exaustiva sobre a conversão ADC no Arduino (analogRead).
3) Configuração
Na função de configuração, limpamos a tabela de dados imaginários e chamamos as funções de configuração do temporizador e ADC
zeroI (); // uma função que define como 0 todos os dados imaginários - explicado na seção anterior
timer_setup (); adc_setup ();
3) Loop
FFT.dcRemoval (); // Remova o componente DC deste sinal, uma vez que o ADC é referenciado ao aterramento
FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward); // Pesar dados FFT.compute (FFTDirection:: Forward); // Computa FFT FFT.complexToMagnitude (); // Calcula magnitudes // imprimindo o espectro e a frequência fundamental f0 PrintVector (vReal, (samples >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");
Removemos o componente DC porque o ADC é referenciado ao aterramento e o sinal está centrado em torno de 2,5 volts aproximadamente.
Em seguida, calculamos os dados conforme explicado no exemplo anterior.
Etapa 8: Análise de um Sinal Real - Resultados
Na verdade, vemos apenas uma frequência neste sinal simples. A frequência fundamental calculada é 440,118194 Hz. Aqui, novamente, o valor é uma aproximação muito próxima da frequência real.
Etapa 9: o que dizer de um sinal sinusoidal cortado?
Agora vamos sobrecarregar um pouco o ADC, aumentando a amplitude do sinal acima de 5 volts, para que seja cortado. Não force demais para não destruir a entrada do ADC!
Podemos ver alguns harmônicos aparecendo. O corte do sinal cria componentes de alta frequência.
Você viu os fundamentos da análise FFT em uma placa Arduino. Agora você pode tentar alterar a frequência de amostragem, o número de amostras e o parâmetro de janela. A biblioteca também adiciona alguns parâmetros para calcular a FFT mais rápido com menos precisão. Você notará que se definir a frequência de amostragem muito baixa, as magnitudes calculadas parecerão totalmente errôneas por causa do dobramento espectral.
Recomendado:
Como fazer um analisador de espectro de áudio LED: 7 etapas (com fotos)
Como fazer um LED Audio Spectrum Analyzer: O LED Audio Spectrum Analyzer gera um belo padrão de iluminação de acordo com a intensidade da música. Existem muitos kits DIY LED Music Spectrum disponíveis no mercado, mas aqui vamos fazer um LED Audio Spectrum Analisador usando NeoPixe
Analisador de espectro acrílico superdimensionado: 7 etapas (com imagens)
Analisador de espectro acrílico superdimensionado: por que você iria querer olhar para aqueles minúsculos monitores de LED ou LCDs se você pode fazer isso grande? Esta é uma descrição passo a passo de como construir seu próprio analisador de espectro gigante. Usando ladrilhos de acrílico e tiras de led para construir uma sala enchendo a luz
Analisador de espectro de áudio FFT DIY: 3 etapas
DIY FFT Audio Spectrum Analyzer: O analisador de espectro FFT é um equipamento de teste que usa análise de Fourier e técnicas de processamento de sinal digital para fornecer análise de espectro. Usando a análise de Fourier, é possível que um valor, por exemplo, no domínio do tempo contínuo seja convertido
Analisador de espectro de 10 bandas: 11 etapas
Analisador de espectro 10 Band Led: Boa tarde, queridos espectadores e leitores. Hoje eu quero mostrar a vocês o guia de montagem completo para o analisador de espectro de LED de 10 bandas
Fonte Dançante: Arduino com analisador de espectro MSGEQ7: 8 etapas
Dancing Fountain: Arduino com MSGEQ7 Spectrum Analyzer: A recepção de um sinal de áudio e sua conversão em reação visual ou mecânica é muito interessante. Neste projeto, devemos usar um Arduino Mega para ser conectado a um analisador de espectro MSGEQ7 que pega o sinal de áudio de entrada e executa a banda