Hi all,
I've been trying to get a frequency sweep going well on my spectrum analyzer, but unfortunately other columns seem to light up when they shouldn't be.. I'm pretty sure the problem is in the way I'm analyzing the fft data. I'm using a Teensy 3.2 and the following input circuit:
https://i.imgur.com/TIw8KaG.jpg?1
The audio is coming from a breadboard aux jack, amplified by the non inverting amplifier and level shifted to oscillate around 2.5V.
The code I'm using (where I suspect the problem lies) is below:
I realize that the mapping is not a great way to do this, especially since when I'm looking at the fft bins since they rarely reach 1.5 and seem to vary by bin. Additionally, I don't fully understand the documentation at https://www.pjrc.com/teensy/gui/index.html?info=AudioAnalyzeFFT1024 since sometimes the values are above 1.0. The computeVerticalThreshold method performs worse, however.
There is typically high bin noise - the last 2 bins mostly, which should be from 3k-9.5k and 9.5k-22k. The frequency sweep seems to generally map to the right bins, except for the noise and the last bin, where it seems to never truly come alive.
Frequency Sweep from: http://www.szynalski.com/tone-generator/
Do you think the problem lies within how I'm processing the FFT data, or with the input circuit -- should I switch to the recommended input circuit at http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog, and if so, why?
Any advice would be great. Thanks!
I've been trying to get a frequency sweep going well on my spectrum analyzer, but unfortunately other columns seem to light up when they shouldn't be.. I'm pretty sure the problem is in the way I'm analyzing the fft data. I'm using a Teensy 3.2 and the following input circuit:
https://i.imgur.com/TIw8KaG.jpg?1
The audio is coming from a breadboard aux jack, amplified by the non inverting amplifier and level shifted to oscillate around 2.5V.
The code I'm using (where I suspect the problem lies) is below:
Code:
// LED Audio Spectrum Analyzer Display
//
// Code derived from pjrc's //https://github.com/PaulStoffregen/OctoWS2811/blob/master/examples/SpectrumAnalyzer/Spectr//umAnalyzer.ino
//
// Line Level Audio Input connects to analog pin A3
// Recommended input circuit:
// http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog
//
// This example code is in the public domain.
//#include <OctoWS2811.h>
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <LedControl.h>
int DIN = 12;
int CS = 11;
int CLK = 10;
// The display size and color to use
const unsigned int matrix_width = 8;
const unsigned int matrix_height = 8;
// These parameters adjust the vertical thresholds
const float maxLevel = 1.0; // 1.0 = max, lower is more "sensitive"
const float dynamicRange = 40.0; // total range to display, in decibels
const float linearBlend = 0.3; // useful range is 0 to 0.7
//AudioInputI2S audioInput; //xy=139,91
//AudioAnalyzeFFT1024 fft; //xy=467,147
//AudioConnection c1(audioInput, 0, fft, 0); // left passing through
//AudioConnection c2(audioInput, 1, fft, 1); // right passing through
//AudioControlSGTL5000 audioShield; //xy=366,225
//const int myInput = AUDIO_INPUT_LINEIN;
// Audio library objects
AudioInputAnalog adc1(A3); //xy=99,55
AudioAnalyzeFFT1024 fft; //xy=265,75
AudioConnection patchCord1(adc1, fft);
LedControl lc = LedControl(DIN, CLK, CS, 0);
// This array holds the volume level (0 to 1.0) for each
// vertical pixel to turn on. Computed in setup() using
// the 3 parameters above.
float thresholdVertical[matrix_height];
// This array specifies how many of the FFT frequency bin
// to use for each horizontal pixel. Because humans hear
// in octaves and FFT bins are linear, the low frequencies
// use a small number of bins, higher frequencies use more.
//int frequencyBinsHorizontal[matrix_width + 1] = {0, 3, 6, 9, 10, 13, 20, 32, 69};
const int borders[9] = {0, 10, 13, 16, 24, 32, 69, 221, 511}; //borders of the frequency areas
unsigned char previousHeights[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //height of each column
//const unsigned char borders[9] = {1, 6, 12, 30, 47, 94, 140, 280, 511}; //borders of the frequency areas
//const unsigned char borders[9] = {2, 5, 5, 30, 47, 94, 140, 280, 511}; //borders of the frequency areas
// Run once from setup, the compute the vertical levels
void computeVerticalLevels() {
unsigned int y;
float n, logLevel, linearLevel;
for (y = 0; y < matrix_height; y++) {
n = (float)y / (float)(matrix_height - 1);
logLevel = pow10f(n * -1.0 * (dynamicRange / 20.0));
linearLevel = 1.0 - n;
linearLevel = linearLevel * linearBlend;
logLevel = logLevel * (1.0 - linearBlend);
thresholdVertical[y] = (logLevel + linearLevel) * maxLevel;
}
}
void setColumn(int column, float height) {
// maps height from 0 to 255 to 0 to 8
unsigned char h;
h = (unsigned char) map(height, 0, 1.5, 0, 8);
// if new h is less than previous value, decrement
if (h < previousHeights[column]) {
previousHeights[column] = previousHeights[column] - 1;
} else if (h > previousHeights[column]) {
previousHeights[column] = h;
}
// light up LEDs
for (unsigned char y = 0; y < 8; y++) {
if (previousHeights[column] > y) {
// addr then col then row
lc.setLed(0, column, y, true);
} else {
lc.setLed(0, column, y, false);
}
}
}
// Run setup once
void setup() {
// the audio library needs to be given memory to start working
AudioMemory(12);
// compute the vertical thresholds before starting
computeVerticalLevels();
fft.windowFunction(AudioWindowHanning1024);
// turn on the display
lc.shutdown(0, false); //The MAX72XX is in power-saving mode on startup
lc.setIntensity(0, 10); // Set the brightness
lc.clearDisplay(0); // and clear the display
}
// Run repetitively
void loop() {
unsigned int x;
float level;
if (fft.available()) {
for (x = 0; x < 8; x++) {
level = fft.read(borders[x] + 1, borders[x + 1]);
setColumn(x, level);
Serial.print(level);
Serial.print(" ");
}
Serial.println("");
}
}
void setColumn2(int row, int column, float height) {
// for each vertical pixel, check if above the threshold
// and turn the LED on or off
if (height >= thresholdVertical[column]) {
lc.setLed(0, row, column, true);
} else {
lc.setLed(0, row, column, false);
}
}
I realize that the mapping is not a great way to do this, especially since when I'm looking at the fft bins since they rarely reach 1.5 and seem to vary by bin. Additionally, I don't fully understand the documentation at https://www.pjrc.com/teensy/gui/index.html?info=AudioAnalyzeFFT1024 since sometimes the values are above 1.0. The computeVerticalThreshold method performs worse, however.
There is typically high bin noise - the last 2 bins mostly, which should be from 3k-9.5k and 9.5k-22k. The frequency sweep seems to generally map to the right bins, except for the noise and the last bin, where it seems to never truly come alive.
Frequency Sweep from: http://www.szynalski.com/tone-generator/
Do you think the problem lies within how I'm processing the FFT data, or with the input circuit -- should I switch to the recommended input circuit at http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog, and if so, why?
Any advice would be great. Thanks!