In questo tutorial imparerai come costruire un semplice Analizzatore di Spettro di Frequenza con un ESP32. Useremo il microfono MAX4466 e la libreria arduinoFFT per misurare le frequenze nel segnale audio e visualizzare lo spettro di frequenza su un OLED.
Iniziamo con i componenti necessari per questo progetto.
Componenti necessari
Ti serviranno un ESP32, uno schermo OLED e il modulo microfono MAX4466. Io uso l’ESP32 lite come microprocessore, perché ha un’interfaccia di ricarica batteria e potresti quindi far funzionare facilmente l’Analizzatore di Spettro con una batteria per renderlo portatile. Ma qualsiasi altro ESP32 andrà bene.

ESP32 lite

Cavo dati USB

Microfono MAX4466

Display OLED

Set di fili Dupont

Breadboard
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Analizzatore di Spettro di Frequenza
Un Analizzatore di Spettro di Frequenza è un dispositivo che visualizza e analizza il contenuto spettrale dei segnali e mostra l’ampiezza o la potenza di un segnale lungo il suo intervallo di frequenze. In pratica ti dice quanta potenza del segnale è distribuita su frequenze o bande di frequenza specifiche.
L’immagine seguente mostra uno spettro di frequenza. L’intervallo di frequenza è sull’asse x e la magnitudine del segnale è misurata in Decibel come mostrato sull’asse y:

A seconda della precisione e dell’intervallo di frequenza, gli Analizzatori di Spettro possono essere molto costosi. Qui sotto una foto dell’Analizzatore di Spettro Siglent Technologies SSA3021X che può analizzare frequenze radio da 9 kHz a 2,1 GHz.

Spettro di Frequenza Audio
Un’applicazione comune degli Analizzatori di Spettro è visualizzare la distribuzione delle frequenze all’interno di unsegnale audio. L’intervallo di frequenza o uditivo di un segnale audio che gli esseri umani possono percepire va da 20 a 20.000 Hz (=20KHz). Tuttavia, questi sono gli estremi e l’udito diminuisce con l’età. Per gli adulti il limite superiore è tipicamente intorno a 15.000 Hz. Se vuoi conoscere il tuo limite superiore, puoi provare questo piccolo test dell’udito.
L’immagine seguente mostra il display di un tipico Analizzatore di Spettro Audio. Puoi vedere le diverse bande di frequenza (barre verdi) che vanno da 20Hz a 20KHz.
In questo tutorial costruiremo un Analizzatore di Spettro Audio simile. Tuttavia, non aspettarti troppo. Poiché usiamo un economico ESP32, un piccolo OLED e un semplice microfono MAX4466, il nostro Analizzatore di Spettro non sarà molto preciso.
Il suo intervallo di frequenza sarà solo da 125Hz a 8000 Hz e avremo solo 7 bande di frequenza, ma sarà abbastanza per visualizzare e animare il contenuto in frequenza della musica.
Funzionamento di un Analizzatore di Spettro
Come funziona il nostro piccolo Analizzatore di Spettro Audio. Il microfono converte le onde sonore in impulsi elettrici. Questi deboli impulsi sono amplificati dal MAX4466 e inviati al Convertitore Analogico Digitale (ADC) dell’ESP32. Se leggi l’uscita dell’ADC e la tracci, il segnale audio rilevato potrebbe apparire così:

Sull’asse x c’è il tempo e sull’asse y l’ampiezza del segnale. Questo segnale si chiama segnale nel dominio del tempo, perché è riportato nel tempo ma non mostra le frequenze all’interno del segnale.
Il segnale sopra è in realtà composto da segnali coseno con frequenze di 10, 20, 30, 40 e 50 Hz con ampiezze crescenti. Se applichiamo un metodo matematico chiamato Fast Fourier Transformation (FFT), possiamo estrarre queste frequenze dal segnale. Il grafico sotto mostra lo stesso segnale dopo l’applicazione della FFT:

Il segnale è ora nel dominio della frequenza con la frequenza sull’asse x (invece del tempo). Si vedono chiaramente i picchi a 10, 20, 30, 40 e 50 Hz, che rivelano le frequenze di cui è composto il segnale in ingresso. Per eseguire la FFT facciamo campionare all’ESP32 il segnale audio prelevato dall’ADC e poi chiamiamo la arduinoFFT library per estrarre le frequenze. Lo spettro di frequenza risultante viene poi visualizzato sull’OLED.
Tuttavia, non mostreremo le singole frequenze nello spettro ma le raggrupperemo in bande di frequenza più facili da leggere e comunemente usate negli Analizzatori di Spettro Audio. Le bande di frequenza saranno intorno a 125, 250, 500, 1000, 2000, 4000 e 8000 Hz, come mostrato sotto:

Modulo Microfono MAX4466
Il modulo microfono MAX4466 è una scheda breakout con un microfono elettrete 20-20KHz e il MAX4466 circuito preamplificatore IC. Sul retro della scheda c’è un piccolo trimmer che permette di regolare il guadagno da 25x a 125x. L’immagine sotto mostra il fronte e il retro della scheda:

Il modulo funziona con 2.4…5.5V per VCC con una corrente di alimentazione a riposo molto bassa di <24μA. L’uscita avrà un bias di VCC/2. Quindi quando è perfettamente silenzioso, la tensione di uscita sarà a VCC/2 V.
Se vuoi saperne di più sul modulo microfono MAX4466 dai un’occhiata al Detect sound with MAX4466 and Arduino tutorial.
Collegare MAX4466 e OLED all’ESP32
In questa sezione colleghiamo prima il modulo microfono MAX4466 all’ESP32 e testiamo il suo funzionamento. Poi aggiungiamo l’OLED al circuito e scriviamo il codice per l’Analizzatore di Spettro:
Collegare MAX4466 all’ESP32
Per collegare il MAX4466 a un ESP32, inizia collegando la massa (GND) dell’ESP32 e del modulo MAX4466 (filo blu). Poi collega il VCC del MAX4466 all’uscita 3.3V dell’ESP32 (filo rosso). Infine, collega il GPIO 4 dell’ESP32 al pin OUT del MAX4466 (filo arancione):

Nota che invece del GPIO 4 puoi usare qualsiasi altro pin purché possa leggere un segnale analogico.
Codice di test per MAX4466
Dopo aver collegato il microfono MAX4466 all’ESP32, eseguiamo un piccolo test per vedere se tutto funziona come previsto. Il codice seguente legge il segnale del microfono sul pin 4 e lo stampa sul Monitor Seriale:
const byte micPin = 4;
void setup() {
Serial.begin(115200);
pinMode(micPin, INPUT);
}
void loop() {
int value = analogRead(micPin);
Serial.println(value);
delay(100);
}
Se carichi questo codice, apri il Serial Plotter e fai un po’ di rumore, dovresti vedere delle fluttuazioni nel segnale audio correlate al volume del rumore:

Se non vedi alcun cambiamento nel segnale audio, allora o il cablaggio è sbagliato, o il pin GPIO per il microfono nel codice è errato.
Aggiungere OLED all’ESP32
Nel passo successivo aggiungiamo l’OLED all’ESP32. Prima collega GND e VCC dell’OLED alle linee di alimentazione esistenti (fili blu e rossi). Poi collega SCL al pin 23 e SDA al pin 18 dell’ESP32, come mostrato sotto:

GPIO 23 e 18 sono i pin hardware I2C per l’ESP32 lite. Se usi una scheda ESP32 diversa, i pin per l’I2C hardware potrebbero essere diversi. Se non sei sicuro di quali pin usare, dai un’occhiata al Find I2C and SPI default pins tutorial. L’immagine sotto mostra il circuito completo su breadboard:

Codice per visualizzare lo Spettrogramma di Frequenza
Prima di poter scrivere il codice per calcolare e visualizzare lo Spettrogramma di Frequenza, dobbiamo installare la arduinoFFT library. Apri il LIBRARY MANAGER, digita “arduinoFFT” nella barra di ricerca e premi il INSTALL pulsante. Dopo un’installazione riuscita dovresti vedere quanto segue:

Inoltre, dovremo installare la Adafruit_SSD1306 Library per controllare l’OLED. Digita “Adafruit_SSD1306” nella barra di ricerca e come prima premi INSTALL per installare la libreria:

Fatto ciò, possiamo iniziare a scrivere il codice. Il codice seguente per un visualizzatore di spettro audio legge l’ingresso audio da un microfono, esegue una Trasformata di Fourier Veloce (FFT) per analizzare lo spettro di frequenza e visualizza i risultati su un OLED. L’immagine seguente mostra l’output creato e il significato degli elementi visivi:

Nelle sezioni successive esamineremo questo codice funzione per funzione. Il codice si basa sull’esempio ESP32_FFT_VU ma è stato suddiviso in funzioni più piccole e leggermente modificato per una migliore leggibilità.
#include "arduinoFFT.h"
#include "Adafruit_SSD1306.h"
const int micPin = 4;
const int volume = 300; // Adjust depending on audio volume
const int noise = 2000; // Noise filter, smaller signal is ignored
const int nSamples = 256; // Must be a power of 2
const int sampleFreq = 40000; // Hz, 40000 or less
double vReal[nSamples];
double vImag[nSamples];
byte peaks[] = { 0, 0, 0, 0, 0, 0, 0 };
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, nSamples, sampleFreq);
Adafruit_SSD1306 oled(128, 64, &Wire, -1);
void displayScale() {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print(".1 .2 .5 1K 2K 4K 8K");
}
void displayBands() {
for (int i = 2; i < (nSamples / 2); i++) {
if (vReal[i] > noise) {
if (i <= 2) displayBand(0, vReal[i]); // 125Hz
if (i > 3 && i <= 5) displayBand(1, vReal[i]); // 250Hz
if (i > 5 && i <= 7) displayBand(2, vReal[i]); // 500Hz
if (i > 7 && i <= 15) displayBand(3, vReal[i]); // 1000Hz
if (i > 15 && i <= 30) displayBand(4, vReal[i]); // 2000Hz
if (i > 30 && i <= 53) displayBand(5, vReal[i]); // 4000Hz
if (i > 53 && i <= 200) displayBand(6, vReal[i]); // 8000Hz
if (i > 200) displayBand(7, vReal[i]); // 16000Hz
}
}
}
void calcFFT() {
FFT.windowing(vReal, nSamples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(vReal, vImag, nSamples, FFT_FORWARD);
FFT.complexToMagnitude(vReal, vImag, nSamples);
}
void sampleAudio() {
static unsigned long newTime, oldTime;
long period_us = round(1000000.0 / sampleFreq);
for (int i = 0; i < nSamples; i++) {
newTime = micros() - oldTime;
oldTime = newTime;
vReal[i] = analogRead(micPin);
vImag[i] = 0;
while (micros() < (newTime + period_us))
;
}
}
void displayPeaks() {
for (byte band = 0; band <= 6; band++) {
oled.drawFastHLine(18 * band, 64 - peaks[band], 14, WHITE);
}
}
void decayPeaks() {
if (millis() % 4 == 0) {
for (byte band = 0; band <= 6; band++) {
peaks[band] = max(0, peaks[band] - 1);
}
}
}
void displayBand(int band, double magnitude) {
int dmax = 50;
int dsize = min((int)(magnitude / volume), dmax);
if (band == 7) {
oled.drawFastHLine(18 * 6, 0, 14, WHITE);
}
for (int s = 0; s <= dsize; s += 2) {
oled.drawFastHLine(18 * band, 64 - s, 14, WHITE);
}
if (dsize > peaks[band]) {
peaks[band] = dsize;
}
}
void setup() {
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.setTextSize(1);
oled.setTextColor(WHITE);
pinMode(micPin, INPUT);
}
void loop() {
displayScale();
sampleAudio();
calcFFT();
displayBands();
displayPeaks();
decayPeaks();
oled.display();
delay(1);
}
Librerie
Il codice inizia includendo le librerie necessarie. C’è la libreriaarduinoFFT per calcolare la Trasformata di Fourier Veloce (FFT) e la libreria Adafruit_SSD1306, necessaria per controllare l’OLED:
#include "arduinoFFT.h" #include "Adafruit_SSD1306.h"
Costanti
Definiamo poi alcune costanti. micPin definisce il pin GPIO a cui è collegata l’uscita del MAX4466. La costante volume ti permette di regolare la magnitudine dello spettro di frequenza visualizzato in base al volume audio. Se non vedi barre, abbassa questo valore e se le barre sono molto grandi anche per suoni deboli, aumentalo.
Allo stesso modo, la costante noise ti permette di filtrare il rumore a basso livello. Se vedi troppo rumore nello spettro di frequenza (fluttuazioni casuali anche in assenza di suono) aumenta questo valore.
nSamples definisce quanti campioni audio vengono presi e sampleFreq è la frequenza di campionamento. Per microcontrollori più lenti dell’ESP32 potresti dover abbassare questi valori.
const int micPin = 4; const int volume = 300; // Adjust depending on audio volume const int noise = 2000; // Noise filter, smaller signal is ignored const int nSamples = 256; // Must be a power of 2 const int sampleFreq = 40000; // Hz, 40000 or less
Variabili
Ci sono tre variabili. vReal e vImag sono array che memorizzano la parte reale e immaginaria del segnale e l’array peaks tiene traccia delle magnitudini massime per ogni barra di frequenza.
double vReal[nSamples];
double vImag[nSamples];
byte peaks[] = { 0, 0, 0, 0, 0, 0, 0 };
Oggetti
Infine abbiamo gli oggetti. L’oggetto FFT contiene le funzioni necessarie per calcolare la Trasformata di Fourier Veloce, e l’oggetto oled contiene le funzioni per controllare il display OLED.
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, nSamples, sampleFreq); Adafruit_SSD1306 oled(128, 64, &Wire, -1);
displayScale
La funzione displayScale() prepara il display OLED cancellando ogni contenuto precedente e stampando le etichette per le bande di frequenza. Questo aiuta chi guarda a capire quale banda corrisponde a quale frequenza. La funzione usa questo codice:
void displayScale() {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print(".1 .2 .5 1K 2K 4K 8K");
}
La funzione displayBands() elabora il risultato FFT memorizzato nell’array vReal e decide a quale banda di frequenza appartiene ogni bin FFT. Filtra i segnali sotto una certa soglia di rumore e poi chiama displayBand() con l’indice della banda e la magnitudine del segnale:
void displayBands() {
for (int i = 2; i < (nSamples / 2); i++) {
if (vReal[i] > noise) {
if (i <= 2) displayBand(0, vReal[i]);
if (i > 3 && i <= 5) displayBand(1, vReal[i]);
if (i > 5 && i <= 7) displayBand(2, vReal[i]);
if (i > 7 && i <= 15) displayBand(3, vReal[i]);
if (i > 15 && i <= 30) displayBand(4, vReal[i]);
if (i > 30 && i <= 53) displayBand(5, vReal[i]);
if (i > 53 && i <= 200) displayBand(6, vReal[i]);
if (i > 200) displayBand(7, vReal[i]);
}
}
}
La funzione calcFFT() esegue l’analisi FFT vera e propria. Applica una finestra di Hamming per smussare il segnale e poi calcola la FFT, trasformando le parti reale e immaginaria in magnitudini memorizzate di nuovo in vReal:
void calcFFT() {
FFT.windowing(vReal, nSamples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(vReal, vImag, nSamples, FFT_FORWARD);
FFT.complexToMagnitude(vReal, vImag, nSamples);
}
La funzione sampleAudio() raccoglie nSamples dati analogici dal microfono. Legge il segnale a intervalli regolari, calcolati usando sampleFreq, e li memorizza nell’array vReal. vImag è impostato a zero poiché l’ingresso è puramente reale:
void sampleAudio() {
static unsigned long newTime, oldTime;
long period_us = round(1000000.0 / sampleFreq);
for (int i = 0; i < nSamples; i++) {
newTime = micros() - oldTime;
oldTime = newTime;
vReal[i] = analogRead(micPin);
vImag[i] = 0;
while (micros() < (newTime + period_us))
;
}
}
La funzione displayPeaks() mostra i valori di picco persistenti di ogni banda di frequenza disegnando brevi linee orizzontali dove il picco si è verificato l’ultima volta. Queste linee aiutano a visualizzare i livelli massimi recenti di volume in ogni banda:
void displayPeaks() {
for (byte band = 0; band <= 6; band++) {
oled.drawFastHLine(18 * band, 64 - peaks[band], 14, WHITE);
}
}
La funzione decayPeaks() riduce lentamente il valore di picco nel tempo, simulando un effetto di decadimento. Viene eseguita circa ogni 4 millisecondi e abbassa il picco di ogni banda di 1, fino a un minimo di 0:
void decayPeaks() {
if (millis() % 4 == 0) {
for (byte band = 0; band <= 6; band++) {
peaks[band] = max(0, peaks[band] - 1);
}
}
}
La funzione displayBand() disegna barre verticali per ogni banda sull’OLED. Scala la dimensione della barra in base alla magnitudine del segnale divisa per il parametro volume. Se l’indice della banda è 7, viene disegnata una barra speciale in cima allo schermo. La funzione aggiorna anche l’array peaks se la barra corrente supera il picco precedente:
void displayBand(int band, double magnitude) {
int dmax = 50;
int dsize = min((int)(magnitude / volume), dmax);
if (band == 7) {
oled.drawFastHLine(18 * 6, 0, 14, WHITE);
}
for (int s = 0; s <= dsize; s += 2) {
oled.drawFastHLine(18 * band, 64 - s, 14, WHITE);
}
if (dsize > peaks[band]) {
peaks[band] = dsize;
}
}
La funzione setup() inizializza lo schermo OLED e imposta il pin del microfono come input. Questo prepara il sistema a iniziare a campionare e visualizzare i dati audio:
void setup() {
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.setTextSize(1);
oled.setTextColor(WHITE);
pinMode(micPin, INPUT);
}
Infine, la funzione loop() è il ciclo di esecuzione principale. Esegue ripetutamente tutti i passaggi necessari per catturare l’audio, elaborarlo tramite FFT, visualizzare i dati e aggiornare lo schermo OLED:
void loop() {
displayScale();
sampleAudio();
calcFFT();
displayBands();
displayPeaks();
decayPeaks();
oled.display();
delay(1);
}
Insieme, queste funzioni formano un ciclo completo che analizza continuamente l’ingresso audio e mostra uno spettro visivo sul display OLED.
Toni di Test
Puoi testare l’Analizzatore di Spettro riproducendo alcuni toni di test. Ecco dei link a video Youtube che riproducono toni con frequenze specifiche:
L’Analizzatore di Spettro dovrebbe mostrare una barra più grande/che cresce per la banda di frequenza in cui rientra il tono di test. Per esempio, per un tono a 2000 Hz dovresti vedere una barra più grande nella banda a 2KHz:

L’altezza della barra dipenderà dal volume. Probabilmente dovrai regolare la costante volume o la gain control per il MAX4466 per ottenere un segnale pulito. Puoi trovare il potenziometro per regolare il guadagno sul retro del modulo MAX4466:

Conclusioni
In questo tutorial hai imparato come costruire un Analizzatore di Spettro di Frequenza usando il modulo microfono MAX4466, un OLED e un ESP32.
Se vuoi migliorare la precisione e l’intervallo di frequenza dell’Analizzatore di Spettro, potresti usare un Convertitore Analogico Digitale esterno per una risoluzione più alta e un microfono I2C per una gamma migliore.
Allo stesso modo, se vuoi un display più grande e a colori, potresti sostituire l’OLED con uno schermo TFT. Dai un’occhiata ai tutorial Interface TFT ILI9341 Touch Display with ESP32 e magari anche a quello How to configure TFT_eSPI Library for TFT display.
La scheda ESP32 lite ha un’interfaccia per batteria LiPo, che rende facile far funzionare l’Analizzatore di Spettro con una batteria LiPo da 4.2V. Tuttavia, la scheda è un po’ grande, soprattutto se confrontata con il piccolo OLED che abbiamo usato. Invece dell’ESP32 lite, potresti usare un ESP32-C SuperMini per costruire un Analizzatore di Spettro molto piccolo, carino e portatile.
Buon divertimento con il tinkering ; )
Link
Di seguito alcuni link che ho trovato utili mentre scrivevo questo tutorial:
- arduinoFFT Examples
- esp32-mic-fft
- ESP32_FFT_VU
- ESP32-8266-Audio-Spectrum-Display
- ESP32_Music_Spectrum_Analyzer
- ESP32 spectrum analyser VU meter using arduinoFFT and a FastLED matrix


