EasyFFT:Fast Fourier Transform (FFT) para Arduino
Componentes e suprimentos
| × | 1 |
Aplicativos e serviços online
|
Sobre este projeto
A medição da frequência do sinal capturado pode ser uma tarefa difícil, especialmente no Arduino, pois tem menor poder computacional. Existem métodos disponíveis para capturar o cruzamento de zero, onde a frequência é capturada, verificando quantas vezes o sinal cruza as linhas de zero dentro do tempo determinado. Esse método pode não funcionar quando o sinal é uma combinação de várias frequências.
Isso é de alguma forma difícil de codificar se você não tiver esse histórico. Mas sendo um remendador, este código pode ser muito útil para vários projetos relacionados à música, análise de sinais. O motivo deste projeto foi preparar um código que seja fácil de implementar no Arduino sem entrar em seus antecedentes.
Este projeto não explica o funcionamento da FFT, mas explica a aplicação da função FFT. O mesmo processo também é explicado no vídeo anexo.
Se você está interessado apenas na aplicação do código e não em uma explicação sobre ele. Você pode pular diretamente para a etapa 3.
Se você precisa executar FFT com alta velocidade (3x) com pequeno comprometimento na precisão (cerca de 5%), consulte meu outro artigo sobre ApproxFFT.
https://create.arduino.cc/projecthub/abhilashpatel121/approxfft-fastest-fft-function-for-arduino-fd4917?ref=user&ref_id=1593632&offset=0
Etapa 1:Transformação Rápida de Fourier
Para tornar o cálculo do DFT mais rápido, o algoritmo FFT foi desenvolvido por James Cooley e John Tukey. Este algoritmo também é considerado um dos algoritmos mais importantes do século XX. Ele divide um sinal em uma parte de sequência ímpar e par, o que reduz o número de cálculos necessários. Ao usá-lo, a multiplicação complexa total necessária pode ser reduzida a NlogN. o que é uma melhoria significativa. DFT típico leva N * N multiplicação complexa para resultados, enquanto FFT leva apenas N * logN. esta é uma vantagem significativa quando os números da amostra são altos.
Você pode consultar as referências abaixo que me referi ao escrever o código para uma compreensão detalhada da matemática por trás da 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 ...
Etapa 2:Explicação do código
1. Seno e cosseno rápidos:
O cálculo FFT leva o valor de vários seno e cosseno várias vezes. A função embutida do Arduino não é rápida o suficiente e leva muito tempo para fornecer o valor necessário. O que torna o código significativamente mais lento (dobra o tempo para 64 amostras). Para neutralizar esse valor de emissão de seno de 0 a 90 graus, é armazenado como múltiplo de 255. Fazer isso eliminará a necessidade de armazenar números como flutuante e podemos armazená-lo como byte, que ocupa 1/4 de espaço no Arduino. O sine_data [] precisa ser colado no topo do código para declará-lo como uma variável global.
Além de sine_data, uma matriz chamada f_peaks [] declarada como uma variável global . Após cada execução da função FFT, este array é atualizado. Onde f_peaks [0] é a frequência mais dominante e outros valores em ordem decrescente.
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, 255}; flutuar f_peaks [5 ];
Como armazenamos o valor de seno de 0 a 90 graus, qualquer valor de seno ou cosseno pode ser calculado. Abaixo da função a primeira rodada do número para a casa decimal zero e o valor de retorno dos dados armazenados. este método precisa de apenas uma divisão flutuante. Isso pode ser reduzido ainda mais armazenando diretamente os valores do seno (não o múltiplo de 255). mas isso consome muita memória no Arduino.
Usar o procedimento acima reduz a precisão, mas melhora a velocidade. Para 64 pontos dá uma vantagem de 8ms e para 128 pontos dá uma vantagem de 20ms.
Etapa 3:Explicação do código:Função FFT
A FFT só pode ser realizada para o tamanho da amostra de 2, 4, 8, 16, 32, 64 e assim por diante. se o valor não for 2 ^ n, ele assumirá o lado inferior do valor. Por exemplo, se escolhermos o tamanho da amostra de 70, ele irá considerar apenas as primeiras 64 amostras e omitir o resto.
É sempre recomendado ter um tamanho de amostra de 2 ^ n. que pode ser:
2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, ...
Dois flutuadores out_r e out_im ocuparão uma grande quantidade de memória. para Arduino nano não funcionará para amostras superiores a 128 (e em alguns casos 128) devido à falta de memória disponível.
dados int não assinados [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 os níveis {if (data [i] <=a) {o =i;}} int in_ps [data [o]] ={}; // entrada para sequencingfloat out_r [data [o]] ={}; // parte real de transformfloat out_im [data [o]] ={}; // parte da imaginação da transformação
O fluxo adicional é o seguinte:
1. O código gera um bit invertido na ordem para o tamanho de amostra fornecido (detalhes sobre a reversão do bit nas referências:etapa 2)
2. Dados de entrada ordenados de acordo com o pedido gerado,
3. FFT realizada
4. A amplitude do número complexo calculado,
5. Os picos são detectados e ordenados em ordem decrescente
6. os resultados podem ser acessados em f_peaks [].
[para acessar outros dados (além da frequência de pico), o código deve ser modificado, de modo que a variável local possa ser copiada para alguma variável global predefinida]
Etapa 4:Teste do código
Uma amostra de onda de triângulo é fornecida como entrada. para esta onda, a frequência de amostragem é 10 Hz e a frequência da própria onda é 1,25 Hz.
Como pode ser mostrado na saída bruta, o valor é compatível com o FFT calculado pelo Scilab. no entanto, esses valores não são exatamente os mesmos que temos baixa precisão, mas onda senoidal mais rápida.
Na frequência de saída, a frequência da matriz é 1,25 e 3,75. não é necessário obter o valor exato todas as vezes. normalmente, esses números são chamados de compartimentos de frequência. portanto, o valor de saída pode estar em qualquer lugar dentro das caixas especificadas.
Velocidade:
para Arduino nano é preciso:
- 16 pontos:4ms
- 32 pontos:10 ms
- 64 pontos:26 ms
- 128 pontos:53ms
Etapa 5:Conclusão
Este código FFT pode ser usado em aplicativos em tempo real. Uma vez que leva cerca de 30 ms para completar o cálculo. No entanto, sua resolução é limitada por um número de amostras. O número da amostra é limitado pela memória do Arduino. Usando o Arduino Mega ou outra placa de maior desempenho, a precisão pode ser melhorada.
Se você tiver alguma dúvida, sugestão ou correção, sinta-se à vontade para comentar.
Código
- EasyFFT
EasyFFT Arduino
Este código executa FFT e atualiza a matriz F_peasks com as 5 frequências mais dominantes./ * // Exemplo de dados:dados internos [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, // Cole no início do 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]; // 5 principais picos de frequências em ordem decrescente // --------------------------------------- ------------------------------------ // void setup () {Serial.begin (250000); } void loop () {/ * // exampleFFT (dados, 64.100); // para obter os cinco principais valores de frequências de X com 64 amostras em 100 Hz samplingSerial.println (f_peaks [0]); Serial.println (f_peaks [1]); delay (99999); * // * após ruir acima de FFT ( ), frequências disponíveis em f_peaks [0], f_peaks [1], f_peaks [2], f_peaks [3], f_peaks [4], * /} // --------------- -------------- Função FFT ---------------------------------- ------------ // float FFT (int in [], int N, float Frequency) {/ * Código para executar FFT no arduino, setup:paste sine_data [91] no topo do programa [ variável global], cole a função FFT no final do programTerm:1. in []:Matriz de dados, 2. N:Número da amostra (tamanho de amostra recomendado 2,4,8,16,32,64,128 ...) 3. Frequência:frequência de amostragem necessária como entrada (Hz) Se o tamanho da amostra não estiver na potência de 2, ela será cortada para o lado inferior do número. ou seja, para 150 números de amostras, o código irá considerar a primeira 128 amostra, a amostra restante será omitida. Para Arduino nano, FFT de mais de 128 amostras não é possível devido à limitação mamory (64 recomendado) Para maior número de amostra pode surgir relacionado a Mamory emissão, Código por ABHILASHContato:[email protected] Documentação:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:alterar o tipo de dados N de float para int para> =256 amostras * / dados int sem sinal [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 os níveis {if (data [i] <=a) {o =i;}} int in_ps [data [o]] ={}; // entrada para sequencingfloat out_r [data [o]] ={}; // parte real de transformfloat out_im [data [o]] ={}; // parte da imaginação da transformação x =0; para (int b =0; ba) {out_r [i] =in [in_ps [i] -a];}} int i10, i11, n1; float e, c, s, tr, ti; para (int i =0; i aqui em diante out_r contém amplitude e our_in conecta a frequência (Hz) para (int i =0; i out_r [i-1] &&out_r [i]> out_r [i + 1] ) {in_ps [x] =i; // array in_ps usado para armazenamento do 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];} else if (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 cosseno (int i) {int j =i; flutuar; 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
Processo de manufatura
- O que é a transformada de Fourier?
- Decodificador DTMF usando apenas Arduino
- Sistema de alarme Arduino:SERENA
- Comunicação Python3 e Arduino
- Monitoramento de temperatura SMART para escolas
- Biblioteca de portas IO de 8 bits para Arduino
- Matriz de teclado de prototipagem de 64 teclas para Arduino
- Uma entrada analógica isolada para Arduino
- Robô para navegação interna supercool
- O que é o código HS para bomba hidráulica?