I'm having trouble creating an audio visualizer using the downloadable arduinoFFT.h (Version 2.0.4). My two concerns are the library itself and if my microphone that's connected to a preamplifier circuit is actually producing a usable signal.
Microphone:
The model is the Cylindrical Electret Condenser Microphone Pickup (Amazon). When I read its analog signal it's consistently around the 340-370 (1.7V) range, no matter if there is audio playing or not. Is that enough voltage? If not, is there a pre-amped microphone I can purchase instead?
FFT:
I would just like to check if the code posted below is correct. Please ignore the commented code as they are for my display. Please let me know if you need more information and thank you in advanced.
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include "arduinoFFT.h"
#ifndef PSTR
#define PSTR
#endif
#define PIN 6
#define MATRIX_WIDTH 32
#define MATRIX_HEIGHT 8
//Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(32, 8, PIN,
//NEO_MATRIX_TOP + NEO_MATRIX_RIGHT +
//NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG,
//NEO_GRB + NEO_KHZ800); // Width = 32, Height = 8
const int samples = 64;
const double samplingFrequency = 8000.0; //The Nyquist-Shannon sampling theorem states that your sampling frequency must be at least twice the highest frequency present in your signal
const int microphonePin = A4;
int sensorValue;
double peakFrequency;
int height;
int counter = 0;
double realComponent[samples];
double imagComponent[samples];
ArduinoFFT<double> FFT = ArduinoFFT<double>(realComponent, imagComponent, samples, samplingFrequency);
//double fftBins[samples/2];
void setup()
{
//matrix.begin();
//matrix.setTextWrap(false);
//matrix.setBrightness(20);
Serial.begin(9600);
}
void loop()
{
//matrix.fillScreen(0);
for (int i = 0; i < samples;i++)
{
realComponent[i] = analogRead (microphonePin);
imagComponent[i] = 0.0;
//Serial.println(realComponent[i]);
}
FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward);
FFT.compute(FFTDirection::Forward);
FFT.complexToMagnitude();
An Arduino cannot interface to that microphone which requires a bias voltage and a transistor amplifier to produce any output. Use Google to find circuits using electret microphones.
Perhaps you could show how you have connected it. And what to (ie what "arduino" are you using.
and how you are "reading" it.
The audio waveform will come out of the OUT pin. The output will have a DC bias of VCC/2 so when its perfectly quiet, the voltage will be a steady VCC/2 volts (it is DC coupled).
So you would expect a reading of around 1.7V if you are supplying it with 3.3V as reccommended.
I'd suggest you start with a simple sketch to read the adc and print the raw data.
and why
I just discovered the second microphone today as I continue researching this project. To test my original microphone setup, I printed the raw data as you described and was able to get the range. I'm not sure what you mean about outputting to a teletype.
So if I wanted to measure 4000 Hz, I should set the sampling Frequency to 8004Hz for example. Until my new microphone arrives, is there a way I can check if the FFT is producing the correct values? For example, can I just create an array of integers and compare my values with an FFT calculator or do I have to use a sine wave?
Using such a low baud rate is nonsense if you are using modern equipment.
And I say again - I'd suggest you start with a simple sketch to read the adc and print the raw data.
Unless you know that is OK youre wasting your time. Garbage in - garbage out.
You must use a low pass filter to make sure than no signal component with frequency higher than 4 kHz is in the input sample, or the result will be aliased, possibly making the result of the FFT calculation uninterpretable.
The other option is to use a sample frequency at least 2X that of any signal present in the input, and ignore output components with frequency > 4 kHz.
After plugging in multiple values using the code I've pasted below and comparing it with MathLab and an online FFT calculator, I still haven't been able to produce correct results.
Code:
#include "arduinoFFT.h"
const uint16_t samples = 8; //This value MUST ALWAYS be a power of 2
const double signalFrequency = 1000;
const double samplingFrequency = 5000;
double vReal[samples];
double vImag[samples];
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, samples, samplingFrequency);
int num[samples] = {0, 3, 0, 3, 0, 3, 0, 3};
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop()
{
// put your main code here, to run repeatedly:
double ratio = twoPi * signalFrequency / samplingFrequency; // Fraction of a complete cycle stored at each sample (in radians)
for (uint16_t i = 0; i < samples; i++)
{
vReal[i] = num[i];
vImag[i] = 0.0; //Imaginary part must be zeroed in case of looping to avoid wrong calculations and overflows
}
FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward);
FFT.compute(FFTDirection::Forward);
FFT.complexToMagnitude();
for (int i = 0; i < (samples); i++)
{
Serial.println(vReal[i]);
}
Serial.println();
double x = FFT.majorPeak();
Serial.println(x, 7);
delay (5000);
exit(0);
}