I'm using this example code. With this library GitHub - kosme/arduinoFFT: Fast Fourier Transform for Arduino · GitHub
#include <Arduino.h>
#include <arduinoFFT.h>
#define AUDIO_PIN 35 // ADC1 channel pin
#define SAMPLES 512 // Must be a power of 2
#define SAMPLING_FREQ 16000 // 16 kHz sampling (Nyquist limit = 8 kHz audio)
double vReal[SAMPLES];
double vImag[SAMPLES];
// Create the FFT object using standard ArduinoFFT configuration
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, SAMPLES, SAMPLING_FREQ);
unsigned int sampling_period_us;
unsigned long microseconds;
void setup() {
Serial.begin(115200);
sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQ));
analogSetAttenuation(ADC_11db); // Sets full-scale voltage range to ~3.3V
}
void loop() {
// 1. Collect Samples
for (int i = 0; i < SAMPLES; i++) {
microseconds = micros();
vReal[i] = analogRead(AUDIO_PIN);
vImag[i] = 0; // Imaginary part is 0 for real audio input
// Maintain precise timing interval
while (micros() - microseconds < sampling_period_us) {
// Empty loop to delay exactly to the target period
}
}
// 2. Process FFT
FFT.dcRemoval(); // Removes the 1.65V DC bias offset
FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward); // Smooths the signal edges
FFT.compute(FFTDirection::Forward); // Calculates FFT
FFT.complexToMagnitude(); // Computes magnitude vectors
// 3. Print out to Serial Monitor (Visualizer Output)
// We only look at the first SAMPLES/2 bins (0Hz to 8kHz) due to Nyquist frequency
for (int i = 2; i < (SAMPLES / 2); i++) {
// Calculate frequency for current bin
double frequency = (i * SAMPLING_FREQ) / SAMPLES;
// Simple filter to suppress background noise floor
if (vReal[i] > 100) {
Serial.print((int)frequency);
Serial.print("Hz: ");
// Draw ASCII bar relative to frequency amplitude
int barLength = map(vReal[i], 0, 5000, 0, 40);
for (int j = 0; j < barLength; j++) {
Serial.print("|");
}
Serial.println();
}
}
Serial.println("--- Frame ---");
delay(2000); // Small delay to make the Serial Monitor readable
}
I previously assumed it was one of the examples provided by the library, but it doesn't seem to be. I'm not sure where I got it from, sorry for not keeping better notes. I'm building that code with VS Code + PlatformIO.
I'm feeding this 1kHz sine wave into GPIO 35, as observed on my PicoScope
The red trace is trace B. I'm not showing trace A because that's for the signal generator that's feeding a signal into the opamp that's producing the red trace. That opamp is running off the ESP32's 3.3V pin for power. It's a MCP6022-I/P. The output of the opamp clips at just above 0V and just below 3.3V (where the horizontal cursors are) and it's DC coupled into the ESP32 ADC pin, so I think it can't damage the ESP32.
My question is whether this is known / expected behaviour for the example with that library.
--- Frame ---
62Hz: ||||||||
93Hz: |||||
343Hz:
1281Hz: |||
1312Hz: ||||
1343Hz: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1375Hz: ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1406Hz: ||||||||||||||||||||||||||||||||||||||||||
1437Hz: ||||
1468Hz: ||
2656Hz:
2687Hz:
2718Hz: ||||||||||||||||||||
2750Hz: |||||||||||||||||||||||||||||||||
2781Hz: |||||||||
2812Hz: |
4031Hz: |
4062Hz: |
4093Hz: |||||
4125Hz: |||||||
4156Hz: ||
4187Hz: |
5468Hz: ||
5500Hz: |||
5562Hz:
6375Hz: |
6406Hz: |
6843Hz: |||
6875Hz: |||
--- Frame ---
I'm not concerned about the signal in the 62Hz / 93Hz bins, as it's just a lash up and it's probably just mains hum being picked up.
What surprised me is how off the main peak at 1375Hz is, for 1kHz input. I suspect it's due to ADC sampling timing. I was just posting in case someone who sees this knows it's a known problem, and may be able to suggest a better way to get more accurate FFT frequency results. I did have a quick scan though FFT related posts on this forum, but didn't see anything for how to best do ADC sampling for the FFT library with an ESP32.
I know the ESP32 ADC has its issues with non linearity and dead spots close to 0V and close to 3.3V. Perhaps that's contributing to the harmonics of 1375Hz seen in the output. I'm not bothered about those harmonics ATM. I just want to get the main peak to show closer to 1KHz.
This is just for a 3 channel (bass, mid, treble) light organ, so it doesn't need to be doing high quality audio processing.

