Spectrum Analyzer Noise with Frequency Sweep

Status
Not open for further replies.

erosten

New member
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:

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!
 
Hi!

if you use the internal ADC of the Teensy for audio input, make sure, the audio signal swings between 0 and 1.2 volts. Otherwise the ADC will produce nasty things, which you would not want to see in a spectrum.

If your audio amp is biased at 2.5 Volts, you are far away from the recommended voltage swing and the ADC will clip horribly.

So, I think, yes, you should use the bias circuit recommended by Paul in the audio library GUI and bias your signal at 0.6 volts and make sure that the voltage swings do not exceed 1.2 volts or go below 0 volts.

I did not have a look at your software, because I think the cause of your problem is probably your hardware / biasing.

Have fun with the Teensy!

Frank
 
Worked like a charm! Thank you. Is there some documentation somewhere about the ADC that mentions the 0 to 1.2volt requirement? I see on the page I linked that it says the output of that circuit is 0 to 1.2volts but is there some more detailed information anywhere?

Thanks again!!
 
Status
Not open for further replies.
Back
Top