O mundo está se tornando cada vez mais sem fios: ao nosso redor, há um número crescente de ondas de rádio trafegando, e o uso de comunicações sem fio tende apenas a crescer. Isso exige de nós — projetistas, makers e engenheiros eletrônicos — a instrumentação adequada para verificarmos como e em quais frequências nossos projetos que utilizam comunicação sem fio estão operando. Além disso, projetos e soluções em áudio também exigem a verificação das frequências audíveis que estão sendo utilizadas, a fim de checar desde a operação correta do sistema até a qualidade final do som — como a representatividade das frequências graves, médias e agudas, por exemplo. Para estas verificações, existe uma instrumentação específica: o analisador de espectro.
Neste artigo, será explicado o que é o analisador de espectro, para que ele serve e, ainda, como montar o seu próprio com Arduino e o chip MSGEQ7.
O que é um analisador de espectro?
O analisador de espectro, muitas vezes também chamado de analisador de áudio, é uma instrumentação muito útil em diversos campos da eletrônica e telecomunicações, pois permite a visualização e análise das frequências que compõem um determinado sinal.
Um analisador de espectro profissional, visualmente, se parece muito com um osciloscópio mas, ao contrário do osciloscópio, que mostra um dado sinal ao longo do tempo, o analisador de espectro permite enxergar o conteúdo espectral do sinal (ou seja, ver quais frequências estão presentes no sinal e quais suas amplitudes e ganhos). Essa representação é crucial para qualquer tarefa que envolva a análise de sinais, como por exemplo: verificação de harmônicos, na detecção de ruídos e interferências ou na análise da qualidade de sinais transmitidos.
Figura 1 – Analisador de espectro do fabricante Siglent
A importância dos analisadores de frequência é grande, e seu uso abrange desde laboratórios de pesquisa até aplicações práticas como o desenvolvimento de produtos de áudio, comunicações sem fio e diagnósticos de problemas em comunicação sem fio (interferências, por exemplo).
Como funciona o analisador de espectro?
O analisador de espectro profissional funciona com base em conversores de frequência e filtros (digitais ou analógicos, a depender da funcionalidade selecionada no equipamento e de sua disponibilidade no mesmo). Combinando esses elementos, o analisador de espectro é, portanto, capaz de detectar a amplitude de sinais em diferentes faixas de frequência.
Como exemplo, observe a figura 2. Nela, tem-se à esquerda um sinal complexo e, à direita, o resultado da análise desse sinal em um analisador espectral, onde é possível visualizar graficamente quais as frequências que estão presentes no sinal (e a amplitude de suas componentes, em dB). Com essa informação, é possível verificar se há alguma frequência indesejada no sinal e se é preciso implementar algum filtro em hardware para eliminá-la do sinal, por exemplo.
Figura 2 – Sinal complexo (à esquerda) e sua análise espectral (à direita).
Existem também analisadores de espectro RF, voltados especificamente para análise de sinais de rádio frequência, muito utilizados em aplicações de telecomunicações e rádio. Outra categoria interessante são os analisadores de espectro portáteis, ideais para medições em campo ou situações que exigem mobilidade.
Como construir um analisador de áudio com Arduino?
Se você está se perguntando se é possível fazer um analisador de espectro com Arduino, a resposta curta é sim. Embora analisadores de espectro profissionais tenham recursos que necessitem de microcontroladores e SoCs com muito mais recursos computacionais (memória, armazenamento e memória RAM) do que àqueles usados nas placas Arduino, é possível desenvolver analisadores de espectro simples e funcionais utilizando Arduino.
Entretanto, somente uma placa Arduino sozinha não é suficiente. É necessário usar junto do Arduino um chip extra para a “quebra” do sinal em suas componentes de frequência. Um dos chips mais populares para isso é o MSGEQ7, do fabricante MSI (o datasheet dele pode ser visto aqui).
Esse chip é um equalizador de sete bandas (63 Hz, 160 Hz, 400 Hz, 1 kHz, 2,5 kHz, 6,25 kHz e 16 kHz) e opera analisando o sinal de áudio e fornecendo uma saída analógica correspondente ao nível de energia em cada uma das sete bandas de frequência. Dessa forma, se o Arduino fizer a leitura destas saídas analógicas, será capaz de saber quais bandas (dentre as sete) estão presentes no sinal que entra no MSGEQ7, em tempo real.
Um exemplo de projeto que une Arduino Uno e o chip MSGEQ7 é o presente neste repositório do Github: nele, é criado um analisador de espectro de áudio, criando uma visualização interessante das 7 bandas detectadas em um display de fitas de LED.
Vale destacar que, para projetos que demandem mais entradas, saídas ou maior capacidade de processamento, também é possível utilizar placas como o Arduino Mega, que oferece mais recursos do que o tradicional Arduino Uno. Naturalmente, o preço de um analisador de espectro profissional pode ser bastante elevado, o que torna as soluções baseadas em Arduino uma alternativa acessível e educativa.
Ainda, há um vídeo muito interessante de um analisador de espectro com Arduino e MSGEQ7 usando display OLED. Veja-o em:
Materiais necessários
Os materiais necessários para a montagem do analisador de áudio com Arduino estão listados abaixo:
- Arduino Uno
- Fita de LED NeoPixel
- Equalizador Gráfico de 7 bandas MSGEQ7
- Capacitor de 100nF (2 unidades)
- Capacitor de 10nF
- Capacitor de 33pF
- Trimpot de 20kΩ
- Resistor de 200kΩ
- Resistor de 15kΩ
- Resistor de 330Ω
- Resistor de 220Ω
- Trimpot de 20kΩ
- Conector de entrada de áudio de 3,5mm
- Protoboard
Circuito do analisador de áudio com Arduino
O circuito esquemático deste projeto pode ser visto na figura 3.
Figura 3 – circuito esquemático de um analisador de espectro de áudio feito com Arduino UNO e MSGEQ7
Código do analisador de áudio com Arduino
O código a seguir tem como função ler, processar e exibir visualmente as informações fornecidas pelo chip MSGEQ7. Ele utiliza dois MSGEQ7 (um para o canal esquerdo e outro para o direito), ligados ao Arduino Uno, que realiza a leitura analógica das sete bandas de frequência de cada canal. Essas leituras são processadas e convertidas em sinais visuais por meio de duas fitas de LED do tipo NeoPixel, permitindo visualizar em tempo real a intensidade de cada banda de frequência captada no áudio.
A biblioteca Adafruit_NeoPixel é usada para controlar as fitas de LED RGB, permitindo a seleção e a exibição de cores de forma dinâmica. Cada coluna de LEDs representa uma banda de frequência (de 63 Hz a 16 kHz), enquanto a quantidade de LEDs acesos em cada coluna representa a intensidade dessa banda no sinal de áudio.
A lógica do código funciona da seguinte forma:
- As funções readData() e readConsole() realizam, respectivamente, a leitura das intensidades de frequência dos dois chips MSGEQ7 e comandos recebidos via porta serial.
- A função setLEDs() determina quais LEDs devem ser acesos em cada coluna, de acordo com a intensidade captada.
- As funções auxiliares calcMethod(), condition(), setLEDcolor() e setLEDoff() ajudam a organizar a lógica de exibição, determinando a posição exata dos LEDs na fita e a cor que cada um deve exibir.
Além disso, o sistema permite alternar o modo de exibição por meio de comandos seriais. Por padrão, o sistema exibe os LEDs na cor laranja, mas pode ser expandido para diferentes cores, modos de visualização ou animações. Esse tipo de projeto é ideal para experiências com visualizações de áudio, como iluminação ambiente reativa a música, painéis decorativos ou projetos educacionais que envolvam sinais analógicos, espectros de frequência e programação embarcada.
#include <Adafruit_NeoPixel.h> unsigned short leftMSGEQ[7]; //arrays for storing MSGEQ7 data unsigned short rightMSGEQ[7]; unsigned short strobePins[2] = { 2,4 }; //IO pins unsigned short resetPins[2] = { 3,5 }; unsigned short analogPins[2] = { 0,1 }; unsigned short outputPins[2] = { 8,9 }; //data to the LED strips unsigned short numLEDs = 119; //per block unsigned short LEDsPerStrip = numLEDs / 7; unsigned short minMAPlimit = 0; //limits used to convert MSGEQ7 values unsigned short maxMAPlimit = LEDsPerStrip; unsigned short noiseFilter = 90; //used to get rid of unwanted noise unsigned short brightness = 20; //LED strips brightness unsigned short readDataDelay = 3; //delay after reading MSGEQ7 data unsigned short readConsoleDelay = 2; //delay while reading from the console unsigned short baudRate = 9600; unsigned short serialInputNumber; //read input command is stored here unsigned short lastCommand; //keep track of the last command unsigned short command = 2; //set a default value of 2 //strip objects Adafruit_NeoPixel strip0 = Adafruit_NeoPixel(numLEDs, outputPins[0], NEO_RGB + NEO_KHZ800); Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(numLEDs, outputPins[1], NEO_RGB + NEO_KHZ800); //some color samples uint32_t white = strip0.Color(255, 255, 255); uint32_t black = strip0.Color(0, 0, 0); uint32_t red = strip0.Color(255, 0, 0); uint32_t green = strip0.Color(0, 255, 0); uint32_t blue = strip0.Color(0, 0, 255); uint32_t orange = strip0.Color(255, 50, 0); void setup() { Serial.begin(baudRate); Serial.setTimeout(readConsoleDelay); //set the delay when reading from the console pinMode(strobePins[0], OUTPUT); //set pin modes pinMode(strobePins[1], OUTPUT); pinMode(resetPins[0], OUTPUT); pinMode(resetPins[1], OUTPUT); pinMode(analogPins[0], INPUT); pinMode(analogPins[1], INPUT); digitalWrite(resetPins[0], HIGH); //reset the MSGEQ7s digitalWrite(resetPins[1], HIGH); digitalWrite(resetPins[0], LOW); digitalWrite(resetPins[1], LOW); strip0.begin(); //initialize the strips strip1.begin(); strip0.setBrightness(brightness); //set their brightness strip1.setBrightness(brightness); } void loop() { readData(); setLEDs(); readConsole(); strip0.show(); //update the strips strip1.show(); } void readData() //reads MSGEQ7 data { for (short i = 0; i < 7; i++) { digitalWrite(strobePins[0], LOW); //enable both MSGEQ7s digitalWrite(strobePins[1], LOW); leftMSGEQ[i] = analogRead(analogPins[0]); //read data rightMSGEQ[i] = analogRead(analogPins[1]); digitalWrite(strobePins[0], HIGH); //disable both and on the next enable it will spit out values for digitalWrite(strobePins[1], HIGH); //the other frequency bands leftMSGEQ[i] = constrain(leftMSGEQ[i], noiseFilter, 1023); //getting rid of that noise rightMSGEQ[i] = constrain(rightMSGEQ[i], noiseFilter, 1023); leftMSGEQ[i] = map(leftMSGEQ[i], noiseFilter, 1023, minMAPlimit, maxMAPlimit); //convert to more suitable values rightMSGEQ[i] = map(rightMSGEQ[i], noiseFilter, 1023, minMAPlimit, maxMAPlimit); delay(readDataDelay); //DEBUGGING /* Serial.print(leftMSGEQ[i]); Serial.print(" ");*/ } /*Serial.print("\t\t"); for (short i = 0; i < 7; i++) { Serial.print(rightMSGEQ[i]); Serial.print(" "); } Serial.println();*/ //END DEBUGGING } void setLEDs() //set which LEDs should be on/off { for (short i = 0; i < 7; i++) //i is like an LED colomn { for (short j = 0; j < LEDsPerStrip; j++) //j is like an LED row { strip0.setPixelColor(calcMethod(i, j), condition(i, j, 0) ? setLEDcolor(i, j, 0) : setLEDoff(i, j, 0)); strip1.setPixelColor(calcMethod(i, j), condition(i, j, 1) ? setLEDcolor(i, j, 1) : setLEDoff(i, j, 1)); } } } //stripNum is used to differentiate between the first strip (strip0) and the second (strip1) //because both strips are updated in the same function void readConsole() //read command from the console { serialInputNumber = Serial.parseInt(); //read a number(command) from the console if (serialInputNumber != 0) //Serial.parseInt() returns 0 if nothing else is read { lastCommand = command; command = serialInputNumber; } } short calcMethod(short i, short j) //calculate the exact position of the LED i and j are looking at { switch (i % 2) { case 0: return LEDsPerStrip * i + j; //even strips are looking up break; case 1: return LEDsPerStrip * (i + 1) - j; //odd strips are looking down so you calculate in reverse break; } } short condition(short i, short j, short stripNum) //used to differentiate between the setLEDcolor and setLEDoff { return stripNum == 0 ? j < leftMSGEQ[i] : j < rightMSGEQ[i]; } uint32_t setLEDcolor(short i, short j, short stripNum) //returns the desired color for the .setPixelcolor function { switch (command) { case 1: //reserved for menu Serial.print("Command list:\n\n1.Print command list\n2.Orange\n"); command = lastCommand; break; case 2: //default value of command return orange; break; default: //all LEDs will be black if no condition in the switch-case is met return black; break; } } uint32_t setLEDoff(short i, short j, short stripNum) //used to set the rest of the LEDs to black(off) { return black; }
Conclusão
O analisador de espectro é uma instrumentação muito útil tanto para profissionais quanto para entusiastas da eletrônica. Com a popularização de plataformas acessíveis como Arduino e chips como o MSGEQ7, tornou-se possível construir projetos funcionais e didáticos de analisadores de espectro caseiros com relativa facilidade.
O uso conjunto do Arduino UNO e MSGEQ7, por exemplo, é uma excelente combinação para fazer seu primeiro analisador de espectros. Utilizando os projetos mostrados neste artigo como base, você pode aplicar ambos diretamente como um analisador de espectro de áudio e usar as informações de frequências do sinal de áudio fornecidas pelo MSGEQ7 para criar iluminação RGB sincronizada com o áudio, por exemplo.
E para não perder nenhum conteúdo como este, não deixe de seguir a MakerHero no Instagram.