Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Spectrum Analyzer Noise with Frequency Sweep

  1. #1
    Junior Member
    Join Date
    Sep 2018
    Posts
    2

    Spectrum Analyzer Noise with Frequency Sweep

    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/inde...AnalyzeFFT1024 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!

  2. #2
    Senior Member DD4WH's Avatar
    Join Date
    Oct 2015
    Location
    Central Europe
    Posts
    302
    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

  3. #3
    Junior Member
    Join Date
    Sep 2018
    Posts
    2
    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!!

  4. #4
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    1,788
    Everything is in the MK20DX256 reference manual which is can be downloaded on the PJRC website: MK20DX256 Manual

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •